From d93c8e79a7b9a096758bd06dbefe7e102d6da2d3 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Tue, 1 Jul 2025 17:10:47 +0900 Subject: [PATCH 001/200] chore: lint --- apps/admin/src/views/score/ui/scoreForm.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/admin/src/views/score/ui/scoreForm.tsx b/apps/admin/src/views/score/ui/scoreForm.tsx index 375b6f2f..6b0d0cd1 100644 --- a/apps/admin/src/views/score/ui/scoreForm.tsx +++ b/apps/admin/src/views/score/ui/scoreForm.tsx @@ -8,11 +8,12 @@ import { useCallback } from "react"; import { Controller, useForm, useWatch } from "react-hook-form"; import { toast } from "sonner"; +import { Checkbox } from "@/entities/score/ui/checkbox"; +import Header from "@/shared/ui/header"; + import { featScore } from "../api/featScore"; import type { ScoreFormType } from "../model/score"; -import { Checkbox } from "@/entities/score/ui/checkbox"; -import Header from "@/shared/ui/header"; const SCORE_CATEGORIES = { SEMESTER_1: "HUMANITIES-SERVICE-CLUB_SEMESTER_1", From 8fbceb6c8b5a061ed0c2a3a0c1c8ba7496653389 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Tue, 1 Jul 2025 17:10:57 +0900 Subject: [PATCH 002/200] fix: score api --- apps/admin/src/views/score/api/featScore.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/admin/src/views/score/api/featScore.ts b/apps/admin/src/views/score/api/featScore.ts index 69ddf906..a3808a30 100644 --- a/apps/admin/src/views/score/api/featScore.ts +++ b/apps/admin/src/views/score/api/featScore.ts @@ -1,5 +1,5 @@ import instance from "@repo/api/axios"; -import { AxiosError, type AxiosResponse } from "axios"; +import { isAxiosError, type AxiosResponse } from "axios"; interface FeatScoreResponse { categoryName: string; @@ -7,25 +7,24 @@ interface FeatScoreResponse { } interface FeatScoreRequest { - email: string; - category: string; - score: number; + categoryName: string; + value: number; } export const featScore = async ( email: string, category: string, - score: number, + score: number ): Promise> => { const data: FeatScoreRequest = { - email, - category, - score, + categoryName: category, + value: Number(score), }; try { - return await instance.patch("/score", data); + const id = email.split("@")[0]?.slice(1); + return await instance.patch(`/score/${id}`, data); } catch (error) { - if (error instanceof AxiosError) { + if (isAxiosError(error) && error.response) { throw error; } throw new Error("Unknown error occurred"); From 36d801c7139ebc1aaae7209ac000c876eb5b6579 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Tue, 1 Jul 2025 17:55:24 +0900 Subject: [PATCH 003/200] fix: score --- apps/admin/src/views/score/ui/scoreForm.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/admin/src/views/score/ui/scoreForm.tsx b/apps/admin/src/views/score/ui/scoreForm.tsx index 6b0d0cd1..8ca1b5ef 100644 --- a/apps/admin/src/views/score/ui/scoreForm.tsx +++ b/apps/admin/src/views/score/ui/scoreForm.tsx @@ -141,7 +141,7 @@ const ScoreForm = () => { { Date: Tue, 1 Jul 2025 18:10:14 +0900 Subject: [PATCH 004/200] =?UTF-8?q?feat:=20=EB=B4=89=EC=82=AC=ED=99=9C?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/admin/src/views/score/model/score.ts | 1 + apps/admin/src/views/score/ui/scoreForm.tsx | 25 +++++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/admin/src/views/score/model/score.ts b/apps/admin/src/views/score/model/score.ts index c8970165..26504bde 100644 --- a/apps/admin/src/views/score/model/score.ts +++ b/apps/admin/src/views/score/model/score.ts @@ -4,6 +4,7 @@ export interface Score { } export interface ScoreFormType { + activity: number | null; oneSemester: number | null; twoSemester: number | null; newrrow: number | null; diff --git a/apps/admin/src/views/score/ui/scoreForm.tsx b/apps/admin/src/views/score/ui/scoreForm.tsx index 8ca1b5ef..168f7cde 100644 --- a/apps/admin/src/views/score/ui/scoreForm.tsx +++ b/apps/admin/src/views/score/ui/scoreForm.tsx @@ -16,6 +16,7 @@ import type { ScoreFormType } from "../model/score"; const SCORE_CATEGORIES = { + ACTIVITY: "HUMANITIES-SERVICE-ACTIVITY", SEMESTER_1: "HUMANITIES-SERVICE-CLUB_SEMESTER_1", SEMESTER_2: "HUMANITIES-SERVICE-CLUB_SEMESTER_2", NEWRROW: "HUMANITIES-ACTIVITIES-NEWRROW_S", @@ -35,9 +36,7 @@ const ScoreForm = () => { }, [router]); const renderCheckbox = useCallback( - ({ - field, - }: { + ({ field }: { field: { value?: boolean; onChange: (value: boolean | null) => void }; }) => , [], @@ -77,7 +76,16 @@ const ScoreForm = () => { async (data: ScoreFormType) => { let success = true; - if (data.oneSemester !== null && data.oneSemester > 0) { + if (data.activity !== null && data.activity > 0) { + success = + (await handleScoreSubmit( + SCORE_CATEGORIES.ACTIVITY, + data.activity, + "봉사활동 점수 추가 완료", + )) && success; + } + + else if (data.oneSemester !== null && data.oneSemester > 0) { success = (await handleScoreSubmit( SCORE_CATEGORIES.SEMESTER_1, @@ -138,6 +146,15 @@ const ScoreForm = () => {

점수 추가

+ + + Date: Wed, 2 Jul 2025 00:26:13 +0900 Subject: [PATCH 005/200] fix: read_a_thon --- .../src/widgets/main/api/sendEvidence.ts | 23 ++++++++++++++----- apps/client/src/widgets/main/model/options.ts | 10 ++++++-- apps/client/src/widgets/main/ui/modal.tsx | 5 +++- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/apps/client/src/widgets/main/api/sendEvidence.ts b/apps/client/src/widgets/main/api/sendEvidence.ts index ed6e4160..40c6a670 100644 --- a/apps/client/src/widgets/main/api/sendEvidence.ts +++ b/apps/client/src/widgets/main/api/sendEvidence.ts @@ -1,10 +1,21 @@ import instance from "@repo/api/axios"; +import { isAxiosError } from "axios"; -import type { Evidence } from "../model/evidence"; +interface EvidenceProps { + categoryName: string; + file: File; +} -export const sendEvidence = async (data: Evidence) => { - const formData = new FormData(); - formData.append("file", data.file); - formData.append("categoryName", data.option.send); - return await instance.post("/evidence/current/other", formData); +export const sendEvidence = async (data: EvidenceProps) => { + try { + const formData = new FormData(); + formData.append("file", data.file); + formData.append("categoryName", data.categoryName); + return await instance.post("/evidence/current/other", formData); + } catch (error) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "기타증빙자료 등록 실패"; + } + throw error; + } }; diff --git a/apps/client/src/widgets/main/model/options.ts b/apps/client/src/widgets/main/model/options.ts index e494dfe5..3546371a 100644 --- a/apps/client/src/widgets/main/model/options.ts +++ b/apps/client/src/widgets/main/model/options.ts @@ -9,8 +9,14 @@ export const options = [ ]; export const bookOption = [ - { name: "거북이 코스", send: "HUMANITIES-READING-READ_A_THON-TURTLE" }, - { name: "악어 코스", send: "HUMANITIES-READING-READ_A_THON-CROCODILE" }, + { + name: "거북이 코스", + send: "HUMANITIES-READING-READ_A_THON-TURTLE", + }, + { + name: "악어 코스", + send: "HUMANITIES-READING-READ_A_THON-CROCODILE", + }, { name: "토끼 코스 이상", send: "HUMANITIES-READING-READ_A_THON-RABBIT_OVER", diff --git a/apps/client/src/widgets/main/ui/modal.tsx b/apps/client/src/widgets/main/ui/modal.tsx index b0eb616a..24b55f92 100644 --- a/apps/client/src/widgets/main/ui/modal.tsx +++ b/apps/client/src/widgets/main/ui/modal.tsx @@ -60,7 +60,10 @@ const Modal = ({ onClose, type }: ModalProps) => { }); } case "READ_A_THON": { - return await sendEvidence(data); + return await sendEvidence({ + categoryName: data.option.send, + file: data.file + }); } case "HUMANITY": { return await sendCertification({ From 371f8595e5e5a59932d7f147f464a12fbcd0a367 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 00:30:41 +0900 Subject: [PATCH 006/200] fix: calculate --- apps/client/src/app/calculate/page.tsx | 13 ++----------- apps/client/src/views/calculate/ui/index.tsx | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 apps/client/src/views/calculate/ui/index.tsx diff --git a/apps/client/src/app/calculate/page.tsx b/apps/client/src/app/calculate/page.tsx index 06395caa..02e5b135 100644 --- a/apps/client/src/app/calculate/page.tsx +++ b/apps/client/src/app/calculate/page.tsx @@ -1,16 +1,7 @@ -import { Calculate } from "@widgets/calculate/ui"; +import CalculateView from "@/views/calculate/ui"; const CalculatePage = () => { - return ( -
-
-

- 점수 계산 -

- -
-
- ); + return }; export default CalculatePage; diff --git a/apps/client/src/views/calculate/ui/index.tsx b/apps/client/src/views/calculate/ui/index.tsx new file mode 100644 index 00000000..ea4e735e --- /dev/null +++ b/apps/client/src/views/calculate/ui/index.tsx @@ -0,0 +1,16 @@ +import { Calculate } from '@/widgets/calculate/ui' + +const CalculateView = () => { + return ( +
+
+

+ 점수 계산 +

+ +
+
+ ) +} + +export default CalculateView \ No newline at end of file From 5cd582a0e1c34c3d4fee1b036996a5d37c3865f2 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 10:26:57 +0900 Subject: [PATCH 007/200] fix: deletePost type --- apps/client/src/entities/detail/api/deletePost.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/client/src/entities/detail/api/deletePost.ts b/apps/client/src/entities/detail/api/deletePost.ts index e386a225..09607cb5 100644 --- a/apps/client/src/entities/detail/api/deletePost.ts +++ b/apps/client/src/entities/detail/api/deletePost.ts @@ -1,16 +1,16 @@ import instance from "@repo/api"; -import type { AxiosError, AxiosResponse } from "axios"; +import { isAxiosError } from "axios"; -export const deletePost = async ( - id: number, -): Promise => { +export const deletePost = async (id: number) => { try { const response = await instance.delete(`/evidence/current/${id}`, { method: "DELETE", }); - return response; - } catch (error) { - return error as AxiosError; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "게시물 삭제 실패"; + } + throw error; } }; From 463e6268f0c7e6b0547c94f0a6bf4a313ebceec7 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 10:28:31 +0900 Subject: [PATCH 008/200] move: draft --- .../src/entities/posts/lib/useGetPosts.ts | 12 ------------ apps/client/src/shared/api/getDraft.ts | 17 +++++++++++++++++ .../posts => shared}/lib/useGetDraft.ts | 2 +- apps/client/src/views/posts/api/getDraft.ts | 7 ------- 4 files changed, 18 insertions(+), 20 deletions(-) delete mode 100644 apps/client/src/entities/posts/lib/useGetPosts.ts create mode 100644 apps/client/src/shared/api/getDraft.ts rename apps/client/src/{entities/posts => shared}/lib/useGetDraft.ts (81%) delete mode 100644 apps/client/src/views/posts/api/getDraft.ts diff --git a/apps/client/src/entities/posts/lib/useGetPosts.ts b/apps/client/src/entities/posts/lib/useGetPosts.ts deleted file mode 100644 index cbaaa4f1..00000000 --- a/apps/client/src/entities/posts/lib/useGetPosts.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { EvidenceType } from "@repo/types/evidences"; -import { useQuery } from "@tanstack/react-query"; - -import { getPosts } from "@/views/posts/api/getPosts"; - -export const useGetPosts = (type: EvidenceType | "DRAFT" | null) => { - return useQuery({ - queryKey: ["posts", type], - queryFn: () => getPosts(type as EvidenceType | null), - enabled: type !== "DRAFT", - }); -}; diff --git a/apps/client/src/shared/api/getDraft.ts b/apps/client/src/shared/api/getDraft.ts new file mode 100644 index 00000000..69b97ea9 --- /dev/null +++ b/apps/client/src/shared/api/getDraft.ts @@ -0,0 +1,17 @@ +import instance from "@repo/api/axios"; +import type { DraftResponse } from "@repo/types/draft"; +import { isAxiosError } from "axios"; + +export const getDraft = async (): Promise => { + try { + const response = await instance.get( + "/evidence/current/draft" + ); + return response.data; + } catch (error) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "임시저장 게시물 조회 실패"; + } + throw error; + } +}; diff --git a/apps/client/src/entities/posts/lib/useGetDraft.ts b/apps/client/src/shared/lib/useGetDraft.ts similarity index 81% rename from apps/client/src/entities/posts/lib/useGetDraft.ts rename to apps/client/src/shared/lib/useGetDraft.ts index ae1b3760..f9d731e6 100644 --- a/apps/client/src/entities/posts/lib/useGetDraft.ts +++ b/apps/client/src/shared/lib/useGetDraft.ts @@ -1,7 +1,7 @@ import type { DraftResponse } from "@repo/types/draft"; import { useQuery } from "@tanstack/react-query"; -import { getDraft } from "@/views/posts/api/getDraft"; +import { getDraft } from "../api/getDraft"; export const useGetDraft = () => { return useQuery({ diff --git a/apps/client/src/views/posts/api/getDraft.ts b/apps/client/src/views/posts/api/getDraft.ts deleted file mode 100644 index 701322fb..00000000 --- a/apps/client/src/views/posts/api/getDraft.ts +++ /dev/null @@ -1,7 +0,0 @@ -import instance from "@repo/api/axios"; -import type { DraftResponse } from "@repo/types/draft"; - -export const getDraft = async () => { - const response = await instance.get("/evidence/current/draft"); - return response.data; -}; From b6b72c2c093170bb7b86cf14aa2d00da536d8fce Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 10:29:01 +0900 Subject: [PATCH 009/200] move: post --- .../src/{views/posts => shared}/api/getPosts.ts | 0 apps/client/src/shared/lib/useGetPosts.ts | 12 ++++++++++++ apps/client/src/shared/ui/index.ts | 2 +- .../src/shared/ui/post/{post.tsx => index.tsx} | 0 4 files changed, 13 insertions(+), 1 deletion(-) rename apps/client/src/{views/posts => shared}/api/getPosts.ts (100%) create mode 100644 apps/client/src/shared/lib/useGetPosts.ts rename apps/client/src/shared/ui/post/{post.tsx => index.tsx} (100%) diff --git a/apps/client/src/views/posts/api/getPosts.ts b/apps/client/src/shared/api/getPosts.ts similarity index 100% rename from apps/client/src/views/posts/api/getPosts.ts rename to apps/client/src/shared/api/getPosts.ts diff --git a/apps/client/src/shared/lib/useGetPosts.ts b/apps/client/src/shared/lib/useGetPosts.ts new file mode 100644 index 00000000..6f19df81 --- /dev/null +++ b/apps/client/src/shared/lib/useGetPosts.ts @@ -0,0 +1,12 @@ +import type { EvidenceType } from "@repo/types/evidences"; +import { useQuery } from "@tanstack/react-query"; + +import { getPosts } from "../api/getPosts"; + +export const useGetPosts = (type: EvidenceType | "DRAFT" | null) => { + return useQuery({ + queryKey: ["posts", type], + queryFn: () => getPosts(type as EvidenceType | null), + enabled: type !== "DRAFT", + }); +}; diff --git a/apps/client/src/shared/ui/index.ts b/apps/client/src/shared/ui/index.ts index fa39e928..f68be711 100644 --- a/apps/client/src/shared/ui/index.ts +++ b/apps/client/src/shared/ui/index.ts @@ -1,4 +1,4 @@ export { default as Dropdown } from "./dropdown"; export { default as File } from "./file"; export { default as Textarea } from "./textarea"; -export { default as Post } from "./post/post"; +export { default as Post } from "./post"; diff --git a/apps/client/src/shared/ui/post/post.tsx b/apps/client/src/shared/ui/post/index.tsx similarity index 100% rename from apps/client/src/shared/ui/post/post.tsx rename to apps/client/src/shared/ui/post/index.tsx From c4ffa16e5653ab271a4d58ff1818dd4cf1ce93a5 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 10:29:17 +0900 Subject: [PATCH 010/200] move: currentMember --- apps/client/src/shared/{model => lib}/useGetCurrentMember.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename apps/client/src/shared/{model => lib}/useGetCurrentMember.ts (100%) diff --git a/apps/client/src/shared/model/useGetCurrentMember.ts b/apps/client/src/shared/lib/useGetCurrentMember.ts similarity index 100% rename from apps/client/src/shared/model/useGetCurrentMember.ts rename to apps/client/src/shared/lib/useGetCurrentMember.ts From de24b44fd51a55a9c6e456afec124d2b87b36dfc Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 10:29:28 +0900 Subject: [PATCH 011/200] move: httpError --- apps/client/src/shared/{types => model}/error.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename apps/client/src/shared/{types => model}/error.ts (100%) diff --git a/apps/client/src/shared/types/error.ts b/apps/client/src/shared/model/error.ts similarity index 100% rename from apps/client/src/shared/types/error.ts rename to apps/client/src/shared/model/error.ts From c0acc2a2993d3f7c1ac9e3f36496e36f28a46637 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 15:31:51 +0900 Subject: [PATCH 012/200] fix: certification --- .../src/entities/main/api/getCertification.ts | 19 ++++++++++++++----- .../src/entities/main/model/certification.ts | 6 ------ apps/client/src/shared/model/certification.ts | 12 ++++++++++++ .../src/widgets/main/api/sendCertification.ts | 4 ++-- .../src/widgets/main/model/certification.ts | 5 ----- 5 files changed, 28 insertions(+), 18 deletions(-) delete mode 100644 apps/client/src/entities/main/model/certification.ts create mode 100644 apps/client/src/shared/model/certification.ts delete mode 100644 apps/client/src/widgets/main/model/certification.ts diff --git a/apps/client/src/entities/main/api/getCertification.ts b/apps/client/src/entities/main/api/getCertification.ts index a98ae9fa..17d8518b 100644 --- a/apps/client/src/entities/main/api/getCertification.ts +++ b/apps/client/src/entities/main/api/getCertification.ts @@ -1,13 +1,22 @@ import instance from "@repo/api/axios"; +import { isAxiosError } from "axios"; -import type { Certification } from "../model/certification"; +import type { CertificationResponse } from "@/shared/model/certification"; interface Certifications { - data: { - certificates: Certification[]; - }; + certificates: CertificationResponse[]; } export const getCertification = async (): Promise => { - return instance.get("/certificates/current"); + try { + const response = await instance.get( + "/certificates/current" + ); + return response.data; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "자격증 취득 실패"; + } + throw error; + } }; diff --git a/apps/client/src/entities/main/model/certification.ts b/apps/client/src/entities/main/model/certification.ts deleted file mode 100644 index cc030ad8..00000000 --- a/apps/client/src/entities/main/model/certification.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface Certification { - id: number; - name: string; - acquisitionDate: Date; - evidenceUri: string; -} diff --git a/apps/client/src/shared/model/certification.ts b/apps/client/src/shared/model/certification.ts new file mode 100644 index 00000000..e107d5af --- /dev/null +++ b/apps/client/src/shared/model/certification.ts @@ -0,0 +1,12 @@ +export interface CertificationRequest { + name: string; + file: File; + acquisitionDate: string; +} + +export interface CertificationResponse { + id: number; + name: string; + acquisitionDate: Date; + evidenceUri: string; +} diff --git a/apps/client/src/widgets/main/api/sendCertification.ts b/apps/client/src/widgets/main/api/sendCertification.ts index df6c2d49..6b2610a2 100644 --- a/apps/client/src/widgets/main/api/sendCertification.ts +++ b/apps/client/src/widgets/main/api/sendCertification.ts @@ -1,10 +1,10 @@ import instance from "@repo/api/axios"; import { isAxiosError, type AxiosResponse } from "axios"; -import type { Certification } from "../model/certification"; +import type { CertificationRequest } from "@/shared/model/certification"; export const sendCertification = async ( - data: Certification + data: CertificationRequest ): Promise => { try { const formData = new FormData(); diff --git a/apps/client/src/widgets/main/model/certification.ts b/apps/client/src/widgets/main/model/certification.ts deleted file mode 100644 index f3bb6a2c..00000000 --- a/apps/client/src/widgets/main/model/certification.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface Certification { - name: string; - file: File; - acquisitionDate: string; -} From 0dd55a21d52bf83f11c5e2ee954f6cc2ae98e28a Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 15:32:46 +0900 Subject: [PATCH 013/200] fix: auth --- apps/client/src/app/api/auth/signin/route.ts | 10 +++--- .../src/entities/signin/api/postSignin.ts | 13 ++++--- .../src/entities/signup/api/postSignup.ts | 4 +-- apps/client/src/shared/model/AuthForm.ts | 36 ------------------- apps/client/src/shared/model/changePWForm.ts | 6 ++-- apps/client/src/shared/model/signin.ts | 14 ++++++++ apps/client/src/shared/model/signup.ts | 15 ++++++++ .../src/views/changePassword/ui/index.tsx | 32 ++++++++--------- apps/client/src/views/signin/ui/index.tsx | 4 +-- apps/client/src/views/signup/ui/index.tsx | 20 +++++------ .../src/widgets/changePassword/ui/index.tsx | 4 +-- .../src/widgets/stepAuthCode/ui/index.tsx | 16 ++++----- .../src/widgets/stepPassword/ui/index.tsx | 4 +-- 13 files changed, 88 insertions(+), 90 deletions(-) delete mode 100644 apps/client/src/shared/model/AuthForm.ts create mode 100644 apps/client/src/shared/model/signin.ts create mode 100644 apps/client/src/shared/model/signup.ts diff --git a/apps/client/src/app/api/auth/signin/route.ts b/apps/client/src/app/api/auth/signin/route.ts index fa2a5fdd..e72a0773 100644 --- a/apps/client/src/app/api/auth/signin/route.ts +++ b/apps/client/src/app/api/auth/signin/route.ts @@ -1,7 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { setAuthCookies } from "@/shared/lib/setAuthCookies"; -import type { SigninFormProps } from "@/shared/model/AuthForm"; +import type { SigninFormProps } from "@/shared/model/signin"; const API_URL = process.env["NEXT_PUBLIC_API_URL"]; @@ -12,7 +12,7 @@ export async function POST(request: NextRequest) { if (!body.email || !body.password) { return NextResponse.json( { error: "이메일과 비밀번호를 입력해주세요." }, - { status: 400 }, + { status: 400 } ); } @@ -33,7 +33,7 @@ export async function POST(request: NextRequest) { .catch(() => ({ error: "알 수 없는 오류" }))) as { error?: string }; return NextResponse.json( { error: errorData.error ?? "로그인에 실패했습니다." }, - { status: apiResponse.status }, + { status: apiResponse.status } ); } @@ -45,7 +45,7 @@ export async function POST(request: NextRequest) { if (!response.accessToken || !response.refreshToken) { return NextResponse.json( { error: "인증 토큰이 없습니다." }, - { status: 500 }, + { status: 500 } ); } @@ -63,7 +63,7 @@ export async function POST(request: NextRequest) { ? `로그인 처리 중 오류: ${error.message}` : "로그인 처리 중 오류가 발생했습니다.", }, - { status: 500 }, + { status: 500 } ); } } diff --git a/apps/client/src/entities/signin/api/postSignin.ts b/apps/client/src/entities/signin/api/postSignin.ts index cba009bb..edc9eb2b 100644 --- a/apps/client/src/entities/signin/api/postSignin.ts +++ b/apps/client/src/entities/signin/api/postSignin.ts @@ -4,12 +4,17 @@ import { isAxiosError } from "axios"; import type { SigninFormProps, SigninFormResponse, -} from "@shared/model/AuthForm"; +} from "@/shared/model/signin"; -export const postSignin = async (form: SigninFormProps) => { +export const postSignin = async ( + form: SigninFormProps +): Promise => { try { - const response = await instance.post(`/auth/signin`, form); - return response.data as SigninFormResponse; + const response = await instance.post( + `/auth/signin`, + form + ); + return response.data; } catch (error) { if (isAxiosError(error) && error.response) { throw error.response.data ?? "로그인 실패"; diff --git a/apps/client/src/entities/signup/api/postSignup.ts b/apps/client/src/entities/signup/api/postSignup.ts index 844c29b1..a54e35a0 100644 --- a/apps/client/src/entities/signup/api/postSignup.ts +++ b/apps/client/src/entities/signup/api/postSignup.ts @@ -1,10 +1,10 @@ import instance from "@repo/api/axios"; import { isAxiosError, type AxiosResponse } from "axios"; -import type { SignupFormProps } from "@shared/model/AuthForm"; +import type { SignupFormProps } from "@/shared/model/signup"; export const postSignup = async ( - form: SignupFormProps, + form: SignupFormProps ): Promise => { try { const response = await instance.post(`/auth/signup`, form); diff --git a/apps/client/src/shared/model/AuthForm.ts b/apps/client/src/shared/model/AuthForm.ts deleted file mode 100644 index c3b0f5f5..00000000 --- a/apps/client/src/shared/model/AuthForm.ts +++ /dev/null @@ -1,36 +0,0 @@ -import type { role } from "@repo/types/member"; - -export interface SigninFormProps { - email: string; - password: string; -} - -export interface SigninFormResponse { - accessToken: string; - accessTokenExpiresAt: Date; - refreshToken: string; - refreshTokenExpiresAt: Date; - role: role; -} - -export interface AuthStepForm { - email: string; - authcode: string; - name: string; -} - -export interface SignupStepForm { - password: string; - passwordCheck: string; -} - -export interface SignupFormProps { - email: string; - password: string; - name: string; -} - -export interface ServerResponse { - success: boolean; - message?: string; -} diff --git a/apps/client/src/shared/model/changePWForm.ts b/apps/client/src/shared/model/changePWForm.ts index 7e6c4455..130528f3 100644 --- a/apps/client/src/shared/model/changePWForm.ts +++ b/apps/client/src/shared/model/changePWForm.ts @@ -1,13 +1,13 @@ -import type { AuthStepForm } from "./AuthForm"; +import type { StepAuthCodeForm } from "./signup"; export interface ChangePasswordProps { email: string; password: string; } -export type ChangePW_AuthStepForm = Omit; +export type ChangePassword_StepAuthCodeForm = Omit; -export interface ChangePasswordStepForm { +export interface StepChangePasswordForm { password: string; passwordCheck: string; } diff --git a/apps/client/src/shared/model/signin.ts b/apps/client/src/shared/model/signin.ts new file mode 100644 index 00000000..cb9c8410 --- /dev/null +++ b/apps/client/src/shared/model/signin.ts @@ -0,0 +1,14 @@ +import type { role } from "@repo/types/member"; + +export interface SigninFormProps { + email: string; + password: string; +} + +export interface SigninFormResponse { + accessToken: string; + accessTokenExpiresAt: Date; + refreshToken: string; + refreshTokenExpiresAt: Date; + role: role; +} diff --git a/apps/client/src/shared/model/signup.ts b/apps/client/src/shared/model/signup.ts new file mode 100644 index 00000000..90ea1090 --- /dev/null +++ b/apps/client/src/shared/model/signup.ts @@ -0,0 +1,15 @@ +export interface SignupFormProps { + email: string; + password: string; + name: string; +} +export interface StepAuthCodeForm { + email: string; + authcode: string; + name: string; +} + +export interface StepPasswordForm { + password: string; + passwordCheck: string; +} diff --git a/apps/client/src/views/changePassword/ui/index.tsx b/apps/client/src/views/changePassword/ui/index.tsx index cbe3d191..b9f2187a 100644 --- a/apps/client/src/views/changePassword/ui/index.tsx +++ b/apps/client/src/views/changePassword/ui/index.tsx @@ -11,11 +11,11 @@ import { toast } from "sonner"; import { patchVerifyEmail } from "@/entities/signup/api/patchVerifyEmail"; import { patchPassword } from "@/shared/api/patchPassword"; import type { - ChangePasswordStepForm, + StepChangePasswordForm, ChangePasswordProps, - ChangePW_AuthStepForm, + ChangePassword_StepAuthCodeForm, } from "@/shared/model/changePWForm"; -import type { HttpError } from "@/shared/types/error"; +import type { HttpError } from "@/shared/model/error"; import ChangePassword from "@/widgets/changePassword/ui"; import StepAuthCode from "@/widgets/stepAuthCode/ui"; import { AuthForm } from "@widgets/auth/ui"; @@ -56,7 +56,7 @@ const ChangePasswordView = () => { handleSubmit: handleAuthSubmit, watch: watchAuth, formState: { errors: authErrors }, - } = useForm({ + } = useForm({ mode: "onChange", defaultValues: { email: "", @@ -68,7 +68,7 @@ const ChangePasswordView = () => { control, handleSubmit, formState: { errors: changePWErrors, isValid }, - } = useForm({ + } = useForm({ mode: "onChange", defaultValues: { password: "", passwordCheck: "" }, }); @@ -77,32 +77,32 @@ const ChangePasswordView = () => { const isAuthCodeStepValid = Boolean( watchedAuthValues.email && - /^s\d{5}@gsm\.hs\.kr$/.test(watchedAuthValues.email) && - !authErrors.email, + /^s\d{5}@gsm\.hs\.kr$/.test(watchedAuthValues.email) && + !authErrors.email, ); const canProceedToPassword = isAuthCodeStepValid && Boolean( watchedAuthValues.authcode && - watchedAuthValues.authcode.length >= 8 && - !authErrors.authcode, + watchedAuthValues.authcode.length >= 8 && + !authErrors.authcode, ); const isPasswordValid = useCallback( - (data: ChangePasswordStepForm) => + (data: StepChangePasswordForm) => Boolean( data.password && - data.passwordCheck && - data.password === data.passwordCheck && - !changePWErrors.password && - !changePWErrors.passwordCheck, + data.passwordCheck && + data.password === data.passwordCheck && + !changePWErrors.password && + !changePWErrors.passwordCheck, ), [changePWErrors.password, changePWErrors.passwordCheck], ); const handleVerifyEmail = useCallback( - async (data: ChangePW_AuthStepForm) => { + async (data: ChangePassword_StepAuthCodeForm) => { if (!canProceedToPassword || isAuthVerifying) return; try { @@ -124,7 +124,7 @@ const ChangePasswordView = () => { ); const onSubmit = useCallback( - (data: ChangePasswordStepForm) => { + (data: StepChangePasswordForm) => { if (!verifiedInfo) { toast.error("이메일 인증이 필요합니다."); setStep("authCode"); diff --git a/apps/client/src/views/signin/ui/index.tsx b/apps/client/src/views/signin/ui/index.tsx index 1432a96e..6b7e51b4 100644 --- a/apps/client/src/views/signin/ui/index.tsx +++ b/apps/client/src/views/signin/ui/index.tsx @@ -13,8 +13,8 @@ import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { postSignin } from "@/entities/signin/api/postSignin"; -import type { HttpError } from "@/shared/types/error"; -import type { SigninFormProps } from "@shared/model/AuthForm"; +import type { HttpError } from "@/shared/model/error"; +import type { SigninFormProps } from "@/shared/model/signin"; import { AuthForm } from "@widgets/auth/ui"; const SigninView = () => { diff --git a/apps/client/src/views/signup/ui/index.tsx b/apps/client/src/views/signup/ui/index.tsx index a139a554..335ed485 100644 --- a/apps/client/src/views/signup/ui/index.tsx +++ b/apps/client/src/views/signup/ui/index.tsx @@ -9,13 +9,13 @@ import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { postSignup } from "@/entities/signup/api/postSignup"; -import type { HttpError } from "@/shared/types/error"; -import { patchVerifyEmail } from "@entities/signup/api/patchVerifyEmail"; +import type { HttpError } from "@/shared/model/error"; import type { - AuthStepForm, + StepAuthCodeForm, SignupFormProps, - SignupStepForm, -} from "@shared/model/AuthForm"; + StepPasswordForm +} from "@/shared/model/signup" +import { patchVerifyEmail } from "@entities/signup/api/patchVerifyEmail"; import { AuthForm } from "@widgets/auth/ui"; import StepAuthCode from "@widgets/stepAuthCode/ui"; import StepPassword from "@widgets/stepPassword/ui"; @@ -59,7 +59,7 @@ const SignupView = () => { handleSubmit: handleAuthSubmit, watch: watchAuth, formState: { errors: authErrors }, - } = useForm({ + } = useForm({ mode: "onChange", defaultValues: { name: "", @@ -72,7 +72,7 @@ const SignupView = () => { control: signupControl, handleSubmit: handleSignupSubmit, formState: { errors: signupErrors, isValid }, - } = useForm({ + } = useForm({ mode: "onChange", defaultValues: { password: "", @@ -99,7 +99,7 @@ const SignupView = () => { ); const isPasswordValid = useCallback( - (data: SignupStepForm) => + (data: StepPasswordForm) => Boolean( data.password && data.passwordCheck && @@ -111,7 +111,7 @@ const SignupView = () => { ); const handleVerifyEmail = useCallback( - async (data: AuthStepForm) => { + async (data: StepAuthCodeForm) => { if (!canProceedToPassword || isAuthVerifying) return; try { @@ -133,7 +133,7 @@ const SignupView = () => { ); const onSubmit = useCallback( - (data: SignupStepForm) => { + (data: StepPasswordForm) => { if (!verifiedInfo) { toast.error("이메일 인증이 필요합니다."); setStep("authCode"); diff --git a/apps/client/src/widgets/changePassword/ui/index.tsx b/apps/client/src/widgets/changePassword/ui/index.tsx index a5d57406..94196470 100644 --- a/apps/client/src/widgets/changePassword/ui/index.tsx +++ b/apps/client/src/widgets/changePassword/ui/index.tsx @@ -3,12 +3,12 @@ import { InputContainer } from "@repo/shared/inputContainer"; import React from "react"; import type { Control } from "react-hook-form"; -import type { ChangePasswordStepForm } from "@/shared/model/changePWForm"; +import type { StepChangePasswordForm } from "@/shared/model/changePWForm"; export default function ChangePassword({ control, }: { - control: Control; + control: Control; }) { return ( <> diff --git a/apps/client/src/widgets/stepAuthCode/ui/index.tsx b/apps/client/src/widgets/stepAuthCode/ui/index.tsx index ccd56d2e..2529ec93 100644 --- a/apps/client/src/widgets/stepAuthCode/ui/index.tsx +++ b/apps/client/src/widgets/stepAuthCode/ui/index.tsx @@ -5,21 +5,21 @@ import React, { useCallback, useState } from "react"; import { type Control, useWatch } from "react-hook-form"; import { toast } from "sonner"; -import type { ChangePW_AuthStepForm } from "@/shared/model/changePWForm"; +import type { ChangePassword_StepAuthCodeForm } from "@/shared/model/changePWForm"; import { postSendEmail } from "@entities/signup/api/postSendEmail"; -import type { AuthStepForm } from "@shared/model/AuthForm"; +import type { StepAuthCodeForm } from "@shared/model/signup"; interface StepAuthCodeBaseProps { isAuthButtonActive: boolean; } interface StepAuthCodeWithNameProps extends StepAuthCodeBaseProps { - control: Control; + control: Control; hasName: true; } interface StepAuthCodeWithoutNameProps extends StepAuthCodeBaseProps { - control: Control; + control: Control; hasName?: false; } @@ -33,7 +33,7 @@ export default function StepAuthCode(props: StepAuthCodeProps) { const [show, setShow] = useState(false); const email = useWatch({ - control: control as Control, + control: control as Control, name: "email", }); @@ -61,7 +61,7 @@ export default function StepAuthCode(props: StepAuthCodeProps) { {hasName ? ( } + control={props.control as Control} name="name" rules={{ required: "이름을 필수로 입력해야 합니다.", @@ -73,7 +73,7 @@ export default function StepAuthCode(props: StepAuthCodeProps) {
} + control={control as Control} name="email" rules={{ required: "이메일을 필수로 입력해야 합니다.", @@ -96,7 +96,7 @@ export default function StepAuthCode(props: StepAuthCodeProps) { } + control={control as Control} name="authcode" rules={{ required: "인증번호를 필수로 입력해야 합니다.", diff --git a/apps/client/src/widgets/stepPassword/ui/index.tsx b/apps/client/src/widgets/stepPassword/ui/index.tsx index 9df953b8..b9178679 100644 --- a/apps/client/src/widgets/stepPassword/ui/index.tsx +++ b/apps/client/src/widgets/stepPassword/ui/index.tsx @@ -3,12 +3,12 @@ import { InputContainer } from "@repo/shared/inputContainer"; import React from "react"; import type { Control } from "react-hook-form"; -import type { SignupStepForm } from "@shared/model/AuthForm"; +import type { StepPasswordForm } from "@/shared/model/signup"; export default function StepPassword({ control, }: { - control: Control; + control: Control; }) { return ( <> From 2fc22b24330ca7ab908f2f4e913b48d35b287c52 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 15:33:23 +0900 Subject: [PATCH 014/200] fix: posts --- .../src/entities/posts/api/getSearchResult.ts | 18 ++++++++++++------ apps/client/src/entities/posts/ui/search.tsx | 4 +--- apps/client/src/widgets/posts/ui/index.tsx | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/client/src/entities/posts/api/getSearchResult.ts b/apps/client/src/entities/posts/api/getSearchResult.ts index e9f7d7a2..947369a8 100644 --- a/apps/client/src/entities/posts/api/getSearchResult.ts +++ b/apps/client/src/entities/posts/api/getSearchResult.ts @@ -1,14 +1,20 @@ import instance from "@repo/api/axios"; -import type { AxiosError, AxiosResponse } from "axios"; +import type { EvidenceResponse } from "@repo/types/evidences"; +import { isAxiosError } from "axios"; export const getSearchResult = async ( query: string, - type?: string, -): Promise => { + type?: string +): Promise => { try { - const res = instance.get(`/evidence/search?title=${query}&type=${type}`); - return res; + const response = await instance.get( + `/evidence/search?title=${query}&type=${type}` + ); + return response.data; } catch (error) { - return error as AxiosError; + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "증빙 자료 검색 실패"; + } + throw error; } }; diff --git a/apps/client/src/entities/posts/ui/search.tsx b/apps/client/src/entities/posts/ui/search.tsx index d211e7df..9ac9a1d5 100644 --- a/apps/client/src/entities/posts/ui/search.tsx +++ b/apps/client/src/entities/posts/ui/search.tsx @@ -21,16 +21,14 @@ const Search = ({ setResult, search, type, setSearch }: SearchProps) => { useEffect(() => { const fetchSearchResult = async () => { if (!debouncedValue) return; - try { const search = await getSearchResult(debouncedValue, type); - setResult(search.data as EvidenceResponse); + setResult(search); } catch { toast.error("게시물 검색중 오류가 발생했습니다."); } }; - // Promise를 명시적으로 처리 void fetchSearchResult(); }, [debouncedValue, setResult, type]); diff --git a/apps/client/src/widgets/posts/ui/index.tsx b/apps/client/src/widgets/posts/ui/index.tsx index 185c14ae..90d5cc4d 100644 --- a/apps/client/src/widgets/posts/ui/index.tsx +++ b/apps/client/src/widgets/posts/ui/index.tsx @@ -8,9 +8,9 @@ import { useRouter } from "next/navigation"; import { useCallback, useState } from "react"; import { toast } from "sonner"; -import { useGetDraft } from "@/entities/posts/lib/useGetDraft"; -import { useGetPosts } from "@/entities/posts/lib/useGetPosts"; import Search from "@/entities/posts/ui/search"; +import { useGetDraft } from "@/shared/lib/useGetDraft"; +import { useGetPosts } from "@/shared/lib/useGetPosts" import { Post } from "@/shared/ui"; import type { CategoryType } from "../model/category"; From 06cac709667e32d4cd7e267f840026f90fe937f6 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 15:34:27 +0900 Subject: [PATCH 015/200] fix: score --- .../shared/api/{fixScore.ts => postScore.ts} | 4 +- apps/client/src/shared/model/config.ts | 6 +++ .../edit/api/patchActivity.ts} | 10 ++--- .../edit/api/patchOthers.ts} | 4 +- .../edit/api/patchReading.ts} | 2 +- .../client/src/widgets/edit/api/patchScore.ts | 5 +++ .../edit/model/{config.ts => editConfig.ts} | 40 ++++++++++++++----- .../edit/ui/{EditForm.tsx => index.tsx} | 2 +- .../api/{sendActivity.ts => postActivity.ts} | 4 +- .../{saveDraft.ts => postActivityDraft.ts} | 6 +-- .../write/api/{sendBook.ts => postBook.ts} | 2 +- .../{saveBookDraft.ts => postBookDraft.ts} | 2 +- .../write/api/postScore.ts} | 4 +- 13 files changed, 60 insertions(+), 31 deletions(-) rename apps/client/src/shared/api/{fixScore.ts => postScore.ts} (85%) create mode 100644 apps/client/src/shared/model/config.ts rename apps/client/src/{shared/api/updateActivity.ts => widgets/edit/api/patchActivity.ts} (78%) rename apps/client/src/{shared/api/updateOthers.ts => widgets/edit/api/patchOthers.ts} (84%) rename apps/client/src/{shared/api/updateReading.ts => widgets/edit/api/patchReading.ts} (68%) create mode 100644 apps/client/src/widgets/edit/api/patchScore.ts rename apps/client/src/widgets/edit/model/{config.ts => editConfig.ts} (67%) rename apps/client/src/widgets/edit/ui/{EditForm.tsx => index.tsx} (99%) rename apps/client/src/widgets/write/api/{sendActivity.ts => postActivity.ts} (83%) rename apps/client/src/widgets/write/api/{saveDraft.ts => postActivityDraft.ts} (80%) rename apps/client/src/widgets/write/api/{sendBook.ts => postBook.ts} (74%) rename apps/client/src/widgets/write/api/{saveBookDraft.ts => postBookDraft.ts} (75%) rename apps/client/src/{shared/api/sendScore.ts => widgets/write/api/postScore.ts} (84%) diff --git a/apps/client/src/shared/api/fixScore.ts b/apps/client/src/shared/api/postScore.ts similarity index 85% rename from apps/client/src/shared/api/fixScore.ts rename to apps/client/src/shared/api/postScore.ts index 6557cadc..e4e767d5 100644 --- a/apps/client/src/shared/api/fixScore.ts +++ b/apps/client/src/shared/api/postScore.ts @@ -1,13 +1,13 @@ import instance from "@repo/api/axios"; import { isAxiosError, type AxiosResponse } from "axios"; -interface FixScore { +interface PostScore { categoryName: string; file: File; value: number; } -export const FixScore = async (data: FixScore): Promise => { +export const PostScore = async (data: PostScore): Promise => { try { const formData = new FormData(); formData.append("file", data.file); diff --git a/apps/client/src/shared/model/config.ts b/apps/client/src/shared/model/config.ts new file mode 100644 index 00000000..3b3467fe --- /dev/null +++ b/apps/client/src/shared/model/config.ts @@ -0,0 +1,6 @@ +export type ConfigType = + | "major" + | "humanities" + | "reading" + | "others" + | "foreign"; diff --git a/apps/client/src/shared/api/updateActivity.ts b/apps/client/src/widgets/edit/api/patchActivity.ts similarity index 78% rename from apps/client/src/shared/api/updateActivity.ts rename to apps/client/src/widgets/edit/api/patchActivity.ts index 4061a49e..46f1996d 100644 --- a/apps/client/src/shared/api/updateActivity.ts +++ b/apps/client/src/widgets/edit/api/patchActivity.ts @@ -1,9 +1,9 @@ import instance from "@repo/api/axios"; import type { AxiosError, AxiosResponse } from "axios"; -export const updateMajorActivity = async ( +export const patchMajorActivity = async ( evidenceId: number, - activity: FormData, + activity: FormData ): Promise => { try { const res = await instance.patch(`evidence/major/${evidenceId}`, activity); @@ -13,14 +13,14 @@ export const updateMajorActivity = async ( } }; -export const updateHumanitiesActivity = async ( +export const patchHumanitiesActivity = async ( evidenceId: number, - activity: FormData, + activity: FormData ): Promise => { try { const res = await instance.patch( `evidence/humanities/${evidenceId}`, - activity, + activity ); return res; } catch (error) { diff --git a/apps/client/src/shared/api/updateOthers.ts b/apps/client/src/widgets/edit/api/patchOthers.ts similarity index 84% rename from apps/client/src/shared/api/updateOthers.ts rename to apps/client/src/widgets/edit/api/patchOthers.ts index 39a944fc..d7b73017 100644 --- a/apps/client/src/shared/api/updateOthers.ts +++ b/apps/client/src/widgets/edit/api/patchOthers.ts @@ -1,9 +1,9 @@ import instance from "@repo/api/axios"; import type { AxiosError, AxiosResponse } from "axios"; -export const updateOthers = async ( +export const patchOthers = async ( evidenceId: number, - formData: FormData, + formData: FormData ): Promise => { try { const res = await instance.patch(`evidence/other/${evidenceId}`, formData); diff --git a/apps/client/src/shared/api/updateReading.ts b/apps/client/src/widgets/edit/api/patchReading.ts similarity index 68% rename from apps/client/src/shared/api/updateReading.ts rename to apps/client/src/widgets/edit/api/patchReading.ts index ab775466..ca9175f3 100644 --- a/apps/client/src/shared/api/updateReading.ts +++ b/apps/client/src/widgets/edit/api/patchReading.ts @@ -2,6 +2,6 @@ import instance from "@repo/api/axios"; import type { Book } from "@/widgets/write/model/book"; -export const updateReading = async (evidenceId: number, bookData: Book) => { +export const patchReading = async (evidenceId: number, bookData: Book) => { await instance.patch(`evidence/reading/${evidenceId}`, bookData); }; diff --git a/apps/client/src/widgets/edit/api/patchScore.ts b/apps/client/src/widgets/edit/api/patchScore.ts new file mode 100644 index 00000000..e6b97e2f --- /dev/null +++ b/apps/client/src/widgets/edit/api/patchScore.ts @@ -0,0 +1,5 @@ +import instance from "@repo/api/axios"; + +export const patchScore = async (evidenceId: number, formData: FormData) => { + await instance.patch(`evidence/reading/${evidenceId}`, formData); +}; diff --git a/apps/client/src/widgets/edit/model/config.ts b/apps/client/src/widgets/edit/model/editConfig.ts similarity index 67% rename from apps/client/src/widgets/edit/model/config.ts rename to apps/client/src/widgets/edit/model/editConfig.ts index 9764f10d..d9e1cf7c 100644 --- a/apps/client/src/widgets/edit/model/config.ts +++ b/apps/client/src/widgets/edit/model/editConfig.ts @@ -1,21 +1,25 @@ +import type { ConfigType } from "@/shared/model/config"; import { - updateMajorActivity, - updateHumanitiesActivity, -} from "@/shared/api/updateActivity"; -import { updateReading } from "@/shared/api/updateReading"; -import { majorCategoryOptions } from "@/widgets/calculate/model/category"; + foreignCategoryOptions, + majorCategoryOptions, +} from "@/widgets/calculate/model/category"; import type { FormValues } from "@/widgets/edit/types/types"; import { CharacterCategory } from "@/widgets/write/model/category"; +import { + patchMajorActivity, + patchHumanitiesActivity, +} from "../api/patchActivity"; +import { patchReading } from "../api/patchReading"; +import { patchScore } from "../api/patchScore"; + interface Config { title: string; categoryOptions?: { name: string; send: string }[]; onSubmit: (data: FormValues, id: number) => Promise; } -export const getEditConfig = ( - type: "major" | "humanities" | "reading" | "others", -): Config => { +export const getEditConfig = (type: ConfigType): Config => { switch (type) { case "major": { return { @@ -31,7 +35,7 @@ export const getEditConfig = ( formData.append("content", data.content || ""); formData.append("activityType", "MAJOR"); - await updateMajorActivity(id, formData); + await patchMajorActivity(id, formData); }, }; } @@ -49,7 +53,7 @@ export const getEditConfig = ( formData.append("content", data.content || ""); formData.append("activityType", "HUMANITIES"); - await updateHumanitiesActivity(id, formData); + await patchHumanitiesActivity(id, formData); }, }; } @@ -63,7 +67,21 @@ export const getEditConfig = ( page: Number(data.page) || 0, content: data.content || "", }; - await updateReading(id, bookData); + await patchReading(id, bookData); + }, + }; + } + case "foreign": { + return { + title: "외국어 영역 수정", + categoryOptions: foreignCategoryOptions, + onSubmit: async (data: FormValues, id: number) => { + const formData = new FormData(); + if (data.file) { + formData.append("file", data.file); + } + formData.append("value", String(data.value)); + await patchScore(id, formData); }, }; } diff --git a/apps/client/src/widgets/edit/ui/EditForm.tsx b/apps/client/src/widgets/edit/ui/index.tsx similarity index 99% rename from apps/client/src/widgets/edit/ui/EditForm.tsx rename to apps/client/src/widgets/edit/ui/index.tsx index 09f66987..1f7eee26 100644 --- a/apps/client/src/widgets/edit/ui/EditForm.tsx +++ b/apps/client/src/widgets/edit/ui/index.tsx @@ -11,7 +11,7 @@ import { toast } from "sonner"; import { Dropdown, File, Textarea } from "@/shared/ui"; import { getDefaultValues } from "@/widgets/edit/lib/getDefaultValues"; -import { getEditConfig } from "@/widgets/edit/model/config"; +import { getEditConfig } from "@/widgets/edit/model/editConfig"; import type { EditFormProps, FormValues, diff --git a/apps/client/src/widgets/write/api/sendActivity.ts b/apps/client/src/widgets/write/api/postActivity.ts similarity index 83% rename from apps/client/src/widgets/write/api/sendActivity.ts rename to apps/client/src/widgets/write/api/postActivity.ts index a09a6b5c..021a8565 100644 --- a/apps/client/src/widgets/write/api/sendActivity.ts +++ b/apps/client/src/widgets/write/api/postActivity.ts @@ -1,8 +1,8 @@ import instance from "@repo/api/axios"; import type { AxiosError, AxiosResponse } from "axios"; -export const sendActivity = async ( - activity: FormData, +export const postActivity = async ( + activity: FormData ): Promise => { try { const res = await instance.post("evidence/current/activity", activity); diff --git a/apps/client/src/widgets/write/api/saveDraft.ts b/apps/client/src/widgets/write/api/postActivityDraft.ts similarity index 80% rename from apps/client/src/widgets/write/api/saveDraft.ts rename to apps/client/src/widgets/write/api/postActivityDraft.ts index 58bbb9dd..b58f0e41 100644 --- a/apps/client/src/widgets/write/api/saveDraft.ts +++ b/apps/client/src/widgets/write/api/postActivityDraft.ts @@ -1,13 +1,13 @@ import instance from "@repo/api/axios"; import type { AxiosError, AxiosResponse } from "axios"; -export const saveDraft = async ( - activity: FormData, +export const postActivityDraft = async ( + activity: FormData ): Promise => { try { const res = await instance.post( "/evidence/current/draft/activity", - activity, + activity ); return res; } catch (error) { diff --git a/apps/client/src/widgets/write/api/sendBook.ts b/apps/client/src/widgets/write/api/postBook.ts similarity index 74% rename from apps/client/src/widgets/write/api/sendBook.ts rename to apps/client/src/widgets/write/api/postBook.ts index c8218946..2f2c4aaa 100644 --- a/apps/client/src/widgets/write/api/sendBook.ts +++ b/apps/client/src/widgets/write/api/postBook.ts @@ -2,6 +2,6 @@ import instance from "@repo/api/axios"; import type { Book } from "../model/book"; -export const sendBook = async (bookData: Book) => { +export const postBook = async (bookData: Book) => { await instance.post("evidence/current/reading", bookData); }; diff --git a/apps/client/src/widgets/write/api/saveBookDraft.ts b/apps/client/src/widgets/write/api/postBookDraft.ts similarity index 75% rename from apps/client/src/widgets/write/api/saveBookDraft.ts rename to apps/client/src/widgets/write/api/postBookDraft.ts index a0a285da..938c44a4 100644 --- a/apps/client/src/widgets/write/api/saveBookDraft.ts +++ b/apps/client/src/widgets/write/api/postBookDraft.ts @@ -2,6 +2,6 @@ import instance from "@repo/api/axios"; import type { Book } from "../model/book"; -export const saveBookDraft = async (data: Book) => { +export const postBookDraft = async (data: Book) => { return await instance.post("/evidence/current/draft/reading", data); }; diff --git a/apps/client/src/shared/api/sendScore.ts b/apps/client/src/widgets/write/api/postScore.ts similarity index 84% rename from apps/client/src/shared/api/sendScore.ts rename to apps/client/src/widgets/write/api/postScore.ts index 5ba77ff1..1347d1b6 100644 --- a/apps/client/src/shared/api/sendScore.ts +++ b/apps/client/src/widgets/write/api/postScore.ts @@ -1,8 +1,8 @@ import instance from "@repo/api/axios"; import type { AxiosError, AxiosResponse } from "axios"; -export const sendScore = async ( - formData: FormData, +export const postScore = async ( + formData: FormData ): Promise => { try { const res = await instance.post("/evidence/current/scoring", formData); From 287a6a11ae4e84769b7b2449df5feacf791ded27 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 15:34:44 +0900 Subject: [PATCH 016/200] fix: edit --- apps/client/src/views/edit/index.tsx | 6 +++--- apps/client/src/widgets/edit/lib/getDefaultValues.ts | 2 +- apps/client/src/widgets/edit/types/types.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/client/src/views/edit/index.tsx b/apps/client/src/views/edit/index.tsx index b47dcecb..407351e3 100644 --- a/apps/client/src/views/edit/index.tsx +++ b/apps/client/src/views/edit/index.tsx @@ -6,9 +6,9 @@ import { isActivity, isReading } from "@repo/utils/handlePost"; import { useParams, useSearchParams } from "next/navigation"; import { toast } from "sonner"; -import { useGetDraft } from "@/entities/posts/lib/useGetDraft"; -import { useGetPosts } from "@/entities/posts/lib/useGetPosts"; -import EditForm from "@/widgets/edit/ui/EditForm"; +import { useGetDraft } from "@/shared/lib/useGetDraft"; +import { useGetPosts } from "@/shared/lib/useGetPosts" +import EditForm from "@/widgets/edit/ui"; const EditView = () => { const params = useParams(); diff --git a/apps/client/src/widgets/edit/lib/getDefaultValues.ts b/apps/client/src/widgets/edit/lib/getDefaultValues.ts index 8528709b..bea78a0e 100644 --- a/apps/client/src/widgets/edit/lib/getDefaultValues.ts +++ b/apps/client/src/widgets/edit/lib/getDefaultValues.ts @@ -1,6 +1,6 @@ import type { Activity, Reading, Others } from "@repo/types/evidences"; -import { getEditConfig } from "../model/config"; +import { getEditConfig } from "../model/editConfig"; import type { FormValues } from "../types/types"; export const getDefaultValues = ( diff --git a/apps/client/src/widgets/edit/types/types.ts b/apps/client/src/widgets/edit/types/types.ts index 27172eda..e5263420 100644 --- a/apps/client/src/widgets/edit/types/types.ts +++ b/apps/client/src/widgets/edit/types/types.ts @@ -13,7 +13,7 @@ export interface FormValues { file?: File; author?: string; page?: string; - value?: string | number; + value?: number; draftId?: string; } From 0805a0d17e5e2041e4fe1611dd6e8815fb6f5386 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 15:34:55 +0900 Subject: [PATCH 017/200] fix: detail --- apps/client/src/views/detail/index.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/client/src/views/detail/index.tsx b/apps/client/src/views/detail/index.tsx index f9778f41..1b0509d9 100644 --- a/apps/client/src/views/detail/index.tsx +++ b/apps/client/src/views/detail/index.tsx @@ -11,23 +11,25 @@ import { useCallback, useState } from "react"; import { toast } from "sonner"; import { deletePost } from "@/entities/detail/api/deletePost"; -import { useGetDraft } from "@/entities/posts/lib/useGetDraft"; -import { useGetPosts } from "@/entities/posts/lib/useGetPosts"; -import { useGetCurrentMember } from "@/shared/model/useGetCurrentMember"; +import { useGetCurrentMember } from "@/shared/lib/useGetCurrentMember"; +import { useGetDraft } from "@/shared/lib/useGetDraft"; +import { useGetPosts } from "@/shared/lib/useGetPosts"; import MockJson from "@shared/mocks/data/evidenceMock.json"; const DetailView = () => { + const [modalOpen, setModalOpen] = useState(false); + const searchParams = useSearchParams(); const example = searchParams.get("example"); const draft = searchParams.get("draft"); + const params = useParams(); const router = useRouter(); const { id } = params; + const { data: postsData, isError: isPostsError } = useGetPosts(null); const { data: draftsData, isError: isDraftsError } = useGetDraft(); - const { data: studentData, isError: isStudentDataError } = - useGetCurrentMember(); - const [modalOpen, setModalOpen] = useState(false); + const { data: studentData, isError: isStudentDataError } = useGetCurrentMember(); if (isPostsError || isDraftsError) { toast.error("게시물을 불러오지 못했습니다."); From 4d218aa12609c0ee0b1d907efe920d0494f4ac51 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 15:35:06 +0900 Subject: [PATCH 018/200] fix: write --- .../src/widgets/write/lib/handleBookSubmit.ts | 8 +++--- .../widgets/write/lib/handleSubmitActivity.ts | 10 +++---- .../src/widgets/write/model/writeConfig.ts | 27 +++++++++---------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/apps/client/src/widgets/write/lib/handleBookSubmit.ts b/apps/client/src/widgets/write/lib/handleBookSubmit.ts index 41708dc4..79206447 100644 --- a/apps/client/src/widgets/write/lib/handleBookSubmit.ts +++ b/apps/client/src/widgets/write/lib/handleBookSubmit.ts @@ -1,15 +1,15 @@ import { toast } from "sonner"; -import { saveBookDraft } from "../api/saveBookDraft"; -import { sendBook } from "../api/sendBook"; +import { postBook } from "../api/postBook"; +import { postBookDraft } from "../api/postBookDraft"; import type { Book } from "../model/book"; export const handleSubmitBook = async ( data: Book, - submitType: "submit" | "draft", + submitType: "submit" | "draft" ) => { try { - await (submitType === "draft" ? saveBookDraft(data) : sendBook(data)); + await (submitType === "draft" ? postBookDraft(data) : postBook(data)); toast.success(submitType === "draft" ? "임시저장 완료" : "제출 완료"); return true; } catch { diff --git a/apps/client/src/widgets/write/lib/handleSubmitActivity.ts b/apps/client/src/widgets/write/lib/handleSubmitActivity.ts index 73dc5eba..5a1dff71 100644 --- a/apps/client/src/widgets/write/lib/handleSubmitActivity.ts +++ b/apps/client/src/widgets/write/lib/handleSubmitActivity.ts @@ -1,16 +1,16 @@ import { toast } from "sonner"; -import { saveDraft } from "../api/saveDraft"; -import { sendActivity } from "../api/sendActivity"; +import { postActivity } from "../api/postActivity"; +import { postActivityDraft } from "../api/postActivityDraft"; export const handleSubmitActivity = async ( submitType: "submit" | "draft", - formData: FormData, + formData: FormData ) => { try { await (submitType === "draft" - ? saveDraft(formData) - : sendActivity(formData)); + ? postActivityDraft(formData) + : postActivity(formData)); toast.success(submitType === "draft" ? "임시저장 완료" : "제출 완료"); return true; } catch { diff --git a/apps/client/src/widgets/write/model/writeConfig.ts b/apps/client/src/widgets/write/model/writeConfig.ts index 21eb5fad..747aae9c 100644 --- a/apps/client/src/widgets/write/model/writeConfig.ts +++ b/apps/client/src/widgets/write/model/writeConfig.ts @@ -1,8 +1,9 @@ -import { sendScore } from "@/shared/api/sendScore"; +import type { ConfigType } from "@/shared/model/config"; import { majorCategoryOptions } from "@/widgets/calculate/model/category"; import type { FormValues } from "@/widgets/edit/types/types"; import { CharacterCategory } from "@/widgets/write/model/category"; +import { postScore } from "../api/postScore"; import { handleSubmitBook } from "../lib/handleBookSubmit"; import { handleSubmitActivity } from "../lib/handleSubmitActivity"; @@ -14,9 +15,7 @@ interface Config { onSubmit: (data: FormValues, type: "draft" | "submit") => Promise; } -export const getWriteConfig = ( - type: "major" | "humanities" | "reading" | "others" | "foreign" -): Config => { +export const getWriteConfig = (type: ConfigType): Config => { switch (type) { case "major": { return { @@ -75,14 +74,6 @@ export const getWriteConfig = ( }, }; } - case "others": { - return { - title: "기타 증빙 자료", - onSubmit: async () => { - // No submission logic implemented for 'others' category yet. - }, - }; - } case "foreign": { return { title: "외국어 영역", @@ -93,8 +84,16 @@ export const getWriteConfig = ( formData.append("file", data.file); } formData.append("categoryName", data.categoryName?.send ?? ""); - formData.append("value", data.title || ""); - await sendScore(formData); + formData.append("value", String(data.value)); + await postScore(formData); + }, + }; + } + case "others": { + return { + title: "기타 증빙 자료", + onSubmit: async () => { + // No submission logic implemented for 'others' category yet. }, }; } From ebbf1b6b2a09a25f590c682bf5a772a90718f681 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 15:35:14 +0900 Subject: [PATCH 019/200] fix: main --- apps/client/src/views/main/ui/index.tsx | 6 +++--- apps/client/src/widgets/main/model/evidence.ts | 2 +- apps/client/src/widgets/main/ui/modal.tsx | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/client/src/views/main/ui/index.tsx b/apps/client/src/views/main/ui/index.tsx index a2c51c8b..bc118a44 100644 --- a/apps/client/src/views/main/ui/index.tsx +++ b/apps/client/src/views/main/ui/index.tsx @@ -9,7 +9,7 @@ import Link from "next/link"; import { useCallback, useEffect, useState } from "react"; import ShowSignin from "@/entities/main/ui/showSignin"; -import { useGetCurrentMember } from "@/shared/model/useGetCurrentMember"; +import { useGetCurrentMember } from "@/shared/lib/useGetCurrentMember"; import { getCertification } from "@entities/main/api/getCertification"; import MainDropdown from "@entities/main/ui/dropdown"; import { ShowInformation } from "@entities/main/ui/showInformation"; @@ -168,8 +168,8 @@ const MainView = () => { 로그인 후 확인가능합니다. ) : (certification && - certification.data.certificates.length > 0 ? ( - certification.data.certificates.map((v, i) => ( + certification.certificates.length > 0 ? ( + certification.certificates.map((v, i) => ( )) ) : ( diff --git a/apps/client/src/widgets/main/model/evidence.ts b/apps/client/src/widgets/main/model/evidence.ts index d453f8a7..c78418ba 100644 --- a/apps/client/src/widgets/main/model/evidence.ts +++ b/apps/client/src/widgets/main/model/evidence.ts @@ -1,7 +1,7 @@ export interface Evidence { categoryName: string; file: File; - acquisitionDate?: string; + acquisitionDate?: Date; value?: number; option: { send: string; name: string }; } diff --git a/apps/client/src/widgets/main/ui/modal.tsx b/apps/client/src/widgets/main/ui/modal.tsx index 24b55f92..9fbcd4a4 100644 --- a/apps/client/src/widgets/main/ui/modal.tsx +++ b/apps/client/src/widgets/main/ui/modal.tsx @@ -8,8 +8,8 @@ import React, { useCallback } from "react"; import { Controller, useForm } from "react-hook-form"; import { toast } from "sonner"; -import type { HttpError } from "@/shared/types/error"; -import { FixScore } from "@shared/api/fixScore"; +import type { HttpError } from "@/shared/model/error"; +import { PostScore } from "@shared/api/postScore"; import Dropdown from "@shared/ui/dropdown"; import File from "@shared/ui/file"; @@ -53,7 +53,7 @@ const Modal = ({ onClose, type }: ModalProps) => { }); } case "TOPCIT": { - return await FixScore({ + return await PostScore({ categoryName: "MAJOR-TOPCIT_SCORE", file: data.file, value: Number(data.value), From 4697c5db11c2e360c78fa559569ee251eb8defb6 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 16:04:42 +0900 Subject: [PATCH 020/200] fix: detail --- apps/client/src/views/detail/index.tsx | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/apps/client/src/views/detail/index.tsx b/apps/client/src/views/detail/index.tsx index 1b0509d9..301b1ffd 100644 --- a/apps/client/src/views/detail/index.tsx +++ b/apps/client/src/views/detail/index.tsx @@ -11,7 +11,6 @@ import { useCallback, useState } from "react"; import { toast } from "sonner"; import { deletePost } from "@/entities/detail/api/deletePost"; -import { useGetCurrentMember } from "@/shared/lib/useGetCurrentMember"; import { useGetDraft } from "@/shared/lib/useGetDraft"; import { useGetPosts } from "@/shared/lib/useGetPosts"; import MockJson from "@shared/mocks/data/evidenceMock.json"; @@ -29,16 +28,11 @@ const DetailView = () => { const { data: postsData, isError: isPostsError } = useGetPosts(null); const { data: draftsData, isError: isDraftsError } = useGetDraft(); - const { data: studentData, isError: isStudentDataError } = useGetCurrentMember(); if (isPostsError || isDraftsError) { toast.error("게시물을 불러오지 못했습니다."); } - if (isStudentDataError) { - toast.error("회원 정보를 불러오지 못했습니다."); - } - const posts: post[] = [ ...(postsData?.data.majorActivityEvidence ?? []), ...(postsData?.data.humanitiesActivityEvidence ?? []), @@ -112,7 +106,7 @@ const DetailView = () => { content = post.content; if ("author" in post && post.author) { - subTitle = post.author; + subTitle = `저자: ${post.author}`; } else if ("categoryName" in post) { subTitle = `카테고리: ${getCategoryName(post.categoryName)}`; } @@ -130,12 +124,8 @@ const DetailView = () => {

{title}

-

- {`${studentData?.name ?? "사용자"} · ${subTitle}`} -

-
{imageUri == null ? null : (
@@ -148,7 +138,6 @@ const DetailView = () => { />
)} -

{subTitle}

@@ -167,7 +156,6 @@ const DetailView = () => {

- {draft == null && example !== "true" && ( { 이 게시글 삭제하기 )} -
{draft == null && example == null ? ( <> From 0bf74ec8722eeadd9cc0c91d2373d00d41f0d381 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 16:39:35 +0900 Subject: [PATCH 021/200] chore: calculate --- .../client/src/widgets/calculate/ui/index.tsx | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/apps/client/src/widgets/calculate/ui/index.tsx b/apps/client/src/widgets/calculate/ui/index.tsx index 5d3a82f6..d5536221 100644 --- a/apps/client/src/widgets/calculate/ui/index.tsx +++ b/apps/client/src/widgets/calculate/ui/index.tsx @@ -20,18 +20,13 @@ export const Calculate = () => { const [bookCount, setBookCount] = useState(0); const [totalScore, setTotalScore] = useState(0); - const [selectedOptions, setSelectedOptions] = useState< - Record - >({ + const [selectedOptions, setSelectedOptions] = useState>({ 인성: null, 전공: null, 외국어: null, }); - const [categoryCounts, setCategoryCounts] = useState>( - {}, - ); - + const [categoryCounts, setCategoryCounts] = useState>({}); const [idCounts, setIdCounts] = useState>({}); const { control } = useForm(); @@ -44,9 +39,9 @@ export const Calculate = () => { const selectedId = selected.id; const currentSendCount = categoryCounts[selected.send] ?? 0; const currentIdCount = idCounts[selectedId] ?? 0; - const max = - Number.parseInt(selected.max_number?.replace(/[^0-9]/g, "") ?? "") || 1; + const max = Number.parseInt(selected.max_number?.replace(/[^0-9]/g, "") ?? "") || 1; const score = Number.parseInt(selected.score?.match(/\d+/)?.[0] ?? "0"); + if (currentIdCount < max) { setCategoryCounts((prev) => ({ ...prev, @@ -71,6 +66,7 @@ export const Calculate = () => { const score = Number.parseInt(selected.score?.match(/\d+/)?.[0] ?? "0"); const currentSendCount = categoryCounts[selected.send] ?? 0; const currentIdCount = idCounts[selected.id] ?? 0; + if (currentSendCount > 0 && currentIdCount > 0) { setCategoryCounts((prev) => ({ ...prev, @@ -93,13 +89,6 @@ export const Calculate = () => { [], ); - const handleBookMinus = useCallback(() => { - if (bookCount > 0) { - setBookCount((prev) => prev - 1); - setTotalScore((prev) => prev - 10); - } - }, [bookCount]); - const handleBookPlus = useCallback(() => { if (bookCount < 10) { setBookCount((prev) => prev + 1); @@ -107,6 +96,13 @@ export const Calculate = () => { } }, [bookCount]); + const handleBookMinus = useCallback(() => { + if (bookCount > 0) { + setBookCount((prev) => prev - 1); + setTotalScore((prev) => prev - 10); + } + }, [bookCount]); + return (
From c400cb59a44e9e069780996cf057c74c7ce6ff8e Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Wed, 2 Jul 2025 23:10:46 +0900 Subject: [PATCH 022/200] move: score_category --- apps/admin/src/views/score/model/score_category.ts | 7 +++++++ apps/admin/src/views/score/ui/scoreForm.tsx | 14 +++----------- 2 files changed, 10 insertions(+), 11 deletions(-) create mode 100644 apps/admin/src/views/score/model/score_category.ts diff --git a/apps/admin/src/views/score/model/score_category.ts b/apps/admin/src/views/score/model/score_category.ts new file mode 100644 index 00000000..c057d22e --- /dev/null +++ b/apps/admin/src/views/score/model/score_category.ts @@ -0,0 +1,7 @@ +export const SCORE_CATEGORIES = { + ACTIVITY: "HUMANITIES-SERVICE-ACTIVITY", + SEMESTER_1: "HUMANITIES-SERVICE-CLUB_SEMESTER_1", + SEMESTER_2: "HUMANITIES-SERVICE-CLUB_SEMESTER_2", + NEWRROW: "HUMANITIES-ACTIVITIES-NEWRROW_S", + TOEIC: "FOREIGN_LANG-ATTENDANCE-TOEIC_ACADEMY_STATUS", +}; diff --git a/apps/admin/src/views/score/ui/scoreForm.tsx b/apps/admin/src/views/score/ui/scoreForm.tsx index 168f7cde..84207c41 100644 --- a/apps/admin/src/views/score/ui/scoreForm.tsx +++ b/apps/admin/src/views/score/ui/scoreForm.tsx @@ -8,20 +8,12 @@ import { useCallback } from "react"; import { Controller, useForm, useWatch } from "react-hook-form"; import { toast } from "sonner"; -import { Checkbox } from "@/entities/score/ui/checkbox"; -import Header from "@/shared/ui/header"; - import { featScore } from "../api/featScore"; import type { ScoreFormType } from "../model/score"; +import { SCORE_CATEGORIES } from "../model/score_category"; - -const SCORE_CATEGORIES = { - ACTIVITY: "HUMANITIES-SERVICE-ACTIVITY", - SEMESTER_1: "HUMANITIES-SERVICE-CLUB_SEMESTER_1", - SEMESTER_2: "HUMANITIES-SERVICE-CLUB_SEMESTER_2", - NEWRROW: "HUMANITIES-ACTIVITIES-NEWRROW_S", - TOEIC: "FOREIGN_LANG-ATTENDANCE-TOEIC_ACADEMY_STATUS", -} as const; +import { Checkbox } from "@/entities/score/ui/checkbox"; +import Header from "@/shared/ui/header"; const ScoreForm = () => { const { id } = useParams(); From 11eeb37ec306c21036fef3245334b9d3ff81e100 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 07:55:11 +0900 Subject: [PATCH 023/200] =?UTF-8?q?fix:=20OPIC=20=EC=98=A4=ED=83=88?= =?UTF-8?q?=EC=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/utils/src/handleCategory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/handleCategory.ts b/packages/utils/src/handleCategory.ts index 367b418c..4375e6a6 100644 --- a/packages/utils/src/handleCategory.ts +++ b/packages/utils/src/handleCategory.ts @@ -67,7 +67,7 @@ export const categoryMapping: Record = { "FOREIGN_LANG-TEPS_SCORE": "외국어 영역-외국어 공인 시험-TEPS", "FOREIGN_LANG-TOEIC_SPEAKING_LEVEL": "외국어 영역-외국어 공인 시험-TOEIC Speaking", - "FOREIGN_LANG-OPIC_SCORE": "외국어 영역-외국어 공인 시험-OPIc", + "FOREIGN_LANG-OPIC_SCORE": "외국어 영역-외국어 공인 시험-OPIC", "FOREIGN_LANG-JPT_SCORE": "외국어 영역-외국어 공인 시험-JPT", "FOREIGN_LANG-CPT_SCORE": "외국어 영역-외국어 공인 시험-CPT", "FOREIGN_LANG-HSK_SCORE": "외국어 영역-외국어 공인 시험-HSK", From c197d7e71d1dfc4a521051641e6150a63f361ceb Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 08:50:11 +0900 Subject: [PATCH 024/200] chore: auth --- .../src/views/changePassword/ui/index.tsx | 68 ++++++++--------- apps/client/src/views/signup/ui/index.tsx | 74 ++++++++----------- 2 files changed, 63 insertions(+), 79 deletions(-) diff --git a/apps/client/src/views/changePassword/ui/index.tsx b/apps/client/src/views/changePassword/ui/index.tsx index b9f2187a..f7387262 100644 --- a/apps/client/src/views/changePassword/ui/index.tsx +++ b/apps/client/src/views/changePassword/ui/index.tsx @@ -26,9 +26,7 @@ const ChangePasswordView = () => { const [step, setStep] = useState("authCode"); const [isAuthVerifying, setIsAuthVerifying] = useState(false); - const [verifiedInfo, setVerifiedInfo] = useState<{ email: string } | null>( - null, - ); + const [verifiedInfo, setVerifiedInfo] = useState<{ email: string } | null>(null); const { mutate: changePWMutate, isPending } = useMutation({ mutationFn: (form: ChangePasswordProps) => patchPassword(form), @@ -81,46 +79,42 @@ const ChangePasswordView = () => { !authErrors.email, ); - const canProceedToPassword = + const canProceedToPassword = Boolean( isAuthCodeStepValid && + watchedAuthValues.authcode && + watchedAuthValues.authcode.length >= 8 && + !authErrors.authcode, + ); + + const isPasswordValid = useCallback((data: StepChangePasswordForm) => Boolean( - watchedAuthValues.authcode && - watchedAuthValues.authcode.length >= 8 && - !authErrors.authcode, - ); - - const isPasswordValid = useCallback( - (data: StepChangePasswordForm) => - Boolean( - data.password && - data.passwordCheck && - data.password === data.passwordCheck && - !changePWErrors.password && - !changePWErrors.passwordCheck, - ), + data.password && + data.passwordCheck && + data.password === data.passwordCheck && + !changePWErrors.password && + !changePWErrors.passwordCheck, + ), [changePWErrors.password, changePWErrors.passwordCheck], ); - const handleVerifyEmail = useCallback( - async (data: ChangePassword_StepAuthCodeForm) => { - if (!canProceedToPassword || isAuthVerifying) return; - - try { - setIsAuthVerifying(true); - const response = await patchVerifyEmail(Number(data.authcode)); - - if (response.status === 204) { - setVerifiedInfo({ email: data.email }); - setStep("password"); - toast.success("이메일 인증이 완료되었습니다."); - } - } catch { - toast.error("인증코드가 일치하지 않습니다."); - } finally { - setIsAuthVerifying(false); + const handleVerifyEmail = useCallback(async (data: ChangePassword_StepAuthCodeForm) => { + if (!canProceedToPassword || isAuthVerifying) return; + + try { + setIsAuthVerifying(true); + const response = await patchVerifyEmail(Number(data.authcode)); + + if (response.status === 204) { + setVerifiedInfo({ email: data.email }); + setStep("password"); + toast.success("이메일 인증이 완료되었습니다."); } - }, - [canProceedToPassword, isAuthVerifying], + } catch { + toast.error("인증코드가 일치하지 않습니다."); + } finally { + setIsAuthVerifying(false); + } + }, [canProceedToPassword, isAuthVerifying] ); const onSubmit = useCallback( diff --git a/apps/client/src/views/signup/ui/index.tsx b/apps/client/src/views/signup/ui/index.tsx index 335ed485..94fc4531 100644 --- a/apps/client/src/views/signup/ui/index.tsx +++ b/apps/client/src/views/signup/ui/index.tsx @@ -26,10 +26,7 @@ const SignupView = () => { const [step, setStep] = useState("authCode"); const [isAuthVerifying, setIsAuthVerifying] = useState(false); - const [verifiedInfo, setVerifiedInfo] = useState<{ - name: string; - email: string; - } | null>(null); + const [verifiedInfo, setVerifiedInfo] = useState<{ name: string; email: string; } | null>(null); const { mutate: signupMutate, isPending } = useMutation({ mutationFn: (form: SignupFormProps) => postSignup(form), @@ -74,10 +71,7 @@ const SignupView = () => { formState: { errors: signupErrors, isValid }, } = useForm({ mode: "onChange", - defaultValues: { - password: "", - passwordCheck: "", - }, + defaultValues: { password: "", passwordCheck: "", }, }); const watchedAuthValues = watchAuth(); @@ -90,46 +84,42 @@ const SignupView = () => { !authErrors.email, ); - const canProceedToPassword = + const canProceedToPassword = Boolean( isAuthCodeStepValid && + watchedAuthValues.authcode && + watchedAuthValues.authcode.length >= 8 && + !authErrors.authcode, + ); + + const isPasswordValid = useCallback((data: StepPasswordForm) => Boolean( - watchedAuthValues.authcode && - watchedAuthValues.authcode.length >= 8 && - !authErrors.authcode, - ); - - const isPasswordValid = useCallback( - (data: StepPasswordForm) => - Boolean( - data.password && - data.passwordCheck && - data.password === data.passwordCheck && - !signupErrors.password && - !signupErrors.passwordCheck, - ), + data.password && + data.passwordCheck && + data.password === data.passwordCheck && + !signupErrors.password && + !signupErrors.passwordCheck, + ), [signupErrors.password, signupErrors.passwordCheck], ); - const handleVerifyEmail = useCallback( - async (data: StepAuthCodeForm) => { - if (!canProceedToPassword || isAuthVerifying) return; - - try { - setIsAuthVerifying(true); - const response = await patchVerifyEmail(Number(data.authcode)); - - if (response.status === 204) { - setVerifiedInfo({ name: data.name, email: data.email }); - setStep("password"); - toast.success("이메일 인증이 완료되었습니다."); - } - } catch { - toast.error("인증코드가 일치하지 않습니다."); - } finally { - setIsAuthVerifying(false); + const handleVerifyEmail = useCallback(async (data: StepAuthCodeForm) => { + if (!canProceedToPassword || isAuthVerifying) return; + + try { + setIsAuthVerifying(true); + const response = await patchVerifyEmail(Number(data.authcode)); + + if (response.status === 204) { + setVerifiedInfo({ name: data.name, email: data.email }); + setStep("password"); + toast.success("이메일 인증이 완료되었습니다."); } - }, - [canProceedToPassword, isAuthVerifying], + } catch { + toast.error("인증코드가 일치하지 않습니다."); + } finally { + setIsAuthVerifying(false); + } + }, [canProceedToPassword, isAuthVerifying] ); const onSubmit = useCallback( From 172201e4618168a9c9443889398da575138640fc Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 09:32:14 +0900 Subject: [PATCH 025/200] =?UTF-8?q?fix:=20=EA=B5=90=EB=82=B4=EC=99=B8?= =?UTF-8?q?=EC=9D=B8=EC=84=B1=EC=98=81=EC=97=AD=EA=B4=80=EB=A0=A8=EC=88=98?= =?UTF-8?q?=EC=83=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/admin/src/views/score/model/score.ts | 2 + .../src/views/score/model/score_category.ts | 2 + apps/admin/src/views/score/ui/scoreForm.tsx | 131 +++++++++++------- .../src/widgets/write/model/category.ts | 8 -- 4 files changed, 86 insertions(+), 57 deletions(-) diff --git a/apps/admin/src/views/score/model/score.ts b/apps/admin/src/views/score/model/score.ts index 26504bde..bb5bb43d 100644 --- a/apps/admin/src/views/score/model/score.ts +++ b/apps/admin/src/views/score/model/score.ts @@ -5,6 +5,8 @@ export interface Score { export interface ScoreFormType { activity: number | null; + inAward: number | null; + outAward: number | null; oneSemester: number | null; twoSemester: number | null; newrrow: number | null; diff --git a/apps/admin/src/views/score/model/score_category.ts b/apps/admin/src/views/score/model/score_category.ts index c057d22e..69c49ec2 100644 --- a/apps/admin/src/views/score/model/score_category.ts +++ b/apps/admin/src/views/score/model/score_category.ts @@ -1,4 +1,6 @@ export const SCORE_CATEGORIES = { + AWARD_IN: "HUMANITIES-AWARD_CAREER-HUMANITY-IN_SCHOOL", + AWARD_OUT: "HUMANITIES-AWARD_CAREER-HUMANITY-OUT_SCHOOL", ACTIVITY: "HUMANITIES-SERVICE-ACTIVITY", SEMESTER_1: "HUMANITIES-SERVICE-CLUB_SEMESTER_1", SEMESTER_2: "HUMANITIES-SERVICE-CLUB_SEMESTER_2", diff --git a/apps/admin/src/views/score/ui/scoreForm.tsx b/apps/admin/src/views/score/ui/scoreForm.tsx index 84207c41..bfcb6a76 100644 --- a/apps/admin/src/views/score/ui/scoreForm.tsx +++ b/apps/admin/src/views/score/ui/scoreForm.tsx @@ -69,48 +69,59 @@ const ScoreForm = () => { let success = true; if (data.activity !== null && data.activity > 0) { - success = - (await handleScoreSubmit( - SCORE_CATEGORIES.ACTIVITY, - data.activity, - "봉사활동 점수 추가 완료", - )) && success; + success = (await handleScoreSubmit( + SCORE_CATEGORIES.ACTIVITY, + data.activity, + "봉사활동 점수 추가 완료", + )) && success; } - else if (data.oneSemester !== null && data.oneSemester > 0) { - success = - (await handleScoreSubmit( - SCORE_CATEGORIES.SEMESTER_1, - data.oneSemester, - "1학기 봉사 시간 점수 추가 완료", - )) && success; + if (data.oneSemester !== null && data.oneSemester > 0) { + success = (await handleScoreSubmit( + SCORE_CATEGORIES.SEMESTER_1, + data.oneSemester, + "1학기 봉사 시간 점수 추가 완료", + )) && success; } if (data.twoSemester !== null && data.twoSemester > 0) { - success = - (await handleScoreSubmit( - SCORE_CATEGORIES.SEMESTER_2, - data.twoSemester, - "2학기 봉사 시간 점수 추가 완료", - )) && success; + success = (await handleScoreSubmit( + SCORE_CATEGORIES.SEMESTER_2, + data.twoSemester, + "2학기 봉사 시간 점수 추가 완료", + )) && success; + } + + if (data.inAward !== null && data.inAward > 0) { + success = (await handleScoreSubmit( + SCORE_CATEGORIES.AWARD_IN, + data.inAward, + "교내인성영역관련수상 점수 추가 완료", + )) && success; + } + + if (data.outAward !== null && data.outAward > 0) { + success = (await handleScoreSubmit( + SCORE_CATEGORIES.AWARD_OUT, + data.outAward, + "교외인성영역관련수상 점수 추가 완료", + )) && success; } if (data.newrrow !== null && data.newrrow > 0) { - success = - (await handleScoreSubmit( - SCORE_CATEGORIES.NEWRROW, - data.newrrow, - "뉴로우 참여 횟수 점수 추가 완료", - )) && success; + success = (await handleScoreSubmit( + SCORE_CATEGORIES.NEWRROW, + data.newrrow, + "뉴로우 참여 횟수 점수 추가 완료", + )) && success; } if (data.checkbox !== undefined) { - success = - (await handleScoreSubmit( - SCORE_CATEGORIES.TOEIC, - data.checkbox ? 1 : 0, - "TOEIC 참여 여부 점수 추가 완료", - )) && success; + success = (await handleScoreSubmit( + SCORE_CATEGORIES.TOEIC, + data.checkbox ? 1 : 0, + "TOEIC 참여 여부 점수 추가 완료", + )) && success; } if (success) { @@ -147,24 +158,46 @@ const ScoreForm = () => { type="number" /> - - - - - - +
+ + + + + + +
+
+ + + + + + +
Date: Thu, 3 Jul 2025 09:44:56 +0900 Subject: [PATCH 026/200] fix: writeCategory, editCategory, calculateCategory --- .../src/widgets/calculate/model/category.ts | 42 +++---- .../src/widgets/edit/model/editConfig.ts | 16 +-- .../src/widgets/write/model/category.ts | 108 +++++++++++++++++- .../src/widgets/write/model/foreignOptions.ts | 13 --- .../src/widgets/write/model/writeConfig.ts | 15 +-- 5 files changed, 144 insertions(+), 50 deletions(-) delete mode 100644 apps/client/src/widgets/write/model/foreignOptions.ts diff --git a/apps/client/src/widgets/calculate/model/category.ts b/apps/client/src/widgets/calculate/model/category.ts index e8e21de8..8fb9b1af 100644 --- a/apps/client/src/widgets/calculate/model/category.ts +++ b/apps/client/src/widgets/calculate/model/category.ts @@ -125,72 +125,72 @@ export const humanCategoryOptions = [ name: "교내인성영역관련수상", score: "50점", max_number: "최대 4회", - send: "humanities-award_career-humanity-in_school", + send: "HUMANITIES-AWARD_CAREER-HUMANITY-IN_SCHOOL", id: 5, }, { name: "교외인성영역관련수상", score: "50점", max_number: "최대 4회", - send: "humanities-award_career-humanity-out_school", + send: "HUMANITIES-AWARD_CAREER-HUMANITY-OUT_SCHOOL", id: 5, }, { name: "독서마라톤 거북이코스", score: "40점", - send: "humanities-book-bookmarathon-turtle", + send: "HUMANITIES-BOOK-BOOKMARATHON-TURTLE", id: 6, }, { name: "독서마라톤 악어코스", score: "70점", - send: "humanities-book-bookmarathon-crocodile", + send: "HUMANITIES-BOOK-BOOKMARATHON-CROCODILE", id: 6, }, { name: "독서마라톤 토끼코스이상", score: "100점", - send: "humanities-book-bookmarathon-over_rabbit", + send: "HUMANITIES-BOOK-BOOKMARATHON-OVER_RABBIT", id: 6, }, { name: "봉사활동", score: "시간당 5점", max_number: "최대 40시간", - send: "humanities-service-activity", + send: "HUMANITIES-SERVICE-ACTIVITY", id: 8, }, { name: "봉사동아리", score: "학기당 50점", max_number: "최대 2", - send: "humanities-service-club", + send: "HUMANITIES-SERVICE-CLUB", id: 9, }, { name: "한자자격증", score: "50점 (4급 이상)", - send: "humanities-certificate-chinese_character", + send: "HUMANITIES-CERTIFICATE-CHINESE_CHARACTER", id: 10, }, { name: "한국사", score: "50점 (3급 이상)", - send: "humanities-certificate-korean_history", + send: "HUMANITIES-CERTIFICATE-KOREAN_HISTORY", id: 11, }, { name: "자기주도적 활동", score: "25점", max_number: "최대 8회", - send: "humanities-activities-self_directed_activities", + send: "HUMANITIES-ACTIVITIES-SELF_DIRECTED_ACTIVITIES", id: 12, }, { name: "뉴로우S", score: "5점 (1일 1회로 인정)", max_number: "최대 40", - send: "humanities-activities-newrrow_s", + send: "HUMANITIES-ACTIVITIES-NEWRROW_S", id: 13, }, ]; @@ -199,55 +199,55 @@ export const foreignCategoryOptions = [ { name: "TOEIC 점수", score: "500점", - send: "foreign_lang-test-toeic-score", + send: "FOREIGN_LANG-TEST-TOEIC-SCORE", id: 14, }, { - name: " TOEFL 점수", + name: "TOEFL 점수", score: "500점", - send: "foreign_lang-test-toefl-score", + send: "FOREIGN_LANG-TEST-TOEFL-SCORE", id: 14, }, { name: "TEPS 점수", score: "500점", - send: "foreign_lang-test-teps-score", + send: "FOREIGN_LANG-TEST-TEPS-SCORE", id: 14, }, { name: "TOEIC SPEAKING level", score: "500점", - send: "foreign_lang-test-toeic_speaking-level", + send: "FOREIGN_LANG-TEST-TOEIC_SPEAKING-LEVEL", id: 14, }, { name: "OPIC 등급", score: "500점", - send: "foreign_lang-test-opic-grade", + send: "FOREIGN_LANG-TEST-OPIC-GRADE", id: 14, }, { name: "JPT 점수", score: "500점", - send: "foreign_lang-test-jpt-score", + send: "FOREIGN_LANG-TEST-JPT-SCORE", id: 14, }, { name: "CPT 점수", score: "500점", - send: "foreign_lang-test-cpt-score", + send: "FOREIGN_LANG-TEST-CPT-SCORE", id: 14, }, { name: "HSK 급수", score: "500점", - send: "foreign_lang-test-hsk-grade", + send: "FOREIGN_LANG-TEST-HSK-GRADE", id: 14, }, { name: "토사관 참여", score: "100점", - send: "foreign_lang-attendance_toeic_academy-status", + send: "FOREIGN_LANG-ATTENDANCE_TOEIC_ACADEMY-STATUS", id: 15, }, ]; diff --git a/apps/client/src/widgets/edit/model/editConfig.ts b/apps/client/src/widgets/edit/model/editConfig.ts index d9e1cf7c..632d0c09 100644 --- a/apps/client/src/widgets/edit/model/editConfig.ts +++ b/apps/client/src/widgets/edit/model/editConfig.ts @@ -1,10 +1,10 @@ import type { ConfigType } from "@/shared/model/config"; -import { - foreignCategoryOptions, - majorCategoryOptions, -} from "@/widgets/calculate/model/category"; import type { FormValues } from "@/widgets/edit/types/types"; -import { CharacterCategory } from "@/widgets/write/model/category"; +import { + MajorOptions, + HumanitiesOptions, + ForeignOptions, +} from "@/widgets/write/model/category"; import { patchMajorActivity, @@ -24,7 +24,7 @@ export const getEditConfig = (type: ConfigType): Config => { case "major": { return { title: "전공 영역 수정", - categoryOptions: majorCategoryOptions, + categoryOptions: MajorOptions, onSubmit: async (data: FormValues, id: number) => { const formData = new FormData(); if (data.file) { @@ -42,7 +42,7 @@ export const getEditConfig = (type: ConfigType): Config => { case "humanities": { return { title: "인성 영역 수정", - categoryOptions: CharacterCategory, + categoryOptions: HumanitiesOptions, onSubmit: async (data: FormValues, id: number) => { const formData = new FormData(); if (data.file) { @@ -74,7 +74,7 @@ export const getEditConfig = (type: ConfigType): Config => { case "foreign": { return { title: "외국어 영역 수정", - categoryOptions: foreignCategoryOptions, + categoryOptions: ForeignOptions, onSubmit: async (data: FormValues, id: number) => { const formData = new FormData(); if (data.file) { diff --git a/apps/client/src/widgets/write/model/category.ts b/apps/client/src/widgets/write/model/category.ts index 9a025a17..96bde2f2 100644 --- a/apps/client/src/widgets/write/model/category.ts +++ b/apps/client/src/widgets/write/model/category.ts @@ -1,6 +1,112 @@ -export const CharacterCategory = [ +export const MajorOptions = [ + { + name: "공문을 통한 전공분야 대회 수상", + send: "MAJOR-AWARD_CAREER-OUT_SCHOOL-OFFICIAL", + }, + { + name: "전공분야 대회 개별참여 수상", + send: "MAJOR-AWARD_CAREER-OUT_SCHOOL-UNOFFICIAL", + }, + { + name: "연합 해커톤 수상", + send: "MAJOR-AWARD_CAREER-OUT_SCHOOL-HACKATHON", + }, + { + name: "GSM FESTIVAL 수상", + send: "MAJOR-AWARD_CAREER-IN_SCHOOL-GSMFEST", + }, + { + name: "교내해커톤 수상", + send: "MAJOR-AWARD_CAREER-IN_SCHOOL-SCHOOL_HACKATHON", + }, + { + name: "전공동아리 발표 수상", + send: "MAJOR-AWARD_CAREER-IN_SCHOOL-PRESENTATION", + }, + { + name: "전공(심화), 취업 동아리 참여 - 1학기", + send: "MAJOR-CLUB_ATTENDANCE_SEMESTER_1", + }, + { + name: "전공(심화), 취업 동아리 참여 - 2학기", + send: "MAJOR-CLUB_ATTENDANCE_SEMESTER_2", + }, + { + name: "공문을 통한 전공분야 대회 참가", + send: "MAJOR-OUT_SCHOOL-ATTENDANCE_OFFICIAL_CONTEST", + }, + { + name: "전공분야 대회 개별참여 참가", + send: "MAJOR-OUT_SCHOOL-ATTENDANCE_UNOFFICIAL_CONTEST", + }, + { + name: "연합 해커톤 참가", + send: "MAJOR-OUT_SCHOOL-ATTENDANCE_HACKATHON", + }, + { + name: "전공 관련 교육 프로그램(세미나 등) 참가", + send: "MAJOR-OUT_SCHOOL-ATTENDANCE_SEMINAR", + }, + { + name: "GSM FESTIVAL 참가", + send: "MAJOR-IN_SCHOOL-ATTENDANCE_GSMFEST", + }, + { + name: "교내 해커톤 참가", + send: "MAJOR-IN_SCHOOL-ATTENDANCE_HACKATHON", + }, + { + name: "전공동아리 발표대회 참가", + send: "MAJOR-IN_SCHOOL-ATTENDANCE_CLUB-PRESENTATION", + }, + { + name: "전공특강(방과후) 참가", + send: "MAJOR-IN_SCHOOL-ATTENDANCE_SEMINAR", + }, + { + name: "전공 관련 방과후학교 이수", + send: "MAJOR-IN_SCHOOL-ATTENDANCE_AFTER-SCHOOL", + }, +]; + +export const HumanitiesOptions = [ { name: "자기주도적 활동", send: "HUMANITIES-ACTIVITIES-SELF-DIRECTED_ACTIVITIES", }, ]; + +export const ForeignOptions = [ + { + name: "TOEIC", + send: "FOREIGN_LANG-TOEIC_SCORE", + }, + { + name: "TOEFL", + send: "FOREIGN_LANG-TOEFL_SCORE", + }, + { + name: "TEPS", + send: "FOREIGN_LANG-TEPS_SCORE", + }, + { + name: "TOEIC SPEAKING", + send: "FOREIGN_LANG-TOEIC_SPEAKING_LEVEL", + }, + { + name: "OPIC", + send: "FOREIGN_LANG-OPIC_SCORE", + }, + { + name: "JPT", + send: "FOREIGN_LANG-JPT_SCORE", + }, + { + name: "CPT", + send: "FOREIGN_LANG-CPT_SCORE", + }, + { + name: "HSK", + send: "FOREIGN_LANG-HSK_SCORE", + }, +]; diff --git a/apps/client/src/widgets/write/model/foreignOptions.ts b/apps/client/src/widgets/write/model/foreignOptions.ts deleted file mode 100644 index c03a0ebb..00000000 --- a/apps/client/src/widgets/write/model/foreignOptions.ts +++ /dev/null @@ -1,13 +0,0 @@ -export const foreignOptions = [ - { name: "TOEIC", send: "FOREIGN_LANG-TOEIC_SCORE" }, - { name: "TOEFL", send: "FOREIGN_LANG-TOEFL_SCORE" }, - { name: "TEPS", send: "FOREIGN_LANG-TEPS_SCORE" }, - { - name: "TOEIC SPEAKING", - send: "FOREIGN_LANG-TOEIC_SPEAKING_LEVEL", - }, - { name: "OPIC", send: "FOREIGN_LANG-OPIC_SCORE" }, - { name: "JPT", send: "FOREIGN_LANG-JPT_SCORE" }, - { name: "CPT", send: "FOREIGN_LANG-CPT_SCORE" }, - { name: "HSK", send: "FOREIGN_LANG-HSK_SCORE" }, -]; diff --git a/apps/client/src/widgets/write/model/writeConfig.ts b/apps/client/src/widgets/write/model/writeConfig.ts index 747aae9c..cab25d25 100644 --- a/apps/client/src/widgets/write/model/writeConfig.ts +++ b/apps/client/src/widgets/write/model/writeConfig.ts @@ -1,14 +1,15 @@ import type { ConfigType } from "@/shared/model/config"; -import { majorCategoryOptions } from "@/widgets/calculate/model/category"; import type { FormValues } from "@/widgets/edit/types/types"; -import { CharacterCategory } from "@/widgets/write/model/category"; +import { + MajorOptions, + HumanitiesOptions, + ForeignOptions, +} from "@/widgets/write/model/category"; import { postScore } from "../api/postScore"; import { handleSubmitBook } from "../lib/handleBookSubmit"; import { handleSubmitActivity } from "../lib/handleSubmitActivity"; -import { foreignOptions } from "./foreignOptions"; - interface Config { title: string; categoryOptions?: { name: string; send: string }[]; @@ -20,7 +21,7 @@ export const getWriteConfig = (type: ConfigType): Config => { case "major": { return { title: "전공 영역", - categoryOptions: majorCategoryOptions, + categoryOptions: MajorOptions, onSubmit: async (data: FormValues, type) => { const formData = new FormData(); if (data.file) { @@ -41,7 +42,7 @@ export const getWriteConfig = (type: ConfigType): Config => { case "humanities": { return { title: "인성 영역", - categoryOptions: CharacterCategory, + categoryOptions: HumanitiesOptions, onSubmit: async (data: FormValues, type) => { const formData = new FormData(); if (data.file) { @@ -77,7 +78,7 @@ export const getWriteConfig = (type: ConfigType): Config => { case "foreign": { return { title: "외국어 영역", - categoryOptions: foreignOptions, + categoryOptions: ForeignOptions, onSubmit: async (data: FormValues) => { const formData = new FormData(); if (data.file) { From 6829697516bc4fbf1984b62c37b52824e6bdf48d Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 10:56:50 +0900 Subject: [PATCH 027/200] fix: config type & remove others --- apps/client/src/shared/model/config.ts | 7 +-- .../src/widgets/edit/lib/getDefaultValues.ts | 4 +- .../src/widgets/edit/model/editConfig.ts | 8 --- apps/client/src/widgets/edit/ui/index.tsx | 50 ++++++++----------- 4 files changed, 26 insertions(+), 43 deletions(-) diff --git a/apps/client/src/shared/model/config.ts b/apps/client/src/shared/model/config.ts index 3b3467fe..047f1b1e 100644 --- a/apps/client/src/shared/model/config.ts +++ b/apps/client/src/shared/model/config.ts @@ -1,6 +1 @@ -export type ConfigType = - | "major" - | "humanities" - | "reading" - | "others" - | "foreign"; +export type ConfigType = "major" | "humanities" | "reading" | "foreign"; diff --git a/apps/client/src/widgets/edit/lib/getDefaultValues.ts b/apps/client/src/widgets/edit/lib/getDefaultValues.ts index bea78a0e..e101777a 100644 --- a/apps/client/src/widgets/edit/lib/getDefaultValues.ts +++ b/apps/client/src/widgets/edit/lib/getDefaultValues.ts @@ -1,10 +1,12 @@ import type { Activity, Reading, Others } from "@repo/types/evidences"; +import type { ConfigType } from "@/shared/model/config"; + import { getEditConfig } from "../model/editConfig"; import type { FormValues } from "../types/types"; export const getDefaultValues = ( - type: "major" | "humanities" | "reading" | "others", + type: ConfigType, post: Activity | Reading | Others ): Partial => { const config = getEditConfig(type); diff --git a/apps/client/src/widgets/edit/model/editConfig.ts b/apps/client/src/widgets/edit/model/editConfig.ts index 632d0c09..a950ce8d 100644 --- a/apps/client/src/widgets/edit/model/editConfig.ts +++ b/apps/client/src/widgets/edit/model/editConfig.ts @@ -85,13 +85,5 @@ export const getEditConfig = (type: ConfigType): Config => { }, }; } - case "others": { - return { - title: "기타 증빙 수정", - onSubmit: async () => { - // No submission logic implemented for 'others' category yet. - }, - }; - } } }; diff --git a/apps/client/src/widgets/edit/ui/index.tsx b/apps/client/src/widgets/edit/ui/index.tsx index 1f7eee26..77387a8f 100644 --- a/apps/client/src/widgets/edit/ui/index.tsx +++ b/apps/client/src/widgets/edit/ui/index.tsx @@ -9,6 +9,7 @@ import { useCallback } from "react"; import { Controller, useForm, useWatch } from "react-hook-form"; import { toast } from "sonner"; +import type { ConfigType } from "@/shared/model/config"; import { Dropdown, File, Textarea } from "@/shared/ui"; import { getDefaultValues } from "@/widgets/edit/lib/getDefaultValues"; import { getEditConfig } from "@/widgets/edit/model/editConfig"; @@ -24,8 +25,8 @@ const EditForm = ({ type, post }: EditFormProps) => { const isDraft = Boolean(searchParams.get("draft")); const router = useRouter(); - const config = getEditConfig(type as "major" | "humanities" | "reading" | "others"); - const draftConfig = getWriteConfig(type as "major" | "humanities" | "reading" | "others"); + const config = getEditConfig(type as ConfigType); + const draftConfig = getWriteConfig(type as ConfigType); const { handleSubmit, @@ -34,39 +35,32 @@ const EditForm = ({ type, post }: EditFormProps) => { } = useForm({ mode: "onChange", defaultValues: getDefaultValues( - type as "major" | "humanities" | "reading" | "others", + type as ConfigType, post as Activity | Reading | Others, ), }); const file = useWatch({ control, name: "file" }); - const handleFormSubmit = useCallback( - async (data: FormValues) => { - try { - if (isDraft && "draftId" in post) { - await draftConfig.onSubmit({ ...data, draftId: post.draftId }, "submit"); - toast.success("작성이 완료되었습니다."); - router.back(); - return; - } else if (!isDraft && "id" in post) { - await config.onSubmit(data, Number(post.id)); - toast.success("수정이 완료되었습니다."); - router.back(); - } - } catch { - toast.error("수정에 실패했습니다."); + const handleFormSubmit = useCallback(async (data: FormValues) => { + try { + if (isDraft && "draftId" in post) { + await draftConfig.onSubmit({ ...data, draftId: post.draftId }, "submit"); + toast.success("작성이 완료되었습니다."); + router.back(); + } else if (!isDraft && "id" in post) { + await config.onSubmit(data, Number(post.id)); + toast.success("수정이 완료되었습니다."); + router.back(); } - }, - [config, draftConfig, isDraft, post, router], - ); - - const handleReviseSubmit = useCallback( - (e: React.FormEvent) => { - void handleSubmit(handleFormSubmit)(e); - }, - [handleSubmit, handleFormSubmit], - ); + } catch { + toast.error("수정에 실패했습니다."); + } + }, [config, draftConfig, isDraft, post, router]); + + const handleReviseSubmit = useCallback((e: React.FormEvent) => { + void handleSubmit(handleFormSubmit)(e); + }, [handleSubmit, handleFormSubmit]); const handleBack = useCallback(() => { router.back(); From 0c398292cda8ffa4ed13a2e75312073a2ddc2be5 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 10:57:06 +0900 Subject: [PATCH 028/200] fix: activity --- apps/client/src/widgets/write/api/postActivity.ts | 15 +++++++++------ .../src/widgets/write/api/postActivityDraft.ts | 15 +++++++++------ .../src/widgets/write/lib/handleSubmitActivity.ts | 15 +++------------ 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/apps/client/src/widgets/write/api/postActivity.ts b/apps/client/src/widgets/write/api/postActivity.ts index 021a8565..286c52ab 100644 --- a/apps/client/src/widgets/write/api/postActivity.ts +++ b/apps/client/src/widgets/write/api/postActivity.ts @@ -1,13 +1,16 @@ import instance from "@repo/api/axios"; -import type { AxiosError, AxiosResponse } from "axios"; +import { isAxiosError, type AxiosResponse } from "axios"; export const postActivity = async ( activity: FormData -): Promise => { +): Promise => { try { - const res = await instance.post("evidence/current/activity", activity); - return res; - } catch (error) { - return error as AxiosError; + const response = await instance.post("evidence/current/activity", activity); + return response; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "활동영역 저장 실패"; + } + throw error; } }; diff --git a/apps/client/src/widgets/write/api/postActivityDraft.ts b/apps/client/src/widgets/write/api/postActivityDraft.ts index b58f0e41..e7a3c962 100644 --- a/apps/client/src/widgets/write/api/postActivityDraft.ts +++ b/apps/client/src/widgets/write/api/postActivityDraft.ts @@ -1,16 +1,19 @@ import instance from "@repo/api/axios"; -import type { AxiosError, AxiosResponse } from "axios"; +import { isAxiosError, type AxiosResponse } from "axios"; export const postActivityDraft = async ( activity: FormData -): Promise => { +): Promise => { try { - const res = await instance.post( + const response = await instance.post( "/evidence/current/draft/activity", activity ); - return res; - } catch (error) { - return error as AxiosError; + return response; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "활동영역 임시 저장 실패"; + } + throw error; } }; diff --git a/apps/client/src/widgets/write/lib/handleSubmitActivity.ts b/apps/client/src/widgets/write/lib/handleSubmitActivity.ts index 5a1dff71..fe630fa6 100644 --- a/apps/client/src/widgets/write/lib/handleSubmitActivity.ts +++ b/apps/client/src/widgets/write/lib/handleSubmitActivity.ts @@ -1,5 +1,3 @@ -import { toast } from "sonner"; - import { postActivity } from "../api/postActivity"; import { postActivityDraft } from "../api/postActivityDraft"; @@ -7,14 +5,7 @@ export const handleSubmitActivity = async ( submitType: "submit" | "draft", formData: FormData ) => { - try { - await (submitType === "draft" - ? postActivityDraft(formData) - : postActivity(formData)); - toast.success(submitType === "draft" ? "임시저장 완료" : "제출 완료"); - return true; - } catch { - toast.error(submitType === "draft" ? "임시저장 실패" : "제출 실패"); - return false; - } + return await (submitType === "draft" + ? postActivityDraft(formData) + : postActivity(formData)); }; From d6d5502235def11569cbaf2e010f1eb64415fe46 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 10:57:17 +0900 Subject: [PATCH 029/200] fix: book --- apps/client/src/widgets/write/api/postBook.ts | 13 +++++++++++-- .../src/widgets/write/api/postBookDraft.ts | 16 ++++++++++++++-- .../src/widgets/write/lib/handleBookSubmit.ts | 11 +---------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/apps/client/src/widgets/write/api/postBook.ts b/apps/client/src/widgets/write/api/postBook.ts index 2f2c4aaa..75d14cc0 100644 --- a/apps/client/src/widgets/write/api/postBook.ts +++ b/apps/client/src/widgets/write/api/postBook.ts @@ -1,7 +1,16 @@ import instance from "@repo/api/axios"; +import { isAxiosError, type AxiosResponse } from "axios"; import type { Book } from "../model/book"; -export const postBook = async (bookData: Book) => { - await instance.post("evidence/current/reading", bookData); +export const postBook = async (bookData: Book): Promise => { + try { + const response = await instance.post("evidence/current/reading", bookData); + return response; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "독서영역 저장 실패"; + } + throw error; + } }; diff --git a/apps/client/src/widgets/write/api/postBookDraft.ts b/apps/client/src/widgets/write/api/postBookDraft.ts index 938c44a4..17a8f3e1 100644 --- a/apps/client/src/widgets/write/api/postBookDraft.ts +++ b/apps/client/src/widgets/write/api/postBookDraft.ts @@ -1,7 +1,19 @@ import instance from "@repo/api/axios"; +import { isAxiosError, type AxiosResponse } from "axios"; import type { Book } from "../model/book"; -export const postBookDraft = async (data: Book) => { - return await instance.post("/evidence/current/draft/reading", data); +export const postBookDraft = async (data: Book): Promise => { + try { + const response = await instance.post( + "/evidence/current/draft/reading", + data + ); + return response; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "독서영역 임시 저장 실패"; + } + throw error; + } }; diff --git a/apps/client/src/widgets/write/lib/handleBookSubmit.ts b/apps/client/src/widgets/write/lib/handleBookSubmit.ts index 79206447..880e3b82 100644 --- a/apps/client/src/widgets/write/lib/handleBookSubmit.ts +++ b/apps/client/src/widgets/write/lib/handleBookSubmit.ts @@ -1,5 +1,3 @@ -import { toast } from "sonner"; - import { postBook } from "../api/postBook"; import { postBookDraft } from "../api/postBookDraft"; import type { Book } from "../model/book"; @@ -8,12 +6,5 @@ export const handleSubmitBook = async ( data: Book, submitType: "submit" | "draft" ) => { - try { - await (submitType === "draft" ? postBookDraft(data) : postBook(data)); - toast.success(submitType === "draft" ? "임시저장 완료" : "제출 완료"); - return true; - } catch { - toast.error(submitType === "draft" ? "임시저장 실패" : "제출 실패"); - return false; - } + return await (submitType === "draft" ? postBookDraft(data) : postBook(data)); }; From b61f90aa05b123f1c685541283613dd616bc4c95 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 10:57:25 +0900 Subject: [PATCH 030/200] fix: score --- apps/client/src/widgets/write/api/postScore.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/client/src/widgets/write/api/postScore.ts b/apps/client/src/widgets/write/api/postScore.ts index 1347d1b6..45ba7b4e 100644 --- a/apps/client/src/widgets/write/api/postScore.ts +++ b/apps/client/src/widgets/write/api/postScore.ts @@ -1,13 +1,14 @@ import instance from "@repo/api/axios"; -import type { AxiosError, AxiosResponse } from "axios"; +import { isAxiosError, type AxiosResponse } from "axios"; -export const postScore = async ( - formData: FormData -): Promise => { +export const postScore = async (formData: FormData): Promise => { try { const res = await instance.post("/evidence/current/scoring", formData); return res; - } catch (error) { - return error as AxiosError; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "외국어 영역 저장 실패"; + } + throw error; } }; From 0436241021922769bc0eb8c5666e4155221bee13 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 10:57:34 +0900 Subject: [PATCH 031/200] fix: writeConfig return --- .../src/widgets/write/model/writeConfig.ts | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/apps/client/src/widgets/write/model/writeConfig.ts b/apps/client/src/widgets/write/model/writeConfig.ts index cab25d25..6d6464ff 100644 --- a/apps/client/src/widgets/write/model/writeConfig.ts +++ b/apps/client/src/widgets/write/model/writeConfig.ts @@ -1,3 +1,5 @@ +import type { AxiosResponse } from "axios"; + import type { ConfigType } from "@/shared/model/config"; import type { FormValues } from "@/widgets/edit/types/types"; import { @@ -13,7 +15,10 @@ import { handleSubmitActivity } from "../lib/handleSubmitActivity"; interface Config { title: string; categoryOptions?: { name: string; send: string }[]; - onSubmit: (data: FormValues, type: "draft" | "submit") => Promise; + onSubmit: ( + data: FormValues, + type: "draft" | "submit" + ) => Promise; } export const getWriteConfig = (type: ConfigType): Config => { @@ -35,7 +40,7 @@ export const getWriteConfig = (type: ConfigType): Config => { formData.append("content", data.content || ""); formData.append("activityType", "MAJOR"); - await handleSubmitActivity(type, formData); + return await handleSubmitActivity(type, formData); }, }; } @@ -56,7 +61,7 @@ export const getWriteConfig = (type: ConfigType): Config => { formData.append("content", data.content || ""); formData.append("activityType", "HUMANITIES"); - await handleSubmitActivity(type, formData); + return await handleSubmitActivity(type, formData); }, }; } @@ -71,7 +76,7 @@ export const getWriteConfig = (type: ConfigType): Config => { content: data.content || "", draftId: data.draftId ?? null, }; - await handleSubmitBook(bookData, type); + return await handleSubmitBook(bookData, type); }, }; } @@ -86,15 +91,7 @@ export const getWriteConfig = (type: ConfigType): Config => { } formData.append("categoryName", data.categoryName?.send ?? ""); formData.append("value", String(data.value)); - await postScore(formData); - }, - }; - } - case "others": { - return { - title: "기타 증빙 자료", - onSubmit: async () => { - // No submission logic implemented for 'others' category yet. + return await postScore(formData); }, }; } From 6e1dffaaa3453837d64a73e93423786d0670483d Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 10:57:44 +0900 Subject: [PATCH 032/200] fix: use mutation --- apps/client/src/widgets/write/ui/index.tsx | 77 ++++++++++++---------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/apps/client/src/widgets/write/ui/index.tsx b/apps/client/src/widgets/write/ui/index.tsx index c90009bc..a576e3a7 100644 --- a/apps/client/src/widgets/write/ui/index.tsx +++ b/apps/client/src/widgets/write/ui/index.tsx @@ -3,10 +3,15 @@ import { Button } from "@repo/shared/button"; import { Input } from "@repo/shared/input"; import { InputContainer } from "@repo/shared/inputContainer"; +import { useMutation } from "@tanstack/react-query"; +import { HttpStatusCode } from "axios"; import { useRouter, useSearchParams } from "next/navigation"; import { useCallback, useRef } from "react"; import { Controller, useForm, useWatch } from "react-hook-form"; +import { toast } from "sonner"; +import type { ConfigType } from "@/shared/model/config"; +import type { HttpError } from "@/shared/model/error"; import { Dropdown, File, Textarea } from "@/shared/ui"; import type { Option } from "@/shared/ui/dropdown"; import type { FormValues } from "@/widgets/edit/types/types"; @@ -14,23 +19,38 @@ import { chooseDropdownOption } from "@/widgets/write/lib/chooseDropdownOption"; import { getWriteConfig } from "../model/writeConfig"; + + export default function WriteForm() { const searchParams = useSearchParams(); const router = useRouter(); - const type = searchParams.get("type") as - | "major" - | "humanities" - | "reading" - | "others" - | "foreign"; + const type = searchParams.get("type") as ConfigType const config = getWriteConfig(type); const submitTypeRef = useRef<"draft" | "submit">("submit"); + const { mutate } = useMutation({ + mutationFn: (data: FormValues) => config.onSubmit(data, submitTypeRef.current), + onSuccess: (data) => { + if (data.status === 201) { + toast.success("증빙자료를 성공적으로 저장하였습니다.") + router.push("/"); + } + }, + onError: (error: HttpError) => { + if (error.httpStatus === HttpStatusCode.NotFound) { + toast.error("해당 증빙 자료가 존재하지 않습니다."); + } else if (error.httpStatus === HttpStatusCode.UnprocessableEntity) { + toast.error("더 이상 증빙 자료를 추가할 수 없습니다."); + } else { + toast.error("증빙 자료 추가에 실패했습니다."); + } + } + }) + const { handleSubmit, control, - getValues, formState: { isValid }, } = useForm({ mode: "onChange", @@ -44,39 +64,30 @@ export default function WriteForm() { file: undefined, }, }); + const file = useWatch({ control, name: "file" }); - const category = useWatch({ - control, - name: "categoryName", - }); + + const category = useWatch({ control, name: "categoryName", }); const needDropdown = category?.name === "OPIC" || category?.name === "TOEIC SPEAKING" || category?.name === "HSK"; - const handleFormSubmit = useCallback( - async (data: FormValues) => { - await config.onSubmit(data, submitTypeRef.current); - router.push("/"); - }, - [config, router], - ); + const handleFormSubmit = useCallback((data: FormValues) => { + mutate(data) + }, [mutate]); - const handleWriteSubmit = useCallback( - (e: React.FormEvent) => { - e.preventDefault(); - void handleSubmit(handleFormSubmit)(); - }, - [handleFormSubmit, handleSubmit], - ); + const handleWriteSubmit = useCallback((e: React.FormEvent) => { + e.preventDefault(); + void handleSubmit(handleFormSubmit)(); + }, [handleFormSubmit, handleSubmit]); - const handleTemporarySave = useCallback(() => { + const ChangeStatusDraft = useCallback(() => { submitTypeRef.current = "draft"; - void handleFormSubmit(getValues()); - }, [getValues, handleFormSubmit]); + }, []); - const handleSubmissionSubmit = useCallback(() => { + const ChangeStatusWrite = useCallback(() => { submitTypeRef.current = "submit"; }, []); @@ -221,11 +232,11 @@ export default function WriteForm() { {type !== "foreign" && (
From dfb9ad9834cee8a3f233b9a48521a6ce84f06f77 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 17:01:38 +0900 Subject: [PATCH 033/200] fix: mockdata --- .../src/shared/mocks/data/evidenceMock.json | 246 +++++++++--------- apps/client/src/views/detail/index.tsx | 11 +- apps/client/src/widgets/example/ui/index.tsx | 25 +- 3 files changed, 150 insertions(+), 132 deletions(-) diff --git a/apps/client/src/shared/mocks/data/evidenceMock.json b/apps/client/src/shared/mocks/data/evidenceMock.json index a45b55b9..af411746 100644 --- a/apps/client/src/shared/mocks/data/evidenceMock.json +++ b/apps/client/src/shared/mocks/data/evidenceMock.json @@ -1,119 +1,127 @@ -[ - { - "id": 1, - "title": "AWS를 이용하는 방법", - "content": "2024년 9월 12일에 진행된 4시간짜리 AWS 교육에 참여하여 AWS VPC, AWS Lambda, AWS S3, AWS EC2 등 현대 소프트웨어 개발에서 핵심이 되는 서비스들을 학습하고 실습하였다. 학생으로서는 알기 힘든 AWS의 요금제, VPC 구성 방법 등을 실습을 통해 익히고, AI 서비스인 PartyRock을 활용한 애플리케이션도 제작해보며 AWS 생태계 전반을 이해하는 데 큰 도움이 되었다. 교육 후 임시 계정을 발급받아 자율 실습도 진행하며 다양한 시도를 해볼 수 있었다.", - "categoryName": "전공영역-전공특강(방과후) 참가", - "status": "APPROVE", - "imageUri": "/mocks/aws.png" - }, - { - "id": 2, - "title": "한전 KDN 소프트웨어 경진대회", - "content": "2024년 11월 27일, 나주 한전 KDN 본사에서 개최된 소프트웨어 경진대회에 참가하여 Bstorm이라는 치매 예방 목적의 소프트웨어를 개발 및 발표하였다. 나는 서버 개발을 담당하였으며, 약 40개의 API를 설계 및 구현하고 CI 파이프라인까지 구축하였다. 모놀리식 아키텍처에 대한 이해를 넓힐 수 있었고, Git Flow를 기반으로 한 협업 방식도 경험하였다. 끝까지 버그를 해결하며 노력한 결과, 장려상을 수상하였다.", - "categoryName": "전공영역-공문을 통한 전공분야 대회 참여", - "status": "APPROVE", - "imageUri": "/mocks/KDN.png" - }, - { - "id": 3, - "title": "모두의 HTML5 & CSS3", - "author": "김인권", - "page": 324, - "content": "HTML과 CSS의 기초를 쉽고 재미있게 배울 수 있도록 구성된 입문서이다. 실제 예제를 기반으로 HTML5 태그와 CSS3의 스타일링 기법을 설명하고, 반응형 웹 디자인까지 다루며 웹 개발 초보자에게 실용적인 내용을 제공한다.", - "status": "APPROVE" - }, - { - "id": 4, - "fileUrl": "/mocks/toefl.png", - "evidenceType": "TOEFL", - "categoryName": "외국어영역-TOEFL 점수", - "status": "APPROVE" - }, - { - "id": 5, - "title": "제 27회 앱잼 참여", - "content": "Alpaco에서 주최한 제27회 앱잼에 참여하여 '가치 하다'라는 앱을 개발하였다. 백엔드 개발을 맡아 Spring Boot와 Kotlin을 사용하였고, Git을 통한 협업의 어려움을 직접 겪으며 해결책을 찾아갔다. 앱 개발이라는 환경에 적응하며 REST API 기반으로 개발을 진행했고, 협업과 시간 관리의 중요성을 체감할 수 있었다. 생활정보 분야에서 최우수상을 수상하였다.", - "categoryName": "전공영역-전공 분야 대회 개별 참여", - "status": "APPROVE", - "imageUri": "/mocks/appjam.png" - }, - { - "id": 6, - "title": "C언어 코딩 콘테스트 참여", - "content": "2024년 5월부터 6월까지 진행된 교내 C언어 코딩 콘테스트에서 DB 서버와 curl 라이브러리를 활용해 실시간 온라인 게임인 'project return(회귀)'를 개발하였다. 포인터 누수로 인한 DB 연결 중단 문제를 해결하기 위해 포인터 관리 기능을 도입하였고, 이메일 전송 기능도 직접 구현하였다. 총 누적 75,000줄에 달하는 코드 작업 끝에 최우수상을 수상하였다.", - "categoryName": "전공영역-교내 해커톤 대회", - "status": "APPROVE" - }, - { - "id": 7, - "fileUrl": "/mocks/ReadingMarathon.png", - "evidenceType": "READ-A-THON", - "categoryName": "인성영역-독서마라톤 토끼코스 이상", - "status": "APPROVE" - }, - { - "id": 8, - "title": "전기CAD기능사", - "content": "2025년 1월부터 시작하여 3월까지 방과후 및 정규 수업을 통해 전기CAD기능사 자격증 필기를 준비하고, 이후 실기시험 대비까지 병행하였다. 학교 실습실을 활용해 꾸준히 실습하였고 5월 초에 자격증을 최종 취득하였다.", - "categoryName": "인성영역-자기주도적 활동", - "status": "APPROVE" - }, - { - "id": 9, - "fileUrl": "/mocks/toeic.png", - "evidenceType": "TOEIC", - "categoryName": "외국어영역-TOEIC 점수", - "status": "APPROVE" - }, - { - "id": 10, - "title": "카이스트 진로 강의", - "content": "디지털 P:UM 프로젝트의 일환으로 KAIST 견학 프로그램에 참여하여 AI 및 소프트웨어 분야의 진로 강의를 들었다. AI 시대에서 개발자가 갖춰야 할 자세와 중장기 계획 수립에 대해 실제 사례와 함께 구체적으로 배울 수 있었다.", - "categoryName": "전공영역-전공 관련 교육프로그램 참여", - "status": "APPROVE", - "imageUri": "/mocks/pum.png" - }, - { - "id": 11, - "fileUrl": "/mocks/certificate.png", - "evidenceType": "CERTIFICATE", - "categoryName": "인성영역-한자자격증", - "status": "APPROVE" - }, - { - "id": 12, - "title": "한국사 자격증 1급", - "content": "한국사 능력 검정 시험 1급 취득.", - "categoryName": "인성영역-한국사자격증", - "status": "APPROVE" - }, - { - "id": 13, - "title": "아이디어 페스티벌", - "content": "학년별로 팀을 구성해 1년 동안 전공 수업을 통해 준비한 프로젝트를 발표하는 교내 행사에 참여하였다. 팀워크와 실무 경험을 통해 협업의 중요성과 발표 능력을 키울 수 있었다.", - "categoryName": "전공영역-GSM FESTIVAL", - "status": "APPROVE" - }, - { - "id": 14, - "title": "전공 캠프", - "content": "방학 동안 1주일간 학교에서 진행된 전공 캠프에 참여하여 Python, 백엔드, Git, 그리고 TOPCIT 대비 교육을 받았다. 실습 위주의 수업을 통해 백엔드 개발과 형상관리 도구에 대한 이해를 높일 수 있었고, 진로에 대한 방향을 설정하는 데 큰 도움이 되었다.", - "categoryName": "전공영역-전공관련 방과후학교 이수", - "status": "APPROVE" - }, - { - "id": 15, - "fileUrl": "/mocks/toeiccertificate.png", - "evidenceType": "TOEIC", - "categoryName": "외국어영역-토사관 참여", - "status": "APPROVE" - }, - { - "id": 16, - "fileUrl": "/mocks/multireadingaward.png", - "evidenceType": "CERTIFICATE", - "categoryName": "인성영역-교내인성영역관련수상", - "status": "APPROVE" - } -] +{ + "majorActivityEvidence": [ + { + "id": 1, + "title": "AWS를 이용하는 방법", + "content": "2024년 9월 12일에 진행된 4시간짜리 AWS 교육에 참여하여 AWS VPC, AWS Lambda, AWS S3, AWS EC2 등 현대 소프트웨어 개발에서 핵심이 되는 서비스들을 학습하고 실습하였다. 학생으로서는 알기 힘든 AWS의 요금제, VPC 구성 방법 등을 실습을 통해 익히고, AI 서비스인 PartyRock을 활용한 애플리케이션도 제작해보며 AWS 생태계 전반을 이해하는 데 큰 도움이 되었다. 교육 후 임시 계정을 발급받아 자율 실습도 진행하며 다양한 시도를 해볼 수 있었다.", + "categoryName": "전공영역-전공특강(방과후) 참가", + "status": "APPROVE", + "imageUri": "/mocks/aws.png" + }, + { + "id": 2, + "title": "한전 KDN 소프트웨어 경진대회", + "content": "2024년 11월 27일, 나주 한전 KDN 본사에서 개최된 소프트웨어 경진대회에 참가하여 Bstorm이라는 치매 예방 목적의 소프트웨어를 개발 및 발표하였다. 나는 서버 개발을 담당하였으며, 약 40개의 API를 설계 및 구현하고 CI 파이프라인까지 구축하였다. 모놀리식 아키텍처에 대한 이해를 넓힐 수 있었고, Git Flow를 기반으로 한 협업 방식도 경험하였다. 끝까지 버그를 해결하며 노력한 결과, 장려상을 수상하였다.", + "categoryName": "전공영역-공문을 통한 전공분야 대회 참여", + "status": "APPROVE", + "imageUri": "/mocks/KDN.png" + }, + { + "id": 5, + "title": "제 27회 앱잼 참여", + "content": "Alpaco에서 주최한 제27회 앱잼에 참여하여 '가치 하다'라는 앱을 개발하였다. 백엔드 개발을 맡아 Spring Boot와 Kotlin을 사용하였고, Git을 통한 협업의 어려움을 직접 겪으며 해결책을 찾아갔다. 앱 개발이라는 환경에 적응하며 REST API 기반으로 개발을 진행했고, 협업과 시간 관리의 중요성을 체감할 수 있었다. 생활정보 분야에서 최우수상을 수상하였다.", + "categoryName": "전공영역-전공 분야 대회 개별 참여", + "status": "APPROVE", + "imageUri": "/mocks/appjam.png" + }, + { + "id": 6, + "title": "C언어 코딩 콘테스트 참여", + "content": "2024년 5월부터 6월까지 진행된 교내 C언어 코딩 콘테스트에서 DB 서버와 curl 라이브러리를 활용해 실시간 온라인 게임인 'project return(회귀)'를 개발하였다. 포인터 누수로 인한 DB 연결 중단 문제를 해결하기 위해 포인터 관리 기능을 도입하였고, 이메일 전송 기능도 직접 구현하였다. 총 누적 75,000줄에 달하는 코드 작업 끝에 최우수상을 수상하였다.", + "categoryName": "전공영역-교내 해커톤 대회", + "status": "APPROVE" + }, + { + "id": 10, + "title": "카이스트 진로 강의", + "content": "디지털 P:UM 프로젝트의 일환으로 KAIST 견학 프로그램에 참여하여 AI 및 소프트웨어 분야의 진로 강의를 들었다. AI 시대에서 개발자가 갖춰야 할 자세와 중장기 계획 수립에 대해 실제 사례와 함께 구체적으로 배울 수 있었다.", + "categoryName": "전공영역-전공 관련 교육프로그램 참여", + "status": "APPROVE", + "imageUri": "/mocks/pum.png" + }, + { + "id": 13, + "title": "아이디어 페스티벌", + "content": "학년별로 팀을 구성해 1년 동안 전공 수업을 통해 준비한 프로젝트를 발표하는 교내 행사에 참여하였다. 팀워크와 실무 경험을 통해 협업의 중요성과 발표 능력을 키울 수 있었다.", + "categoryName": "전공영역-GSM FESTIVAL", + "status": "APPROVE" + }, + { + "id": 14, + "title": "전공 캠프", + "content": "방학 동안 1주일간 학교에서 진행된 전공 캠프에 참여하여 Python, 백엔드, Git, 그리고 TOPCIT 대비 교육을 받았다. 실습 위주의 수업을 통해 백엔드 개발과 형상관리 도구에 대한 이해를 높일 수 있었고, 진로에 대한 방향을 설정하는 데 큰 도움이 되었다.", + "categoryName": "전공영역-전공관련 방과후학교 이수", + "status": "APPROVE" + } + ], + "humanitiesActivityEvidence": [ + { + "id": 8, + "title": "전기CAD기능사", + "content": "2025년 1월부터 시작하여 3월까지 방과후 및 정규 수업을 통해 전기CAD기능사 자격증 필기를 준비하고, 이후 실기시험 대비까지 병행하였다. 학교 실습실을 활용해 꾸준히 실습하였고 5월 초에 자격증을 최종 취득하였다.", + "categoryName": "인성영역-자기주도적 활동", + "status": "APPROVE" + }, + { + "id": 12, + "title": "한국사 자격증 1급", + "content": "한국사 능력 검정 시험 1급 취득.", + "categoryName": "인성영역-한국사자격증", + "status": "APPROVE" + } + ], + "readingEvidence": [ + { + "id": 3, + "title": "모두의 HTML5 & CSS3", + "author": "김인권", + "page": 324, + "content": "HTML과 CSS의 기초를 쉽고 재미있게 배울 수 있도록 구성된 입문서이다. 실제 예제를 기반으로 HTML5 태그와 CSS3의 스타일링 기법을 설명하고, 반응형 웹 디자인까지 다루며 웹 개발 초보자에게 실용적인 내용을 제공한다.", + "status": "APPROVE" + } + ], + "otherEvidence": [ + { + "id": 4, + "fileUrl": "/mocks/toefl.png", + "evidenceType": "TOEFL", + "categoryName": "외국어영역-TOEFL 점수", + "status": "APPROVE" + }, + { + "id": 7, + "fileUrl": "/mocks/ReadingMarathon.png", + "evidenceType": "READ-A-THON", + "categoryName": "인성영역-독서마라톤 토끼코스 이상", + "status": "APPROVE" + }, + { + "id": 9, + "fileUrl": "/mocks/toeic.png", + "evidenceType": "TOEIC", + "categoryName": "외국어영역-TOEIC 점수", + "status": "APPROVE" + }, + { + "id": 11, + "fileUrl": "/mocks/certificate.png", + "evidenceType": "CERTIFICATE", + "categoryName": "인성영역-한자자격증", + "status": "APPROVE" + }, + { + "id": 15, + "fileUrl": "/mocks/toeiccertificate.png", + "evidenceType": "TOEIC", + "categoryName": "외국어영역-토사관 참여", + "status": "APPROVE" + }, + { + "id": 16, + "fileUrl": "/mocks/multireadingaward.png", + "evidenceType": "CERTIFICATE", + "categoryName": "인성영역-교내인성영역관련수상", + "status": "APPROVE" + } + ] +} diff --git a/apps/client/src/views/detail/index.tsx b/apps/client/src/views/detail/index.tsx index 301b1ffd..1857b565 100644 --- a/apps/client/src/views/detail/index.tsx +++ b/apps/client/src/views/detail/index.tsx @@ -13,7 +13,7 @@ import { toast } from "sonner"; import { deletePost } from "@/entities/detail/api/deletePost"; import { useGetDraft } from "@/shared/lib/useGetDraft"; import { useGetPosts } from "@/shared/lib/useGetPosts"; -import MockJson from "@shared/mocks/data/evidenceMock.json"; +import Mock from "@shared/mocks/data/evidenceMock.json"; const DetailView = () => { const [modalOpen, setModalOpen] = useState(false); @@ -45,14 +45,19 @@ const DetailView = () => { ...(draftsData?.readingEvidences ?? []), ]; - const Mock: post[] = MockJson as post[]; + const mockPosts: post[] = [ + ...(Mock.majorActivityEvidence as post[]), + ...(Mock.humanitiesActivityEvidence as post[]), + ...(Mock.readingEvidence as post[]), + ...(Mock.otherEvidence as post[]), + ]; let post: post | Draft | undefined; if (draft === "true") { post = draftPosts.find((post) => post.draftId === id); } else if (example === "true") { - post = Mock.find((post) => post.id === Number(id)); + post = mockPosts.find((post) => post.id === Number(id)); } else { post = posts.find((post) => post.id === Number(id)); } diff --git a/apps/client/src/widgets/example/ui/index.tsx b/apps/client/src/widgets/example/ui/index.tsx index 942aae85..2479d321 100644 --- a/apps/client/src/widgets/example/ui/index.tsx +++ b/apps/client/src/widgets/example/ui/index.tsx @@ -12,23 +12,28 @@ export default function ExampleWidget() { const { setPost } = usePost(); const R = useRouter(); - const handleExamplePost = useCallback( - (data: post) => () => { - setPost(data); - R.push(`/detail/${data.id}?example=${true}`); - }, - [R, setPost], - ); + const handleExamplePost = useCallback((data: post) => () => { + setPost(data); + R.push(`/detail/${data.id}?example=${true}`); + }, [R, setPost]); + + const mockPosts: post[] = [ + ...(Mock.majorActivityEvidence as post[]), + ...(Mock.humanitiesActivityEvidence as post[]), + ...(Mock.readingEvidence as post[]), + ...(Mock.otherEvidence as post[]), + ]; + return (
- {Mock.map((data) => { + {mockPosts.map((data) => { return ( ); })} From 0fb98b3a79b4f1e306dacda4cc66b459870681ac Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 17:02:05 +0900 Subject: [PATCH 034/200] refactor: edit --- .../src/widgets/edit/api/patchActivity.ts | 31 ++++++++---- .../src/widgets/edit/api/patchReading.ts | 19 ++++++- .../client/src/widgets/edit/api/patchScore.ts | 19 ++++++- .../src/widgets/edit/model/editConfig.ts | 12 +++-- apps/client/src/widgets/edit/ui/index.tsx | 50 ++++++++++++------- 5 files changed, 93 insertions(+), 38 deletions(-) diff --git a/apps/client/src/widgets/edit/api/patchActivity.ts b/apps/client/src/widgets/edit/api/patchActivity.ts index 46f1996d..be50412f 100644 --- a/apps/client/src/widgets/edit/api/patchActivity.ts +++ b/apps/client/src/widgets/edit/api/patchActivity.ts @@ -1,29 +1,38 @@ import instance from "@repo/api/axios"; -import type { AxiosError, AxiosResponse } from "axios"; +import { isAxiosError, type AxiosResponse } from "axios"; export const patchMajorActivity = async ( evidenceId: number, activity: FormData -): Promise => { +): Promise => { try { - const res = await instance.patch(`evidence/major/${evidenceId}`, activity); - return res; - } catch (error) { - return error as AxiosError; + const response = await instance.patch( + `evidence/major/${evidenceId}`, + activity + ); + return response; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "전공 영역 수정 실패"; + } + throw error; } }; export const patchHumanitiesActivity = async ( evidenceId: number, activity: FormData -): Promise => { +): Promise => { try { - const res = await instance.patch( + const response = await instance.patch( `evidence/humanities/${evidenceId}`, activity ); - return res; - } catch (error) { - return error as AxiosError; + return response; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "인성 영역 수정 실패"; + } + throw error; } }; diff --git a/apps/client/src/widgets/edit/api/patchReading.ts b/apps/client/src/widgets/edit/api/patchReading.ts index ca9175f3..2fae23e9 100644 --- a/apps/client/src/widgets/edit/api/patchReading.ts +++ b/apps/client/src/widgets/edit/api/patchReading.ts @@ -1,7 +1,22 @@ import instance from "@repo/api/axios"; +import { isAxiosError, type AxiosResponse } from "axios"; import type { Book } from "@/widgets/write/model/book"; -export const patchReading = async (evidenceId: number, bookData: Book) => { - await instance.patch(`evidence/reading/${evidenceId}`, bookData); +export const patchReading = async ( + evidenceId: number, + bookData: Book +): Promise => { + try { + const response = await instance.patch( + `evidence/reading/${evidenceId}`, + bookData + ); + return response; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "독서 영역 수정 실패"; + } + throw error; + } }; diff --git a/apps/client/src/widgets/edit/api/patchScore.ts b/apps/client/src/widgets/edit/api/patchScore.ts index e6b97e2f..933a071e 100644 --- a/apps/client/src/widgets/edit/api/patchScore.ts +++ b/apps/client/src/widgets/edit/api/patchScore.ts @@ -1,5 +1,20 @@ import instance from "@repo/api/axios"; +import { isAxiosError, type AxiosResponse } from "axios"; -export const patchScore = async (evidenceId: number, formData: FormData) => { - await instance.patch(`evidence/reading/${evidenceId}`, formData); +export const patchScore = async ( + evidenceId: number, + formData: FormData +): Promise => { + try { + const response = await instance.patch( + `evidence/reading/${evidenceId}`, + formData + ); + return response; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "외국어 영역 수정 실패"; + } + throw error; + } }; diff --git a/apps/client/src/widgets/edit/model/editConfig.ts b/apps/client/src/widgets/edit/model/editConfig.ts index a950ce8d..f46011ac 100644 --- a/apps/client/src/widgets/edit/model/editConfig.ts +++ b/apps/client/src/widgets/edit/model/editConfig.ts @@ -1,3 +1,5 @@ +import type { AxiosResponse } from "axios"; + import type { ConfigType } from "@/shared/model/config"; import type { FormValues } from "@/widgets/edit/types/types"; import { @@ -16,7 +18,7 @@ import { patchScore } from "../api/patchScore"; interface Config { title: string; categoryOptions?: { name: string; send: string }[]; - onSubmit: (data: FormValues, id: number) => Promise; + onSubmit: (data: FormValues, id: number) => Promise; } export const getEditConfig = (type: ConfigType): Config => { @@ -35,7 +37,7 @@ export const getEditConfig = (type: ConfigType): Config => { formData.append("content", data.content || ""); formData.append("activityType", "MAJOR"); - await patchMajorActivity(id, formData); + return await patchMajorActivity(id, formData); }, }; } @@ -53,7 +55,7 @@ export const getEditConfig = (type: ConfigType): Config => { formData.append("content", data.content || ""); formData.append("activityType", "HUMANITIES"); - await patchHumanitiesActivity(id, formData); + return await patchHumanitiesActivity(id, formData); }, }; } @@ -67,7 +69,7 @@ export const getEditConfig = (type: ConfigType): Config => { page: Number(data.page) || 0, content: data.content || "", }; - await patchReading(id, bookData); + return await patchReading(id, bookData); }, }; } @@ -81,7 +83,7 @@ export const getEditConfig = (type: ConfigType): Config => { formData.append("file", data.file); } formData.append("value", String(data.value)); - await patchScore(id, formData); + return await patchScore(id, formData); }, }; } diff --git a/apps/client/src/widgets/edit/ui/index.tsx b/apps/client/src/widgets/edit/ui/index.tsx index 77387a8f..6db58a37 100644 --- a/apps/client/src/widgets/edit/ui/index.tsx +++ b/apps/client/src/widgets/edit/ui/index.tsx @@ -4,12 +4,15 @@ import { Button } from "@repo/shared/button"; import { Input } from "@repo/shared/input"; import { InputContainer } from "@repo/shared/inputContainer"; import type { Activity, Others, Reading } from "@repo/types/evidences"; -import { useRouter, useSearchParams } from "next/navigation"; +import { useMutation } from "@tanstack/react-query"; +import { HttpStatusCode } from "axios"; +import { useRouter } from "next/navigation"; import { useCallback } from "react"; import { Controller, useForm, useWatch } from "react-hook-form"; import { toast } from "sonner"; import type { ConfigType } from "@/shared/model/config"; +import type { HttpError } from "@/shared/model/error"; import { Dropdown, File, Textarea } from "@/shared/ui"; import { getDefaultValues } from "@/widgets/edit/lib/getDefaultValues"; import { getEditConfig } from "@/widgets/edit/model/editConfig"; @@ -20,14 +23,36 @@ import type { } from "@/widgets/edit/types/types"; import { getWriteConfig } from "@/widgets/write/model/writeConfig"; + + const EditForm = ({ type, post }: EditFormProps) => { - const searchParams = useSearchParams(); - const isDraft = Boolean(searchParams.get("draft")); const router = useRouter(); + const isDraft = "draftId" in post; const config = getEditConfig(type as ConfigType); const draftConfig = getWriteConfig(type as ConfigType); + const { mutate } = useMutation({ + mutationFn: (data: FormValues) => isDraft ? + draftConfig.onSubmit({ ...data, draftId: post.draftId }, "submit") : + config.onSubmit(data, Number(post.id)), + onSuccess: (data) => { + if (data.status === 201) { + toast.success("증빙자료를 성공적으로 저장하였습니다.") + router.push("/"); + } + }, + onError: (error: HttpError) => { + if (error.httpStatus === HttpStatusCode.NotFound) { + toast.error("해당 증빙 자료가 존재하지 않습니다."); + } else if (error.httpStatus === HttpStatusCode.UnprocessableEntity) { + toast.error("더 이상 증빙 자료를 추가할 수 없습니다."); + } else { + toast.error("증빙 자료 추가에 실패했습니다."); + } + } + }) + const { handleSubmit, control, @@ -42,21 +67,10 @@ const EditForm = ({ type, post }: EditFormProps) => { const file = useWatch({ control, name: "file" }); - const handleFormSubmit = useCallback(async (data: FormValues) => { - try { - if (isDraft && "draftId" in post) { - await draftConfig.onSubmit({ ...data, draftId: post.draftId }, "submit"); - toast.success("작성이 완료되었습니다."); - router.back(); - } else if (!isDraft && "id" in post) { - await config.onSubmit(data, Number(post.id)); - toast.success("수정이 완료되었습니다."); - router.back(); - } - } catch { - toast.error("수정에 실패했습니다."); - } - }, [config, draftConfig, isDraft, post, router]); + const handleFormSubmit = useCallback((data: FormValues) => { + mutate(data) + router.back() + }, [mutate, router]); const handleReviseSubmit = useCallback((e: React.FormEvent) => { void handleSubmit(handleFormSubmit)(e); From 07845c3655b6bfaaee3f5f4286ba8746ced68255 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 17:02:14 +0900 Subject: [PATCH 035/200] chore: posts --- apps/client/src/widgets/posts/ui/index.tsx | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/apps/client/src/widgets/posts/ui/index.tsx b/apps/client/src/widgets/posts/ui/index.tsx index 90d5cc4d..e8dd187f 100644 --- a/apps/client/src/widgets/posts/ui/index.tsx +++ b/apps/client/src/widgets/posts/ui/index.tsx @@ -63,17 +63,14 @@ export default function PostsWidget() { [], ); - const handleRoute = useCallback( - (post: post | Draft) => () => { - setPost(post); - if ("draftId" in post) { - R.push(`/detail/${post.draftId}?draft=${true}`); - return; - } - R.push(`/detail/${post.id}`); - }, - [R, setPost], - ); + const handleRoute = useCallback((post: post | Draft) => () => { + setPost(post); + if ("draftId" in post) { + R.push(`/detail/${post.draftId}`); + return; + } + R.push(`/detail/${post.id}`); + }, [R, setPost]); let displayedPosts: (post | Draft)[] = []; From f6195b6c1ac0212c3205d852c31cfaded31179c5 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Thu, 3 Jul 2025 17:02:27 +0900 Subject: [PATCH 036/200] chore: write --- apps/client/src/widgets/write/ui/index.tsx | 52 +++++++++------------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/apps/client/src/widgets/write/ui/index.tsx b/apps/client/src/widgets/write/ui/index.tsx index a576e3a7..3923534c 100644 --- a/apps/client/src/widgets/write/ui/index.tsx +++ b/apps/client/src/widgets/write/ui/index.tsx @@ -19,8 +19,6 @@ import { chooseDropdownOption } from "@/widgets/write/lib/chooseDropdownOption"; import { getWriteConfig } from "../model/writeConfig"; - - export default function WriteForm() { const searchParams = useSearchParams(); const router = useRouter(); @@ -101,8 +99,7 @@ export default function WriteForm() { className="flex sm:gap-[2rem] gap-[1.5rem] flex-col" onSubmit={handleWriteSubmit} > - {(type === "major" || type === "humanities" || type === "foreign") && - config.categoryOptions ? ( + {type !== "reading" && config.categoryOptions ? ( control={control} name="categoryName" @@ -136,7 +133,6 @@ export default function WriteForm() { rules={{ required: "카테고리를 선택해주세요." }} /> ) : null} - {type !== "foreign" && ( @@ -148,7 +144,6 @@ export default function WriteForm() { /> )} - {(type === "reading" || (type === "foreign" && !needDropdown)) && ( <> {type === "reading" && ( @@ -176,7 +171,6 @@ export default function WriteForm() { )} - {type !== "foreign" && ( control={control} @@ -204,30 +198,26 @@ export default function WriteForm() { }} /> )} - - {(type === "major" || - type === "humanities" || - type === "foreign") && ( - - control={control} - name="file" - // eslint-disable-next-line react/jsx-no-bind - render={({ field: { value, onChange, ...field } }) => ( - - )} - rules={{ - ...(type === "foreign" && { - required: "파일을 첨부해주세요.", - }), - }} - /> - )} - + {(type !== "reading") && ( + + control={control} + name="file" + // eslint-disable-next-line react/jsx-no-bind + render={({ field: { value, onChange, ...field } }) => ( + + )} + rules={{ + ...(type === "foreign" && { + required: "파일을 첨부해주세요.", + }), + }} + /> + )}
{type !== "foreign" && (
{modalOpen ? ( From a96eaf9415eadac74fb13416897fe0dee4791c87 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Fri, 4 Jul 2025 09:34:23 +0900 Subject: [PATCH 052/200] fix: evidence types --- packages/types/src/draft.ts | 26 ++++++++++++++++++++------ packages/types/src/evidences.ts | 18 +++++++++--------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/packages/types/src/draft.ts b/packages/types/src/draft.ts index 63c3dd43..0c3829ec 100644 --- a/packages/types/src/draft.ts +++ b/packages/types/src/draft.ts @@ -1,11 +1,25 @@ -import type { Activity, Reading } from "@repo/types/evidences"; +export interface ActivityDraft { + draftId: string; + title: string; + content: string; + imageUri?: string; + categoryName: string; + activityType: ActivityType; +} -export interface DraftResponse { - activityEvidences: Draft[]; - readingEvidences: Draft[]; +export interface ReadingDraft { + draftId: string; + title: string; + content: string; + author: string; + page: number; } -export type ActivityDraft = Omit & { draftId: string }; -export type ReadingDraft = Omit & { draftId: string }; +export type ActivityType = "MAJOR" | "HUMANITIES"; export type Draft = ActivityDraft | ReadingDraft; + +export interface DraftResponse { + activityEvidences: ActivityDraft[]; + readingEvidences: ReadingDraft[]; +} diff --git a/packages/types/src/evidences.ts b/packages/types/src/evidences.ts index 167ee929..04940503 100644 --- a/packages/types/src/evidences.ts +++ b/packages/types/src/evidences.ts @@ -3,31 +3,27 @@ export interface Activity { title: string; content: string; imageUri?: string; - status: postState; categoryName: string; + status: PostStatus; } export interface Reading { id: number; title: string; + content: string; author: string; page: number; - content: string; - status: postState; + status: PostStatus; } export interface Others { id: number; - fileUri: string; evidenceType: EvidenceType; - status: postState; + fileUri: string; categoryName: string; + status: PostStatus; } -export type postState = "APPROVE" | "PENDING" | "REJECT"; - -export type post = Activity | Reading | Others; - export type EvidenceType = | "MAJOR" | "HUMANITIES" @@ -45,6 +41,10 @@ export type EvidenceType = | "CPT" | "HSK"; +export type PostStatus = "PENDING" | "APPROVE" | "REJECT"; + +export type Post = Activity | Reading | Others; + export interface EvidenceResponse { majorActivityEvidence: Activity[]; humanitiesActivityEvidence: Activity[]; From 4f42a74fbb795396103d589b6b888f22b9b817ca Mon Sep 17 00:00:00 2001 From: bae080311 Date: Sat, 5 Jul 2025 15:57:03 +0900 Subject: [PATCH 053/200] feat: get score --- apps/admin/src/entities/member/api/getScore.ts | 18 ++++++++++++++++++ .../src/entities/member/model/useGetScore.ts | 11 +++++++++++ 2 files changed, 29 insertions(+) create mode 100644 apps/admin/src/entities/member/api/getScore.ts create mode 100644 apps/admin/src/entities/member/model/useGetScore.ts diff --git a/apps/admin/src/entities/member/api/getScore.ts b/apps/admin/src/entities/member/api/getScore.ts new file mode 100644 index 00000000..b332a341 --- /dev/null +++ b/apps/admin/src/entities/member/api/getScore.ts @@ -0,0 +1,18 @@ +import instance from "@repo/api"; +import { AxiosError } from "axios"; +import { toast } from "sonner"; +import type { ScoreResponse } from "../model/score"; + +export const getScore = async ( + id: string +): Promise => { + try { + const res = await instance.get(`/score/${id}`); + return res.data as ScoreResponse; + } catch (error) { + if (error instanceof AxiosError) { + toast.error("점수 정보를 불러오는데 실패했습니다"); + } + } + return undefined; +}; diff --git a/apps/admin/src/entities/member/model/useGetScore.ts b/apps/admin/src/entities/member/model/useGetScore.ts new file mode 100644 index 00000000..c84abc7c --- /dev/null +++ b/apps/admin/src/entities/member/model/useGetScore.ts @@ -0,0 +1,11 @@ +import { useQuery } from "@tanstack/react-query"; +import { getScore } from "../api/getScore"; +import type { ScoreResponse } from "./score"; + +export const useGetScore = (id: string) => { + return useQuery({ + queryKey: ["score", id], + queryFn: () => getScore(id), + enabled: !!id, + }); +}; From e2c546b8da1b94d331e486c10924ab5675398d35 Mon Sep 17 00:00:00 2001 From: bae080311 Date: Sat, 5 Jul 2025 15:57:09 +0900 Subject: [PATCH 054/200] feat: score type --- apps/admin/src/entities/member/model/score.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 apps/admin/src/entities/member/model/score.ts diff --git a/apps/admin/src/entities/member/model/score.ts b/apps/admin/src/entities/member/model/score.ts new file mode 100644 index 00000000..c9559eb2 --- /dev/null +++ b/apps/admin/src/entities/member/model/score.ts @@ -0,0 +1,9 @@ +export interface ScoreResponse { + totalScore: number; + scores: Score[]; +} + +export interface Score { + categoryName: string; + value: number; +} From e2387b5168648d33ef6755306268f0dfe635c955 Mon Sep 17 00:00:00 2001 From: bae080311 Date: Sat, 5 Jul 2025 16:01:32 +0900 Subject: [PATCH 055/200] feat: score modal --- .../src/entities/member/ui/scoreModal.tsx | 39 +++++++++++++++++++ .../src/widgets/member/ui/information.tsx | 33 +++++++++++----- 2 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 apps/admin/src/entities/member/ui/scoreModal.tsx diff --git a/apps/admin/src/entities/member/ui/scoreModal.tsx b/apps/admin/src/entities/member/ui/scoreModal.tsx new file mode 100644 index 00000000..c3575258 --- /dev/null +++ b/apps/admin/src/entities/member/ui/scoreModal.tsx @@ -0,0 +1,39 @@ +"use client"; + +import { Button } from "@repo/shared/button"; +import Card from "@repo/shared/card"; +import List from "@repo/shared/list"; +import { useGetScore } from "../model/useGetScore"; +import { getCategoryName } from "@repo/utils/handleCategory"; + +interface ScoreModalProps { + close: () => void; + show: boolean; + id: string; +} + +export default function ScoreModal({ show, close, id }: ScoreModalProps) { + const { data } = useGetScore(id as string); + if (!show) return; + return ( +
+
+

부분점수

+ + {data && + data?.scores.map((v) => { + return ( + + ); + })} + +
+
+ ); +} diff --git a/apps/admin/src/widgets/member/ui/information.tsx b/apps/admin/src/widgets/member/ui/information.tsx index c7b963e2..301ca209 100644 --- a/apps/admin/src/widgets/member/ui/information.tsx +++ b/apps/admin/src/widgets/member/ui/information.tsx @@ -2,11 +2,13 @@ import { Button } from "@repo/shared/button"; import { useRouter } from "next/navigation"; -import { useCallback } from "react"; +import { useCallback, useState } from "react"; import { useMember } from "@/entities/member/model/memberContext"; +import ScoreModal from "@/entities/member/ui/scoreModal"; export default function Information() { + const [modal, setModal] = useState(false); const R = useRouter(); const { member: student } = useMember(); @@ -18,6 +20,13 @@ export default function Information() { R.push(`/score/${student?.email}`); }, [R, student?.email]); + const open = useCallback(() => { + setModal(true); + }, []); + const close = useCallback(() => { + setModal(false); + }, []); + if (student === undefined) { return

로딩중...

; } @@ -31,19 +40,23 @@ export default function Information() { {student.name} {`${student.grade}학년 ${student.classNumber}반 ${student.number}번`}
-
+
{student.totalScore + "점"}
-
-
+
+
+ ); } From 1b75c3a6757af5dfb02b48486477c8f165d8b467 Mon Sep 17 00:00:00 2001 From: bae080311 Date: Sat, 5 Jul 2025 16:01:38 +0900 Subject: [PATCH 056/200] fix: title optional --- packages/shared/src/list.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/shared/src/list.tsx b/packages/shared/src/list.tsx index ef8e9788..a22d0b39 100644 --- a/packages/shared/src/list.tsx +++ b/packages/shared/src/list.tsx @@ -6,7 +6,7 @@ import { Filtered } from "./filtered.tsx"; interface ListProps { children: React.ReactNode; - title: string; + title?: string; className?: string; isFilter?: boolean; onClick?: () => void; @@ -25,7 +25,7 @@ const List = ({

- {title} + {title ?? ""}

{isFilter ? ( From 8341ad1083936ff2013d623970685b78cf41f841 Mon Sep 17 00:00:00 2001 From: bae080311 Date: Sat, 5 Jul 2025 16:03:14 +0900 Subject: [PATCH 057/200] feat: cursor pointer --- apps/admin/src/widgets/member/ui/information.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/admin/src/widgets/member/ui/information.tsx b/apps/admin/src/widgets/member/ui/information.tsx index 301ca209..8894ff8d 100644 --- a/apps/admin/src/widgets/member/ui/information.tsx +++ b/apps/admin/src/widgets/member/ui/information.tsx @@ -42,7 +42,7 @@ export default function Information() {
{student.totalScore + "점"}
From 71c07f96b7a433a5f832183b5d6abaad0455a7a5 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:11:50 +0900 Subject: [PATCH 058/200] fix: configType --- apps/client/src/shared/model/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/client/src/shared/model/config.ts b/apps/client/src/shared/model/config.ts index 047f1b1e..bdcf8fb2 100644 --- a/apps/client/src/shared/model/config.ts +++ b/apps/client/src/shared/model/config.ts @@ -1 +1 @@ -export type ConfigType = "major" | "humanities" | "reading" | "foreign"; +export type ConfigType = "major" | "humanities" | "reading" | "others"; From 7e3a2aa1221156fc2982fc3d84ba12dcb2b4e3cd Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:12:18 +0900 Subject: [PATCH 059/200] fix: typeGuard --- packages/utils/src/handlePost.ts | 43 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/packages/utils/src/handlePost.ts b/packages/utils/src/handlePost.ts index 87e73b4a..cea8f423 100644 --- a/packages/utils/src/handlePost.ts +++ b/packages/utils/src/handlePost.ts @@ -1,32 +1,31 @@ -import type { Draft, ActivityDraft, ReadingDraft } from "@repo/types/draft"; -import type { Activity, Reading, Others } from "@repo/types/evidences"; +import type { DraftType, ActivityDraft, ReadingDraft } from "@repo/types/draft"; +import type { + Activity, + Reading, + Others, + PostType, +} from "@repo/types/evidences"; -interface MockPostFlag { - __isMock: true; +function isDraft(data: PostType | DraftType): data is DraftType { + return typeof data === "object" && "draftId" in data; } -export type MockPost = (Activity | Reading | Others) & MockPostFlag; +function isPost(data: PostType | DraftType): data is PostType { + return typeof data === "object" && "id" in data; +} -const isActivity = ( - data: Activity | Reading | Others | Draft -): data is Activity | ActivityDraft => { +function isActivity( + data: PostType | DraftType +): data is Activity | ActivityDraft { return "imageUri" in data; -}; +} -const isReading = ( - data: Activity | Reading | Others | Draft -): data is Reading | ReadingDraft => { +function isReading(data: PostType | DraftType): data is Reading | ReadingDraft { return "author" in data; -}; +} -const isOthers = ( - data: Activity | Reading | Others | Draft -): data is Others => { +function isOthers(data: PostType | DraftType): data is Others { return !isActivity(data) && !isReading(data); -}; - -const isMockPost = (data: unknown): data is MockPost => { - return typeof data === "object" && data !== null && "__isMock" in data; -}; +} -export { isActivity, isReading, isOthers, isMockPost }; +export { isDraft, isPost, isActivity, isReading, isOthers }; From 38a1a16a056ab163588613e61ecd566474da1cd8 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:13:15 +0900 Subject: [PATCH 060/200] fix: evidence, post type --- packages/types/src/draft.ts | 6 ++--- packages/types/src/evidences.ts | 42 ++++++++++++++++----------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/types/src/draft.ts b/packages/types/src/draft.ts index 0c3829ec..e0646a79 100644 --- a/packages/types/src/draft.ts +++ b/packages/types/src/draft.ts @@ -1,3 +1,5 @@ +export type ActivityType = "MAJOR" | "HUMANITIES"; + export interface ActivityDraft { draftId: string; title: string; @@ -15,9 +17,7 @@ export interface ReadingDraft { page: number; } -export type ActivityType = "MAJOR" | "HUMANITIES"; - -export type Draft = ActivityDraft | ReadingDraft; +export type DraftType = ActivityDraft | ReadingDraft; export interface DraftResponse { activityEvidences: ActivityDraft[]; diff --git a/packages/types/src/evidences.ts b/packages/types/src/evidences.ts index 04940503..cac9a850 100644 --- a/packages/types/src/evidences.ts +++ b/packages/types/src/evidences.ts @@ -1,3 +1,22 @@ +export type EvidenceType = + | "MAJOR" + | "HUMANITIES" + | "READING" + | "FOREIGN_LANGUAGE" + | "CERTIFICATE" + | "TOPCIT" + | "READ-A-THON" + | "TOEIC" + | "TOEFL" + | "TEPS" + | "TOEIC_SPEAKING" + | "OPIC" + | "JPT" + | "CPT" + | "HSK"; + +export type PostStatus = "PENDING" | "APPROVE" | "REJECT"; + export interface Activity { id: number; title: string; @@ -24,28 +43,9 @@ export interface Others { status: PostStatus; } -export type EvidenceType = - | "MAJOR" - | "HUMANITIES" - | "READING" - | "FOREIGN_LANGUAGE" - | "CERTIFICATE" - | "TOPCIT" - | "READ-A-THON" - | "TOEIC" - | "TOEFL" - | "TEPS" - | "TOEIC_SPEAKING" - | "OPIC" - | "JPT" - | "CPT" - | "HSK"; - -export type PostStatus = "PENDING" | "APPROVE" | "REJECT"; - -export type Post = Activity | Reading | Others; +export type PostType = Activity | Reading | Others; -export interface EvidenceResponse { +export interface PostResponse { majorActivityEvidence: Activity[]; humanitiesActivityEvidence: Activity[]; readingEvidence: Reading[]; From 11946ba0cb90fe721480a3afe04bcafc0ce9bf7b Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:14:11 +0900 Subject: [PATCH 061/200] fix: mock --- .../src/shared/mocks/data/evidenceMock.json | 68 +++++++------------ 1 file changed, 26 insertions(+), 42 deletions(-) diff --git a/apps/client/src/shared/mocks/data/evidenceMock.json b/apps/client/src/shared/mocks/data/evidenceMock.json index 7f2567ea..2322402a 100644 --- a/apps/client/src/shared/mocks/data/evidenceMock.json +++ b/apps/client/src/shared/mocks/data/evidenceMock.json @@ -3,80 +3,71 @@ { "id": 1, "title": "AWS를 이용하는 방법", - "content": "...", + "content": "2024년 9월 12일에 진행된 4시간짜리 AWS 교육에 참여하여 AWS VPC, AWS Lambda, AWS S3, AWS EC2 등 현대 소프트웨어 개발에서 핵심이 되는 서비스들을 학습하고 실습하였다. 학생으로서는 알기 힘든 AWS의 요금제, VPC 구성 방법 등을 실습을 통해 익히고, AI 서비스인 PartyRock을 활용한 애플리케이션도 제작해보며 AWS 생태계 전반을 이해하는 데 큰 도움이 되었다. 교육 후 임시 계정을 발급받아 자율 실습도 진행하며 다양한 시도를 해볼 수 있었다.", "categoryName": "전공영역-전공특강(방과후) 참가", "status": "APPROVE", - "imageUri": "/mocks/aws.png", - "__isMock": true + "imageUri": "/mocks/aws.png" }, { "id": 2, "title": "한전 KDN 소프트웨어 경진대회", - "content": "...", + "content": "2024년 11월 27일, 나주 한전 KDN 본사에서 개최된 소프트웨어 경진대회에 참가하여 Bstorm이라는 치매 예방 목적의 소프트웨어를 개발 및 발표하였다. 나는 서버 개발을 담당하였으며, 약 40개의 API를 설계 및 구현하고 CI 파이프라인까지 구축하였다. 모놀리식 아키텍처에 대한 이해를 넓힐 수 있었고, Git Flow를 기반으로 한 협업 방식도 경험하였다. 끝까지 버그를 해결하며 노력한 결과, 장려상을 수상하였다.", "categoryName": "전공영역-공문을 통한 전공분야 대회 참여", "status": "APPROVE", - "imageUri": "/mocks/KDN.png", - "__isMock": true + "imageUri": "/mocks/KDN.png" }, { "id": 5, "title": "제 27회 앱잼 참여", - "content": "...", + "content": "Alpaco에서 주최한 제27회 앱잼에 참여하여 '가치 하다'라는 앱을 개발하였다. 백엔드 개발을 맡아 Spring Boot와 Kotlin을 사용하였고, Git을 통한 협업의 어려움을 직접 겪으며 해결책을 찾아갔다. 앱 개발이라는 환경에 적응하며 REST API 기반으로 개발을 진행했고, 협업과 시간 관리의 중요성을 체감할 수 있었다. 생활정보 분야에서 최우수상을 수상하였다.", "categoryName": "전공영역-전공 분야 대회 개별 참여", "status": "APPROVE", - "imageUri": "/mocks/appjam.png", - "__isMock": true + "imageUri": "/mocks/appjam.png" }, { "id": 6, "title": "C언어 코딩 콘테스트 참여", - "content": "...", + "content": "2024년 5월부터 6월까지 진행된 교내 C언어 코딩 콘테스트에서 DB 서버와 curl 라이브러리를 활용해 실시간 온라인 게임인 'project return(회귀)'를 개발하였다. 포인터 누수로 인한 DB 연결 중단 문제를 해결하기 위해 포인터 관리 기능을 도입하였고, 이메일 전송 기능도 직접 구현하였다. 총 누적 75,000줄에 달하는 코드 작업 끝에 최우수상을 수상하였다.", "categoryName": "전공영역-교내 해커톤 대회", - "status": "APPROVE", - "__isMock": true + "status": "APPROVE" }, { "id": 10, "title": "카이스트 진로 강의", - "content": "...", + "content": "디지털 P:UM 프로젝트의 일환으로 KAIST 견학 프로그램에 참여하여 AI 및 소프트웨어 분야의 진로 강의를 들었다. AI 시대에서 개발자가 갖춰야 할 자세와 중장기 계획 수립에 대해 실제 사례와 함께 구체적으로 배울 수 있었다.", "categoryName": "전공영역-전공 관련 교육프로그램 참여", "status": "APPROVE", - "imageUri": "/mocks/pum.png", - "__isMock": true + "imageUri": "/mocks/pum.png" }, { "id": 13, "title": "아이디어 페스티벌", - "content": "...", + "content": "학년별로 팀을 구성해 1년 동안 전공 수업을 통해 준비한 프로젝트를 발표하는 교내 행사에 참여하였다. 팀워크와 실무 경험을 통해 협업의 중요성과 발표 능력을 키울 수 있었다.", "categoryName": "전공영역-GSM FESTIVAL", - "status": "APPROVE", - "__isMock": true + "status": "APPROVE" }, { "id": 14, "title": "전공 캠프", - "content": "...", + "content": "방학 동안 1주일간 학교에서 진행된 전공 캠프에 참여하여 Python, 백엔드, Git, 그리고 TOPCIT 대비 교육을 받았다. 실습 위주의 수업을 통해 백엔드 개발과 형상관리 도구에 대한 이해를 높일 수 있었고, 진로에 대한 방향을 설정하는 데 큰 도움이 되었다.", "categoryName": "전공영역-전공관련 방과후학교 이수", - "status": "APPROVE", - "__isMock": true + "status": "APPROVE" } ], "humanitiesActivityEvidence": [ { "id": 8, "title": "전기CAD기능사", - "content": "...", + "content": "2025년 1월부터 시작하여 3월까지 방과후 및 정규 수업을 통해 전기CAD기능사 자격증 필기를 준비하고, 이후 실기시험 대비까지 병행하였다. 학교 실습실을 활용해 꾸준히 실습하였고 5월 초에 자격증을 최종 취득하였다.", "categoryName": "인성영역-자기주도적 활동", - "status": "APPROVE", - "__isMock": true + "status": "APPROVE" }, { "id": 12, "title": "한국사 자격증 1급", - "content": "...", + "content": "한국사 능력 검정 시험 1급 취득.", "categoryName": "인성영역-한국사자격증", - "status": "APPROVE", - "__isMock": true + "status": "APPROVE" } ], "readingEvidence": [ @@ -85,9 +76,8 @@ "title": "모두의 HTML5 & CSS3", "author": "김인권", "page": 324, - "content": "...", - "status": "APPROVE", - "__isMock": true + "content": "HTML과 CSS의 기초를 쉽고 재미있게 배울 수 있도록 구성된 입문서이다. 실제 예제를 기반으로 HTML5 태그와 CSS3의 스타일링 기법을 설명하고, 반응형 웹 디자인까지 다루며 웹 개발 초보자에게 실용적인 내용을 제공한다.", + "status": "APPROVE" } ], "otherEvidence": [ @@ -96,48 +86,42 @@ "fileUri": "/mocks/toefl.png", "evidenceType": "TOEFL", "categoryName": "외국어영역-TOEFL 점수", - "status": "APPROVE", - "__isMock": true + "status": "APPROVE" }, { "id": 7, "fileUri": "/mocks/ReadingMarathon.png", "evidenceType": "READ-A-THON", "categoryName": "인성영역-독서마라톤 토끼코스 이상", - "status": "APPROVE", - "__isMock": true + "status": "APPROVE" }, { "id": 9, "fileUri": "/mocks/toeic.png", "evidenceType": "TOEIC", "categoryName": "외국어영역-TOEIC 점수", - "status": "APPROVE", - "__isMock": true + "status": "APPROVE" }, { "id": 11, "fileUri": "/mocks/certificate.png", "evidenceType": "CERTIFICATE", "categoryName": "인성영역-한자자격증", - "status": "APPROVE", - "__isMock": true + "status": "APPROVE" }, { "id": 15, "fileUri": "/mocks/toeiccertificate.png", "evidenceType": "TOEIC", "categoryName": "외국어영역-토사관 참여", - "status": "APPROVE", - "__isMock": true + "status": "APPROVE" }, { "id": 16, "fileUri": "/mocks/multireadingaward.png", "evidenceType": "CERTIFICATE", "categoryName": "인성영역-교내인성영역관련수상", - "status": "APPROVE", - "__isMock": true + "status": "APPROVE" } ] } From ee266f0f8246babed35d44d51176580f0a1bb263 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:15:13 +0900 Subject: [PATCH 062/200] chore: post --- apps/client/src/shared/ui/post/index.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/client/src/shared/ui/post/index.tsx b/apps/client/src/shared/ui/post/index.tsx index a6981cdc..248b3710 100644 --- a/apps/client/src/shared/ui/post/index.tsx +++ b/apps/client/src/shared/ui/post/index.tsx @@ -1,17 +1,18 @@ -import type { Draft } from "@repo/types/draft"; -import type { post } from "@repo/types/evidences"; +import type { DraftType } from "@repo/types/draft"; +import type { PostType } from "@repo/types/evidences"; import { getCategoryName } from "@repo/utils/handleCategory"; import { isActivity, isOthers, isReading } from "@repo/utils/handlePost"; import { handleState, handleStateColor } from "@repo/utils/handleState"; import Image from "next/image"; interface PostProps { - data: post | Draft; + data: PostType | DraftType; isExample?: boolean; onClick?: () => void; } const Post = ({ data, isExample = false, onClick }: PostProps) => { + const title = (() => { if ("title" in data) return data.title; if ("evidenceType" in data) return data.evidenceType @@ -52,7 +53,7 @@ const Post = ({ data, isExample = false, onClick }: PostProps) => { {subTitle}

{!isExample && state ? - + {handleState(state)} : null} From 9fb88ae12485742ff556586690ecc4f5055065c5 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:15:35 +0900 Subject: [PATCH 063/200] fix: patch --- apps/client/src/widgets/edit/api/patchOthers.ts | 16 +++++++++++----- .../edit/api/{patchScore.ts => patchScoring.ts} | 4 ++-- 2 files changed, 13 insertions(+), 7 deletions(-) rename apps/client/src/widgets/edit/api/{patchScore.ts => patchScoring.ts} (85%) diff --git a/apps/client/src/widgets/edit/api/patchOthers.ts b/apps/client/src/widgets/edit/api/patchOthers.ts index d7b73017..64f6bba6 100644 --- a/apps/client/src/widgets/edit/api/patchOthers.ts +++ b/apps/client/src/widgets/edit/api/patchOthers.ts @@ -1,14 +1,20 @@ import instance from "@repo/api/axios"; -import type { AxiosError, AxiosResponse } from "axios"; +import { isAxiosError, type AxiosError, type AxiosResponse } from "axios"; export const patchOthers = async ( evidenceId: number, formData: FormData ): Promise => { try { - const res = await instance.patch(`evidence/other/${evidenceId}`, formData); - return res; - } catch (error) { - return error as AxiosError; + const response = await instance.patch( + `evidence/other/${evidenceId}`, + formData + ); + return response; + } catch (error: unknown) { + if (isAxiosError(error) && error.response) { + throw error.response.data ?? "기타 영역 수정 실패"; + } + throw error; } }; diff --git a/apps/client/src/widgets/edit/api/patchScore.ts b/apps/client/src/widgets/edit/api/patchScoring.ts similarity index 85% rename from apps/client/src/widgets/edit/api/patchScore.ts rename to apps/client/src/widgets/edit/api/patchScoring.ts index 933a071e..be083289 100644 --- a/apps/client/src/widgets/edit/api/patchScore.ts +++ b/apps/client/src/widgets/edit/api/patchScoring.ts @@ -1,13 +1,13 @@ import instance from "@repo/api/axios"; import { isAxiosError, type AxiosResponse } from "axios"; -export const patchScore = async ( +export const patchScoring = async ( evidenceId: number, formData: FormData ): Promise => { try { const response = await instance.patch( - `evidence/reading/${evidenceId}`, + `evidence/scoring/${evidenceId}`, formData ); return response; From d55b837257885d2f6dfdf1d55d7260aec599754e Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:16:00 +0900 Subject: [PATCH 064/200] fix: post --- apps/client/src/widgets/write/api/postActivity.ts | 2 +- apps/client/src/widgets/write/api/postActivityDraft.ts | 2 +- .../src/widgets/write/api/{postBook.ts => postReading.ts} | 4 ++-- .../write/api/{postBookDraft.ts => postReadingDraft.ts} | 4 ++-- .../widgets/write/api/{postScore.ts => postScoring.ts} | 8 +++++--- 5 files changed, 11 insertions(+), 9 deletions(-) rename apps/client/src/widgets/write/api/{postBook.ts => postReading.ts} (71%) rename apps/client/src/widgets/write/api/{postBookDraft.ts => postReadingDraft.ts} (71%) rename apps/client/src/widgets/write/api/{postScore.ts => postScoring.ts} (60%) diff --git a/apps/client/src/widgets/write/api/postActivity.ts b/apps/client/src/widgets/write/api/postActivity.ts index 286c52ab..0bdb9b03 100644 --- a/apps/client/src/widgets/write/api/postActivity.ts +++ b/apps/client/src/widgets/write/api/postActivity.ts @@ -9,7 +9,7 @@ export const postActivity = async ( return response; } catch (error: unknown) { if (isAxiosError(error) && error.response) { - throw error.response.data ?? "활동영역 저장 실패"; + throw error.response.data ?? "활동 영역 저장 실패"; } throw error; } diff --git a/apps/client/src/widgets/write/api/postActivityDraft.ts b/apps/client/src/widgets/write/api/postActivityDraft.ts index e7a3c962..93b3c9be 100644 --- a/apps/client/src/widgets/write/api/postActivityDraft.ts +++ b/apps/client/src/widgets/write/api/postActivityDraft.ts @@ -12,7 +12,7 @@ export const postActivityDraft = async ( return response; } catch (error: unknown) { if (isAxiosError(error) && error.response) { - throw error.response.data ?? "활동영역 임시 저장 실패"; + throw error.response.data ?? "활동 영역 임시 저장 실패"; } throw error; } diff --git a/apps/client/src/widgets/write/api/postBook.ts b/apps/client/src/widgets/write/api/postReading.ts similarity index 71% rename from apps/client/src/widgets/write/api/postBook.ts rename to apps/client/src/widgets/write/api/postReading.ts index 75d14cc0..de5c17f5 100644 --- a/apps/client/src/widgets/write/api/postBook.ts +++ b/apps/client/src/widgets/write/api/postReading.ts @@ -3,13 +3,13 @@ import { isAxiosError, type AxiosResponse } from "axios"; import type { Book } from "../model/book"; -export const postBook = async (bookData: Book): Promise => { +export const postReading = async (bookData: Book): Promise => { try { const response = await instance.post("evidence/current/reading", bookData); return response; } catch (error: unknown) { if (isAxiosError(error) && error.response) { - throw error.response.data ?? "독서영역 저장 실패"; + throw error.response.data ?? "독서 영역 저장 실패"; } throw error; } diff --git a/apps/client/src/widgets/write/api/postBookDraft.ts b/apps/client/src/widgets/write/api/postReadingDraft.ts similarity index 71% rename from apps/client/src/widgets/write/api/postBookDraft.ts rename to apps/client/src/widgets/write/api/postReadingDraft.ts index 17a8f3e1..4c287469 100644 --- a/apps/client/src/widgets/write/api/postBookDraft.ts +++ b/apps/client/src/widgets/write/api/postReadingDraft.ts @@ -3,7 +3,7 @@ import { isAxiosError, type AxiosResponse } from "axios"; import type { Book } from "../model/book"; -export const postBookDraft = async (data: Book): Promise => { +export const postReadingDraft = async (data: Book): Promise => { try { const response = await instance.post( "/evidence/current/draft/reading", @@ -12,7 +12,7 @@ export const postBookDraft = async (data: Book): Promise => { return response; } catch (error: unknown) { if (isAxiosError(error) && error.response) { - throw error.response.data ?? "독서영역 임시 저장 실패"; + throw error.response.data ?? "독서 영역 임시 저장 실패"; } throw error; } diff --git a/apps/client/src/widgets/write/api/postScore.ts b/apps/client/src/widgets/write/api/postScoring.ts similarity index 60% rename from apps/client/src/widgets/write/api/postScore.ts rename to apps/client/src/widgets/write/api/postScoring.ts index 45ba7b4e..3f9cbed7 100644 --- a/apps/client/src/widgets/write/api/postScore.ts +++ b/apps/client/src/widgets/write/api/postScoring.ts @@ -1,10 +1,12 @@ import instance from "@repo/api/axios"; import { isAxiosError, type AxiosResponse } from "axios"; -export const postScore = async (formData: FormData): Promise => { +export const postScoring = async ( + formData: FormData +): Promise => { try { - const res = await instance.post("/evidence/current/scoring", formData); - return res; + const response = await instance.post("/evidence/current/scoring", formData); + return response; } catch (error: unknown) { if (isAxiosError(error) && error.response) { throw error.response.data ?? "외국어 영역 저장 실패"; From 8aadbaa6fed408126625c860155a1b645df158a1 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:16:38 +0900 Subject: [PATCH 065/200] rename: handle reading --- .../client/src/widgets/write/lib/handleBookSubmit.ts | 10 ---------- .../src/widgets/write/lib/handleSubmitReading.ts | 12 ++++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) delete mode 100644 apps/client/src/widgets/write/lib/handleBookSubmit.ts create mode 100644 apps/client/src/widgets/write/lib/handleSubmitReading.ts diff --git a/apps/client/src/widgets/write/lib/handleBookSubmit.ts b/apps/client/src/widgets/write/lib/handleBookSubmit.ts deleted file mode 100644 index 880e3b82..00000000 --- a/apps/client/src/widgets/write/lib/handleBookSubmit.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { postBook } from "../api/postBook"; -import { postBookDraft } from "../api/postBookDraft"; -import type { Book } from "../model/book"; - -export const handleSubmitBook = async ( - data: Book, - submitType: "submit" | "draft" -) => { - return await (submitType === "draft" ? postBookDraft(data) : postBook(data)); -}; diff --git a/apps/client/src/widgets/write/lib/handleSubmitReading.ts b/apps/client/src/widgets/write/lib/handleSubmitReading.ts new file mode 100644 index 00000000..92c78750 --- /dev/null +++ b/apps/client/src/widgets/write/lib/handleSubmitReading.ts @@ -0,0 +1,12 @@ +import { postReading } from "../api/postReading"; +import { postReadingDraft } from "../api/postReadingDraft"; +import type { Book } from "../model/book"; + +export const handleSubmitReading = async ( + data: Book, + submitType: "submit" | "draft" +) => { + return await (submitType === "draft" + ? postReadingDraft(data) + : postReading(data)); +}; From f55c0efec0b59d89819e8ea6f2efd62f1c7b06a4 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:17:06 +0900 Subject: [PATCH 066/200] chore: config --- apps/client/src/widgets/edit/model/editConfig.ts | 10 +++++----- apps/client/src/widgets/write/model/writeConfig.ts | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/client/src/widgets/edit/model/editConfig.ts b/apps/client/src/widgets/edit/model/editConfig.ts index f46011ac..b7f47f1c 100644 --- a/apps/client/src/widgets/edit/model/editConfig.ts +++ b/apps/client/src/widgets/edit/model/editConfig.ts @@ -1,7 +1,7 @@ import type { AxiosResponse } from "axios"; import type { ConfigType } from "@/shared/model/config"; -import type { FormValues } from "@/widgets/edit/types/types"; +import type { FormValues, Option } from "@/widgets/edit/types/types"; import { MajorOptions, HumanitiesOptions, @@ -13,11 +13,11 @@ import { patchHumanitiesActivity, } from "../api/patchActivity"; import { patchReading } from "../api/patchReading"; -import { patchScore } from "../api/patchScore"; +import { patchScoring } from "../api/patchScoring"; interface Config { title: string; - categoryOptions?: { name: string; send: string }[]; + categoryOptions?: Option[]; onSubmit: (data: FormValues, id: number) => Promise; } @@ -73,7 +73,7 @@ export const getEditConfig = (type: ConfigType): Config => { }, }; } - case "foreign": { + case "others": { return { title: "외국어 영역 수정", categoryOptions: ForeignOptions, @@ -83,7 +83,7 @@ export const getEditConfig = (type: ConfigType): Config => { formData.append("file", data.file); } formData.append("value", String(data.value)); - return await patchScore(id, formData); + return await patchScoring(id, formData); }, }; } diff --git a/apps/client/src/widgets/write/model/writeConfig.ts b/apps/client/src/widgets/write/model/writeConfig.ts index 6d6464ff..294baf01 100644 --- a/apps/client/src/widgets/write/model/writeConfig.ts +++ b/apps/client/src/widgets/write/model/writeConfig.ts @@ -1,20 +1,20 @@ import type { AxiosResponse } from "axios"; import type { ConfigType } from "@/shared/model/config"; -import type { FormValues } from "@/widgets/edit/types/types"; +import type { FormValues, Option } from "@/widgets/edit/types/types"; import { MajorOptions, HumanitiesOptions, ForeignOptions, } from "@/widgets/write/model/category"; -import { postScore } from "../api/postScore"; -import { handleSubmitBook } from "../lib/handleBookSubmit"; +import { postScoring } from "../api/postScoring"; import { handleSubmitActivity } from "../lib/handleSubmitActivity"; +import { handleSubmitReading } from "../lib/handleSubmitReading"; interface Config { title: string; - categoryOptions?: { name: string; send: string }[]; + categoryOptions?: Option[]; onSubmit: ( data: FormValues, type: "draft" | "submit" @@ -76,11 +76,11 @@ export const getWriteConfig = (type: ConfigType): Config => { content: data.content || "", draftId: data.draftId ?? null, }; - return await handleSubmitBook(bookData, type); + return await handleSubmitReading(bookData, type); }, }; } - case "foreign": { + case "others": { return { title: "외국어 영역", categoryOptions: ForeignOptions, @@ -91,7 +91,7 @@ export const getWriteConfig = (type: ConfigType): Config => { } formData.append("categoryName", data.categoryName?.send ?? ""); formData.append("value", String(data.value)); - return await postScore(formData); + return await postScoring(formData); }, }; } From c1dd1ab6a6e44d9908a4aa27b80ff0cdd1823533 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:21:17 +0900 Subject: [PATCH 067/200] chore: getPost --- apps/client/src/shared/api/getPosts.ts | 8 +++----- apps/client/src/shared/lib/useGetPosts.ts | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/client/src/shared/api/getPosts.ts b/apps/client/src/shared/api/getPosts.ts index 4482c91c..7564f3be 100644 --- a/apps/client/src/shared/api/getPosts.ts +++ b/apps/client/src/shared/api/getPosts.ts @@ -1,8 +1,6 @@ import instance from "@repo/api/axios"; -import type { EvidenceResponse, EvidenceType } from "@repo/types/evidences"; +import type { PostResponse, EvidenceType } from "@repo/types/evidences"; -export const getPosts = async (type: EvidenceType | null) => { - return await instance.get( - `/evidence/current${type === null ? "" : "?type=" + type}`, - ); +export const getPosts = async (type: EvidenceType) => { + return await instance.get(`/evidence/current?type=${type}`); }; diff --git a/apps/client/src/shared/lib/useGetPosts.ts b/apps/client/src/shared/lib/useGetPosts.ts index 6f19df81..ac366ef9 100644 --- a/apps/client/src/shared/lib/useGetPosts.ts +++ b/apps/client/src/shared/lib/useGetPosts.ts @@ -3,10 +3,10 @@ import { useQuery } from "@tanstack/react-query"; import { getPosts } from "../api/getPosts"; -export const useGetPosts = (type: EvidenceType | "DRAFT" | null) => { +export const useGetPosts = (type: EvidenceType | "DRAFT") => { return useQuery({ queryKey: ["posts", type], - queryFn: () => getPosts(type as EvidenceType | null), + queryFn: () => getPosts(type as EvidenceType), enabled: type !== "DRAFT", }); }; From 0aea3a4f83e7be534f3398cf0c2773c7beeb219d Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:21:27 +0900 Subject: [PATCH 068/200] chore: getDraft --- apps/client/src/shared/lib/useGetDraft.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/client/src/shared/lib/useGetDraft.ts b/apps/client/src/shared/lib/useGetDraft.ts index f9d731e6..3dab4695 100644 --- a/apps/client/src/shared/lib/useGetDraft.ts +++ b/apps/client/src/shared/lib/useGetDraft.ts @@ -1,11 +1,12 @@ -import type { DraftResponse } from "@repo/types/draft"; +import type { EvidenceType } from "@repo/types/evidences"; import { useQuery } from "@tanstack/react-query"; import { getDraft } from "../api/getDraft"; -export const useGetDraft = () => { - return useQuery({ - queryKey: ["drafts"], +export const useGetDraft = (type: EvidenceType | "DRAFT" | null) => { + return useQuery({ + queryKey: ["drafts", type], queryFn: getDraft, + enabled: type == "DRAFT", }); }; From 2d38838cedbe5b80d046d3324bd1e84c1a73fdff Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:21:49 +0900 Subject: [PATCH 069/200] move: view -> widget --- apps/client/src/views/edit/index.tsx | 79 +--------------------------- 1 file changed, 1 insertion(+), 78 deletions(-) diff --git a/apps/client/src/views/edit/index.tsx b/apps/client/src/views/edit/index.tsx index 407351e3..ab94b9b6 100644 --- a/apps/client/src/views/edit/index.tsx +++ b/apps/client/src/views/edit/index.tsx @@ -1,84 +1,7 @@ -"use client"; - -import type { Draft } from "@repo/types/draft"; -import type { post, Activity } from "@repo/types/evidences"; -import { isActivity, isReading } from "@repo/utils/handlePost"; -import { useParams, useSearchParams } from "next/navigation"; -import { toast } from "sonner"; - -import { useGetDraft } from "@/shared/lib/useGetDraft"; -import { useGetPosts } from "@/shared/lib/useGetPosts" import EditForm from "@/widgets/edit/ui"; const EditView = () => { - const params = useParams(); - const searchParams = useSearchParams(); - - const { id } = params; - const isDraft = searchParams.get("draft") === "true"; - - const { data: postsData, isError: isPostsError } = useGetPosts(null); - const { data: draftsData, isError: isDraftsError } = useGetDraft(); - - if (isPostsError || isDraftsError) { - toast.error("게시물을 불러오지 못했습니다."); - } - - const posts: post[] = [ - ...(postsData?.data.majorActivityEvidence ?? []), - ...(postsData?.data.humanitiesActivityEvidence ?? []), - ...(postsData?.data.readingEvidence ?? []), - ...(postsData?.data.otherEvidence ?? []), - ]; - - const draftPosts: Draft[] = [ - ...(draftsData?.activityEvidences ?? []), - ...(draftsData?.readingEvidences ?? []), - ]; - - const post: post | Draft | undefined = isDraft - ? draftPosts.find((p) => String(p.draftId) === id) - : posts.find((p) => p.id === Number(id)); - - if (!post) { - return
게시물을 찾을 수 없습니다.
; - } - - let type: "major" | "humanities" | "reading" | "others"; - - if ("draftId" in post) { - if ("author" in post) { - type = "reading"; - } else if ("categoryName" in post && post.categoryName === "MAJOR") { - type = "major"; - } else { - type = "humanities"; - } - } else { - const isMajorActivity = - isActivity(post) && - postsData?.data.majorActivityEvidence.some( - (p: Activity) => p.id === post.id, - ); - - const isHumanitiesActivity = - isActivity(post) && - postsData?.data.humanitiesActivityEvidence.some( - (p: Activity) => p.id === post.id, - ); - - if (isMajorActivity ?? false) { - type = "major"; - } else if (isHumanitiesActivity ?? false) { - type = "humanities"; - } else if (isReading(post)) { - type = "reading"; - } else { - type = "others"; - } - } - - return ; + return ; }; export default EditView; From 15b56fe748e97b5c866fd1393c5e2d33d098a712 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:22:05 +0900 Subject: [PATCH 070/200] remove: unused type --- apps/client/src/widgets/edit/types/types.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apps/client/src/widgets/edit/types/types.ts b/apps/client/src/widgets/edit/types/types.ts index e5263420..c3b558a3 100644 --- a/apps/client/src/widgets/edit/types/types.ts +++ b/apps/client/src/widgets/edit/types/types.ts @@ -1,6 +1,3 @@ -import type { Draft } from "@repo/types/draft"; -import type { post } from "@repo/types/evidences"; - export interface Option { name: string; send: string; @@ -16,8 +13,3 @@ export interface FormValues { value?: number; draftId?: string; } - -export interface EditFormProps { - type: "major" | "humanities" | "reading" | "others" | "foreign"; - post: post | Draft; -} From df91187dfd6cd4aba7c1115cba60591aa0e9606c Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:22:32 +0900 Subject: [PATCH 071/200] chore: posts --- apps/client/src/widgets/posts/ui/index.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/client/src/widgets/posts/ui/index.tsx b/apps/client/src/widgets/posts/ui/index.tsx index 96fbf3e2..4185e1b5 100644 --- a/apps/client/src/widgets/posts/ui/index.tsx +++ b/apps/client/src/widgets/posts/ui/index.tsx @@ -2,8 +2,8 @@ import { Button } from "@repo/shared/button"; import { usePost } from "@repo/store/postProvider"; -import type { Draft } from "@repo/types/draft"; -import type { EvidenceResponse, post } from "@repo/types/evidences"; +import type { DraftType } from "@repo/types/draft"; +import type { PostType, PostResponse } from "@repo/types/evidences"; import { useRouter } from "next/navigation"; import { useCallback, useState } from "react"; import { toast } from "sonner"; @@ -17,31 +17,31 @@ import type { CategoryType } from "../model/category"; export default function PostsWidget() { const router = useRouter(); - const [result, setResult] = useState(); + const [result, setResult] = useState(); const [search, setSearch] = useState(""); const [categoryName, setCategoryName] = useState("READING"); const { data: postsData, isError: isPostsError } = useGetPosts(categoryName); - const { data: draftsData, isError: isDraftsError } = useGetDraft(); + const { data: draftsData, isError: isDraftsError } = useGetDraft(categoryName); const { setPost } = usePost(); if (isPostsError || isDraftsError) { toast.error("게시물을 불러오지 못했습니다."); } - const posts: post[] = [ + const posts: PostType[] = [ ...(postsData?.data.majorActivityEvidence ?? []), ...(postsData?.data.humanitiesActivityEvidence ?? []), ...(postsData?.data.readingEvidence ?? []), ...(postsData?.data.otherEvidence ?? []), ]; - const draftPosts: Draft[] = [ + const draftPosts: DraftType[] = [ ...(draftsData?.activityEvidences ?? []), ...(draftsData?.readingEvidences ?? []), ]; - const resultPosts: post[] = [ + const resultPosts: PostType[] = [ ...(result?.majorActivityEvidence ?? []), ...(result?.humanitiesActivityEvidence ?? []), ...(result?.readingEvidence ?? []), @@ -56,7 +56,7 @@ export default function PostsWidget() { { label: "임시저장", value: "DRAFT" }, ]; - let displayedPosts: (post | Draft)[] = []; + let displayedPosts: (PostType | DraftType)[] = []; if (search.trim().length > 0 && resultPosts.length > 0) { displayedPosts = resultPosts; @@ -70,7 +70,7 @@ export default function PostsWidget() { setCategoryName(value); }, []); - const handleRoute = useCallback((post: post | Draft) => () => { + const handleRoute = useCallback((post: PostType | DraftType) => () => { setPost(post); if ("draftId" in post) { router.push(`/detail/${post.draftId}`); From 7329a005c192b605b0da0ba984ff6ae89682cd29 Mon Sep 17 00:00:00 2001 From: Dino0204 Date: Sat, 5 Jul 2025 19:22:53 +0900 Subject: [PATCH 072/200] chore: write --- apps/client/src/widgets/write/ui/index.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/client/src/widgets/write/ui/index.tsx b/apps/client/src/widgets/write/ui/index.tsx index dd7845a3..bbdb0b87 100644 --- a/apps/client/src/widgets/write/ui/index.tsx +++ b/apps/client/src/widgets/write/ui/index.tsx @@ -20,8 +20,8 @@ import { chooseDropdownOption } from "@/widgets/write/lib/chooseDropdownOption"; import { getWriteConfig } from "../model/writeConfig"; export default function WriteForm() { - const searchParams = useSearchParams(); const router = useRouter(); + const searchParams = useSearchParams(); const type = searchParams.get("type") as ConfigType const config = getWriteConfig(type); @@ -116,7 +116,7 @@ export default function WriteForm() { rules={{ required: "카테고리를 선택해주세요." }} /> ) : null} - {type === "foreign" && needDropdown ? ( + {type === "others" && needDropdown ? ( control={control} name="value" @@ -133,7 +133,7 @@ export default function WriteForm() { rules={{ required: "카테고리를 선택해주세요." }} /> ) : null} - {type !== "foreign" && ( + {type !== "others" && ( control={control} @@ -149,7 +149,7 @@ export default function WriteForm() { )} - {(type === "reading" || (type === "foreign" && !needDropdown)) && ( + {(type === "reading" || (type === "others" && !needDropdown)) && ( <> {type === "reading" && ( @@ -184,7 +184,7 @@ export default function WriteForm() { )} - {type !== "foreign" && ( + {type !== "others" && ( control={control} name="content" @@ -225,14 +225,14 @@ export default function WriteForm() { /> )} rules={{ - ...(type === "foreign" && { + ...(type === "others" && { required: "파일을 첨부해주세요.", }), }} /> )}
- {type !== "foreign" && ( + {type !== "others" && (
- + +
+
- - - value === formValues.password || "비밀번호가 일치하지 않습니다.", - }} - type="password" - /> + +
+ passwordCheck === password || "비밀번호가 일치하지 않습니다.", + }} + type={showPasswordCheck ? "text" : "password"} + /> + +
+ + +
+
- - - value === formValues.password || "비밀번호가 일치하지 않습니다.", - }} - type="password" - /> + +
+ passwordCheck === password || "비밀번호가 일치하지 않습니다.", + }} + type={showPasswordCheck ? "text" : "password"} + /> + +
+