diff --git a/public/svgs/support/consumer/Ic_Alert.svg b/public/svgs/support/consumer/Ic_Alert.svg new file mode 100644 index 0000000..e8dfb3b --- /dev/null +++ b/public/svgs/support/consumer/Ic_Alert.svg @@ -0,0 +1,9 @@ + diff --git a/public/svgs/support/consumer/Ic_SupportMessage.svg b/public/svgs/support/consumer/Ic_SupportMessage.svg new file mode 100644 index 0000000..e2bc0a4 --- /dev/null +++ b/public/svgs/support/consumer/Ic_SupportMessage.svg @@ -0,0 +1,9 @@ + diff --git a/src/pages/join/components/GoHome.jsx b/src/pages/join/components/GoHome.jsx index 135a733..6e5d7e1 100644 --- a/src/pages/join/components/GoHome.jsx +++ b/src/pages/join/components/GoHome.jsx @@ -21,7 +21,7 @@ const GoHome = ({ onNext, onBack }) => {
+
가까운 사회적 기업을 추천해드릴게요.
@@ -61,7 +61,7 @@ const LocationStep = ({ onNext, onBack }) => { } py-2`} > {!checked && ( - + 서울특별시 )} @@ -74,7 +74,7 @@ const LocationStep = ({ onNext, onBack }) => { value={location} onChange={handleChange} readOnly={checked} - className={`flex-1 bg-transparent text-h2 font-semibold focus:outline-none placeholder-gray-6 ${ + className={`flex-1 bg-transparent h2 focus:outline-none placeholder-gray-6 ${ checked ? "bg-gray-6 cursor-not-allowed" : "" }`} /> @@ -91,7 +91,7 @@ const LocationStep = ({ onNext, onBack }) => { {(showWarningForSeoul || showNotSeoulMessage) && ( -+
현재는 서울에 한해 사회적 기업들을 소개하고 있습니다.
)} @@ -105,7 +105,7 @@ const LocationStep = ({ onNext, onBack }) => { ) : (+
우리 동네 사회적기업 찾아보기
-+
사회적기업은, 판매 수익을 사회문제 해결이나 {"\n"}이웃 돕기에 쓰는 특별한 기업들이에요. {"\n"}우리 동네 사회적기업을 찾아보고, 함께 참여해보세요! diff --git a/src/pages/map/components/PlaceContent.jsx b/src/pages/map/components/PlaceContent.jsx index 7c033d2..74807c5 100644 --- a/src/pages/map/components/PlaceContent.jsx +++ b/src/pages/map/components/PlaceContent.jsx @@ -115,21 +115,21 @@ const PlaceContent = ({ place, onToggleLike, showMapLink = true }) => {
+
{business}
{companyType && ( @@ -148,7 +148,7 @@ const PlaceContent = ({ place, onToggleLike, showMapLink = true }) => { alt={companyType} className="w-5 h-5" /> - + {companyTypeNameMap[companyType]}{place.address}
+{place.address}
데이터를 불러오지 못했습니다.
+데이터를 불러오지 못했습니다.
+
해당 상품 정보를 찾을 수 없습니다.
{data.productName}
-{data.bankName}
+{data.productName}
+{data.bankName}
-- 기본 정보 -
+기본 정보
가입 기간
-- {data.period || "-"} -
+가입 기간
+{data.period || "-"}
방식
-+
방식
+{data.method || "-"}
기본 금리
-+
기본 금리
+{data.benefit || "-"}
+
금융상품 소개
+
{data.productDescription || "상품 설명이 없습니다."}
• 본 서비스에서 제공하는 상품 정보는 각 기관의 공고를 바탕으로 수집·정리한 참고용 자료입니다. @@ -125,7 +131,7 @@ const FinancialProductDetailPage = () => { className="w-6 h-6" alt="바로가기" /> -
+
바로가기
diff --git a/src/pages/support/FinancialProductListPage.jsx b/src/pages/support/FinancialProductListPage.jsx index 1af984b..74f988f 100644 --- a/src/pages/support/FinancialProductListPage.jsx +++ b/src/pages/support/FinancialProductListPage.jsx @@ -1,13 +1,78 @@ +import { useEffect, useState } from "react"; import RecommendationCard from "@/pages/support/components/RecommendationCard"; import { useNavigate } from "react-router-dom"; -import { useFinancialProducts } from "@/pages/support/hooks/useFinancialProducts"; import Spinner from "@components/common/Spinner"; +import { useFinancialProducts } from "@/pages/support/hooks/useFinancialProducts"; +import { getConsumptionDetail } from "@apis/consumer/getConsumptionDetail"; +import { getMyProfile } from "@apis/member/auth"; +import { KOR_TO_ENUM_MAP } from "@pages/support/constants/consumerMap"; const FinancialProductList = () => { const navigate = useNavigate(); const { data: products, isLoading, error } = useFinancialProducts(); + const [userName, setUserName] = useState(""); + + useEffect(() => { + const fetchProfile = async () => { + try { + const res = await getMyProfile(); + setUserName(res?.name || "사용자"); + } catch (e) { + console.error("프로필 로딩 실패:", e); + } + }; + + fetchProfile(); + }, []); + + const [sortedProducts, setSortedProducts] = useState([]); + + useEffect(() => { + const sortProductsByReviewCount = async () => { + if (!products || products.length === 0) return; + + const uniqueCategories = new Set(); + products.forEach((item) => { + if (item.recommendedCategory) + uniqueCategories.add(item.recommendedCategory); + if (item.defaultCategory) uniqueCategories.add(item.defaultCategory); + }); + + const reviewCountMap = new Map(); + + await Promise.all( + [...uniqueCategories].map(async (korName) => { + const enumKey = KOR_TO_ENUM_MAP[korName]; + if (!enumKey) return; + + try { + const res = await getConsumptionDetail(enumKey); + reviewCountMap.set(korName, res?.reviewCount || 0); + } catch { + reviewCountMap.set(korName, 0); + } + }) + ); + + const sorted = [...products].sort((a, b) => { + const aCount = + reviewCountMap.get(a.recommendedCategory) || + reviewCountMap.get(a.defaultCategory) || + 0; + const bCount = + reviewCountMap.get(b.recommendedCategory) || + reviewCountMap.get(b.defaultCategory) || + 0; + return bCount - aCount; + }); + + setSortedProducts(sorted); + }; + + sortProductsByReviewCount(); + }, [products]); - const safeProducts = Array.isArray(products) ? products : []; + const safeProducts = Array.isArray(sortedProducts) ? sortedProducts : []; return (총 {safeProducts.length}개
++ 총 {safeProducts.length}개 +
+
+ {userName}님이 리뷰를 남긴 기업 특성과
+
연관된 금융상품 순으로 보여드려요!
+
데이터를 불러오지 못했습니다.
}데이터를 불러오지 못했습니다.
; @@ -25,23 +47,22 @@ const ConsumerTab = () => { value: item.totalPrice, })) || []; - const safeProducts = Array.isArray(consumerProducts) ? consumerProducts : []; - return ( -+ {RECOMMEND_MESSAGE_MAP[ENUM_TO_KOR_MAP[topCategory]]} +
+
-
+
+
총
{reviewCount}
-
+
건
기반 기반
{message}
+ {subMessage &&{subMessage}
} + + {showButton && ( +{title}
-{bank}
+{title}
+{bank}
+
{description}
)} diff --git a/src/pages/support/constants/consumerMap.js b/src/pages/support/constants/consumerMap.js index b92a8b4..1769d88 100644 --- a/src/pages/support/constants/consumerMap.js +++ b/src/pages/support/constants/consumerMap.js @@ -12,7 +12,16 @@ export const SPEECH_BUBBLE_MAP = { 사회서비스제공형: "돌봄과 배려가 필요한 곳에,\n당신의 소비가 닿았어요.", 혼합형: "다양한 사회문제를 동시에 돕는\n멋진 소비를 하셨네요!", "기타(창의ㆍ혁신)형": "사회에 선한 영향을 준\n당신의 소비, 함께 기억할게요.", - 예비: "예비 사회적 기업에\n 선한 영향을 준\n 당신의 소비, 함께 기억할게요.", + 예비형: "예비 사회적 기업에\n 선한 영향을 준\n 당신의 소비, 함께 기억할게요.", +}; + +export const RECOMMEND_MESSAGE_MAP = { + 일자리제공형: "고용을 살린 소비, 이 금융상품과 잘 맞아요", + 지역사회공헌형: "지역을 밝힌 소비, 이 금융상품이 닮았어요", + 사회서비스제공형: "돌봄을 실천한 소비, 이 금융과 함께 이어가보세요", + 혼합형: "다방면의 가치소비, 금융에서도 이어집니다", + "기타(창의ㆍ혁신)형": "특별한 소비, 특별한 금융 제안이에요", + 예비형: "예비 사회적기업까지 알아본 소비, 아래 금융상품을 추천해요", }; export const KOR_TO_ENUM_MAP = { @@ -21,7 +30,7 @@ export const KOR_TO_ENUM_MAP = { 혼합형: "MIXED", "기타(창의ㆍ혁신)형": "ETC", 지역사회공헌형: "COMPANY_CONTRIBUTION", - 예비: "PRE", + 예비형: "PRE", }; export const ENUM_TO_KOR_MAP = { @@ -30,5 +39,5 @@ export const ENUM_TO_KOR_MAP = { MIXED: "혼합형", ETC: "기타(창의ㆍ혁신)형", COMPANY_CONTRIBUTION: "지역사회공헌형", - PRE: "예비", + PRE: "예비형", }; diff --git a/tailwind.config.js b/tailwind.config.js index 94df9d5..ff29322 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -12,6 +12,9 @@ export default { error: "rgba(232, 58, 58, 1)", errorContainer: "rgba(255, 232, 232, 1)", Scrim: "rgba(46, 45, 43, 0.20)", + supportMessage: + "linear-gradient(90deg, rgba(255, 111, 49, 0.20) 0%, rgba(255, 255, 255, 0.20) 100%), #FFF", + gray: { 0: "rgba(255, 255, 255, 1)", 1: "rgba(253, 253, 253, 1)",