From 261be8d457abf340d8760eba3ed8586140044bb2 Mon Sep 17 00:00:00 2001 From: SangwanYu Date: Sun, 30 Nov 2025 21:11:58 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=EC=B6=94=EC=B2=9C=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EB=A0=8C=EB=8D=94=EB=A7=81=20=EC=8B=9C=20=EB=8B=A4?= =?UTF-8?q?=EB=A5=B8=20=EB=9E=9C=EB=8D=A4=20=EC=B9=B4=EB=93=9C=20=EC=9E=A0?= =?UTF-8?q?=EA=B9=90=20=EB=B3=B4=EC=9D=B4=EB=8A=94=20=ED=98=84=EC=83=81=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20->=20=EC=8A=A4=EC=BC=88=EB=A0=88=ED=86=A4u?= =?UTF-8?q?i?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RecommendedTermCardSkeleton.tsx | 22 ++++++ .../search/RecommendedTermsSection.tsx | 69 ++++++++++++------- 2 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 src/components/RecommendedTermCardSkeleton.tsx diff --git a/src/components/RecommendedTermCardSkeleton.tsx b/src/components/RecommendedTermCardSkeleton.tsx new file mode 100644 index 0000000..4a73442 --- /dev/null +++ b/src/components/RecommendedTermCardSkeleton.tsx @@ -0,0 +1,22 @@ +export default function RecommendedTermCardSkeleton() { + return ( +
+
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+ ); +} diff --git a/src/components/search/RecommendedTermsSection.tsx b/src/components/search/RecommendedTermsSection.tsx index 5bc0d80..71800e8 100644 --- a/src/components/search/RecommendedTermsSection.tsx +++ b/src/components/search/RecommendedTermsSection.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from "react"; import RecommendedTermCard from "@/components/RecommendedTermCard"; +import RecommendedTermCardSkeleton from "@/components/RecommendedTermCardSkeleton"; import { ChevronsDownIcon } from "@/components/icons/ic_chevrons_down"; import { useAuth } from "@/contexts/AuthContext"; import { @@ -15,16 +16,24 @@ export default function RecommendedTermsSection() { const [recommendedTerms, setRecommendedTerms] = useState( [] ); + const [isLoading, setIsLoading] = useState(true); useEffect(() => { const loadTerms = async () => { - const category = userData?.selectedCategory || "all"; + // userData가 로드되지 않았으면 로딩 상태 유지 + if (!userData) { + return; + } + + setIsLoading(true); + const category = userData.selectedCategory || "all"; const terms = await getRecommendedTerms(category, 6); setRecommendedTerms(terms); + setIsLoading(false); }; loadTerms(); - }, [userData?.selectedCategory]); + }, [userData]); const displayedRecommendedTerms = showMoreRecommended ? recommendedTerms @@ -36,29 +45,41 @@ export default function RecommendedTermsSection() { 추천 용어
- {displayedRecommendedTerms.map((term, index) => ( - - ))} -
-
- + {isLoading ? ( + // 로딩 중일 때 스켈레톤 3개 표시 + <> + + + + + ) : ( + // 데이터 로드 완료 시 실제 카드 표시 + displayedRecommendedTerms.map((term, index) => ( + + )) + )}
+ {!isLoading && ( +
+ +
+ )} ); } From dc4d3ff2734140c6c262f73226c12fbc4d24f4ab Mon Sep 17 00:00:00 2001 From: SangwanYu Date: Sun, 30 Nov 2025 21:15:51 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EC=B6=94=EC=B2=9C=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20=EC=9A=A9=EC=96=B4=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EB=84=A4=EB=B9=84=EA=B2=8C=EC=9D=B4?= =?UTF-8?q?=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/RecommendedTermCard.tsx | 15 ++++++++++++++- src/components/search/RecommendedTermsSection.tsx | 1 + src/lib/recommendations.ts | 3 +++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/components/RecommendedTermCard.tsx b/src/components/RecommendedTermCard.tsx index 4a88a6e..01bb40b 100644 --- a/src/components/RecommendedTermCard.tsx +++ b/src/components/RecommendedTermCard.tsx @@ -1,4 +1,7 @@ +"use client"; + import React, { ElementType } from "react"; +import { useRouter } from "next/navigation"; // 1. 카테고리 아이콘 컴포넌트 임포트 (TagList.tsx와 동일한 Named Export 가정) import { CategoryAllIcon } from "@/components/icons/ic_category_all"; @@ -17,6 +20,7 @@ interface TermCardProps { category: string; description: string; iconColor: string; + slug: string; } // 2. 카테고리 이름과 아이콘 컴포넌트를 매핑 @@ -38,13 +42,22 @@ export default function RecommendedTermCard({ category, description, iconColor, + slug, }: TermCardProps) { + const router = useRouter(); // 3. 현재 카테고리에 맞는 아이콘 컴포넌트를 찾습니다. const IconComponent = CategoryIconMap[category] || CategoryAllIcon; + const handleClick = () => { + router.push(`/terms/${slug}`); + }; + return ( // Figma: w-64 p-5 rounded-xl outline outline-[0.25px] outline-offset-[-0.25px] outline-white -
+
diff --git a/src/components/search/RecommendedTermsSection.tsx b/src/components/search/RecommendedTermsSection.tsx index 71800e8..b2d6347 100644 --- a/src/components/search/RecommendedTermsSection.tsx +++ b/src/components/search/RecommendedTermsSection.tsx @@ -61,6 +61,7 @@ export default function RecommendedTermsSection() { category={term.category} description={term.description} iconColor={term.iconColor} + slug={term.slug} /> )) )} diff --git a/src/lib/recommendations.ts b/src/lib/recommendations.ts index 348e267..fcef629 100644 --- a/src/lib/recommendations.ts +++ b/src/lib/recommendations.ts @@ -43,6 +43,7 @@ export interface RecommendedTerm { category: string; description: string; iconColor: string; + slug: string; } /** @@ -64,6 +65,7 @@ export async function getRecommendedTerms( category: categoryLabels[targetCategory], description: t.summary, iconColor: categoryColors[categoryId], + slug: t.slug, })); } @@ -78,6 +80,7 @@ export async function getRecommendedTerms( category: categoryLabels[targetCategory], description: t.summary, iconColor: categoryColors[categoryId], + slug: t.slug, })); } catch (error) { console.error("추천 용어 로드 실패:", error);