From b5c78c188d3cb832f4ff6d0e374f5df112c7d310 Mon Sep 17 00:00:00 2001 From: yougyung Date: Mon, 6 May 2024 14:18:49 +0900 Subject: [PATCH 01/12] fix: change UserInfo fetch api --- app/business/user/user.validation.ts | 11 ++------- app/mocks/db.mock.ts | 23 ++++--------------- app/ui/user/user-credit-result.tsx | 5 ++-- .../user-info-navigator.tsx | 4 ++-- 4 files changed, 11 insertions(+), 32 deletions(-) diff --git a/app/business/user/user.validation.ts b/app/business/user/user.validation.ts index ae8aaafd..b5b73117 100644 --- a/app/business/user/user.validation.ts +++ b/app/business/user/user.validation.ts @@ -5,15 +5,8 @@ import { z } from 'zod'; export const UserInfoResponseSchema = z.object({ studentNumber: z.string(), studentName: z.string(), - completionDivision: z.array( - z.object({ - majorType: z.string(), - major: z.string(), - }), - ), - totalCredit: z.number(), - takenCredit: z.number(), - graduated: z.boolean(), + major: z.string(), + isSumbitted: z.boolean(), }); export const ValidateTokenResponseSchema = z.object({ diff --git a/app/mocks/db.mock.ts b/app/mocks/db.mock.ts index 6ee804cc..307e9a58 100644 --- a/app/mocks/db.mock.ts +++ b/app/mocks/db.mock.ts @@ -92,30 +92,15 @@ export const mockDatabase: MockDatabaseAction = { return { studentNumber: '', studentName: '', - completionDivision: [ - { - majorType: '', - major: '', - }, - ], - totalCredit: 0, - takenCredit: 0, - graduated: false, + major: '', + isSumbitted: false, }; } return { studentNumber: user.studentNumber, studentName: user.name, - completionDivision: [ - { - majorType: 'primary', - major: '디지털컨텐츠디자인학과', - }, - ], - - totalCredit: 132, - takenCredit: 50, - graduated: false, + major: user.major, + isSumbitted: user.isSumbitted, }; }, }; diff --git a/app/ui/user/user-credit-result.tsx b/app/ui/user/user-credit-result.tsx index a9b45591..9d79e497 100644 --- a/app/ui/user/user-credit-result.tsx +++ b/app/ui/user/user-credit-result.tsx @@ -1,10 +1,11 @@ -import { getUserInfo } from '@/app/business/user/user.query'; +import { fetchResultUserInfo } from '@/app/business/user/user.query'; import books from '@/public/assets/books.png'; import pencil from '@/public/assets/pencil.png'; import Image from 'next/image'; export default async function UserCreditResult() { - const userInfo = await getUserInfo(); + const userInfo = await fetchResultUserInfo(); + 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 56caea14..8363273f 100644 --- a/app/ui/user/user-info-navigator/user-info-navigator.tsx +++ b/app/ui/user/user-info-navigator/user-info-navigator.tsx @@ -1,9 +1,9 @@ import Avatar from '../../view/atom/avatar/avatar'; import Button from '../../view/atom/button/button'; -import { getUserInfo } from '@/app/business/user/user.query'; +import { fetchResultUserInfo } from '@/app/business/user/user.query'; export default async function UserInfoNavigator() { - const userInfo = await getUserInfo(); + const userInfo = await fetchResultUserInfo(); return (
From 798184553239c5775b0072eb3e18b0820fc21066 Mon Sep 17 00:00:00 2001 From: yougyung Date: Wed, 8 May 2024 10:48:45 +0900 Subject: [PATCH 02/12] fix: remove getUser MockDatabaseAction --- app/mocks/db.mock.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/mocks/db.mock.ts b/app/mocks/db.mock.ts index 307e9a58..ebc7692c 100644 --- a/app/mocks/db.mock.ts +++ b/app/mocks/db.mock.ts @@ -29,7 +29,6 @@ type MockDatabaseAction = { getResultCategoryDetailInfo: () => ResultCategoryDetailResponse; addTakenLecture: (lectureId: number) => boolean; deleteTakenLecture: (lectureId: number) => boolean; - getUser: (authId: string) => MockUser | undefined; createUser: (user: SignUpRequestBody) => boolean; signIn: (userData: SignInRequestBody) => boolean; getCredits: () => CreditResponse[]; @@ -65,7 +64,6 @@ export const mockDatabase: MockDatabaseAction = { return true; }, getResultCategoryDetailInfo: () => mockDatabaseStore.resultCategoryDetailInfo, - getUser: (authId: string) => mockDatabaseStore.users.find((user) => user.authId === authId), getCredits: () => mockDatabaseStore.credits, createUser: (user: SignUpRequestBody) => { if (mockDatabaseStore.users.find((u) => u.authId === user.authId || u.studentNumber === user.studentNumber)) { From 2a5541f3c9ed6dc6c54297ba11c5c1dd2b347cda Mon Sep 17 00:00:00 2001 From: yougyung Date: Thu, 9 May 2024 12:40:29 +0900 Subject: [PATCH 03/12] fix: remove resultUserInfo --- app/business/api-path.ts | 1 - app/business/result/result.query.ts | 9 ---- app/business/user/user.query.ts | 18 ------- app/mocks/data.mock.ts | 2 +- app/mocks/db.mock.ts | 50 ++++++------------- app/mocks/handlers/user-handler.mock.ts | 19 +------ app/ui/user/user-credit-result.tsx | 4 +- app/ui/user/user-info-card/user-info-card.tsx | 5 +- .../user-info-navigator.tsx | 7 ++- 9 files changed, 25 insertions(+), 90 deletions(-) diff --git a/app/business/api-path.ts b/app/business/api-path.ts index ec95e279..c17bf5f9 100644 --- a/app/business/api-path.ts +++ b/app/business/api-path.ts @@ -7,7 +7,6 @@ export const API_PATH = { takenLectures: `${BASE_URL}/taken-lectures`, resultCategoryDetailInfo: `${BASE_URL}/result-category-detail-info`, user: `${BASE_URL}/users`, - resultUserInfo: `${BASE_URL}/resultUserInfo`, credits: `${BASE_URL}/credits`, auth: `${BASE_URL}/auth`, lectures: `${BASE_URL}/lectures`, diff --git a/app/business/result/result.query.ts b/app/business/result/result.query.ts index a718881e..de990988 100644 --- a/app/business/result/result.query.ts +++ b/app/business/result/result.query.ts @@ -25,15 +25,6 @@ export interface Major { major: string; } -export interface ResultUserInfo { - studentNumber: string; - studentName: string; - completionDivision: Major[]; - totalCredit: number; - takenCredit: number; - graduated: boolean; -} - export interface CreditResponse { category: keyof typeof RESULT_CATEGORY; totalCredit: number; diff --git a/app/business/user/user.query.ts b/app/business/user/user.query.ts index 88d666da..6704e6f7 100644 --- a/app/business/user/user.query.ts +++ b/app/business/user/user.query.ts @@ -4,7 +4,6 @@ import { UserInfoResponse } from './user.type'; import { cookies } from 'next/headers'; import { isValidation } from '@/app/utils/zod/validation.util'; import { UserInfoResponseSchema } from './user.validation'; -import { ResultUserInfo } from '../result/result.query'; export async function getUserInfo(): Promise { try { @@ -27,20 +26,3 @@ export async function getUserInfo(): Promise { throw error; } } - -export async function fetchResultUserInfo(): Promise { - try { - const response = await fetch(API_PATH.resultUserInfo, { - headers: { - Authorization: `Bearer ${cookies().get('accessToken')?.value}`, - }, - }); - - const result = await response.json(); - - httpErrorHandler(response, result); - return result; - } catch (error) { - throw error; - } -} diff --git a/app/mocks/data.mock.ts b/app/mocks/data.mock.ts index 2deb61d8..194b460a 100644 --- a/app/mocks/data.mock.ts +++ b/app/mocks/data.mock.ts @@ -69,7 +69,7 @@ export const takenLectures = JSON.parse(`{ ] }`); -export const resultUserInfo = JSON.parse(`{ +export const userInfo = JSON.parse(`{ "studentNumber": "60181666", "studentName": "장진욱", "completionDivision" : [ diff --git a/app/mocks/db.mock.ts b/app/mocks/db.mock.ts index ebc7692c..9b6db320 100644 --- a/app/mocks/db.mock.ts +++ b/app/mocks/db.mock.ts @@ -1,45 +1,34 @@ import { SearchLectures } from '../business/lecture/search-lecture.query'; import { TakenLectures } from '../business/lecture/taken-lecture.query'; -import { CreditResponse, ResultCategoryDetailResponse, ResultUserInfo } from '../business/result/result.query'; -import { SignUpRequestBody, SignInRequestBody, UserInfoResponse } from '../business/user/user.type'; -import { takenLectures, resultCategoryDetailInfo, resultUserInfo, credits, searchLectures } from './data.mock'; - -interface MockUser { - authId: string; - password: string; - studentNumber: string; - engLv: string; - major: string; - isSumbitted: boolean; - name: string; -} +import { CreditResponse, ResultCategoryDetailResponse } from '../business/result/result.query'; +import { SignUpRequestBody, SignInRequestBody, MockUser, User, Init } from '../business/user/user.type'; +import { takenLectures, credits, searchLectures, userInfo, resultCategoryDetailInfo } from './data.mock'; interface MockDatabaseState { takenLectures: TakenLectures; resultCategoryDetailInfo: ResultCategoryDetailResponse; - resultUserInfo: ResultUserInfo; credits: CreditResponse[]; users: MockUser[]; searchLectures: SearchLectures; + userInfo: User; } type MockDatabaseAction = { getTakenLectures: () => TakenLectures; getSearchLectures: () => SearchLectures; - getResultCategoryDetailInfo: () => ResultCategoryDetailResponse; addTakenLecture: (lectureId: number) => boolean; deleteTakenLecture: (lectureId: number) => boolean; createUser: (user: SignUpRequestBody) => boolean; signIn: (userData: SignInRequestBody) => boolean; getCredits: () => CreditResponse[]; - getUserInfo: (authId: string) => UserInfoResponse; - getResultUserInfo: () => ResultUserInfo; + getUserInfo: (authId: string) => User | Init; + getResultCategoryDetailInfo: () => ResultCategoryDetailResponse; }; export const mockDatabase: MockDatabaseAction = { getTakenLectures: () => mockDatabaseStore.takenLectures, - getResultUserInfo: () => mockDatabaseStore.resultUserInfo, getSearchLectures: () => mockDatabaseStore.searchLectures, + getResultCategoryDetailInfo: () => mockDatabaseStore.resultCategoryDetailInfo, deleteTakenLecture: (lectureId) => { if (mockDatabaseStore.takenLectures.takenLectures.find((lecture) => lecture.id === lectureId)) { mockDatabaseStore.takenLectures.takenLectures = mockDatabaseStore.takenLectures.takenLectures.filter( @@ -63,7 +52,7 @@ export const mockDatabase: MockDatabaseAction = { ]; return true; }, - getResultCategoryDetailInfo: () => mockDatabaseStore.resultCategoryDetailInfo, + getCredits: () => mockDatabaseStore.credits, createUser: (user: SignUpRequestBody) => { if (mockDatabaseStore.users.find((u) => u.authId === user.authId || u.studentNumber === user.studentNumber)) { @@ -73,9 +62,6 @@ export const mockDatabase: MockDatabaseAction = { ...mockDatabaseStore.users, { ...user, - isSumbitted: false, - major: '융소입니다', - name: '모킹이2', }, ]; return true; @@ -89,17 +75,14 @@ export const mockDatabase: MockDatabaseAction = { if (!user) { return { studentNumber: '', - studentName: '', - major: '', - isSumbitted: false, + studentName: null, + completionDivision: null, + totalCredit: null, + takenCredit: null, + graduated: null, }; } - return { - studentNumber: user.studentNumber, - studentName: user.name, - major: user.major, - isSumbitted: user.isSumbitted, - }; + return mockDatabaseStore.userInfo; }, }; @@ -107,19 +90,16 @@ const initialState: MockDatabaseState = { takenLectures: takenLectures, resultCategoryDetailInfo: resultCategoryDetailInfo, credits: credits, - resultUserInfo: resultUserInfo, users: [ { authId: 'admin', password: 'admin', studentNumber: '60000000', engLv: 'ENG12', - isSumbitted: false, - major: '융소입니다', - name: '모킹이', }, ], searchLectures: searchLectures, + userInfo: userInfo, }; function initStore(): MockDatabaseState { diff --git a/app/mocks/handlers/user-handler.mock.ts b/app/mocks/handlers/user-handler.mock.ts index e045474a..72a00b48 100644 --- a/app/mocks/handlers/user-handler.mock.ts +++ b/app/mocks/handlers/user-handler.mock.ts @@ -9,7 +9,6 @@ import { UserInfoResponse, } from '@/app/business/user/user.type'; import { ErrorResponseData } from '@/app/utils/http/http-error-handler'; -import { ResultUserInfo } from '@/app/business/result/result.query'; function mockDecryptToken(token: string) { if (token === 'fake-access-token') { @@ -32,12 +31,11 @@ export const userHandlers = [ accessToken: 'fake-access-token', }); }), - http.get(`${API_PATH.user}`, async ({ request }) => { + 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 }); } - const userInfo = mockDatabase.getUserInfo(mockDecryptToken(accessToken).authId); await delay(3000); @@ -47,24 +45,9 @@ export const userHandlers = [ return HttpResponse.json(userInfo); }), - http.get(API_PATH.resultUserInfo, async ({ request }) => { - const accessToken = request.headers.get('Authorization')?.replace('Bearer ', ''); - if (accessToken === 'undefined' || !accessToken) { - return HttpResponse.json({ status: 401, message: 'Unauthorized' }, { status: 401 }); - } - - const userInfo = mockDatabase.getResultUserInfo(); - await delay(2000); - if (!userInfo) { - 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(); - const isSuccess = mockDatabase.createUser(userData); await delay(500); diff --git a/app/ui/user/user-credit-result.tsx b/app/ui/user/user-credit-result.tsx index 9d79e497..95d02672 100644 --- a/app/ui/user/user-credit-result.tsx +++ b/app/ui/user/user-credit-result.tsx @@ -1,10 +1,10 @@ -import { fetchResultUserInfo } from '@/app/business/user/user.query'; +import { getUserInfo } from '@/app/business/user/user.query'; import books from '@/public/assets/books.png'; import pencil from '@/public/assets/pencil.png'; import Image from 'next/image'; export default async function UserCreditResult() { - const userInfo = await fetchResultUserInfo(); + const userInfo = await getUserInfo(); return (
diff --git a/app/ui/user/user-info-card/user-info-card.tsx b/app/ui/user/user-info-card/user-info-card.tsx index 6fc977de..04719bd2 100644 --- a/app/ui/user/user-info-card/user-info-card.tsx +++ b/app/ui/user/user-info-card/user-info-card.tsx @@ -1,7 +1,8 @@ import { getPercentage } from '@/app/utils/chart.util'; import PieChart from '../../view/molecule/pie-chart/pie-chart'; -import { fetchResultUserInfo } from '@/app/business/user/user.query'; +import { getUserInfo } from '@/app/business/user/user.query'; import { MAJOR_NOTATION } from '@/app/utils/key/result-category.key'; +import { User } from '@/app/business/user/user.type'; async function UserInfoCard() { const { @@ -11,7 +12,7 @@ async function UserInfoCard() { totalCredit, takenCredit, graduated, - } = await fetchResultUserInfo(); + } = (await getUserInfo()) as User; const displaySeveralMajor = (notation: 'major' | 'title'): React.ReactNode => { return majors.map((major, index) => { 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 8363273f..e7277895 100644 --- a/app/ui/user/user-info-navigator/user-info-navigator.tsx +++ b/app/ui/user/user-info-navigator/user-info-navigator.tsx @@ -1,9 +1,9 @@ import Avatar from '../../view/atom/avatar/avatar'; import Button from '../../view/atom/button/button'; -import { fetchResultUserInfo } from '@/app/business/user/user.query'; +import { getUserInfo } from '@/app/business/user/user.query'; export default async function UserInfoNavigator() { - const userInfo = await fetchResultUserInfo(); + const userInfo = await getUserInfo(); return (
@@ -13,9 +13,8 @@ export default async function UserInfoNavigator() { {userInfo.studentName}
-
{userInfo.completionDivision[0].major}
+
{userInfo.completionDivision ? userInfo.completionDivision[0].major : ''}
{userInfo.studentNumber}
-
From 4cc780a94a6dea4dde5214b58d1ab83fa947116a Mon Sep 17 00:00:00 2001 From: yougyung Date: Thu, 9 May 2024 12:41:03 +0900 Subject: [PATCH 04/12] fix: change UserInfoResponseSchema --- app/business/user/user.type.ts | 26 +++++++++++++++++++ app/business/user/user.validation.ts | 17 ++++++++---- .../handlers/taken-lecture-handler.mock.ts | 1 - middleware.ts | 3 +-- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/app/business/user/user.type.ts b/app/business/user/user.type.ts index 3f18be25..50561449 100644 --- a/app/business/user/user.type.ts +++ b/app/business/user/user.type.ts @@ -1,6 +1,7 @@ // https://stackoverflow.com/questions/76957592/error-only-async-functions-are-allowed-to-be-exported-in-a-use-server-file // server action 파일에서는 async function만 export 가능 +import { Major } from '../result/result.query'; import { SignInResponseSchema, UserInfoResponseSchema, ValidateTokenResponseSchema } from './user.validation'; import z from 'zod'; @@ -21,3 +22,28 @@ export type SignInResponse = z.infer; export type UserInfoResponse = z.infer; export type ValidateTokenResponse = z.infer; + +export interface MockUser { + authId: string; + password: string; + studentNumber: string; + engLv: string; +} + +export interface User { + studentNumber: string; + studentName: string; + completionDivision: Major[]; + totalCredit: number; + takenCredit: number; + graduated: boolean; +} + +export interface Init { + studentNumber: string; + studentName: null; + completionDivision: null; + totalCredit: null; + takenCredit: null; + graduated: null; +} diff --git a/app/business/user/user.validation.ts b/app/business/user/user.validation.ts index b5b73117..d02937d6 100644 --- a/app/business/user/user.validation.ts +++ b/app/business/user/user.validation.ts @@ -1,12 +1,19 @@ import { z } from 'zod'; -// api 변경 예정 - export const UserInfoResponseSchema = z.object({ studentNumber: z.string(), - studentName: z.string(), - major: z.string(), - isSumbitted: z.boolean(), + studentName: z.string().nullable(), + completionDivision: z + .array( + z.object({ + majorType: z.enum(['PRIMARY', 'DUAL', 'SUB']), + major: z.string(), + }), + ) + .nullable(), + totalCredit: z.number().nullable(), + takenCredit: z.number().nullable(), + graduated: z.boolean().nullable(), }); export const ValidateTokenResponseSchema = z.object({ diff --git a/app/mocks/handlers/taken-lecture-handler.mock.ts b/app/mocks/handlers/taken-lecture-handler.mock.ts index daf28079..7b208698 100644 --- a/app/mocks/handlers/taken-lecture-handler.mock.ts +++ b/app/mocks/handlers/taken-lecture-handler.mock.ts @@ -32,7 +32,6 @@ export const takenLectureHandlers = [ }), http.post(API_PATH.parsePDFtoText, async () => { await delay(1000); - console.log(parsePDF); return HttpResponse.json(parsePDF); }), diff --git a/middleware.ts b/middleware.ts index c61ab09a..44877416 100644 --- a/middleware.ts +++ b/middleware.ts @@ -27,7 +27,7 @@ async function getAuth(request: NextRequest): Promise<{ // 유저 정보 요청 const user = await getUserInfo(); return { - role: user.isSumbitted ? 'user' : 'init', + role: user.studentName ? 'user' : 'init', }; } @@ -43,7 +43,6 @@ export async function middleware(request: NextRequest) { // 개발용이성을 위해 isAuth=true 일 때만 동작 if (isAuth === 'true') { const auth = await getAuth(request); - if (auth.role === 'init' && !request.nextUrl.pathname.startsWith('/grade-upload')) { return Response.redirect(new URL('/grade-upload', request.url)); } From 1e6945db513fc1db11764cf07babfcd6609e81c0 Mon Sep 17 00:00:00 2001 From: yougyung Date: Thu, 9 May 2024 16:11:53 +0900 Subject: [PATCH 05/12] fix: separate type in result in query file --- app/business/result/result.query.ts | 30 +---------------------- app/business/result/result.type.ts | 30 +++++++++++++++++++++++ app/business/user/user.type.ts | 2 +- app/mocks/db.mock.ts | 2 +- app/mocks/handlers/result-handler.mock.ts | 2 +- 5 files changed, 34 insertions(+), 32 deletions(-) create mode 100644 app/business/result/result.type.ts diff --git a/app/business/result/result.query.ts b/app/business/result/result.query.ts index de990988..0763d40a 100644 --- a/app/business/result/result.query.ts +++ b/app/business/result/result.query.ts @@ -1,36 +1,8 @@ -import { LectureInfo } from '@/app/type/lecture'; import { API_PATH } from '../api-path'; import { cookies } from 'next/headers'; import { httpErrorHandler } from '@/app/utils/http/http-error-handler'; -import { RESULT_CATEGORY } from '@/app/utils/key/result-category.key'; +import { CreditResponse, ResultCategoryDetailResponse } from './result.type'; -export interface ResultCategoryDetailLectures { - categoryName: string; - totalCredits: number; - takenCredits: number; - takenLectures: LectureInfo[]; - haveToLectures: LectureInfo[]; - completed: boolean; -} - -export interface ResultCategoryDetailResponse { - totalCredit: number; - takenCredit: number; - detailCategory: ResultCategoryDetailLectures[]; - completed: boolean; -} - -export interface Major { - majorType: 'PRIMARY' | 'DUAL' | 'SUB'; - major: string; -} - -export interface CreditResponse { - category: keyof typeof RESULT_CATEGORY; - totalCredit: number; - takenCredit: number; - completed: boolean; -} export const fetchResultCategoryDetailInfo = async (category: string): Promise => { //FIX : category를 querystring으로 호출하는 건은 mock단계에서는 불필요할 것으로 예상, 실제 api 연결시 변경 예정 try { diff --git a/app/business/result/result.type.ts b/app/business/result/result.type.ts new file mode 100644 index 00000000..2fa3b412 --- /dev/null +++ b/app/business/result/result.type.ts @@ -0,0 +1,30 @@ +import { LectureInfo } from '@/app/type/lecture'; +import { RESULT_CATEGORY } from '@/app/utils/key/result-category.key'; + +export interface ResultCategoryDetailLectures { + categoryName: string; + totalCredits: number; + takenCredits: number; + takenLectures: LectureInfo[]; + haveToLectures: LectureInfo[]; + completed: boolean; +} + +export interface ResultCategoryDetailResponse { + totalCredit: number; + takenCredit: number; + detailCategory: ResultCategoryDetailLectures[]; + completed: boolean; +} + +export interface Major { + majorType: 'PRIMARY' | 'DUAL' | 'SUB'; + major: string; +} + +export interface CreditResponse { + category: keyof typeof RESULT_CATEGORY; + totalCredit: number; + takenCredit: number; + completed: boolean; +} diff --git a/app/business/user/user.type.ts b/app/business/user/user.type.ts index 50561449..ee08b0d2 100644 --- a/app/business/user/user.type.ts +++ b/app/business/user/user.type.ts @@ -1,7 +1,7 @@ // https://stackoverflow.com/questions/76957592/error-only-async-functions-are-allowed-to-be-exported-in-a-use-server-file // server action 파일에서는 async function만 export 가능 -import { Major } from '../result/result.query'; +import { Major } from '../result/result.type'; import { SignInResponseSchema, UserInfoResponseSchema, ValidateTokenResponseSchema } from './user.validation'; import z from 'zod'; diff --git a/app/mocks/db.mock.ts b/app/mocks/db.mock.ts index 9b6db320..266eab58 100644 --- a/app/mocks/db.mock.ts +++ b/app/mocks/db.mock.ts @@ -1,6 +1,6 @@ import { SearchLectures } from '../business/lecture/search-lecture.query'; import { TakenLectures } from '../business/lecture/taken-lecture.query'; -import { CreditResponse, ResultCategoryDetailResponse } from '../business/result/result.query'; +import { CreditResponse, ResultCategoryDetailResponse } from '../business/result/result.type'; import { SignUpRequestBody, SignInRequestBody, MockUser, User, Init } from '../business/user/user.type'; import { takenLectures, credits, searchLectures, userInfo, resultCategoryDetailInfo } from './data.mock'; diff --git a/app/mocks/handlers/result-handler.mock.ts b/app/mocks/handlers/result-handler.mock.ts index 52ac5b1e..32941455 100644 --- a/app/mocks/handlers/result-handler.mock.ts +++ b/app/mocks/handlers/result-handler.mock.ts @@ -2,7 +2,7 @@ import { HttpResponse, http, delay } from 'msw'; import { API_PATH } from '../../business/api-path'; import { mockDatabase } from '../db.mock'; import { ErrorResponseData } from '@/app/utils/http/http-error-handler'; -import { CreditResponse, ResultCategoryDetailResponse } from '@/app/business/result/result.query'; +import { CreditResponse, ResultCategoryDetailResponse } from '@/app/business/result/result.type'; export const resultHandlers = [ http.get( From 820cb4e61baaeb0ac1d1ac9fd8264428b729c17f Mon Sep 17 00:00:00 2001 From: yougyung Date: Thu, 9 May 2024 16:53:55 +0900 Subject: [PATCH 06/12] fix: remove redendancy type --- app/business/user/user.command.ts | 2 +- app/business/user/user.query.ts | 4 +- app/business/user/user.type.ts | 41 +++++-------------- app/business/user/user.validation.ts | 31 ++++++++------ app/mocks/data.mock.ts | 10 +++++ app/mocks/db.mock.ts | 25 ++++------- app/mocks/handlers/user-handler.mock.ts | 2 +- .../result-category-detail-content.tsx | 2 +- .../result-cagegory-detail-lecture.tsx | 2 +- app/ui/user/user-info-card/user-info-card.tsx | 5 ++- 10 files changed, 55 insertions(+), 69 deletions(-) diff --git a/app/business/user/user.command.ts b/app/business/user/user.command.ts index 33a1f833..3884f4f6 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 { MockUser as SignUpRequestBody, SignInRequestBody, ValidateTokenResponse } from './user.type'; import { httpErrorHandler } from '@/app/utils/http/http-error-handler'; import { BadRequestError } from '@/app/utils/http/http-error'; import { diff --git a/app/business/user/user.query.ts b/app/business/user/user.query.ts index 6704e6f7..1ba64301 100644 --- a/app/business/user/user.query.ts +++ b/app/business/user/user.query.ts @@ -3,7 +3,7 @@ import { API_PATH } from '../api-path'; import { UserInfoResponse } from './user.type'; import { cookies } from 'next/headers'; import { isValidation } from '@/app/utils/zod/validation.util'; -import { UserInfoResponseSchema } from './user.validation'; +import { InitUserInfoResponseSchema, UserInfoResponseSchema } from './user.validation'; export async function getUserInfo(): Promise { try { @@ -17,7 +17,7 @@ export async function getUserInfo(): Promise { httpErrorHandler(response, result); - if (isValidation(result, UserInfoResponseSchema)) { + if (isValidation(result, UserInfoResponseSchema || InitUserInfoResponseSchema)) { return result; } else { throw 'Invalid user info response schema.'; diff --git a/app/business/user/user.type.ts b/app/business/user/user.type.ts index ee08b0d2..552f640b 100644 --- a/app/business/user/user.type.ts +++ b/app/business/user/user.type.ts @@ -1,28 +1,19 @@ // https://stackoverflow.com/questions/76957592/error-only-async-functions-are-allowed-to-be-exported-in-a-use-server-file // server action 파일에서는 async function만 export 가능 -import { Major } from '../result/result.type'; -import { SignInResponseSchema, UserInfoResponseSchema, ValidateTokenResponseSchema } from './user.validation'; +import { + InitUserInfoResponseSchema, + SignInResponseSchema, + UserInfoResponseSchema, + ValidateTokenResponseSchema, +} from './user.validation'; import z from 'zod'; -export interface SignUpRequestBody { - authId: string; - password: string; - studentNumber: string; - engLv: string; -} - export interface SignInRequestBody { authId: string; password: string; } -export type SignInResponse = z.infer; - -export type UserInfoResponse = z.infer; - -export type ValidateTokenResponse = z.infer; - export interface MockUser { authId: string; password: string; @@ -30,20 +21,8 @@ export interface MockUser { engLv: string; } -export interface User { - studentNumber: string; - studentName: string; - completionDivision: Major[]; - totalCredit: number; - takenCredit: number; - graduated: boolean; -} +export type SignInResponse = z.infer; -export interface Init { - studentNumber: string; - studentName: null; - completionDivision: null; - totalCredit: null; - takenCredit: null; - graduated: null; -} +export type UserInfoResponse = z.infer; + +export type ValidateTokenResponse = z.infer; diff --git a/app/business/user/user.validation.ts b/app/business/user/user.validation.ts index d02937d6..89596799 100644 --- a/app/business/user/user.validation.ts +++ b/app/business/user/user.validation.ts @@ -2,18 +2,25 @@ import { z } from 'zod'; export const UserInfoResponseSchema = z.object({ studentNumber: z.string(), - studentName: z.string().nullable(), - completionDivision: z - .array( - z.object({ - majorType: z.enum(['PRIMARY', 'DUAL', 'SUB']), - major: z.string(), - }), - ) - .nullable(), - totalCredit: z.number().nullable(), - takenCredit: z.number().nullable(), - graduated: z.boolean().nullable(), + studentName: z.string(), + completionDivision: z.array( + z.object({ + majorType: z.enum(['PRIMARY', 'DUAL', 'SUB']), + major: z.string(), + }), + ), + totalCredit: z.number(), + takenCredit: z.number(), + graduated: z.boolean(), +}); + +export const InitUserInfoResponseSchema = z.object({ + studentNumber: z.string(), + studentName: z.null(), + completionDivision: z.null(), + totalCredit: z.null(), + takenCredit: z.null(), + graduated: z.null(), }); export const ValidateTokenResponseSchema = z.object({ diff --git a/app/mocks/data.mock.ts b/app/mocks/data.mock.ts index 194b460a..2de1a1c6 100644 --- a/app/mocks/data.mock.ts +++ b/app/mocks/data.mock.ts @@ -195,6 +195,15 @@ export const resultCategoryDetailInfo = JSON.parse(`{ "completed": false }`); +export const users = JSON.parse(`[ + { + "authId": "admin", + "password": "admin", + "studentNumber": "60000000", + "engLv": "ENG12" + } + ]`); + export const credits = JSON.parse(`[ { "category": "COMMON_CULTURE", @@ -269,6 +278,7 @@ export const credits = JSON.parse(`[ "completed": false } ]`); + export const searchLectures = JSON.parse(`{ "lectures": [ { diff --git a/app/mocks/db.mock.ts b/app/mocks/db.mock.ts index 266eab58..be01be4b 100644 --- a/app/mocks/db.mock.ts +++ b/app/mocks/db.mock.ts @@ -1,8 +1,9 @@ +import { MockUser, UserInfoResponse } from './../business/user/user.type'; import { SearchLectures } from '../business/lecture/search-lecture.query'; import { TakenLectures } from '../business/lecture/taken-lecture.query'; import { CreditResponse, ResultCategoryDetailResponse } from '../business/result/result.type'; -import { SignUpRequestBody, SignInRequestBody, MockUser, User, Init } from '../business/user/user.type'; -import { takenLectures, credits, searchLectures, userInfo, resultCategoryDetailInfo } from './data.mock'; +import { MockUser as SignUpRequestBody, SignInRequestBody } from '../business/user/user.type'; +import { takenLectures, credits, searchLectures, userInfo, users, resultCategoryDetailInfo } from './data.mock'; interface MockDatabaseState { takenLectures: TakenLectures; @@ -10,7 +11,7 @@ interface MockDatabaseState { credits: CreditResponse[]; users: MockUser[]; searchLectures: SearchLectures; - userInfo: User; + userInfo: UserInfoResponse; } type MockDatabaseAction = { @@ -21,7 +22,7 @@ type MockDatabaseAction = { createUser: (user: SignUpRequestBody) => boolean; signIn: (userData: SignInRequestBody) => boolean; getCredits: () => CreditResponse[]; - getUserInfo: (authId: string) => User | Init; + getUserInfo: (authId: string) => UserInfoResponse; getResultCategoryDetailInfo: () => ResultCategoryDetailResponse; }; @@ -58,12 +59,7 @@ export const mockDatabase: MockDatabaseAction = { if (mockDatabaseStore.users.find((u) => u.authId === user.authId || u.studentNumber === user.studentNumber)) { return false; } - mockDatabaseStore.users = [ - ...mockDatabaseStore.users, - { - ...user, - }, - ]; + mockDatabaseStore.users = [...mockDatabaseStore.users, user]; return true; }, signIn: (userData: SignInRequestBody) => { @@ -90,14 +86,7 @@ const initialState: MockDatabaseState = { takenLectures: takenLectures, resultCategoryDetailInfo: resultCategoryDetailInfo, credits: credits, - users: [ - { - authId: 'admin', - password: 'admin', - studentNumber: '60000000', - engLv: 'ENG12', - }, - ], + users: users, searchLectures: searchLectures, userInfo: userInfo, }; diff --git a/app/mocks/handlers/user-handler.mock.ts b/app/mocks/handlers/user-handler.mock.ts index 72a00b48..4b4dc81f 100644 --- a/app/mocks/handlers/user-handler.mock.ts +++ b/app/mocks/handlers/user-handler.mock.ts @@ -2,7 +2,7 @@ import { HttpResponse, http, delay } from 'msw'; import { API_PATH } from '../../business/api-path'; import { mockDatabase } from '../db.mock'; import { - SignUpRequestBody, + MockUser as SignUpRequestBody, SignInRequestBody, SignInResponse, ValidateTokenResponse, diff --git a/app/ui/result/result-category-detail-content/result-category-detail-content.tsx b/app/ui/result/result-category-detail-content/result-category-detail-content.tsx index 6b2a7a0b..1cee5608 100644 --- a/app/ui/result/result-category-detail-content/result-category-detail-content.tsx +++ b/app/ui/result/result-category-detail-content/result-category-detail-content.tsx @@ -4,7 +4,7 @@ import { cn } from '@/app/utils/shadcn/utils'; import { useState } from 'react'; import { ResultCategoryDetailLectureToggle } from '../result-category-detail-lecture/result-category-detail-lecture-toggle'; import ResultCagegoryDetailLecture from '../result-category-detail-lecture/result-cagegory-detail-lecture'; -import { ResultCategoryDetailResponse } from '@/app/business/result/result.query'; +import { ResultCategoryDetailResponse } from '@/app/business/result/result.type'; interface ResultCategoryDetailContentProps { info: ResultCategoryDetailResponse; diff --git a/app/ui/result/result-category-detail-lecture/result-cagegory-detail-lecture.tsx b/app/ui/result/result-category-detail-lecture/result-cagegory-detail-lecture.tsx index 3d48179a..988077cc 100644 --- a/app/ui/result/result-category-detail-lecture/result-cagegory-detail-lecture.tsx +++ b/app/ui/result/result-category-detail-lecture/result-cagegory-detail-lecture.tsx @@ -1,7 +1,7 @@ import { Table } from '../../view/molecule/table'; import AnnounceMessageBox from '@/app/ui/view/molecule/announce-message-box/announce-massage-box'; -import { ResultCategoryDetailLectures } from '@/app/business/result/result.query'; import LabelContainer from '@/app/ui/view/atom/label-container/label-container'; +import { ResultCategoryDetailLectures } from '@/app/business/result/result.type'; const headerInfo = ['과목코드', '과목명', '학점']; diff --git a/app/ui/user/user-info-card/user-info-card.tsx b/app/ui/user/user-info-card/user-info-card.tsx index 04719bd2..a56f41b6 100644 --- a/app/ui/user/user-info-card/user-info-card.tsx +++ b/app/ui/user/user-info-card/user-info-card.tsx @@ -2,7 +2,8 @@ import { getPercentage } from '@/app/utils/chart.util'; import PieChart from '../../view/molecule/pie-chart/pie-chart'; import { getUserInfo } from '@/app/business/user/user.query'; import { MAJOR_NOTATION } from '@/app/utils/key/result-category.key'; -import { User } from '@/app/business/user/user.type'; +import { UserInfoResponseSchema } from '@/app/business/user/user.validation'; +import { z } from 'zod'; async function UserInfoCard() { const { @@ -12,7 +13,7 @@ async function UserInfoCard() { totalCredit, takenCredit, graduated, - } = (await getUserInfo()) as User; + } = (await getUserInfo()) as z.infer; const displaySeveralMajor = (notation: 'major' | 'title'): React.ReactNode => { return majors.map((major, index) => { From e7c6517b2208fe6b4c11f5ab5e2ecb2f60a6c5fb Mon Sep 17 00:00:00 2001 From: yougyung Date: Thu, 9 May 2024 17:01:22 +0900 Subject: [PATCH 07/12] fix: change naming getUserInfo to fetchUserInfo --- app/ui/user/user-credit-result.tsx | 4 ++-- app/ui/user/user-info-card/user-info-card.tsx | 4 ++-- app/ui/user/user-info-navigator/user-info-navigator.tsx | 4 ++-- middleware.ts | 5 ++--- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app/ui/user/user-credit-result.tsx b/app/ui/user/user-credit-result.tsx index 95d02672..fc67872f 100644 --- a/app/ui/user/user-credit-result.tsx +++ b/app/ui/user/user-credit-result.tsx @@ -1,10 +1,10 @@ -import { getUserInfo } from '@/app/business/user/user.query'; +import { fetchUserInfo } from '@/app/business/user/user.query'; import books from '@/public/assets/books.png'; import pencil from '@/public/assets/pencil.png'; import Image from 'next/image'; export default async function UserCreditResult() { - const userInfo = await getUserInfo(); + const userInfo = await fetchUserInfo(); return (
diff --git a/app/ui/user/user-info-card/user-info-card.tsx b/app/ui/user/user-info-card/user-info-card.tsx index a56f41b6..694e3d16 100644 --- a/app/ui/user/user-info-card/user-info-card.tsx +++ b/app/ui/user/user-info-card/user-info-card.tsx @@ -1,6 +1,6 @@ import { getPercentage } from '@/app/utils/chart.util'; import PieChart from '../../view/molecule/pie-chart/pie-chart'; -import { getUserInfo } from '@/app/business/user/user.query'; +import { fetchUserInfo } from '@/app/business/user/user.query'; import { MAJOR_NOTATION } from '@/app/utils/key/result-category.key'; import { UserInfoResponseSchema } from '@/app/business/user/user.validation'; import { z } from 'zod'; @@ -13,7 +13,7 @@ async function UserInfoCard() { totalCredit, takenCredit, graduated, - } = (await getUserInfo()) as z.infer; + } = (await fetchUserInfo()) as z.infer; const displaySeveralMajor = (notation: 'major' | 'title'): React.ReactNode => { return majors.map((major, index) => { 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 e7277895..76f53361 100644 --- a/app/ui/user/user-info-navigator/user-info-navigator.tsx +++ b/app/ui/user/user-info-navigator/user-info-navigator.tsx @@ -1,9 +1,9 @@ import Avatar from '../../view/atom/avatar/avatar'; import Button from '../../view/atom/button/button'; -import { getUserInfo } from '@/app/business/user/user.query'; +import { fetchUserInfo } from '@/app/business/user/user.query'; export default async function UserInfoNavigator() { - const userInfo = await getUserInfo(); + const userInfo = await fetchUserInfo(); return (
diff --git a/middleware.ts b/middleware.ts index 44877416..90a7fa7e 100644 --- a/middleware.ts +++ b/middleware.ts @@ -1,6 +1,6 @@ import type { NextRequest } from 'next/server'; import { validateToken } from './app/business/user/user.command'; -import { getUserInfo } from './app/business/user/user.query'; +import { fetchUserInfo } from './app/business/user/user.query'; async function getAuth(request: NextRequest): Promise<{ role: 'guest' | 'user' | 'init'; @@ -24,8 +24,7 @@ async function getAuth(request: NextRequest): Promise<{ request.cookies.set('accessToken', validatedResult.accessToken); - // 유저 정보 요청 - const user = await getUserInfo(); + const user = await fetchUserInfo(); return { role: user.studentName ? 'user' : 'init', }; From a773ede6c4ef5ddb2c4607bd8be01e87497b4a2c Mon Sep 17 00:00:00 2001 From: yougyung Date: Thu, 9 May 2024 17:03:31 +0900 Subject: [PATCH 08/12] chore: change Missing changes --- app/business/user/user.query.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/business/user/user.query.ts b/app/business/user/user.query.ts index 1ba64301..b6f1ed5a 100644 --- a/app/business/user/user.query.ts +++ b/app/business/user/user.query.ts @@ -5,7 +5,7 @@ import { cookies } from 'next/headers'; import { isValidation } from '@/app/utils/zod/validation.util'; import { InitUserInfoResponseSchema, UserInfoResponseSchema } from './user.validation'; -export async function getUserInfo(): Promise { +export async function fetchUserInfo(): Promise { try { const response = await fetch(`${API_PATH.user}`, { headers: { From 1989ef5e89148e6f19aaa0bdc0b98b5d2320b5bc Mon Sep 17 00:00:00 2001 From: yougyung Date: Thu, 9 May 2024 17:16:13 +0900 Subject: [PATCH 09/12] fix: add type assertion at fetchUserInfo --- app/ui/user/user-info-navigator/user-info-navigator.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 76f53361..d291e8f9 100644 --- a/app/ui/user/user-info-navigator/user-info-navigator.tsx +++ b/app/ui/user/user-info-navigator/user-info-navigator.tsx @@ -1,9 +1,11 @@ +import { UserInfoResponseSchema } from '@/app/business/user/user.validation'; import Avatar from '../../view/atom/avatar/avatar'; import Button from '../../view/atom/button/button'; import { fetchUserInfo } from '@/app/business/user/user.query'; +import { z } from 'zod'; export default async function UserInfoNavigator() { - const userInfo = await fetchUserInfo(); + const userInfo = (await fetchUserInfo()) as z.infer; return (
@@ -13,7 +15,7 @@ export default async function UserInfoNavigator() { {userInfo.studentName}
-
{userInfo.completionDivision ? userInfo.completionDivision[0].major : ''}
+
{userInfo.completionDivision[0].major}
{userInfo.studentNumber}