diff --git a/app/routes/home/home-after-match.tsx b/app/routes/home/home-after-match.tsx index 0012c77..4f24ac5 100644 --- a/app/routes/home/home-after-match.tsx +++ b/app/routes/home/home-after-match.tsx @@ -7,7 +7,13 @@ import BrandCard from "./components/BrandCard"; import CampaignCard from "./components/CampaignCard"; import MatchAnalysisSection from "./components/MatchAnalysisSection"; import CreatorProfileCard from "./components/CreatorProfileCard"; -import { getMatchingBrands, getMatchingCampaigns, toggleBrandLike, type MatchingBrand, type MatchingCampaign } from "../matching/api/matching"; +import { + getMatchingBrands, + getMatchingCampaigns, + toggleBrandLike, + type MatchingBrand, + type MatchingCampaign, +} from "../matching/api/matching"; import { useMatchResultStore } from "../../stores/matching-result"; import bannerBeauty from "../../assets/home-banner/banner-beauty.svg"; import bannerFashion from "../../assets/home-banner/banner-fashion.svg"; @@ -17,7 +23,9 @@ export default function HomeAfterMatchPage() { const [category, setCategory] = useState("beauty"); const [brands, setBrands] = useState([]); const [campaigns, setCampaigns] = useState([]); - const [popularCampaigns, setPopularCampaigns] = useState([]); + const [popularCampaigns, setPopularCampaigns] = useState( + [], + ); // 스토어에서 매칭 결과 가져오지만 -> api/v1/me/feature로 변경 const matchResult = useMatchResultStore((s) => s.result); @@ -28,7 +36,7 @@ export default function HomeAfterMatchPage() { const [brandsData, campaignsData, popularData] = await Promise.all([ getMatchingBrands("MATCH_SCORE", "ALL"), getMatchingCampaigns("MATCH_SCORE", "ALL"), - getMatchingCampaigns("POPULARITY", "ALL") + getMatchingCampaigns("POPULARITY", "ALL"), ]); setBrands(brandsData.brands); setCampaigns(campaignsData.campaigns); @@ -50,12 +58,14 @@ export default function HomeAfterMatchPage() { creatorName: "크리에이터 님", creatorType: "creator", summary: apiResult.userType || "크리에이터", - highlightBrandText: apiResult.highMatchingBrandList?.brands[0]?.brandName || "매칭된 브랜드", + highlightBrandText: + apiResult.highMatchingBrandList?.brands[0]?.brandName || + "매칭된 브랜드", traits: { beauty: apiResult.typeTag?.[0] || "특성 1", fashion: apiResult.typeTag?.[1] || "특성 2", content: apiResult.typeTag?.[2] || "특성 3", - } + }, } as CreatorProfileModel; } else if (matchResult?.summary) { // apiResult가 없으면 summary 사용 @@ -63,12 +73,13 @@ export default function HomeAfterMatchPage() { creatorName: "크리에이터 님", creatorType: "creator", summary: matchResult.summary.userName || "크리에이터", - highlightBrandText: matchResult.summary.recommendedBrand || "매칭된 브랜드", + highlightBrandText: + matchResult.summary.recommendedBrand || "매칭된 브랜드", traits: { beauty: matchResult.summary.traits.beauty || "특성 1", fashion: matchResult.summary.traits.style || "특성 2", content: matchResult.summary.traits.content || "특성 3", - } + }, } as CreatorProfileModel; } return null; @@ -80,9 +91,11 @@ export default function HomeAfterMatchPage() { const brandId = Number(id); const newLikeStatus = await toggleBrandLike(brandId); - setBrands(prev => prev.map(brand => - brand.id === brandId ? { ...brand, isLiked: newLikeStatus } : brand - )); + setBrands((prev) => + prev.map((brand) => + brand.id === brandId ? { ...brand, isLiked: newLikeStatus } : brand, + ), + ); } catch (error) { console.error("Failed to toggle brand like:", error); } @@ -95,13 +108,21 @@ export default function HomeAfterMatchPage() { const newLikeStatus = await toggleBrandLike(campaignId); // 매칭률 높은 캠페인 업데이트 - setCampaigns(prev => prev.map(campaign => - campaign.id === campaignId ? { ...campaign, isLiked: newLikeStatus } : campaign - )); + setCampaigns((prev) => + prev.map((campaign) => + campaign.id === campaignId + ? { ...campaign, isLiked: newLikeStatus } + : campaign, + ), + ); // 인기 캠페인도 업데이트 - setPopularCampaigns(prev => prev.map(campaign => - campaign.id === campaignId ? { ...campaign, isLiked: newLikeStatus } : campaign - )); + setPopularCampaigns((prev) => + prev.map((campaign) => + campaign.id === campaignId + ? { ...campaign, isLiked: newLikeStatus } + : campaign, + ), + ); } catch (error) { console.error("Failed to toggle campaign like:", error); } @@ -145,7 +166,9 @@ export default function HomeAfterMatchPage() { isLiked: brand.isLiked, }} onClick={() => { - navigate(`/brand?brandId=${brand.id}&domain=${brand.name?.toLowerCase() || ""}`); + navigate( + `/brand?brandId=${brand.id}&domain=${brand.name?.toLowerCase() || ""}`, + ); }} onLikeToggle={handleBrandLikeToggle} /> @@ -175,7 +198,12 @@ export default function HomeAfterMatchPage() { descText: campaign.name || campaign.title || "", rewardText: `원고료 ${campaign.reward?.toLocaleString()}원`, startAt: "", - ddayLabel: campaign.dDay !== undefined ? (campaign.dDay === 0 ? "D-DAY" : `D-${campaign.dDay}`) : "", + ddayLabel: + campaign.dDay !== undefined + ? campaign.dDay === 0 + ? "D-DAY" + : `D-${campaign.dDay}` + : "", progressText: String(campaign.applicants), isLiked: campaign.isLiked, logoUrl: campaign.logoUrl, @@ -215,7 +243,12 @@ export default function HomeAfterMatchPage() { descText: campaign.name || campaign.title || "", rewardText: `원고료 ${campaign.reward?.toLocaleString()}원`, startAt: "", - ddayLabel: campaign.dDay !== undefined ? (campaign.dDay === 0 ? "D-DAY" : `D-${campaign.dDay}`) : "", + ddayLabel: + campaign.dDay !== undefined + ? campaign.dDay === 0 + ? "D-DAY" + : `D-${campaign.dDay}` + : "", progressText: String(campaign.applicants), isLiked: campaign.isLiked, logoUrl: campaign.logoUrl, diff --git a/app/routes/home/home.mock.ts b/app/routes/home/home.mock.ts deleted file mode 100644 index b82b886..0000000 --- a/app/routes/home/home.mock.ts +++ /dev/null @@ -1,120 +0,0 @@ -// src/routes/_home/home.mock.ts -import type { HomeAfterMatchResponse } from "./types"; - -export const HOME_AFTER_MATCH_MOCK: HomeAfterMatchResponse = { - beauty: { - category: "beauty", - hero: [ - { id: "b-hero-1", imageUrl: "https://picsum.photos/900/600?1", alt: "beauty hero 1" }, - { id: "b-hero-2", imageUrl: "https://picsum.photos/900/600?2", alt: "beauty hero 2" }, - { id: "b-hero-3", imageUrl: "https://picsum.photos/900/600?3", alt: "beauty hero 3" }, - ], - - topBrands: [ - { id: "b-brand-1", name: "beplain", matchRate: 98, isLiked: true, subText: "#비건 #천연재료", badgeText: "모집중" }, - { id: "b-brand-2", name: "isntree", matchRate: 95, subText: "#저자극 #클린뷰티", badgeText: "모집중" }, - { id: "b-brand-3", name: "manyo", matchRate: 92, subText: "#순한성분 #클린뷰티", badgeText: "모집중" }, - ], - - topCampaigns: [ - { - id: "b-camp-1", - brandName: "beplain", - startAt: "7/10", - ddayLabel: "D-DAY", - matchRate: 98, - descText: "신제품 릴스 홍보", - rewardText: "원고료 200,000원", - }, - { - id: "b-camp-2", - brandName: "isntree", - startAt: "1/5", - ddayLabel: "D-7", - matchRate: 98, - isLiked: true, - descText: "신제품 체험단 모집", - rewardText: "원고료 200,000원", - }, - { - id: "b-camp-3", - brandName: "manyo", - startAt: "7/10", - ddayLabel: "D-3", - matchRate: 92, - descText: "신제품 릴스 홍보", - rewardText: "원고료 200,000원", - }, - ], - - creatorProfile: { - creatorName: "크리에이터 님", - creatorType: "creator", - summary: "OO한 크리에이터", - highlightBrandText: "OO한 브랜드", - traits: { beauty: "OO 뷰티 특성", fashion: "OO 패션 특성", content: "OO 콘텐츠 특성" }, - }, - - popularCampaigns: [ - { - id: "b-pop-1", - brandName: "beplain", - ddayLabel: "D-DAY", - progressText: "7/10", - descText: "신제품 릴스 홍보", - rewardText: "원고료 200,000원", - }, - { - id: "b-pop-2", - brandName: "isntree", - ddayLabel: "D-7", - progressText: "1/5", - descText: "신제품 체험단 모집", - rewardText: "원고료 200,000원", - }, - { - id: "b-pop-3", - brandName: "manyo", - ddayLabel: "D-3", - progressText: "7/10", - descText: "신제품 릴스 홍보", - rewardText: "원고료 200,000원", - }, - ], - }, - - fashion: { - category: "fashion", - hero: [ - { id: "f-hero-1", imageUrl: "https://picsum.photos/900/600?4", alt: "fashion hero 1" }, - { id: "f-hero-2", imageUrl: "https://picsum.photos/900/600?5", alt: "fashion hero 2" }, - { id: "f-hero-3", imageUrl: "https://picsum.photos/900/600?6", alt: "fashion hero 3" }, - ], - - topBrands: [ - { id: "f-brand-1", name: "GRACE U", matchRate: 98, subText: "#타임리스 #클래식", badgeText: "모집중" }, - { id: "f-brand-2", name: "Thetis", matchRate: 95, isLiked: true, subText: "#러블리 #트렌디",badgeText: "모집중" }, - { id: "f-brand-3", name: "GLOWNY", matchRate: 92, subText: "#클린걸 #편안함",badgeText: "모집중" }, - ], - - topCampaigns: [ - { id: "f-camp-1", brandName: "Thetis", startAt: "7/10", ddayLabel: "D-DAY", matchRate: 96, descText: "신제품 릴스 홍보", rewardText: "원고료 100,000원" }, - { id: "f-camp-2", brandName: "GRACE U", startAt: "1/5", ddayLabel: "D-7", matchRate: 93, descText: "신제품 체험단 모집", rewardText: "원고료 300,000원" }, - { id: "f-camp-3", brandName: "GLOWNY", startAt: "7/10", ddayLabel: "D-3", matchRate: 91, descText: "신제품 릴스 홍보", rewardText: "원고료 200,000원" }, - ], - - creatorProfile: { - creatorName: "크리에이터 님", - creatorType: "creator", - summary: "OO한 크리에이터", - highlightBrandText: "OO한 브랜드", - traits: { beauty: "OO 뷰티 특성", fashion: "OO 패션 특성", content: "OO 콘텐츠 특성" }, - }, - - popularCampaigns: [ - { id: "f-pop-1", brandName: "GRACE U", ddayLabel: "D-DAY", progressText: "7/10", descText: "신제품 릴스 홍보", rewardText: "원고료 300,000원" }, - { id: "f-pop-2", brandName: "Thetis", ddayLabel: "D-7", progressText: "1/5", descText: "신제품 체험단 모집", rewardText: "원고료 100,000원" }, - { id: "f-pop-3", brandName: "GLOWNY", ddayLabel: "D-3", progressText: "7/10", descText: "신제품 릴스 홍보", rewardText: "원고료 200,000원" }, - ], - }, -}; diff --git a/app/routes/matching/test/_shared/types/matches.types.ts b/app/routes/matching/test/_shared/types/matches.types.ts index d22f8d3..1faf1cf 100644 --- a/app/routes/matching/test/_shared/types/matches.types.ts +++ b/app/routes/matching/test/_shared/types/matches.types.ts @@ -54,6 +54,7 @@ export type HighMatchingBrandList = { }; export type MatchesResponseResult = { + userName: string; userType: string; typeTag: string[]; highMatchingBrandList: HighMatchingBrandList; diff --git a/app/routes/matching/test/result/matching-result-content.tsx b/app/routes/matching/test/result/matching-result-content.tsx index 8785236..f782445 100644 --- a/app/routes/matching/test/result/matching-result-content.tsx +++ b/app/routes/matching/test/result/matching-result-content.tsx @@ -12,7 +12,9 @@ type Brand = { }; type ApiResult = { + username: string; userType: string; + userTypeImage?: string; typeTag: string[]; highMatchingBrandList: { count: number; @@ -33,21 +35,33 @@ export default function MatchingResultContent() { const data = useMemo(() => { const apiResult = location.state?.apiResult; - // userName은 아직 API에 없으므로 기존대로 query/default 사용 - const userName = searchParams.get("userName") ?? "비비"; - if (apiResult) { + console.log("[result] apiResult exists:", !!apiResult); + console.log( + "[result] first brand:", + apiResult?.highMatchingBrandList?.brands?.[0], + ); + const userName = apiResult.username; const userType = apiResult.userType; const tags = apiResult.typeTag.slice(0, 3); const brands = [...apiResult.highMatchingBrandList.brands] .sort((a, b) => b.matchingRatio - a.matchingRatio) .slice(0, 3); - return { userName, userType, tags, brands }; + return { + userName, + userType, + tags, + brands, + userTypeImage: apiResult.userTypeImage, + }; } // fallback (직접 진입/새로고침으로 state 사라진 경우) + const userName = + searchParams.get("username") ?? searchParams.get("userName") ?? "비비"; const userType = searchParams.get("userType") ?? "섬세한 설계자"; + const tags = searchParams .get("typeTag") ?.split(",") @@ -61,7 +75,7 @@ export default function MatchingResultContent() { { brandId: 3, brandName: "ma:nyo", matchingRatio: 91 }, ]; - return { userName, userType, tags, brands }; + return { userName, userType, tags, brands, userTypeImage: undefined }; }, [location.state, searchParams]); const onStart = () => {