Skip to content

Commit c74d2cf

Browse files
committed
Merge branch 'dev' of https://github.com/imaginer-dev/DateLeaf into 51-그룹일정-추가-시-DB-저장
2 parents dcbbba8 + 2fdbe9a commit c74d2cf

14 files changed

+168
-45
lines changed

src/App.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import Calendar from './components/common/Calendar';
22

3-
43
function App() {
54
return (
65
<div>

src/apis/groupScheduleApis.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ export const addGroupSchedule = async ({ startDate, endDate, ...props }: addGrou
1919
}
2020
};
2121

22+
interface UpdateGroupSchedule {
23+
name: string;
24+
description: string;
25+
startDate: string;
26+
endDate: string;
27+
memo: string;
28+
scheduleId: string;
29+
}
30+
31+
interface UpdateGroupScheduleMember {
32+
updatedMemberList: Member[];
33+
groupId: string;
34+
}
35+
2236
export const getOneGroupSchedule = async (scheduleId: string) => {
2337
const { data, error } = await supabase.from('group_schedules').select('*').eq('id', +scheduleId);
2438

@@ -33,15 +47,6 @@ export const getOneGroupSchedule = async (scheduleId: string) => {
3347
return data[0];
3448
};
3549

36-
interface UpdateGroupSchedule {
37-
name: string;
38-
description: string;
39-
startDate: string;
40-
endDate: string;
41-
memo: string;
42-
scheduleId: string;
43-
}
44-
4550
export const updateGroupSchedule = async ({
4651
name,
4752
description,
@@ -68,11 +73,6 @@ export const updateGroupSchedule = async ({
6873
return data;
6974
};
7075

71-
interface UpdateGroupScheduleMember {
72-
updatedMemberList: Member[];
73-
groupId: string;
74-
}
75-
7676
export const updateGroupScheduleMember = async ({ updatedMemberList, groupId }: UpdateGroupScheduleMember) => {
7777
const { error: deleteError } = await supabase.from('group_user_ralations').delete().eq('group_id', groupId);
7878
if (deleteError) {

src/components/Group/GroupForm.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ interface Props {
1313
endDate?: string;
1414
memo?: string | null;
1515
memberList?: Member[];
16+
isLoading?: boolean;
1617
onSubmit: (e: React.FormEvent<HTMLFormElement>, userList: Member[]) => void;
1718
}
1819

@@ -24,6 +25,7 @@ const GroupForm: FC<Props> = ({
2425
memo = '',
2526
memberList = [],
2627
onSubmit,
28+
isLoading = false,
2729
}) => {
2830
const [member, setMember] = useState<Member[]>(memberList);
2931

@@ -43,8 +45,12 @@ const GroupForm: FC<Props> = ({
4345
<UserInvite member={member} setMember={onClick} />
4446
<GroupFormMemoInput memo={memo ?? ''} />
4547
</div>
46-
<button type="submit" className="btn btn-outline btn-primary w-full">
47-
저장
48+
<button
49+
disabled={isLoading}
50+
type="submit"
51+
className={`btn btn-outline btn-primary w-full ${isLoading ? 'disabled' : ''}`}
52+
>
53+
{isLoading ? <span className="loading" /> : '저장'}
4854
</button>
4955
</form>
5056
);

src/components/Group/GroupFormDateInput.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
1-
import { FC } from 'react';
1+
import { FC, useState } from 'react';
22
import { dateToYYMMDD } from '@/utils/dateUtils';
3+
import { getGroupSchedulePeriodErrorDefineObject } from '@/utils/groupScheduleUtils';
34

45
interface Props {
56
startDate: string;
67
endDate: string;
78
}
89

910
const GroupFormDateInput: FC<Props> = ({ startDate, endDate }) => {
11+
const [curStartDate, setCurStartDate] = useState<string>(dateToYYMMDD(startDate));
12+
const [curEndDate, setCurEndDate] = useState<string>(dateToYYMMDD(endDate));
13+
const { errorText, isError } = getGroupSchedulePeriodErrorDefineObject({
14+
startDate: curStartDate,
15+
endDate: curEndDate,
16+
});
17+
18+
const onStartDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
19+
setCurStartDate(e.target.value);
20+
};
21+
22+
const onEndDateChange = (e: React.ChangeEvent<HTMLInputElement>) => {
23+
setCurEndDate(e.target.value);
24+
};
25+
1026
return (
1127
<div className="w-full">
1228
<label className="label label-text w-full text-start">모임 설정 기간 *</label>
@@ -17,7 +33,8 @@ const GroupFormDateInput: FC<Props> = ({ startDate, endDate }) => {
1733
<input
1834
className="input border-none"
1935
type="date"
20-
defaultValue={dateToYYMMDD(new Date(startDate))}
36+
onChange={onStartDateChange}
37+
value={curStartDate}
2138
id="group-start-date-input"
2239
name="startDate"
2340
/>
@@ -28,11 +45,15 @@ const GroupFormDateInput: FC<Props> = ({ startDate, endDate }) => {
2845
<input
2946
className="input border-none"
3047
type="date"
48+
onChange={onEndDateChange}
3149
id="group-end-date-input"
32-
defaultValue={dateToYYMMDD(new Date(endDate))}
50+
value={curEndDate}
3351
name="endDate"
3452
/>
3553
</div>
54+
<div className="label flex h-8 flex-row items-center">
55+
<span className={`label-text-alt ${isError ? 'text-error' : ''}`}>{isError ? errorText : ''}</span>
56+
</div>
3657
</div>
3758
);
3859
};

src/components/Group/GroupFormNameInput.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
1-
import { FC } from 'react';
1+
import { FC, useState } from 'react';
22
import InputForm from '../common/InputForm';
3+
import { isValidGroupScheduleName } from '@/utils/groupScheduleUtils';
34

45
interface Props {
56
name: string;
67
}
78

89
const GroupFormNameInput: FC<Props> = ({ name = '' }) => {
10+
const [isError, setIsError] = useState(false);
11+
12+
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
13+
setIsError(!isValidGroupScheduleName(e.target.value));
14+
};
15+
916
return (
1017
<InputForm
1118
id="group-name-input"
1219
type="text"
1320
defaultValue={name}
1421
placeholder="모임명을 입력하세요"
15-
onChange={() => {}}
22+
onChange={onChange}
1623
title="모임명 *"
1724
hint=""
25+
error={isError}
26+
errorText="모임명을 입력해주세요."
1827
name="name"
1928
/>
2029
);

src/components/common/Calendar.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useRef, useState, useEffect, useCallback } from 'react';
77
import { useEventState } from '@/stores/myEventsStore';
88
import { getPersonalSchedule } from '@/apis/personalScheduleApi';
99
import { Events } from '../../utils/index.ts';
10+
import { formatDateRange, formatTime } from '../../utils/dateUtils';
1011
/*
1112
type Event = {
1213
title: string;
@@ -18,7 +19,6 @@ type Event = {
1819
};
1920
*/
2021

21-
2222
interface EventInfo {
2323
timeText: string;
2424
event: {
@@ -214,7 +214,6 @@ export default function Calendar() {
214214
<div className="mt-10">{selectedDate && <EventCards events={selectedEvents} date={selectedDate} />}</div>
215215
</div>
216216
);
217-
218217
}
219218

220219
function renderEventContent(eventInfo: EventInfo) {
@@ -246,10 +245,13 @@ function EventCards({ events, date }: EventCardsProps) {
246245
<h2 className="ml-2">{date}</h2>
247246
<div className="flex gap-5 overflow-x-auto">
248247
{events.map((event, index) => {
248+
const eventDateRange = formatDateRange(event.start, event.end);
249+
const eventTime = formatTime(event.start);
249250
return (
250251
<div key={index} className="relative min-h-[150px] min-w-[240px] bg-white p-4 text-black">
251252
<h3>{event.title}</h3>
252-
<p className="mt-1 text-xs">{event.start === event.end ? event.start : `${event.start}~${event.end}`}</p>
253+
<p className="mt-1 text-xs">{eventDateRange}</p>
254+
<p className="mt-1 text-xs">{eventTime}</p>
253255
{/* 메뉴 버튼 */}
254256
<div
255257
className="absolute right-2 top-2 flex cursor-pointer flex-col items-center justify-center"

src/components/common/Loading/Loading.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ interface Props {
55
display: 'spinner' | 'dots' | 'ring' | 'ball' | 'bars' | 'infinity';
66
size: 'xs' | 'sm' | 'md' | 'lg';
77
color: 'primary' | 'secondary' | 'accent' | 'neutral' | 'info' | 'success' | 'warning' | 'error';
8+
transparent?: boolean;
89
}
910

1011
const styleMap = {
@@ -28,12 +29,10 @@ const styleMap = {
2829
error: 'text-error',
2930
};
3031

31-
const Loading: React.FC<Props> = ({ display, size, color }) => {
32+
const Loading: React.FC<Props> = ({ display, size, color, transparent = false }) => {
3233
return (
3334
<div
34-
className={
35-
'fixed left-0 top-0 z-50 flex h-screen w-screen flex-col items-center justify-center overflow-hidden bg-base-100'
36-
}
35+
className={`fixed left-0 top-0 z-50 flex h-screen w-screen flex-col items-center justify-center overflow-hidden bg-base-100 ${transparent ? 'bg-opacity-50' : ''}`}
3736
>
3837
<Logo />
3938
<span className={`loading absolute bottom-20 ${styleMap[display]} ${styleMap[size]} ${styleMap[color]}`}></span>

src/pages/EditGroupSchedulePage.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Loading } from '.';
55
import { Member } from '@/types/Member';
66
import { useUpdateGroupSchedule } from '@/react-queries/useUpdateGroupSchedule';
77
import { useGetGroupScheduleDefaultData } from '@/hooks/useGetGroupScheduleDefaultData';
8+
import Dialog from '@/components/common/Dialog';
89

910
const EditGroupSchedulePage = () => {
1011
const params = useParams<{ groupId: string; scheduleId: string }>();
@@ -15,7 +16,7 @@ const EditGroupSchedulePage = () => {
1516
scheduleId,
1617
groupId,
1718
);
18-
const { mutate, isError: updateHasError, isPending: updateIsPending } = useUpdateGroupSchedule();
19+
const { mutate, successDialog, errorDialogRef, isPending: updateIsPending } = useUpdateGroupSchedule();
1920

2021
if (isError) {
2122
return <div>{error!.message}</div>;
@@ -40,10 +41,6 @@ const EditGroupSchedulePage = () => {
4041
mutate(updatePayload);
4142
};
4243

43-
if (updateHasError) {
44-
// TODO: 에러 다이얼로그 표시
45-
}
46-
4744
if (updateIsPending) {
4845
// TODO: 로딩 스피너 표시
4946
}
@@ -63,7 +60,10 @@ const EditGroupSchedulePage = () => {
6360
endDate={groupScheduleData!.end_date}
6461
memo={groupScheduleData!.memo}
6562
memberList={groupMemberData}
63+
isLoading={updateIsPending}
6664
/>
65+
<Dialog ref={errorDialogRef} desc="오류가 발생했습니다. 다시시도해 주세요." />
66+
<Dialog ref={successDialog} desc="성공적으로 수정했습니다." />
6767
</div>
6868
)}
6969
</>

src/react-queries/useUpdateGroupSchedule.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useMutation } from '@tanstack/react-query';
33
import { queries } from './queryKeys';
44
import { Member } from '@/types/Member';
55
import { useNavigate } from 'react-router-dom';
6-
import { useEffect } from 'react';
6+
import { useEffect, useRef } from 'react';
77

88
interface UpdateGroupSchedule {
99
name: string;
@@ -15,14 +15,23 @@ interface UpdateGroupSchedule {
1515
newMemberList: Member[];
1616
}
1717

18+
interface DialogElement {
19+
openModal: () => void;
20+
closeModal: () => void;
21+
}
22+
1823
export const useUpdateGroupSchedule = () => {
1924
const navigator = useNavigate();
2025

26+
const errorDialogRef = useRef<DialogElement | null>(null);
27+
const successDialog = useRef<DialogElement | null>(null);
28+
2129
const {
2230
mutate: updateGroupScheduleMutate,
2331
isPending: updateGroupScheduleIsPending,
2432
isSuccess: updateGroupScheduleIsSuccess,
2533
isError: updateGroupScheduleIsError,
34+
reset: updateGroupScheduleReset,
2635
} = useMutation({
2736
mutationKey: queries.groupSchedule.update.queryKey,
2837
mutationFn: updateGroupSchedule,
@@ -33,6 +42,7 @@ export const useUpdateGroupSchedule = () => {
3342
isPending: updateGroupMemberIsPending,
3443
isSuccess: updateGroupMemberIsSuccess,
3544
isError: updateGroupMemberIsError,
45+
reset: updateGroupMemberReset,
3646
} = useMutation({
3747
mutationKey: queries.group.updateMember.queryKey,
3848
mutationFn: updateGroupScheduleMember,
@@ -48,13 +58,30 @@ export const useUpdateGroupSchedule = () => {
4858

4959
useEffect(() => {
5060
if (updateGroupScheduleIsSuccess && updateGroupMemberIsSuccess) {
51-
navigator(-1);
61+
successDialog.current?.openModal();
62+
updateGroupMemberReset();
63+
updateGroupScheduleReset();
64+
}
65+
}, [
66+
updateGroupScheduleIsSuccess,
67+
updateGroupMemberIsSuccess,
68+
navigator,
69+
updateGroupMemberReset,
70+
updateGroupScheduleReset,
71+
]);
72+
73+
useEffect(() => {
74+
if (updateGroupScheduleIsError || updateGroupMemberIsError) {
75+
errorDialogRef.current?.openModal();
76+
updateGroupMemberReset();
77+
updateGroupScheduleReset();
5278
}
53-
}, [updateGroupScheduleIsSuccess, updateGroupMemberIsSuccess, navigator]);
79+
}, [updateGroupScheduleIsError, updateGroupMemberIsError, updateGroupMemberReset, updateGroupScheduleReset]);
5480

5581
return {
5682
mutate,
5783
isPending: updateGroupScheduleIsPending || updateGroupMemberIsPending,
58-
isError: updateGroupScheduleIsError || updateGroupMemberIsError,
84+
errorDialogRef,
85+
successDialog,
5986
};
6087
};

src/tests/EditGroupSchedulePage.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ describe('EditGroupPage', () => {
3333

3434
expect(groupNameInput.value).toBe(groupScheduleFixture[0].title);
3535
expect(groupDescriptionInput.value).toBe(groupScheduleFixture[0].description);
36-
expect(groupDateStartInput.value).toBe(dateToYYMMDD(new Date(groupScheduleFixture[0].start_date)));
37-
expect(groupDateEndInput.value).toBe(dateToYYMMDD(new Date(groupScheduleFixture[0].end_date)));
36+
expect(groupDateStartInput.value).toBe(dateToYYMMDD(groupScheduleFixture[0].start_date));
37+
expect(groupDateEndInput.value).toBe(dateToYYMMDD(groupScheduleFixture[0].end_date));
3838
expect(groupMemoInput.value).toBe(groupScheduleFixture[0].memo);
3939
});
4040
});

0 commit comments

Comments
 (0)