Skip to content

Commit

Permalink
[#505] [모임 상세] 모임 삭제 기능 구현 (#537)
Browse files Browse the repository at this point in the history
* fix: toast default 지연시간 2초로 늘림

* style: button foucs outline 스타일 수정

* feat: 모임 삭제 기능 구현

- 모임 상세 페이지 error boundary 추가
- 존재하지않는 모임 페이지 접근 시 not-found 페이지로 이동
- Query refetchOnWindowFocus 옵션 false
  • Loading branch information
gxxrxn committed Jun 17, 2024
1 parent 3671624 commit efdb2c5
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 20 deletions.
19 changes: 19 additions & 0 deletions src/app/group/[groupId]/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Button from '@/v1/base/Button';
import Image from 'next/image';
import Link from 'next/link';

export default function NotFound() {
return (
<div className="absolute left-0 top-0 flex h-full w-full flex-col items-center justify-center gap-[2rem]">
<Image src="/images/loading.gif" width={230} height={160} alt="loading" />
<p className="text-2xl">
<span className="font-bold text-main-900">다독이</span>가 길을 잃었어요.
</p>
<Link href="/group">
<Button size="large" colorScheme="main" fill={false}>
모임 둘러보기
</Button>
</Link>
</div>
);
}
14 changes: 9 additions & 5 deletions src/app/group/[groupId]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
'use client';

import { notFound } from 'next/navigation';
import { ErrorBoundary } from 'react-error-boundary';

import { checkAuthentication } from '@/utils/helpers';

import SSRSafeSuspense from '@/components/SSRSafeSuspense';
import BookGroupInfo from '@/v1/bookGroup/detail/BookGroupInfo';
import BookGroupCommentList from '@/v1/comment/BookGroupCommentList';
import LoginBottomActionButton from '@/v1/base/LoginBottomActionButton';
import BookGroupNavigation from '@/v1/bookGroup/BookGroupNavigation';
import BookGroupInfo from '@/v1/bookGroup/detail/BookGroupInfo';
import JoinBookGroupButton from '@/v1/bookGroup/detail/JoinBookGroupButton';
import LoginBottomActionButton from '@/v1/base/LoginBottomActionButton';
import BookGroupCommentList from '@/v1/comment/BookGroupCommentList';

const DetailBookGroupPage = ({
params: { groupId },
}: {
params: { groupId: number };
}) => {
const isAuthenticated = checkAuthentication();

return (
<>
<ErrorBoundary fallbackRender={notFound}>
<BookGroupNavigation groupId={groupId}>
<BookGroupNavigation.BackButton />
<BookGroupNavigation.Title />
Expand All @@ -39,7 +43,7 @@ const DetailBookGroupPage = ({
<LoginBottomActionButton />
)}
</SSRSafeSuspense>
</>
</ErrorBoundary>
);
};

Expand Down
3 changes: 2 additions & 1 deletion src/components/ReactQueryProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const ReactQueryProvider: NextPage<PropTypes> = ({ children }) => {
new QueryClient({
defaultOptions: {
queries: {
retry: 0,
refetchOnWindowFocus: false,
retry: false,
},
},
})
Expand Down
14 changes: 14 additions & 0 deletions src/queries/group/useDeleteBookGroupMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useMutation } from '@tanstack/react-query';

import type { APIGroup } from '@/types/group';

import groupAPI from '@/apis/group';

const useDeleteBookGroupMutation = () => {
return useMutation({
mutationFn: (bookGroupId: APIGroup['bookGroupId']) =>
groupAPI.deleteGroup({ bookGroupId }).then(({ data }) => data),
});
};

export default useDeleteBookGroupMutation;
2 changes: 1 addition & 1 deletion src/v1/base/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const getSchemeClasses = (theme: ColorScheme, isFill: boolean) => {
};

const BASE_BUTTON_CLASSES =
'cursor-pointer border-[0.1rem] leading-none inline-block font-bold';
'cursor-pointer border-[0.1rem] leading-none inline-block font-bold focus:outline-none focus:ring-2';

const Button = ({
size = 'medium',
Expand Down
2 changes: 1 addition & 1 deletion src/v1/base/Toast/ToastProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const ToastProvider = ({ children }: { children?: ReactNode }) => {

const controller = useMemo<ToastController>(
() => ({
show: ({ type, message, duration = 1000 }) => {
show: ({ type, message, duration = 2000 }) => {
setToast({ type, message, duration });

setAnimation('slide-init');
Expand Down
109 changes: 97 additions & 12 deletions src/v1/bookGroup/BookGroupNavigation.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
import { useRouter } from 'next/navigation';
import {
ReactNode,
Children,
createContext,
isValidElement,
ReactNode,
useContext,
useRef,
} from 'react';
import { useRouter } from 'next/navigation';

import SSRSafeSuspense from '@/components/SSRSafeSuspense';
import TopNavigation from '@/v1/base/TopNavigation';
import CommentDrawer from '@/v1/comment/CommentDrawer';
import { IconArrowLeft, IconHamburger, IconPost } from '@public/icons';
import { SERVICE_ERROR_MESSAGE } from '@/constants';
import { IconArrowLeft, IconPost } from '@public/icons';
import { isAxiosErrorWithCustomCode } from '@/utils/helpers';

import useDisclosure from '@/hooks/useDisclosure';
import {
useBookGroupJoinInfo,
useBookGroupOwner,
useBookGroupTitle,
useBookGroupJoinInfo,
} from '@/queries/group/useBookGroupQuery';
import useToast from '@/v1/base/Toast/useToast';
import useDisclosure from '@/hooks/useDisclosure';
import useCreateBookGroupCommentMutation from '@/queries/group/useCreateBookGroupCommentMutation';
import { isAxiosErrorWithCustomCode } from '@/utils/helpers';
import { SERVICE_ERROR_MESSAGE } from '@/constants';
import useDeleteBookGroupMutation from '@/queries/group/useDeleteBookGroupMutation';

import SSRSafeSuspense from '@/components/SSRSafeSuspense';
import Button from '@/v1/base/Button';
import Menu from '@/v1/base/Menu';
import Modal from '@/v1/base/Modal';
import useToast from '@/v1/base/Toast/useToast';
import TopNavigation from '@/v1/base/TopNavigation';
import CommentDrawer from '@/v1/comment/CommentDrawer';

const NavigationContext = createContext({} as { groupId: number });

Expand Down Expand Up @@ -102,7 +108,52 @@ const MenuButton = () => {
const { groupId } = useContext(NavigationContext);
const { data: owner } = useBookGroupOwner(groupId);

return <>{owner.isMe && <IconHamburger />}</>;
const router = useRouter();

const deleteBookGroup = useDeleteBookGroupMutation();

const { show: showToast } = useToast();
const { isOpen, onClose, onOpen } = useDisclosure();

const handleModalConfirm = async () => {
await deleteBookGroup.mutateAsync(groupId, {
onSuccess: () => {
showToast({ type: 'success', message: '모임을 삭제했어요' });
router.replace('/group');
},
onError: error => {
if (isAxiosErrorWithCustomCode(error)) {
const { code } = error.response.data;
const message = SERVICE_ERROR_MESSAGE[code];
showToast({ type: 'error', message });
return;
}

showToast({ type: 'error', message: '잠시 후 다시 시도해주세요' });
},
});
};

return (
<>
{owner.isMe && (
<>
<Menu>
<Menu.Toggle />
<Menu.DropdownList>
<Menu.Item>수졍하기</Menu.Item>
<Menu.Item onSelect={onOpen}>삭제하기</Menu.Item>
</Menu.DropdownList>
</Menu>
<DeleteBookGroupModal
isOpen={isOpen}
onClose={onClose}
onConfirm={handleModalConfirm}
/>
</>
)}
</>
);
};

const WriteButton = () => {
Expand Down Expand Up @@ -173,6 +224,40 @@ const TitleSkeleton = () => (
<div className="h-[1.5rem] w-[40%] animate-pulse bg-black-400"></div>
);

const DeleteBookGroupModal = ({
isOpen,
onClose,
onConfirm,
}: {
isOpen: boolean;
onClose: () => void;
onConfirm?: () => void;
}) => {
const handleConfirm = () => {
onConfirm && onConfirm();
onClose();
};

return (
<Modal isOpen={isOpen} onClose={onClose}>
<div className="text-lg font-bold leading-loose">
모임을 정말 삭제할까요?
<p className="text-sm font-normal leading-tight text-black-500">
참여 중인 모임원이 있는 경우, 모임을 삭제할 수 없어요.
</p>
</div>
<div className="flex justify-end gap-[1rem]">
<Button onClick={onClose} fill={false} colorScheme="grey" size="small">
취소
</Button>
<Button onClick={handleConfirm} size="small">
확인
</Button>
</div>
</Modal>
);
};

const BackButtonType = (<BackButton />).type;
const TitleType = (<Title />).type;
const MenuButtonType = (<MenuButton />).type;
Expand Down

0 comments on commit efdb2c5

Please sign in to comment.