Skip to content
Open
12 changes: 12 additions & 0 deletions frontend/apps/client/src/features/discussion/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ export const discussionApi = {
return response;
},

putDiscussion: async (
discussionId: string, body: DiscussionRequest,
): Promise<DiscussionResponse> => {
const response = await request.put(`/api/v1/discussion/${discussionId}`, { body });
return response;
},

deleteDiscussion: async (discussionId: string): Promise<void> => {
const response = await request.delete(`/api/v1/discussion/${discussionId}`);
return response;
},

getIsHost: async (id: string): Promise<boolean> => {
const response = await request.get(`/api/v1/discussion/${id}/role`);
return response;
Expand Down
68 changes: 56 additions & 12 deletions frontend/apps/client/src/features/discussion/api/mutations.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useNavigate } from '@tanstack/react-router';
import { useNavigate, useParams } from '@tanstack/react-router';

import { sharedScheduleKey } from '@/features/shared-schedule/api/keys';
import {
ongoingQueryKey,
sharedScheduleKey,
upcomingQueryKey,
} from '@/features/shared-schedule/api/keys';

import type { DiscussionConfirmRequest, DiscussionRequest } from '../model';
import { candidateApi, discussionApi } from '.';
Expand All @@ -10,20 +14,60 @@ import { discussionKeys } from './keys';

export const useDiscussionMutation = () => {
const queryClient = useQueryClient();

const navigate = useNavigate();

const { mutate } = useMutation({
mutationFn: ({ body }: {
body: DiscussionRequest;
callback: (id: string) => void;
}) => discussionApi.postDiscussion(body),
onSuccess: ({ id }, { callback }) => {
callback?.(id.toString());
queryClient.invalidateQueries({
queryKey: discussionKeys.all,
mutationFn: (body: DiscussionRequest) => discussionApi.postDiscussion(body),
onSuccess: ({ id }) => {
queryClient.invalidateQueries({ queryKey: upcomingQueryKey });
queryClient.invalidateQueries({ queryKey: ongoingQueryKey.all });
queryClient.invalidateQueries({ queryKey: discussionKeys.all });
navigate({
to: '/discussion/$id',
params: { id: String(id) },
});
},
});


return { mutate };
};

export const useDiscussionEditMutation = () => {
const { id } = useParams({ from: '/_main/discussion/edit/$id' });
const queryClient = useQueryClient();
const navigate = useNavigate();

const { mutate } = useMutation({
mutationFn: (body: DiscussionRequest) => discussionApi.putDiscussion(id, body),
onSuccess: (_) => {
queryClient.invalidateQueries({ queryKey: upcomingQueryKey });
queryClient.invalidateQueries({ queryKey: ongoingQueryKey.all });
queryClient.invalidateQueries({ queryKey: discussionKeys.detail(id) });
navigate({
to: '/discussion/$id',
params: { id },
});
},
});

return { mutate };
};

export const useDiscussionDeleteMutation = (callback: () => void) => {
const { id } = useParams({ from: '/_main/discussion/edit/$id' });
const queryClient = useQueryClient();
const navigate = useNavigate();

const { mutate } = useMutation({
mutationFn: () => discussionApi.deleteDiscussion(id),
onSuccess: (_) => {
queryClient.invalidateQueries({ queryKey: upcomingQueryKey });
queryClient.invalidateQueries({ queryKey: ongoingQueryKey.all });
callback();
navigate({ to: '/home' });
},
});

return { mutate };
};

Expand Down
4 changes: 2 additions & 2 deletions frontend/apps/client/src/features/discussion/api/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ export const discussionHostQuery = (discussionId: string) => ({
});

export const useDiscussionQuery = (discussionId: string) => {
const { data: discussion, isLoading }
const { data: discussion, isPending }
= useQuery<DiscussionResponse>(discussionQuery(discussionId));

return { discussion, isLoading };
return { discussion, isPending };
};

export const useDiscussionCalendarQuery = (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Button, Icon } from '@endolphin/ui';
import { Link, useParams } from '@tanstack/react-router';

import { useDiscussionHostQuery } from '../../api/queries';

const DiscussionEditButton = () => {
const { id } = useParams({ from: '/_main/discussion/$id' });

const { isHost, isPending } = useDiscussionHostQuery(id);
if (isPending || !isHost) return null;

return (
<Button
as={Link}
rightIcon={<Icon.Pencil />}
size='lg'
style='weak'
to={`/discussion/edit/${id}`}
variant='secondary'
>
수정하기
</Button>
);
};

export default DiscussionEditButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { clsx } from '@endolphin/core/utils';
import { Button, Flex } from '@endolphin/ui';

import { useGlobalModal } from '@/store/global/modal';

import {
useDiscussionDeleteMutation,
useDiscussionEditMutation,
useDiscussionMutation,
} from '../../api/mutations';
import { useFormContext } from './FormContext';
import { buttonStyle } from './index.css';

export const AddButton = () => {
const { name, formState, isValidForm } = useFormContext();
const { mutate } = useDiscussionMutation();

const handleClickEnrollButton = () => {
mutate(formState);
};

return (
<Button
className={clsx(name, buttonStyle)}
disabled={!isValidForm()}
onClick={handleClickEnrollButton}
size='xl'
>
생성하기
</Button>
);
};

export const EditButton = () => {
const { name, formState, isValidForm } = useFormContext();
const { mutate } = useDiscussionEditMutation();

const handleClickEnrollButton = () => {
mutate(formState);
};

return (
<Button
className={clsx(name, buttonStyle)}
disabled={!isValidForm()}
onClick={handleClickEnrollButton}
size='xl'
>
수정하기
</Button>
);
};

export const DeleteButton = () => {
const { createModal, onModalClose } = useGlobalModal();
const { mutate } = useDiscussionDeleteMutation(onModalClose);

const handleClickDeleteDiscussion = () => {
createModal({
subTitle: '경고',
type: 'error',
title: '정말 삭제할까요?',
description: '삭제하면 다시 되돌릴 수 없어요.',
children: (
<Flex
align='flex-end'
height='100%'
justify='flex-end'
>
<Button
onClick={() => mutate()}
size='xl'
variant='re'
>
삭제하기
</Button>
</Flex>
),
});
};

return (
<Button
onClick={handleClickDeleteDiscussion}
size='xl'
style='outline'
variant='re'
>
삭제하기
</Button>
);
};
Original file line number Diff line number Diff line change
@@ -1,83 +1,21 @@
import { clsx } from '@endolphin/core/utils';
import { Button, Flex } from '@endolphin/ui';
import { type QueryClient, useQueryClient } from '@tanstack/react-query';
import { useNavigate } from '@tanstack/react-router';
import { Flex } from '@endolphin/ui';

import { ongoingQueryKey, upcomingQueryKey } from '@/features/shared-schedule/api/keys';

import { useDiscussionMutation } from '../../api/mutations';
import { useFormContext } from './FormContext';
import { buttonStyle } from './index.css';
import { AddButton, DeleteButton, EditButton } from './EnrollButton';
import type { FormType } from './type';

const FormButton = ({ type }: { type: FormType }) => {
const handleClickDeleteDiscussion = () => {
/* Do something */
};
return type === 'add' ? (
<EnrollButton type={type} />
const FormButton = ({ type }: { type: FormType }) => (
type === 'add' ? (
<AddButton />
) : (
<Flex
gap={100}
gap={300}
justify='flex-end'
width='100%'
>
<Button
onClick={handleClickDeleteDiscussion}
size='xl'
style='outline'
variant='re'
>
삭제하기
</Button>
<EnrollButton type={type} />
<DeleteButton />
<EditButton />
</Flex>
);
};

const EnrollButton = ({ type }: { type: FormType }) => {
const queryClient = useQueryClient();
const { name, formState, isValidForm } = useFormContext();
const navigate = useNavigate();
const { mutate } = useDiscussionMutation();

const typeMap: Record<FormType, Record<string, string>> = {
add: {
text: '생성하기',
navigate: '/discussion/create/$id',
},
edit: {
text: '수정하기',
navigate: '/discussion/$id',
},
};

const handleClickEnrollButton = () => {
const callback = (id: string) => {
invalidateScheduleCaches(queryClient);
navigate({
to: typeMap[type].navigate,
params: { id },
});
};
mutate({ body: formState, callback });
};

return (
<Button
className={clsx(name, buttonStyle)}
disabled={!isValidForm()}
onClick={handleClickEnrollButton}
size='xl'
>
{typeMap[type].text}
</Button>
);
};

const invalidateScheduleCaches = (queryClient: QueryClient) => {
queryClient.invalidateQueries({ queryKey: upcomingQueryKey });
queryClient.invalidateQueries({ queryKey: ongoingQueryKey.all });
};
)
);

export default FormButton;
export default FormButton;
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import MeetingTitle from './MeetingTitle';
import type { FormType } from './type';

const DiscussionForm = (
{ type, initialValues }: { type: FormType; initialValues?: DiscussionRequest },
{ type, initialValues }:
{ type: FormType; initialValues?: DiscussionRequest },
) => {
const SEVEN_DAYS = 7 * 24 * 60 * 60 * 1000;
const today = new Date();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,37 @@ import { Flex, Text } from '@endolphin/ui';
import { useParams } from '@tanstack/react-router';

import { useDiscussionQuery } from '../../api/queries';
import DiscussionEditButton from '../DiscussionEditButton';
import { DiscussionBadges } from './DiscussionBadges';
import { titleStyle } from './index.css';

const DiscussionTitle = () => {
const params: { id: string } = useParams({ from: '/_main/discussion/$id' });
const { discussion, isLoading } = useDiscussionQuery(params.id);
const { discussion, isPending } = useDiscussionQuery(params.id);
return (
<Flex
align='flex-start'
className={titleStyle}
direction='column'
gap={200}
width='100%'
justify='space-between'
width='full'
>
{!isLoading && (
<>
<Text color={vars.color.Ref.Netural[900]} typo='h2'>
{discussion?.title}
{' '}
일정 조율 결과
</Text>
<DiscussionBadges discussion={discussion} />
</>
)}
<Flex
align='flex-start'
direction='column'
gap={200}
width='100%'
>
{!isPending && (
<>
<Text color={vars.color.Ref.Netural[900]} typo='h2'>
{discussion?.title}
{' '}
일정 조율 결과
</Text>
<DiscussionBadges discussion={discussion} />
</>
)}
</Flex>
<DiscussionEditButton />
</Flex>
);
};
Expand Down
Loading