From 0f60da0d3664354edb7bd0eec391b57da453b89b Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 11:29:23 +0000
Subject: [PATCH 01/14] [web] feat: Update middleware.ts to improve guest path
handling
---
middleware.ts | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/middleware.ts b/middleware.ts
index c61ab09a..b701287e 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -31,10 +31,12 @@ async function getAuth(request: NextRequest): Promise<{
};
}
-const allowdGuestPath = ['/tutorial', '/sign-in', '/sign-up', '/find-password', '/find-id'];
+const allowdOnlyGuestPath = ['/sign-in', '/sign-up', '/find-password', '/find-id'];
+const allowdGuestPath = ['/', '/tutorial', ...allowdOnlyGuestPath];
-function isAllowedGuestPath(path: string) {
- return allowdGuestPath.some((allowedPath) => path.startsWith(allowedPath));
+function isAllowedGuestPath(path: string, strict: boolean = false) {
+ const allowdPath = strict ? allowdOnlyGuestPath : allowdGuestPath;
+ return allowdPath.some((allowedPath) => path.startsWith(allowedPath));
}
export async function middleware(request: NextRequest) {
@@ -51,6 +53,10 @@ export async function middleware(request: NextRequest) {
if (auth.role === 'guest' && !isAllowedGuestPath(request.nextUrl.pathname)) {
return Response.redirect(new URL('/sign-in', request.url));
}
+
+ if (auth.role !== 'guest' && isAllowedGuestPath(request.nextUrl.pathname, true)) {
+ return Response.redirect(new URL('/my', request.url));
+ }
}
}
From ae407937ac5dd0818ca0cb89729125c98100af8f Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 11:36:58 +0000
Subject: [PATCH 02/14] feat: Add signOut function and redirect to sign-in page
---
app/business/user/user.command.ts | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/app/business/user/user.command.ts b/app/business/user/user.command.ts
index 33a1f833..a4f45fb8 100644
--- a/app/business/user/user.command.ts
+++ b/app/business/user/user.command.ts
@@ -15,6 +15,13 @@ import { cookies } from 'next/headers';
import { isValidation } from '@/app/utils/zod/validation.util';
import { redirect } from 'next/navigation';
+export async function signOut() {
+ cookies().delete('accessToken');
+ cookies().delete('refreshToken');
+
+ redirect('/sign-in');
+}
+
export async function validateToken(): Promise {
const accessToken = cookies().get('accessToken')?.value;
const refreshToken = cookies().get('refreshToken')?.value;
From 944399f76618fb928f31b97f340f7d4296a76398 Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 11:38:16 +0000
Subject: [PATCH 03/14] feat: Add SignOutButton component to UserInfoNavigator
---
app/ui/user/user-info-navigator/sign-out-button.tsx | 11 +++++++++++
.../user/user-info-navigator/user-info-navigator.tsx | 3 ++-
2 files changed, 13 insertions(+), 1 deletion(-)
create mode 100644 app/ui/user/user-info-navigator/sign-out-button.tsx
diff --git a/app/ui/user/user-info-navigator/sign-out-button.tsx b/app/ui/user/user-info-navigator/sign-out-button.tsx
new file mode 100644
index 00000000..3fbe6726
--- /dev/null
+++ b/app/ui/user/user-info-navigator/sign-out-button.tsx
@@ -0,0 +1,11 @@
+'use client';
+import { signOut } from '@/app/business/user/user.command';
+import Button from '../../view/atom/button/button';
+
+export default function SignOutButton() {
+ const handleSignOut = async () => {
+ await signOut();
+ };
+
+ return ;
+}
diff --git a/app/ui/user/user-info-navigator/user-info-navigator.tsx b/app/ui/user/user-info-navigator/user-info-navigator.tsx
index e975e6bc..dd927ee6 100644
--- a/app/ui/user/user-info-navigator/user-info-navigator.tsx
+++ b/app/ui/user/user-info-navigator/user-info-navigator.tsx
@@ -2,6 +2,7 @@ import Avatar from '../../view/atom/avatar/avatar';
import Button from '../../view/atom/button/button';
import { getUserInfo } from '@/app/business/user/user.query';
import Skeleton from '../../view/atom/skeleton';
+import SignOutButton from './sign-out-button';
export default async function UserInfoNavigator() {
const userInfo = await getUserInfo();
@@ -18,7 +19,7 @@ export default async function UserInfoNavigator() {
{userInfo.studentNumber}
-
+
From 4e0650015da57f8f268825155f5c846d234f71fc Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 11:41:47 +0000
Subject: [PATCH 04/14] feat: Add USER_DEELETE dialog key
---
app/store/dialog.ts | 1 +
app/utils/key/dialog.key.ts | 1 +
2 files changed, 2 insertions(+)
diff --git a/app/store/dialog.ts b/app/store/dialog.ts
index 5b554c53..941b2542 100644
--- a/app/store/dialog.ts
+++ b/app/store/dialog.ts
@@ -5,6 +5,7 @@ const initialState = {
[DIALOG_KEY.RESULT_CATEGORY]: false,
[DIALOG_KEY.DIALOG_TEST]: true,
[DIALOG_KEY.LECTURE_SEARCH]: false,
+ [DIALOG_KEY.USER_DEELETE]: false,
};
const dialogAtom = atom(initialState);
diff --git a/app/utils/key/dialog.key.ts b/app/utils/key/dialog.key.ts
index 93e3c913..f799df8e 100644
--- a/app/utils/key/dialog.key.ts
+++ b/app/utils/key/dialog.key.ts
@@ -2,6 +2,7 @@ export const DIALOG_KEY = {
RESULT_CATEGORY: 'RESULT_CATEGORY',
DIALOG_TEST: 'DIALOG_TEST',
LECTURE_SEARCH: 'LECTURE_SEARCH',
+ USER_DEELETE: 'USER_DEELETE',
} as const;
export type DialogKey = (typeof DIALOG_KEY)[keyof typeof DIALOG_KEY];
From f6a2f424d03507b8b1b7b7e7bc76177e6386e708 Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 11:45:19 +0000
Subject: [PATCH 05/14] feat: Add UserDeleteButton component to
UserInfoNavigator
---
app/ui/user/user-info-navigator/user-delete-button.tsx | 5 +++++
app/ui/user/user-info-navigator/user-info-navigator.tsx | 3 ++-
2 files changed, 7 insertions(+), 1 deletion(-)
create mode 100644 app/ui/user/user-info-navigator/user-delete-button.tsx
diff --git a/app/ui/user/user-info-navigator/user-delete-button.tsx b/app/ui/user/user-info-navigator/user-delete-button.tsx
new file mode 100644
index 00000000..56aa084c
--- /dev/null
+++ b/app/ui/user/user-info-navigator/user-delete-button.tsx
@@ -0,0 +1,5 @@
+import Button from '../../view/atom/button/button';
+
+export default function UserDeleteButton() {
+ return ;
+}
diff --git a/app/ui/user/user-info-navigator/user-info-navigator.tsx b/app/ui/user/user-info-navigator/user-info-navigator.tsx
index dd927ee6..a485b98f 100644
--- a/app/ui/user/user-info-navigator/user-info-navigator.tsx
+++ b/app/ui/user/user-info-navigator/user-info-navigator.tsx
@@ -3,6 +3,7 @@ import Button from '../../view/atom/button/button';
import { getUserInfo } from '@/app/business/user/user.query';
import Skeleton from '../../view/atom/skeleton';
import SignOutButton from './sign-out-button';
+import UserDeleteButton from './user-delete-button';
export default async function UserInfoNavigator() {
const userInfo = await getUserInfo();
@@ -22,7 +23,7 @@ export default async function UserInfoNavigator() {
-
+
);
From 1ccb7b37e99a6736224da64ea0ae61e9e5e8633f Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 11:47:28 +0000
Subject: [PATCH 06/14] feat: Add UserDeleteModal component
---
app/ui/user/user-info-navigator/user-delete-modal.tsx | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 app/ui/user/user-info-navigator/user-delete-modal.tsx
diff --git a/app/ui/user/user-info-navigator/user-delete-modal.tsx b/app/ui/user/user-info-navigator/user-delete-modal.tsx
new file mode 100644
index 00000000..fe89de34
--- /dev/null
+++ b/app/ui/user/user-info-navigator/user-delete-modal.tsx
@@ -0,0 +1,10 @@
+import { DIALOG_KEY } from '@/app/utils/key/dialog.key';
+import Modal from '../../view/molecule/modal/modal';
+
+export default function UserDeleteModal() {
+ return (
+
+
+
+ );
+}
From 5863c3bc774dd3e93b7f4d7028d00a04c492e9eb Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 11:49:48 +0000
Subject: [PATCH 07/14] feat: Add FloatingComponentContainer to MyPage
---
app/(sub-page)/my/floating-component-container.tsx | 9 +++++++++
app/(sub-page)/my/page.tsx | 2 ++
2 files changed, 11 insertions(+)
create mode 100644 app/(sub-page)/my/floating-component-container.tsx
diff --git a/app/(sub-page)/my/floating-component-container.tsx b/app/(sub-page)/my/floating-component-container.tsx
new file mode 100644
index 00000000..7be873eb
--- /dev/null
+++ b/app/(sub-page)/my/floating-component-container.tsx
@@ -0,0 +1,9 @@
+import UserDeleteModal from '@/app/ui/user/user-info-navigator/user-delete-modal';
+
+export default function FloatingComponentContainer() {
+ return (
+ <>
+
+ >
+ );
+}
diff --git a/app/(sub-page)/my/page.tsx b/app/(sub-page)/my/page.tsx
index a1bf7f11..4cfea195 100644
--- a/app/(sub-page)/my/page.tsx
+++ b/app/(sub-page)/my/page.tsx
@@ -5,6 +5,7 @@ import ContentContainer from '@/app/ui/view/atom/content-container';
import Drawer from '@/app/ui/view/molecule/drawer/drawer';
import { DIALOG_KEY } from '@/app/utils/key/dialog.key';
import { Suspense } from 'react';
+import FloatingComponentContainer from './floating-component-container';
export default function MyPage() {
return (
@@ -22,6 +23,7 @@ export default function MyPage() {
+
>
);
}
From f125a640191c2ffb56a0d05058f46c1e364bab8b Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 11:53:08 +0000
Subject: [PATCH 08/14] feat: Add user delete dialog and handle toggle
---
.../user/user-info-navigator/user-delete-button.tsx | 11 ++++++++++-
app/ui/user/user-info-navigator/user-delete-modal.tsx | 2 +-
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/app/ui/user/user-info-navigator/user-delete-button.tsx b/app/ui/user/user-info-navigator/user-delete-button.tsx
index 56aa084c..ed4dad76 100644
--- a/app/ui/user/user-info-navigator/user-delete-button.tsx
+++ b/app/ui/user/user-info-navigator/user-delete-button.tsx
@@ -1,5 +1,14 @@
+'use client';
import Button from '../../view/atom/button/button';
+import { DIALOG_KEY } from '@/app/utils/key/dialog.key';
+import useDialog from '@/app/hooks/useDialog';
export default function UserDeleteButton() {
- return ;
+ const { toggle } = useDialog(DIALOG_KEY.USER_DEELETE);
+
+ const handleModalToggle = () => {
+ toggle();
+ };
+
+ return ;
}
diff --git a/app/ui/user/user-info-navigator/user-delete-modal.tsx b/app/ui/user/user-info-navigator/user-delete-modal.tsx
index fe89de34..7147502f 100644
--- a/app/ui/user/user-info-navigator/user-delete-modal.tsx
+++ b/app/ui/user/user-info-navigator/user-delete-modal.tsx
@@ -4,7 +4,7 @@ import Modal from '../../view/molecule/modal/modal';
export default function UserDeleteModal() {
return (
-
+ test
);
}
From 804fa9530004f29a2c4b9467a3d66b7d97d60929 Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 12:19:58 +0000
Subject: [PATCH 09/14] refactor: Refactor user-handler.mock.ts to add
devModeAuthGuard function
---
app/mocks/handlers/user-handler.mock.ts | 34 ++++++++++++++++++-------
1 file changed, 25 insertions(+), 9 deletions(-)
diff --git a/app/mocks/handlers/user-handler.mock.ts b/app/mocks/handlers/user-handler.mock.ts
index af26d9d7..7aa98163 100644
--- a/app/mocks/handlers/user-handler.mock.ts
+++ b/app/mocks/handlers/user-handler.mock.ts
@@ -9,6 +9,7 @@ import {
UserInfoResponse,
} from '@/app/business/user/user.type';
import { ErrorResponseData } from '@/app/utils/http/http-error-handler';
+import { StrictRequest } from 'msw';
function mockDecryptToken(token: string) {
if (token === 'fake-access-token') {
@@ -21,6 +22,21 @@ function mockDecryptToken(token: string) {
};
}
+export const devModeAuthGuard = (request: StrictRequest) => {
+ if (process.env.NODE_ENV === 'development') {
+ const accessToken = request.headers.get('Authorization')?.replace('Bearer ', '');
+ if (accessToken === 'undefined' || !accessToken) {
+ throw new Error('Unauthorized');
+ }
+
+ return mockDecryptToken(accessToken);
+ } else {
+ return {
+ authId: 'admin',
+ };
+ }
+};
+
export const userHandlers = [
http.get(`${API_PATH.auth}/failure`, async ({ request }) => {
await delay(500);
@@ -32,19 +48,19 @@ export const userHandlers = [
});
}),
http.get(`${API_PATH.user}`, async ({ request }) => {
- const accessToken = request.headers.get('Authorization')?.replace('Bearer ', '');
- if (accessToken === 'undefined' || !accessToken) {
- return HttpResponse.json({ status: 401, message: 'Unauthorized' }, { status: 401 });
- }
+ try {
+ const { authId } = devModeAuthGuard(request);
+ const userInfo = mockDatabase.getUserInfo(authId);
+ await delay(3000);
- const userInfo = mockDatabase.getUserInfo(mockDecryptToken(accessToken).authId);
- await delay(3000);
+ if (!userInfo) {
+ return HttpResponse.json({ status: 401, message: 'Unauthorized' }, { status: 401 });
+ }
- if (!userInfo) {
+ return HttpResponse.json(userInfo);
+ } catch {
return HttpResponse.json({ status: 401, message: 'Unauthorized' }, { status: 401 });
}
-
- return HttpResponse.json(userInfo);
}),
http.post(`${API_PATH.user}/sign-up`, async ({ request }) => {
const userData = await request.json();
From d4e50cc23d84afd2c9a0f9291f16f78f6d591ba0 Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 12:20:26 +0000
Subject: [PATCH 10/14] feat: Add unit tests for UserInfoNavigator component
and update mock database
---
.../ui/user/user-info-navigator.test.tsx | 21 +++++++++++++++++++
app/mocks/db.mock.ts | 4 ++--
2 files changed, 23 insertions(+), 2 deletions(-)
create mode 100644 app/__test__/ui/user/user-info-navigator.test.tsx
diff --git a/app/__test__/ui/user/user-info-navigator.test.tsx b/app/__test__/ui/user/user-info-navigator.test.tsx
new file mode 100644
index 00000000..032bd6ec
--- /dev/null
+++ b/app/__test__/ui/user/user-info-navigator.test.tsx
@@ -0,0 +1,21 @@
+import '@testing-library/jest-dom';
+import UserInfoNavigator from '@/app/ui/user/user-info-navigator/user-info-navigator';
+import { render, screen } from '@testing-library/react';
+
+jest.mock('next/headers', () => ({
+ cookies: jest.fn().mockReturnValue({
+ get: jest.fn().mockReturnValue({
+ value: 'fake-access-token',
+ }),
+ }),
+}));
+
+describe('UserInfoNavigator', () => {
+ it('UserInfoNavigator를 렌더링한다.', async () => {
+ render(await UserInfoNavigator());
+
+ expect(await screen.findByText(/모킹이/i)).toBeInTheDocument();
+ expect(await screen.findByText(/융합소프트웨어/i)).toBeInTheDocument();
+ expect(await screen.findByText(/60000000/i)).toBeInTheDocument();
+ });
+});
diff --git a/app/mocks/db.mock.ts b/app/mocks/db.mock.ts
index 302d1615..a611b6de 100644
--- a/app/mocks/db.mock.ts
+++ b/app/mocks/db.mock.ts
@@ -66,7 +66,7 @@ export const mockDatabase: MockDatabaseAction = {
{
...user,
isSumbitted: false,
- major: '융소입니다',
+ major: '융합소프트웨어',
name: '모킹이2',
},
];
@@ -105,7 +105,7 @@ const initialState: MockDatabaseState = {
studentNumber: '60000000',
engLv: 'ENG12',
isSumbitted: false,
- major: '융소입니다',
+ major: '융합소프트웨어',
name: '모킹이',
},
],
From eca405fe82ffb022311a236659a4389e7694472f Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 12:31:20 +0000
Subject: [PATCH 11/14] feat: Update UserDeleteModal component to improve UI
and add user delete functionality
---
.../user-info-navigator/user-delete-modal.tsx | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/app/ui/user/user-info-navigator/user-delete-modal.tsx b/app/ui/user/user-info-navigator/user-delete-modal.tsx
index 7147502f..fd8ac051 100644
--- a/app/ui/user/user-info-navigator/user-delete-modal.tsx
+++ b/app/ui/user/user-info-navigator/user-delete-modal.tsx
@@ -1,10 +1,25 @@
import { DIALOG_KEY } from '@/app/utils/key/dialog.key';
import Modal from '../../view/molecule/modal/modal';
+import Form from '../../view/molecule/form';
+import { deleteUser } from '@/app/business/user/user.command';
export default function UserDeleteModal() {
return (
- test
+
+
회원 탈퇴
+
+
+ 회원탈퇴를 진행하시겠습니까? 탈퇴를 진행하면더 비밀번호 입력이 필요합니다.
+
+
+
+
+
+
+
정보를 누락하여 서비스를 이용해 주셔서 감사합니다.
+
);
}
From 8bbc2f5fe1acdbff5af2be6228001e863652229f Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 12:41:20 +0000
Subject: [PATCH 12/14] feat: add UserDeleteRequestBody interface
---
app/business/user/user.command.ts | 40 +++++++++++++++++++++++++++++++
app/business/user/user.type.ts | 4 ++++
2 files changed, 44 insertions(+)
diff --git a/app/business/user/user.command.ts b/app/business/user/user.command.ts
index a4f45fb8..4e01b2f2 100644
--- a/app/business/user/user.command.ts
+++ b/app/business/user/user.command.ts
@@ -22,6 +22,46 @@ export async function signOut() {
redirect('/sign-in');
}
+export async function deleteUser(prevState: FormState, formData: FormData): Promise {
+ // const body: SignUpRequestBody = {
+ // authId,
+ // };
+
+ // try {
+ // const response = await fetch(`${API_PATH.user}/sign-up`, {
+ // method: 'POST',
+ // headers: {
+ // 'Content-Type': 'application/json',
+ // },
+ // body: JSON.stringify(body),
+ // });
+
+ // const result = await response.json();
+
+ // httpErrorHandler(response, result);
+ // } catch (error) {
+ // if (error instanceof BadRequestError) {
+ // // 잘못된 요청 처리 로직
+ // return {
+ // isSuccess: false,
+ // isFailure: true,
+ // validationError: {},
+ // message: error.message,
+ // };
+ // } else {
+ // // 나머지 에러는 더 상위 수준에서 처리
+ // throw error;
+ // }
+ // }
+
+ return {
+ isSuccess: true,
+ isFailure: false,
+ validationError: {},
+ message: '회원가입이 완료되었습니다.',
+ };
+}
+
export async function validateToken(): Promise {
const accessToken = cookies().get('accessToken')?.value;
const refreshToken = cookies().get('refreshToken')?.value;
diff --git a/app/business/user/user.type.ts b/app/business/user/user.type.ts
index 3f18be25..3014a628 100644
--- a/app/business/user/user.type.ts
+++ b/app/business/user/user.type.ts
@@ -16,6 +16,10 @@ export interface SignInRequestBody {
password: string;
}
+export interface UserDeleteRequestBody {
+ password: string;
+}
+
export type SignInResponse = z.infer;
export type UserInfoResponse = z.infer;
From 259ed1036c784fb18ee6692848f3edca311a98cb Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 12:41:42 +0000
Subject: [PATCH 13/14] feat: Add deleteUser function to mockDatabase and
update user-handler.mock.ts
---
app/mocks/db.mock.ts | 9 +++++++++
app/mocks/handlers/user-handler.mock.ts | 19 ++++++++++++++++++-
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/app/mocks/db.mock.ts b/app/mocks/db.mock.ts
index a611b6de..7aafa81e 100644
--- a/app/mocks/db.mock.ts
+++ b/app/mocks/db.mock.ts
@@ -28,6 +28,7 @@ type MockDatabaseAction = {
createUser: (user: SignUpRequestBody) => boolean;
signIn: (userData: SignInRequestBody) => boolean;
getUserInfo: (authId: string) => UserInfoResponse;
+ deleteUser: (authId: string, password: string) => boolean;
};
export const mockDatabase: MockDatabaseAction = {
@@ -93,6 +94,14 @@ export const mockDatabase: MockDatabaseAction = {
isSumbitted: user.isSumbitted,
};
},
+ deleteUser: (authId: string, password: string) => {
+ const user = mockDatabaseStore.users.find((u) => u.authId === authId && u.password === password);
+ if (user) {
+ mockDatabaseStore.users = mockDatabaseStore.users.filter((u) => u.authId !== authId);
+ return true;
+ }
+ return false;
+ },
};
const initialState: MockDatabaseState = {
diff --git a/app/mocks/handlers/user-handler.mock.ts b/app/mocks/handlers/user-handler.mock.ts
index 7aa98163..d9a52164 100644
--- a/app/mocks/handlers/user-handler.mock.ts
+++ b/app/mocks/handlers/user-handler.mock.ts
@@ -7,6 +7,7 @@ import {
SignInResponse,
ValidateTokenResponse,
UserInfoResponse,
+ UserDeleteRequestBody,
} from '@/app/business/user/user.type';
import { ErrorResponseData } from '@/app/utils/http/http-error-handler';
import { StrictRequest } from 'msw';
@@ -22,7 +23,7 @@ function mockDecryptToken(token: string) {
};
}
-export const devModeAuthGuard = (request: StrictRequest) => {
+export const devModeAuthGuard = (request: StrictRequest) => {
if (process.env.NODE_ENV === 'development') {
const accessToken = request.headers.get('Authorization')?.replace('Bearer ', '');
if (accessToken === 'undefined' || !accessToken) {
@@ -47,6 +48,22 @@ export const userHandlers = [
accessToken: 'fake-access-token',
});
}),
+ http.delete(`${API_PATH.user}/delete-me`, async ({ request }) => {
+ try {
+ const { authId } = devModeAuthGuard(request);
+ const { password } = await request.json();
+
+ const result = mockDatabase.deleteUser(authId, password);
+
+ if (result) {
+ return HttpResponse.json({ status: 200 });
+ } else {
+ return HttpResponse.json({ status: 400, message: '비밀번호가 일치하지 않습니다' }, { status: 400 });
+ }
+ } catch {
+ return HttpResponse.json({ status: 401, message: 'Unauthorized' }, { status: 401 });
+ }
+ }),
http.get(`${API_PATH.user}`, async ({ request }) => {
try {
const { authId } = devModeAuthGuard(request);
From 364e3127137feeca04151a68d33ac7697180b47c Mon Sep 17 00:00:00 2001
From: SeonghunYang
Date: Thu, 25 Apr 2024 13:01:37 +0000
Subject: [PATCH 14/14] feat: add deleteUser function and update
UserDeleteModal component
---
app/business/user/user.command.ts | 64 +++++++++----------
.../user-info-navigator/user-delete-modal.tsx | 3 +-
2 files changed, 34 insertions(+), 33 deletions(-)
diff --git a/app/business/user/user.command.ts b/app/business/user/user.command.ts
index 4e01b2f2..6c234392 100644
--- a/app/business/user/user.command.ts
+++ b/app/business/user/user.command.ts
@@ -2,7 +2,7 @@
import { FormState } from '@/app/ui/view/molecule/form/form-root';
import { API_PATH } from '../api-path';
-import { SignUpRequestBody, SignInRequestBody, ValidateTokenResponse } from './user.type';
+import { SignUpRequestBody, SignInRequestBody, ValidateTokenResponse, UserDeleteRequestBody } from './user.type';
import { httpErrorHandler } from '@/app/utils/http/http-error-handler';
import { BadRequestError } from '@/app/utils/http/http-error';
import {
@@ -23,42 +23,42 @@ export async function signOut() {
}
export async function deleteUser(prevState: FormState, formData: FormData): Promise {
- // const body: SignUpRequestBody = {
- // authId,
- // };
-
- // try {
- // const response = await fetch(`${API_PATH.user}/sign-up`, {
- // method: 'POST',
- // headers: {
- // 'Content-Type': 'application/json',
- // },
- // body: JSON.stringify(body),
- // });
-
- // const result = await response.json();
-
- // httpErrorHandler(response, result);
- // } catch (error) {
- // if (error instanceof BadRequestError) {
- // // 잘못된 요청 처리 로직
- // return {
- // isSuccess: false,
- // isFailure: true,
- // validationError: {},
- // message: error.message,
- // };
- // } else {
- // // 나머지 에러는 더 상위 수준에서 처리
- // throw error;
- // }
- // }
+ try {
+ const body: UserDeleteRequestBody = {
+ password: formData.get('password') as string,
+ };
+
+ const response = await fetch(`${API_PATH.user}/delete-me`, {
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: `Bearer ${cookies().get('accessToken')?.value}`,
+ },
+ body: JSON.stringify(body),
+ });
+ const result = await response.json();
+
+ httpErrorHandler(response, result);
+ } catch (error) {
+ if (error instanceof BadRequestError) {
+ // 잘못된 요청 처리 로직
+ return {
+ isSuccess: false,
+ isFailure: true,
+ validationError: {},
+ message: error.message,
+ };
+ } else {
+ // 나머지 에러는 더 상위 수준에서 처리
+ throw error;
+ }
+ }
return {
isSuccess: true,
isFailure: false,
validationError: {},
- message: '회원가입이 완료되었습니다.',
+ message: '회원 탈퇴가 완료되었습니다.',
};
}
diff --git a/app/ui/user/user-info-navigator/user-delete-modal.tsx b/app/ui/user/user-info-navigator/user-delete-modal.tsx
index fd8ac051..2e18ad48 100644
--- a/app/ui/user/user-info-navigator/user-delete-modal.tsx
+++ b/app/ui/user/user-info-navigator/user-delete-modal.tsx
@@ -1,3 +1,4 @@
+'use client';
import { DIALOG_KEY } from '@/app/utils/key/dialog.key';
import Modal from '../../view/molecule/modal/modal';
import Form from '../../view/molecule/form';
@@ -13,7 +14,7 @@ export default function UserDeleteModal() {
회원탈퇴를 진행하시겠습니까? 탈퇴를 진행하면더 비밀번호 입력이 필요합니다.
-