Skip to content

Main page 목표 추가 제외 완성#31

Merged
Hys-Lee merged 194 commits intoprography:mainfrom
Hys-Lee:main-page
Jul 9, 2025
Merged

Main page 목표 추가 제외 완성#31
Hys-Lee merged 194 commits intoprography:mainfrom
Hys-Lee:main-page

Conversation

@Hys-Lee
Copy link
Copy Markdown
Collaborator

@Hys-Lee Hys-Lee commented Jul 7, 2025

목표 추가는 상세 페이지 쪽과 연결되어 있어서,
상세 페이지 제작하며 추가할 생각입니다.

컴포넌트 변경

  • GoalCard
  • TodoList
  • TodoItem

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced modular main page layout with new components for goals, todos, and main header.
    • Added interactive Goal Card, Goal Menu, Todo List, Todo Bottom Sheet, and Todo Result Bottom Sheet components.
    • Implemented optimistic UI updates, drag gestures, and modal interactions for todos and sub-goals.
    • Added Zustand-based global state management for goals and todo bottom sheets.
    • Integrated Mock Service Worker (MSW) for API mocking in development, with environment-specific initialization.
    • Added Storybook stories for key UI components including GoalCard, TodoList, and TodoBottomSheet.
    • Added new hooks for fetching and managing goal and todo data with data transformation.
    • Introduced generic HTTP request utility with token authentication.
    • Added date formatting utility function.
    • Enhanced onboarding flow with localStorage flag on completion and navigation improvements.
    • Added new bottom tab bar navigation with link integration.
    • Updated root layout to occupy full viewport and conditionally render MSW component in development.
    • Added conditional API request rewrites for development environment proxying.
  • Bug Fixes

    • Improved UI alignment and styling for several shared components.
    • Fixed missing commas and syntax issues in configuration files.
  • Documentation

    • Updated README with clearer installation, documentation, and contribution instructions.
  • Chores

    • Added and configured new dependencies: motion, swr, vaul, msw.
    • Updated package versions and peer dependencies for React 19 compatibility.
    • Added MSW configuration and service worker script for request interception.
  • Tests

    • Added comprehensive mock API handlers and in-memory mock database for local development and testing.
    • Set up MSW server and browser workers for environment-specific mocking.
  • Refactor

    • Reorganized import paths and improved code formatting for consistency.
    • Enhanced modularity and reusability of UI components and hooks.
    • Converted HTTP client in API generation config from axios to fetch.
  • Style

    • Applied consistent formatting and minor style improvements across multiple components.
    • Added CSS adjustments to prevent layout shifts and improve element centering.

Hys-Lee added 30 commits May 21, 2025 12:44
포크한 레포에 작동 테스틀 위해 연결
스토리북 형태도 세팅함
구조 수정 및 tailwind prefix에 맞게 mapping
이전 패키지 버전에선 빌드가 안 됐음.
Hys-Lee added 11 commits July 4, 2025 16:40
(이전 커밋에서 GoalCard에서 pb추가)
TodoBottomSheet는 바텀탭바 존재에 따라 위치 변경 가능하도록 수정.
추가로,
여기서, 기본 subGoal 지정.
발표할 때 필요할 것 같아서.
컴포넌트들 props변경에 따른 에러 수정.
shared내부에 동일한 것으로 복제했습니다.
onboarding에서 Link를 통해 이동
fetch 시 로컬스토리지에서 access token사용하도록 변경
메인 페이지 수정
@Hys-Lee Hys-Lee self-assigned this Jul 7, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jul 7, 2025

Walkthrough

This update introduces a comprehensive main page redesign and a robust goal/todo management system, including new React components, Zustand state stores, custom hooks, and API abstraction layers. It establishes an MSW-powered mock backend for local development and adds Storybook stories for UI components. The update also refines utility functions, documentation, and configuration for development and production environments.

Changes

File(s) / Group Change Summary
app/layout.tsx, app/page.tsx, app/onboarding/_components/CompletionScreen.tsx, app/onboarding/page.tsx Layout and onboarding flow updated; main page restructured with modular components; onboarding completion now sets a localStorage flag instead of redirecting.
components/_mocks/MSWComponent.tsx, components/main/GoalCard/GoalCard.tsx, components/main/GoalMenuContainer/GoalMenuContainer.tsx, components/main/GoalTitleArea/GoalTitleArea.tsx, components/main/MainHeader/MainHeader.tsx, components/main/TodoList/TodoList.tsx, components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx, components/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx New React components for goal/todo management, MSW initialization, and UI elements added.
components/main/GoalCard/GoalCard.stories.tsx, components/main/TodoList/TodoList.stories.tsx, components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.stories.tsx New Storybook stories for GoalCard, TodoList, and TodoBottomSheet components.
components/shared/AppBar/AppBar.tsx, components/shared/BottomTabBar/BottomTabBar.tsx, components/shared/Button/Button.tsx, components/shared/ButtonRound/ButtonRound.tsx, components/shared/Checkbox/Checkbox.tsx, components/shared/GoalInfo/GoalInfo.tsx, components/shared/GoalMenu/GoalMenu.tsx, components/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsx, components/shared/Modal/_compound/Modal.tsx, components/shared/Modal/_compound/ModalButton.tsx, components/shared/SegmentedControl/SegmentedControl.tsx, components/shared/SnackBar/SnackBar.tsx, components/shared/Toast/Toast.tsx, components/shared/TodoItem/TodoItem.tsx Formatting, import path adjustments, minor UI tweaks (e.g., class names, props typing, z-index, etc.), and type exports.
components/shared/utils/utils.ts New utility function cn for merging class names using clsx and twMerge.
components/shared/package.json Updated version, React peer dependencies, and devDependencies.
components/shared/README.md Documentation updated with correct package name, installation, and contribution info.
hooks/main/queries/useGoalList.ts, hooks/main/queries/useGoalWithSubGoalTodo.ts, hooks/main/queries/useTodoList.ts, hooks/main/useOptimisticToggle.ts New hooks for fetching and transforming goal/todo data, and managing optimistic UI state.
hooks/useModal.ts Added isOpened boolean to modal state hook.
lib/common/fetchTemplate.ts, lib/main/cheersFetching.ts, lib/main/goalFetching.ts, lib/main/pointsFetching.ts, lib/main/subGoalFetching.ts, lib/main/todoFetching.ts New API abstraction modules for HTTP requests to backend endpoints, using a shared fetch utility.
mocks/apiHandlers/cheerHandlers.ts, mocks/apiHandlers/db.ts, mocks/apiHandlers/goalHandlers.ts, mocks/apiHandlers/pointsHandlers.ts, mocks/apiHandlers/subGoalHandlers.ts, mocks/apiHandlers/todoHandlers.ts, mocks/apiHandlers/utils.ts, mocks/browser.ts, mocks/handlers.ts, mocks/index.ts, mocks/server.ts New MSW mock API handlers, mock database, and environment-specific MSW initialization for local development/testing.
next.config.ts Added dev-only API rewrites for proxying /v1/:path requests; minor syntax fixes.
package.json Updated scripts, added dependencies (motion, swr, vaul), MSW config, and devDependencies.
plopfile.js Excluded SVG and group components from story generation.
public/mockServiceWorker.js Added MSW service worker script for request interception in the browser.
stores/useActiveTodoBottomSheet.ts, stores/useGoalStore.ts, stores/useModalStore.ts New Zustand stores for managing active todo bottom sheet, selected goal, and modal state.
types/todoList.ts New type alias for normalized todo item info.
utils/date2String.ts New utility for formatting dates as strings.
api/generator.mjs Changed API client generator HTTP type from axios to fetch.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MainPage
    participant GoalMenuContainer
    participant GoalCard
    participant API
    participant MSW

    User->>MainPage: Load page
    MainPage->>GoalMenuContainer: Render and fetch goal list
    GoalMenuContainer->>API: GET /v1/goals
    API-->>MSW: Request intercepted (dev)
    MSW-->>API: Mocked response (goal list)
    API-->>GoalMenuContainer: Return goal list
    GoalMenuContainer->>MainPage: User selects goal
    MainPage->>GoalCard: Render with selected goalId
    GoalCard->>API: GET /v1/goals/:goalId/sub-goals/all
    API-->>MSW: Request intercepted (dev)
    MSW-->>API: Mocked response (goal detail + todos)
    API-->>GoalCard: Return goal + sub-goals + todos
    User->>GoalCard: Add/Edit/Toggle Todo
    GoalCard->>API: POST/PUT/PATCH /v1/sub-goals/:subGoalId/todo or /v1/todos/:todoId
    API-->>MSW: Request intercepted (dev)
    MSW-->>API: Mocked response (update DB)
    API-->>GoalCard: Return updated data
    GoalCard->>GoalMenuContainer: Optionally trigger refetch
Loading

Poem

( )
(_/) A rabbit hops and taps its paw,
(='.'=) New goals and todos—oh what I saw!
(")_(") With MSW, the backend's tamed,
UI and hooks—so neatly named.
Stories, mocks, and states galore—
Motimo's main page is never a bore!
Let's hop ahead and build some more!

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-07-09T03_32_19_269Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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
Copy Markdown

@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: 24

🔭 Outside diff range comments (2)
components/main/GoalMenuContainer/GoalMenuContainer.tsx (1)

1-76: Add missing Storybook file for GoalMenuContainer

A Storybook entry is required for every new component. Please add:

  • File: components/main/GoalMenuContainer/GoalMenuContainer.stories.tsx
    • Include at least one story named Primary demonstrating the default rendering of GoalMenuContainer.
components/main/MainHeader/MainHeader.tsx (1)

1-32: Add missing Storybook file for MainHeader

The MainHeader component in components/main/MainHeader/MainHeader.tsx does not have a corresponding Storybook file. Please add components/main/MainHeader/MainHeader.stories.tsx with the first story named Primary. For example:

import React from "react";
import MainHeader from "./MainHeader";

export default {
  title: "MainHeader",
  component: MainHeader,
};

export const Primary = {
  args: {
    daysOfServiceUse: 1,
  },
};
  • File to create:
    • components/main/MainHeader/MainHeader.stories.tsx
  • First example name: Primary
🧹 Nitpick comments (36)
lib/common/fetchTemplate.ts (4)

1-1: Remove unused variable.

The tmpToken variable is declared but never used, creating dead code.

-const tmpToken = "";
-

3-9: Add explicit return type annotation.

The function should have an explicit return type annotation for better type safety and documentation.

-const templateFetch = async <T>(
+const templateFetch = async <T>(
   apiUrl: string,
   method: "GET" | "PUT" | "PATCH" | "POST" | "DELETE",
   body?: object,
   onFetchNonOk?: (fetchRes: Response) => void,
   onErrorCatch?: (error: unknown) => void,
-) => {
+): Promise<T | undefined> => {

30-31: Use consistent language for comments.

Mix Korean and English comments in the same codebase reduces readability and maintainability.

-      // onFetchNonOk에서 throw을 안 할수도 있어서
+      // onFetchNonOk might not throw an error

36-39: Improve error logging with structured information.

The current error logging provides minimal debugging information. Consider logging more structured data.

   } catch (e) {
     if (onErrorCatch) onErrorCatch(e);
-    console.error(`fetch error: ${e}`);
+    console.error('templateFetch error:', {
+      url: apiUrl,
+      method,
+      error: e instanceof Error ? e.message : e
+    });
   }
types/todoList.ts (1)

7-7: Nit: re-export inline
You can shorten to a single line export for brevity:

export type TodoItemsInfo = Omit<TodoItemProps, "onReportedClick" | "onChecked"> & {
  id: string;
};
components/shared/Button/Button.tsx (2)

2-2: Consistent utility path
The relative import works, but other files still use the alias "@/lib/utils". Consider standardising on one style to avoid churn and accidental path breaks during moves.


34-35: Minor comment alignment
The comment for the medium size variant still lists “8px 16px” padding, but the class is px-4 py-2 (16px 8px). Update the comment for accuracy.

components/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsx (1)

81-83: State update OK – consider handler extraction
Inline handler is fine, though extracting to handleChange avoids re-creation on every render and keeps JSX terse.

hooks/useModal.ts (1)

20-20: Simplify the boolean conversion.

The ternary operator is redundant when converting to boolean.

-  const isOpened = useModalStore((state) => (state.Modal ? true : false));
+  const isOpened = useModalStore((state) => !!state.Modal);
utils/date2String.ts (1)

1-7: Suggest variable naming improvement and add documentation.

The function logic is correct, but consider these improvements:

  1. Variable naming: The variable date on line 4 represents the day of the month, which could be confusing. Consider renaming to day for clarity.

  2. Add JSDoc documentation: The function would benefit from documentation explaining its purpose, parameters, and return value.

+/**
+ * Converts a Date object to a formatted string with custom separator
+ * @param dateValue - The Date object to format
+ * @param spliter - The separator to use between year, month, and day
+ * @returns Formatted string in YYYY{spliter}MM{spliter}DD format
+ */
 const date2StringWithSpliter = (dateValue: Date, spliter: string) => {
   const year = dateValue.getFullYear();
   const month = dateValue.getMonth() + 1;
-  const date = dateValue.getDate();
-  return `${year}${spliter}${String(month).padStart(2, "0")}${spliter}${String(date).padStart(2, "0")}`;
+  const day = dateValue.getDate();
+  return `${year}${spliter}${String(month).padStart(2, "0")}${spliter}${String(day).padStart(2, "0")}`;
 };
mocks/handlers.ts (1)

1-2: Remove unused imports.

The imports HttpResponse, delay, http from "msw" and todo from "node:test" are not used in this file.

-import { HttpResponse, delay, http } from "msw";
-import { todo } from "node:test";
import goalHandlers from "./apiHandlers/goalHandlers";
import todoHandlers from "./apiHandlers/todoHandlers";
import subGoalHandlers from "./apiHandlers/subGoalHandlers";
import cheerHandlers from "./apiHandlers/cheerHandlers";
import pointsHandlers from "./apiHandlers/pointsHandlers";
components/_mocks/MSWComponent.tsx (1)

5-22: Missing Storybook files for the component.

Based on the coding guidelines, components should have corresponding Storybook files. This MSW component might benefit from a story to demonstrate its initialization behavior.

Do you want me to generate a Storybook file for this component or open an issue to track this requirement?

app/layout.tsx (1)

8-9: Remove unused imports.

The imports for SWRConfig and BottomTabBar are not used in the component and should be removed to maintain clean code.

-import { SWRConfig } from "swr";
-import { BottomTabBar } from "@/components/shared";
components/main/GoalTitleArea/GoalTitleArea.tsx (2)

10-21: Remove unnecessary Fragment wrapper and clean up commented code.

The Fragment wrapper is unnecessary since you're returning a single element. Also, remove the commented-out code.

Apply this diff:

  return (
-    <>
-      <div className="self-stretch h-10 inline-flex justify-start items-center gap-2">
+    <div className="self-stretch h-10 inline-flex justify-start items-center gap-2">
        <p className="flex-1 justify-center text-label-strong text-lg font-bold font-['SUIT_Variable'] leading-relaxed">
          {goalTitle}
        </p>
        <div className="w-6 h-6 relative overflow-hidden">
          <RightArrowSvg width={24} height={24} />
-          {/* <div className="w-1 h-2 left-[10px] top-[8px] absolute  outline-[1.50px] outline-offset-[-0.75px] outline-Color-gray-80"></div> */}
        </div>
-      </div>
-    </>
+    </div>
  );

4-6: Consider adding missing Storybook story.

According to the coding guidelines, components should have associated Storybook stories. Consider adding a story file for this component.

Would you like me to generate a Storybook story for this component?

components/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx (2)

11-13: Complete the overlay click handler implementation.

The commented out resetBottomSheet() function suggests incomplete implementation. The overlay should close the modal when clicked.

 <Drawer.Overlay
-  onClick={() => {
-    // resetBottomSheet();
-  }}
+  onClick={onClose}
   className="fixed inset-0 bg-black/10 z-10"
 />

17-19: Add content to the empty Drawer.Content.

The drawer content is currently empty, which suggests incomplete implementation. Consider adding placeholder content or a clear TODO comment.

 <Drawer.Content
   className={`z-20  h-[585px] relative bg-background-alternative rounded-tl-lg rounded-tr-lg shadow-[0px_0px_4px_0px_rgba(0,0,0,0.24)] overflow-hidden`}
->
+>
+  {/* TODO: Add todo result content */}
 </Drawer.Content>
components/shared/README.md (1)

63-64: Fix bare URL formatting in documentation links.

The static analysis tool correctly identified that these URLs should be properly formatted as markdown links.

-- [시작하기] https://10th-motimo-storybook.vercel.app/?path=/docs/introduction--docs
-- [예시] https://10th-motimo-storybook.vercel.app/?path=/docs/components-test--docs
+- [시작하기](https://10th-motimo-storybook.vercel.app/?path=/docs/introduction--docs)
+- [예시](https://10th-motimo-storybook.vercel.app/?path=/docs/components-test--docs)
components/main/GoalCard/GoalCard.stories.tsx (2)

1-1: Remove the template comment.

The plop template comment should be removed from the final code.

-// plop-templates/story.tsx.hbs

25-34: Consider adding meaningful args and argTypes.

The Primary story has empty argTypes and args, which limits its usefulness for demonstrating the component's capabilities. Consider adding relevant props based on the GoalCard component's interface.

 export const Primary: Story = {
   argTypes: {
-    // 예시: backgroundColor: { control: 'color', description: '컴포넌트 배경색' },
+    // Add actual prop controls based on GoalCard's interface
   },
   args: {
-    // Primary 스토리에만 적용될 Props
+    // Add meaningful default props
   },
 };
hooks/main/queries/useTodoList.ts (2)

9-9: Remove unused mockFetcher.

The mockFetcher variable is defined but never used, creating dead code.

-const mockFetcher = async () => {};

26-43: Consider removing commented code or adding explanation.

The commented-out mutateWithConversion function adds noise to the codebase. Either remove it if it's no longer needed, or add a comment explaining why it's preserved for future use.

If this code is intended for future use, add a comment explaining the purpose:

+// TODO: Implement optimistic updates with data transformation
+// This function will convert TodoItemsInfo back to TodoRs format for mutations
 // const mutateWithConversion = (

Otherwise, remove the commented code entirely.

components/main/GoalMenuContainer/GoalMenuContainer.tsx (1)

64-64: Remove commented code.

The commented-out updateGoalId call should be removed since the effect at line 26-28 already handles this functionality.

               onSelected={() => {
                 setSelectedGoalIdx(idx);
-                // updateGoalId(goalMenuInfo.goalId);
               }}
app/page.tsx (1)

6-14: Clean up unused imports and finalize temporary implementation.

Several imported components are commented out in the JSX but still present in the imports. Consider removing unused imports or uncommenting the components if they're needed.

Additionally, the temporary constant tmpDaysOfServiceUse suggests this is incomplete - consider implementing proper service usage tracking.

-import { AppBar } from "@/components/shared";
-import GoalInfo from "@/components/shared/GoalInfo/GoalInfo";
-import TodoList from "@/components/main/TodoList/TodoList";
-import GoalTitleArea from "@/components/main/GoalTitleArea/GoalTitleArea";
-
-import GoalMenuContainer from "@/components/main/GoalMenuContainer/GoalMenuContainer";
-import Banner from "@/components/shared/Banner/Banner";
-import GoalCard from "@/components/main/GoalCard/GoalCard";
-import MainHeader from "@/components/main/MainHeader/MainHeader";
+import GoalMenuContainer from "@/components/main/GoalMenuContainer/GoalMenuContainer";
+import GoalCard from "@/components/main/GoalCard/GoalCard";
+import MainHeader from "@/components/main/MainHeader/MainHeader";
+
+// TODO: Uncomment when these components are integrated
+// import { AppBar } from "@/components/shared";
+// import GoalInfo from "@/components/shared/GoalInfo/GoalInfo";
+// import TodoList from "@/components/main/TodoList/TodoList";
+// import GoalTitleArea from "@/components/main/GoalTitleArea/GoalTitleArea";
+// import Banner from "@/components/shared/Banner/Banner";
components/main/GoalCard/GoalCard.tsx (1)

37-44: Improve date calculation robustness.

The date calculation could fail with invalid dates or timezone issues. Consider adding error handling.

-const goalLeftDate = Math.floor(
-  (new Date(goalWithSubGoalTodo.dueDate ?? "").getTime() -
-    new Date().getTime()) /
-    1000 /
-    24 /
-    60 /
-    60,
-);
+const goalLeftDate = useMemo(() => {
+  if (!goalWithSubGoalTodo.dueDate) return 0;
+  try {
+    const dueDate = new Date(goalWithSubGoalTodo.dueDate);
+    const now = new Date();
+    const diffTime = dueDate.getTime() - now.getTime();
+    return Math.floor(diffTime / (1000 * 60 * 60 * 24));
+  } catch (error) {
+    console.error('Invalid due date:', goalWithSubGoalTodo.dueDate);
+    return 0;
+  }
+}, [goalWithSubGoalTodo.dueDate]);
mocks/apiHandlers/goalHandlers.ts (1)

20-22: Standardize error handling and internationalize error messages.

Consider using consistent error handling patterns and English error messages for better maintainability.

-const errMsg = "존재하지 않는 골 id임";
-console.error(errMsg);
-throw new Error(errMsg);
+const errMsg = "Goal not found";
+console.error(errMsg, { goalId: updatedGoal.id });
+return createErrorResponse(errMsg, 404);

Apply similar patterns to other error cases throughout the file.

Also applies to: 76-77, 92-94

mocks/apiHandlers/todoHandlers.ts (1)

12-12: Consider using English error messages for consistency.

The Korean error messages ("못찾음") might be inconsistent with the rest of the codebase. Consider using English error messages for better maintainability.

Apply this diff to use English error messages:

-      throw new Error("못찾음");
+      throw new Error("Todo not found");

Also applies to: 26-26, 41-41, 48-48, 62-62, 77-77

hooks/main/queries/useGoalWithSubGoalTodo.ts (2)

25-25: Simplify the ternary operator.

The ternary operator is unnecessary and can be simplified to a direct boolean assignment.

Apply this diff to simplify the code:

-          reported: todoInfo.todoResultId ? true : false,
+          reported: Boolean(todoInfo.todoResultId),

11-13: Consider using a more descriptive type name.

The type name ConvertedGoalWithSubGoalTodo could be more descriptive about what the conversion entails.

Consider renaming to:

-type ConvertedGoalWithSubGoalTodo = Omit<GoalWithSubGoalTodoRs, "subGoals"> & {
-  subGoals: TodoListProps[];
-};
+type GoalWithTodoListProps = Omit<GoalWithSubGoalTodoRs, "subGoals"> & {
+  subGoals: TodoListProps[];
+};
mocks/apiHandlers/subGoalHandlers.ts (1)

14-14: Consider using English error messages for consistency.

Similar to the todo handlers, the Korean error messages ("못찾음") might be inconsistent with the rest of the codebase.

Apply this diff to use English error messages:

-        throw new Error("못찾음");
+        throw new Error("SubGoal not found");

Also applies to: 41-41, 62-62

components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (3)

251-259: Use optional chaining for cleaner code.

The conditional check can be simplified using optional chaining.

Apply this diff to use optional chaining:

-                nullabeTodoInfo &&
-                  nullabeTodoInfo.setTodoInfo((prev) => ({
-                    ...prev,
-                    subGoalTitle: subGoalTitle,
-                    subGoalId: subGoalId,
-                  }));
+                nullabeTodoInfo?.setTodoInfo((prev) => ({
+                  ...prev,
+                  subGoalTitle: subGoalTitle,
+                  subGoalId: subGoalId,
+                }));

336-337: Consider moving utility function to a shared utils module.

The date formatting utility function could be moved to a shared utils module for better reusability.

Consider creating a utils/dateUtils.ts file:

export const formatDateWithDots = (date: Date): string =>
  `${date.getFullYear()}.${String(date.getMonth() + 1).padStart(2, "0")}.${String(date.getDate()).padStart(2, "0")}`;

23-38: Consider using more descriptive type names.

The type definitions could be more descriptive about their purpose and differences.

Consider renaming for better clarity:

-type TodoInfoForSubmission = {
+type CompleteTodoInfo = {
   /** id값이 존재한다면 수정, 없다면 추가로 봐야 함. */
   id?: string;
   todo: string;
   date: Date;
   subGoalTitle: string;
   subGoalId: string;
 };

-type TodoInfo = {
+type PartialTodoInfo = {
   id?: TodoInfoForSubmission["todo"];
   todo: TodoInfoForSubmission["todo"];
   date?: TodoInfoForSubmission["date"];
   subGoalTitle?: TodoInfoForSubmission["subGoalTitle"];
   subGoalId?: TodoInfoForSubmission["subGoalId"];
 };
components/main/TodoList/TodoList.stories.tsx (1)

12-25: Consider moving the detailed description to component documentation.

The lengthy description with implementation details might be better placed in the component's JSDoc or README rather than in the Storybook story.

Consider moving this to the component file's JSDoc or a separate documentation file, and keeping only essential usage information in the story description.

components/main/TodoList/TodoList.tsx (2)

189-189: Use optional chaining for cleaner code.

Replace the mutate && mutate() pattern with optional chaining:

-mutate && mutate();
+mutate?.();

This applies to lines 189, 321, and 342.

Also applies to: 321-321, 342-342


330-335: Simplify with optional chaining.

 const initTodoInfo = {
-  date: info?.targetDate ?? new Date(),
-  subGoalId: subGoalId ?? "",
-  subGoalTitle: subGoalTitle ?? "",
+  date: info.targetDate ?? new Date(),
+  subGoalId: subGoalId ?? "",
+  subGoalTitle: subGoalTitle ?? "",
   todo: info?.title,
   id: info?.id,
 };

Since info is required (not optional in the props), you don't need optional chaining for targetDate.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 3ec1119 and b02d996.

⛔ Files ignored due to path filters (18)
  • api/generated/motimo/Api.ts is excluded by !**/generated/**
  • components/shared/public/Calendar.svg is excluded by !**/*.svg
  • components/shared/public/Carrot_Down_MD.svg is excluded by !**/*.svg
  • components/shared/public/Paper_Plane.svg is excluded by !**/*.svg
  • components/shared/public/check.svg is excluded by !**/*.svg
  • package-lock.json is excluded by !**/package-lock.json
  • public/Caret_Down_MD.svg is excluded by !**/*.svg
  • public/images/Bell.svg is excluded by !**/*.svg
  • public/images/Caret_Down_MD.svg is excluded by !**/*.svg
  • public/images/Caret_Up_MD.svg is excluded by !**/*.svg
  • public/images/Chevron_Right_MD.svg is excluded by !**/*.svg
  • public/images/Edit_Pencil_01.svg is excluded by !**/*.svg
  • public/images/Trash_Full.svg is excluded by !**/*.svg
  • public/images/file.svg is excluded by !**/*.svg
  • public/images/globe.svg is excluded by !**/*.svg
  • public/images/next.svg is excluded by !**/*.svg
  • public/images/vercel.svg is excluded by !**/*.svg
  • public/images/window.svg is excluded by !**/*.svg
📒 Files selected for processing (64)
  • api/generator.mjs (1 hunks)
  • app/layout.tsx (3 hunks)
  • app/onboarding/_components/CompletionScreen.tsx (3 hunks)
  • app/onboarding/page.tsx (4 hunks)
  • app/page.tsx (3 hunks)
  • components/_mocks/MSWComponent.tsx (1 hunks)
  • components/main/GoalCard/GoalCard.stories.tsx (1 hunks)
  • components/main/GoalCard/GoalCard.tsx (1 hunks)
  • components/main/GoalMenuContainer/GoalMenuContainer.tsx (1 hunks)
  • components/main/GoalTitleArea/GoalTitleArea.tsx (1 hunks)
  • components/main/MainHeader/MainHeader.tsx (1 hunks)
  • components/main/TodoList/TodoList.stories.tsx (1 hunks)
  • components/main/TodoList/TodoList.tsx (1 hunks)
  • components/shared/AppBar/AppBar.tsx (5 hunks)
  • components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.stories.tsx (1 hunks)
  • components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (1 hunks)
  • components/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx (1 hunks)
  • components/shared/BottomTabBar/BottomTabBar.tsx (2 hunks)
  • components/shared/Button/Button.tsx (3 hunks)
  • components/shared/ButtonRound/ButtonRound.tsx (3 hunks)
  • components/shared/Checkbox/Checkbox.tsx (1 hunks)
  • components/shared/GoalInfo/GoalInfo.tsx (1 hunks)
  • components/shared/GoalMenu/GoalMenu.tsx (1 hunks)
  • components/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsx (1 hunks)
  • components/shared/Modal/_compound/Modal.tsx (1 hunks)
  • components/shared/Modal/_compound/ModalButton.tsx (1 hunks)
  • components/shared/README.md (3 hunks)
  • components/shared/SegmentedControl/SegmentedControl.tsx (3 hunks)
  • components/shared/SnackBar/SnackBar.tsx (4 hunks)
  • components/shared/Toast/Toast.tsx (1 hunks)
  • components/shared/TodoItem/TodoItem.tsx (3 hunks)
  • components/shared/package.json (2 hunks)
  • components/shared/utils/utils.ts (1 hunks)
  • hooks/main/queries/useGoalList.ts (1 hunks)
  • hooks/main/queries/useGoalWithSubGoalTodo.ts (1 hunks)
  • hooks/main/queries/useTodoList.ts (1 hunks)
  • hooks/main/useOptimisticToggle.ts (1 hunks)
  • hooks/useModal.ts (2 hunks)
  • lib/common/fetchTemplate.ts (1 hunks)
  • lib/main/cheersFetching.ts (1 hunks)
  • lib/main/goalFetching.ts (1 hunks)
  • lib/main/pointsFetching.ts (1 hunks)
  • lib/main/subGoalFetching.ts (1 hunks)
  • lib/main/todoFetching.ts (1 hunks)
  • mocks/apiHandlers/cheerHandlers.ts (1 hunks)
  • mocks/apiHandlers/db.ts (1 hunks)
  • mocks/apiHandlers/goalHandlers.ts (1 hunks)
  • mocks/apiHandlers/pointsHandlers.ts (1 hunks)
  • mocks/apiHandlers/subGoalHandlers.ts (1 hunks)
  • mocks/apiHandlers/todoHandlers.ts (1 hunks)
  • mocks/apiHandlers/utils.ts (1 hunks)
  • mocks/browser.ts (1 hunks)
  • mocks/handlers.ts (1 hunks)
  • mocks/index.ts (1 hunks)
  • mocks/server.ts (1 hunks)
  • next.config.ts (3 hunks)
  • package.json (4 hunks)
  • plopfile.js (1 hunks)
  • public/mockServiceWorker.js (1 hunks)
  • stores/useActiveTodoBottomSheet.ts (1 hunks)
  • stores/useGoalStore.ts (1 hunks)
  • stores/useModalStore.ts (1 hunks)
  • types/todoList.ts (1 hunks)
  • utils/date2String.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
`components/**/*`: Component should be created in components/

components/**/*: Component should be created in components/

📄 Source: CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)

List of files the instruction was applied to:

  • components/shared/GoalInfo/GoalInfo.tsx
  • components/shared/GoalMenu/GoalMenu.tsx
  • components/shared/Modal/_compound/Modal.tsx
  • components/shared/ButtonRound/ButtonRound.tsx
  • components/shared/Button/Button.tsx
  • components/shared/Checkbox/Checkbox.tsx
  • components/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsx
  • components/shared/utils/utils.ts
  • components/shared/package.json
  • components/shared/Modal/_compound/ModalButton.tsx
  • components/shared/AppBar/AppBar.tsx
  • components/shared/SnackBar/SnackBar.tsx
  • components/shared/TodoItem/TodoItem.tsx
  • components/_mocks/MSWComponent.tsx
  • components/shared/SegmentedControl/SegmentedControl.tsx
  • components/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx
  • components/main/GoalTitleArea/GoalTitleArea.tsx
  • components/main/GoalCard/GoalCard.stories.tsx
  • components/shared/README.md
  • components/shared/BottomTabBar/BottomTabBar.tsx
  • components/main/TodoList/TodoList.tsx
  • components/shared/Toast/Toast.tsx
  • components/main/GoalMenuContainer/GoalMenuContainer.tsx
  • components/main/MainHeader/MainHeader.tsx
  • components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.stories.tsx
  • components/main/GoalCard/GoalCard.tsx
  • components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx
  • components/main/TodoList/TodoList.stories.tsx
`components/**/*.stories.{js,jsx,ts,tsx}`: If Component is created, add storybook files as well. The first example name of storybook should be `Primary` not `Default`

components/**/*.stories.{js,jsx,ts,tsx}: If Component is created, add storybook files as well.
The first example name of storybook should be Primary not Default

📄 Source: CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)

List of files the instruction was applied to:

  • components/main/GoalCard/GoalCard.stories.tsx
  • components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.stories.tsx
  • components/main/TodoList/TodoList.stories.tsx
🧠 Learnings (11)
next.config.ts (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/icons/**/* : For icon and svg, create component at components/icons.
components/shared/package.json (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The first example name of storybook should be `Primary` not `Default`
components/_mocks/MSWComponent.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
plopfile.js (3)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The first example name of storybook should be `Primary` not `Default`
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/icons/**/* : For icon and svg, create component at components/icons.
components/main/GoalTitleArea/GoalTitleArea.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/icons/**/* : For icon and svg, create component at components/icons.
components/main/GoalCard/GoalCard.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The first example name of storybook should be `Primary` not `Default`
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/shared/README.md (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The first example name of storybook should be `Primary` not `Default`
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
package.json (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The first example name of storybook should be `Primary` not `Default`
app/page.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The first example name of storybook should be `Primary` not `Default`
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The first example name of storybook should be `Primary` not `Default`
components/main/TodoList/TodoList.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The first example name of storybook should be `Primary` not `Default`
🧬 Code Graph Analysis (29)
types/todoList.ts (1)
components/shared/TodoItem/TodoItem.tsx (1)
  • TodoItemProps (102-102)
mocks/index.ts (2)
mocks/server.ts (1)
  • server (4-4)
mocks/browser.ts (1)
  • worker (4-4)
lib/main/cheersFetching.ts (2)
lib/common/fetchTemplate.ts (1)
  • templateFetch (42-42)
api/generated/motimo/Api.ts (1)
  • CheerPhraseRs (350-356)
mocks/server.ts (1)
mocks/handlers.ts (1)
  • handlers (9-24)
lib/main/pointsFetching.ts (2)
lib/common/fetchTemplate.ts (1)
  • templateFetch (42-42)
api/generated/motimo/Api.ts (1)
  • PointRs (247-254)
mocks/apiHandlers/utils.ts (1)
api/generated/motimo/Api.ts (1)
  • HttpResponse (425-429)
mocks/browser.ts (1)
mocks/handlers.ts (1)
  • handlers (9-24)
components/shared/Modal/_compound/ModalButton.tsx (1)
components/shared/Button/Button.tsx (1)
  • ButtonProps (4-10)
components/shared/AppBar/AppBar.tsx (1)
components/shared/utils/utils.ts (1)
  • cn (4-6)
components/shared/SnackBar/SnackBar.tsx (1)
components/shared/utils/utils.ts (1)
  • cn (4-6)
components/_mocks/MSWComponent.tsx (1)
mocks/index.ts (1)
  • initMsw (1-9)
mocks/apiHandlers/pointsHandlers.ts (2)
mocks/apiHandlers/db.ts (1)
  • myMainDB (191-191)
api/generated/motimo/Api.ts (1)
  • HttpResponse (425-429)
mocks/apiHandlers/cheerHandlers.ts (2)
mocks/apiHandlers/db.ts (1)
  • myMainDB (191-191)
api/generated/motimo/Api.ts (1)
  • HttpResponse (425-429)
app/layout.tsx (1)
components/_mocks/MSWComponent.tsx (1)
  • MSWComponent (5-22)
components/shared/SegmentedControl/SegmentedControl.tsx (1)
components/shared/utils/utils.ts (1)
  • cn (4-6)
components/shared/BottomTabBar/BottomTabBar.tsx (1)
components/shared/utils/utils.ts (1)
  • cn (4-6)
components/shared/Toast/Toast.tsx (3)
components/shared/index.ts (1)
  • Toast (10-10)
components/shared/utils/utils.ts (1)
  • cn (4-6)
lib/utils.ts (1)
  • cn (4-6)
stores/useActiveTodoBottomSheet.ts (1)
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (1)
  • TodoInfoForSubmission (229-229)
hooks/main/queries/useGoalList.ts (2)
lib/main/goalFetching.ts (1)
  • getAllGoals (68-68)
components/main/GoalMenuContainer/GoalMenuContainer.tsx (1)
  • GoalMenuInfo (75-75)
hooks/main/queries/useTodoList.ts (2)
types/todoList.ts (1)
  • TodoItemsInfo (7-7)
lib/main/subGoalFetching.ts (1)
  • getTodosOnSubGoal (47-47)
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.stories.tsx (1)
components/main/TodoList/TodoList.stories.tsx (1)
  • Primary (92-104)
lib/main/subGoalFetching.ts (2)
api/generated/motimo/Api.ts (2)
  • TodoCreateRq (99-112)
  • TodoRs (179-212)
lib/common/fetchTemplate.ts (1)
  • templateFetch (42-42)
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (1)
components/shared/Button/Button.tsx (1)
  • Button (77-77)
mocks/apiHandlers/todoHandlers.ts (2)
mocks/apiHandlers/db.ts (1)
  • myMainDB (191-191)
api/generated/motimo/Api.ts (1)
  • HttpResponse (425-429)
mocks/apiHandlers/goalHandlers.ts (3)
mocks/apiHandlers/utils.ts (1)
  • createErrorResponse (6-6)
mocks/apiHandlers/db.ts (1)
  • myMainDB (191-191)
api/generated/motimo/Api.ts (1)
  • HttpResponse (425-429)
hooks/main/queries/useGoalWithSubGoalTodo.ts (4)
api/generated/motimo/Api.ts (1)
  • GoalWithSubGoalTodoRs (313-332)
components/main/TodoList/TodoList.tsx (1)
  • TodoListProps (151-151)
lib/main/goalFetching.ts (1)
  • getGoalWithSubGoalTodo (73-73)
types/todoList.ts (1)
  • TodoItemsInfo (7-7)
mocks/apiHandlers/subGoalHandlers.ts (2)
mocks/apiHandlers/db.ts (1)
  • myMainDB (191-191)
api/generated/motimo/Api.ts (1)
  • HttpResponse (425-429)
lib/main/goalFetching.ts (2)
api/generated/motimo/Api.ts (6)
  • GoalUpdateRq (34-49)
  • GoalListRs (280-283)
  • GoalCreateRq (114-138)
  • SubGoalCreateRq (140-155)
  • GoalDetailRs (285-311)
  • GoalWithSubGoalTodoRs (313-332)
lib/common/fetchTemplate.ts (1)
  • templateFetch (42-42)
lib/main/todoFetching.ts (3)
lib/common/fetchTemplate.ts (1)
  • templateFetch (42-42)
utils/date2String.ts (1)
  • date2StringWithSpliter (7-7)
api/generated/motimo/Api.ts (1)
  • TodoRs (179-212)
🪛 markdownlint-cli2 (0.17.2)
components/shared/README.md

63-63: Bare URL used

(MD034, no-bare-urls)


64-64: Bare URL used

(MD034, no-bare-urls)

🪛 Biome (1.9.4)
components/main/TodoList/TodoList.tsx

[error] 196-197: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 330-331: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 332-333: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

components/main/GoalMenuContainer/GoalMenuContainer.tsx

[error] 20-20: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

components/main/GoalCard/GoalCard.tsx

[error] 93-94: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 109-110: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx

[error] 254-261: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

mocks/apiHandlers/todoHandlers.ts

[error] 103-104: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)


[error] 105-105: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

mocks/apiHandlers/goalHandlers.ts

[error] 144-145: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

hooks/main/queries/useGoalWithSubGoalTodo.ts

[error] 25-25: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

components/main/TodoList/TodoList.stories.tsx

[error] 103-104: Avoid the use of spread (...) syntax on accumulators.

Spread syntax should be avoided on accumulators (like those in .reduce) because it causes a time complexity of O(n^2).
Consider methods such as .splice or .push instead.

(lint/performance/noAccumulatingSpread)

public/mockServiceWorker.js

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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: chromatic-test
🔇 Additional comments (70)
plopfile.js (1)

15-16: LGTM! Appropriate exclusion patterns added.

The exclusion of icon components and completed component groups from story generation is sensible, as these typically don't require interactive Storybook stories. This aligns with the coding guidelines for icon components.

components/shared/GoalMenu/GoalMenu.tsx (1)

65-65: LGTM! Proper type export for reusability.

Exporting the GoalMenuProps type enables type sharing with other components, which is a good TypeScript practice for maintaining type consistency across the codebase.

api/generator.mjs (1)

22-22: LGTM! Consistent HTTP client choice.

Switching from "axios" to "fetch" aligns with the new templateFetch utility function and reduces external dependencies by using the native fetch API.

components/shared/Modal/_compound/Modal.tsx (1)

26-26: LGTM! Proper z-index stacking for modal backdrop.

Adding z-20 ensures the modal backdrop appears above other UI elements, which is essential for proper modal behavior and user experience.

stores/useModalStore.ts (1)

1-1: Directive is appropriate
Adding "use client"; is necessary for Zustand stores consumed in React Client Components under the Next 13+ app router. No further action required.

types/todoList.ts (1)

1-5: Confirm id duplication with TodoItemProps
If TodoItemProps already contains an optional id, intersecting with { id: string } makes it required, which is usually intended but could introduce silent type-narrowing. Double-check the source definition to ensure this is desirable for every caller.

components/shared/Checkbox/Checkbox.tsx (1)

11-12: Good addition
shrink-0 prevents flex shrink and fixes layout jitter next to text. Looks correct.

components/shared/utils/utils.ts (1)

1-6: LGTM! Standard utility for Tailwind class merging.

This is a well-implemented utility function that combines clsx for conditional class handling and twMerge for resolving Tailwind CSS conflicts. This is a common and recommended pattern in React projects using Tailwind CSS.

mocks/apiHandlers/utils.ts (1)

3-6: LGTM! Reusable error response utility for MSW.

This utility function provides a consistent way to generate error responses across mock handlers. The implementation is correct and follows MSW best practices.

app/onboarding/_components/CompletionScreen.tsx (2)

84-86: Verify dual navigation behavior.

The button now has both a Link wrapper (navigating to "/") and an onClick handler (onComplete). This dual navigation setup could cause race conditions or unexpected behavior.

Please verify that this is the intended behavior and that the onComplete handler doesn't perform navigation that conflicts with the Link component.


71-73: Minor formatting improvement.

Clean formatting change that improves readability without affecting functionality.

components/shared/package.json (3)

3-3: Version update to stable release.

Good progression from pre-release to stable version, indicating the shared UI package is now production-ready.


17-18: Verify React 19 compatibility.

The upgrade from React 18 to React 19 is a major version change that could introduce breaking changes. Please ensure all components in the shared UI package are compatible with React 19.


23-24: Consider the impact of enforcing React 19.

Changing from flexible version ranges (>=18) to a specific major version (^19.0.0) makes React 19 a hard requirement. This could be a breaking change for consumers still using React 18.

Consider whether this restriction is necessary or if a more flexible range would be appropriate.

mocks/browser.ts (1)

1-4: LGTM! Standard MSW browser setup.

This is a clean and correct implementation of MSW worker setup for the browser environment. The pattern of importing handlers and spreading them into setupWorker follows MSW best practices.

mocks/server.ts (1)

1-4: LGTM! Clean MSW server setup.

The server setup follows MSW best practices with proper imports and handler configuration.

lib/main/pointsFetching.ts (1)

4-10: Address TODO comments for production readiness.

The function lacks error handling and the return type may need conversion. Consider implementing:

  • Try-catch blocks with appropriate error handling
  • Toast notifications for user feedback
  • Type validation/conversion if needed

Since this is noted as incomplete, please ensure error handling is implemented before merging to production.

mocks/index.ts (1)

1-9: LGTM! Proper MSW environment detection and initialization.

The function correctly detects the runtime environment and initializes MSW appropriately with dynamic imports to prevent bundling issues.

hooks/useModal.ts (1)

29-29: LGTM! Good addition of modal state visibility.

The isOpened property provides a clean way for components to check modal visibility state.

components/shared/GoalInfo/GoalInfo.tsx (1)

12-13: LGTM! Calendar icon centering improvement.

The addition of justify-center items-center classes properly centers the calendar icon within its container, improving the visual alignment of the component.

components/shared/Toast/Toast.tsx (2)

8-21: Code formatting improvements look good.

The function signature consolidation and JSX formatting with trailing commas enhance code readability and maintainability.


1-1: ✅ Import path verified – no issues found

  • The relative import (components/shared/utils/utils.ts) exports the same cn function as the original absolute path (lib/utils.ts).
  • Formatting changes are purely cosmetic and consistent with the project’s refactoring.

All good to merge.

components/shared/TodoItem/TodoItem.tsx (4)

49-49: Good responsive design improvement.

Changing from fixed width w-72 to w-full makes the component more flexible and responsive to different container sizes.


55-55: Better layout control with max-width constraint.

The change from "flex-1 self-stretch" to "max-w-full" provides better control over the label's maximum width, preventing potential overflow issues.


67-67: Appropriate removal of flex-1 class.

Removing the "flex-1" class from the paragraph while keeping "truncate" ensures proper text truncation without unnecessary flex behavior.


110-110: Essential styling addition for icon visibility.

Adding the "text-white" class ensures the CheckSvg icon is visible against the background, improving the component's visual clarity.

mocks/apiHandlers/pointsHandlers.ts (1)

1-12: Well-structured mock API handler implementation.

The implementation correctly follows MSW patterns and integrates well with the broader mock infrastructure. The handler properly:

  1. Uses the correct HTTP method and endpoint pattern
  2. Accesses the mock database appropriately
  3. Returns a properly formatted JSON response
  4. Exports the handler in the expected format

This complements the other mock handlers introduced in this PR and supports the frontend development workflow.

components/shared/AppBar/AppBar.tsx (3)

1-1: LGTM: Import path change improves consistency.

The change from alias import to relative import aligns with the project's import strategy and maintains consistency across components.


27-36: LGTM: Improved JSX formatting with trailing commas.

The multi-line formatting with trailing commas enhances readability and makes future modifications easier by reducing diff noise.


49-55: LGTM: Consistent JSX formatting applied.

The conditional rendering blocks are now properly formatted with parentheses and multi-line structure, improving code readability.

Also applies to: 72-78

mocks/handlers.ts (1)

9-24: LGTM: Clean handlers aggregation.

The handlers are properly organized and spread into a single array for easy consumption by MSW setup.

hooks/main/useOptimisticToggle.ts (1)

3-11: LGTM: Well-implemented optimistic toggle hook.

The hook properly uses React's useOptimistic with a clean toggle reducer and returns a properly typed tuple. The implementation is concise and reusable.

components/shared/Modal/_compound/ModalButton.tsx (1)

4-5: Excellent interface improvement for type consistency.

The change from ButtonHTMLAttributes<HTMLButtonElement> to Omit<ButtonProps, "children"> is a great improvement that:

  • Maintains consistency with the shared ButtonProps interface
  • Prevents potential prop conflicts by explicitly omitting children
  • Leverages the existing button prop structure while allowing the text prop to handle content
components/shared/SnackBar/SnackBar.tsx (2)

1-1: Consistent import path refactoring.

The change from absolute import @/lib/utils to relative import ../utils/utils aligns with the broader refactoring effort to standardize utility imports across shared components.


20-25: Improved JSX formatting with trailing commas.

The multiline JSX formatting with trailing commas enhances readability and follows modern React formatting conventions.

app/layout.tsx (2)

42-42: Proper MSWComponent integration for development mocking.

The conditional rendering of MSWComponent only in development mode is the correct approach for setting up API mocking without affecting production builds.


28-28: Good addition of full width/height classes.

Adding w-full h-full classes to the html element ensures proper viewport coverage for the application layout.

components/shared/SegmentedControl/SegmentedControl.tsx (2)

1-1: Consistent import path standardization.

The change to relative import path ../utils/utils maintains consistency with the broader refactoring effort across shared components.


22-27: Improved JSX formatting consistency.

The multiline JSX formatting with trailing commas improves readability and maintains consistency with modern React formatting standards across the shared components.

Also applies to: 40-47

stores/useGoalStore.ts (1)

1-22: Well-implemented Zustand store for goal management.

The useGoalStore implementation demonstrates excellent practices:

  • Clean, simple interface with proper TypeScript typing
  • Appropriate use of string | null for the goalId state
  • Clear naming conventions for state and updater function
  • Proper Zustand store creation pattern
  • Helpful documentation comment explaining the purpose

This provides a solid foundation for managing the selected goal state across the application.

components/shared/BottomTabBar/BottomTabBar.tsx (1)

1-1: Good improvement to navigation.

The addition of Next.js Link components and the switch to relative imports aligns with the overall codebase improvements. The navigation URLs are properly structured for the main app sections.

Also applies to: 5-5

components/shared/ButtonRound/ButtonRound.tsx (1)

1-1: Good formatting improvements and consistent import path.

The changes improve code readability with better formatting and align with the consistent move to relative imports for utility functions across the codebase.

Also applies to: 13-23

package.json (1)

13-13: Good alignment with new architecture.

The script change to use .mjs and the MSW configuration properly support the new API generation approach and mock service worker setup introduced in the PR.

Also applies to: 70-74

app/onboarding/page.tsx (1)

19-19: Good formatting improvements.

The arrow function parameter formatting improves code readability and consistency.

Also applies to: 23-23, 27-27

hooks/main/queries/useGoalList.ts (1)

8-16: LGTM! Well-structured data transformation.

The hook properly handles the data transformation from API response to UI format with good use of optional chaining and nullish coalescing for safe property access.

mocks/apiHandlers/db.ts (1)

1-191: Excellent mock database structure with comprehensive test data.

The mock database provides:

  • Well-structured relational data with proper ID references
  • Comprehensive coverage of all entity types (goals, subGoals, todos, todoResults, cheer, points)
  • Realistic test scenarios including completion states and progress tracking
  • Intentionally long content for UI testing (todo12 title)

This will support robust testing of the entire goal/todo management system.

next.config.ts (3)

10-10: Good fix for missing comma in webpack configuration.

The added comma properly terminates the rule test property.


26-26: Good fix for missing comma in webpack configuration.

The added comma properly terminates the use property array.


49-60: External proxy URL is reachable

Checked via curl -I http://motimo.kro.kr:8080/v1/health – it returns HTTP/1.1 401, confirming the host is up and responding. No changes required to the rewrite configuration.

components/shared/README.md (3)

1-3: Good improvement from generic template to project-specific content.

The updated title and description make the README more relevant to the actual project.


30-33: Proper package name specification in installation instructions.

The installation instructions now correctly specify motimo-shared-ui instead of placeholder text.


70-70: Good update to project-specific issue reporting URL.

The issue reporting link now correctly points to the actual project repository.

stores/useActiveTodoBottomSheet.ts (1)

5-21: Clean and well-structured Zustand store implementation.

The store follows Zustand best practices with clear type definitions and proper state management. The setIsActive function correctly handles both the boolean state and optional content initialization.

components/main/MainHeader/MainHeader.tsx (1)

12-16: Good implementation with clear improvement path.

The component correctly implements client-side data fetching with SWR, and the comment about moving to RSC shows good architectural awareness. The error handling with default values is appropriate.

components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.stories.tsx (1)

34-53: Excellent adherence to coding guidelines.

The story file correctly follows the established guidelines:

  • Uses "Primary" as the first story name (not "Default")
  • Includes proper Meta configuration
  • Provides multiple scenarios for testing different states

The documentation note about portal usage is helpful for users.

mocks/apiHandlers/todoHandlers.ts (5)

5-20: LGTM! Well-structured PUT handler with proper error handling.

The handler correctly updates todos in the mock database and includes proper error handling for missing todos.


22-40: LGTM! Comprehensive DELETE handler with cascade deletion.

The handler properly removes todos from both the todos array and cleans up references in subGoals. The cascade deletion logic is well-implemented.


42-54: LGTM! Simple and correct GET handler for todo results.

The handler follows the expected pattern with proper error handling.


56-71: LGTM! POST handler correctly creates new todo results.

The handler properly generates new IDs and creates todo result entries with the correct structure.


73-87: LGTM! PATCH handler correctly toggles completion status.

The toggle logic is straightforward and correctly implemented.

hooks/main/queries/useGoalWithSubGoalTodo.ts (1)

15-46: LGTM! Well-structured data transformation hook.

The hook correctly uses SWR for data fetching and provides comprehensive data transformation from the API response to the expected component props format. The mapping logic properly handles null/undefined values with fallbacks.

mocks/apiHandlers/subGoalHandlers.ts (3)

5-30: LGTM! Well-implemented POST handler for creating todos under sub-goals.

The handler correctly creates new todos, assigns them to sub-goals, and maintains consistency between the subGoals and todos tables in the mock database.


32-52: LGTM! Simple and correct PATCH handler for toggling sub-goal completion.

The toggle logic is straightforward and correctly implemented with proper error handling.


54-72: LGTM! Correct GET handler for retrieving todos by sub-goal.

The handler properly filters todos associated with a specific sub-goal and returns the correct data structure.

components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (1)

78-104: LGTM! Well-structured component with proper state management.

The component correctly uses React Context to share state between nested components and implements proper state reset functionality.

components/main/TodoList/TodoList.stories.tsx (2)

27-46: LGTM! Well-structured Storybook configuration.

The story metadata is properly configured with appropriate title, documentation, and follows the coding guidelines with Primary as the first example name.


92-150: LGTM! Comprehensive story variants covering different use cases.

The story variants effectively demonstrate different states of the TodoList component, including edge cases like empty lists and long lists for testing scroll behavior.

lib/main/goalFetching.ts (2)

19-23: Good type safety implementation!

The function correctly uses the type parameter for templateFetch.


48-64: Well-typed fetch functions!

Both functions correctly specify type parameters for templateFetch.

public/mockServiceWorker.js (1)

1-345: Skip review - generated file.

This is a generated Mock Service Worker file that should not be modified per the header comment.

Comment on lines +12 to +23
const updateTodo = async (todoId: string, body: UpdateTodoBody) => {
await templateFetch(`/v1/todos/${todoId}`, "PUT", {
...body,
date: body.date ? date2StringWithSpliter(body.date, "-") : undefined,
});
};
const toggleTodo = async (todoId: string) => {
await templateFetch(`/v1/todos/${todoId}/completion`, "PATCH");
};
const deleteTodo = async (todoId: string) => {
await templateFetch(`/v1/todos/${todoId}`, "DELETE");
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add return types for better type safety.

These functions should have explicit return types:

-const updateTodo = async (todoId: string, body: UpdateTodoBody) => {
+const updateTodo = async (todoId: string, body: UpdateTodoBody): Promise<void> => {
   await templateFetch(`/v1/todos/${todoId}`, "PUT", {
     ...body,
     date: body.date ? date2StringWithSpliter(body.date, "-") : undefined,
   });
 };

-const toggleTodo = async (todoId: string) => {
+const toggleTodo = async (todoId: string): Promise<void> => {
   await templateFetch(`/v1/todos/${todoId}/completion`, "PATCH");
 };

-const deleteTodo = async (todoId: string) => {
+const deleteTodo = async (todoId: string): Promise<void> => {
   await templateFetch(`/v1/todos/${todoId}`, "DELETE");
 };
📝 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 updateTodo = async (todoId: string, body: UpdateTodoBody) => {
await templateFetch(`/v1/todos/${todoId}`, "PUT", {
...body,
date: body.date ? date2StringWithSpliter(body.date, "-") : undefined,
});
};
const toggleTodo = async (todoId: string) => {
await templateFetch(`/v1/todos/${todoId}/completion`, "PATCH");
};
const deleteTodo = async (todoId: string) => {
await templateFetch(`/v1/todos/${todoId}`, "DELETE");
};
const updateTodo = async (todoId: string, body: UpdateTodoBody): Promise<void> => {
await templateFetch(`/v1/todos/${todoId}`, "PUT", {
...body,
date: body.date ? date2StringWithSpliter(body.date, "-") : undefined,
});
};
const toggleTodo = async (todoId: string): Promise<void> => {
await templateFetch(`/v1/todos/${todoId}/completion`, "PATCH");
};
const deleteTodo = async (todoId: string): Promise<void> => {
await templateFetch(`/v1/todos/${todoId}`, "DELETE");
};
🤖 Prompt for AI Agents
In lib/main/todoFetching.ts around lines 12 to 23, the async functions
updateTodo, toggleTodo, and deleteTodo lack explicit return types. Add explicit
return types such as Promise<void> to each function declaration to improve type
safety and clarity.

Comment on lines +34 to +39
const postTodoResult = async (todoId: string) => {
await templateFetch(`/v1/todos/${todoId}/result`, "POST");
};
const deleteTodoResult = async (todoResultId: string) => {
await templateFetch(`/v1/todos/result/${todoResultId}`, "DELETE");
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add explicit return types.

-const postTodoResult = async (todoId: string) => {
+const postTodoResult = async (todoId: string): Promise<void> => {
   await templateFetch(`/v1/todos/${todoId}/result`, "POST");
 };

-const deleteTodoResult = async (todoResultId: string) => {
+const deleteTodoResult = async (todoResultId: string): Promise<void> => {
   await templateFetch(`/v1/todos/result/${todoResultId}`, "DELETE");
 };
📝 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 postTodoResult = async (todoId: string) => {
await templateFetch(`/v1/todos/${todoId}/result`, "POST");
};
const deleteTodoResult = async (todoResultId: string) => {
await templateFetch(`/v1/todos/result/${todoResultId}`, "DELETE");
};
const postTodoResult = async (todoId: string): Promise<void> => {
await templateFetch(`/v1/todos/${todoId}/result`, "POST");
};
const deleteTodoResult = async (todoResultId: string): Promise<void> => {
await templateFetch(`/v1/todos/result/${todoResultId}`, "DELETE");
};
🤖 Prompt for AI Agents
In lib/main/todoFetching.ts around lines 34 to 39, the async functions
postTodoResult and deleteTodoResult lack explicit return types. Add the return
type Promise<void> to both functions to clearly indicate they return a promise
that resolves to void.

Comment on lines +26 to +33
const getTodoResult = async (todoId: string) => {
const todoResult = await templateFetch<TodoRs>(
`/v1/todos/${todoId}/result`,
"GET",
);

return todoResult ?? {};
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid returning empty object - loses type safety.

Returning {} when todoResult is null/undefined breaks type safety. Consider returning null or undefined instead:

-const getTodoResult = async (todoId: string) => {
+const getTodoResult = async (todoId: string): Promise<TodoRs | null> => {
   const todoResult = await templateFetch<TodoRs>(
     `/v1/todos/${todoId}/result`,
     "GET",
   );
 
-  return todoResult ?? {};
+  return todoResult ?? null;
 };

This maintains type safety and allows callers to properly handle the absence of data.

📝 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 getTodoResult = async (todoId: string) => {
const todoResult = await templateFetch<TodoRs>(
`/v1/todos/${todoId}/result`,
"GET",
);
return todoResult ?? {};
};
const getTodoResult = async (todoId: string): Promise<TodoRs | null> => {
const todoResult = await templateFetch<TodoRs>(
`/v1/todos/${todoId}/result`,
"GET",
);
return todoResult ?? null;
};
🤖 Prompt for AI Agents
In lib/main/todoFetching.ts around lines 26 to 33, the function getTodoResult
returns an empty object {} when todoResult is null or undefined, which breaks
type safety. Modify the function to return null or undefined instead of {}, so
the return type remains consistent and callers can handle the absence of data
properly.

Comment on lines +316 to +322
onChecked={async () => {
toggleChecekdOptimistically();
updateOptimisticCheckedLen && updateOptimisticCheckedLen(1);

await toggleTodo(info.id);
mutate && mutate();
}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix optimistic checked count logic.

The optimistic update always increments by 1, but it should decrement when unchecking:

 onChecked={async () => {
   toggleChecekdOptimistically();
-  updateOptimisticCheckedLen && updateOptimisticCheckedLen(1);
+  updateOptimisticCheckedLen && updateOptimisticCheckedLen(checked ? -1 : 1);
 
   await toggleTodo(info.id);
   mutate && mutate();
 }}

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

🤖 Prompt for AI Agents
In components/main/TodoList/TodoList.tsx around lines 316 to 322, the optimistic
update logic for the checked count always increments by 1 regardless of whether
the item is being checked or unchecked. Modify the updateOptimisticCheckedLen
call to increment by 1 when checking and decrement by 1 when unchecking, based
on the current checked state before toggling.

BottomTabBar 불필요 key제거
TodoList className정리, scroll 되도록 수정, 불필요 낙관적 업데이트 제거
Copy link
Copy Markdown

@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 (1)
components/main/TodoList/TodoList.tsx (1)

318-319: Re-enable the optimistic checked count update logic.

The commented code appears to address a previous review comment about fixing optimistic update logic. The optimistic count update should be re-enabled to provide proper UI feedback when checking/unchecking todos.

-              // updateOptimisticCheckedLen &&
-              //   updateOptimisticCheckedLen(checked ? -1 : +1);
+              updateOptimisticCheckedLen &&
+                updateOptimisticCheckedLen(checked ? -1 : +1);
🧹 Nitpick comments (6)
components/main/TodoList/TodoList.tsx (6)

183-184: Use optional chaining to simplify the conditional check.

The static analysis tool correctly identifies that this can be simplified using optional chaining.

-                    if (!goalId) return;
-
-                    const mutateResult = await createNewSubGoalOnGoal(goalId, {
+                    const mutateResult = await createNewSubGoalOnGoal(goalId, {

Wait, this change would be incorrect as it would still call the function with undefined goalId. Let me reconsider:

-                    if (!goalId) return;
-
-                    const mutateResult = await createNewSubGoalOnGoal(goalId, {
+                    if (!goalId) return;
+
+                    const mutateResult = await createNewSubGoalOnGoal(goalId, {

Actually, the current code is correct. The optional chaining suggestion from the static analysis tool is not applicable here since we need to return early if goalId is undefined.


332-335: Use optional chaining for cleaner null checks.

The static analysis tool correctly identifies opportunities to use optional chaining for cleaner code.

-                date: info?.targetDate ?? new Date(),
-                subGoalId: subGoalId ?? "",
-                subGoalTitle: subGoalTitle ?? "",
-                todo: info?.title,
+                date: info?.targetDate ?? new Date(),
+                subGoalId: subGoalId ?? "",
+                subGoalTitle: subGoalTitle ?? "",
+                todo: info?.title,

Actually, the current code already uses optional chaining appropriately. The static analysis tool might be suggesting a different pattern, but the current implementation is correct and readable.


241-241: Consider using a more semantic height constraint.

The fixed height of h-80 (320px) might not be ideal for all screen sizes. Consider using a more flexible approach.

-      <div className="self-stretch h-80 flex flex-col justify-start items-start  gap-2  overflow-y-auto overflow-x-hidden">
+      <div className="self-stretch max-h-80 flex flex-col justify-start items-start  gap-2  overflow-y-auto overflow-x-hidden">

This allows the container to be smaller than 320px when there are fewer items while still maintaining the maximum height constraint.


364-367: Use proper line height utilities instead of inline styles.

Mixing Tailwind classes with inline styles can lead to inconsistencies. Consider using Tailwind's line height utilities.

-          <p
-            className=" whitespace-pre-wrap  text-center justify-center text-label-alternative text-xs font-medium font-['SUIT_Variable'] leading-none "
-            style={{ lineHeight: "140%" }}
-          >
+          <p className="whitespace-pre-wrap text-center justify-center text-label-alternative text-xs font-medium font-['SUIT_Variable'] leading-relaxed">

The leading-relaxed class provides 1.625 line height which is close to 140% and maintains consistency with the Tailwind design system.


34-34: Remove commented import or add explanation.

The commented import should either be removed if not needed or uncommented if it will be used.

-// import { createNewTodoOnSubGoal } from "@/lib/main/subGoalFetching";

If this import will be needed for future functionality, consider adding a TODO comment explaining when it will be used.


384-387: Remove unused/mysterious div element.

This div appears to be leftover from design tools or serves no clear purpose. It should be removed to clean up the code.

-          <div
-            data-type="normal"
-            className="w-40 h-9 left-0 top-0 absolute"
-          ></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 b02d996 and eb32626.

📒 Files selected for processing (2)
  • components/main/TodoList/TodoList.tsx (1 hunks)
  • components/shared/BottomTabBar/BottomTabBar.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/shared/BottomTabBar/BottomTabBar.tsx
🧰 Additional context used
📓 Path-based instructions (1)
`components/**/*`: Component should be created in components/

components/**/*: Component should be created in components/

📄 Source: CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)

List of files the instruction was applied to:

  • components/main/TodoList/TodoList.tsx
🧠 Learnings (1)
components/main/TodoList/TodoList.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: For every styling, use tailwind css.
🧬 Code Graph Analysis (1)
components/main/TodoList/TodoList.tsx (4)
types/todoList.ts (1)
  • TodoItemsInfo (7-7)
api/generated/motimo/Api.ts (1)
  • TodoRs (179-212)
lib/main/goalFetching.ts (1)
  • createNewSubGoalOnGoal (70-70)
lib/main/todoFetching.ts (2)
  • toggleTodo (48-48)
  • deleteTodo (45-45)
🪛 Biome (1.9.4)
components/main/TodoList/TodoList.tsx

[error] 196-197: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 333-334: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: chromatic-test
🔇 Additional comments (1)
components/main/TodoList/TodoList.tsx (1)

63-149: LGTM! Well-structured component with proper state management.

The main TodoList component is well-implemented with proper use of React hooks, context, and conditional rendering. The optimistic updates pattern is correctly set up and the component handles various states appropriately.

Comment on lines +378 to +382
type="button"
className="justify-start text-white text-sm font-semibold font-['Pretendard'] leading-tight"
>
목표 상세페이지로 이동
</button>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add proper button functionality or disable the button.

The button has no onClick handler, which makes it non-functional. Either add the navigation logic or disable the button if the functionality is not yet implemented.

           <button
             type="button"
             className="justify-start text-white text-sm font-semibold font-['Pretendard'] leading-tight"
+            onClick={() => {
+              // TODO: Navigate to goal detail page
+            }}
           >
             목표 상세페이지로 이동
           </button>

Alternatively, if the functionality is not ready:

           <button
             type="button"
+            disabled
             className="justify-start text-white text-sm font-semibold font-['Pretendard'] leading-tight"
           >
             목표 상세페이지로 이동
           </button>
📝 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
type="button"
className="justify-start text-white text-sm font-semibold font-['Pretendard'] leading-tight"
>
목표 상세페이지로 이동
</button>
type="button"
className="justify-start text-white text-sm font-semibold font-['Pretendard'] leading-tight"
onClick={() => {
// TODO: Navigate to goal detail page
}}
>
목표 상세페이지로 이동
</button>
🤖 Prompt for AI Agents
In components/main/TodoList/TodoList.tsx around lines 378 to 382, the button
lacks an onClick handler, making it non-functional. To fix this, either add the
appropriate onClick handler to implement the navigation logic to the 목표 상세페이지
or, if the functionality is not ready, add the disabled attribute to the button
to prevent user interaction.

AppBar보다 BottomSheet와 Modal이 z-index 높도록 수정
@Hys-Lee Hys-Lee requested a review from devgony July 8, 2025 06:14
body자체를 scrollbar에 의해 layout shift발생하지 않게 수정하고, bottom sheet에도 적용했습니다.
component/shared 패키지 버전 수정에 따른 lock파일 변경이 추가로 있습니다.
bottom tabbar의 fixed로 인해 modal과의 z-index차이를 조정했습니다.
상단 AppBar관련해서 배너 상단에 공간을 만들어 ui겹침을 제거했습니다.
Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (3)
app/globals.css (1)

35-37: Consider alternative approaches for preventing scrollbar layout shifts.

While width: 100vw; overflow-x: hidden; prevents layout shifts, using 100vw can cause issues on mobile browsers where the viewport width includes the scrollbar width, potentially creating horizontal scrolling problems.

Consider these alternative approaches:

- /* 스크롤바 layout shift안되게 수정 */
- width: 100vw;
- overflow-x: hidden;
+ /* 스크롤바 layout shift안되게 수정 */
+ width: 100%;
+ overflow-x: hidden;

Or use the more modern CSS approach:

- /* 스크롤바 layout shift안되게 수정 */
- width: 100vw;
- overflow-x: hidden;
+ /* 스크롤바 layout shift안되게 수정 */
+ width: 100%;
+ overflow-x: hidden;
+ scrollbar-gutter: stable;
app/page.tsx (1)

52-64: Remove commented-out code blocks.

The commented-out code blocks should be removed to keep the codebase clean, especially since this appears to be leftover from development.

- {/* <div className="flex justify-end w-full">
-   <AppBar type="main" />
- </div>
- <Banner
-   title="목표는 멀어도 나는 계속 가는 중"
-   tag="모티모와 함께 한 지 1일차"
- /> */}
- {/* <div className="w-full flex-1 p-4 bg-background-normal inline-flex flex-col justify-start items-start gap-2 ">
-   <GoalTitleArea goalTitle="6개월 안에 책 50권 읽기" />
-   <GoalInfo leftDateNum={180} leftTodoNum={0} />
-   <TodoList initTodoItemsInfo={[]} todoTotalLen={0} />
- </div> */}
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (1)

253-260: Simplify null checking with optional chaining.

The explicit null check can be simplified using optional chaining for better readability and modern JavaScript practices.

-                nullabeTodoInfo &&
-                  nullabeTodoInfo.setTodoInfo((prev) => ({
-                    ...prev,
-                    subGoalTitle: subGoalTitle,
-                    subGoalId: subGoalId,
-                  }));
+                nullabeTodoInfo?.setTodoInfo((prev) => ({
+                  ...prev,
+                  subGoalTitle: subGoalTitle,
+                  subGoalId: subGoalId,
+                }));
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between eb32626 and 0622490.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • app/globals.css (2 hunks)
  • app/layout.tsx (3 hunks)
  • app/page.tsx (3 hunks)
  • components/main/MainHeader/MainHeader.tsx (1 hunks)
  • components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (1 hunks)
  • components/shared/Modal/_compound/Modal.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • components/shared/Modal/_compound/Modal.tsx
  • app/layout.tsx
  • components/main/MainHeader/MainHeader.tsx
🧰 Additional context used
📓 Path-based instructions (1)
`components/**/*`: Component should be created in components/

components/**/*: Component should be created in components/

📄 Source: CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)

List of files the instruction was applied to:

  • components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx
🧠 Learnings (1)
app/page.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The first example name of storybook should be `Primary` not `Default`
🪛 Biome (1.9.4)
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx

[error] 256-263: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: chromatic-test
🔇 Additional comments (6)
app/page.tsx (2)

17-17: Component rename aligns with PR objectives.

The component rename from Home to Main properly reflects the main page functionality described in the PR objectives.


44-72: Excellent modular component structure.

The new main page structure with separate components (MainHeader, GoalMenuContainer, GoalCard, BottomTabBar) provides good separation of concerns and aligns perfectly with the PR objectives of completing the main page functionality.

components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (4)

56-76: Well-implemented utility function.

The makeDefaultTodoBottomSheetInfo function properly handles both initialization scenarios with appropriate fallbacks and null safety checks.


78-228: Solid component architecture and state management.

The main component demonstrates good React patterns with proper state management, form handling, and lifecycle methods. The conditional rendering and event handling are well-structured.


287-335: Well-implemented date picker component.

The BottomSheetDate component properly manages date selection state and provides a clean user interface for date picking with appropriate cancel/confirm actions.


337-339: Clean date formatting utility.

The date2stringSplitByDot function correctly formats dates with proper zero-padding. The inline comment explains the rationale for its placement.

</div>
);
}
const tmpDaysOfServiceUse = 1;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace hardcoded temporary value with proper implementation.

The hardcoded tmpDaysOfServiceUse = 1 should be replaced with actual service usage calculation or fetched from an API.

Consider implementing proper days calculation:

- const tmpDaysOfServiceUse = 1;
+ const daysOfServiceUse = useMemo(() => {
+   // Calculate actual days since service registration
+   const registrationDate = new Date(/* get from user data */);
+   const now = new Date();
+   return Math.floor((now.getTime() - registrationDate.getTime()) / (1000 * 60 * 60 * 24));
+ }, []);

Or fetch from an API endpoint if available.

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

🤖 Prompt for AI Agents
In app/page.tsx at line 41, replace the hardcoded temporary value
`tmpDaysOfServiceUse = 1` with a dynamic calculation of the actual days of
service use or fetch this value from an appropriate API endpoint. Implement
logic to compute the days based on relevant data or integrate an API call to
retrieve the accurate service usage duration.

Comment on lines +32 to +38
type TodoInfo = {
id?: TodoInfoForSubmission["todo"];
todo: TodoInfoForSubmission["todo"];
date?: TodoInfoForSubmission["date"];
subGoalTitle?: TodoInfoForSubmission["subGoalTitle"];
subGoalId?: TodoInfoForSubmission["subGoalId"];
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix type reference error.

The id property in TodoInfo type references the wrong field from TodoInfoForSubmission. It should reference the id field, not the todo field.

type TodoInfo = {
-  id?: TodoInfoForSubmission["todo"];
+  id?: TodoInfoForSubmission["id"];
  todo: TodoInfoForSubmission["todo"];
  date?: TodoInfoForSubmission["date"];
  subGoalTitle?: TodoInfoForSubmission["subGoalTitle"];
  subGoalId?: TodoInfoForSubmission["subGoalId"];
};
📝 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
type TodoInfo = {
id?: TodoInfoForSubmission["todo"];
todo: TodoInfoForSubmission["todo"];
date?: TodoInfoForSubmission["date"];
subGoalTitle?: TodoInfoForSubmission["subGoalTitle"];
subGoalId?: TodoInfoForSubmission["subGoalId"];
};
type TodoInfo = {
id?: TodoInfoForSubmission["id"];
todo: TodoInfoForSubmission["todo"];
date?: TodoInfoForSubmission["date"];
subGoalTitle?: TodoInfoForSubmission["subGoalTitle"];
subGoalId?: TodoInfoForSubmission["subGoalId"];
};
🤖 Prompt for AI Agents
In components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx around
lines 32 to 38, the TodoInfo type incorrectly sets the id property to reference
TodoInfoForSubmission["todo"]. Change this to reference
TodoInfoForSubmission["id"] instead to fix the type reference error.

Hys-Lee added 3 commits July 9, 2025 12:16
엔터로 입력하면 높이 이상해지는 버그 수정했습니다.
focus관련한 버그여서 blur처리로 수정했습니다.
반환값을 보고 결과를 판단하도록 로직을 짰는데, 반환하지 않아서 제대로 작동하지 않았었습니당.
주소 동적 연결되게 수정 및 msw 주석처리.
이외 자잘한 오류 정리
Copy link
Copy Markdown

@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

♻️ Duplicate comments (3)
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (1)

32-38: Fix type reference error.

The id property in TodoInfo type references the wrong field from TodoInfoForSubmission. It should reference the id field, not the todo field.

type TodoInfo = {
-  id?: TodoInfoForSubmission["todo"];
+  id?: TodoInfoForSubmission["id"];
  todo: TodoInfoForSubmission["todo"];
  date?: TodoInfoForSubmission["date"];
  subGoalTitle?: TodoInfoForSubmission["subGoalTitle"];
  subGoalId?: TodoInfoForSubmission["subGoalId"];
};
components/main/TodoList/TodoList.tsx (2)

379-384: Add proper button functionality or disable the button.

The button has no onClick handler, which makes it non-functional. Either add the navigation logic or disable the button if the functionality is not yet implemented.

<button
  type="button"
+ onClick={() => {
+   // TODO: Navigate to goal detail page
+ }}
  className="justify-start text-white text-sm font-semibold font-['Pretendard'] leading-tight"
>
  목표 상세페이지로 이동
</button>

Alternatively, if the functionality is not ready:

<button
  type="button"
+ disabled
  className="justify-start text-white text-sm font-semibold font-['Pretendard'] leading-tight"
>
  목표 상세페이지로 이동
</button>

317-325: Fix optimistic checked count logic and remove commented code.

The optimistic update logic has issues and there's commented code that should be addressed.

onChecked={async () => {
  startTransition(async () => {
    toggleChecekdOptimistically();
+    updateOptimisticCheckedLen && updateOptimisticCheckedLen(checked ? -1 : 1);
    await toggleTodo(info.id);
    mutate && mutate();
  });
-  // updateOptimisticCheckedLen &&
-  //   updateOptimisticCheckedLen(checked ? -1 : +1);
}}

The optimistic update should be moved inside the startTransition to ensure consistency.

🧹 Nitpick comments (6)
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (3)

96-102: Improve the blur handling and add error handling.

The current blur handling uses type assertion which can be unsafe. Consider using a more type-safe approach.

const resetBottomSheet = () => {
  setIsActivated(false);
  setVisibleSelect(false);
  setShowDate(false);
  setTodoInfo(makeDefaultTodoBottomSheetInfo(subGoals));
-  inputRef.current && (inputRef.current as HTMLInputElement).blur();
+  if (inputRef.current) {
+    (inputRef.current as HTMLInputElement).blur();
+  }
};

266-276: Use optional chaining for better code safety.

The current conditional logic can be simplified using optional chaining.

onClick={() => {
-  nullabeTodoInfo &&
-    nullabeTodoInfo.setTodoInfo((prev) => ({
-      ...prev,
-      subGoalTitle: subGoalTitle,
-      subGoalId: subGoalId,
-    }));
+  nullabeTodoInfo?.setTodoInfo((prev) => ({
+    ...prev,
+    subGoalTitle: subGoalTitle,
+    subGoalId: subGoalId,
+  }));
}}

351-353: Move utility function to a proper location.

The utility function date2stringSplitByDot is defined inline but would be better placed in a dedicated utils module for reusability.

Consider moving this function to a shared utility module:

// utils/dateUtils.ts
export const date2stringSplitByDot = (date: Date) =>
  `${date.getFullYear()}.${String(date.getMonth() + 1).padStart(2, "0")}.${String(date.getDate()).padStart(2, "0")}`;

Then import and use it in this component.

components/main/TodoList/TodoList.tsx (3)

186-194: Use optional chaining for better code safety.

The current conditional logic can be simplified using optional chaining.

onAddSubGoal={async (subGoal: string) => {
  // mutateResult가 네트워크 fail에서는 undefined가 나와야 함.
  if (!goalId) return;

  const mutateResult = await createNewSubGoalOnGoal(goalId, {
    title: subGoal,
  });
  if (mutateResult) {
-    mutate && mutate();
+    mutate?.();
    closeModal();
  }
}}

332-340: Use optional chaining for better code safety.

The current conditional logic can be simplified using optional chaining.

const initTodoInfo = {
-  date: info?.targetDate,
+  date: info?.targetDate,
  subGoalId: subGoalId ?? "",
  subGoalTitle: subGoalTitle ?? "",
  todo: info?.title,
  id: info?.id,
};

This specific line is already using optional chaining correctly, but the static analysis hint might be referring to other usages in the same area.


274-276: Fix typo in function name.

There's a typo in the function name toggleChecekdOptimistically - it should be toggleCheckedOptimistically.

-const [checked, toggleChecekdOptimistically] = useOptimisticToggle(
+const [checked, toggleCheckedOptimistically] = useOptimisticToggle(
  info.checked ?? false,
);

Make sure to update all references to this function throughout the component.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0622490 and df2ed11.

📒 Files selected for processing (6)
  • app/layout.tsx (3 hunks)
  • components/main/TodoList/TodoList.tsx (1 hunks)
  • components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (1 hunks)
  • components/shared/TodoItem/TodoItem.tsx (4 hunks)
  • lib/main/todoFetching.ts (1 hunks)
  • next.config.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • app/layout.tsx
  • components/shared/TodoItem/TodoItem.tsx
  • next.config.ts
  • lib/main/todoFetching.ts
🧰 Additional context used
📓 Path-based instructions (1)
`components/**/*`: Component should be created in components/

components/**/*: Component should be created in components/

📄 Source: CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)

List of files the instruction was applied to:

  • components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx
  • components/main/TodoList/TodoList.tsx
🧠 Learnings (1)
components/main/TodoList/TodoList.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: For every styling, use tailwind css.
🧬 Code Graph Analysis (2)
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (1)
components/shared/Button/Button.tsx (1)
  • Button (77-77)
components/main/TodoList/TodoList.tsx (4)
types/todoList.ts (1)
  • TodoItemsInfo (7-7)
api/generated/motimo/Api.ts (1)
  • TodoRs (179-212)
lib/main/goalFetching.ts (1)
  • createNewSubGoalOnGoal (70-70)
lib/main/todoFetching.ts (2)
  • toggleTodo (53-53)
  • deleteTodo (50-50)
🪛 Biome (1.9.4)
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx

[error] 270-277: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

components/main/TodoList/TodoList.tsx

[error] 197-198: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


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

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: chromatic-test

Comment on lines +154 to +165
onSubmit={async (e) => {
e.preventDefault();
e.stopPropagation();
if (todoInfo.subGoalTitle) {
const submitRes = await onSubmitTodo(
todoInfo as TodoInfoForSubmission,
);

submitRes && resetBottomSheet();
}
// else의 경우 에러 메시지를 넣어야 할 수도 있음
}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add proper error handling for form submission.

The form submission lacks comprehensive error handling. Consider adding user feedback for failed submissions.

onSubmit={async (e) => {
  e.preventDefault();
  e.stopPropagation();
  if (todoInfo.subGoalTitle) {
+    try {
      const submitRes = await onSubmitTodo(
        todoInfo as TodoInfoForSubmission,
      );
      submitRes && resetBottomSheet();
+    } catch (error) {
+      console.error('Failed to submit todo:', error);
+      // Add user notification here
+    }
  }
-  // else의 경우 에러 메시지를 넣어야 할 수도 있음
+  else {
+    // Add validation error handling here
+  }
}}
📝 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
onSubmit={async (e) => {
e.preventDefault();
e.stopPropagation();
if (todoInfo.subGoalTitle) {
const submitRes = await onSubmitTodo(
todoInfo as TodoInfoForSubmission,
);
submitRes && resetBottomSheet();
}
// else의 경우 에러 메시지를 넣어야 할 수도 있음
}}
onSubmit={async (e) => {
e.preventDefault();
e.stopPropagation();
if (todoInfo.subGoalTitle) {
try {
const submitRes = await onSubmitTodo(
todoInfo as TodoInfoForSubmission,
);
submitRes && resetBottomSheet();
} catch (error) {
console.error('Failed to submit todo:', error);
// Add user notification here
}
} else {
// Add validation error handling here
}
}}
🤖 Prompt for AI Agents
In components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx around
lines 154 to 165, the onSubmit handler does not handle errors from the
onSubmitTodo call. Update the handler to catch any errors during submission and
provide user feedback, such as displaying an error message or notification, when
the submission fails. Ensure that the error handling does not block the form's
normal flow and resets or maintains the form state appropriately.

Comment on lines +343 to +346
onDelete={async () => {
await deleteTodo(info.id);
mutate && mutate();
}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for delete operation.

The delete operation lacks error handling which could lead to silent failures.

onDelete={async () => {
+  try {
    await deleteTodo(info.id);
    mutate && mutate();
+  } catch (error) {
+    console.error('Failed to delete todo:', error);
+    // Add user notification here
+  }
}}
📝 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
onDelete={async () => {
await deleteTodo(info.id);
mutate && mutate();
}}
onDelete={async () => {
try {
await deleteTodo(info.id);
mutate && mutate();
} catch (error) {
console.error('Failed to delete todo:', error);
// Add user notification here
}
}}
🤖 Prompt for AI Agents
In components/main/TodoList/TodoList.tsx around lines 343 to 346, the onDelete
async function calls deleteTodo without any error handling, which may cause
silent failures. Wrap the deleteTodo call in a try-catch block, and in the catch
block handle or log the error appropriately to ensure any failure during
deletion is captured and can be addressed.

Comment on lines +320 to +322
await toggleTodo(info.id);
mutate && mutate();
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for toggle operation.

The toggle operation lacks error handling which could lead to inconsistent state.

startTransition(async () => {
  toggleChecekdOptimistically();
+  try {
    await toggleTodo(info.id);
    mutate && mutate();
+  } catch (error) {
+    console.error('Failed to toggle todo:', error);
+    // Revert optimistic update here
+    toggleChecekdOptimistically();
+  }
});
📝 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
await toggleTodo(info.id);
mutate && mutate();
});
startTransition(async () => {
toggleChecekdOptimistically();
try {
await toggleTodo(info.id);
mutate && mutate();
} catch (error) {
console.error('Failed to toggle todo:', error);
// Revert optimistic update here
toggleChecekdOptimistically();
}
});
🤖 Prompt for AI Agents
In components/main/TodoList/TodoList.tsx around lines 320 to 322, the toggleTodo
function call lacks error handling, which may cause inconsistent state if the
operation fails. Wrap the await toggleTodo(info.id) call in a try-catch block,
and in the catch block, handle the error appropriately, such as logging the
error or showing a user notification. This ensures that any failure during the
toggle operation is managed gracefully without breaking the app flow.

Copy link
Copy Markdown
Collaborator

@devgony devgony left a comment

Choose a reason for hiding this comment

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

👍🏼 👍🏼👍🏼

@Hys-Lee Hys-Lee merged commit 2c7960a into prography:main Jul 9, 2025
3 of 4 checks passed
Hys-Lee added a commit that referenced this pull request Jul 9, 2025
* feat: 메인 페이지 제작중

관련 svg설정 next turbopack에 적용

* feat: 메인 페이지 제작에 필요한 컴포넌트 추가 제작

GoalMenuContainer, GoalTItleArea.
TodoList는 todoItem이 빈 배열이라 checkedLen필요 없을 때를 고려해 수정함.

* feat: 일부 공유 컴포넌트 반응형으로 수정

고정 너비가 아니라 full로 수정함.
고정 크기일 필요가 없어보여서 임시로 수정.
추후 디자이너가 결정한 것으로 수정 가능.

* feat: 메인페이지 추가 컴포넌트 AppBar 제작

* feat: msw 적용하기

* feat: 메인 페이지 제작 관련 컴포넌트 수정

svg들 폴더 위치 변경

* feat: 배너 컴포넌트 반응형으로 수정

* feat: 모달 컴포넌트 및 관련 훅과 스토어 생성 (진행중)

모달 공통 컴포넌트와 파생 컴포넌트 제작.
공통에서 종속적인 부분이 있어 합성 컴포넌트로 제작.
모달 전역 관리를 위해 zustand와 커스텀 훅을 사용.
svgr관련 세팅 대해 브랜치 꼬여서 임시 저장.

* feat: TodoList 접힌 상황 추가 및 api에 대한 추상화 타입 적용. 비동기 미처리.

api 변동과 무관하게 사용될 타입을 생성해 적용했습니다. api의 반환 타입을 이로 변환하는 로직을 fetch함수 만들 때 적용 예정입니다.

* feat: AppBar삭제 및 패키지 재설치

공유 컴포넌트에 있었어서 AppBar는 삭제함.

* feat: 불필요 컴포넌트 제거(ModalAddingSubGoal겹침)

* feat: 모달 버튼 공용 컴포넌트의 것으로 수정

* feat: 메인 페이지 TodoList 모달 연결

* feat: todoList관련 데이터 페칭 연결 임시

* feat: api generation 스크립트 수정 및 재생성

* feat: 날짜 타입 문자열로 변환하는 유틸 함수 제작

* feat: todo와 subGoal관련 fetching 함수 제작

이곳에 타입 변환 존재합니다

* feat: api generator fetch기반으로 변경 후 재생성

* feat: todo, todolist관련 swr 훅 제작

* feat: TodoItem 체크에 대한 낙관적 업데이트위한 훅 제작

기본 useOptimistic은 action인자가 필요하지만, 체크는 toggle이라 필요 없어서 따로 제작했습니다.
깔끔하게 만들기 위해서용.

* feat: TodoList 비동기 onEdit제외 연결

onEdit은 바텀 시트 제작 후 연결.

* feat: TodoList subGoal추가 관련 비동기 수정

mutate 적용

* feat: 스토리북 generation 예외 추가

완성된 도메인 및 영역은 제외시킴.

* feat: shared 모노레포 구조에서 react 관련 버전 프로젝트 루트와 일치

shared에서 bottom sheet컴포넌트 제작에 외부 라이브러리 사용할 때, 버전 불일치 생겨서.

* feat: check svg 수정 관련 연관 컴포넌트 TodoItem 수정

svg 색상을 외부에서 주입하도록 바꿔서, 기존에 사용하던 TodoItem에서 흰색 주입하도록 했습니다.

* feat: TodoBottomSheet 완성

비동기 동작의 책임을 외부에 넘겼습니다.

* feat: 데이터 페칭 이후 타입 변환의 책임을 비동기 훅으로 변경

비동기 훅은 도메인 별로 커스텀 가능한 것이기 때문에 변경했습니다.

* feat: goal 관련 fetching함수 제작

* feat: TodoBottomSheet 동작 수정

초기값 바뀌는 동작 외부에서 key로 제어하지 않고, 내부에서 useEffect로 제어하도록 변경함.
key로 제어하면 remount때문에 애니메이션 이상해서.

* feat: todo, goal, subGoal에 대한 fethcing과 쿼리 훅 생성

데이터 처리를 쿼리 훅 내부에서 하도록 수정.
mutate는 대부분 낙관적 업데이트로 사용하지 않기 때문에 변환 로직으로 덮어쓰지 않았음.

* feat: TodoBottomSheet활성화, 선택된 goal관련 zustand store생성

이들 데이터는 멀리 떨어진 컴포넌트 사이에서 사용되기 때문에 전역 상태 사용함.

* feat: msw모킹 위한 api 및 db 생성

* feat: 메인 페이지 goal관련 데이터 갖는 GoalCard 컴포넌트 생성 (진행중)

* feat: 메인 페이지에 필요한 컴포넌트 생성 및 수정  MainHeader, GoalMenuContainer (임시)

문구 api연결은 아직 안했고, 컴포넌트 구분만 해뒀습니다.
GoalMenuContainer는 선택에 대해 zustand로 전역 상태 처리하도록 수정했습니다.

* feat: 메인 페이지 연결을 위한 자잘한 수정

fetchTemplate는 위치 변경으로 인한 수정.
GoalMenu는 api연결에 필요한 타입 export
TodoItem은 UI가 반응형으로 동작하도록 수정

* feat: TodoList 메인페이지 api연결을 위한 수정

쿼리 훅과 zustand 사용해 동작하도록 수정함. edit버튼 클릭에 대한 동작 추가함. UI반응형으로 동작하도록 w-full로 수정함.

* fix: 바텀 시트 todo추가 동작 수정, 바텀시트 선택된 subgoal 버튼에 보이도록 수정

todo추가 동작 수정에 대해서, 기존 분기처리 잘못해 update를 실행하던 것을 create실행하도록 수정

* fix: TodoBottomSheet 상태 초기화 수정

initTodoInfo를 매번 object 새로 생성해 넘겨줘서 useEffect가 동작했음. 이에 컴폰너트 내부에서 분해해서 사용하도록 수정함.

* feat: GoalCard 모달이 존재하면 바텀시트 닫도록 수정.

이렇지 않으면 dialog가 rule로 지정된 바텀시트에 focus-trap이 걸림.

* feat: useModal 수정

바텀시트 사용할 때 모달의 사용을 알 수 있도록 isOpen을 추가함.

* feat: TodoList에서 ModalAddingSubGoal 동작 관련 연결

subgoal을 추가할 수 있도록 api제작 및 연결

* fix: 자잘한 UI 에러 수정

* feat: 페칭 및 훅 자잘한 수정

use client추가 및 타입 수정

* feat: useTodoList undefined도 가능하도록 수정.

사용하는 입장에서 undefined반환 값으로 처리 분기할 수 있도록.

* feat: cheer, point 관련 fetching 제작

goalFetching에서 불필요 부분 삭제

* feat: 모킹 구조 변경 및 points, cheer 핸들러 추가

관리하기 쉽도록 분리했습니다.

* feat: 불필요 부분 삭제

콘솔 제거 및 element정리

* feat: fetch 동작에서 헤더 설정 수정

get요청에서도 authorization등 적용되도록 수정

* feat: 목표 추가 버튼 제작

모달 클릭 후 페이지 이동은 아직 구현하지 않았습니다.
해당 페이지 구현 마친 후 라우팅 추가하겠습니다.

* feat: GoalCard와 useGoalWithSubGoalTodo대해 타입 및 props명 변경에 따른 수정

* feat: BottomTabBar Link추가로 페이지 이동할 수 있도록 함.

* feat: main페이지에 BottomTabBar추가에 따른 UI수정

(이전 커밋에서 GoalCard에서 pb추가)
TodoBottomSheet는 바텀탭바 존재에 따라 위치 변경 가능하도록 수정.
추가로,
여기서, 기본 subGoal 지정.

* feat: main page에서 bottom tab bar관련 불필요 패딩 제거.

* feat: 로컬 개발 시 msw사용하도록 수정

발표할 때 필요할 것 같아서.

* feat: 시연 전 ui 수정사항 반영

* feat: 스토리북 빌드 에러 수정

컴포넌트들 props변경에 따른 에러 수정.

* feat: shared 모노 레포 관련 유틸 함수 처리

shared내부에 동일한 것으로 복제했습니다.

* feat: 페이지 이동 관련 수정

onboarding에서 Link를 통해 이동
fetch 시 로컬스토리지에서 access token사용하도록 변경
메인 페이지 수정

* fix: PR 전 정리

BottomTabBar 불필요 key제거
TodoList className정리, scroll 되도록 수정, 불필요 낙관적 업데이트 제거

* feat: AppBar 상단 고정 및 관련해 z-index 수정

AppBar보다 BottomSheet와 Modal이 z-index 높도록 수정

* feat: 메인페이지 bottom tab bar추가 및 bottom sheet와 함께 모바일 넓이에 맞게 조정

body자체를 scrollbar에 의해 layout shift발생하지 않게 수정하고, bottom sheet에도 적용했습니다.
component/shared 패키지 버전 수정에 따른 lock파일 변경이 추가로 있습니다.
bottom tabbar의 fixed로 인해 modal과의 z-index차이를 조정했습니다.
상단 AppBar관련해서 배너 상단에 공간을 만들어 ui겹침을 제거했습니다.

* fix: TodoBottomSheet 버그 수정

엔터로 입력하면 높이 이상해지는 버그 수정했습니다.
focus관련한 버그여서 blur처리로 수정했습니다.

* fix: fetching 반환값 반환하도록 해서 이후 동작 연결되도록 수정

반환값을 보고 결과를 판단하도록 로직을 짰는데, 반환하지 않아서 제대로 작동하지 않았었습니당.

* feat: dev서버 배포 전 프록시 및 msw수정

주소 동적 연결되게 수정 및 msw 주석처리.
이외 자잘한 오류 정리
This was referenced Aug 17, 2025
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.

2 participants