Skip to content

Commit cd9a8ce

Browse files
committed
feat: 버튼 클릭시 모임 수정 기능 추가
1 parent a684047 commit cd9a8ce

File tree

9 files changed

+262
-29
lines changed

9 files changed

+262
-29
lines changed

src/apis/groupScheduleApis.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import supabase from '@/supabase';
2+
import { Member } from '@/types/Member';
23

34
export const getOneGroupSchedule = async (scheduleId: string) => {
45
const { data, error } = await supabase.from('group_schedules').select('*').eq('id', +scheduleId);
@@ -13,3 +14,90 @@ export const getOneGroupSchedule = async (scheduleId: string) => {
1314

1415
return data[0];
1516
};
17+
18+
interface UpdateGroupSchedule {
19+
name: string;
20+
description: string;
21+
startDate: string;
22+
endDate: string;
23+
memo: string;
24+
scheduleId: string;
25+
}
26+
27+
export const updateGroupSchedule = async ({
28+
name,
29+
description,
30+
startDate,
31+
endDate,
32+
memo,
33+
scheduleId,
34+
}: UpdateGroupSchedule) => {
35+
const { data, error } = await supabase
36+
.from('group_schedules')
37+
.update({
38+
title: name,
39+
description,
40+
start_date: startDate,
41+
end_date: endDate,
42+
memo,
43+
})
44+
.eq('id', +scheduleId);
45+
46+
if (error) {
47+
throw error;
48+
}
49+
50+
return data;
51+
};
52+
53+
interface UpdateGroupScheduleMember {
54+
updatedMemberList: Member[];
55+
groupId: string;
56+
}
57+
58+
export const updateGroupScheduleMember = async ({ updatedMemberList, groupId }: UpdateGroupScheduleMember) => {
59+
const { error: deleteError } = await supabase.from('group_user_ralations').delete().eq('group_id', groupId);
60+
if (deleteError) {
61+
throw deleteError;
62+
}
63+
64+
const { data, error: insertError } = await supabase.from('group_user_ralations').insert(
65+
updatedMemberList.map((member) => ({
66+
group_id: +groupId,
67+
user_id: member.id,
68+
})),
69+
);
70+
71+
if (insertError) {
72+
throw insertError;
73+
}
74+
75+
return data;
76+
};
77+
78+
export const getAllGroupMembers = async (groupId: string) => {
79+
// group_user_ralations 의 응답 결과의 user_id를 포함하는 profile리스트를 받아온다.
80+
const { data, error } = await supabase.from('group_user_ralations').select('user_id').eq('group_id', +groupId);
81+
82+
if (error) {
83+
throw error;
84+
}
85+
86+
if (!data) {
87+
throw new Error('데이터를 찾을 수 없습니다.');
88+
}
89+
90+
const { data: allUserProfile, error: getProfileError } = await supabase
91+
.from('profiles')
92+
.select('*')
93+
.in(
94+
'id',
95+
data.map((d) => d.user_id),
96+
);
97+
98+
if (getProfileError) {
99+
throw getProfileError;
100+
}
101+
102+
return allUserProfile;
103+
};

src/components/Group/GroupForm.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ interface Props {
1212
startDate?: string;
1313
endDate?: string;
1414
memo?: string | null;
15+
memberList?: Member[];
1516
onSubmit: (e: React.FormEvent<HTMLFormElement>, userList: Member[]) => void;
1617
}
1718

@@ -21,9 +22,10 @@ const GroupForm: FC<Props> = ({
2122
startDate = new Date().toString(),
2223
endDate = new Date().toString(),
2324
memo = '',
25+
memberList = [],
2426
onSubmit,
2527
}) => {
26-
const [member, setMember] = useState<Member[]>([]);
28+
const [member, setMember] = useState<Member[]>(memberList);
2729

2830
const onClick = (newMember: Member) => {
2931
setMember((prev) => [...prev, newMember]);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { useGetAllMember } from '@/react-queries/useGetAllMember';
2+
import { useGetOneGroupSchedule } from '@/react-queries/useGetOneGroupSchedule';
3+
4+
export const useGetGroupScheduleDefaultData = (scheduleId: string, groupId: string) => {
5+
const {
6+
data: groupScheduleData,
7+
isLoading: groupScheduleIsLoading,
8+
error: groupScheduleError,
9+
isError: groupScheduleIsError,
10+
} = useGetOneGroupSchedule(scheduleId);
11+
12+
const {
13+
data: groupMemberData,
14+
isLoading: groupMemberIsLoading,
15+
error: groupMemberError,
16+
isError: groupMemberIsError,
17+
} = useGetAllMember(groupId);
18+
19+
return {
20+
groupScheduleData,
21+
groupMemberData,
22+
isLoading: groupScheduleIsLoading || groupMemberIsLoading,
23+
error: groupScheduleError ?? groupMemberError,
24+
isError: groupScheduleIsError || groupMemberIsError,
25+
};
26+
};

src/pages/EditGroupSchedulePage.tsx

Lines changed: 46 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,71 @@
11
import GroupForm from '@/components/Group/GroupForm';
22
import AppBar from '@/components/common/AppBar';
3-
import { useGetOneGroupSchedule } from '@/react-queries/useGetOneGroupSchedule';
43
import { useParams } from 'react-router-dom';
54
import { Loading } from '.';
65
import { Member } from '@/types/Member';
6+
import { useUpdateGroupSchedule } from '@/react-queries/useUpdateGroupSchedule';
7+
import { useGetGroupScheduleDefaultData } from '@/hooks/useGetGroupScheduleDefaultData';
78

89
const EditGroupSchedulePage = () => {
910
const params = useParams<{ groupId: string; scheduleId: string }>();
10-
const { scheduleId } = params;
11-
const { data, isError, error, isLoading } = useGetOneGroupSchedule(scheduleId!);
11+
const scheduleId = params.scheduleId!;
12+
const groupId = params.groupId!;
13+
14+
const { groupMemberData, groupScheduleData, error, isLoading, isError } = useGetGroupScheduleDefaultData(
15+
scheduleId,
16+
groupId,
17+
);
18+
const { mutate, isError: updateHasError, isPending: updateIsPending } = useUpdateGroupSchedule();
1219

1320
if (isError) {
14-
// TODO: 에러 처리
15-
return <div>{error.message}</div>;
21+
return <div>{error!.message}</div>;
1622
}
1723

18-
if (!data) {
19-
// TODO: 에러 처리
24+
if ((!groupMemberData || !groupScheduleData) && !isLoading) {
2025
return <div>데이터를 찾을 수 없습니다.</div>;
2126
}
2227

2328
const handleSubmit = (e: React.FormEvent<HTMLFormElement>, userList: Member[]) => {
2429
e.preventDefault();
2530
const formData = new FormData(e.currentTarget);
26-
console.log(formData.get('name'));
27-
console.log(formData.get('description'));
28-
console.log(formData.get('startDate'));
29-
console.log(formData.get('endDate'));
30-
console.log(formData.get('memo'));
31-
console.log('userList', userList);
31+
const updatePayload = {
32+
name: formData.get('name') as string,
33+
description: formData.get('description') as string,
34+
startDate: formData.get('startDate') as string,
35+
endDate: formData.get('endDate') as string,
36+
memo: formData.get('memo') as string,
37+
scheduleId,
38+
newMemberList: userList,
39+
};
40+
mutate(updatePayload);
3241
};
3342

43+
if (updateHasError) {
44+
// TODO: 에러 다이얼로그 표시
45+
}
46+
47+
if (updateIsPending) {
48+
// TODO: 로딩 스피너 표시
49+
}
50+
3451
return (
3552
<>
36-
{isLoading && <Loading display="spinner" size="lg" color="primary" />}
37-
<div className="flex min-h-dvh w-screen flex-col overflow-x-hidden px-4">
38-
<AppBar backButton title={'모임 일정 등록하기'} />
39-
<GroupForm
40-
onSubmit={handleSubmit}
41-
name={data.title}
42-
description={data.description}
43-
startDate={data.start_date}
44-
endDate={data.end_date}
45-
memo={data.memo}
46-
/>
47-
</div>
53+
{isLoading ? (
54+
<Loading display="spinner" size="lg" color="primary" />
55+
) : (
56+
<div className="flex min-h-dvh w-screen flex-col overflow-x-hidden px-4">
57+
<AppBar backButton title={'모임 일정 수정하기'} />
58+
<GroupForm
59+
onSubmit={handleSubmit}
60+
name={groupScheduleData!.title}
61+
description={groupScheduleData!.description}
62+
startDate={groupScheduleData!.start_date}
63+
endDate={groupScheduleData!.end_date}
64+
memo={groupScheduleData!.memo}
65+
memberList={groupMemberData}
66+
/>
67+
</div>
68+
)}
4869
</>
4970
);
5071
};

src/react-queries/queryKeys.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,13 @@ export const queries = createQueryKeyStore({
1010
groupSchedule: {
1111
getOne: (scheduleId: string) => [scheduleId],
1212
getAll: null,
13+
update: null,
14+
},
15+
group: {
16+
getOne: (groupId: string) => [groupId],
17+
getAll: null,
18+
update: null,
19+
updateMember: null,
20+
getAllMember: (groupId: string) => [groupId],
1321
},
1422
});
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { getAllGroupMembers } from '@/apis/groupScheduleApis';
2+
import { useQuery } from '@tanstack/react-query';
3+
import { queries } from './queryKeys';
4+
5+
export const useGetAllMember = (groupId: string) =>
6+
useQuery({
7+
queryKey: queries.group.getAllMember(groupId).queryKey,
8+
queryFn: () => getAllGroupMembers(groupId),
9+
});
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { updateGroupSchedule, updateGroupScheduleMember } from '@/apis/groupScheduleApis';
2+
import { useMutation } from '@tanstack/react-query';
3+
import { queries } from './queryKeys';
4+
import { Member } from '@/types/Member';
5+
import { useNavigate } from 'react-router-dom';
6+
import { useEffect } from 'react';
7+
8+
interface UpdateGroupSchedule {
9+
name: string;
10+
description: string;
11+
startDate: string;
12+
endDate: string;
13+
memo: string;
14+
scheduleId: string;
15+
newMemberList: Member[];
16+
}
17+
18+
export const useUpdateGroupSchedule = () => {
19+
const navigator = useNavigate();
20+
21+
const {
22+
mutate: updateGroupScheduleMutate,
23+
isPending: updateGroupScheduleIsPending,
24+
isSuccess: updateGroupScheduleIsSuccess,
25+
isError: updateGroupScheduleIsError,
26+
} = useMutation({
27+
mutationKey: queries.groupSchedule.update.queryKey,
28+
mutationFn: updateGroupSchedule,
29+
});
30+
31+
const {
32+
mutate: updateGroupMemberMutate,
33+
isPending: updateGroupMemberIsPending,
34+
isSuccess: updateGroupMemberIsSuccess,
35+
isError: updateGroupMemberIsError,
36+
} = useMutation({
37+
mutationKey: queries.group.updateMember.queryKey,
38+
mutationFn: updateGroupScheduleMember,
39+
});
40+
41+
const mutate = (data: UpdateGroupSchedule) => {
42+
updateGroupScheduleMutate(data);
43+
updateGroupMemberMutate({
44+
updatedMemberList: data.newMemberList,
45+
groupId: data.scheduleId,
46+
});
47+
};
48+
49+
useEffect(() => {
50+
if (updateGroupScheduleIsSuccess && updateGroupMemberIsSuccess) {
51+
navigator(-1);
52+
}
53+
}, [updateGroupScheduleIsSuccess, updateGroupMemberIsSuccess, navigator]);
54+
55+
return {
56+
mutate,
57+
isPending: updateGroupScheduleIsPending || updateGroupMemberIsPending,
58+
isError: updateGroupScheduleIsError || updateGroupMemberIsError,
59+
};
60+
};

src/tests/EditGroupSchedulePage.test.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import { groupScheduleFixture } from './fixtures/groupScheduleFixture';
33
import { render, screen, waitFor } from '@testing-library/react';
44
import EditGroupPage from '@/pages/EditGroupSchedulePage';
55
import wrapper from './helpers/wrapper';
6-
import { getOneGroupSchedule } from '@/apis/groupScheduleApis';
6+
import { getAllGroupMembers, getOneGroupSchedule } from '@/apis/groupScheduleApis';
77
import { dateToYYMMDD } from '@/utils/dateUtils';
8+
import { memberListFixture } from './fixtures/memberFixture';
89

910
vi.mock('react-router-dom', () => ({
1011
useNavigate: () => vi.fn(),
@@ -16,11 +17,13 @@ vi.mock('@/apis/groupScheduleApis');
1617
describe('EditGroupPage', () => {
1718
it('페이지 파라미터를 통해 그룹의 기본값을 받아올 수 있어야 한다.', async () => {
1819
vi.mocked(getOneGroupSchedule).mockResolvedValueOnce(groupScheduleFixture[0]);
20+
vi.mocked(getAllGroupMembers).mockResolvedValueOnce(memberListFixture);
1921
render(<EditGroupPage />, {
2022
wrapper: wrapper,
2123
});
2224

2325
await waitFor(() => expect(screen.getByPlaceholderText(//)).toHaveValue(groupScheduleFixture[0].title));
26+
await waitFor(() => expect(screen.getByText(/gihwan/gi)).toBeInTheDocument());
2427

2528
const groupNameInput = screen.getByPlaceholderText(//) as HTMLInputElement;
2629
const groupDescriptionInput = screen.getByPlaceholderText(/ /) as HTMLInputElement;
@@ -34,6 +37,4 @@ describe('EditGroupPage', () => {
3437
expect(groupDateEndInput.value).toBe(dateToYYMMDD(new Date(groupScheduleFixture[0].end_date)));
3538
expect(groupMemoInput.value).toBe(groupScheduleFixture[0].memo);
3639
});
37-
38-
it('저장 버튼을 누르면 그룹 수정 요청을 보낼 수 있어야 한다.', () => {});
3940
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Member } from '@/types/Member';
2+
3+
export const memberListFixture: Member[] = [
4+
{
5+
id: '1',
6+
user_name: '최기환',
7+
created_at: '2021-10-10',
8+
phone: '010-1234-5678',
9+
user_nickname: 'gihwan-dev',
10+
},
11+
{
12+
id: '2',
13+
user_name: '홍길동',
14+
created_at: '2021-10-10',
15+
phone: '010-1234-5678',
16+
user_nickname: 'hong',
17+
},
18+
];

0 commit comments

Comments
 (0)