Skip to content

Conversation

@shroqkf
Copy link
Collaborator

@shroqkf shroqkf commented May 9, 2025

🌟 어떤 이유로 MR를 하셨나요?

  • feature 병합()
  • 버그 수정(아래에 issue #를 남겨주세요)
  • 코드 개선
  • 코드 수정
  • 배포
  • 기타(아래에 자세한 내용 기입해주세요)

📝 세부 내용 - 왜 해당 MR이 필요한지 작업 내용을 자세하게 설명해주세요

  • 지원 페이지에 금융 상품 추천 로직을 추가했습니다.
    • ConsumptionChart에서 가장 리뷰 비중이 높은 사회적기업 유형(companyType) 추출
    • 추출된 유형을 ENUM_TO_KOR_MAP으로 한글 카테고리로 변환
    • ConsumerTab에서 추천 금융상품 목록을 금융상품 데이터의 카테고리(recommendedCategory, defaultCategory) 기준으로 필터링하여 렌더링
    • 전체 금융 상품 리스트도 리뷰 많은 순으로 정렬되어 보이도록 구현

📸 작업 화면 스크린샷

2025-05-09.5.06.05.mov

⚠️ MR하기 전에 확인해주세요

  • 로컬테스트를 진행하셨나요?
  • 머지할 브랜치를 확인하셨나요?
  • 관련 label을 선택하셨나요?

📢 로컬 실행 시 유의사항

  • 로그인한 계정에 등록된 리뷰가 없으면 확인이 어려울 수 있습니다. 작업 화면의 경우 제 계정에 테스트용 데이터를 추가해 확인했습니다.

🚨 관련 이슈 번호

Summary by CodeRabbit

  • 신규 기능

    • 로그인 유도가 필요한 상황에서 표시되는 로그인 모달이 추가되었습니다.
  • 기능 개선

    • 금융상품 목록이 리뷰 수 기준으로 정렬되어 표시되며, 정렬 기준 안내 메시지가 추가되었습니다.
    • 소비자 추천 탭에서 카테고리별 필터링이 가능해졌고, 차트와 연동하여 상위 카테고리 선택이 지원됩니다.
    • 추천 카드와 금융상품 상세 페이지에서 상품 유형, 추천 카테고리, 기본 카테고리를 모두 표시하도록 개선되었습니다.
    • 소비자 추천 메시지 맵이 추가되어 카테고리별 맞춤 추천 메시지가 제공됩니다.
    • Tailwind CSS에 지원 메시지용 그라데이션 색상이 추가되었습니다.
  • 버그 수정/스타일

    • 카테고리 명칭이 "예비"에서 "예비형"으로 일괄 변경되었습니다.
    • 여러 컴포넌트에서 텍스트 스타일 관련 CSS 클래스명이 간소화되어 일관된 디자인이 적용되었습니다.
  • 기타

    • 일부 컴포넌트의 import 경로가 수정되었습니다.

@vercel
Copy link

vercel bot commented May 9, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
morak ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 14, 2025 11:04am

@coderabbitai
Copy link

coderabbitai bot commented May 9, 2025

"""

Walkthrough

이 변경사항은 금융 상품 추천 및 소비자 탭 관련 페이지와 컴포넌트의 렌더링 및 데이터 흐름을 개선합니다. 상품 타입 및 카테고리 표기 방식이 변경되었고, 상품 리스트는 리뷰 수 기준으로 정렬됩니다. 새로운 로그인 모달 컴포넌트가 추가되었으며, 카테고리 명칭 일관성도 확보되었습니다.

Changes

파일/경로 요약 변경 내용 요약
src/pages/support/FinancialProductDetailPage.jsx, src/pages/support/components/RecommendationCard.jsx 상품 타입 및 카테고리 렌더링 로직을 변경하여 세 필드가 모두 존재할 때만 세 개의 라벨(span)을 각각 다른 스타일로 표시하도록 수정. RecommendationCard 컴포넌트에서 benefit prop 제거, recommendedCategorydefaultCategory prop 추가. CSS 클래스명 text- 접두사 제거 및 간소화.
src/pages/support/FinancialProductListPage.jsx 금융 상품 리스트를 리뷰 수 기준으로 정렬하는 상태와 로직 추가. 정렬된 리스트로 렌더링하며, 카테고리 정보도 카드에 전달. 사용자 이름 표시 및 정렬 기준 안내 메시지 추가. 로딩 상태 및 빈 리스트 처리 개선.
src/pages/support/SupportPage.jsx HaveToLoginModal 컴포넌트 경로를 절대 경로에서 상대 경로로 변경.
src/pages/support/components/ConsumerTab.jsx topCategory 상태 추가 및 카테고리 필터링 기능 구현. 차트에 onTopCategory 콜백 전달. 추천 메시지 박스 추가 및 Swiper 캐러셀로 상품 리스트 UI 변경. 카드에 카테고리 정보 전달. CSS 클래스명 간소화 및 UI 텍스트 수정.
src/pages/support/components/ConsumptionChart.jsx onTopCategory prop 추가, 상위 카테고리 자동 선택 콜백 구현. 데이터 객체에 companyType 포함. CSS 클래스명 간소화.
src/pages/support/components/HaveToLoginModal.jsx 로그인 유도 모달 컴포넌트 신규 추가. 메시지, 로그인 버튼, 닫기 버튼 포함. react-router-domuseNavigate 사용해 로그인 페이지 이동 처리.
src/pages/support/constants/consumerMap.js "예비" → "예비형"으로 키 및 값 변경. 신규 RECOMMEND_MESSAGE_MAP 추가하여 카테고리별 추천 메시지 매핑.
tailwind.config.js supportMessage 이름의 선형 그라데이션 컬러 추가.
src/pages/join/components/GoHome.jsx, LocationStep.jsx, NameStep.jsx, OwnerStep.jsx, ProfileImageStep.jsx 여러 컴포넌트에서 CSS 클래스명 text- 접두사 제거 및 폰트 굵기 클래스 삭제하여 간소화.
src/pages/kakaoAuth/kakaoAuth.jsx, src/pages/map/MapPage.jsx, src/pages/map/components/CategoryBar.jsx, IntroModal.jsx, PlaceContent.jsx, src/pages/search/SearchPage.jsx, PlaceCard.jsx, SearchPlaceList.jsx, story/components/carousel/StoryCarousel.jsx 다양한 컴포넌트 내 텍스트 관련 CSS 클래스명에서 text- 접두사 제거 및 불필요한 폰트 굵기 클래스 삭제 등 스타일링 클래스명 일괄 간소화.

Possibly related PRs

Suggested reviewers

  • dbstj0403
    """

Tip

⚡️ Faster reviews with caching
  • CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.

Enjoy the performance boost—your workflow just got faster.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56770e0 and bf23be4.

📒 Files selected for processing (9)
  • src/pages/join/components/LocationStep.jsx (6 hunks)
  • src/pages/join/components/OwnerStep.jsx (1 hunks)
  • src/pages/join/components/ProfileImageStep.jsx (1 hunks)
  • src/pages/map/MapPage.jsx (1 hunks)
  • src/pages/map/components/CategoryBar.jsx (1 hunks)
  • src/pages/map/components/PlaceContent.jsx (5 hunks)
  • src/pages/search/SearchPage.jsx (1 hunks)
  • src/pages/support/SupportPage.jsx (1 hunks)
  • tailwind.config.js (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • src/pages/join/components/OwnerStep.jsx
  • src/pages/search/SearchPage.jsx
  • src/pages/map/MapPage.jsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/pages/join/components/ProfileImageStep.jsx
  • src/pages/support/SupportPage.jsx
  • src/pages/map/components/CategoryBar.jsx
  • src/pages/join/components/LocationStep.jsx
  • src/pages/map/components/PlaceContent.jsx
  • tailwind.config.js
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (5)
src/pages/support/components/HaveToLoginModal.jsx (1)

1-55: 필요한 특성들이 모두 구현된 잘 작성된 모달 컴포넌트입니다.

로그인 요구 모달 컴포넌트가 명확하게 구현되어 있으며, props를 통한 유연한 설정이 가능합니다. 다만 몇 가지 개선 사항을 제안합니다:

  1. 접근성 향상을 위한 ARIA 속성 추가
  2. 키보드 이벤트 처리 (예: Escape 키로 모달 닫기)
  3. 로그인 경로 하드코딩 대신 기본값이 있는 prop으로 받기

모달의 접근성을 향상시키기 위해 다음과 같은 변경사항을 적용해보세요:

  <div 
-   className="fixed inset-0 z-[10001] flex justify-center items-center bg-black bg-opacity-30">
+   className="fixed inset-0 z-[10001] flex justify-center items-center bg-black bg-opacity-30"
+   role="dialog" 
+   aria-modal="true"
+   onKeyDown={(e) => e.key === 'Escape' && onClose()}>

그리고 로그인 경로를 더 유연하게 만들기 위해:

const HaveToLoginModal = ({
  message,
  subMessage,
  onClose,
  showButton = true,
  showClose = true,
+  loginPath = "/auth",
}) => {
  const navigate = useNavigate();

  const handleLogin = () => {
    onClose();
-   navigate("/auth");
+   navigate(loginPath);
  };
src/pages/support/SupportPage.jsx (1)

67-77: 조건부 렌더링이 명확하게 처리되었습니다.

로그인 상태에 따른 컴포넌트 렌더링 로직이 적절히 구현되어 있습니다. 사용자가 로그인하지 않은 경우 ConsumerTab 대신 HaveToLoginModal을 표시하고, 로그인 상태 확인 중에는 아무것도 표시하지 않습니다.

로딩 상태(isLoggedIn이 null일 때)에 대한 처리를 개선할 수 있습니다:

{category === "consumer" &&
-  (isLoggedIn === null ? null : isLoggedIn ? (
+  (isLoggedIn === null ? (
+    <div className="flex justify-center items-center h-64">
+      <p className="text-gray-6">로그인 상태 확인 중...</p>
+    </div>
+  ) : isLoggedIn ? (
    <ConsumerTab />
  ) : (
    <HaveToLoginModal
      message="로그인이 필요한 기능입니다"
      subMessage="소비 가치 확인을 위해 로그인해주세요"
      showButton
      onClose={() => handleTabChange("company")}
    />
  ))}
src/pages/support/components/RecommendationCard.jsx (1)

34-46: 카테고리 표시 로직이 개선되었습니다.

상품 유형과 카테고리 표시 로직이 향상되었으나, FinancialProductDetailPage와 마찬가지로 세 필드가 모두 존재하는 경우에만 표시됩니다. 일부 상품에는 모든 필드가 없을 수 있습니다.

제안사항: 가능한 경우 조건부 로직을 보다 유연하게 만들어 일부 필드만 있는 경우에도 해당 정보를 표시하는 것이 좋습니다.

-{productType && recommendedCategory && defaultCategory && (
+{(productType || recommendedCategory || defaultCategory) && (
   <>
-    <span className="text-caption2 font-medium text-error bg-errorContainer px-2 py-1 rounded">
-      {productType}
-    </span>
-    <span className="text-caption2 font-medium text-secondary bg-secondaryBackground px-2 py-1 rounded">
-      {recommendedCategory}
-    </span>
-    <span className="text-caption2 font-medium text-secondary bg-secondaryBackground px-2 py-1 rounded">
-      {defaultCategory}
-    </span>
+    {productType && (
+      <span className="text-caption2 font-medium text-error bg-errorContainer px-2 py-1 rounded">
+        {productType}
+      </span>
+    )}
+    {recommendedCategory && (
+      <span className="text-caption2 font-medium text-secondary bg-secondaryBackground px-2 py-1 rounded">
+        {recommendedCategory}
+      </span>
+    )}
+    {defaultCategory && (
+      <span className="text-caption2 font-medium text-secondary bg-secondaryBackground px-2 py-1 rounded">
+        {defaultCategory}
+      </span>
+    )}
   </>
 )}
src/pages/support/components/ConsumerTab.jsx (1)

24-31: 카테고리 기반 필터링 로직 추가

소비 패턴 기반으로 금융 상품을 필터링하는 로직을 구현했습니다. 선택된 topCategory가 있을 경우 각 상품의 recommendedCategory 또는 defaultCategory와 일치하는지 확인합니다.

성능 최적화를 위해 useMemo를 사용하여 filteredProducts를 메모이제이션하는 것이 좋을 것 같습니다.

- const filteredProducts = topCategory
-   ? safeProducts.filter(
-       (item) =>
-         item.recommendedCategory === ENUM_TO_KOR_MAP[topCategory] ||
-         item.defaultCategory === ENUM_TO_KOR_MAP[topCategory]
-     )
-   : safeProducts;
+ const filteredProducts = useMemo(() => {
+   return topCategory
+     ? safeProducts.filter(
+         (item) =>
+           item.recommendedCategory === ENUM_TO_KOR_MAP[topCategory] ||
+           item.defaultCategory === ENUM_TO_KOR_MAP[topCategory]
+       )
+     : safeProducts;
+ }, [safeProducts, topCategory, ENUM_TO_KOR_MAP]);
src/pages/support/FinancialProductListPage.jsx (1)

83-96: RecommendationCard에 카테고리 props 추가

RecommendationCard 컴포넌트에 recommendedCategory와 defaultCategory props를 전달합니다. 이를 통해 카드 컴포넌트가 카테고리 정보를 활용할 수 있습니다.

map 함수에서 사용되지 않는 두 번째 인자는 제거하거나 명확한 이름을 사용하는 것이 좋습니다.

- {safeProducts.map((item) => (
+ {safeProducts.map((item) => (

또는

- {safeProducts.map((item, _) => (
+ {safeProducts.map((item, index) => (
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f40239 and ae33c8e.

⛔ Files ignored due to path filters (1)
  • public/svgs/support/consumer/Ic_Alert.svg is excluded by !**/*.svg
📒 Files selected for processing (8)
  • src/pages/support/FinancialProductDetailPage.jsx (1 hunks)
  • src/pages/support/FinancialProductListPage.jsx (3 hunks)
  • src/pages/support/SupportPage.jsx (1 hunks)
  • src/pages/support/components/ConsumerTab.jsx (5 hunks)
  • src/pages/support/components/ConsumptionChart.jsx (4 hunks)
  • src/pages/support/components/HaveToLoginModal.jsx (1 hunks)
  • src/pages/support/components/RecommendationCard.jsx (2 hunks)
  • src/pages/support/constants/consumerMap.js (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/pages/support/FinancialProductListPage.jsx (1)
src/components/common/Spinner.jsx (1)
  • Spinner (3-9)
🔇 Additional comments (19)
src/pages/support/constants/consumerMap.js (3)

15-15: 카테고리 이름이 일관성 있게 변경되었습니다.

"예비"에서 "예비형"으로의 변경은 다른 카테고리 명명 규칙(~형)과 일치하도록 보입니다. 이 변경은 UI 전반에 걸쳐 일관된 사용자 경험을 제공할 것입니다.


24-24: 일관된 카테고리 매핑 업데이트.

KOR_TO_ENUM_MAP에서 "예비"에서 "예비형"으로의 키 변경은 SPEECH_BUBBLE_MAP의 변경사항과 일치합니다.


33-33: 양방향 매핑이 올바르게 업데이트되었습니다.

"PRE" enum 값에 대한 한국어 이름이 "예비"에서 "예비형"으로 일관되게 변경되었습니다. 이 변경으로 KOR_TO_ENUM_MAP과 ENUM_TO_KOR_MAP 간의 양방향 매핑이 유지됩니다.

src/pages/support/FinancialProductDetailPage.jsx (1)

63-77:

Details

❓ Verification inconclusive

카테고리 표시 로직이 강화되었습니다.

상품 유형과 카테고리 표시 로직이 개선되었습니다. 이제 productType, recommendedCategory, defaultCategory 세 필드가 모두 존재해야 표시됩니다. 각 카테고리는 서로 다른 스타일로 렌더링되어 사용자가 쉽게 구분할 수 있습니다.

그러나 모든 필드가 필요하다는 조건이 너무 제한적일 수 있습니다. 일부 상품에는 세 필드 중 하나 또는 두 개만 존재할 수 있으며, 이 경우에는 아무것도 표시되지 않습니다.

다음 스크립트를 실행하여 데이터에 항상 세 필드가 모두 존재하는지 확인해보세요:


🏁 Script executed:

#!/bin/bash
# 금융 상품 데이터에서 필수 필드 존재 여부 확인

# 금융 상품 API 호출 또는 상품 데이터 파일 분석
rg -A 5 "productType|recommendedCategory|defaultCategory" --type js

Length of output: 7025


카테고리 렌더링 조건 완화 검토 요청

현재 productType, recommendedCategory, defaultCategory 세 필드가 모두 있어야만 렌더링되므로 일부 필드만 있는 상품은 UI가 비어보일 수 있습니다.
다음 위치에서 해당 로직을 사용 중입니다:

  • src/pages/support/FinancialProductDetailPage.jsx (63–77라인)
  • src/pages/support/components/RecommendationCard.jsx
  • 유사 조건: FinancialProductListPage.jsxConsumerTab.jsx

API 스펙이나 실제 데이터에서 세 필드가 항상 제공되는지 검증하거나, 아래 예시처럼 개별 필드가 존재할 때만 렌더링하도록 로직을 완화하는 방안을 검토해주세요:

- {data.productType && data.recommendedCategory && data.defaultCategory && (
-   <>
-     <span className="text-caption2 font-medium text-error bg-errorContainer px-2 py-1 rounded">
-       {data.productType}
-     </span>
-     <span className="text-caption2 font-medium text-secondary bg-secondaryBackground px-2 py-1 rounded">
-       {data.recommendedCategory}
-     </span>
-     <span className="text-caption2 font-medium text-secondary bg-secondaryBackground px-2 py-1 rounded">
-       {data.defaultCategory}
-     </span>
-   </>
- )}
+ <>
+   {data.productType && (
+     <span className="text-caption2 font-medium text-error bg-errorContainer px-2 py-1 rounded">
+       {data.productType}
+     </span>
+   )}
+   {data.recommendedCategory && (
+     <span className="text-caption2 font-medium text-secondary bg-secondaryBackground px-2 py-1 rounded">
+       {data.recommendedCategory}
+     </span>
+   )}
+   {data.defaultCategory && (
+     <span className="text-caption2 font-medium text-secondary bg-secondaryBackground px-2 py-1 rounded">
+       {data.defaultCategory}
+     </span>
+   )}
+ </>
src/pages/support/components/ConsumptionChart.jsx (4)

12-12: 컴포넌트 API가 확장되었습니다.

새로운 onTopCategory 콜백 프롭이 추가되어 부모 컴포넌트와의 상호작용이 가능해졌습니다. 이를 통해 최상위 카테고리 정보를 상위 컴포넌트로 전달할 수 있습니다.


54-54: 데이터 구조 개선.

각 데이터 항목에 companyType 필드를 추가하여 상위 컴포넌트에서 활용할 수 있게 되었습니다.


68-71: 최상위 카테고리 콜백 기능 구현.

최상위 카테고리가 존재하는 경우에만 onTopCategory 콜백을 호출하는 조건부 로직이 적절히 구현되었습니다. 이는 PR 목표에 부합하는 변경사항입니다.


85-85: 의존성 배열 적절하게 업데이트.

useEffect 의존성 배열에 onTopCategory가 추가되어 콜백이 변경될 때 효과가 적절히 재실행됩니다. 이는 React의 베스트 프랙티스를 따르는 변경입니다.

src/pages/support/components/RecommendationCard.jsx (1)

9-10: props API가 개선되었습니다.

benefit prop 대신 recommendedCategorydefaultCategory props를 추가하여 더 구체적인 카테고리 정보를 표시할 수 있게 되었습니다. 이는 FinancialProductDetailPage와의 일관성을 유지합니다.

src/pages/support/components/ConsumerTab.jsx (6)

9-9: 새로운 상수 맵 ENUM_TO_KOR_MAP 추가

언어 상수 매핑을 위한 ENUM_TO_KOR_MAP을 import하여 카테고리 변환에 활용하고 있습니다. 이 상수를 통해 리뷰의 companyType을 한국어 카테고리명으로 변환하는 것으로 보입니다.


12-12: 상태 추가: topCategory

사용자의 소비 패턴에서 상위 카테고리를 추적하기 위한 상태를 추가했습니다. 이 상태는 ConsumptionChart에서 가장 많은 비율을 차지하는 카테고리를 저장하는 데 사용됩니다.


22-23: 배열 안전 처리

consumerProducts가 배열인지 확인하고 안전하게 처리하는 코드를 추가했습니다. API 응답이 예상과 다를 경우 오류를 방지하는 데 도움이 됩니다.


50-50: ConsumptionChart에 onTopCategory prop 추가

ConsumptionChart 컴포넌트에 onTopCategory prop을 전달하여 사용자의 소비 패턴에서 최상위 카테고리를 설정할 수 있게 했습니다. 이를 통해 차트 컴포넌트가 부모 컴포넌트의 상태를 업데이트할 수 있습니다.


67-67: filteredProducts를 사용하도록 변경

기존 safeProducts 대신 필터링된 상품 목록인 filteredProducts를 사용하도록 변경했습니다. 이는 사용자의 소비 패턴에 맞는 상품만 표시하기 위한 변경입니다.


77-79: RecommendationCard에 카테고리 props 추가

RecommendationCard 컴포넌트에 recommendedCategory와 defaultCategory props를 전달합니다. 이를 통해 카드 컴포넌트가 카테고리 정보를 활용할 수 있습니다.

이 props가 RecommendationCard 컴포넌트에서 올바르게 활용되는지 확인하세요.

src/pages/support/FinancialProductListPage.jsx (4)

6-7: API와 상수 맵 import 추가

리뷰 수에 따라 상품을 정렬하기 위해 소비 데이터를 가져오는 API와 카테고리 매핑을 위한 상수를 추가했습니다. 이는 금융 상품을 리뷰 수에 따라 정렬하는 기능을 지원합니다.


13-14: 정렬된 상품 목록을 위한 상태 추가

리뷰 수에 따라 정렬된 상품 목록을 저장하기 위한 상태를 추가했습니다. 이를 통해 사용자에게 더 관련성 높은 상품을 먼저 표시할 수 있습니다.


60-60: 정렬된 상품 배열 안전 처리

sortedProducts가 배열인지 확인하고 안전하게 처리하는 코드를 추가했습니다. API 응답이 예상과 다를 경우 오류를 방지하는 데 도움이 됩니다.


74-77: 정렬 기준 안내 메시지 추가

사용자에게 상품이 리뷰 수에 따라 정렬되었음을 알리는 메시지를 추가했습니다. 이는 좋은 UX 관행으로 사용자가 정렬 기준을 이해하는 데 도움이 됩니다.

import ConsumerTab from "@/pages/support/components/ConsumerTab";
import HaveToLoginModal from "@components/common/HaveToLoginModal";
import { getMyProfile } from "@apis/member/auth";
import HaveToLoginModal from "./components/HaveToLoginModal";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

HaveToLoginModal 컴포넌트 경로 변경이 적절히 이루어졌습니다.

컴포넌트의 위치가 공용 디렉토리에서 지원 페이지 전용 디렉토리로 이동된 것으로 보입니다. 이는 해당 모달이 지원 페이지에서만 사용된다는 의도를 명확히 합니다.


🏁 Script executed:

#!/bin/bash
# 다른 파일에서 이전 경로의 HaveToLoginModal import 문이 있는지 확인
rg "@components/common/HaveToLoginModal" --type js --type jsx

Length of output: 89


🏁 Script executed:

#!/bin/bash
# 다른 파일에서 이전 경로의 HaveToLoginModal import 문이 있는지 재확인
rg "@components/common/HaveToLoginModal" -g '*.js' -g '*.jsx'

Length of output: 366


HaveToLoginModal 경로 일괄 업데이트 필요

지원 페이지 외 다른 파일들이 아직 이전 @components/common/HaveToLoginModal 경로를 참조하고 있어, 빌드 에러가 발생할 수 있습니다. 아래 파일들의 import 문을 새로운 위치(예: ../support/components/HaveToLoginModal)로 변경해 주세요.

• src/pages/search/SearchPage.jsx

- import HaveToLoginModal from "@components/common/HaveToLoginModal";
+ import HaveToLoginModal from "../support/components/HaveToLoginModal";

• src/pages/story/components/StoryDetail.jsx

- import HaveToLoginModal from "@components/common/HaveToLoginModal";
+ import HaveToLoginModal from "../../support/components/HaveToLoginModal";

• src/pages/map/MapPage.jsx

- import HaveToLoginModal from "@components/common/HaveToLoginModal";
+ import HaveToLoginModal from "../support/components/HaveToLoginModal";

위와 같이 모든 참조를 일관되게 업데이트한 후 다시 검증 부탁드립니다.

Committable suggestion skipped: line range outside the PR's diff.

</div>

{isLoading && <Spinner />}
{(isLoading || safeProducts.length === 0) && <Spinner />}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

로딩 상태 처리 개선

로딩 상태 확인 조건을 수정하여 isLoading이 true이거나 safeProducts가 비어 있을 때 스피너를 표시합니다. 그러나 이 조건은 실제로 상품이 없는 경우와 로딩 중인 경우를 구분하지 못합니다.

- {(isLoading || safeProducts.length === 0) && <Spinner />}
+ {isLoading ? (
+   <Spinner />
+ ) : (
+   safeProducts.length === 0 && (
+     <div className="w-full py-8 text-center text-gray-7">
+       표시할 금융 상품이 없습니다.
+     </div>
+   )
+ )}

Comment on lines +15 to +58
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]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

상품 정렬 로직 구현

리뷰 수에 따라 금융 상품을 정렬하는 로직을 useEffect 내에 구현했습니다. 고유한 카테고리를 추출하고 각 카테고리의 리뷰 수를 가져온 다음, 이 데이터를 기반으로 상품을 정렬합니다.

몇 가지 개선 사항이 있습니다:

  1. API 호출 실패 시 에러 로깅이나 사용자 피드백이 없습니다.
  2. 중복 API 호출을 최소화하기 위한 캐싱 메커니즘이 없습니다.
 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();
+    // 로컬 스토리지를 통한 간단한 캐싱 구현
+    const cachedReviewCounts = localStorage.getItem('categoryReviewCounts');
+    const cachedData = cachedReviewCounts ? JSON.parse(cachedReviewCounts) : {};
+    const cacheTimestamp = localStorage.getItem('categoryReviewCountsTimestamp');
+    const isCacheValid = cacheTimestamp && (Date.now() - parseInt(cacheTimestamp)) < 3600000; // 1시간 캐시

     await Promise.all(
       [...uniqueCategories].map(async (korName) => {
         const enumKey = KOR_TO_ENUM_MAP[korName];
         if (!enumKey) return;

+        // 유효한 캐시가 있으면 사용
+        if (isCacheValid && cachedData[korName] !== undefined) {
+          reviewCountMap.set(korName, cachedData[korName]);
+          return;
+        }

         try {
           const res = await getConsumptionDetail(enumKey);
           reviewCountMap.set(korName, res?.reviewCount || 0);
+          // 캐시 업데이트
+          cachedData[korName] = res?.reviewCount || 0;
         } catch (error) {
+          console.error(`카테고리 ${korName}의 리뷰 수를 가져오는 중 오류 발생:`, error);
           reviewCountMap.set(korName, 0);
+          // 캐시에 0 설정
+          cachedData[korName] = 0;
         }
       })
     );

+    // 캐시 저장
+    localStorage.setItem('categoryReviewCounts', JSON.stringify(cachedData));
+    localStorage.setItem('categoryReviewCountsTimestamp', Date.now().toString());

     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]);

Committable suggestion skipped: line range outside the PR's diff.

@shroqkf shroqkf changed the title Feature/#64/support consumer [Feat] 소비자 소비 유형 기반 맞춤 금융상품 추천 필터링 로직 구현 May 9, 2025
@dbstj0403
Copy link
Collaborator

저.. 는 왜 이렇게 뜰까요??

스크린샷 2025-05-09 오후 5 26 43

@dbstj0403
Copy link
Collaborator

금융 상품 정렬 페이지에 리뷰 건수가 많은 순서대로 정렬되어 있다고 하는 멘트가 좀 이해하기 어려운 것 같아요! 금융상품에 사용자들이 리뷰를 달았다는 건가..? 싶을 것 같아서 좀더 명확한 멘트로 변경하는 것이 좋을 것 같습니다.

@dbstj0403
Copy link
Collaborator

마찬가지로 여기에 붙은 태그들이 본래 사회적 기업 유형이다 보니.. 이런 곳에 소비를 한 사람에게 추천하는 금융상품이다 를 명확하게 하는 디자인 혹은 기획 수정이 필요할 듯 하네요..!! 사회적 기업 유형에 대한 숙지가 보통 잘 안되어 있을 텐데, 이런 태그들을 금융 상품에 붙이면 혼동이 좀 올 것 같고 질문 공격으로도 들어올 수 있어보여요 🥹

스크린샷 2025-05-09 오후 5 28 43

@shroqkf shroqkf self-assigned this May 12, 2025
@shroqkf shroqkf added Feat Improvements or additions to documentation Design This doesn't seem right labels May 12, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/pages/support/FinancialProductListPage.jsx (1)

97-97: 🛠️ Refactor suggestion

로딩 상태 처리 개선 필요

로딩 상태와 데이터 없음 상태를 구분하지 않고 있어, 사용자가 실제로 상품이 없는 것인지 아직 로딩 중인 것인지 알 수 없습니다.

로딩 상태와 데이터 없음 상태를 명확히 구분하여 표시하는 것이 좋습니다:

- {(isLoading || safeProducts.length === 0) && <Spinner />}
+ {isLoading ? (
+   <Spinner />
+ ) : (
+   safeProducts.length === 0 && (
+     <div className="w-full py-8 text-center text-gray-7">
+       표시할 금융 상품이 없습니다.
+     </div>
+   )
+ )}
🧹 Nitpick comments (2)
src/pages/support/FinancialProductListPage.jsx (2)

30-73: 리뷰 수에 따른 금융 상품 정렬 로직

소비 유형별 리뷰 수에 따라 금융 상품을 정렬하는 기능이 구현되었습니다. 다만, 몇 가지 개선할 수 있는 부분이 있습니다:

  1. API 호출 실패 시 사용자에게 피드백을 제공하지 않고 있습니다.
  2. 카테고리별 리뷰 수를 캐싱하는 메커니즘이 없어 성능 이슈가 발생할 수 있습니다.

리뷰 수 데이터를 캐싱하여 성능을 개선할 수 있습니다:

 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();
+    // 로컬 스토리지를 통한 간단한 캐싱 구현
+    const cachedReviewCounts = localStorage.getItem('categoryReviewCounts');
+    const cachedData = cachedReviewCounts ? JSON.parse(cachedReviewCounts) : {};
+    const cacheTimestamp = localStorage.getItem('categoryReviewCountsTimestamp');
+    const isCacheValid = cacheTimestamp && (Date.now() - parseInt(cacheTimestamp)) < 3600000; // 1시간 캐시

     await Promise.all(
       [...uniqueCategories].map(async (korName) => {
         const enumKey = KOR_TO_ENUM_MAP[korName];
         if (!enumKey) return;

+        // 유효한 캐시가 있으면 사용
+        if (isCacheValid && cachedData[korName] !== undefined) {
+          reviewCountMap.set(korName, cachedData[korName]);
+          return;
+        }

         try {
           const res = await getConsumptionDetail(enumKey);
           reviewCountMap.set(korName, res?.reviewCount || 0);
+          // 캐시 업데이트
+          cachedData[korName] = res?.reviewCount || 0;
         } catch (error) {
+          console.error(`카테고리 ${korName}의 리뷰 수를 가져오는 중 오류 발생:`, error);
           reviewCountMap.set(korName, 0);
+          // 캐시에 0 설정
+          cachedData[korName] = 0;
         }
       })
     );

+    // 캐시 저장
+    localStorage.setItem('categoryReviewCounts', JSON.stringify(cachedData));
+    localStorage.setItem('categoryReviewCountsTimestamp', Date.now().toString());

     // 나머지 코드는 동일...

89-94: 맞춤형 상품 정렬 메시지 추가

사용자 이름을 활용한 맞춤형 메시지를 추가하여 사용자 경험을 개선했습니다. 다만, PR 코멘트에서 언급된 것처럼 이 메시지가 명확하지 않을 수 있습니다.

메시지를 더 명확하게 수정하는 것이 좋을 것 같습니다:

 <p className="caption2 text-primary-8">
-  {userName}님이 리뷰를 남긴 기업 특성과 연관된 금융상품 순으로
-  보여드려요!
+  {userName}님의 소비 패턴과 관련성이 높은 금융상품을 우선적으로
+  보여드립니다!
 </p>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae33c8e and 8dd74c1.

⛔ Files ignored due to path filters (1)
  • public/svgs/support/consumer/Ic_SupportMessage.svg is excluded by !**/*.svg
📒 Files selected for processing (5)
  • src/pages/support/FinancialProductListPage.jsx (3 hunks)
  • src/pages/support/components/ConsumerTab.jsx (4 hunks)
  • src/pages/support/components/RecommendationCard.jsx (3 hunks)
  • src/pages/support/constants/consumerMap.js (3 hunks)
  • tailwind.config.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tailwind.config.js
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/pages/support/components/ConsumerTab.jsx
  • src/pages/support/components/RecommendationCard.jsx
  • src/pages/support/constants/consumerMap.js
🔇 Additional comments (5)
src/pages/support/FinancialProductListPage.jsx (5)

6-8: API 임포트 추가

getConsumptionDetail과 getMyProfile API를 추가하여 소비 유형과 사용자 정보를 가져오는 기능이 구현되었습니다. KOR_TO_ENUM_MAP도 추가하여 한글 카테고리명과 enum 값을 매핑하는 기능이 추가되었습니다.


13-14: 사용자 이름 상태 변수 추가

사용자 이름을 저장하기 위한 상태 변수가 추가되었습니다. 이는 맞춤형 메시지를 표시하는 데 사용될 예정입니다.


15-26: 사용자 프로필 데이터 가져오기

컴포넌트 마운트 시 사용자 프로필을 비동기적으로 가져오는 로직이 구현되었습니다. 오류 처리도 적절히 되어 있습니다.


28-29: 정렬된 상품 목록을 위한 상태 변수 추가

리뷰 수에 따라 정렬된 금융 상품 목록을 저장하기 위한 상태 변수가 추가되었습니다.


101-113: RecommendationCard에 카테고리 정보 전달

금융 상품 카드에 카테고리 정보를 전달하여 PR 목표인 "소비자 소비 유형 기반 맞춤 금융상품 추천 필터링 로직"을 구현하였습니다. 이를 통해 사용자의 소비 패턴에 맞는 금융 상품을 추천할 수 있게 되었습니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/pages/support/FinancialProductListPage.jsx (2)

30-73: 🛠️ Refactor suggestion

카테고리 리뷰 기반 정렬 로직 성능 및 안정성 개선 필요

상품 정렬 로직이 잘 구현되었지만, 몇 가지 개선 사항이 있습니다:

  1. API 호출 결과를 캐싱하지 않아 불필요한 네트워크 요청이 발생할 수 있습니다.
  2. API 호출 에러에 대한 사용자 피드백이 없습니다.
  3. 카테고리가 많은 경우 병렬 API 요청이 많아질 수 있으므로 제한이 필요할 수 있습니다.

다음과 같이 캐싱과 에러 처리를 개선할 수 있습니다:

  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();
+     // 로컬 스토리지를 통한 간단한 캐싱 구현
+     const cachedReviewCounts = localStorage.getItem('categoryReviewCounts');
+     const cachedData = cachedReviewCounts ? JSON.parse(cachedReviewCounts) : {};
+     const cacheTimestamp = localStorage.getItem('categoryReviewCountsTimestamp');
+     const isCacheValid = cacheTimestamp && (Date.now() - parseInt(cacheTimestamp)) < 3600000; // 1시간 캐시

      await Promise.all(
        [...uniqueCategories].map(async (korName) => {
          const enumKey = KOR_TO_ENUM_MAP[korName];
          if (!enumKey) return;

+         // 유효한 캐시가 있으면 사용
+         if (isCacheValid && cachedData[korName] !== undefined) {
+           reviewCountMap.set(korName, cachedData[korName]);
+           return;
+         }

          try {
            const res = await getConsumptionDetail(enumKey);
            reviewCountMap.set(korName, res?.reviewCount || 0);
+           // 캐시 업데이트
+           cachedData[korName] = res?.reviewCount || 0;
          } catch (error) {
+           console.error(`카테고리 ${korName}의 리뷰 수를 가져오는 중 오류 발생:`, error);
            reviewCountMap.set(korName, 0);
+           // 캐시에 0 설정
+           cachedData[korName] = 0;
          }
        })
      );

+     // 캐시 저장
+     localStorage.setItem('categoryReviewCounts', JSON.stringify(cachedData));
+     localStorage.setItem('categoryReviewCountsTimestamp', Date.now().toString());

      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]);

99-99: 🛠️ Refactor suggestion

로딩 상태 처리 개선 필요

로딩 상태 확인 조건을 수정하여 isLoading이 true이거나 safeProducts가 비어 있을 때 스피너를 표시합니다. 그러나 이 조건은 실제로 상품이 없는 경우와 로딩 중인 경우를 구분하지 못합니다.

- {(isLoading || safeProducts.length === 0) && <Spinner />}
+ {isLoading ? (
+   <Spinner />
+ ) : (
+   safeProducts.length === 0 && (
+     <div className="w-full py-8 text-center text-gray-7">
+       표시할 금융 상품이 없습니다.
+     </div>
+   )
+ )}
🧹 Nitpick comments (1)
src/pages/support/FinancialProductListPage.jsx (1)

15-26: 사용자 프로필 가져오기 로직 개선 필요

프로필 정보를 가져오는 로직이 잘 구현되었지만, 로딩 상태를 표시하는 부분이 없습니다. 또한 사용자 경험을 위해 Suspense나 ErrorBoundary 등을 활용하여 좀 더 견고한 에러 처리를 구현하는 것이 좋겠습니다.

다음과 같이 로딩 상태를 추가하고 에러 처리를 개선할 수 있습니다:

  const [userName, setUserName] = useState("");
+ const [profileLoading, setProfileLoading] = useState(false);

  useEffect(() => {
    const fetchProfile = async () => {
+     setProfileLoading(true);
      try {
        const res = await getMyProfile();
        setUserName(res?.name || "사용자");
      } catch (e) {
        console.error("프로필 로딩 실패:", e);
+       // 사용자에게 에러를 표시하는 로직 추가 가능
      } finally {
+       setProfileLoading(false);
      }
    };

    fetchProfile();
  }, []);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8dd74c1 and d0f8f27.

📒 Files selected for processing (2)
  • src/pages/support/FinancialProductListPage.jsx (3 hunks)
  • src/pages/support/components/ConsumerTab.jsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/pages/support/components/ConsumerTab.jsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/pages/support/FinancialProductListPage.jsx (2)
src/pages/support/constants/consumerMap.js (2)
  • KOR_TO_ENUM_MAP (27-34)
  • KOR_TO_ENUM_MAP (27-34)
src/components/common/Spinner.jsx (1)
  • Spinner (3-9)
🔇 Additional comments (4)
src/pages/support/FinancialProductListPage.jsx (4)

1-1: 필요한 API 및 유틸리티 추가가 잘 되었습니다.

소비자 소비 유형 기반 추천 필터링을 위한 필수 기능들을 적절히 가져왔습니다.

Also applies to: 5-8


13-14: 상태 관리 로직이 잘 설계되었습니다.

사용자 이름과 정렬된 상품 목록을 위한 상태 변수들이 명확하게 정의되었습니다.

Also applies to: 28-29


75-75: 방어적 프로그래밍이 잘 적용되었습니다.

정렬된 상품이 항상 배열로 처리되도록 하는 안전장치가 적절히 구현되었습니다.


103-115: RecommendationCard 컴포넌트 props 전달이 잘 수정되었습니다.

recommendedCategory와 defaultCategory props를 적절히 전달하여 카테고리 기반 필터링과 표시를 지원합니다.

Comment on lines 89 to 96
<div className="flex items-center justify-between mt-10">
<p className="text-b5 font-medium text-gray-9">
총 {safeProducts.length}개
</p>
<p className="text-caption2 text-primary-8 text-right">
{userName}님이 리뷰를 남긴 기업 특성과
<br /> 연관된 금융상품 순으로 보여드려요!
</p>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

사용자 피드백 메시지 개선 필요

사용자 이름을 활용한 개인화된 메시지가 잘 구현되었습니다. 다만, "리뷰를 남긴 기업 특성과 연관된 금융상품 순으로 보여드려요"라는 문구가 사용자에게 명확하지 않을 수 있습니다. 특히 PR 코멘트에 언급된 바와 같이, 사용자들이 소셜 엔터프라이즈 유형 태그를 혼동할 수 있습니다.

다음과 같이 좀 더 명확한 메시지로 개선할 수 있습니다:

  <p className="text-caption2 text-primary-8 text-right">
-   {userName}님이 리뷰를 남긴 기업 특성과
-   <br /> 연관된 금융상품 순으로 보여드려요!
+   {userName}님의 소비 패턴에 맞춰
+   <br /> 추천 금융상품을 보여드려요!
  </p>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="flex items-center justify-between mt-10">
<p className="text-b5 font-medium text-gray-9">
{safeProducts.length}
</p>
<p className="text-caption2 text-primary-8 text-right">
{userName}님이 리뷰를 남긴 기업 특성과
<br /> 연관된 금융상품 순으로 보여드려요!
</p>
<div className="flex items-center justify-between mt-10">
<p className="text-b5 font-medium text-gray-9">
{safeProducts.length}
</p>
<p className="text-caption2 text-primary-8 text-right">
{userName}님의 소비 패턴에 맞춰
<br /> 추천 금융상품을 보여드려요!
</p>

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
src/pages/map/components/PlaceContent.jsx (1)

170-172: ⚠️ Potential issue

잘못된 아이콘이 사용되고 있습니다.

전화번호를 표시하는데 위치 아이콘(Ic_Location.svg)이 사용되고 있습니다. 전화번호에 맞는 아이콘으로 변경하는 것이 좋습니다.

            <img
-              src="/svgs/map/Ic_Location.svg"
+              src="/svgs/map/Ic_Phone.svg"
              alt="기업 전화번호"
              className="w-5 h-5"
            />
♻️ Duplicate comments (3)
src/pages/support/FinancialProductListPage.jsx (3)

28-73: 🛠️ Refactor suggestion

상품 정렬 로직 개선 필요

소비 유형에 따른 상품 정렬 로직이 잘 구현되었습니다. 그러나 몇 가지 개선점이 있습니다:

  1. API 호출 실패 시 사용자 피드백이 없습니다
  2. 중복 API 호출을 최소화하기 위한 캐싱 메커니즘이 없습니다
  3. 각 카테고리별 API 호출이 많아질 경우 성능 이슈가 발생할 수 있습니다
  const [sortedProducts, setSortedProducts] = useState([]);
+ const [isSorting, setIsSorting] = useState(false);

  useEffect(() => {
    const sortProductsByReviewCount = async () => {
      if (!products || products.length === 0) return;
+     setIsSorting(true);

      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();
+     // 로컬 스토리지를 통한 간단한 캐싱 구현
+     const cachedReviewCounts = localStorage.getItem('categoryReviewCounts');
+     const cachedData = cachedReviewCounts ? JSON.parse(cachedReviewCounts) : {};
+     const cacheTimestamp = localStorage.getItem('categoryReviewCountsTimestamp');
+     const isCacheValid = cacheTimestamp && (Date.now() - parseInt(cacheTimestamp)) < 3600000; // 1시간 캐시

      await Promise.all(
        [...uniqueCategories].map(async (korName) => {
          const enumKey = KOR_TO_ENUM_MAP[korName];
          if (!enumKey) return;

+         // 유효한 캐시가 있으면 사용
+         if (isCacheValid && cachedData[korName] !== undefined) {
+           reviewCountMap.set(korName, cachedData[korName]);
+           return;
+         }

          try {
            const res = await getConsumptionDetail(enumKey);
            reviewCountMap.set(korName, res?.reviewCount || 0);
+           // 캐시 업데이트
+           cachedData[korName] = res?.reviewCount || 0;
          } catch (error) {
+           console.error(`카테고리 ${korName}의 리뷰 수를 가져오는 중 오류 발생:`, error);
            reviewCountMap.set(korName, 0);
+           // 캐시에 0 설정
+           cachedData[korName] = 0;
          }
        })
      );

+     // 캐시 저장
+     localStorage.setItem('categoryReviewCounts', JSON.stringify(cachedData));
+     localStorage.setItem('categoryReviewCountsTimestamp', Date.now().toString());

      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);
+     setIsSorting(false);
    };

    sortProductsByReviewCount();
  }, [products]);

89-96: 🛠️ Refactor suggestion

사용자 피드백 메시지 개선 필요

사용자 이름을 활용한 개인화된 메시지가 잘 구현되었습니다. 다만, "리뷰를 남긴 기업 특성과 연관된 금융상품 순으로 보여드려요"라는 문구가 사용자에게 명확하지 않을 수 있습니다. 특히 PR 코멘트에 언급된 바와 같이, 사용자들이 소셜 엔터프라이즈 유형 태그를 혼동할 수 있습니다.

  <p className="caption2 text-primary-8 text-right">
-   {userName}님이 리뷰를 남긴 기업 특성과
-   <br /> 연관된 금융상품 순으로 보여드려요!
+   {userName}님의 소비 패턴에 맞춰
+   <br /> 추천 금융상품을 보여드려요!
  </p>

99-99: 🛠️ Refactor suggestion

로딩 상태 처리 개선

로딩 상태 확인 조건을 수정하여 isLoading이 true이거나 safeProducts가 비어 있을 때 스피너를 표시합니다. 그러나 이 조건은 실제로 상품이 없는 경우와 로딩 중인 경우를 구분하지 못합니다.

- {(isLoading || safeProducts.length === 0) && <Spinner />}
+ {isLoading ? (
+   <Spinner />
+ ) : (
+   safeProducts.length === 0 && (
+     <div className="w-full py-8 text-center text-gray-7">
+       표시할 금융 상품이 없습니다.
+     </div>
+   )
+ )}
🧹 Nitpick comments (1)
src/pages/support/FinancialProductListPage.jsx (1)

13-26: 사용자 프로필 로딩 로직이 잘 구현되었습니다.

사용자 이름을 가져오는 로직이 적절하게 구현되어 있으며, 오류 처리와 기본값 설정도 잘 되어 있습니다. 다만, 프로필 로딩 중에 사용자에게 보여줄 로딩 상태 표시가 없어 UX를 개선할 여지가 있습니다.

  const [userName, setUserName] = useState("");
+ const [isProfileLoading, setIsProfileLoading] = useState(false);

  useEffect(() => {
    const fetchProfile = async () => {
+     setIsProfileLoading(true);
      try {
        const res = await getMyProfile();
        setUserName(res?.name || "사용자");
      } catch (e) {
        console.error("프로필 로딩 실패:", e);
      } finally {
+       setIsProfileLoading(false);
      }
    };

    fetchProfile();
  }, []);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d0f8f27 and 56770e0.

📒 Files selected for processing (19)
  • src/pages/join/components/GoHome.jsx (2 hunks)
  • src/pages/join/components/LocationStep.jsx (6 hunks)
  • src/pages/join/components/NameStep.jsx (2 hunks)
  • src/pages/join/components/OwnerStep.jsx (1 hunks)
  • src/pages/join/components/ProfileImageStep.jsx (1 hunks)
  • src/pages/kakaoAuth/kakaoAuth.jsx (1 hunks)
  • src/pages/map/MapPage.jsx (1 hunks)
  • src/pages/map/components/CategoryBar.jsx (1 hunks)
  • src/pages/map/components/IntroModal.jsx (2 hunks)
  • src/pages/map/components/PlaceContent.jsx (5 hunks)
  • src/pages/search/SearchPage.jsx (1 hunks)
  • src/pages/search/components/PlaceCard.jsx (2 hunks)
  • src/pages/search/components/SearchPlaceList.jsx (1 hunks)
  • src/pages/story/components/carousel/StoryCarousel.jsx (1 hunks)
  • src/pages/support/FinancialProductDetailPage.jsx (3 hunks)
  • src/pages/support/FinancialProductListPage.jsx (3 hunks)
  • src/pages/support/components/ConsumerTab.jsx (4 hunks)
  • src/pages/support/components/ConsumptionChart.jsx (6 hunks)
  • src/pages/support/components/RecommendationCard.jsx (3 hunks)
✅ Files skipped from review due to trivial changes (13)
  • src/pages/kakaoAuth/kakaoAuth.jsx
  • src/pages/map/MapPage.jsx
  • src/pages/map/components/IntroModal.jsx
  • src/pages/join/components/OwnerStep.jsx
  • src/pages/search/components/SearchPlaceList.jsx
  • src/pages/map/components/CategoryBar.jsx
  • src/pages/search/SearchPage.jsx
  • src/pages/join/components/GoHome.jsx
  • src/pages/join/components/LocationStep.jsx
  • src/pages/search/components/PlaceCard.jsx
  • src/pages/join/components/ProfileImageStep.jsx
  • src/pages/join/components/NameStep.jsx
  • src/pages/story/components/carousel/StoryCarousel.jsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/pages/support/components/ConsumptionChart.jsx
  • src/pages/support/FinancialProductDetailPage.jsx
  • src/pages/support/components/RecommendationCard.jsx
  • src/pages/support/components/ConsumerTab.jsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/pages/map/components/PlaceContent.jsx (1)
src/constants/categoryMap.js (2)
  • businessTypeNameMap (32-43)
  • businessTypeNameMap (32-43)
🔇 Additional comments (7)
src/pages/support/FinancialProductListPage.jsx (2)

5-8: 새로운 의존성 추가 부분이 적절히 구현되었습니다.

API 및 상수 관련 임포트가 명확하게 추가되었습니다. 금융 상품 데이터와 사용자 프로필을 가져오는 API 함수들이 적절히 임포트되었습니다.


103-115: 카테고리 정보가 올바르게 전달되고 있습니다.

금융 상품 카드에 recommendedCategory와 defaultCategory 정보를 적절히 전달하고 있습니다. 이로써 상품 카드에서 적절한 카테고리 정보를 표시할 수 있게 되었습니다.

src/pages/map/components/PlaceContent.jsx (5)

82-90: 클래스 이름 변경이 적절하게 적용되었습니다.

스타일 리팩토링에 맞게 타이포그래피 클래스 이름이 간결하게 변경되었습니다. b4 클래스가 기존 font-weight 설정을 포함하고 있는지 확인하세요.


96-98: 클래스 이름 변경이 적절하게 적용되었습니다.

비즈니스 설명을 위한 컨테이너의 스타일링이 코드베이스의 전반적인 타이포그래피 리팩토링 방향에 맞게 업데이트되었습니다.


106-108: 클래스 이름 변경이 적절하게 적용되었습니다.

text-caption2 대신 caption2로 변경한 것이 전체 코드베이스의 타이포그래피 클래스 단순화 패턴과 일치합니다.


148-165: 클래스 이름 변경이 적절하게 적용되었습니다.

위치 정보 컨테이너의 클래스 이름이 새로운 타이포그래피 시스템에 맞게 적절히 업데이트되었습니다.


168-185: 클래스 이름 변경이 적절하게 적용되었습니다.

전화번호 정보 컨테이너의 클래스 이름이 새로운 타이포그래피 시스템에 맞게 적절히 업데이트되었습니다.

Comment on lines +73 to 80
<h3 className="h3 break-words text-gray-12">
<div className="max-w-full h3 text-gray-12 break-keep whitespace-normal mt-6">
{companyName}
<span className="ml-2 text-b5 text-gray-6 font-medium">
<span className="ml-2 b5 text-gray-6">
{businessTypeNameMap[companyCategory] ?? companyCategory}
</span>
</div>
</h3>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

HTML 구조에 중복되는 h3 및 div 태그가 있습니다.

h3 태그 안에 동일한 h3 클래스를 가진 div를 중첩시킨 것은 HTML 구조상 문제가 될 수 있습니다. 이러한 중첩은 스타일 충돌이나 예기치 않은 렌더링 결과를 초래할 수 있습니다.

아래와 같이 구조를 수정하는 것이 좋습니다:

-          <h3 className="h3 break-words text-gray-12">
-            <div className="max-w-full h3 text-gray-12 break-keep whitespace-normal mt-6">
+          <h3 className="max-w-full h3 text-gray-12 break-keep whitespace-normal mt-6">
               {companyName}
               <span className="ml-2 b5 text-gray-6">
                 {businessTypeNameMap[companyCategory] ?? companyCategory}
               </span>
-            </div>
           </h3>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<h3 className="h3 break-words text-gray-12">
<div className="max-w-full h3 text-gray-12 break-keep whitespace-normal mt-6">
{companyName}
<span className="ml-2 text-b5 text-gray-6 font-medium">
<span className="ml-2 b5 text-gray-6">
{businessTypeNameMap[companyCategory] ?? companyCategory}
</span>
</div>
</h3>
<h3 className="max-w-full h3 text-gray-12 break-keep whitespace-normal mt-6">
{companyName}
<span className="ml-2 b5 text-gray-6">
{businessTypeNameMap[companyCategory] ?? companyCategory}
</span>
</h3>

@dbstj0403 dbstj0403 merged commit 6f462c4 into develop May 14, 2025
4 checks passed
@dbstj0403 dbstj0403 deleted the feature/#64/support-consumer branch May 14, 2025 11:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Design This doesn't seem right Feat Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants