Skip to content

[DEV-58] 목표 별 할일 구현 #160

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

Merged
merged 26 commits into from
Feb 26, 2025
Merged

[DEV-58] 목표 별 할일 구현 #160

merged 26 commits into from
Feb 26, 2025

Conversation

hvrain
Copy link
Contributor

@hvrain hvrain commented Feb 25, 2025

📑 작업 개요

  • mockdata를 사용하여 목표 별 할일 일부 구현

✨ 작업 이유

  • 대시보드에 필요한 작업이라서

📌 작업 내용

  • 목표 별 할일 ui 구현 (반응형 포함)
  • 데이터 요청 중 로딩 상태 구현
  • mockData를 사용해서 무한스크롤 동작 구현

🖥️ 실행 화면

2025-02-25.10.40.47.mp4

🤝🏻 해당 부분을 중점적으로 리뷰해주세요!

  • pr을 분리 못하고 너무 많은 내용이 들어갔네요..
  • GET 요청에 대한 부분만 구현이 되었습니다.
  • 할일 추가는 아직 구현하지 못했습니다. (할일 생성 모달 만든 뒤에 구현하겠습니다.)

🎟️ 관련 이슈

close:

Summary by CodeRabbit

Summary by CodeRabbit

  • 새로운 기능

    • 대시보드와 할 일/목표 목록에서 비동기 데이터 로딩 및 무한 스크롤 기능이 추가되어 빠르고 부드러운 사용자 경험을 제공합니다.
    • 목표 진행 상황 확인, 할 일 체크박스, 목표 제목 및 아이콘 등의 다양한 UI 요소가 도입되어 할 일 및 목표 관리를 개선했습니다.
    • 목표 및 할 일 관련 API 서비스 기능이 확장되었습니다.
  • 스타일

    • 레이아웃 및 스타일 조정을 통해 반응형 디자인과 가독성이 향상되었습니다.

Copy link

coderabbitai bot commented Feb 25, 2025

Walkthrough

이 PR은 대시보드 페이지와 관련 API, 컴포넌트, 타입 정의에 비동기 데이터 프리패칭, 무한 스크롤, 로딩 상태 관리 등의 기능을 추가 및 개선합니다. 함수 선언을 전통적인 방식에서 화살표 함수로 변경하고, CSS 클래스와 레이아웃을 조정하여 UI를 개선하였으며, 새로운 컴포넌트와 인터페이스를 도입해 코드 구조를 보강하였습니다.

Changes

파일 변경 사항 요약
src/app/(main)/dashboard/page.tsx, src/app/(main)/layout.tsx Dashboard 페이지 비동기 함수(DashboardPage) 추가, Suspense를 통한 로딩 상태 관리 및 레이아웃 CSS 클래스 수정
src/app/api/v1/dashboard/mock.ts, src/app/api/v1/dashboard/route.ts 기존 함수 선언을 화살표 함수 표현식으로 변경 (기능은 동일하게 유지)
src/app/api/v1/goals/route.ts 모의 목표 데이터를 반환하는 신규 API 엔드포인트 추가 (페이징 정보 제공)
src/app/api/v1/todos/progress/route.ts GET 요청 시 goalId 유효성 검사 및 진행률 정보를 반환하는 신규 API 엔드포인트 추가
src/app/api/v1/todos/route.ts 할 일 목록 조회를 위한 신규 API 엔드포인트 추가 (페이징 및 기본값 처리 포함)
src/components/@common/goal.tsx, src/components/@common/progress-bar.tsx, src/components/@common/todo-title-and-checkbox.tsx, src/components/@common/todo.tsx 공통 컴포넌트 업데이트: 신규 GoalTodoTitleAndCheckBox 컴포넌트 추가, progress-bar 스타일 업데이트, 리스트 항목 수정
src/components/@svgr/plus-icon.tsx 색상 변경이 가능한 신규 PlusIcon 컴포넌트 추가
src/components/dashboard/section-container.tsx, src/components/dashboard/section-title.tsx, src/components/dashboard/todos-by-goal/goal-container.tsx, src/components/dashboard/todos-by-goal/goal-item-progress-bar.tsx, src/components/dashboard/todos-by-goal/goal-item.tsx, src/components/dashboard/todos-by-goal/goal-list.tsx, src/components/dashboard/todos-by-goal/goal-title.tsx, src/components/dashboard/todos-by-goal/todo-list-by-done.tsx, src/components/dashboard/todos-by-goal/todos-by-goal-container.tsx 대시보드 관련 신규 컴포넌트 추가: 섹션 컨테이너/타이틀, 목표 및 할 일 항목, 진행률 및 무한 스크롤 기능 도입, Suspense 활용
src/components/todo/todo-title-checkbox.tsx 할 일 제목과 체크박스 컴포넌트의 메인 div 클래스(flex items-center gap-10flex w-3/5 items-center gap-10 overflow-hidden text-nowrap) 수정
src/services/dashboard/index.ts, src/services/dashboard/query.ts, src/services/endpoint.ts 신규 API 서비스 함수(getInfiniteGoals, getInfiniteTodosByGoalId, getProgressByGoalId) 및 쿼리 옵션 함수 추가, 엔드포인트 URL 정의에 PREFIX 활용
src/types/dashboard.ts, src/types/todo.ts 신규 인터페이스 추가 및 기존 타입 수정: 페이징 정보(hasNext 등)와 전달 props 명세 보강

Sequence Diagram(s)

sequenceDiagram
  participant U as 사용자
  participant DP as DashboardPage
  participant SP as Suspense
  participant TGC as TodosByGoalContainer
  participant API as API 서비스
  
  U->>DP: 대시보드 페이지 요청
  DP->>API: 대시보드 데이터 및 목표 목록 프리패칭 호출
  API-->>DP: 데이터 응답
  DP->>SP: Suspense 컴포넌트 통해 로딩 상태 표시
  SP->>TGC: 할 일 및 목표 목록 컴포넌트 렌더링 요청
  TGC->>API: 무한 스크롤 데이터 요청 (추가 페이지)
  API-->>TGC: 추가 데이터 응답
Loading
sequenceDiagram
  participant U as 사용자
  participant TGC as TodosByGoalContainer
  participant IS as useInfiniteScroll
  participant API as API 서비스

  U->>TGC: 스크롤하여 추가 데이터 요청
  TGC->>IS: fetchNextPage 트리거
  IS->>API: 추가 페이지 데이터 페칭 호출
  API-->>IS: 데이터 응답
  IS-->>TGC: 추가 데이터 전달 및 렌더링 갱신
Loading

Possibly related PRs

Suggested reviewers

  • ChaeYubin
  • xorms571

Poem

나는 귀여운 토끼, 코드 숲을 뛰어넘어
새 기능과 변화 꽃피운 걸음에 박수를 보네 🐇
비동기 데이터가 쏟아지고, Suspense가 빛나며
무한 스크롤을 타고, 목표가 춤추네
코드의 정원 속에서, 우리는 함께 뛰놀리라!
하프 피리 소리와 함께, 달콤한 변화 찬가를 부르네!

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

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.

@hvrain hvrain self-assigned this Feb 25, 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: 10

🧹 Nitpick comments (21)
src/app/api/v1/dashboard/route.ts (1)

5-10: 에러 처리 로직 추가 필요

현재 구현은 기본적인 기능은 잘 동작하지만, 다음과 같은 개선사항을 고려해보세요:

  • 데이터 가져오기 실패 시의 에러 처리
  • HTTP 상태 코드 명시적 설정
 export const GET = async () => {
-  await sleep(1);
-  const data = mockData();
-
-  return Response.json(data);
+  try {
+    await sleep(1);
+    const data = mockData();
+    
+    return Response.json(data, { status: 200 });
+  } catch (error) {
+    return Response.json(
+      { message: "데이터를 가져오는데 실패했습니다." },
+      { status: 500 }
+    );
+  }
 };
src/app/api/v1/todos/progress/route.ts (2)

9-10: 에러 코드와 메시지의 일관성 개선 필요

에러 코드는 영문이지만 메시지는 한글로 되어있습니다. 일관성을 위해 다음과 같이 수정하는 것을 추천드립니다:

-        code: "INVALID_TODO_PK",
-        message: "Todo ID가 올바르지 않습니다.",
+        code: "INVALID_GOAL_ID",
+        message: "목표 ID가 올바르지 않습니다.",

17-17: 진행률 값의 타입 안전성 개선 필요

진행률 값의 타입 안전성을 보장하기 위해 명시적인 타입 변환이 필요합니다:

-  return Response.json({ progress: (Math.random() * 100).toFixed(0) });
+  const progress = Math.min(Math.floor(Math.random() * 101), 100);
+  return Response.json({ progress: progress.toString() });
src/components/dashboard/todos-by-goal/goal-title.tsx (1)

6-15: 접근성 개선 제안

컴포넌트의 기본 구현은 잘 되어있지만, 접근성을 위해 다음과 같은 개선을 제안드립니다:

 export default function GoalTitle({
   children,
   className = "",
+  id,
-}: PropsWithChildren<WithClassName>) {
+}: PropsWithChildren<WithClassName & { id?: string }>) {
   return (
     <h3
+      id={id}
+      role="heading"
+      aria-level={3}
       className={cn("text-base font-bold md:text-lg", className)}
     >
       {children}
     </h3>
   );
 }
src/components/dashboard/todos-by-goal/goal-item-progress-bar.tsx (1)

10-20: 로딩 및 에러 상태 처리가 필요합니다.

useQuery를 사용할 때 다음과 같이 로딩 및 에러 상태를 처리하는 것이 좋습니다:

 export default function GoalItemProgressBar({
   goalId,
 }: GoalItemProgressBarProps) {
-  const { data } = useQuery(getProgressByGoalIdOptions(goalId));
+  const { data, isLoading, error } = useQuery(getProgressByGoalIdOptions(goalId));
+
+  if (isLoading) {
+    return <div className="mb-16 mt-8">로딩 중...</div>;
+  }
+
+  if (error) {
+    return <div className="mb-16 mt-8 text-red-500">진행률을 불러오는데 실패했습니다.</div>;
+  }

   return (
     <div className="mb-16 mt-8">
       <ProgressBar total={100} current={data?.progress ?? 0} />
     </div>
   );
 }
src/components/@svgr/plus-icon.tsx (1)

11-34: 접근성 개선이 필요합니다.

SVG 아이콘의 접근성을 높이기 위해 다음과 같은 속성들을 추가하는 것이 좋습니다:

 <svg
   width="16"
   height="16"
   viewBox="0 0 16 16"
   fill="none"
   xmlns="http://www.w3.org/2000/svg"
+  role="img"
+  aria-label="더하기"
 >
src/components/@common/goal.tsx (2)

8-10: 변수명을 더 명확하게 개선해주세요.

currentTodo보다는 목적을 더 잘 나타내는 이름을 사용하는 것이 좋습니다.

-  todo: currentTodo,
+  todo: goalTodo,

18-21: 텍스트 콘텐츠의 접근성을 개선해주세요.

목표 제목에 대한 접근성을 높이기 위해 적절한 ARIA 속성을 추가하는 것이 좋습니다.

 <div className="flex items-center gap-10">
-  <GoalIcon />
+  <GoalIcon aria-hidden="true" />
   <p 
-    className={`${isDone && "line-through"}`}
+    className={`${isDone && "line-through"}`}
+    role="heading"
+    aria-level={3}
   >
     {goalInformation.title}
   </p>
 </div>
src/components/dashboard/section-container.tsx (1)

14-21: 시맨틱 HTML 구조를 개선해주세요.

섹션에 대한 의미를 더 명확하게 전달하기 위해 헤딩 요소를 추가하는 것이 좋습니다.

 <section
   className={cn(
     "flex w-full flex-col gap-16 rounded-2xl bg-white p-16",
     className,
   )}
+  aria-labelledby="section-title"
 >
+  <h2 id="section-title" className="sr-only">
+    대시보드 섹션
+  </h2>
   {children}
 </section>
src/components/dashboard/todos-by-goal/goal-list.tsx (1)

20-24: 빈 상태 표시를 개선해주세요.

빈 상태를 나타내는 메시지의 의미와 스타일을 더 명확하게 전달하는 것이 좋습니다.

 {goals.length === 0 && (
   <div 
     className="flex h-full min-h-200 w-full items-center justify-center text-sm text-slate-500"
+    role="status"
+    aria-label="목표 없음 상태"
   >
     등록한 목표가 없어요
   </div>
 )}
src/app/(main)/dashboard/page.tsx (1)

25-27: 로딩 상태 UI 개선이 필요합니다.

현재 로딩 상태 표시가 너무 단순합니다. 사용자 경험 향상을 위해 더 나은 로딩 UI를 구현하는 것이 좋습니다.

스켈레톤 UI나 스피너를 사용하여 개선하는 것을 제안합니다:

- <Suspense fallback={<div>TodosByGoalContainer 로딩중 ...</div>}>
+ <Suspense
+   fallback={
+     <div className="animate-pulse">
+       <div className="h-20 w-full rounded bg-gray-200" />
+       <div className="mt-4 h-20 w-full rounded bg-gray-200" />
+       <div className="mt-4 h-20 w-full rounded bg-gray-200" />
+     </div>
+   }
+ >
src/app/api/v1/goals/route.ts (2)

10-11: 상수 관리 개선이 필요합니다.

매직 넘버를 상수로 분리하여 관리하는 것이 좋습니다.

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

+ const TOTAL_GOALS = 7;
+ const DEFAULT_SIZE = 10;
+ 
  const generateMockGoals = ({
    cursor = 0,
-   size = 10,
+   size = DEFAULT_SIZE,
  }: GoalListParams & { cursor?: number }): GoalListResponse => {
-   const totalGoals = 7;
+   const totalGoals = TOTAL_GOALS;

20-21: 날짜 생성 로직 개선이 필요합니다.

날짜 생성 로직이 매직 넘버를 사용하고 있으며, 테스트하기 어려운 구조입니다.

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

+ const ONE_DAY = 24 * 60 * 60 * 1000;
+ const baseDate = new Date('2024-01-01').getTime();
+ 
-       createdAt: new Date(Date.now() - id * 1000000),
-       updatedAt: new Date(Date.now() - id * 500000),
+       createdAt: new Date(baseDate + id * ONE_DAY),
+       updatedAt: new Date(baseDate + (id + 0.5) * ONE_DAY),
src/components/@common/todo-title-and-checkbox.tsx (1)

29-29: 옵셔널 체이닝을 사용하여 코드를 개선하세요.

toggleStatus && toggleStatus(todo.id) 구문을 옵셔널 체이닝을 사용하여 더 간결하게 작성할 수 있습니다.

-          onChange={() => toggleStatus && toggleStatus(todo.id)} // 상태 변경 시 id 전달
+          onChange={() => toggleStatus?.(todo.id)} // 상태 변경 시 id 전달
🧰 Tools
🪛 Biome (1.9.4)

[error] 29-29: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/components/dashboard/todos-by-goal/goal-item.tsx (1)

46-48: 로딩 텍스트의 일관성을 개선하세요.

로딩 상태를 나타내는 텍스트가 한글과 영어가 혼용되어 있습니다. 일관성을 위해 모두 한글로 통일하는 것이 좋겠습니다.

-              할일 목록 로딩중...
+              할 일 목록을 불러오는 중...
-              완료 목록 로딩중...
+              완료된 목록을 불러오는 중...

Also applies to: 59-61

src/components/dashboard/todos-by-goal/todo-list-by-done.tsx (1)

42-42: 텍스트의 언어를 일관되게 사용하세요.

컴포넌트 내에서 영어("Done", "To do")와 한글이 혼용되고 있습니다. 사용자 경험의 일관성을 위해 모두 한글로 통일하는 것이 좋겠습니다.

-      <h4 className="text-sm font-semibold">{isDone ? "Done" : "To do"}</h4>
+      <h4 className="text-sm font-semibold">{isDone ? "완료됨" : "할 일"}</h4>

Also applies to: 58-60

src/components/dashboard/todos-by-goal/todos-by-goal-container.tsx (3)

15-18: 무한 스크롤 구현의 에러 처리 보완 필요

useSuspenseInfiniteQuery를 사용할 때 에러 상태 처리가 누락되어 있습니다. 사용자 경험 향상을 위해 에러 처리를 추가하는 것이 좋습니다.

  const { data, fetchNextPage, hasNextPage } = useSuspenseInfiniteQuery(
    getInfiniteGoalsOptions({}),
+   {
+     onError: (error) => {
+       console.error('목표 데이터 로딩 중 오류 발생:', error);
+     }
+   }
  );

23-27: 접근성 개선 필요

아이콘을 포함하는 div에 적절한 ARIA 레이블이 없어 스크린 리더 사용자의 접근성이 제한될 수 있습니다.

-        <div className="flex h-40 w-40 items-center justify-center rounded-15 bg-blue-500">
+        <div 
+          className="flex h-40 w-40 items-center justify-center rounded-15 bg-blue-500"
+          role="img"
+          aria-label="목표 플래그 아이콘"
+        >

29-29: 로딩 상태 UI 개선 제안

현재 로딩 상태를 나타내는 텍스트만 표시되고 있습니다. 사용자 경험 향상을 위해 로딩 스피너나 스켈레톤 UI를 추가하는 것이 좋습니다.

-      {hasNextPage && <div ref={ref}>목표 로딩 중...</div>}
+      {hasNextPage && (
+        <div ref={ref} className="flex items-center justify-center p-4">
+          <LoadingSpinner />
+          <span className="ml-2">목표 로딩 중...</span>
+        </div>
+      )}
src/services/dashboard/query.ts (1)

58-63: 데이터 변환 로직 최적화 필요

현재 구현은 데이터를 두 번 변환하고 있습니다 (mapflatMap). 단일 변환으로 최적화할 수 있습니다.

    select: (data) => ({
-     pages: data.pages.map((page) => page.todos),
-     todos: data.pages.flatMap((page) => page.todos),
+     pages: data.pages.map((page) => page.todos),
+     todos: data.pages[0]?.todos || [],
      totalCount: data.pages[0].paginationInformation.totalCount,
      pageParams: data.pageParams,
    }),
src/types/dashboard.ts (1)

49-53: 타입 문서화 필요

GoalListParams 인터페이스의 각 필드에 대한 JSDoc 문서화가 누락되어 있습니다. 코드의 가독성과 유지보수성을 위해 문서화를 추가하는 것이 좋습니다.

+/**
+ * 목표 목록 조회를 위한 매개변수
+ */
 export interface GoalListParams {
+  /** 페이지네이션 커서 */
   cursor?: number;
+  /** 페이지당 항목 수 */
   size?: number;
+  /** 정렬 순서 ("newest": 최신순, "oldest": 오래된순) */
   sortOrder?: "newest" | "oldest";
 }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c0ccb35 and 7165d68.

⛔ Files ignored due to path filters (4)
  • package-lock.json is excluded by !**/package-lock.json
  • src/assets/arrow_down.svg is excluded by !**/*.svg
  • src/assets/flag.svg is excluded by !**/*.svg
  • src/assets/plus/plus_p_sm.svg is excluded by !**/*.svg
📒 Files selected for processing (27)
  • src/app/(main)/dashboard/page.tsx (1 hunks)
  • src/app/(main)/layout.tsx (1 hunks)
  • src/app/api/v1/dashboard/mock.ts (2 hunks)
  • src/app/api/v1/dashboard/route.ts (1 hunks)
  • src/app/api/v1/goals/route.ts (1 hunks)
  • src/app/api/v1/todos/progress/route.ts (1 hunks)
  • src/app/api/v1/todos/route.ts (1 hunks)
  • src/components/@common/goal.tsx (1 hunks)
  • src/components/@common/progress-bar.tsx (1 hunks)
  • src/components/@common/todo-title-and-checkbox.tsx (1 hunks)
  • src/components/@common/todo.tsx (1 hunks)
  • src/components/@svgr/plus-icon.tsx (1 hunks)
  • src/components/dashboard/section-container.tsx (1 hunks)
  • src/components/dashboard/section-title.tsx (1 hunks)
  • src/components/dashboard/todos-by-goal/goal-container.tsx (1 hunks)
  • src/components/dashboard/todos-by-goal/goal-item-progress-bar.tsx (1 hunks)
  • src/components/dashboard/todos-by-goal/goal-item.tsx (1 hunks)
  • src/components/dashboard/todos-by-goal/goal-list.tsx (1 hunks)
  • src/components/dashboard/todos-by-goal/goal-title.tsx (1 hunks)
  • src/components/dashboard/todos-by-goal/todo-list-by-done.tsx (1 hunks)
  • src/components/dashboard/todos-by-goal/todos-by-goal-container.tsx (1 hunks)
  • src/components/todo/todo-title-checkbox.tsx (1 hunks)
  • src/services/dashboard/index.ts (1 hunks)
  • src/services/dashboard/query.ts (1 hunks)
  • src/services/endpoint.ts (3 hunks)
  • src/types/dashboard.ts (3 hunks)
  • src/types/todo.ts (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • src/components/@common/progress-bar.tsx
  • src/app/(main)/layout.tsx
  • src/components/todo/todo-title-checkbox.tsx
🧰 Additional context used
🧠 Learnings (3)
src/services/endpoint.ts (1)
Learnt from: ChaeYubin
PR: codeit-si/buildone-client#95
File: src/services/endpoint.ts:10-14
Timestamp: 2025-02-17T08:54:47.766Z
Learning: The endpoints under GOAL and TODO in src/services/endpoint.ts are example endpoints that will be updated later. These endpoints may not follow the same PREFIX pattern as the finalized AUTH endpoints.
src/components/dashboard/todos-by-goal/todos-by-goal-container.tsx (1)
Learnt from: hvrain
PR: codeit-si/buildone-client#113
File: src/components/dashboard/todos-by-goal/todos-by-goal-container.tsx:1-29
Timestamp: 2025-02-21T01:10:33.389Z
Learning: Placeholder content with repeated elements of fixed height (e.g. multiple divs with "hello") can be temporarily used during development to test scrolling behavior and interactions.
src/components/@common/todo.tsx (1)
Learnt from: xorms571
PR: codeit-si/buildone-client#124
File: src/components/@common/list-todo.tsx:91-91
Timestamp: 2025-02-21T05:44:22.147Z
Learning: Use interactive elements (e.g., button) instead of adding tabIndex to non-interactive elements (e.g., div) to ensure proper keyboard navigation and accessibility. This follows the ESLint rule jsx-a11y/no-noninteractive-tabindex.
🪛 Biome (1.9.4)
src/components/dashboard/todos-by-goal/goal-list.tsx

[error] 15-18: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/components/@common/todo-title-and-checkbox.tsx

[error] 29-29: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (6)
src/components/dashboard/section-title.tsx (1)

1-9: 잘 구현되었습니다!

컴포넌트가 잘 구조화되어 있으며 React의 모범 사례를 따르고 있습니다:

  • TypeScript를 사용한 타입 안전성
  • 함수형 컴포넌트 패턴 적용
  • 시맨틱 HTML 요소 사용
  • 일관된 스타일링
src/app/api/v1/dashboard/mock.ts (1)

1-19: 함수 선언 스타일이 일관되게 적용되었습니다!

화살표 함수로의 리팩토링이 잘 이루어졌으며, 목 데이터의 구조도 일관성 있게 유지되었습니다.

src/components/dashboard/todos-by-goal/goal-container.tsx (1)

1-15: 컴포넌트가 잘 구현되었습니다!

타입 안전성과 재사용성이 잘 고려된 구현입니다. PropsWithChildrenWithClassName을 활용한 타입 정의가 명확하며, cn 유틸리티를 통한 클래스 결합도 적절합니다.

src/components/@common/todo-title-and-checkbox.tsx (1)

18-35: 접근성이 잘 구현되어 있습니다!

체크박스의 상태를 시각적으로 표시하고, 적절한 ARIA 속성을 사용하여 스크린 리더 지원이 잘 되어 있습니다.

🧰 Tools
🪛 Biome (1.9.4)

[error] 29-29: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/components/dashboard/todos-by-goal/goal-item.tsx (1)

37-40: 할 일 추가 버튼이 구현되지 않았습니다.

PR 목표에 따르면 할 일 추가 기능은 아직 구현되지 않았습니다. 사용자에게 피드백을 제공하거나 버튼을 비활성화하는 것이 좋겠습니다.

-        <button className="flex items-center gap-5 text-sm font-semibold text-dark-blue-500">
+        <button 
+          className="flex items-center gap-5 text-sm font-semibold text-dark-blue-500 opacity-50 cursor-not-allowed"
+          disabled
+          title="준비 중인 기능입니다"
+        >
src/components/dashboard/todos-by-goal/todo-list-by-done.tsx (1)

30-38: 잘 구현된 상태 관리입니다!

useEffect를 사용하여 페이지네이션 상태를 상위 컴포넌트와 동기화하는 방식이 깔끔하게 구현되어 있습니다.

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

🧹 Nitpick comments (2)
src/components/dashboard/todos-by-goal/goal-list.tsx (2)

1-9: 불필요한 React import를 제거해주세요.

React 17 이상에서는 JSX 변환이 자동으로 이루어지므로 명시적인 React import가 필요하지 않습니다.

다음과 같이 수정해주세요:

-import React from "react";
-
 import { GoalResponse } from "@/types/dashboard";
 
 import GoalItem from "./goal-item";

11-26: 구현이 전반적으로 잘 되어있습니다!

시맨틱 마크업과 접근성을 고려한 구현이 잘 되어있습니다. 몇 가지 개선사항을 제안드립니다:

  1. 빈 상태 메시지에 대한 접근성 개선
  2. 일관된 높이 단위 사용

다음과 같이 수정하면 더 좋을 것 같습니다:

 <ul className="flex flex-col gap-16" aria-label="목표 리스트">
   {goals.map((goal) => (
     <GoalItem key={`dashboard-goal-${goal.id}`} goal={goal} />
   ))}
 </ul>
 {goals.length === 0 && (
-  <div className="flex h-full min-h-200 w-full items-center justify-center text-sm text-slate-500">
+  <div 
+    className="flex h-full min-h-[12.5rem] w-full items-center justify-center text-sm text-slate-500"
+    role="status"
+    aria-label="목표 없음 상태"
+  >
     등록한 목표가 없어요
   </div>
 )}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7165d68 and b734621.

📒 Files selected for processing (7)
  • src/app/api/v1/todos/progress/route.ts (1 hunks)
  • src/app/api/v1/todos/route.ts (1 hunks)
  • src/components/dashboard/recently-todo/recently-todo-list.tsx (1 hunks)
  • src/components/dashboard/todos-by-goal/goal-list.tsx (1 hunks)
  • src/components/dashboard/todos-by-goal/todo-list-by-done.tsx (1 hunks)
  • src/services/endpoint.ts (2 hunks)
  • src/types/todo.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/components/dashboard/recently-todo/recently-todo-list.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/types/todo.ts
  • src/app/api/v1/todos/progress/route.ts
  • src/app/api/v1/todos/route.ts
  • src/components/dashboard/todos-by-goal/todo-list-by-done.tsx
  • src/services/endpoint.ts

@hvrain hvrain requested review from ChaeYubin and xorms571 February 25, 2025 04:23
Copy link
Contributor

@xorms571 xorms571 left a comment

Choose a reason for hiding this comment

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

get하는거 저도 참고하겠습니다. 수고하셨습니다!

Comment on lines 45 to 46
createdAt: Date;
updatedAt: Date;
Copy link
Contributor

Choose a reason for hiding this comment

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

@hvrain 강우님 아까 @ChaeYubin 님이랑 논의했을때 Date가 아니라 string으로 하는게 어떻겠냐는 얘기가 나왔었는데 어떻게 생각하세요?

일단 chatGpt는 이렇게 알려주네요.

Date 객체 사용을 추천: 
- createdAt과 updatedAt은 날짜와 시간을 다루는 필드이므로 Date 객체로 사용하는 것이 더 안전하고 편리합니다. 
- 날짜 관련 연산이 필요할 때 Date 객체에서 제공하는 메서드를 사용할 수 있어 유용합니다. 
- 다만, API를 통해 데이터가 오갈 때는 Date 객체를 toISOString()으로 변환하여 문자열로 처리하면 됩니다.

string 타입 사용은 선택: 
- 만약 날짜를 단순히 저장하고, 외부 시스템과의 호환성을 위해 문자열로 처리해야 하는 경우라면 string 타입을 사용할 수 있습니다. 
- 다만 이 경우, 날짜 형식에 대한 일관성을 잘 유지해야 합니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

저는 백엔드에서 Date를 넘겨준다는 확신이 있다면 Date로 해도 될 것 같고, 아니라면 string이 좋을 것 같습니다.

Copy link
Contributor

@ChaeYubin ChaeYubin Feb 26, 2025

Choose a reason for hiding this comment

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

어랏 제가 댓글을 달았다고 생각했는데 지웠나보네요😅 JSON으로 주고받을 수 있는 데이터의 타입에 Date는 없는 걸로 알고 있어요! 명세서 상으로도 문자열로 오고 있는데, 만약 Date로 받으려면 이 값을 받을 때 문자열을 Date로 변환해주는 작업이 필요할 거예요.

api 응답 타입에 추가 처리가 필요하지 않도록 기본 타입은 string으로 두고, 날짜나 시간 계산이 필요한 경우라면 그때그때 해당 필드를 Date로 변환해서 사용하는 게 더 적절하지 않을까 싶습니다ㅎㅎ

Copy link
Contributor Author

Choose a reason for hiding this comment

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

그렇네요. 백엔드에서 넘어오는 데이터는 string으로 받아야될 것 같네요. 이 부분 해당 pr에 수정해서 올릴게요

Copy link
Contributor Author

Choose a reason for hiding this comment

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

수정했습니다!

@hvrain hvrain merged commit e705e54 into dev Feb 26, 2025
1 check passed
@hvrain hvrain deleted the DEV-58 branch March 4, 2025 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants