Skip to content

Commit

Permalink
회원 탈퇴 기능 (#146)
Browse files Browse the repository at this point in the history
  • Loading branch information
jijiseong authored Jul 13, 2024
1 parent a276207 commit 69a5b01
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 12 deletions.
15 changes: 15 additions & 0 deletions app/(route)/admin/user/_components/UserTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import {
TableRow,
} from '@app/_shadcn/components/ui/table';
import { Input } from '@app/_shadcn/components/ui/input';
import ButtonWithDialogCheck from '@app/_components/common/WithDialogCheck';
import useWithdrawalMutation from '@app/_hooks/apis/user/useWithdrawalMutation';
import RoleFilterSelect from './RoleFilterSelect';
import RoleUpdateSelect from './RoleUpdateSelect';

function UserTable() {
const roleFilter = useRecoilValue(roleState);
const { data } = useUserQuery(roleFilter);
const { mutate: withdrawMutate } = useWithdrawalMutation();

return (
<>
Expand All @@ -35,6 +38,7 @@ function UserTable() {
<TableHead>닉네임</TableHead>
<TableHead>아이디</TableHead>
<TableHead>이메일</TableHead>
<TableHead>회원 탈퇴</TableHead>
</TableRow>
</TableHeader>
<TableBody>
Expand All @@ -47,6 +51,17 @@ function UserTable() {
<TableCell>{nickname}</TableCell>
<TableCell>{id}</TableCell>
<TableCell>{email}</TableCell>
<TableCell>
<ButtonWithDialogCheck
variant="destructive"
title="회원 탈퇴"
description={`정말 ${id} 계정을 삭제하시겠어요?`}
confirmVariant="destructive"
onClick={() => withdrawMutate(id)}
>
탈퇴
</ButtonWithDialogCheck>
</TableCell>
</TableRow>
))}
</TableBody>
Expand Down
39 changes: 39 additions & 0 deletions app/(route)/mypage/_components/AccountSettingSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use client';

import ButtonWithDialogCheck from '@app/_components/common/WithDialogCheck';
import useWithdrawalMutation from '@app/_hooks/apis/user/useWithdrawalMutation';
import { Button } from '@app/_shadcn/components/ui/button';
import { myProfileState } from '@app/_store/permissionAtoms';
import { useRecoilValue } from 'recoil';

function AccountSettingSection() {
const { mutate: withdrawMutate } = useWithdrawalMutation();
const myProfile = useRecoilValue(myProfileState);

const onWithdrawalClick = () => {
if (!myProfile?.id) {
throw new Error('[개발자 문의 바람] myProfile id 상태를 확인해주세요.');
}
withdrawMutate(myProfile.id);
};

return (
<section className="flex justify-end gap-4">
<Button className="w-full" variant="secondary">
비밀번호 변경(개발 중이에요!)
</Button>
<ButtonWithDialogCheck
title="회원 탈퇴"
description="정말 탈퇴하시겠어요?"
className="w-full"
confirmVariant="destructive"
variant="destructive"
onClick={onWithdrawalClick}
>
회원 탈퇴
</ButtonWithDialogCheck>
</section>
);
}

export default AccountSettingSection;
5 changes: 1 addition & 4 deletions app/(route)/mypage/_components/ProfileForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ function ProfileForm({ children, defaultValues }: Props) {

return (
<FormProvider {...methods}>
<form
onSubmit={handleSubmit(onValid)}
className="small-center flex flex-col gap-12"
>
<form onSubmit={handleSubmit(onValid)} className="flex flex-col gap-12">
{children}
</form>
</FormProvider>
Expand Down
2 changes: 1 addition & 1 deletion app/(route)/mypage/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function Layout({ children }: Props) {
if (!isLoggedIn) return redirect(PATH.user.login.url);

return (
<div className="pb-[200px]">
<div className="small-center pb-[200px]">
<PageTitle pageTitle={PAGE_TITLE.myPage} />
{children}
</div>
Expand Down
20 changes: 13 additions & 7 deletions app/(route)/mypage/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import Link from 'next/link';
import { useRecoilValue } from 'recoil';
import { myProfileState } from '@app/_store/permissionAtoms';
import { Separator } from '@app/_shadcn/components/ui/separator';
import { PATH } from '@app/_constants/urls';
import { Button, buttonVariants } from '@app/_shadcn/components/ui/button';
import MyAvatarInput from './_components/MyAvatarInput';
import MyInfoSection from './_components/MyInfoSection';
import ProfileForm from './_components/ProfileForm';
import AccountSettingSection from './_components/AccountSettingSection';

function MyPage() {
const myProfile = useRecoilValue(myProfileState);
Expand All @@ -33,13 +35,17 @@ function MyPage() {
};

return (
<ProfileForm defaultValues={defaultValues}>
<MyAvatarInput />
<MyInfoSection />
<Button type="submit" size="lg">
저장
</Button>
</ProfileForm>
<>
<ProfileForm defaultValues={defaultValues}>
<MyAvatarInput />
<MyInfoSection />
<Button type="submit" size="lg">
저장
</Button>
</ProfileForm>
<Separator className="my-8" />
<AccountSettingSection />
</>
);
}

Expand Down
53 changes: 53 additions & 0 deletions app/_components/common/WithDialogCheck.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import {
Dialog,
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@app/_shadcn/components/ui/dialog';
import { Button, ButtonProps } from '@app/_shadcn/components/ui/button';

interface Props extends ButtonProps {
title: string;
description: string;
confirmVariant?: ButtonProps['variant'];
cancelVariant?: ButtonProps['variant'];
}

function ButtonWithDialogCheck({
title,
description,
onClick,
confirmVariant,
cancelVariant,
...props
}: Props) {
return (
<Dialog>
<DialogTrigger asChild>
<Button {...props} />
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
</DialogHeader>
<div>{description}</div>
<DialogFooter>
<DialogClose asChild>
<Button variant={cancelVariant || 'secondary'}>취소</Button>
</DialogClose>
<DialogClose asChild>
<Button variant={confirmVariant || 'default'} onClick={onClick}>
확인
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
);
}

export default ButtonWithDialogCheck;
28 changes: 28 additions & 0 deletions app/_hooks/apis/user/useWithdrawalMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import userService from '@app/_service/userService';
import { useToast } from '@app/_shadcn/components/ui/use-toast';
import { useMutation } from '@tanstack/react-query';

function useWithdrawalMutation() {
const { toast } = useToast();

return useMutation({
mutationFn: async (userId: string) => {
await userService.withdrawal(userId);
},

onSuccess: () =>
toast({
title: '회원 탈퇴',
description: '회원 탈퇴에 성공했어요.',
}),

onError: () =>
toast({
variant: 'destructive',
title: '회원 탈퇴',
description: '회원 탈퇴에 실패했어요.',
}),
});
}

export default useWithdrawalMutation;
7 changes: 7 additions & 0 deletions app/_service/userService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ class UserService extends Service {
);
return data;
}

async withdrawal(userId: string) {
const { data } = await this.axiosExtend.delete(
`/api/user/withdrawal/${userId}`,
);
return data;
}
}

const userService = new UserService();
Expand Down

0 comments on commit 69a5b01

Please sign in to comment.