Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 기업상세정보 ui구현 #84

Merged
merged 8 commits into from
Dec 23, 2024
Merged

feat: 기업상세정보 ui구현 #84

merged 8 commits into from
Dec 23, 2024

Conversation

cindycho0423
Copy link
Collaborator

@cindycho0423 cindycho0423 commented Dec 22, 2024

#️⃣ 이슈

📝 작업 내용

이번 PR에서 작업한 내용을 간략히 설명해주세요.

  • ui만 구현했습니다,,

📸 스크린샷

✅ 체크 리스트

  • 적절한 Title 작성
  • 적절한 Label 지정
  • Assignee 및 Reviewer 지정
  • 로컬 작동 확인
  • Merge 되는 브랜치 확인

👩‍💻 공유 포인트 및 논의 사항

자꾸 500에러 떠서 수정할 수가 없어 일단 하드코딩한채로 올립니다. api 연결하면서 수정예정입니다.

Summary by CodeRabbit

  • New Features
    • 새로운 Consensus, FinancialStatements, CompanyOverview, TargetPrice, DetailInfo, 및 RelativeNews 컴포넌트가 추가되었습니다.
    • DetailInfo 컴포넌트는 탭 인터페이스를 통해 회사 개요와 관련 뉴스를 표시합니다.
  • UI 개선
    • CSS 수정으로 다양한 레이아웃 및 스타일이 조정되었습니다.
    • globals.css에 새로운 리스트 스타일 클래스가 추가되었습니다.
  • Bug Fixes
    • 레이아웃 컴포넌트에서 높이 관련 클래스가 수정되어 UI가 개선되었습니다.

@cindycho0423 cindycho0423 added the ✨ FEAT This doesn't seem right label Dec 22, 2024
@cindycho0423 cindycho0423 requested a review from Han-wo December 22, 2024 00:39
@cindycho0423 cindycho0423 self-assigned this Dec 22, 2024
@cindycho0423 cindycho0423 linked an issue Dec 22, 2024 that may be closed by this pull request
1 task
Copy link

coderabbitai bot commented Dec 22, 2024

Walkthrough

이 풀 리퀘스트는 여러 레이아웃 및 컴포넌트에 걸쳐 UI 스타일링과 구조를 개선하는 변경 사항을 포함합니다. 주요 변경 사항은 글로벌 CSS 파일 업데이트, 다양한 레이아웃 컴포넌트의 높이 및 클래스 조정, 그리고 주식 검색 상세 페이지를 위한 새로운 컴포넌트 추가를 포함합니다.

Changes

파일 변경 요약
src/app/globals.css .list-style 클래스 추가, htmlbody에 100% 너비/높이 설정
src/app/*/layout.tsx h-screen 클래스 제거, size-full 또는 h-full 클래스로 대체
src/components/nav-bar/_components/nav-menu.tsx 네비게이션 메뉴 높이 h-screen에서 h-full로 변경
tailwind.config.ts 녹색 및 회색 색상 음영 추가
src/app/search/[id]/_components/ 새로운 상세 정보 UI 컴포넌트 추가 (CompanyOverview, Consensus, FinancialStatements, RelativeNews, TargetPrice)

Assessment against linked issues

목표 해결 여부 설명
상세정보 UI 구현

Possibly related PRs

Suggested labels

💄 DESIGN

Suggested reviewers

  • Han-wo

Poem

🐰 코드의 숲에서 춤추는 레이아웃
스크린 높이를 자유롭게 날아다녀
새로운 UI의 물결 위에
토끼의 눈빛은 반짝이네
디자인의 마법을 노래해요! 🎨

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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. (Beta)
  • @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

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: 12

🧹 Nitpick comments (6)
tailwind.config.ts (1)

54-54: gray-80 색상의 이름을 Tailwind 컨벤션에 맞게 수정해주세요.

Tailwind CSS는 색상 단계를 100 단위로 사용하는 것이 컨벤션입니다. gray-80gray-100과 비교했을 때 더 밝은 색상이므로, 이를 gray-50으로 변경하는 것이 좋겠습니다.

        gray: {
-         80: "#D9D9D9",
+         50: "#D9D9D9",
src/app/my-account/layout.tsx (1)

13-13: 공통 레이아웃 컴포넌트 도입 고려

여러 레이아웃 파일에서 동일한 스타일(lg:max-w-2000 h-full bg-[#F5F6F8])이 반복되고 있습니다. 코드 재사용성과 일관성을 위해 다음과 같은 개선을 제안드립니다:

공통 레이아웃 컴포넌트를 생성하여 스타일을 통합 관리하는 것이 좋을 것 같습니다. 예시:

// src/components/layouts/BaseLayout.tsx
export default function BaseLayout({ children }: { children: React.ReactNode }) {
  return <div className="lg:max-w-2000 h-full bg-[#F5F6F8]">{children}</div>;
}

이렇게 하면:

  1. 스타일 변경 시 한 곳에서만 수정하면 됩니다
  2. 레이아웃 일관성을 보장할 수 있습니다
  3. 코드 중복을 줄일 수 있습니다
src/app/search/[id]/_components/detail-info/relative-news/index.tsx (1)

3-26: 데이터 상태 관리 및 타입 정의가 필요합니다.

뉴스 데이터를 동적으로 처리하기 위한 구조가 필요합니다.

다음과 같은 구조를 제안드립니다:

interface NewsItem {
  title: string;
  source: string;
  date: string;
}

interface RelativeNewsProps {
  news: NewsItem[];
  isLoading?: boolean;
}

export default function RelativeNews({ news, isLoading = false }: RelativeNewsProps) {
  if (isLoading) {
    return <div>로딩 ...</div>;
  }

  if (!news.length) {
    return <div>관련 뉴스가 없습니다.</div>;
  }

  return (
    // 테이블 구현...
  );
}
src/app/search/[id]/_components/detail-info/index.tsx (1)

17-28: 탭 컨텐츠의 지연 로딩 구현을 고려해주세요.

현재 모든 탭 컨텐츠가 동시에 로드되고 있습니다. 성능 최적화를 위해 지연 로딩을 구현하는 것이 좋습니다.

import dynamic from 'next/dynamic';

const CompanyOverview = dynamic(() => import('./company-overview'), {
  loading: () => <div>로딩 ...</div>
});

const RelativeNews = dynamic(() => import('./relative-news'), {
  loading: () => <div>로딩 ...</div>
});
src/app/globals.css (1)

51-56: list-style 클래스 네이밍 및 구조 개선

  1. Tailwind 컨벤션에 맞는 네이밍으로 변경
  2. 재사용 가능한 컴포넌트로 분리 고려
-.list-style {
+.custom-list {
   list-style-type: square;
   padding-inline-start: 1.5em;
   list-style-position: inside;
   line-height: 24px;
 }
src/app/search/[id]/_components/detail-info/company-overview/financial-statements.tsx (1)

3-24: 타입 정의의 개선 가능성

타입 정의가 잘 구성되어 있으나, 몇 가지 개선 사항이 있습니다:

 type FinancialRatio = {
   stockAccountingYearMonth: string;
-  grossMarginRatio: number;
-  businessProfitRate: number;
-  netInterestRate: number;
-  roeValue: number;
-  earningsPerShare: number;
-  salesPerShare: number;
-  bookValuePerShare: number;
-  reserveRate: number;
-  liabilityRate: number;
+  grossMarginRatio: number | null;
+  businessProfitRate: number | null;
+  netInterestRate: number | null;
+  roeValue: number | null;
+  earningsPerShare: number | null;
+  salesPerShare: number | null;
+  bookValuePerShare: number | null;
+  reserveRate: number | null;
+  liabilityRate: number | null;
 };
  1. API에서 null 값이 올 수 있으므로, 타입을 number | null로 정의하는 것이 안전합니다.
  2. 각 필드에 대한 JSDoc 문서화를 추가하면 유지보수성이 향상될 것입니다.
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e3d046c and 47eb237.

📒 Files selected for processing (17)
  • src/app/globals.css (2 hunks)
  • src/app/login/layout.tsx (1 hunks)
  • src/app/main/layout.tsx (1 hunks)
  • src/app/members/layout.tsx (1 hunks)
  • src/app/my-account/layout.tsx (1 hunks)
  • src/app/portfolio/layout.tsx (1 hunks)
  • src/app/search/[id]/_components/detail-info/company-overview/consensus.tsx (1 hunks)
  • src/app/search/[id]/_components/detail-info/company-overview/financial-statements.tsx (1 hunks)
  • src/app/search/[id]/_components/detail-info/company-overview/index.tsx (1 hunks)
  • src/app/search/[id]/_components/detail-info/company-overview/target-price.tsx (1 hunks)
  • src/app/search/[id]/_components/detail-info/index.tsx (1 hunks)
  • src/app/search/[id]/_components/detail-info/relative-news/index.tsx (1 hunks)
  • src/app/search/[id]/layout.tsx (1 hunks)
  • src/app/search/[id]/page.tsx (2 hunks)
  • src/app/search/layout.tsx (1 hunks)
  • src/components/nav-bar/_components/nav-menu.tsx (1 hunks)
  • tailwind.config.ts (2 hunks)
✅ Files skipped from review due to trivial changes (2)
  • src/app/search/layout.tsx
  • src/components/nav-bar/_components/nav-menu.tsx
🔇 Additional comments (8)
tailwind.config.ts (1)

43-43: 초록색 900 색상이 적절하게 추가되었습니다.

기업 상세정보 UI에 사용될 새로운 다크 그린 색상이 기존 색상 팔레트와 잘 어울립니다.

src/app/portfolio/layout.tsx (1)

13-13: 높이 설정 변경이 적절해 보입니다

h-screen에서 h-full로의 변경은 중첩된 레이아웃 구조에서 더 적절해 보입니다. 상위 컨테이너의 높이를 기준으로 동작하므로 레이아웃의 유연성이 향상될 것으로 예상됩니다.

src/app/main/layout.tsx (1)

14-14: 레이아웃 스타일링이 적절히 개선되었습니다.

반응형 패딩과 최대 너비 제한을 통해 다양한 화면 크기에서 일관된 레이아웃을 제공할 수 있게 되었습니다.

src/app/login/layout.tsx (1)

14-14: ⚠️ Potential issue

모바일 화면에서의 최소 너비 제한을 재검토해주세요.

min-w-400 설정으로 인해 모바일 기기(특히 작은 화면)에서 가로 스크롤이 발생할 수 있습니다.

다음 스크립트로 모바일 최적화가 필요한 다른 컴포넌트들을 확인해보겠습니다:

다음과 같이 수정하는 것을 제안드립니다:

-    <div className="lg:max-w-2000 flex size-full min-w-400 shrink-0 flex-col items-center justify-center bg-gradient-to-b from-green-100 via-green-50 to-white px-4 py-8 md:px-12 lg:px-16">
+    <div className="lg:max-w-2000 flex size-full w-full shrink-0 flex-col items-center justify-center bg-gradient-to-b from-green-100 via-green-50 to-white px-4 py-8 md:px-12 lg:px-16">
src/app/members/layout.tsx (1)

14-14: 로그인 레이아웃과 동일한 모바일 최적화 이슈가 있습니다.

로그인 컴포넌트에서 언급된 min-w-400 관련 이슈가 이 컴포넌트에도 동일하게 적용됩니다.

src/app/globals.css (1)

5-9: html/body 스타일 설정 검토 필요

Tailwind의 min-h-screen이나 h-screen 유틸리티와 충돌할 수 있습니다. 레이아웃 컴포넌트에서 이러한 유틸리티를 사용하는 경우 예상치 못한 동작이 발생할 수 있습니다.

src/app/search/[id]/page.tsx (2)

4-4: 새로운 DetailInfo 컴포넌트 import 추가됨

DetailInfo 컴포넌트가 추가되었습니다. 이는 기업 상세 정보를 표시하기 위한 새로운 UI 요소입니다.


78-78: DetailInfo 컴포넌트의 데이터 연동 확인 필요

DetailInfo 컴포넌트가 props 없이 렌더링되고 있습니다. API 연동이 계획되어 있다면, 이후 props 전달을 위한 리팩토링이 필요할 것으로 보입니다.

다음 사항들을 고려해주세요:

  1. API 연동 시 필요한 데이터 구조 설계
  2. 에러 처리 방안
  3. 로딩 상태 처리

{children}
</div>
);
return <div className="lg:max-w-2000 bg-[#F5F6F8]">{children}</div>;
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Let me analyze the layout patterns across the codebase. I can now generate the final response based on the search results.

레이아웃 스타일 변경이 일관성에 영향을 줄 수 있습니다

검토 결과, 다른 유사한 레이아웃 컴포넌트들과 스타일 클래스가 일치하지 않습니다:

  • my-account/layout.tsxportfolio/layout.tsxh-full 클래스를 사용
  • search/layout.tsxflex flex-col 클래스를 사용
  • 현재 파일(search/[id]/layout.tsx)은 이러한 클래스들이 모두 제거됨

상위 검색 페이지(search/layout.tsx)에서 사용 중인 flex flex-col 레이아웃과의 일관성을 위해 이러한 클래스들의 재검토가 필요합니다.

🔗 Analysis chain

레이아웃 스타일 변경사항 검토 필요

화면 높이 관련 클래스(h-screen)와 flex 관련 클래스(flex-col)가 제거되었습니다. 이로 인해 컨텐츠 높이가 동적으로 조정될 수 있습니다. 다음 사항들을 확인해주세요:

  1. 스크롤 동작이 의도한대로 작동하는지
  2. 하위 컴포넌트들의 배치가 올바른지

다음 스크립트로 다른 레이아웃 파일들과의 일관성을 확인할 수 있습니다:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 레이아웃 컴포넌트들의 스타일 클래스 검색
rg -g "layout.tsx" "className=" src/app

Length of output: 1261

Comment on lines +1 to +17
export default function TargetPrice() {
return (
<div>
<div className="mt-13 text-16-500">목표주가</div>
<div className="flex justify-between">
<div className="text-20-700">43.90</div>
<div className="text-12-400">
<div>목표가범위</div>
<div>26.00~60.00</div>
<div className="mt-5 h-6 w-260 rounded-2 bg-green-500">
<span className="inline-block size-16 rounded-full bg-lime-300" />
</div>
</div>
</div>
</div>
);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

하드코딩된 값들을 props로 전달하도록 개선이 필요합니다.

현재 목표주가와 범위가 하드코딩되어 있어 재사용성이 제한됩니다. 다음과 같은 개선사항을 제안드립니다:

  1. 데이터를 props로 전달받도록 수정
  2. 가격 범위 표시 바에 대한 접근성 개선 (aria-label 추가)
  3. 반응형 디자인 고려

다음과 같이 수정하는 것을 제안드립니다:

- export default function TargetPrice() {
+ interface TargetPriceProps {
+   currentPrice: string;
+   minPrice: string;
+   maxPrice: string;
+ }
+ 
+ export default function TargetPrice({ 
+   currentPrice,
+   minPrice,
+   maxPrice 
+ }: TargetPriceProps) {
  return (
    <div>
      <div className="mt-13 text-16-500">목표주가</div>
      <div className="flex justify-between">
-       <div className="text-20-700">43.90</div>
+       <div className="text-20-700">{currentPrice}</div>
        <div className="text-12-400">
          <div>목표가범위</div>
-         <div>26.00~60.00</div>
+         <div>{minPrice}~{maxPrice}</div>
          <div className="mt-5 h-6 w-260 rounded-2 bg-green-500">
-           <span className="inline-block size-16 rounded-full bg-lime-300" />
+           <span 
+             className="inline-block size-16 rounded-full bg-lime-300"
+             aria-label={`현재 목표가: ${currentPrice}`}
+             role="progressbar"
+             aria-valuemin={parseFloat(minPrice)}
+             aria-valuemax={parseFloat(maxPrice)}
+             aria-valuenow={parseFloat(currentPrice)}
+           />
          </div>
        </div>
      </div>
    </div>
  );
}
📝 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
export default function TargetPrice() {
return (
<div>
<div className="mt-13 text-16-500">목표주가</div>
<div className="flex justify-between">
<div className="text-20-700">43.90</div>
<div className="text-12-400">
<div>목표가범위</div>
<div>26.00~60.00</div>
<div className="mt-5 h-6 w-260 rounded-2 bg-green-500">
<span className="inline-block size-16 rounded-full bg-lime-300" />
</div>
</div>
</div>
</div>
);
}
interface TargetPriceProps {
currentPrice: string;
minPrice: string;
maxPrice: string;
}
export default function TargetPrice({
currentPrice,
minPrice,
maxPrice
}: TargetPriceProps) {
return (
<div>
<div className="mt-13 text-16-500">목표주가</div>
<div className="flex justify-between">
<div className="text-20-700">{currentPrice}</div>
<div className="text-12-400">
<div>목표가범위</div>
<div>{minPrice}~{maxPrice}</div>
<div className="mt-5 h-6 w-260 rounded-2 bg-green-500">
<span
className="inline-block size-16 rounded-full bg-lime-300"
aria-label={`현재 목표가: ${currentPrice}`}
role="progressbar"
aria-valuemin={parseFloat(minPrice)}
aria-valuemax={parseFloat(maxPrice)}
aria-valuenow={parseFloat(currentPrice)}
/>
</div>
</div>
</div>
</div>
);
}

Comment on lines +5 to +24
<table className="border-y border-solid border-gray-100">
<caption className="text-left">관련뉴스</caption>
<thead>
<tr className="bg-green-100">
<th>제목</th>
<th>정보 제공</th>
<th>날짜</th>
</tr>
</thead>
<tbody>
<tr className="border-y border-solid border-gray-100">
<td>
코스피, 외국인 &quot;바이 코리아&quot;에 2680 선 마감.. LG 에너지
솔루
</td>
<td>머니 투데이</td>
<td>2024.09.02 </td>
</tr>
</tbody>
</table>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

테이블 구조 및 접근성 개선이 필요합니다.

현재 테이블 구현에서 다음과 같은 개선사항이 필요합니다:

  1. 테이블 헤더에 적절한 스코프 속성 추가
  2. 반응형 테이블 구현 (모바일 대응)
  3. 데이터 로딩 상태 처리

다음과 같이 수정하는 것을 제안드립니다:

- <table className="border-y border-solid border-gray-100">
+ <div className="overflow-x-auto">
+ <table className="w-full border-y border-solid border-gray-100">
  <caption className="text-left">관련뉴스</caption>
  <thead>
    <tr className="bg-green-100">
-     <th>제목</th>
-     <th>정보 제공</th>
-     <th>날짜</th>
+     <th scope="col" className="p-2">제목</th>
+     <th scope="col" className="p-2">정보 제공</th>
+     <th scope="col" className="p-2">날짜</th>
    </tr>
  </thead>
  <tbody>
    <tr className="border-y border-solid border-gray-100">
-     <td>
+     <td className="p-2">
        코스피, 외국인 &quot;바이 코리아&quot;에 2680 선 마감.. LG 에너지
        솔루
      </td>
-     <td>머니 투데이</td>
-     <td>2024.09.02 </td>
+     <td className="p-2">머니 투데이</td>
+     <td className="p-2">2024.09.02</td>
    </tr>
  </tbody>
  </table>
+ </div>
📝 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
<table className="border-y border-solid border-gray-100">
<caption className="text-left">관련뉴스</caption>
<thead>
<tr className="bg-green-100">
<th>제목</th>
<th>정보 제공</th>
<th>날짜</th>
</tr>
</thead>
<tbody>
<tr className="border-y border-solid border-gray-100">
<td>
코스피, 외국인 &quot;바이 코리아&quot; 2680 마감.. LG 에너지
솔루
</td>
<td>머니 투데이</td>
<td>2024.09.02 </td>
</tr>
</tbody>
</table>
<div className="overflow-x-auto">
<table className="w-full border-y border-solid border-gray-100">
<caption className="text-left">관련뉴스</caption>
<thead>
<tr className="bg-green-100">
<th scope="col" className="p-2">제목</th>
<th scope="col" className="p-2">정보 제공</th>
<th scope="col" className="p-2">날짜</th>
</tr>
</thead>
<tbody>
<tr className="border-y border-solid border-gray-100">
<td className="p-2">
코스피, 외국인 &quot;바이 코리아&quot; 2680 마감.. LG 에너지
솔루
</td>
<td className="p-2">머니 투데이</td>
<td className="p-2">2024.09.02</td>
</tr>
</tbody>
</table>
</div>

Comment on lines +13 to +31
export default function DetailInfo() {
return (
<div className="mt-16 rounded-10 bg-white p-30">
<h3 className="mb-25 text-20-700">상세 정보</h3>
<Tabs defaultValue="company-overview">
<TabsList>
<TabsTrigger value="company-overview">기업 개요</TabsTrigger>
<TabsTrigger value="relative-news">관련 뉴스</TabsTrigger>
</TabsList>
<TabsContent value="company-overview">
<CompanyOverview />
</TabsContent>
<TabsContent value="relative-news">
<RelativeNews />
</TabsContent>
</Tabs>
</div>
);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

탭 컴포넌트의 상태 관리 및 에러 처리 개선이 필요합니다.

현재 구현에서 다음과 같은 개선사항이 필요합니다:

  1. 탭 상태 유지 관리
  2. 에러 바운더리 추가
  3. 로딩 상태 처리

다음과 같은 구조를 제안드립니다:

import { useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';

interface DetailInfoProps {
  initialTab?: string;
}

export default function DetailInfo({ initialTab = 'company-overview' }: DetailInfoProps) {
  const [activeTab, setActiveTab] = useState(initialTab);

  return (
    <div className="mt-16 rounded-10 bg-white p-30">
      <h3 className="mb-25 text-20-700">상세 정보</h3>
      <ErrorBoundary fallback={<div>에러가 발생했습니다.</div>}>
        <Tabs 
          defaultValue={activeTab} 
          onValueChange={setActiveTab}
        >
          {/* 기존 탭 구현... */}
        </Tabs>
      </ErrorBoundary>
    </div>
  );
}

Comment on lines +7 to +29
export default function CompanyOverview() {
return (
<div>
<div className="mb-10 flex justify-between">
<div className="text-16-500">기업정보</div>
<span className="text-14-500 text-gray-100">[기준: 2024. 08. 16]</span>
</div>
<ul className="list-style mb-24 border-y-2 border-solid border-gray-100 py-14 text-14-500">
<li>한국 및 DX 부문 해외 9개</li>
<li>한국 및 DX 부문 해외 9개</li>
<li>한국 및 DX 부문 해외 9개</li>
</ul>

<FinancialStatements />
<Consensus />
<TargetPrice />
<div className="text-14-500 text-gray-100">
전 세계 1200개 리서치 회사의 정보를 종합적으로 분석합니다. <br />
기준 2024.08.29 . 레피니티브 제공
</div>
</div>
);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

타입 안정성 및 접근성 개선 필요

  1. TypeScript 인터페이스 정의가 필요합니다.
  2. 시맨틱 HTML 요소 사용이 필요합니다.
interface CompanyOverviewProps {
  referenceDate: Date;
  companyDetails: string[];
  analysisDate: Date;
}
-export default function CompanyOverview() {
+export default function CompanyOverview({
+  referenceDate,
+  companyDetails,
+  analysisDate
+}: CompanyOverviewProps) {

Comment on lines +23 to +26
<div className="text-14-500 text-gray-100">
전 세계 1200개 리서치 회사의 정보를 종합적으로 분석합니다. <br />
기준 2024.08.29 . 레피니티브 제공
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

분석 정보 날짜 동적 처리 필요

분석 정보의 기준 날짜도 하드코딩되어 있습니다. API 연동 시 실제 데이터를 사용하도록 수정이 필요합니다.

-기준 2024.08.29 . 레피니티브 제공
+기준 {formatDate(analysisDate)} . 레피니티브 제공

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

Comment on lines +1 to +29
export default function Consensus() {
return (
<div className="w-full">
<div className="mb-10 text-16-500">컨센서스</div>
<div className="flex w-full justify-between gap-8 text-center text-14-500 text-gray-100">
<div className="flex-1">
<div className="mb-6 h-9 w-full bg-green-900" />
<span>적극 매도</span>
</div>
<div className="flex-1">
<div className="mb-6 h-9 w-full bg-green-900" />
<span>매도</span>
</div>
<div className="flex-1">
<div className="mb-6 h-9 w-full bg-green-900" />
<span>중립</span>
</div>
<div className="flex-1">
<div className="mb-6 h-9 w-full bg-green-900" />
<span>매수</span>
</div>
<div className="flex-1">
<div className="mb-6 h-9 w-full bg-green-900" />
<span>적극 매수</span>
</div>
</div>
</div>
);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

컨센서스 컴포넌트 개선사항

다음과 같은 개선이 필요합니다:

  1. 각 등급별 데이터를 동적으로 처리
  2. 접근성 개선 (aria-label 추가)
  3. 타입 정의
interface ConsensusRating {
  label: string;
  value: number;
  percentage: number;
}

interface ConsensusProps {
  ratings: ConsensusRating[];
}

컴포넌트 리팩토링 예시:

-export default function Consensus() {
+export default function Consensus({ ratings }: ConsensusProps) {
   return (
     <div className="w-full">
       <div className="mb-10 text-16-500">컨센서스</div>
-      <div className="flex w-full justify-between gap-8 text-center text-14-500 text-gray-100">
-        <div className="flex-1">
-          <div className="mb-6 h-9 w-full bg-green-900" />
-          <span>적극 매도</span>
-        </div>
-        {/* 반복되는 코드 */}
+      <div className="flex w-full justify-between gap-8 text-center text-14-500 text-gray-100">
+        {ratings.map((rating) => (
+          <div key={rating.label} className="flex-1">
+            <div 
+              className="mb-6 h-9 w-full" 
+              style={{
+                height: `${rating.percentage}%`,
+                backgroundColor: getRatingColor(rating.value)
+              }}
+              role="progressbar"
+              aria-valuenow={rating.percentage}
+              aria-valuemin={0}
+              aria-valuemax={100}
+              aria-label={`${rating.label} ${rating.percentage}%`}
+            />
+            <span>{rating.label}</span>
+          </div>
+        ))}
       </div>
     </div>
   );
 }

Comment on lines +38 to +42
const formatValue = (value: number | null, isPercentage?: boolean) => {
if (value === null) return "-";
const formattedNumber = value.toLocaleString();
return isPercentage ? `${formattedNumber}%` : formattedNumber;
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

formatValue 함수의 안전성 개선 필요

숫자 포맷팅 함수에 예외 처리가 필요합니다.

 const formatValue = (value: number | null, isPercentage?: boolean) => {
   if (value === null) return "-";
+  if (isNaN(value)) return "-";
+  if (!isFinite(value)) return "-";
   const formattedNumber = value.toLocaleString();
   return isPercentage ? `${formattedNumber}%` : formattedNumber;
 };
  1. NaN과 Infinity 값에 대한 처리가 필요합니다.
  2. 큰 숫자의 경우 단위 표시(예: 백만, 억)를 고려해보세요.
📝 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
const formatValue = (value: number | null, isPercentage?: boolean) => {
if (value === null) return "-";
const formattedNumber = value.toLocaleString();
return isPercentage ? `${formattedNumber}%` : formattedNumber;
};
const formatValue = (value: number | null, isPercentage?: boolean) => {
if (value === null) return "-";
if (isNaN(value)) return "-";
if (!isFinite(value)) return "-";
const formattedNumber = value.toLocaleString();
return isPercentage ? `${formattedNumber}%` : formattedNumber;
};

Comment on lines +86 to +94
{values.map((value, index) => (
<td
// eslint-disable-next-line react/no-array-index-key
key={index}
className="border-r border-solid border-gray-100 last:border-r-0"
>
{formatValue(value, isPercentage)}
</td>
))}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

테이블 셀 렌더링 최적화 필요

배열 인덱스를 key로 사용하는 것은 권장되지 않습니다.

-{values.map((value, index) => (
-  <td
-    // eslint-disable-next-line react/no-array-index-key
-    key={index}
-    className="border-r border-solid border-gray-100 last:border-r-0"
-  >
+{values.map((value, index) => (
+  <td
+    key={`${label}-${index}`}
+    className="border-r border-solid border-gray-100 last:border-r-0"
+  >
  1. 고유한 key 값을 생성하여 React의 재조정(reconciliation) 성능을 개선하세요.
  2. eslint 주석을 제거하고 올바른 key 사용을 권장합니다.

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

Comment on lines +111 to +138
export default function FinancialStatements({
data,
}: FinancialStatementsProps) {
if (!data || data.length === 0) {
return <NoDataMessage />;
}

const years = data.map((item) => item.stockAccountingYearMonth);

return (
<table className="mb-20 w-full">
<caption className="mb-10 text-left text-16-500">재무비율</caption>
<TableHeader years={years} />
<tbody className="text-center">
{FINANCIAL_METRICS.map((metric) => (
<TableRow
key={metric.key}
label={metric.label}
values={data.map((item) =>
item[metric.key] !== undefined ? Number(item[metric.key]) : null,
)}
isPercentage={metric.isPercentage}
/>
))}
</tbody>
</table>
);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

FinancialStatements 컴포넌트 개선 사항

메인 컴포넌트의 기능성 향상이 필요합니다.

  1. 데이터 정렬 기능 추가
  2. 메모이제이션을 통한 성능 최적화
  3. 반응형 테이블 구현
+import { useMemo } from 'react';
+
 export default function FinancialStatements({
   data,
 }: FinancialStatementsProps) {
   if (!data || data.length === 0) {
     return <NoDataMessage />;
   }
 
-  const years = data.map((item) => item.stockAccountingYearMonth);
+  const years = useMemo(() => 
+    data
+      .map((item) => item.stockAccountingYearMonth)
+      .sort((a, b) => b.localeCompare(a)),
+    [data]
+  );

추가로 고려할 사항:

  1. 스켈레톤 UI 추가
  2. 데이터 로딩 상태 처리
  3. 에러 바운더리 구현
📝 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
export default function FinancialStatements({
data,
}: FinancialStatementsProps) {
if (!data || data.length === 0) {
return <NoDataMessage />;
}
const years = data.map((item) => item.stockAccountingYearMonth);
return (
<table className="mb-20 w-full">
<caption className="mb-10 text-left text-16-500">재무비율</caption>
<TableHeader years={years} />
<tbody className="text-center">
{FINANCIAL_METRICS.map((metric) => (
<TableRow
key={metric.key}
label={metric.label}
values={data.map((item) =>
item[metric.key] !== undefined ? Number(item[metric.key]) : null,
)}
isPercentage={metric.isPercentage}
/>
))}
</tbody>
</table>
);
}
import { useMemo } from 'react';
export default function FinancialStatements({
data,
}: FinancialStatementsProps) {
if (!data || data.length === 0) {
return <NoDataMessage />;
}
const years = useMemo(() =>
data
.map((item) => item.stockAccountingYearMonth)
.sort((a, b) => b.localeCompare(a)),
[data]
);
return (
<table className="mb-20 w-full">
<caption className="mb-10 text-left text-16-500">재무비율</caption>
<TableHeader years={years} />
<tbody className="text-center">
{FINANCIAL_METRICS.map((metric) => (
<TableRow
key={metric.key}
label={metric.label}
values={data.map((item) =>
item[metric.key] !== undefined ? Number(item[metric.key]) : null,
)}
isPercentage={metric.isPercentage}
/>
))}
</tbody>
</table>
);
}

@Han-wo
Copy link
Collaborator

Han-wo commented Dec 22, 2024

500에러 토큰이 만료되서 그런거같으니까 백엔드측에 요청할게요!

Copy link
Collaborator

@Han-wo Han-wo left a comment

Choose a reason for hiding this comment

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

500 에러 부분은 백엔드 측에 토큰 지속적으로 갱신 해달라고 하겠습니다

@cindycho0423 cindycho0423 merged commit 18f56ec into develop Dec 23, 2024
5 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Dec 27, 2024
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ FEAT This doesn't seem right
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: 상세정보 ui 구현하기
2 participants