From f6d94cda13d9566fe0eeeeaf505c4ba262215081 Mon Sep 17 00:00:00 2001 From: kuan Date: Tue, 3 Feb 2026 23:14:43 +0900 Subject: [PATCH 1/5] =?UTF-8?q?chore:=20=EB=A9=94=EC=9D=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20lcp=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commons/card/perfumeCard/index.tsx | 6 ++++-- .../card/perfumeCard/perfumeCard.types.ts | 1 + .../domains/main/mainBanner/MainBanner.tsx | 16 +++++----------- .../main/mainBanner/MainBannerPerfumeList.tsx | 6 +++--- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/components/commons/card/perfumeCard/index.tsx b/src/components/commons/card/perfumeCard/index.tsx index f8e21985..dfdfb0c3 100644 --- a/src/components/commons/card/perfumeCard/index.tsx +++ b/src/components/commons/card/perfumeCard/index.tsx @@ -14,6 +14,7 @@ export default function PerfumeCard({ onClick, onClose, className = "", + priority = false, }: PerfumeCardProps) { return (
diff --git a/src/components/commons/card/perfumeCard/perfumeCard.types.ts b/src/components/commons/card/perfumeCard/perfumeCard.types.ts index f7920f67..6fa58b72 100644 --- a/src/components/commons/card/perfumeCard/perfumeCard.types.ts +++ b/src/components/commons/card/perfumeCard/perfumeCard.types.ts @@ -11,6 +11,7 @@ interface PerfumeCardProps { onClick?: () => void; onClose?: () => void; className?: string; + priority?: boolean; } export type { PerfumeCardType, PerfumeCardProps }; diff --git a/src/components/domains/main/mainBanner/MainBanner.tsx b/src/components/domains/main/mainBanner/MainBanner.tsx index 23c21e68..18c5ff2d 100644 --- a/src/components/domains/main/mainBanner/MainBanner.tsx +++ b/src/components/domains/main/mainBanner/MainBanner.tsx @@ -1,11 +1,9 @@ -"use client"; - import { MainBannerPerfumeList } from "./MainBannerPerfumeList"; -import { SkeletonBanner } from "@/components/domains/user/components/skeletons/SkeletonBanner"; -import { usePerfumeByTheme } from "@/lib/hooks/query/usePerfumeQuery"; +import { getPerfumesListByThemeService } from "@/lib/hono/services/perfume.service"; -export const MainBanner = () => { - const { data = [], isLoading } = usePerfumeByTheme("FRESH"); +export const MainBanner = async () => { + const result = await getPerfumesListByThemeService("mostLike"); + const data = result.success ? result.data : []; return (
@@ -13,11 +11,7 @@ export const MainBanner = () => {
현재 가장 인기가 많은 향수 TOP 5
- {isLoading ? ( - - ) : ( - data && - )} +
); diff --git a/src/components/domains/main/mainBanner/MainBannerPerfumeList.tsx b/src/components/domains/main/mainBanner/MainBannerPerfumeList.tsx index b4f5391e..4974cdc5 100644 --- a/src/components/domains/main/mainBanner/MainBannerPerfumeList.tsx +++ b/src/components/domains/main/mainBanner/MainBannerPerfumeList.tsx @@ -1,5 +1,3 @@ -"use client"; - import PerfumeCard from "@/components/commons/card/perfumeCard"; import Link from "next/link"; import { ApiPerfumeSimpleResponse } from "@/lib/hono/schemas/perfume.schema"; @@ -14,7 +12,7 @@ export const MainBannerPerfumeList = ({ return (
- {data.map((item) => ( + {data.map((item, index) => ( ))} From cad9e75216e7178dda9ca2ccfe3498de63d912ed Mon Sep 17 00:00:00 2001 From: kuan Date: Tue, 3 Feb 2026 23:17:27 +0900 Subject: [PATCH 2/5] =?UTF-8?q?chore:=20=EB=B9=84=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EC=8B=9C=20=EC=84=B8=EC=85=98=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=20api=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commons/Provider/GlobalStateSync.tsx | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/components/commons/Provider/GlobalStateSync.tsx b/src/components/commons/Provider/GlobalStateSync.tsx index 42b0c261..c3b34cc7 100644 --- a/src/components/commons/Provider/GlobalStateSync.tsx +++ b/src/components/commons/Provider/GlobalStateSync.tsx @@ -1,13 +1,34 @@ "use client"; -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { useUserProfile } from "@/lib/hooks/query/useUserQuery"; import { useUserStore } from "@/lib/stores/useUserStore"; import { pointApi } from "@/lib/utils/api/points.api"; +/** + * 클라이언트에서 세션 토큰 존재 여부 확인 + */ +function hasSessionToken(): boolean { + if (typeof document === "undefined") return false; + return ( + document.cookie.includes("authjs.session-token=") || + document.cookie.includes("__Secure-authjs.session-token=") + ); +} + //전역으로 사용하는 상태 동기화 export default function GlobalStateSync() { - const { data: userProfile, isFetched } = useUserProfile(); + const [isLoggedIn, setIsLoggedIn] = useState(false); + + // 클라이언트에서만 세션 체크 + useEffect(() => { + setIsLoggedIn(hasSessionToken()); + }, []); + + // 로그인된 사용자만 프로필 조회 + const { data: userProfile, isFetched } = useUserProfile({ + enabled: isLoggedIn, + }); const { setUser, reset } = useUserStore(); // 사용자 프로필 동기화 From c20f94b37974594c7e81d378a76f094b8ea95034 Mon Sep 17 00:00:00 2001 From: kuan Date: Tue, 3 Feb 2026 23:47:08 +0900 Subject: [PATCH 3/5] =?UTF-8?q?chore:=20=EB=A9=94=EC=9D=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EC=9D=B8=EA=B8=B0=EA=B8=80=20=EC=8B=A4?= =?UTF-8?q?=EC=A0=9C=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../commons/Provider/GlobalStateSync.tsx | 13 +++- .../MainContentCommunityList.tsx | 74 +++++++++++++------ 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/src/components/commons/Provider/GlobalStateSync.tsx b/src/components/commons/Provider/GlobalStateSync.tsx index c3b34cc7..60a04bc0 100644 --- a/src/components/commons/Provider/GlobalStateSync.tsx +++ b/src/components/commons/Provider/GlobalStateSync.tsx @@ -20,16 +20,23 @@ function hasSessionToken(): boolean { export default function GlobalStateSync() { const [isLoggedIn, setIsLoggedIn] = useState(false); + const { setUser, reset } = useUserStore(); + // 클라이언트에서만 세션 체크 useEffect(() => { - setIsLoggedIn(hasSessionToken()); - }, []); + const hasSession = hasSessionToken(); + setIsLoggedIn(hasSession); + + // 세션이 없으면 즉시 사용자 상태 초기화 + if (!hasSession) { + reset(); + } + }, [reset]); // 로그인된 사용자만 프로필 조회 const { data: userProfile, isFetched } = useUserProfile({ enabled: isLoggedIn, }); - const { setUser, reset } = useUserStore(); // 사용자 프로필 동기화 useEffect(() => { diff --git a/src/components/domains/main/mainContent/mainContentCommunity/MainContentCommunityList.tsx b/src/components/domains/main/mainContent/mainContentCommunity/MainContentCommunityList.tsx index c344f6ad..dccd6ef0 100644 --- a/src/components/domains/main/mainContent/mainContentCommunity/MainContentCommunityList.tsx +++ b/src/components/domains/main/mainContent/mainContentCommunity/MainContentCommunityList.tsx @@ -4,9 +4,11 @@ import { BOARD_TYPES } from "@/lib/constants/communityBoard"; import ICONS from "@/lib/constants/icons"; import Image from "next/image"; import { useState } from "react"; -import { boardDataMap } from "@/lib/mocks/communityPosts"; import BoardTabBar from "@/components/commons/tabBar/BoardTabBar"; import Link from "next/link"; +import { useCommunityPosts } from "@/lib/hooks/query/useCommunityQuery"; +import { PostCategory } from "@prisma/client"; +import { Indicator } from "@/components/commons/loading/Indicator"; interface IMainContentCommunityList { size: "s" | "m"; @@ -22,6 +24,15 @@ export const MainContentCommunityList = ({ const [selectedTab, setSelectedTab] = useState(boards[0].key); + // API 호출 + const { data: apiData, isLoading } = useCommunityPosts({ + category: selectedTab as PostCategory, + sortBy: "popular", + limit: 8, + }); + + const posts = apiData?.data || []; + const handleTabClick = (key: string) => { setSelectedTab(key); }; @@ -39,29 +50,44 @@ export const MainContentCommunityList = ({ handleTabClick={handleTabClick} />
-
- {boardDataMap[selectedTab].map((post) => ( - -

- {post.title} -

-
- {ICONS.Comment.alt} -
- {post.commentCount > 1000 ? "999+" : post.commentCount} -
-
- - ))} +
+ {isLoading ? ( +
+ +
+ ) : posts.length === 0 ? ( +
+ 게시글이 없습니다. +
+ ) : ( + <> + {posts.map((post) => ( + + {/* title */} +

+ {post.title} +

+ + {/* comment meta */} +
+ {ICONS.Comment.alt} + + {post.commentCount > 1000 ? "999+" : post.commentCount} + +
+ + ))} + + )}
); From 82a4854821d0a1daa2d8ae1b1511b8eec758331e Mon Sep 17 00:00:00 2001 From: kuan Date: Wed, 4 Feb 2026 18:45:49 +0900 Subject: [PATCH 4/5] =?UTF-8?q?feat:=20=EB=A9=94=EC=9D=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/perfumes/page.tsx | 5 +- .../dropdown/SearchResultsDropdown.tsx | 10 +- .../commons/perfumeList/search/index.tsx | 3 + src/components/commons/search/SearchBar.tsx | 35 ++-- src/components/domains/main/MainSearchBar.tsx | 153 +++++++++++++++++- .../MainContentCommunity.tsx | 12 +- .../MainContentCommunityList.tsx | 21 ++- .../perfumes/hook/usePerfumeSearchState.ts | 18 ++- src/components/modal/LoginModalProvider.tsx | 10 +- src/lib/hooks/query/useCommunityQuery.ts | 3 +- src/lib/hooks/useSearchBar.ts | 36 +++++ src/lib/utils/highlightText.tsx | 30 ++++ 12 files changed, 301 insertions(+), 35 deletions(-) create mode 100644 src/lib/hooks/useSearchBar.ts create mode 100644 src/lib/utils/highlightText.tsx diff --git a/src/app/perfumes/page.tsx b/src/app/perfumes/page.tsx index 3fb1ab9f..f46a7d25 100644 --- a/src/app/perfumes/page.tsx +++ b/src/app/perfumes/page.tsx @@ -1,4 +1,5 @@ import { HydrationBoundary, dehydrate } from "@tanstack/react-query"; +import { Suspense } from "react"; import getQueryClient from "@/lib/utils/getQueryClient"; import { brandApi } from "@/lib/utils/api/brands.api"; import { perfumeApi } from "@/lib/utils/api/perfumes.api"; @@ -24,7 +25,9 @@ export default async function Page() { return ( - + + + ); } diff --git a/src/components/commons/dropdown/SearchResultsDropdown.tsx b/src/components/commons/dropdown/SearchResultsDropdown.tsx index 13d884ab..fec83145 100644 --- a/src/components/commons/dropdown/SearchResultsDropdown.tsx +++ b/src/components/commons/dropdown/SearchResultsDropdown.tsx @@ -10,16 +10,14 @@ export function SearchResultsDropdown({ children, }: SearchResultsDropdownProps) { return ( -
- {isLoading ? ( -
검색 중...
- ) : results.length > 0 ? ( +
+ {results.length > 0 ? (
    {results.map((item) => children(item))}
- ) : ( + ) : !isLoading ? (
검색 결과가 없습니다.
- )} + ) : null}
); } diff --git a/src/components/commons/perfumeList/search/index.tsx b/src/components/commons/perfumeList/search/index.tsx index d80da3ec..1ba32d45 100644 --- a/src/components/commons/perfumeList/search/index.tsx +++ b/src/components/commons/perfumeList/search/index.tsx @@ -15,6 +15,7 @@ interface SearchHeaderProps { notes: ApiPerfumeNoteResponse[]; accords: ApiPerfumeAccordResponse[]; isSearch?: boolean; + searchBarMaxWidth?: string; } export function SearchHeader({ @@ -25,6 +26,7 @@ export function SearchHeader({ notes, accords, isSearch = true, + searchBarMaxWidth = "840px", }: SearchHeaderProps) { return (
@@ -34,6 +36,7 @@ export function SearchHeader({ value={inputValue} onChange={onChange} onClick={onSubmit} + maxWidth={searchBarMaxWidth} /> )}