From 4ba2f17f915260fbcb58af6ec21d980e9e2e4b2e Mon Sep 17 00:00:00 2001 From: aken-you Date: Mon, 18 Aug 2025 21:42:23 +0900 Subject: [PATCH 01/34] =?UTF-8?q?refactor:=20=EC=8A=A4=ED=84=B0=EB=94=94?= =?UTF-8?q?=20=EC=8B=A0=EC=B2=AD=20=EB=B2=84=ED=8A=BC=20=EB=94=94=EC=9E=90?= =?UTF-8?q?=EC=9D=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/apply-study.svg | 9 +++++++ public/images/start-study.png | Bin 20978 -> 0 bytes src/features/study/ui/start-study-modal.tsx | 25 +++++++++++++------- 3 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 public/apply-study.svg delete mode 100644 public/images/start-study.png diff --git a/public/apply-study.svg b/public/apply-study.svg new file mode 100644 index 00000000..36d1f6ac --- /dev/null +++ b/public/apply-study.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/images/start-study.png b/public/images/start-study.png deleted file mode 100644 index 52b6682a9b95a6361e96acbbe43824fa99da4fad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20978 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 QhX4Qo07*qoM6N<$f}WYj!~g&Q diff --git a/src/features/study/ui/start-study-modal.tsx b/src/features/study/ui/start-study-modal.tsx index 4c3a190e..f563fe57 100644 --- a/src/features/study/ui/start-study-modal.tsx +++ b/src/features/study/ui/start-study-modal.tsx @@ -89,14 +89,23 @@ export default function StartStudyModal({ memberId }: StartStudyModalProps) { return ( - 스터디 시작 버튼 +
+

+ + CS 스터디를 시작해 보세요! + + + 스터디 신청하기 + +

+ + 스터디 시작 버튼 +
From f1941c142117688af50278f84552f8c9c673c631 Mon Sep 17 00:00:00 2001 From: aken-you Date: Mon, 18 Aug 2025 21:46:39 +0900 Subject: [PATCH 02/34] =?UTF-8?q?feat:=20=ED=94=BC=EB=93=9C=EB=B0=B1=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 피드백 링크는 나오면 추가할 예정 --- public/feedback.svg | 9 +++++++++ src/widgets/home/sidebar.tsx | 17 +++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 public/feedback.svg diff --git a/public/feedback.svg b/public/feedback.svg new file mode 100644 index 00000000..60d352ad --- /dev/null +++ b/public/feedback.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/widgets/home/sidebar.tsx b/src/widgets/home/sidebar.tsx index 9709d142..8eea21c6 100644 --- a/src/widgets/home/sidebar.tsx +++ b/src/widgets/home/sidebar.tsx @@ -1,3 +1,5 @@ +import Image from 'next/image'; +import Link from 'next/link'; import { getUserProfile } from '@/entities/user/api/get-user-profile'; import MyProfileCard from '@/features/study/ui/my-profile-card'; import StartStudyModal from '@/features/study/ui/start-study-modal'; @@ -34,6 +36,21 @@ export default async function Sidebar() { ) : ( )} + +

+ + 여러분의 의견이 궁금해요! + + + 소중한 피드백을 기다리고 있어요 + +

+ + 피드백 + ); From 7777017003bbf806b643c12c200a8c32371cb94f Mon Sep 17 00:00:00 2001 From: aken-you Date: Mon, 18 Aug 2025 21:51:28 +0900 Subject: [PATCH 03/34] =?UTF-8?q?refactor:=20=ED=94=BC=EB=93=9C=EB=B0=B1?= =?UTF-8?q?=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EA=B0=80=EB=A1=9C=EA=B8=B8?= =?UTF-8?q?=EC=9D=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/widgets/home/sidebar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/home/sidebar.tsx b/src/widgets/home/sidebar.tsx index 8eea21c6..bd51ad86 100644 --- a/src/widgets/home/sidebar.tsx +++ b/src/widgets/home/sidebar.tsx @@ -49,7 +49,7 @@ export default async function Sidebar() {

- 피드백 + 피드백 From 7662040d0c6b3c8b8ff0eb31e4f5363d6d99aa6f Mon Sep 17 00:00:00 2001 From: aken-you Date: Wed, 20 Aug 2025 22:38:08 +0900 Subject: [PATCH 04/34] =?UTF-8?q?feat:=20background=20=EC=BB=AC=EB=9F=AC?= =?UTF-8?q?=20=ED=86=A0=ED=81=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/global.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/global.css b/app/global.css index 74119091..8a7fa12f 100644 --- a/app/global.css +++ b/app/global.css @@ -192,6 +192,10 @@ https://velog.io/@oneook/tailwindcss-4.0-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%AC%E --color-background-brand-default: var(--color-rose-500); --color-background-brand-strong: var(--color-rose-700); + --color-background-neutral-subtle: var(--color-gray-200); + --color-background-neutral-default: var(--color-gray-500); + --color-background-neutral-strong: var(--color-gray-900); + --color-background-accent-blue-subtle: var(--color-blue-50); --color-background-accent-blue-default: var(--color-blue-100); --color-background-accent-blue-strong: var(--color-blue-600); From 3a9b7d96fdc4c2e3215643b4f8bdf6d834e9f78f Mon Sep 17 00:00:00 2001 From: aken-you Date: Wed, 20 Aug 2025 22:38:23 +0900 Subject: [PATCH 05/34] =?UTF-8?q?feat:=20=EC=8A=A4=ED=84=B0=EB=94=94?= =?UTF-8?q?=EC=9B=90=20=ED=9B=84=EA=B8=B0=20=EC=9E=91=EC=84=B1=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=EC=97=90=EC=84=9C=20=EB=B3=B4=EC=97=AC=EC=A4=84=20?= =?UTF-8?q?=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/icons/fine-review.svg | 9 +++++++++ public/icons/good-review.svg | 9 +++++++++ public/icons/shame-review.svg | 9 +++++++++ 3 files changed, 27 insertions(+) create mode 100644 public/icons/fine-review.svg create mode 100644 public/icons/good-review.svg create mode 100644 public/icons/shame-review.svg diff --git a/public/icons/fine-review.svg b/public/icons/fine-review.svg new file mode 100644 index 00000000..13307185 --- /dev/null +++ b/public/icons/fine-review.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/icons/good-review.svg b/public/icons/good-review.svg new file mode 100644 index 00000000..e4b9aeeb --- /dev/null +++ b/public/icons/good-review.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/icons/shame-review.svg b/public/icons/shame-review.svg new file mode 100644 index 00000000..50ee650e --- /dev/null +++ b/public/icons/shame-review.svg @@ -0,0 +1,9 @@ + + + + + + + + + From 82c1a5dbb02a0438957689b73d9d9a7313a6b2a5 Mon Sep 17 00:00:00 2001 From: aken-you Date: Wed, 20 Aug 2025 22:54:17 +0900 Subject: [PATCH 06/34] =?UTF-8?q?feat:=20success=20background=20=EC=BB=AC?= =?UTF-8?q?=EB=9F=AC=20=ED=86=A0=ED=81=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/global.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/global.css b/app/global.css index 8a7fa12f..1cb1b7fa 100644 --- a/app/global.css +++ b/app/global.css @@ -230,6 +230,10 @@ https://velog.io/@oneook/tailwindcss-4.0-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%AC%E --color-background-accent-yellow-default: var(--color-yellow-100); --color-background-accent-yellow-strong: var(--color-yellow-600); + --color-background-success-subtle: var(--color-green-300); + --color-background-success-default: var(--color-green-500); + --color-background-success-strong: var(--color-green-700); + --color-fill-brand-default-default: var(--color-rose-500); --color-fill-brand-default-hover: var(--color-rose-600); --color-fill-brand-default-pressed: var(--color-rose-700); From cfd197f93d5c3b1a12187a06b461b0e2e50291bd Mon Sep 17 00:00:00 2001 From: aken-you Date: Thu, 21 Aug 2025 22:54:17 +0900 Subject: [PATCH 07/34] =?UTF-8?q?feat:=20checkbox=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/icons/shape.svg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 public/icons/shape.svg diff --git a/public/icons/shape.svg b/public/icons/shape.svg new file mode 100644 index 00000000..af8ad1d5 --- /dev/null +++ b/public/icons/shape.svg @@ -0,0 +1,3 @@ + + + From 3a0ff1449a3e9d2d6c4d768af67fbe3e82c30000 Mon Sep 17 00:00:00 2001 From: aken-you Date: Thu, 21 Aug 2025 22:54:38 +0900 Subject: [PATCH 08/34] =?UTF-8?q?feat:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=ED=9B=84=EA=B8=B0=20=EB=AA=A8=EB=8B=AC=EC=97=90=20=EB=B3=B4?= =?UTF-8?q?=EC=97=AC=EC=A4=84=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EC=BB=A4=EC=8A=A4=ED=85=80=ED=9B=85=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/api/get-review.ts | 11 +++++++++ src/features/study/api/types.ts | 24 ++++++++++++++++++++ src/features/study/model/use-review-query.ts | 9 ++++++++ 3 files changed, 44 insertions(+) create mode 100644 src/features/study/api/get-review.ts create mode 100644 src/features/study/model/use-review-query.ts diff --git a/src/features/study/api/get-review.ts b/src/features/study/api/get-review.ts new file mode 100644 index 00000000..4b64b14d --- /dev/null +++ b/src/features/study/api/get-review.ts @@ -0,0 +1,11 @@ +import { axiosInstance } from '@/shared/tanstack-query/axios'; +import { StudyEvaluationResponse } from './types'; + +export const getPartnerStudyReview = + async (): Promise => { + const res = await axiosInstance.get( + '/study/reviews/this-week/target-study', + ); + + return res.data.content; + }; diff --git a/src/features/study/api/types.ts b/src/features/study/api/types.ts index f790661b..9a6077a0 100644 --- a/src/features/study/api/types.ts +++ b/src/features/study/api/types.ts @@ -94,3 +94,27 @@ export interface CompleteStudyRequest { feedback: string; progressStatus: StudyProgressStatus; } + +interface EvalKeyword { + id: number; + keyword: string; + satisfactionId: number; + satisfactionLabel: string; +} + +interface Partner { + memberId: number; + memberName: string; + profileImageUrl: string; +} + +export interface StudyEvaluationResponse { + studySpaceId: number; + targetMembers: Partner[]; + studySubject: string; + startDate: string; // "yyyy-MM-dd" 형식 + endDate: string; // "yyyy-MM-dd" 형식 + satisfiedEvalKeywords: EvalKeyword[]; + notBadEvalKeywords: EvalKeyword[]; + unsatisfiedEvalKeywords: EvalKeyword[]; +} diff --git a/src/features/study/model/use-review-query.ts b/src/features/study/model/use-review-query.ts new file mode 100644 index 00000000..2feac763 --- /dev/null +++ b/src/features/study/model/use-review-query.ts @@ -0,0 +1,9 @@ +import { useQuery } from '@tanstack/react-query'; +import { getPartnerStudyReview } from '../api/get-review'; + +export const usePartnerStudyReviewQuery = () => { + return useQuery({ + queryKey: ['partnerStudyReview'], + queryFn: getPartnerStudyReview, + }); +}; From e62a608e9b2582fd193515e594cc8b512bfcb7e9 Mon Sep 17 00:00:00 2001 From: aken-you Date: Thu, 21 Aug 2025 22:55:01 +0900 Subject: [PATCH 09/34] =?UTF-8?q?fix:=20Button=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=EC=84=9C=20cn=20=EC=98=A4=ED=83=80?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/shadcn/ui/button.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/shadcn/ui/button.tsx b/src/shared/shadcn/ui/button.tsx index b81e3ffb..d61405e4 100644 --- a/src/shared/shadcn/ui/button.tsx +++ b/src/shared/shadcn/ui/button.tsx @@ -50,7 +50,7 @@ function Button({ return ( ); From 913982c4cc5de34c01a54e01e5b178d5b1da80f4 Mon Sep 17 00:00:00 2001 From: aken-you Date: Sat, 23 Aug 2025 13:53:00 +0900 Subject: [PATCH 10/34] =?UTF-8?q?feat:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=ED=9B=84=EA=B8=B0=20=EB=AA=A8=EB=8B=AC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- next.config.ts | 5 + src/features/study/api/types.ts | 2 +- src/features/study/ui/study-review-modal.tsx | 298 +++++++++++++++++++ src/shared/ui/checkbox/index.tsx | 15 + src/shared/ui/list-item/index.tsx | 22 ++ 5 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 src/features/study/ui/study-review-modal.tsx create mode 100644 src/shared/ui/checkbox/index.tsx create mode 100644 src/shared/ui/list-item/index.tsx diff --git a/next.config.ts b/next.config.ts index e1dcedae..108ea078 100644 --- a/next.config.ts +++ b/next.config.ts @@ -15,6 +15,11 @@ const nextConfig: NextConfig = { hostname: 'test-api.zeroone.it.kr', pathname: '/profile-image/**', }, + { + protocol: 'https', + hostname: 'api.zeroone.it.kr', + pathname: '/profile-image/**', + }, { protocol: 'https', hostname: 'lh3.googleusercontent.com', diff --git a/src/features/study/api/types.ts b/src/features/study/api/types.ts index 9a6077a0..4cc0bc80 100644 --- a/src/features/study/api/types.ts +++ b/src/features/study/api/types.ts @@ -95,7 +95,7 @@ export interface CompleteStudyRequest { progressStatus: StudyProgressStatus; } -interface EvalKeyword { +export interface EvalKeyword { id: number; keyword: string; satisfactionId: number; diff --git a/src/features/study/ui/study-review-modal.tsx b/src/features/study/ui/study-review-modal.tsx new file mode 100644 index 00000000..56dda129 --- /dev/null +++ b/src/features/study/ui/study-review-modal.tsx @@ -0,0 +1,298 @@ +'use client'; + +import { XIcon } from 'lucide-react'; +import Image from 'next/image'; +import { useState } from 'react'; +import Button from '@/shared/ui/button'; +import Checkbox from '@/shared/ui/checkbox'; +import { TextAreaInput } from '@/shared/ui/input'; +import ListItem from '@/shared/ui/list-item'; +import { Modal } from '@/shared/ui/modal'; +import { EvalKeyword, StudyEvaluationResponse } from '../api/types'; +import { usePartnerStudyReviewQuery } from '../model/use-review-query'; + +export default function StudyReviewModal() { + // 10 - "아쉬워요", 20 - "괜찮아요", 30 - "좋았어요" + const [satisfactionId, setSatisfactionId] = useState<10 | 20 | 30 | null>( + null, + ); + + const { data } = usePartnerStudyReviewQuery(); + + if (!data) return null; + + return ( + + +
+

+ + CS 스터디를 시작해 보세요! + + + 스터디 신청하기 + +

+
+
+ + + + + + + + + + +
+ 함께 스터디한 멤버에 대해 알려주세요 + +
+ + 같이 성장할 수 있는 스터디 문화를 만들기 위해 평가를 + 남겨주세요. + + 평가한 내용은 성실 온도에 반영됩니다. +
+
+ + + +
+ + 스터디 만족도 + + +
+ setSatisfactionId(10)} + /> + + setSatisfactionId(20)} + /> + + setSatisfactionId(30)} + /> +
+
+ + {satisfactionId === 10 && } + + {(satisfactionId === 20 || satisfactionId === 30) && ( + + )} +
+ + + + +
+
+
+ ); +} + +function PartnerInfo(data: StudyEvaluationResponse) { + const partner = data.targetMembers[0]; + + return ( +
+ Study Member + +
+ + {partner.memberName} + + +

+ + {data.studySubject} + + + {data.startDate} ~ {data.endDate} + +

+
+
+ ); +} + +function SatisfactionButton({ + label, + isSelected, + imageSrc, + onClick, +}: { + label: string; + isSelected: boolean; + imageSrc: string; + onClick: () => void; +}) { + return ( + + ); +} + +function PositiveReview({ + satisfactionId, + data, +}: { + satisfactionId: 20 | 30; + data: StudyEvaluationResponse; +}) { + return ( + <> + + + + ); +} + +function NegativeReview({ data }: { data: StudyEvaluationResponse }) { + return ( + <> + + + + ); +} + +function PositiveCheckboxList({ + positiveKeywords, +}: { + positiveKeywords: EvalKeyword[]; +}) { + return ( +
+
+ + 이런 점이 좋았어요 + + 필수 +
+ +
    + {positiveKeywords.map(({ id, keyword }) => ( + + + + + ))} +
+
+ ); +} + +function PositiveTextArea() { + return ( +
+
+

+ 어떤 점이 좋았나요? +

+
+ + 같이 성장할 수 있는 스터디 문화를 만들기 위해 평가를 남겨주세요. + + 평가한 내용은 성실 온도에 반영됩니다. +
+
+ + +
+ ); +} + +function NegativeCheckboxList({ + negativeKeywords, +}: { + negativeKeywords: StudyEvaluationResponse['unsatisfiedEvalKeywords']; +}) { + return ( +
+
+ + 이런 점이 아쉬웠어요 + + 필수 +
+ +
    + {negativeKeywords.map(({ id, keyword }) => ( + + + + + ))} +
+
+ ); +} + +function NegativeTextArea() { + return ( +
+
+

+ 어떤 점이 아쉬웠나요? +

+
+ + 스터디 과정에서 아쉬웠던 점이 있다면, 이는 성장을 위한 소중한 + 피드백이 됩니다. + + 작성하신 내용은 오직 상대방만 확인할 수 있어요. +
+
+ + +
+ ); +} diff --git a/src/shared/ui/checkbox/index.tsx b/src/shared/ui/checkbox/index.tsx new file mode 100644 index 00000000..a4b4961b --- /dev/null +++ b/src/shared/ui/checkbox/index.tsx @@ -0,0 +1,15 @@ +import { cn } from '@/shared/shadcn/lib/utils'; + +const Checkbox = ({ id }: { id: string }) => { + return ( + + ); +}; + +export default Checkbox; diff --git a/src/shared/ui/list-item/index.tsx b/src/shared/ui/list-item/index.tsx new file mode 100644 index 00000000..0c5e8874 --- /dev/null +++ b/src/shared/ui/list-item/index.tsx @@ -0,0 +1,22 @@ +import { cn } from '@/shared/shadcn/lib/utils'; + +const ListItem = ({ + className = '', + children, +}: { + className?: string; + children: React.ReactNode; +}) => { + return ( +
  • + {children} +
  • + ); +}; + +export default ListItem; From 4a97b4d890ec3da1b5889f9e677ead7af244c9fe Mon Sep 17 00:00:00 2001 From: aken-you Date: Sat, 23 Aug 2025 15:50:45 +0900 Subject: [PATCH 11/34] =?UTF-8?q?feat:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EC=A0=9C=EC=B6=9C=20api=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=ED=9B=85=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/api/get-review.ts | 8 +++++++- src/features/study/api/types.ts | 8 ++++++++ src/features/study/model/use-review-query.ts | 10 ++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/features/study/api/get-review.ts b/src/features/study/api/get-review.ts index 4b64b14d..6cd2642d 100644 --- a/src/features/study/api/get-review.ts +++ b/src/features/study/api/get-review.ts @@ -1,5 +1,5 @@ import { axiosInstance } from '@/shared/tanstack-query/axios'; -import { StudyEvaluationResponse } from './types'; +import { AddStudyReviewRequest, StudyEvaluationResponse } from './types'; export const getPartnerStudyReview = async (): Promise => { @@ -9,3 +9,9 @@ export const getPartnerStudyReview = return res.data.content; }; + +export const addStudyReview = async (data: AddStudyReviewRequest) => { + const res = await axiosInstance.post('/study/reviews', data); + + return res.data.content; +}; diff --git a/src/features/study/api/types.ts b/src/features/study/api/types.ts index 4cc0bc80..263bd30b 100644 --- a/src/features/study/api/types.ts +++ b/src/features/study/api/types.ts @@ -118,3 +118,11 @@ export interface StudyEvaluationResponse { notBadEvalKeywords: EvalKeyword[]; unsatisfiedEvalKeywords: EvalKeyword[]; } + +export interface AddStudyReviewRequest { + studySpaceId: number; + targetMemberId: number; + satisfactionId: 10 | 20 | 30; + keywordIds: number[]; + content: string; +} diff --git a/src/features/study/model/use-review-query.ts b/src/features/study/model/use-review-query.ts index 2feac763..f261afe0 100644 --- a/src/features/study/model/use-review-query.ts +++ b/src/features/study/model/use-review-query.ts @@ -1,5 +1,5 @@ -import { useQuery } from '@tanstack/react-query'; -import { getPartnerStudyReview } from '../api/get-review'; +import { useMutation, useQuery, useSuspenseQuery } from '@tanstack/react-query'; +import { addStudyReview, getPartnerStudyReview } from '../api/get-review'; export const usePartnerStudyReviewQuery = () => { return useQuery({ @@ -7,3 +7,9 @@ export const usePartnerStudyReviewQuery = () => { queryFn: getPartnerStudyReview, }); }; + +export const useAddStudyReviewMutation = () => { + return useMutation({ + mutationFn: addStudyReview, + }); +}; From 5cb4e66316d9cc98f028b2a71414d6c57b553763 Mon Sep 17 00:00:00 2001 From: aken-you Date: Sat, 23 Aug 2025 15:52:09 +0900 Subject: [PATCH 12/34] =?UTF-8?q?feat:=20textarea=20onChange=20=ED=95=B8?= =?UTF-8?q?=EB=93=A4=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/ui/study-review-modal.tsx | 136 +++++++++++++++---- 1 file changed, 110 insertions(+), 26 deletions(-) diff --git a/src/features/study/ui/study-review-modal.tsx b/src/features/study/ui/study-review-modal.tsx index 56dda129..cd01a09e 100644 --- a/src/features/study/ui/study-review-modal.tsx +++ b/src/features/study/ui/study-review-modal.tsx @@ -9,18 +9,44 @@ import { TextAreaInput } from '@/shared/ui/input'; import ListItem from '@/shared/ui/list-item'; import { Modal } from '@/shared/ui/modal'; import { EvalKeyword, StudyEvaluationResponse } from '../api/types'; -import { usePartnerStudyReviewQuery } from '../model/use-review-query'; +import { + useAddStudyReviewMutation, + usePartnerStudyReviewQuery, +} from '../model/use-review-query'; -export default function StudyReviewModal() { - // 10 - "아쉬워요", 20 - "괜찮아요", 30 - "좋았어요" - const [satisfactionId, setSatisfactionId] = useState<10 | 20 | 30 | null>( - null, - ); +interface FormState { + studySpaceId: number; + targetMemberId: number; + satisfactionId: 10 | 20 | 30 | null; // 10 - "아쉬워요", 20 - "괜찮아요", 30 - "좋았어요" + keywordIds: number[]; + content: string; +} +export default function StudyReviewModal() { const { data } = usePartnerStudyReviewQuery(); + const { mutate: addStudyReview } = useAddStudyReviewMutation(); + + const [form, setForm] = useState({ + studySpaceId: data?.studySpaceId, + targetMemberId: data?.targetMembers[0].memberId, + satisfactionId: null, + keywordIds: [], + content: '', + }); if (!data) return null; + const handleSubmit = () => { + if ( + form.keywordIds.length === 0 || + form.satisfactionId === null || + form.content === '' + ) + return; + + addStudyReview(form); + }; + return ( @@ -67,38 +93,66 @@ export default function StudyReviewModal() {
    setSatisfactionId(10)} + onClick={() => { + setForm({ + ...form, + satisfactionId: 10, + keywordIds: [], + content: '', + }); + }} /> setSatisfactionId(20)} + onClick={() => { + setForm({ + ...form, + satisfactionId: 20, + keywordIds: [], + content: '', + }); + }} /> setSatisfactionId(30)} + onClick={() => { + setForm({ + ...form, + satisfactionId: 30, + keywordIds: [], + content: '', + }); + }} />
    - {satisfactionId === 10 && } + {form.satisfactionId === 10 && ( + + )} - {(satisfactionId === 20 || satisfactionId === 30) && ( - + {(form.satisfactionId === 20 || form.satisfactionId === 30) && ( + )} - @@ -167,31 +221,47 @@ function SatisfactionButton({ } function PositiveReview({ - satisfactionId, data, + form, + onChange, }: { - satisfactionId: 20 | 30; + form: FormState; data: StudyEvaluationResponse; + onChange: (form: FormState | ((prev: FormState) => FormState)) => void; }) { return ( <> - + onChange((prev) => ({ ...prev, content }))} + /> ); } -function NegativeReview({ data }: { data: StudyEvaluationResponse }) { +function NegativeReview({ + data, + form, + onChange, +}: { + data: StudyEvaluationResponse; + form: FormState; + onChange: (form: FormState | ((prev: FormState) => FormState)) => void; +}) { return ( <> - + onChange((prev) => ({ ...prev, content }))} + /> ); } @@ -222,7 +292,13 @@ function PositiveCheckboxList({ ); } -function PositiveTextArea() { +function PositiveTextArea({ + value, + onChange, +}: { + value: string; + onChange: (content: string) => void; +}) { return (
    @@ -238,9 +314,10 @@ function PositiveTextArea() {
    ); @@ -272,7 +349,13 @@ function NegativeCheckboxList({ ); } -function NegativeTextArea() { +function NegativeTextArea({ + value, + onChange, +}: { + value: string; + onChange: (content: string) => void; +}) { return (
    @@ -289,7 +372,8 @@ function NegativeTextArea() {
    From 0edb94b171b72446c4468a2074ac110be3b65bf3 Mon Sep 17 00:00:00 2001 From: aken-you Date: Sat, 23 Aug 2025 16:28:42 +0900 Subject: [PATCH 13/34] =?UTF-8?q?feat:=20checkbox=20onToggle=20=ED=95=B8?= =?UTF-8?q?=EB=93=A4=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/ui/study-review-modal.tsx | 50 ++++++++++++++++++-- src/shared/ui/checkbox/index.tsx | 42 ++++++++++++---- 2 files changed, 80 insertions(+), 12 deletions(-) diff --git a/src/features/study/ui/study-review-modal.tsx b/src/features/study/ui/study-review-modal.tsx index cd01a09e..0c2efbbc 100644 --- a/src/features/study/ui/study-review-modal.tsx +++ b/src/features/study/ui/study-review-modal.tsx @@ -237,6 +237,8 @@ function PositiveReview({ ? data.notBadEvalKeywords : data.satisfiedEvalKeywords } + keywordIds={form.keywordIds} + onChange={(keywordIds) => onChange((prev) => ({ ...prev, keywordIds }))} /> - + onChange((prev) => ({ ...prev, keywordIds }))} + /> onChange((prev) => ({ ...prev, content }))} @@ -268,9 +274,22 @@ function NegativeReview({ function PositiveCheckboxList({ positiveKeywords, + keywordIds, + onChange, }: { positiveKeywords: EvalKeyword[]; + keywordIds: FormState['keywordIds']; + onChange: (keywordIds: FormState['keywordIds']) => void; }) { + const handleToggle = (id: number) => { + const isChecked = keywordIds.includes(id); + const newKeywordIds = isChecked + ? keywordIds.filter((k) => k !== id) + : [...keywordIds, id]; + + onChange(newKeywordIds); + }; + return (
    @@ -283,7 +302,13 @@ function PositiveCheckboxList({
      {positiveKeywords.map(({ id, keyword }) => ( - + { + handleToggle(id); + }} + /> ))} @@ -325,9 +350,22 @@ function PositiveTextArea({ function NegativeCheckboxList({ negativeKeywords, + keywordIds, + onChange, }: { negativeKeywords: StudyEvaluationResponse['unsatisfiedEvalKeywords']; + keywordIds: FormState['keywordIds']; + onChange: (keywordIds: FormState['keywordIds']) => void; }) { + const handleToggle = (id: number) => { + const isChecked = keywordIds.includes(id); + const newKeywordIds = isChecked + ? keywordIds.filter((k) => k !== id) + : [...keywordIds, id]; + + onChange(newKeywordIds); + }; + return (
      @@ -340,7 +378,13 @@ function NegativeCheckboxList({
        {negativeKeywords.map(({ id, keyword }) => ( - + { + handleToggle(id); + }} + /> ))} diff --git a/src/shared/ui/checkbox/index.tsx b/src/shared/ui/checkbox/index.tsx index a4b4961b..15395e77 100644 --- a/src/shared/ui/checkbox/index.tsx +++ b/src/shared/ui/checkbox/index.tsx @@ -1,14 +1,38 @@ -import { cn } from '@/shared/shadcn/lib/utils'; +import Image from 'next/image'; -const Checkbox = ({ id }: { id: string }) => { +const Checkbox = ({ + id, + defaultChecked = false, + checked = false, + onToggle, +}: { + id: string; + defaultChecked?: boolean; + checked?: boolean; + onToggle: () => void; +}) => { return ( - + ); }; From 24cb4daa690a509b455731e8e915a4fbfeb4e79d Mon Sep 17 00:00:00 2001 From: aken-you Date: Sat, 23 Aug 2025 16:38:39 +0900 Subject: [PATCH 14/34] =?UTF-8?q?refactor:=20checkbox=20border=20=EA=B5=B5?= =?UTF-8?q?=EA=B8=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/shared/ui/checkbox/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/ui/checkbox/index.tsx b/src/shared/ui/checkbox/index.tsx index 15395e77..6652cf8c 100644 --- a/src/shared/ui/checkbox/index.tsx +++ b/src/shared/ui/checkbox/index.tsx @@ -22,7 +22,7 @@ const Checkbox = ({ : { defaultChecked, onChange: onToggle })} />
        Date: Sat, 23 Aug 2025 16:39:13 +0900 Subject: [PATCH 15/34] =?UTF-8?q?refactor:=20=ED=8F=BC=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=9D=84=20StudyReviewForm=EC=9C=BC=EB=A1=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/ui/study-review-modal.tsx | 216 ++++++++++--------- 1 file changed, 110 insertions(+), 106 deletions(-) diff --git a/src/features/study/ui/study-review-modal.tsx b/src/features/study/ui/study-review-modal.tsx index 0c2efbbc..6168c107 100644 --- a/src/features/study/ui/study-review-modal.tsx +++ b/src/features/study/ui/study-review-modal.tsx @@ -23,30 +23,6 @@ interface FormState { } export default function StudyReviewModal() { - const { data } = usePartnerStudyReviewQuery(); - const { mutate: addStudyReview } = useAddStudyReviewMutation(); - - const [form, setForm] = useState({ - studySpaceId: data?.studySpaceId, - targetMemberId: data?.targetMembers[0].memberId, - satisfactionId: null, - keywordIds: [], - content: '', - }); - - if (!data) return null; - - const handleSubmit = () => { - if ( - form.keywordIds.length === 0 || - form.satisfactionId === null || - form.content === '' - ) - return; - - addStudyReview(form); - }; - return ( @@ -70,98 +46,126 @@ export default function StudyReviewModal() { - -
        - 함께 스터디한 멤버에 대해 알려주세요 - -
        - - 같이 성장할 수 있는 스터디 문화를 만들기 위해 평가를 - 남겨주세요. - - 평가한 내용은 성실 온도에 반영됩니다. -
        -
        - - +
        + 함께 스터디한 멤버에 대해 알려주세요 -
        - - 스터디 만족도 +
        + + 같이 성장할 수 있는 스터디 문화를 만들기 위해 평가를 남겨주세요. - -
        - { - setForm({ - ...form, - satisfactionId: 10, - keywordIds: [], - content: '', - }); - }} - /> - - { - setForm({ - ...form, - satisfactionId: 20, - keywordIds: [], - content: '', - }); - }} - /> - - { - setForm({ - ...form, - satisfactionId: 30, - keywordIds: [], - content: '', - }); - }} - /> -
        + 평가한 내용은 성실 온도에 반영됩니다.
        +
        - {form.satisfactionId === 10 && ( - - )} - - {(form.satisfactionId === 20 || form.satisfactionId === 30) && ( - - )} - - - - - + ); } +function StudyReviewForm() { + const { data } = usePartnerStudyReviewQuery(); + const { mutate: addStudyReview } = useAddStudyReviewMutation(); + + const [form, setForm] = useState({ + studySpaceId: data?.studySpaceId, + targetMemberId: data?.targetMembers[0].memberId, + satisfactionId: null, + keywordIds: [], + content: '', + }); + + if (!data) return null; + + const handleSubmit = () => { + if ( + form.keywordIds.length === 0 || + form.satisfactionId === null || + form.content === '' + ) + return; + + addStudyReview(form); + }; + + return ( + <> + + + +
        + + 스터디 만족도 + + +
        + { + setForm({ + ...form, + satisfactionId: 10, + keywordIds: [], + content: '', + }); + }} + /> + + { + setForm({ + ...form, + satisfactionId: 20, + keywordIds: [], + content: '', + }); + }} + /> + + { + setForm({ + ...form, + satisfactionId: 30, + keywordIds: [], + content: '', + }); + }} + /> +
        +
        + + {form.satisfactionId === 10 && ( + + )} + + {(form.satisfactionId === 20 || form.satisfactionId === 30) && ( + + )} +
        + + + + + + + + ); +} + function PartnerInfo(data: StudyEvaluationResponse) { const partner = data.targetMembers[0]; From 557993dcf437d37aa7b6e0b927e59faa6ee0944d Mon Sep 17 00:00:00 2001 From: aken-you Date: Sat, 23 Aug 2025 16:40:22 +0900 Subject: [PATCH 16/34] =?UTF-8?q?refactor:=20=EB=93=B1=EB=A1=9D=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20disabled=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/ui/study-review-modal.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/features/study/ui/study-review-modal.tsx b/src/features/study/ui/study-review-modal.tsx index 6168c107..456dc9fe 100644 --- a/src/features/study/ui/study-review-modal.tsx +++ b/src/features/study/ui/study-review-modal.tsx @@ -158,7 +158,16 @@ function StudyReviewForm() { 취소 - From 3e63ea015e5689373fe36823f1d5b0568bc107b1 Mon Sep 17 00:00:00 2001 From: aken-you Date: Sat, 23 Aug 2025 17:23:19 +0900 Subject: [PATCH 17/34] =?UTF-8?q?feat:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=ED=9B=84=EA=B8=B0=20=EC=B6=94=EA=B0=80=EB=90=98=EB=A9=B4,=20?= =?UTF-8?q?=EC=95=88=EB=82=B4=20=EB=A9=94=EC=84=B8=EC=A7=80=20=EC=A0=9C?= =?UTF-8?q?=EA=B3=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/model/use-review-query.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/features/study/model/use-review-query.ts b/src/features/study/model/use-review-query.ts index f261afe0..f07a7ba0 100644 --- a/src/features/study/model/use-review-query.ts +++ b/src/features/study/model/use-review-query.ts @@ -1,4 +1,4 @@ -import { useMutation, useQuery, useSuspenseQuery } from '@tanstack/react-query'; +import { useMutation, useQuery } from '@tanstack/react-query'; import { addStudyReview, getPartnerStudyReview } from '../api/get-review'; export const usePartnerStudyReviewQuery = () => { @@ -11,5 +11,9 @@ export const usePartnerStudyReviewQuery = () => { export const useAddStudyReviewMutation = () => { return useMutation({ mutationFn: addStudyReview, + onSuccess: () => { + // todo: 모달로 변경 + alert('후기 작성이 완료되었습니다.'); + }, }); }; From d3f0f098f4bdcd4f6ab5e414a35127564fc26d7f Mon Sep 17 00:00:00 2001 From: aken-you Date: Sat, 23 Aug 2025 17:25:42 +0900 Subject: [PATCH 18/34] =?UTF-8?q?refactor:=20useSuspenseQuery=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=ED=95=98=EC=97=AC=20=ED=8C=8C=ED=8A=B8?= =?UTF-8?q?=EB=84=88=20=EC=8A=A4=ED=84=B0=EB=94=94=20=ED=9B=84=EA=B8=B0=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/model/use-review-query.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/features/study/model/use-review-query.ts b/src/features/study/model/use-review-query.ts index f07a7ba0..15bfe304 100644 --- a/src/features/study/model/use-review-query.ts +++ b/src/features/study/model/use-review-query.ts @@ -1,8 +1,8 @@ -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation, useSuspenseQuery } from '@tanstack/react-query'; import { addStudyReview, getPartnerStudyReview } from '../api/get-review'; export const usePartnerStudyReviewQuery = () => { - return useQuery({ + return useSuspenseQuery({ queryKey: ['partnerStudyReview'], queryFn: getPartnerStudyReview, }); From da67164a706dd7bb4736ac31e2afc4837afff254 Mon Sep 17 00:00:00 2001 From: aken-you Date: Sat, 23 Aug 2025 17:26:50 +0900 Subject: [PATCH 19/34] =?UTF-8?q?refactor:=20=EB=93=B1=EB=A1=9D=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20disabled=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/ui/study-review-modal.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/features/study/ui/study-review-modal.tsx b/src/features/study/ui/study-review-modal.tsx index 456dc9fe..e2dbd8db 100644 --- a/src/features/study/ui/study-review-modal.tsx +++ b/src/features/study/ui/study-review-modal.tsx @@ -162,9 +162,7 @@ function StudyReviewForm() { color="primary" size="large" disabled={ - form.keywordIds.length === 0 || - form.satisfactionId === null || - form.content === '' + form.keywordIds.length === 0 || form.satisfactionId === null } onClick={handleSubmit} > From b5e426aa3c6b54aa6f1b93a8d8501edb9190beab Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 17:34:18 +0900 Subject: [PATCH 20/34] =?UTF-8?q?feat:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=ED=8E=98=EC=9D=B4=EC=A7=80=20view=20?= =?UTF-8?q?=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(my)/my-study-review/page.tsx | 155 ++++++++++++++++++++++++++++++ src/widgets/my-page/sidebar.tsx | 6 ++ 2 files changed, 161 insertions(+) create mode 100644 app/(my)/my-study-review/page.tsx diff --git a/app/(my)/my-study-review/page.tsx b/app/(my)/my-study-review/page.tsx new file mode 100644 index 00000000..690839e4 --- /dev/null +++ b/app/(my)/my-study-review/page.tsx @@ -0,0 +1,155 @@ +'use client'; + +import Image from 'next/image'; +import { useState } from 'react'; + +export default function MyStudyReview() { + return ( + <> +
        +
        +
        +
        받은 평가
        +
        11
        +
        + + + 개선이 필요한 점은 나에게만 보여요 + +
        + +
        +
        +
        +

        좋았던 점

        + + +
        + +
          + + + + + +
        +
        + +
        +
        +

        + 개선이 필요한 점 +

        + + +
        + +
          + + + + + +
        +
        +
        +
        + +
        +
        +
        후기
        +
        11
        +
        + + + 모든 후기는 나에게만 보여요 + + +
          + + + + + +
        +
        + + ); +} + +function KeywordReview({ + type, + count, +}: { + type: 'positive' | 'negative'; + count: number; +}) { + return ( +
      • + + {type === 'positive' ? '“좋았어요, 괜찮았어요”' : '“아쉬웠어요”'} 평가 + 키워드 + + {count} +
      • + ); +} + +function Review() { + const [expanded, setExpanded] = useState(false); + + return ( +
      • +
        + 프로필 이미지 + +
        + + 김코드 + + · + 1시간 전 +
        +
        + +
        +

        + 스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 + 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 + 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 + 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 + 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 + 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~ +

        + +
        + +
        +
        + 스터디 기간 + YYYY.MM.DD ~ YYYY.MM.DD +
        +
        + 스터디 주제 + Back-end Deep Dive +
        +
        +
      • + ); +} diff --git a/src/widgets/my-page/sidebar.tsx b/src/widgets/my-page/sidebar.tsx index 2e9d9cb1..646aa66c 100644 --- a/src/widgets/my-page/sidebar.tsx +++ b/src/widgets/my-page/sidebar.tsx @@ -49,6 +49,12 @@ export default function Sidebar() { > 마이스터디 + router.push('/my-study-review')} + isActive={pathname === '/my-study-review'} + > + 스터디 리뷰 + {}} isActive={false}> 계정설정 From b1be3858c190ebe21aff99be83d3601198405ce6 Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 17:34:41 +0900 Subject: [PATCH 21/34] =?UTF-8?q?refactor:=20user=20profile=20modal?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20=EC=9E=85=EB=A0=A5=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EC=95=98=EC=9D=84=20=EA=B2=BD=EC=9A=B0,=20=EB=B9=88?= =?UTF-8?q?=20=EB=AC=B8=EC=9E=90=EC=97=B4=EB=A1=9C=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my-page/ui/user-profile-modal.tsx | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/features/my-page/ui/user-profile-modal.tsx b/src/features/my-page/ui/user-profile-modal.tsx index 0cd0f824..324cd56a 100644 --- a/src/features/my-page/ui/user-profile-modal.tsx +++ b/src/features/my-page/ui/user-profile-modal.tsx @@ -71,25 +71,22 @@ export default function UserProfileModal({
        - {profile.memberProfile.birthDate ?? - '생일을 입력해주세요!'} + {profile.memberProfile.birthDate ?? ''}
        - {profile.memberProfile.tel ?? '번호를 입력해주세요!'} + {profile.memberProfile.tel ?? ''}
        - {profile.memberProfile.githubLink?.url ?? - '깃허브 링크를 입력해주세요!'} + {profile.memberProfile.githubLink?.url ?? ''}
        - {profile.memberProfile.blogOrSnsLink?.url ?? - '블로그 링크를 입력해주세요!'} + {profile.memberProfile.blogOrSnsLink?.url ?? ''}
        @@ -122,6 +119,20 @@ export default function UserProfileModal({ content={profile.memberInfo.studyPlan} />
        + +
        + +
        + + 받은 평가 + + +
        + n명의 유저들이 이런 점이 좋다고 했어요. + +
          +
        +
        From b63525ff35526360be609e0042834e1feb1a949e Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 18:52:44 +0900 Subject: [PATCH 22/34] =?UTF-8?q?style:=20=EA=B3=84=EC=A0=95=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=A3=BC=EC=84=9D=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 구현되어있지 않으므로 주석처리 --- src/widgets/my-page/sidebar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widgets/my-page/sidebar.tsx b/src/widgets/my-page/sidebar.tsx index 646aa66c..af28bc7a 100644 --- a/src/widgets/my-page/sidebar.tsx +++ b/src/widgets/my-page/sidebar.tsx @@ -55,9 +55,9 @@ export default function Sidebar() { > 스터디 리뷰 - {}} isActive={false}> + {/* {}} isActive={false}> 계정설정 - + */}
        로그아웃 From ed2e15a05f30e6718c235224c694c137dfa506db Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 20:31:09 +0900 Subject: [PATCH 23/34] =?UTF-8?q?feat:=20=EA=B8=8D=EC=A0=95=EC=A0=81=20?= =?UTF-8?q?=ED=8F=89=EA=B0=80=20=ED=82=A4=EC=9B=8C=EB=93=9C=20api=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=ED=9B=85=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(my)/my-study-review/page.tsx | 29 +++++++++++++++----- src/features/study/api/get-review.ts | 28 ++++++++++++++++++- src/features/study/api/types.ts | 17 ++++++++++++ src/features/study/model/use-review-query.ts | 25 +++++++++++++++-- 4 files changed, 89 insertions(+), 10 deletions(-) diff --git a/app/(my)/my-study-review/page.tsx b/app/(my)/my-study-review/page.tsx index 690839e4..d6c29eaf 100644 --- a/app/(my)/my-study-review/page.tsx +++ b/app/(my)/my-study-review/page.tsx @@ -2,8 +2,15 @@ import Image from 'next/image'; import { useState } from 'react'; +import { useUserPositiveKeywordsQuery } from '@/features/study/model/use-review-query'; export default function MyStudyReview() { + const { data: positiveKeywordsData } = useUserPositiveKeywordsQuery({ + pageSize: 5, + }); + + const positiveKeywords = positiveKeywordsData?.keywords || []; + return ( <>
        @@ -19,7 +26,7 @@ export default function MyStudyReview() {
        -
        +

        좋았던 점

        @@ -29,15 +36,23 @@ export default function MyStudyReview() {
          - - - - - + {positiveKeywords.length > 0 ? ( + positiveKeywords.map((keyword) => ( + + )) + ) : ( + + 아직 받은 평가가 없습니다. + + )}
        -
        +

        개선이 필요한 점 diff --git a/src/features/study/api/get-review.ts b/src/features/study/api/get-review.ts index 6cd2642d..1f1018f9 100644 --- a/src/features/study/api/get-review.ts +++ b/src/features/study/api/get-review.ts @@ -1,5 +1,10 @@ import { axiosInstance } from '@/shared/tanstack-query/axios'; -import { AddStudyReviewRequest, StudyEvaluationResponse } from './types'; +import type { + AddStudyReviewRequest, + UserPositiveKeywordsResponse, + UserPositiveKeywordsRequest, + StudyEvaluationResponse, +} from './types'; export const getPartnerStudyReview = async (): Promise => { @@ -15,3 +20,24 @@ export const addStudyReview = async (data: AddStudyReviewRequest) => { return res.data.content; }; + +export const getUserPositiveKeywords = async ({ + memberId, + pageSize, +}: UserPositiveKeywordsRequest): Promise => { + const params: Record = {}; + + if (memberId) { + params['member-id'] = memberId; + } + if (pageSize) { + params['page-size'] = pageSize; + } + + const res = await axiosInstance.get( + '/study/reviews/members/keywords/positive', + { params }, + ); + + return res.data.content; +}; diff --git a/src/features/study/api/types.ts b/src/features/study/api/types.ts index 263bd30b..b080eae7 100644 --- a/src/features/study/api/types.ts +++ b/src/features/study/api/types.ts @@ -126,3 +126,20 @@ export interface AddStudyReviewRequest { keywordIds: number[]; content: string; } + +interface Keyword { + id: number; + content: string; + count: number; +} + +export interface UserPositiveKeywordsRequest { + memberId?: number; + pageSize?: number; +} + +export interface UserPositiveKeywordsResponse { + totalCount: number; + reviewerCount: number; + keywords: Keyword[]; +} diff --git a/src/features/study/model/use-review-query.ts b/src/features/study/model/use-review-query.ts index 15bfe304..64bc37a6 100644 --- a/src/features/study/model/use-review-query.ts +++ b/src/features/study/model/use-review-query.ts @@ -1,5 +1,10 @@ -import { useMutation, useSuspenseQuery } from '@tanstack/react-query'; -import { addStudyReview, getPartnerStudyReview } from '../api/get-review'; +import { useMutation, useQuery, useSuspenseQuery } from '@tanstack/react-query'; +import { + addStudyReview, + getUserPositiveKeywords, + getPartnerStudyReview, +} from '../api/get-review'; +import { UserPositiveKeywordsRequest } from '../api/types'; export const usePartnerStudyReviewQuery = () => { return useSuspenseQuery({ @@ -17,3 +22,19 @@ export const useAddStudyReviewMutation = () => { }, }); }; + +export const useUserPositiveKeywordsQuery = ( + params: UserPositiveKeywordsRequest, +) => { + return useQuery({ + queryKey: ['myPositiveKeywords', params], + queryFn: ({ queryKey }) => { + const [, requestParams] = queryKey as [ + string, + UserPositiveKeywordsRequest, + ]; + + return getUserPositiveKeywords(requestParams); + }, + }); +}; From fb2d5dba3a9a9c9f1f542036e6f810d307da51fa Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 20:37:24 +0900 Subject: [PATCH 24/34] =?UTF-8?q?feat:=20=EB=B6=80=EC=A0=95=EC=A0=81=20?= =?UTF-8?q?=ED=8F=89=EA=B0=80=20=ED=82=A4=EC=9B=8C=EB=93=9C=20api=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=ED=9B=85=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(my)/my-study-review/page.tsx | 34 ++++++++++++++++---- src/features/study/api/get-review.ts | 19 +++++++++++ src/features/study/api/types.ts | 10 ++++++ src/features/study/model/use-review-query.ts | 15 ++++++++- 4 files changed, 71 insertions(+), 7 deletions(-) diff --git a/app/(my)/my-study-review/page.tsx b/app/(my)/my-study-review/page.tsx index d6c29eaf..cabf8a3f 100644 --- a/app/(my)/my-study-review/page.tsx +++ b/app/(my)/my-study-review/page.tsx @@ -2,14 +2,21 @@ import Image from 'next/image'; import { useState } from 'react'; -import { useUserPositiveKeywordsQuery } from '@/features/study/model/use-review-query'; +import { + useMyNegativeKeywordsQuery, + useUserPositiveKeywordsQuery, +} from '@/features/study/model/use-review-query'; export default function MyStudyReview() { const { data: positiveKeywordsData } = useUserPositiveKeywordsQuery({ pageSize: 5, }); + const { data: negativeKeywordsData } = useMyNegativeKeywordsQuery({ + pageSize: 5, + }); const positiveKeywords = positiveKeywordsData?.keywords || []; + const negativeKeywords = negativeKeywordsData?.keywords || []; return ( <> @@ -64,16 +71,31 @@ export default function MyStudyReview() {

          - - - - - + {negativeKeywords.length > 0 ? ( + negativeKeywords.map((keyword) => ( + + )) + ) : ( + + 아직 받은 평가가 없습니다. + + )}
        +
        +
        +
        후기
        +
        11
        +
        +
        +
        후기
        diff --git a/src/features/study/api/get-review.ts b/src/features/study/api/get-review.ts index 1f1018f9..b9ff651e 100644 --- a/src/features/study/api/get-review.ts +++ b/src/features/study/api/get-review.ts @@ -4,6 +4,8 @@ import type { UserPositiveKeywordsResponse, UserPositiveKeywordsRequest, StudyEvaluationResponse, + MyNegativeKeywordsRequest, + MyNegativeKeywordsResponse, } from './types'; export const getPartnerStudyReview = @@ -41,3 +43,20 @@ export const getUserPositiveKeywords = async ({ return res.data.content; }; + +export const getMyNegativeKeywords = async ({ + pageSize, +}: MyNegativeKeywordsRequest): Promise => { + const params: Record = {}; + + if (pageSize) { + params['page-size'] = pageSize; + } + + const res = await axiosInstance.get( + '/study/reviews/members/keywords/negative', + { params }, + ); + + return res.data.content; +}; diff --git a/src/features/study/api/types.ts b/src/features/study/api/types.ts index b080eae7..92323514 100644 --- a/src/features/study/api/types.ts +++ b/src/features/study/api/types.ts @@ -143,3 +143,13 @@ export interface UserPositiveKeywordsResponse { reviewerCount: number; keywords: Keyword[]; } + +export interface MyNegativeKeywordsRequest { + pageSize?: number; +} + +export interface MyNegativeKeywordsResponse { + totalCount: number; + reviewerCount: number; + keywords: Keyword[]; +} diff --git a/src/features/study/model/use-review-query.ts b/src/features/study/model/use-review-query.ts index 64bc37a6..9e7fc81f 100644 --- a/src/features/study/model/use-review-query.ts +++ b/src/features/study/model/use-review-query.ts @@ -3,8 +3,12 @@ import { addStudyReview, getUserPositiveKeywords, getPartnerStudyReview, + getMyNegativeKeywords, } from '../api/get-review'; -import { UserPositiveKeywordsRequest } from '../api/types'; +import { + MyNegativeKeywordsRequest, + UserPositiveKeywordsRequest, +} from '../api/types'; export const usePartnerStudyReviewQuery = () => { return useSuspenseQuery({ @@ -38,3 +42,12 @@ export const useUserPositiveKeywordsQuery = ( }, }); }; + +export const useMyNegativeKeywordsQuery = ( + params: MyNegativeKeywordsRequest, +) => { + return useQuery({ + queryKey: ['myNegativeKeywords', params], + queryFn: () => getMyNegativeKeywords(params), + }); +}; From 64b77888b48ddce8f59ab3f3a5b58d574f8f46c1 Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 20:38:04 +0900 Subject: [PATCH 25/34] =?UTF-8?q?refactor:=20=EA=B8=8D=EC=A0=95=EC=A0=81?= =?UTF-8?q?=20=ED=82=A4=EC=9B=8C=EB=93=9C=20=EB=AA=A9=EB=A1=9D=EC=9D=98=20?= =?UTF-8?q?queryKey=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/model/use-review-query.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/study/model/use-review-query.ts b/src/features/study/model/use-review-query.ts index 9e7fc81f..335ad1d6 100644 --- a/src/features/study/model/use-review-query.ts +++ b/src/features/study/model/use-review-query.ts @@ -31,7 +31,7 @@ export const useUserPositiveKeywordsQuery = ( params: UserPositiveKeywordsRequest, ) => { return useQuery({ - queryKey: ['myPositiveKeywords', params], + queryKey: ['userPositiveKeywords', params], queryFn: ({ queryKey }) => { const [, requestParams] = queryKey as [ string, From e778671aa160896f883c786152b5c453107770b5 Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 20:44:39 +0900 Subject: [PATCH 26/34] =?UTF-8?q?refactor:=20=ED=82=A4=EC=9B=8C=EB=93=9C?= =?UTF-8?q?=20response=20=ED=83=80=EC=9E=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/features/study/api/types.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/features/study/api/types.ts b/src/features/study/api/types.ts index 92323514..5356ce4f 100644 --- a/src/features/study/api/types.ts +++ b/src/features/study/api/types.ts @@ -139,8 +139,8 @@ export interface UserPositiveKeywordsRequest { } export interface UserPositiveKeywordsResponse { - totalCount: number; - reviewerCount: number; + totalCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null + reviewerCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null keywords: Keyword[]; } @@ -149,7 +149,7 @@ export interface MyNegativeKeywordsRequest { } export interface MyNegativeKeywordsResponse { - totalCount: number; - reviewerCount: number; + totalCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null + reviewerCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null keywords: Keyword[]; } From f37d4e4e52b6d14c570f3db10abb37dd0bcc9eb6 Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 22:42:38 +0900 Subject: [PATCH 27/34] =?UTF-8?q?feat:=20=EC=8A=A4=ED=84=B0=EB=94=94=20?= =?UTF-8?q?=ED=9B=84=EA=B8=B0=20=EC=A1=B0=ED=9A=8C=20api=20=EC=BB=A4?= =?UTF-8?q?=EC=8A=A4=ED=85=80=20=ED=9B=85=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(my)/my-study-review/page.tsx | 80 +++++++++++++------- public/icons/arrow-down.svg | 3 + src/features/study/api/get-review.ts | 19 +++++ src/features/study/api/types.ts | 30 ++++++++ src/features/study/model/use-review-query.ts | 35 ++++++++- 5 files changed, 140 insertions(+), 27 deletions(-) create mode 100644 public/icons/arrow-down.svg diff --git a/app/(my)/my-study-review/page.tsx b/app/(my)/my-study-review/page.tsx index cabf8a3f..cc7af405 100644 --- a/app/(my)/my-study-review/page.tsx +++ b/app/(my)/my-study-review/page.tsx @@ -1,11 +1,15 @@ 'use client'; +import { formatDistanceToNow } from 'date-fns'; import Image from 'next/image'; import { useState } from 'react'; +import { MyReviewItem } from '@/features/study/api/types'; import { useMyNegativeKeywordsQuery, + useMyReviewsInfinityQuery, useUserPositiveKeywordsQuery, } from '@/features/study/model/use-review-query'; +import { getKoreaDate } from '@/shared/lib/time'; export default function MyStudyReview() { const { data: positiveKeywordsData } = useUserPositiveKeywordsQuery({ @@ -14,10 +18,17 @@ export default function MyStudyReview() { const { data: negativeKeywordsData } = useMyNegativeKeywordsQuery({ pageSize: 5, }); + const { + data: myReviewsData, + fetchNextPage, + hasNextPage, + } = useMyReviewsInfinityQuery(); const positiveKeywords = positiveKeywordsData?.keywords || []; const negativeKeywords = negativeKeywordsData?.keywords || []; + const myReviews = myReviewsData?.reviews || []; + return ( <>
        @@ -92,14 +103,9 @@ export default function MyStudyReview() {
        후기
        -
        11
        -
        -
        - -
        -
        -
        후기
        -
        11
        +
        + {myReviewsData?.totalCount || 0} +
        @@ -107,11 +113,29 @@ export default function MyStudyReview() {
          - - - - - + {myReviews.length > 0 ? ( + myReviews.map((review) => ) + ) : ( +
          + 아직까지 받은 후기가 없습니다. +
          + )} + + {hasNextPage && ( + + )}
        @@ -136,25 +160,29 @@ function KeywordReview({ ); } -function Review() { +function Review({ data }: { data: MyReviewItem }) { const [expanded, setExpanded] = useState(false); return (
      • 프로필 이미지
        - 김코드 + {data.writer.memberName} · - 1시간 전 + + {formatDistanceToNow(getKoreaDate(new Date(data.reviewedAt)), { + addSuffix: true, + })} +
        @@ -162,12 +190,7 @@ function Review() {

        - 스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 - 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 - 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 - 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 - 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 - 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~스터디에서 좋았어요~ + {data.content}

      • diff --git a/public/icons/arrow-down.svg b/public/icons/arrow-down.svg new file mode 100644 index 00000000..10f6a659 --- /dev/null +++ b/public/icons/arrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/features/study/api/get-review.ts b/src/features/study/api/get-review.ts index b9ff651e..e188d28d 100644 --- a/src/features/study/api/get-review.ts +++ b/src/features/study/api/get-review.ts @@ -6,6 +6,8 @@ import type { StudyEvaluationResponse, MyNegativeKeywordsRequest, MyNegativeKeywordsResponse, + MyReviewsResponse, + MyReviewsRequest, } from './types'; export const getPartnerStudyReview = @@ -60,3 +62,20 @@ export const getMyNegativeKeywords = async ({ return res.data.content; }; + +export const getMyReviews = async ({ + cursor, +}: MyReviewsRequest): Promise => { + const params: Record = { + 'page-size': 10, + }; + + // cursor 전송하지 않는 경우 첫 데이터부터 조회 + if (cursor) { + params.cursor = cursor; + } + + const res = await axiosInstance.get('/study/reviews/members', { params }); + + return res.data.content; +}; diff --git a/src/features/study/api/types.ts b/src/features/study/api/types.ts index 5356ce4f..77cfa766 100644 --- a/src/features/study/api/types.ts +++ b/src/features/study/api/types.ts @@ -153,3 +153,33 @@ export interface MyNegativeKeywordsResponse { reviewerCount: number | null; // params에 pageSize 값을 보내지 않는 경우 null keywords: Keyword[]; } + +export interface MyReviewWriter { + memberId: number; + memberName: string; + profileImageUrl: string; +} + +export interface MyReviewItem { + id: number; + writer: MyReviewWriter; + reviewedAt: string; // ISO 날짜 문자열 + content: string; + studySpaceId: number; + startDate: string; // YYYY-MM-DD + endDate: string; // YYYY-MM-DD + studySubjects: string[]; +} + +export interface MyReviewsRequest { + cursor: number | null; +} + +export interface MyReviewsResponse { + totalCount: number; + reviews: { + items: MyReviewItem[]; + nextCursor: number; + hasNext: boolean; + }; +} diff --git a/src/features/study/model/use-review-query.ts b/src/features/study/model/use-review-query.ts index 335ad1d6..40e17990 100644 --- a/src/features/study/model/use-review-query.ts +++ b/src/features/study/model/use-review-query.ts @@ -1,9 +1,15 @@ -import { useMutation, useQuery, useSuspenseQuery } from '@tanstack/react-query'; +import { + useInfiniteQuery, + useMutation, + useQuery, + useSuspenseQuery, +} from '@tanstack/react-query'; import { addStudyReview, getUserPositiveKeywords, getPartnerStudyReview, getMyNegativeKeywords, + getMyReviews, } from '../api/get-review'; import { MyNegativeKeywordsRequest, @@ -51,3 +57,30 @@ export const useMyNegativeKeywordsQuery = ( queryFn: () => getMyNegativeKeywords(params), }); }; + +export const useMyReviewsInfinityQuery = () => { + return useInfiniteQuery({ + queryKey: ['myReviews'], + queryFn: ({ pageParam = null }) => getMyReviews({ cursor: pageParam }), + initialPageParam: null, + getNextPageParam: (lastPage) => { + if (lastPage.reviews.hasNext) { + return lastPage.reviews.nextCursor; + } + + return undefined; + }, + select: (data) => { + const allReviews = data.pages.flatMap((page) => page.reviews.items); + const lastPage = data.pages[data.pages.length - 1]; + const totalCount = data.pages[0].totalCount; + const hasNext = lastPage.reviews.hasNext; + + return { + reviews: allReviews, + totalCount, + hasNext, + }; + }, + }); +}; From 3ae3a8b433b9cac35c32c0436d77629135ff7ced Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 22:51:22 +0900 Subject: [PATCH 28/34] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20border?= =?UTF-8?q?=EC=99=80=20image=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(my)/my-study-review/page.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/(my)/my-study-review/page.tsx b/app/(my)/my-study-review/page.tsx index cc7af405..e84d0ebe 100644 --- a/app/(my)/my-study-review/page.tsx +++ b/app/(my)/my-study-review/page.tsx @@ -164,13 +164,14 @@ function Review({ data }: { data: MyReviewItem }) { const [expanded, setExpanded] = useState(false); return ( -
      • +
      • {`${data.writer.memberName}
        From b0eedf68341688e297f6d38f29864d6242c8ebc5 Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 23:09:44 +0900 Subject: [PATCH 29/34] =?UTF-8?q?refactor:=20=ED=95=9C=EA=B5=AD=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=ED=8F=AC=EB=A7=B7=ED=8C=85=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(my)/my-study-review/page.tsx | 23 ++++++++++--------- src/shared/lib/time.ts | 37 +++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 src/shared/lib/time.ts diff --git a/app/(my)/my-study-review/page.tsx b/app/(my)/my-study-review/page.tsx index e84d0ebe..2e98910d 100644 --- a/app/(my)/my-study-review/page.tsx +++ b/app/(my)/my-study-review/page.tsx @@ -1,6 +1,5 @@ 'use client'; -import { formatDistanceToNow } from 'date-fns'; import Image from 'next/image'; import { useState } from 'react'; import { MyReviewItem } from '@/features/study/api/types'; @@ -9,7 +8,7 @@ import { useMyReviewsInfinityQuery, useUserPositiveKeywordsQuery, } from '@/features/study/model/use-review-query'; -import { getKoreaDate } from '@/shared/lib/time'; +import { formatKoreaRelativeTime } from '@/shared/lib/time'; export default function MyStudyReview() { const { data: positiveKeywordsData } = useUserPositiveKeywordsQuery({ @@ -48,9 +47,11 @@ export default function MyStudyReview() {

        좋았던 점

        - + {positiveKeywords.length > 5 && ( + + )}
          @@ -76,9 +77,11 @@ export default function MyStudyReview() { 개선이 필요한 점 - + {negativeKeywords.length > 5 && ( + + )}
          @@ -180,9 +183,7 @@ function Review({ data }: { data: MyReviewItem }) { · - {formatDistanceToNow(getKoreaDate(new Date(data.reviewedAt)), { - addSuffix: true, - })} + {formatKoreaRelativeTime(data.reviewedAt)}
      • diff --git a/src/shared/lib/time.ts b/src/shared/lib/time.ts new file mode 100644 index 00000000..a4b6bc96 --- /dev/null +++ b/src/shared/lib/time.ts @@ -0,0 +1,37 @@ +import { + differenceInDays, + differenceInHours, + differenceInMinutes, + parseISO, +} from 'date-fns'; +import { format } from 'path'; + +export const getKoreaDate = (targetDate?: Date) => { + const date = targetDate || new Date(); + const utc = date.getTime() + date.getTimezoneOffset() * 60 * 1000; // 1970년 1월 1일로부터 현재까지 지난 시간 (밀리초) + + const koreaTimeDiff = 9 * 60 * 60 * 1000; // 한국은 UTC보다 9시간 빠름 + + const koreaNow = new Date(utc + koreaTimeDiff); + + return koreaNow; +}; + +export const formatKoreaRelativeTime = (targetDateStr: string): string => { + const targetDate = parseISO(targetDateStr); + const koreaTarget = getKoreaDate(targetDate); // 한국 시간 변환 + const koreaNow = getKoreaDate(); + + const minutes = differenceInMinutes(koreaNow, koreaTarget); + + if (minutes < 1) return '지금'; // 1분 미만이면 "지금" + if (minutes < 60) return `${minutes}분 전`; // 60분 미만이면 "n분 전" + + const hours = differenceInHours(koreaNow, koreaTarget); + if (hours < 24) return `${hours}시간 전`; // 24시간 미만이면 "n시간 전" + + const days = differenceInDays(koreaNow, koreaTarget); + if (days < 30) return `${days}일 전`; // 30일 미만이면 "n일 전" + + return targetDateStr; +}; From addf3495a292720784cae4015d96913bfc26db08 Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 23:14:00 +0900 Subject: [PATCH 30/34] =?UTF-8?q?refactor:=20ProfileInfoCard=20=EB=A0=88?= =?UTF-8?q?=EC=9D=B4=EC=96=B4=20widgets=20->=20entities=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my-profile/ui/profile-info-card.tsx} | 2 +- src/features/my-page/ui/profile-info.tsx | 2 +- src/features/my-page/ui/user-profile-modal.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/{widgets/my-page/profileinfo-card.tsx => entities/my-profile/ui/profile-info-card.tsx} (82%) diff --git a/src/widgets/my-page/profileinfo-card.tsx b/src/entities/my-profile/ui/profile-info-card.tsx similarity index 82% rename from src/widgets/my-page/profileinfo-card.tsx rename to src/entities/my-profile/ui/profile-info-card.tsx index fccee5b8..4e5e1db9 100644 --- a/src/widgets/my-page/profileinfo-card.tsx +++ b/src/entities/my-profile/ui/profile-info-card.tsx @@ -6,7 +6,7 @@ interface Props { export default function ProfileInfoCard({ title, content }: Props) { return (
        -
        +
        {title}
        diff --git a/src/features/my-page/ui/profile-info.tsx b/src/features/my-page/ui/profile-info.tsx index 93e87afe..37c918ec 100644 --- a/src/features/my-page/ui/profile-info.tsx +++ b/src/features/my-page/ui/profile-info.tsx @@ -1,8 +1,8 @@ 'use client'; +import ProfileInfoCard from '@/entities/my-profile/ui/profile-info-card'; import { MemberInfo } from '@/entities/user/api/types'; import ProfileInfoEditModal from '@/features/my-page/ui/profile-info-edit-modal'; -import ProfileInfoCard from '@/widgets/my-page/profileinfo-card'; interface ProfileInfoProps { memberId: number; diff --git a/src/features/my-page/ui/user-profile-modal.tsx b/src/features/my-page/ui/user-profile-modal.tsx index 324cd56a..54acff84 100644 --- a/src/features/my-page/ui/user-profile-modal.tsx +++ b/src/features/my-page/ui/user-profile-modal.tsx @@ -1,6 +1,7 @@ 'use client'; import { XIcon } from 'lucide-react'; +import ProfileInfoCard from '@/entities/my-profile/ui/profile-info-card'; import { useUserProfileQuery } from '@/entities/user/model/use-user-profile-query'; import CakeIcon from '@/features/my-page/ui/icon/cake.svg'; import GithubIcon from '@/features/my-page/ui/icon/github-logo.svg'; @@ -9,7 +10,6 @@ import PhoneIcon from '@/features/my-page/ui/icon/phone.svg'; import UserAvatar from '@/shared/ui/avatar'; import Badge from '@/shared/ui/badge'; import { Modal } from '@/shared/ui/modal'; -import ProfileInfoCard from '@/widgets/my-page/profileinfo-card'; interface UserProfileModalProps { memberId: number; From 1bd76b517d675447e920ce955aa50ab1014bb19f Mon Sep 17 00:00:00 2001 From: aken-you Date: Sun, 24 Aug 2025 23:15:29 +0900 Subject: [PATCH 31/34] =?UTF-8?q?feat:=20=EC=B4=9D=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=9B=EC=9D=80=20=EC=88=98=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(my)/my-study-review/page.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/(my)/my-study-review/page.tsx b/app/(my)/my-study-review/page.tsx index 2e98910d..e6ba6a5a 100644 --- a/app/(my)/my-study-review/page.tsx +++ b/app/(my)/my-study-review/page.tsx @@ -26,6 +26,11 @@ export default function MyStudyReview() { const positiveKeywords = positiveKeywordsData?.keywords || []; const negativeKeywords = negativeKeywordsData?.keywords || []; + const positiveKeywordsCount = positiveKeywordsData?.totalCount || 0; + const negativeKeywordsCount = negativeKeywordsData?.totalCount || 0; + + const totalKeywordsCount = positiveKeywordsCount + negativeKeywordsCount; + const myReviews = myReviewsData?.reviews || []; return ( @@ -34,7 +39,9 @@ export default function MyStudyReview() {
        받은 평가
        -
        11
        +
        + {totalKeywordsCount} +
        From 59cecbe33c0f886b16c68dbea360603fb5de2a8b Mon Sep 17 00:00:00 2001 From: aken-you Date: Mon, 25 Aug 2025 00:52:13 +0900 Subject: [PATCH 32/34] =?UTF-8?q?refactor:=20KeywordReview=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20entities=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(my)/my-study-review/page.tsx | 23 +++---------------- src/entities/my-profile/ui/keyword-review.tsx | 14 +++++++++++ 2 files changed, 17 insertions(+), 20 deletions(-) create mode 100644 src/entities/my-profile/ui/keyword-review.tsx diff --git a/app/(my)/my-study-review/page.tsx b/app/(my)/my-study-review/page.tsx index e6ba6a5a..0bcffa95 100644 --- a/app/(my)/my-study-review/page.tsx +++ b/app/(my)/my-study-review/page.tsx @@ -2,6 +2,7 @@ import Image from 'next/image'; import { useState } from 'react'; +import KeywordReview from '@/entities/my-profile/ui/keyword-review'; import { MyReviewItem } from '@/features/study/api/types'; import { useMyNegativeKeywordsQuery, @@ -66,7 +67,7 @@ export default function MyStudyReview() { positiveKeywords.map((keyword) => ( )) @@ -96,7 +97,7 @@ export default function MyStudyReview() { negativeKeywords.map((keyword) => ( )) @@ -152,24 +153,6 @@ export default function MyStudyReview() { ); } -function KeywordReview({ - type, - count, -}: { - type: 'positive' | 'negative'; - count: number; -}) { - return ( -
      • - - {type === 'positive' ? '“좋았어요, 괜찮았어요”' : '“아쉬웠어요”'} 평가 - 키워드 - - {count} -
      • - ); -} - function Review({ data }: { data: MyReviewItem }) { const [expanded, setExpanded] = useState(false); diff --git a/src/entities/my-profile/ui/keyword-review.tsx b/src/entities/my-profile/ui/keyword-review.tsx new file mode 100644 index 00000000..89ecda2a --- /dev/null +++ b/src/entities/my-profile/ui/keyword-review.tsx @@ -0,0 +1,14 @@ +export default function KeywordReview({ + content, + count, +}: { + content: string; + count: number; +}) { + return ( +
      • + {content} + {count} +
      • + ); +} From 1ac1a71d969695cce51f34c88941147d4e5245d1 Mon Sep 17 00:00:00 2001 From: aken-you Date: Mon, 25 Aug 2025 00:53:32 +0900 Subject: [PATCH 33/34] =?UTF-8?q?refactor:=20UserProfileModal=EC=97=90=20?= =?UTF-8?q?=EB=B0=9B=EC=9D=80=20=ED=8F=89=EA=B0=80=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my-page/ui/user-profile-modal.tsx | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/features/my-page/ui/user-profile-modal.tsx b/src/features/my-page/ui/user-profile-modal.tsx index 54acff84..daa68411 100644 --- a/src/features/my-page/ui/user-profile-modal.tsx +++ b/src/features/my-page/ui/user-profile-modal.tsx @@ -1,12 +1,14 @@ 'use client'; import { XIcon } from 'lucide-react'; +import KeywordReview from '@/entities/my-profile/ui/keyword-review'; import ProfileInfoCard from '@/entities/my-profile/ui/profile-info-card'; import { useUserProfileQuery } from '@/entities/user/model/use-user-profile-query'; import CakeIcon from '@/features/my-page/ui/icon/cake.svg'; import GithubIcon from '@/features/my-page/ui/icon/github-logo.svg'; import GlobeIcon from '@/features/my-page/ui/icon/globe-simple.svg'; import PhoneIcon from '@/features/my-page/ui/icon/phone.svg'; +import { useUserPositiveKeywordsQuery } from '@/features/study/model/use-review-query'; import UserAvatar from '@/shared/ui/avatar'; import Badge from '@/shared/ui/badge'; import { Modal } from '@/shared/ui/modal'; @@ -21,8 +23,13 @@ export default function UserProfileModal({ trigger, }: UserProfileModalProps) { const { data: profile, isLoading, isError } = useUserProfileQuery(memberId); + const { data: positiveKeywordsData } = useUserPositiveKeywordsQuery({ + memberId, + }); - if (isLoading || isError || !profile) return null; + if (isLoading || isError || !profile || !positiveKeywordsData) return null; + + const positiveKeywords = positiveKeywordsData?.keywords || []; return ( @@ -128,9 +135,24 @@ export default function UserProfileModal({
        - n명의 유저들이 이런 점이 좋다고 했어요. + {/* todo: 기획 fix되면 수정 */} + {/* n명의 유저들이 이런 점이 좋다고 했어요. */} -
          +
            + {positiveKeywords.length > 0 ? ( + positiveKeywords.map((keyword) => ( + + )) + ) : ( + + 아직 받은 평가가 없습니다. + + )} +
        From 6ebad6eb66040e3a50655a5bd259b1215b128e0d Mon Sep 17 00:00:00 2001 From: aken-you Date: Mon, 25 Aug 2025 00:55:03 +0900 Subject: [PATCH 34/34] =?UTF-8?q?refactor:=20ProfileInfoCard=EC=99=80=20Pr?= =?UTF-8?q?ofileInfoCard=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(my)/my-study-review/page.tsx | 2 +- src/entities/{my-profile => user}/ui/keyword-review.tsx | 0 src/entities/{my-profile => user}/ui/profile-info-card.tsx | 0 src/features/my-page/ui/profile-info.tsx | 2 +- src/features/my-page/ui/user-profile-modal.tsx | 4 ++-- 5 files changed, 4 insertions(+), 4 deletions(-) rename src/entities/{my-profile => user}/ui/keyword-review.tsx (100%) rename src/entities/{my-profile => user}/ui/profile-info-card.tsx (100%) diff --git a/app/(my)/my-study-review/page.tsx b/app/(my)/my-study-review/page.tsx index 0bcffa95..730daa9d 100644 --- a/app/(my)/my-study-review/page.tsx +++ b/app/(my)/my-study-review/page.tsx @@ -2,7 +2,7 @@ import Image from 'next/image'; import { useState } from 'react'; -import KeywordReview from '@/entities/my-profile/ui/keyword-review'; +import KeywordReview from '@/entities/user/ui/keyword-review'; import { MyReviewItem } from '@/features/study/api/types'; import { useMyNegativeKeywordsQuery, diff --git a/src/entities/my-profile/ui/keyword-review.tsx b/src/entities/user/ui/keyword-review.tsx similarity index 100% rename from src/entities/my-profile/ui/keyword-review.tsx rename to src/entities/user/ui/keyword-review.tsx diff --git a/src/entities/my-profile/ui/profile-info-card.tsx b/src/entities/user/ui/profile-info-card.tsx similarity index 100% rename from src/entities/my-profile/ui/profile-info-card.tsx rename to src/entities/user/ui/profile-info-card.tsx diff --git a/src/features/my-page/ui/profile-info.tsx b/src/features/my-page/ui/profile-info.tsx index 37c918ec..9b0047cc 100644 --- a/src/features/my-page/ui/profile-info.tsx +++ b/src/features/my-page/ui/profile-info.tsx @@ -1,7 +1,7 @@ 'use client'; -import ProfileInfoCard from '@/entities/my-profile/ui/profile-info-card'; import { MemberInfo } from '@/entities/user/api/types'; +import ProfileInfoCard from '@/entities/user/ui/profile-info-card'; import ProfileInfoEditModal from '@/features/my-page/ui/profile-info-edit-modal'; interface ProfileInfoProps { diff --git a/src/features/my-page/ui/user-profile-modal.tsx b/src/features/my-page/ui/user-profile-modal.tsx index daa68411..2d98c663 100644 --- a/src/features/my-page/ui/user-profile-modal.tsx +++ b/src/features/my-page/ui/user-profile-modal.tsx @@ -1,9 +1,9 @@ 'use client'; import { XIcon } from 'lucide-react'; -import KeywordReview from '@/entities/my-profile/ui/keyword-review'; -import ProfileInfoCard from '@/entities/my-profile/ui/profile-info-card'; import { useUserProfileQuery } from '@/entities/user/model/use-user-profile-query'; +import KeywordReview from '@/entities/user/ui/keyword-review'; +import ProfileInfoCard from '@/entities/user/ui/profile-info-card'; import CakeIcon from '@/features/my-page/ui/icon/cake.svg'; import GithubIcon from '@/features/my-page/ui/icon/github-logo.svg'; import GlobeIcon from '@/features/my-page/ui/icon/globe-simple.svg';