Conversation
현재 달 이전으로는 disable처리
제어형으로 만들어서 외부에서 선택 처리하도록 함.
앞으로의 페이지 개발과 관련해서 목표 추가
컴포넌트 내부는 deferred가 아니라 낙관적 업뎃을 사용해야 하므로 useDeferredValue제거. 스토리북에선 onChecked를 비동기 동작 적용
외부에서 width, height주입으로 크기 변경가능하게 함. 이에 따른 ToolTip컴포넌트에서의 사용 수정
FloatingButton컴폰너트에서도 사용되는 svg이라서.
ci과정 트리거 위해 무의미한 스토리북 수정
빌드 시 html생성이 될 때도 있고 안될 때도 있어서. CI에서는 캐싱 문제일 수 있다기에 수정
WalkthroughThis update introduces a major refactor of the group chat feature. It adds a new infinite-scroll group chat room component, a header component with navigation, and a custom hook for paginated chat fetching. The old group detail page is replaced with a streamlined version using these new components. Several components are simplified and type definitions updated to focus on "todo" and "reaction" chat styles. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant GroupRoomHeader
participant GroupChatRoom
participant useGroupChatInfinite
participant API
User->>GroupRoomHeader: Clicks back/member button
GroupRoomHeader->>User: Navigates back or to member list
User->>GroupChatRoom: Scrolls chat view
GroupChatRoom->>useGroupChatInfinite: Requests messages (infinite scroll)
useGroupChatInfinite->>API: Fetch group chat messages
API-->>useGroupChatInfinite: Returns paginated messages
useGroupChatInfinite-->>GroupChatRoom: Supplies sorted messages
GroupChatRoom->>User: Renders chat messages
User->>GroupChatRoom: Clicks reaction button
GroupChatRoom->>ReactionModal: Opens modal
User->>ReactionModal: Selects reaction
ReactionModal->>API: Submits reaction
API-->>GroupChatRoom: Updates chat data
GroupChatRoom->>User: Refreshes chat view
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Poem
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
npm error Exit handler never called! Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 32
🔭 Outside diff range comments (3)
components/main/GoalMenuContainer/GoalMenuContainer.tsx (1)
25-30: WrapgoalMenuInfoListinuseMemoto prevent unnecessary re-renders.The computation creates a new array on every render, which causes React Hooks dependency warnings and potential performance issues.
Apply this diff to memoize the computation:
+import { useEffect, useState, useRef, useMemo } from "react"; -import { useEffect, useState, useRef } from "react"; const GoalMenuContainer = ({}: GoalMenuContainerProps) => { const { data: rawGoalData, mutate } = useGoals(); // Convert raw goal data to the format expected by the component - const goalMenuInfoList: GoalMenuInfo[] = + const goalMenuInfoList: GoalMenuInfo[] = useMemo(() => rawGoalData?.goals?.map((goalInfo) => ({ goal: goalInfo.title ?? "", percentage: goalInfo.progress ?? 0, goalId: goalInfo.id ?? "", - })) ?? []; + })) ?? [], [rawGoalData?.goals]);hooks/queries/useTodoList.ts (1)
1-56: Remove commented-out code file.This entire file contains only commented-out code. If this hook has been replaced by the new infinite scrolling hooks, the file should be deleted rather than kept as commented code. Version control history will preserve this code if needed for reference.
Consider deleting this file entirely if it's no longer needed.
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (1)
104-107: Add missingsubGoalsdependency touseEffect.The effect uses
subGoalsthroughmakeDefaultTodoBottomSheetInfobut doesn't include it in the dependency array, which could lead to stale data issues.Apply this diff:
useEffect(() => { setTodoInfo(makeDefaultTodoBottomSheetInfo(subGoals, initTodoInfo)); - }, [initTodoInfo, openBottomSheet]); + }, [initTodoInfo, openBottomSheet, subGoals]);
🧹 Nitpick comments (60)
.gitignore (1)
55-57: Broaden the ignore pattern to cover all dotenv variantsDevelopers often use multiple
.envvariants (.env.local,.env.production, etc.). Ignoring only the base.envincreases the risk of accidentally committing secrets. A single wildcard rule protects them all:-# environment variables -.env +# environment variables +# Ignore all dotenv-style files to prevent leaking secrets +.env*components/shared/Banner/Banner.tsx (1)
9-22: Consider using tokens.css for color and font values.The component uses hardcoded values like
Color-white,Color-black, andfont-['SUIT_Variable']. Per coding guidelines, these should reference tokens.css for consistent theming.Consider updating color and font references to use design tokens:
- className="w-full px-6 py-4 bg-indigo-500 inline-flex justify-start items-center gap-3" + className="w-full px-6 py-4 bg-primary-500 inline-flex justify-start items-center gap-3" - text-Color-white text-base font-bold font-['SUIT_Variable'] + text-white text-base font-bold font-suit-variablecomponents/shared/Modal/ModalDeletingSubGoal/ModalDeletingSubGoal.tsx (1)
6-6: Fix typo in prop name.The prop name
onDeletSubGoalecontains a typo and should beonDeleteSubGoalfor consistency and proper English.- onDeletSubGoale: () => Promise<void>; + onDeleteSubGoal: () => Promise<void>;- onDeletSubGoale, + onDeleteSubGoal,Also applies to: 11-11
components/shared/GoalMenu/GoalMenu.tsx (1)
32-32: Avoid hard-coded pixel widths; stick to design tokens or Tailwind scale
w-[140px]/min-w-[140px]introduces a magic number that bypasses both the Tailwind spacing scale and the design-token system mandated bytokens.css. Unless the design system explicitly calls for 140 px, consider:- className={` w-[140px] min-w-[140px] ... + className={` w-36 min-w-36 ... // 9 rem = 144 pxor create a semantic width token in
tokens.cssand reference it through Tailwind’stheme()or a CSS variable.utils/subGoalTodo2TodoItemList.ts (1)
13-13: Simplify the boolean expression.The ternary operator is unnecessary here as the expression already evaluates to a boolean.
Apply this diff to simplify:
- reported: todoInfo.todoResult?.todoResultId ? true : false, + reported: !!todoInfo.todoResult?.todoResultId,components/details/TabMenu/TabMenu.tsx (1)
11-32: Remove unnecessary fragment wrapper and simplify onClick handler.The React fragment is unnecessary when returning a single element, and the onClick handler can be simplified.
Apply this diff to clean up:
- <> - <div - onClick={() => onClick()} + <div + onClick={onClick} className="w-full h-12 px-4 py-2 relative inline-flex justify-center items-center gap-2" - > + > {/* ... rest of component */} - </div> - </> + </div>app/group/[group_id]/page.tsx (1)
7-17: LGTM - Clean implementation with proper data flow.The component correctly extracts URL parameters, fetches group data, and passes props to child components. The Tailwind CSS usage follows the coding guidelines.
Consider adding error handling for cases where the group_id is invalid or the API call fails:
if (!groupId) { return <div>Invalid group ID</div>; } if (!data) { return <div>Loading...</div>; }components/details/SubGoalEditItem/SubGoalEditItem.tsx (1)
17-51: Clean up component structure and event handlers.The component has some minor structural improvements that could be made.
Apply this diff to clean up:
return ( - <> - <div className="w-full gap-1 h-14 p-2 bg-background-alternative rounded-lg outline-1 outline-offset-[-1px] outline-line-normal flex justify-start items-center"> + <div className="w-full gap-1 h-14 p-2 bg-background-alternative rounded-lg outline-1 outline-offset-[-1px] outline-line-normal flex justify-start items-center"> {/* ... draggable and title content ... */} <div className="flex justify-end gap-1"> <button - onClick={() => onEdit()} + onClick={onEdit} type="button" className="w-8 h-8 p-2 bg-background-normal rounded inline-flex justify-center items-center gap-2" > {/* ... */} </button> <button - onClick={() => onDelete()} + onClick={onDelete} type="button" className="w-8 h-8 p-2 bg-background-normal rounded inline-flex justify-center items-center gap-2" > {/* ... */} </button> </div> - </div> - </> + </div>This removes the unnecessary fragment wrapper, simplifies event handlers, and cleans up extra spaces in class names.
components/details/EditInfo/EditInfo.tsx (2)
1-2: Remove unused import.The
WarningIconcomponent is imported but not used. OnlyWarningInfoSvgis being used in the component.-import { WarningIcon } from "@/components/icons"; import WarningInfoSvg from "@/public/images/WarningInfo.svg";
17-17: Remove commented code.The commented out div with outline styles should be removed to keep the code clean.
- {/* <div className="w-3.5 h-3.5 left-[2.50px] top-[2.50px] absolute outline outline-[1.50px] outline-offset-[-0.75px] outline-label-alternative"></div> */}components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx (1)
23-25: Consider adding functionality to the people button.The people button appears to be a placeholder without any click handler or functionality. Consider adding appropriate behavior or marking it as a future enhancement.
- <button type="button" className="w-10 h-10 text-label-alternative"> + <button + type="button" + className="w-10 h-10 text-label-alternative" + onClick={() => { + // TODO: Add people/member list functionality + }} + > <PeopleSvg /> </button>app/details/edit/[goal_id]/_components/EditHeader/EditHeader.tsx (2)
36-45: Consider responsive design and accessibility improvements.The hardcoded width
w-[55px]may cause issues on different screen sizes. Also, the button lacks proper accessibility attributes.<Button - // 너비가 충분치 않아 글씨가 제대로 안보여서 넓이 직접 수정 - className="w-[55px]" + className="min-w-[55px] px-3" form="GoalInfoEdit" type="submit" size="s" variant="filled" + aria-label="저장" > 저장 </Button>
15-17: Consider using semantic HTML for better accessibility.Using a
<header>element without proper semantic structure. Consider adding appropriate ARIA labels or semantic elements.<header - // AppBar에서 pl-4는 이미 처리 되어 있음. className="flex pr-4 justify-between items-center" + role="banner" + aria-label="편집 페이지 헤더" >components/main/GoalTitleArea/GoalTitleArea.tsx (1)
17-21: Consider accessibility and semantic structure for navigation.The current implementation nests a button inside a Link, which can cause accessibility issues and is semantically redundant.
- <Link href={`/details/${goalId}`} className="cursor-pointer"> - <button type="button" className="w-6 h-6 relative overflow-hidden"> - <RightArrowSvg width={24} height={24} /> - </button> - </Link> + <Link + href={`/details/${goalId}`} + className="w-6 h-6 relative overflow-hidden cursor-pointer inline-flex items-center justify-center" + aria-label={`${goalTitle} 상세 보기`} + > + <RightArrowSvg width={24} height={24} /> + </Link>app/details/[goal_id]/page.tsx (1)
14-14: Consider flexible layout instead of fixed height.Using
h-screenmight cause issues on mobile devices with dynamic viewport heights or when virtual keyboards appear.- <div className=" h-screen flex flex-col flex-1"> + <div className="min-h-screen flex flex-col flex-1">components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.tsx (1)
25-36: Remove unnecessary Fragment wrapper.The Fragment wrapping the bodyNode JSX is redundant since it contains only one child element.
bodyNode={ - <> <section className="flex flex-col gap-[6px] p-6 items-center justify-center"> <h2 className="text-center justify-start text-label-strong text-base font-bold font-['SUIT'] leading-tight"> 세부 목표 </h2> <p className="text-center justify-start text-label-alternative text-sm font-medium font-['SUIT_Variable'] leading-tight"> 세부 목표를 미완료 처리하시겠습니까? </p> </section> - </> }components/details/Modals/ModalExitingEdit/ModalExitingEdit.tsx (2)
43-52: Extract hard-coded Korean text and consider component organization.The Korean text is hard-coded within the component, which reduces maintainability and internationalization support. Additionally, the
Bodycomponent is defined inline at the bottom of the file.Consider extracting the text to constants or an i18n system:
+const MESSAGES = { + CONFIRM_EXIT: "편집화면에서 나가시겠습니까?\n수정된 사항은 저장되지 않습니다." +}; -const comment = `편집화면에서 나가시겠습니까?\n수정된 사항은 저장되지 않습니다.`; const Body = () => { return ( <div className="flex flex-col justify-center items-center gap-[6px] p-6"> <p className="whitespace-pre-wrap text-center justify-start text-label-strong text-base font-bold font-['SUIT_Variable'] leading-tight"> - {comment} + {MESSAGES.CONFIRM_EXIT} </p> </div> ); };Alternatively, move the
Bodycomponent to a separate file or extract it as a named export for better modularity.
30-31: Address the TODO comment for async handling.The comment indicates that asynchronous behavior needs to be handled in the future, but the current implementation doesn't account for this.
The
onExitcallback might need error handling or loading states for async operations. Do you want me to help implement proper async handling with loading states and error boundaries?components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.tsx (1)
47-58: Extract hard-coded Korean text for better maintainability.The Korean confirmation message is hard-coded, which reduces maintainability and internationalization support.
Extract the text to constants:
+const MESSAGES = { + CONFIRM_DELETE: "목표를 삭제하시겠습니까?", + DELETE_WARNING: "삭제 시 세부 목표와 작성된 투두도 함께 삭제됩니다." +}; const Body = () => { return ( <div className="flex flex-col justify-center items-center gap-[6px] p-6"> <p className="text-center justify-start text-label-strong text-base font-bold font-['SUIT_Variable'] leading-tight"> - 목표를 삭제하시겠습니까? + {MESSAGES.CONFIRM_DELETE} </p> <p className=" text-center justify-start text-label-alternative text-sm font-medium font-['SUIT_Variable'] leading-tight"> - 삭제 시 세부 목표와 작성된 투두도 함께 삭제됩니다. + {MESSAGES.DELETE_WARNING} </p> </div> ); };components/main/GoalMenuContainer/GoalMenuContainer.tsx (1)
108-111: Remove commented code.The commented
updateGoalIdcall is redundant since this logic is already handled by theuseEffecthook.Apply this diff:
onSelected={() => { setSelectedGoalIdx(idx); - // updateGoalId(goalMenuInfo.goalId); }}hooks/queries/useGroupChatInfinite.ts (2)
41-41: Make the limit configurable.The hard-coded limit of "10" should be configurable through a parameter to improve flexibility.
-const useGroupChatInfinite = ( - groupId: string, - direction: GetGroupChatParamsDirectionEnum, -) => { +const useGroupChatInfinite = ( + groupId: string, + direction: GetGroupChatParamsDirectionEnum, + limit = 10, +) => {Then update the API call:
- limit: "10", // 임시 값 + limit: limit.toString(),
54-78: Optimize data transformation and add null safety.The current sorting logic could be vulnerable to null/undefined values and the transformation is complex. Consider adding null safety checks.
const sortedChatData = data // 날짜별로 정렬 ?.sort( (dataA, dataB) => - new Date(dataA.messages?.[0].sendAt || undefined).getTime() - - new Date(dataB.messages?.[0].sendAt || undefined).getTime(), + new Date(dataA.messages?.[0]?.sendAt || 0).getTime() - + new Date(dataB.messages?.[0]?.sendAt || 0).getTime(), ) .map((info) => ({ ...info, - messages: info.messages.sort( + messages: info.messages?.sort( (dataA, dataB) => - new Date(dataA.sendAt).getTime() - new Date(dataB.sendAt).getTime(), + new Date(dataA.sendAt || 0).getTime() - new Date(dataB.sendAt || 0).getTime(), ), }))app/details/edit/[goal_id]/_components/GoalEdit/GoalEdit.tsx (4)
20-24: Remove commented-out code.The commented-out interface properties should be removed to keep the code clean.
interface GoalEditProps { - // initGoalTitle: string; - // // initDurationValue?: unknown; - // // initDurationType?: unknown; goalId: string; }
26-31: Remove commented-out parameters.Clean up the commented-out function parameters.
const GoalEdit = ({ - // initDurationValue, - // initDurationType, - // initGoalTitle, goalId, }: GoalEditProps) => {
56-62: Use optional chaining for cleaner code.The static analysis correctly identifies that optional chaining can simplify this code.
onChange={(e) => - setEditContents && - setEditContents((prev) => ({ - ...prev, - goalTitle: e.target.value, - })) + setEditContents?.((prev) => ({ + ...prev, + goalTitle: e.target.value, + })) }
119-126: Use optional chaining for consistency.Apply the same optional chaining pattern here for consistency.
onEdit={async ({ type, value }) => { - setEditContents && - setEditContents((prev) => ({ - ...prev, - durationType: type, - durationValue: value, - })); + setEditContents?.((prev) => ({ + ...prev, + durationType: type, + durationValue: value, + })); // 닫기 setOpenBottomSheet(false); }}hooks/queries/useGoalWithSubGoalTodo.ts (2)
27-27: Simplify boolean expression.The static analysis correctly identifies that this ternary operator is unnecessary.
- reported: todoInfo.todoResult ? true : false, + reported: !!todoInfo.todoResult,
42-45: Consider more specific typing.The return type uses
Partial<ConvertedGoalWithSubGoalTodo>but the data structure suggests it could be more specific since you're always including the original data plus converted subGoals.- const convertedData: Partial<ConvertedGoalWithSubGoalTodo> = { + const convertedData: ConvertedGoalWithSubGoalTodo = { ...data, subGoals: convertedSubGoals, - }; + } as ConvertedGoalWithSubGoalTodo;app/adding-goal/page.tsx (1)
122-137: Consider using a more stable key for sub-goal items.Using array index as the key can cause React rendering issues if sub-goals are later reordered or removed. Consider using a unique identifier for better performance and future-proofing.
+ const [subGoalCounter, setSubGoalCounter] = useState(0); {goalAddInfo.subGoals.map((subGoal, idx) => ( <TextField - key={`${idx}`} + key={`subgoal-${subGoalCounter}-${idx}`} isError={false} value={subGoal} onChange={(e) => { const newSubGoal = e.target.value; const newSubGoalList = [...goalAddInfo.subGoals]; newSubGoalList[idx] = newSubGoal; setGoalAddInfo((prev) => ({ ...prev, subGoals: newSubGoalList, })); }} /> ))} // In the add button onClick: onClick={() => { + setSubGoalCounter(prev => prev + 1); setGoalAddInfo((prev) => ({ ...prev, subGoals: [...prev.subGoals, ""], })); }}lib/fetching/template/fetchTemplate.ts (2)
3-3: Remove unused variable.The
tmpTokenvariable is declared but never used. Clean up by removing it.- const tmpToken = "";
23-23: Clean up commented code.Remove commented code that's no longer needed to improve code cleanliness.
try { - // const token = localStorage.getItem("access_token"); const token = useAuthStore.getState().accessToken; const res = await fetch(apiUrl, { ...options, method: method, headers: { ...headerWithOutAuthorization, - // ...(autoContentType ? {} : { "Content-Type": "application/json" }), Authorization: `Bearer ${token}`, },Also applies to: 30-30
app/details/edit/[goal_id]/page.tsx (2)
4-4: Remove commented import statements.Clean up the commented imports that are no longer needed.
import { useParams } from "next/navigation"; - // import useGoalWithSubGoalTodo from "@/hooks/main/queries/useGoalWithSubGoalTodo"; import useGoalWithSubGoalTodo, { ConvertedGoalWithSubGoalTodo, } from "@/hooks/queries/useGoalWithSubGoalTodo"; import { useState } from "react"; - // import { ConvertedGoalWithSubGoalTodo } from "@/hooks/main/queries/useGoalWithSubGoalTodo";Also applies to: 9-9
70-70: Consider more efficient key generation for EditBody.The current key generation causes complete re-rendering on any sub-goal title change. Consider using a more stable approach that only triggers re-renders when necessary.
<EditBody - key={data.subGoals?.map((s) => `${s.subGoal}`)?.join("") ?? ""} + key={`${goalId}-${data.subGoals?.length ?? 0}-${data.subGoals?.map(s => s.subGoalId).join(",") ?? ""}`} goalId={goalId} initData={initData} tab={tab} />app/details/edit/[goal_id]/_components/SubGoalEdit/SubGoalEdit.tsx (3)
45-58: Simplify conditional logic with optional chaining.Multiple locations can use optional chaining for cleaner, more concise code.
- setEditContents && - setEditContents((prev) => ({ + setEditContents?.((prev) => ({ ...prev, subGoals: [ ...prev.subGoals, { id: null, order: (editContents?.subGoals.length ?? 0) + 1, title: subGoal, tmpKey: new Date().getTime(), }, ], - })); + })); - setEditContents && - setEditContents((prev) => ({ + setEditContents?.((prev) => ({ ...prev, subGoals: orderUpdated.map((subGoalInfo, idx) => ({ ...subGoalInfo, // order: idx + 1, })) ?? [], - })); + })); - setEditContents && - setEditContents((prev) => ({ + setEditContents?.((prev) => ({ ...prev, subGoals: newSubGoals, - })); + })); - setEditContents && - setEditContents((prev) => ({ + setEditContents?.((prev) => ({ ...prev, subGoals: newSubGoals, - })); + }));Also applies to: 78-87, 120-125, 142-147
16-16: Remove unused import.The
randomUUIDimport is not used in this component.- import { randomUUID } from "crypto";
29-72: Remove unnecessary fragment.The fragment wrapper is redundant since it only contains one child element.
<main className="flex flex-col gap-2"> - <> <div data-type="type5" className="w-full p-3 bg-white rounded-lg shadow-[0px_0px_4px_0px_rgba(0,0,0,0.10)] inline-flex flex-col justify-start items-center gap-2 overflow-hidden" > {/* ... existing content ... */} </div> - </>components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.tsx (1)
52-54: Remove commented code.Clean up the commented onClick handler that's no longer needed.
<Modal.Button - // onClick={() => { - // onClose(); - // }} key={"update"} form="subGoalUpdating" type="submit" text="변경하기" color="primary" />app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx (5)
17-19: Clean up commented importsRemove the commented-out import statements as they add clutter to the codebase. If these are no longer needed, they should be deleted rather than commented out.
-// import useGoalWithSubGoalTodo, { -// ConvertedGoalWithSubGoalTodo, -// } from "@/hooks/main/queries/useGoalWithSubGoalTodo"; import useGoalWithSubGoalTodo from "@/hooks/queries/useGoalWithSubGoalTodo"; import GoalEdit from "../GoalEdit/GoalEdit"; import SubGoalEdit from "../SubGoalEdit/SubGoalEdit"; import { date2StringWithSpliter } from "@/utils/date2String"; import { goalApi } from "@/api/service"; -// import { updateGoal } from "@/lib/fetching/goalFetching";Also applies to: 28-28
57-57: Remove unused modal hookThe
useModalhook is imported and called butcloseModalandopenModalare never used in this component. Consider removing it if not needed.- const { closeModal, openModal } = useModal();
84-84: Use English for code commentsReplace the Korean comment with English for consistency and better maintainability across the team.
- // interface라, 임시로 넣은 필드 값 제거하기 위해서. + // Remove temporary field values for the interface
69-83: Simplify duration handling logicThe duration handling logic can be simplified to reduce code duplication.
const res = await goalApi.updateGoal(goalId, { title: editContents.goalTitle, isPeriodByMonth: editContents.durationType === "month", - month: - editContents.durationType === "month" - ? (editContents.durationValue as number) - : undefined, - dueDate: - editContents.durationType === "month" - ? undefined - : date2StringWithSpliter( - editContents.durationValue as Date, - "-", - ), + ...(editContents.durationType === "month" + ? { month: editContents.durationValue as number } + : { dueDate: date2StringWithSpliter(editContents.durationValue as Date, "-") }),
112-112: Use English for code commentsReplace the Korean comment with English for consistency.
- {/** zustaond로 관리하는 것들 GoalEdit이랑 SubGoalEdit내용 넣기. tab에 따라 다르게 렌더링 시키고 */} + {/** Render GoalEdit or SubGoalEdit content based on tab, managed by state */}components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.tsx (2)
46-46: Consider responsive width for mobile devicesThe fixed width of 360px might cause issues on smaller screens. Consider using responsive width.
- w-[360px] h-[585px] bg-background-alternative rounded-tl-lg rounded-tr-lg shadow-[0px_0px_4px_0px_rgba(0,0,0,0.24)] overflow-hidden + w-full max-w-[360px] h-[585px] bg-background-alternative rounded-tl-lg rounded-tr-lg shadow-[0px_0px_4px_0px_rgba(0,0,0,0.24)] overflow-hidden
57-57: Consider internationalization for Korean textThe component contains hardcoded Korean text. Consider using an i18n solution for better maintainability and multi-language support.
Also applies to: 72-73, 112-112
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (2)
86-110: Remove unnecessary fragmentsThe fragments wrapping single elements are redundant and can be removed.
{allSubGoalCompleted && !goalDetail?.isCompleted && ( - <> <button type="button" onClick={() => { openModalCompletingGoal(); }} data-leading-icon="true" data-status="enabled" data-type="filled" className="self-stretch w-full px-4 py-2 relative bg-background-normal rounded-lg inline-flex flex-col justify-center items-start gap-2 overflow-hidden" > <div className="self-stretch inline-flex justify-center items-center gap-2"> <div className="w-6 h-6 relative overflow-hidden flex justify-center items-center text-label-strong"> <CheckSvg /> </div> <p className="justify-start text-label-strong text-base font-semibold font-['Pretendard'] leading-normal"> 목표 완료 처리 하기 </p> </div> </button> - </> )} {groupId && ( - <> <div className="self-stretch w-full h-10 px-2 py-0.5 bg-Color-primary-5 rounded-lg inline-flex justify-start items-center gap-1"> <div data-property-1="Users_Group" className="w-5 h-5 relative overflow-hidden" > <PeopleSvg /> </div> <div className="flex-1 flex justify-start items-center gap-0.5"> <p className="justify-center text-label-normal text-xs font-semibold font-['SUIT_Variable'] leading-none"> 그룹으로 이동 </p> </div> <button type="button" className="w-6 h-6 relative overflow-hidden text-label-assistive" > <Link href={`/group/${groupId}`}> <RightArrowSvg /> </Link> </button> </div> - </> )}Also applies to: 110-134
189-190: Simplify boolean assignmentsRemove unnecessary ternary operators for cleaner code.
- const isCreating = newTodoInfo.id ? false : true; + const isCreating = !newTodoInfo.id; let fetchRes; if (isCreating) { fetchRes = await subGoalApi.createTodo(newTodoInfo.subGoalId, { title: newTodoInfo.todo, date: newTodoInfo?.date ? date2StringWithSpliter(newTodoInfo?.date, "-") : undefined, }); } else { fetchRes = await todoApi.updateTodo(newTodoInfo.id ?? "", { date: newTodoInfo.date ? date2StringWithSpliter(newTodoInfo.date, "-") : undefined, title: newTodoInfo.todo, }); } - const isFetchOk = fetchRes ? true : false; + const isFetchOk = !!fetchRes;Also applies to: 206-207
components/details/ListCard/ListCard.tsx (2)
116-158: Remove unnecessary fragmentThe fragment wrapping a single element is redundant.
{isTodoAllChecked && ( - <> <div className="w-80 h-12 px-3 py-0.5 bg-background-alternative rounded-lg outline-1 outline-offset-[-1px] outline-Color-primary-50 inline-flex justify-start items-center gap-1"> <div className="flex-1 flex justify-start items-center gap-0.5"> <div className="justify-center text-label-normal text-sm font-semibold font-['SUIT_Variable'] leading-tight"> 세부 목표 완료 </div> </div> <Checkbox checked={subGoalInfo.isCompleted} onChange={async () => { if (!subGoalInfo.isCompleted) { // if (!subGoalCompleted) { const res = await subGoalApi.subGoalCompleteToggle( subGoalInfo.id ?? "", ); if (res) { // setSubGoalCompleted(!subGoalCompleted); applyOnGoalData(); } } else { // 모달 후 처리 openModal( <ModalIncompletingSubGoal onClose={() => closeModal()} onIncompleteSubGoal={async () => { const res = await subGoalApi.subGoalCompleteToggle( subGoalInfo.id ?? "", ); if (res) { // setSubGoalCompleted(!subGoalCompleted); applyOnGoalData(); closeModal(); } }} />, ); } }} /> </div> - </> )}
128-128: Clean up commented codeRemove commented-out code and maintain consistent language in comments.
if (!subGoalInfo.isCompleted) { - // if (!subGoalCompleted) { const res = await subGoalApi.subGoalCompleteToggle( subGoalInfo.id ?? "", ); if (res) { - // setSubGoalCompleted(!subGoalCompleted); applyOnGoalData(); } } else { - // 모달 후 처리 + // Open modal for confirmation openModal( <ModalIncompletingSubGoal onClose={() => closeModal()} onIncompleteSubGoal={async () => { const res = await subGoalApi.subGoalCompleteToggle( subGoalInfo.id ?? "", ); if (res) { - // setSubGoalCompleted(!subGoalCompleted); applyOnGoalData(); closeModal(); } }} />, ); } ... onSubmit={async (todoResult) => { if (todoIdForResult && todoResult.emotion !== null) { - // (await todoApi.upsertTodoResult(todoIdForResult, { - // request: { - // emotion: todoResult.emotion as TodoResultRqEmotionEnum, - // content: todoResult.memo, - // }, - // file: todoResult.file || undefined, - // })); const res = await postTodoResult(Also applies to: 133-133, 146-146, 193-199
api/hooks.ts (2)
3-3: Remove unused importThe
GetGroupChatParamsDirectionEnumimport is not used in this file.-import { GetGroupChatParamsDirectionEnum } from "./generated/motimo/Api";
44-52: Consider removing commented-out codeIf these queries are no longer needed, remove them entirely rather than keeping them commented out. If they might be needed later, consider adding a TODO comment explaining why they're kept.
- // // Sub Goal API - // subGoalTodos: (subGoalId: string | null, config?: SWRConfiguration) => - // useApiQuery( - // "세부목표Api", - // "getIncompleteOrTodayTodos", - // subGoalId ? [subGoalId] : null, - // undefined, - // config, - // ), // User API myProfile: (config?: SWRConfiguration) => useApiQuery("사용자Api", "getMyProfile", [], undefined, config), ... - // groupChat: ( - // groupId: string | null, - // page: number, - // size: number, - // config?: SWRConfiguration, - // ) => - // useApiQuery( - // "그룹Api", - // "getGroupChat", - // groupId ? [groupId, { page, size }] : null, - // undefined, - // config, - // ), ... export const useGoalsNotInGroup = useQuery.goalsNotInGroup; -// export const useSubGoalTodos = useQuery.subGoalTodos; export const useMyProfile = useQuery.myProfile; export const useGroupMembers = useQuery.groupMembers; -// export const useGroupChat = useQuery.groupChat; export const useGroupDetail = useQuery.groupDetail;Also applies to: 68-80, 108-108, 111-111
components/group/GroupChatItem.tsx (2)
14-17: Consider using a more maintainable approach for commented codeInstead of keeping commented code inline, consider using feature flags or configuration to control available styles. This approach is cleaner and more maintainable.
+// Define available styles based on feature configuration +const AVAILABLE_STYLES = ["todo", "reaction"] as const; +// const FUTURE_STYLES = ["photo", "diary"] as const; // For future implementation + export interface GroupChatItemProps { type: "me" | "member"; - style: "todo" | "reaction"; - // style: "todo" | "photo" | "diary" | "reaction"; + style: typeof AVAILABLE_STYLES[number];
25-26: Remove commented code or document why it's keptThe
fileUrlproperty is commented out butfileNameis added. IffileUrlis no longer needed, remove it entirely. If it's planned for future use, add a TODO comment explaining when it will be implemented.- // fileUrl?: string; fileName?: string;hooks/queries/useSubGoalTodosInfiniites.ts (2)
33-36: Remove commented codeThe commented code on line 33 appears to be an old implementation. Remove it to keep the codebase clean.
- // previousPageData?.offset ? previousPageData.offset + 1 : 0, previousPageData ? (previousPageData.offset as number) + previousPageData.size : 0,
102-105: Remove commented code blockLines 102-105 contain commented API call code that should be removed.
- // subGoalApi.getTodosBySubGoalIdWithSlice(subGoalId, { - // offset, - // size: 10, - // });components/main/GoalCard/GoalCard.tsx (2)
65-68: Consider using a more descriptive state variable nameThe state variable
newTodoForSubmissionis only used to trigger refetches. Consider renaming it to better reflect its purpose.- const [newTodoForSubmission, setNewTodoForSubmission] = useState<Pick< - TodoInfoForSubmission, - "id" | "subGoalId" - > | null>(null); + const [todoRefreshTrigger, setTodoRefreshTrigger] = useState<Pick< + TodoInfoForSubmission, + "id" | "subGoalId" + > | null>(null);
200-210: Remove commented codeThe commented todoApi.upsertTodoResult code should be removed if it's no longer needed.
- // const res = await todoApi.upsertTodoResult( - // todoResBottomSheetInfo.todoId ?? "", - // { - // request: { - // content: todoResult.memo, - // emotion: - // todoResult.emotion as unknown as TodoResultRqEmotionEnum, - // }, - // file: todoResult.file || undefined, - // }, - // );components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx (1)
33-33: Add TODO comment for temporary direction valueThe comment indicates the direction is temporary but doesn't provide context about what the final implementation should be.
- // 방향은 임시 + // TODO: Implement dynamic direction based on user scroll position or initial load requirementscomponents/main/TodoList/TodoList.tsx (2)
47-47: Remove commented importThe commented import should be removed to keep the code clean.
-// import { useObservingInfiniteOffset } from "@/hooks/queries/useSubGoalTodosInfiniites";
261-263: Consider memoizing context valueThe context value from
useContext(TodoListContext)is destructured on every render. Consider memoizing frequently accessed values.+import { useMemo } from 'react'; const TodoArea = ({ todoItemsInfo, hasTodoItemsInfo, todoCheckedLen, todoTotalLen, }: { todoItemsInfo: TodoItemsInfo[]; hasTodoItemsInfo: boolean; todoCheckedLen: number; todoTotalLen: number; }) => { const nullableContext = useContext(TodoListContext); - const { existObserver, observingRef } = nullableContext || {}; + const { existObserver, observingRef } = useMemo( + () => nullableContext || {}, + [nullableContext] + );components/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx (1)
127-135: Simplify emotion type handlingThe type casting for emotion selection is unnecessarily complex and can be simplified.
setTodoResult((prev) => ({ ...prev, - emotion: - (emotionType as unknown as TodoResult["emotion"]) === - prev.emotion - ? null - : (emotionType as unknown as TodoResult["emotion"]), + emotion: + emotionType === prev.emotion + ? null + : emotionType as TodoResult["emotion"], }));
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (9)
api/generated/motimo/Api.tsis excluded by!**/generated/**components/shared/public/close_circle.svgis excluded by!**/*.svgpackage-lock.jsonis excluded by!**/package-lock.jsonpublic/images/Completion.svgis excluded by!**/*.svgpublic/images/Draggable.svgis excluded by!**/*.svgpublic/images/Edit_Pencil_01.svgis excluded by!**/*.svgpublic/images/People.svgis excluded by!**/*.svgpublic/images/Trash_Full.svgis excluded by!**/*.svgpublic/images/WarningInfo.svgis excluded by!**/*.svg
📒 Files selected for processing (67)
.gitignore(1 hunks)api/hooks.ts(5 hunks)api/service.ts(1 hunks)app/adding-goal/page.tsx(1 hunks)app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx(1 hunks)app/details/[goal_id]/page.tsx(1 hunks)app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx(1 hunks)app/details/edit/[goal_id]/_components/EditHeader/EditHeader.tsx(1 hunks)app/details/edit/[goal_id]/_components/GoalEdit/GoalEdit.tsx(1 hunks)app/details/edit/[goal_id]/_components/SubGoalEdit/SubGoalEdit.tsx(1 hunks)app/details/edit/[goal_id]/page.tsx(1 hunks)app/group/[group_id]/page.tsx(1 hunks)components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx(1 hunks)components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.tsx(1 hunks)components/details/EditInfo/EditInfo.stories.tsx(1 hunks)components/details/EditInfo/EditInfo.tsx(1 hunks)components/details/GoalData/GoalData.stories.tsx(1 hunks)components/details/GoalData/GoalData.tsx(1 hunks)components/details/ListCard/ListCard.stories.tsx(1 hunks)components/details/ListCard/ListCard.tsx(1 hunks)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx(1 hunks)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.tsx(1 hunks)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx(1 hunks)components/details/Modals/ModalExitingEdit/ModalExitingEdit.tsx(1 hunks)components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx(1 hunks)components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.tsx(1 hunks)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx(1 hunks)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.tsx(1 hunks)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx(1 hunks)components/details/SubGoalEditItem/SubGoalEditItem.tsx(1 hunks)components/details/TabMenu/TabMenu.stories.tsx(1 hunks)components/details/TabMenu/TabMenu.tsx(1 hunks)components/group/GroupChatItem.tsx(10 hunks)components/group/GroupItem.tsx(4 hunks)components/group/ReactionModal.tsx(1 hunks)components/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsx(1 hunks)components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx(1 hunks)components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsx(1 hunks)components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx(1 hunks)components/main/GoalCard/GoalCard.tsx(6 hunks)components/main/GoalMenuContainer/GoalMenuContainer.tsx(4 hunks)components/main/GoalTitleArea/GoalTitleArea.tsx(1 hunks)components/main/TodoList/TodoList.tsx(13 hunks)components/shared/AppBar/AppBar.tsx(2 hunks)components/shared/Banner/Banner.tsx(1 hunks)components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx(3 hunks)components/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx(1 hunks)components/shared/GoalMenu/GoalMenu.tsx(1 hunks)components/shared/Modal/ModalAddingGoal/ModalAddingGoal.tsx(2 hunks)components/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsx(2 hunks)components/shared/Modal/ModalCompletingGoal/ModalCompletingGoal.tsx(2 hunks)components/shared/Modal/ModalDeletingAccount/ModalDeletingAccount.tsx(1 hunks)components/shared/Modal/ModalDeletingSubGoal/ModalDeletingSubGoal.tsx(2 hunks)components/shared/TextField/TextField.tsx(1 hunks)components/shared/TodoItem/TodoItem.tsx(1 hunks)components/shared/package.json(1 hunks)hooks/queries/useGoalWithSubGoalTodo.ts(1 hunks)hooks/queries/useGroupChatInfinite.ts(1 hunks)hooks/queries/useSubGoalTodosInfiniites.ts(1 hunks)hooks/queries/useTodoList.ts(1 hunks)lib/fetching/postTodoResult.ts(1 hunks)lib/fetching/template/fetchTemplate.ts(1 hunks)netlify.toml(1 hunks)next.config.ts(2 hunks)package.json(1 hunks)utils/calcLeftDay.ts(1 hunks)utils/subGoalTodo2TodoItemList.ts(1 hunks)
📓 Path-based instructions (4)
components/**/*
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
Component should be created in components/
Files:
components/shared/package.jsoncomponents/shared/Banner/Banner.tsxcomponents/group/ReactionModal.tsxcomponents/shared/GoalMenu/GoalMenu.tsxcomponents/shared/Modal/ModalCompletingGoal/ModalCompletingGoal.tsxcomponents/shared/TodoItem/TodoItem.tsxcomponents/shared/TextField/TextField.tsxcomponents/shared/Modal/ModalAddingGoal/ModalAddingGoal.tsxcomponents/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsxcomponents/shared/Modal/ModalDeletingSubGoal/ModalDeletingSubGoal.tsxcomponents/shared/AppBar/AppBar.tsxcomponents/shared/Modal/ModalDeletingAccount/ModalDeletingAccount.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.tsxcomponents/details/TabMenu/TabMenu.tsxcomponents/group/GroupItem.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsxcomponents/details/GoalData/GoalData.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.stories.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.tsxcomponents/details/EditInfo/EditInfo.stories.tsxcomponents/details/GoalData/GoalData.stories.tsxcomponents/details/TabMenu/TabMenu.stories.tsxcomponents/details/EditInfo/EditInfo.tsxcomponents/details/ListCard/ListCard.stories.tsxcomponents/main/GoalMenuContainer/GoalMenuContainer.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsxcomponents/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsxcomponents/main/GoalTitleArea/GoalTitleArea.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.tsxcomponents/details/ListCard/ListCard.tsxcomponents/group/GroupChatItem.tsxcomponents/main/GoalCard/GoalCard.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.tsxcomponents/main/TodoList/TodoList.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.tsxcomponents/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx
components/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For every styling, use tailwind css.
Files:
components/shared/Banner/Banner.tsxcomponents/group/ReactionModal.tsxcomponents/shared/GoalMenu/GoalMenu.tsxcomponents/shared/Modal/ModalCompletingGoal/ModalCompletingGoal.tsxcomponents/shared/TodoItem/TodoItem.tsxcomponents/shared/TextField/TextField.tsxcomponents/shared/Modal/ModalAddingGoal/ModalAddingGoal.tsxcomponents/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsxcomponents/shared/Modal/ModalDeletingSubGoal/ModalDeletingSubGoal.tsxcomponents/shared/AppBar/AppBar.tsxcomponents/shared/Modal/ModalDeletingAccount/ModalDeletingAccount.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.tsxcomponents/details/TabMenu/TabMenu.tsxcomponents/group/GroupItem.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsxcomponents/details/GoalData/GoalData.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.stories.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.tsxcomponents/details/EditInfo/EditInfo.stories.tsxcomponents/details/GoalData/GoalData.stories.tsxcomponents/details/TabMenu/TabMenu.stories.tsxcomponents/details/EditInfo/EditInfo.tsxcomponents/details/ListCard/ListCard.stories.tsxcomponents/main/GoalMenuContainer/GoalMenuContainer.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsxcomponents/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsxcomponents/main/GoalTitleArea/GoalTitleArea.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.tsxcomponents/details/ListCard/ListCard.tsxcomponents/group/GroupChatItem.tsxcomponents/main/GoalCard/GoalCard.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.tsxcomponents/main/TodoList/TodoList.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.tsxcomponents/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx
{components/**/*.{js,jsx,ts,tsx},**/*.css}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For tokens, use tokens.css (mdc:app/tokens.css).
Files:
components/shared/Banner/Banner.tsxcomponents/group/ReactionModal.tsxcomponents/shared/GoalMenu/GoalMenu.tsxcomponents/shared/Modal/ModalCompletingGoal/ModalCompletingGoal.tsxcomponents/shared/TodoItem/TodoItem.tsxcomponents/shared/TextField/TextField.tsxcomponents/shared/Modal/ModalAddingGoal/ModalAddingGoal.tsxcomponents/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsxcomponents/shared/Modal/ModalDeletingSubGoal/ModalDeletingSubGoal.tsxcomponents/shared/AppBar/AppBar.tsxcomponents/shared/Modal/ModalDeletingAccount/ModalDeletingAccount.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.tsxcomponents/details/TabMenu/TabMenu.tsxcomponents/group/GroupItem.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsxcomponents/details/GoalData/GoalData.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.stories.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.tsxcomponents/details/EditInfo/EditInfo.stories.tsxcomponents/details/GoalData/GoalData.stories.tsxcomponents/details/TabMenu/TabMenu.stories.tsxcomponents/details/EditInfo/EditInfo.tsxcomponents/details/ListCard/ListCard.stories.tsxcomponents/main/GoalMenuContainer/GoalMenuContainer.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsxcomponents/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsxcomponents/main/GoalTitleArea/GoalTitleArea.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.tsxcomponents/details/ListCard/ListCard.tsxcomponents/group/GroupChatItem.tsxcomponents/main/GoalCard/GoalCard.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.tsxcomponents/main/TodoList/TodoList.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.tsxcomponents/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx
components/**/*.stories.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
components/**/*.stories.{js,jsx,ts,tsx}: If Component is created, add storybook files as well.
TheDefaultexample of storybook should be namedPrimary
Files:
components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.stories.tsxcomponents/details/EditInfo/EditInfo.stories.tsxcomponents/details/GoalData/GoalData.stories.tsxcomponents/details/TabMenu/TabMenu.stories.tsxcomponents/details/ListCard/ListCard.stories.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx
🧠 Learnings (18)
components/shared/Banner/Banner.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to {components//*.{js,jsx,ts,tsx},/*.css} : For tokens, use tokens.css (mdc:app/tokens.css).
components/shared/TextField/TextField.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to {components//*.{js,jsx,ts,tsx},/*.css} : For tokens, use tokens.css (mdc:app/tokens.css).
package.json (3)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.{js,jsx,ts,tsx} : For every styling, use tailwind css.
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
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-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
components/details/TabMenu/TabMenu.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.{js,jsx,ts,tsx} : For every styling, use tailwind css.
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to {components//*.{js,jsx,ts,tsx},/*.css} : For tokens, use tokens.css (mdc:app/tokens.css).
components/group/GroupItem.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to {components//*.{js,jsx,ts,tsx},/*.css} : For tokens, use tokens.css (mdc:app/tokens.css).
components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
next.config.ts (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to {components//*.{js,jsx,ts,tsx},/*.css} : For tokens, use tokens.css (mdc:app/tokens.css).
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/icons/**/* : For icon and svg, create component at components/icons.
components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/EditInfo/EditInfo.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/GoalData/GoalData.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/TabMenu/TabMenu.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/ListCard/ListCard.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
🧬 Code Graph Analysis (21)
components/group/GroupItem.tsx (1)
components/icons/BellIcon.tsx (1)
BellIcon(11-51)
app/group/[group_id]/page.tsx (1)
api/hooks.ts (1)
useGroupDetail(112-112)
components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (9)
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (1)
Primary(40-65)components/details/GoalData/GoalData.stories.tsx (1)
Primary(27-40)components/details/EditInfo/EditInfo.stories.tsx (1)
Primary(27-36)components/details/ListCard/ListCard.stories.tsx (1)
Primary(27-51)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (1)
Primary(27-37)components/details/TabMenu/TabMenu.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (1)
Primary(27-36)
lib/fetching/postTodoResult.ts (1)
lib/fetching/template/fetchTemplate.ts (1)
templateFetch(53-53)
components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (8)
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (1)
Primary(40-65)components/details/GoalData/GoalData.stories.tsx (1)
Primary(27-40)components/details/EditInfo/EditInfo.stories.tsx (1)
Primary(27-36)components/details/ListCard/ListCard.stories.tsx (1)
Primary(27-51)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (1)
Primary(27-36)
components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (5)
components/details/EditInfo/EditInfo.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (1)
Primary(27-37)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (1)
Primary(27-36)
utils/subGoalTodo2TodoItemList.ts (2)
api/generated/motimo/Api.ts (1)
SubGoalWithTodosRs(644-663)types/todoList.ts (1)
TodoItemsInfo(7-7)
components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (9)
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (1)
Primary(40-65)components/details/GoalData/GoalData.stories.tsx (1)
Primary(27-40)components/details/EditInfo/EditInfo.stories.tsx (1)
Primary(27-36)components/details/ListCard/ListCard.stories.tsx (1)
Primary(27-51)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (1)
Primary(27-37)components/details/TabMenu/TabMenu.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (1)
Primary(27-36)
components/details/EditInfo/EditInfo.stories.tsx (5)
components/details/GoalData/GoalData.stories.tsx (1)
Primary(27-40)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/TabMenu/TabMenu.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (1)
Primary(27-37)
components/details/TabMenu/TabMenu.stories.tsx (8)
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (1)
Primary(40-65)components/details/GoalData/GoalData.stories.tsx (1)
Primary(27-40)components/details/EditInfo/EditInfo.stories.tsx (1)
Primary(27-36)components/details/ListCard/ListCard.stories.tsx (1)
Primary(27-51)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (1)
Primary(27-37)
app/details/edit/[goal_id]/_components/GoalEdit/GoalEdit.tsx (5)
api/hooks.ts (1)
useGoals(104-104)app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx (1)
EditContext(120-120)utils/date2String.ts (1)
date2StringWithSpliter(7-7)components/shared/Button/Button.tsx (1)
Button(77-77)api/service.ts (1)
goalApi(45-45)
app/adding-goal/page.tsx (2)
api/service.ts (1)
goalApi(45-45)utils/date2String.ts (1)
date2StringWithSpliter(7-7)
hooks/queries/useGoalWithSubGoalTodo.ts (4)
api/generated/motimo/Api.ts (1)
GoalWithSubGoalTodoRs(623-642)components/main/TodoList/TodoList.tsx (1)
TodoListProps(191-191)api/hooks.ts (1)
useGoalWithSubGoals(106-106)types/todoList.ts (1)
TodoItemsInfo(7-7)
hooks/queries/useGroupChatInfinite.ts (2)
api/generated/motimo/Api.ts (4)
GroupJoinContent(418-418)GroupLeaveContent(420-420)TodoCompletedContent(476-480)TodoResultSubmittedContent(482-491)api/service.ts (1)
groupApi(47-47)
components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (3)
components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)
app/details/edit/[goal_id]/_components/SubGoalEdit/SubGoalEdit.tsx (1)
app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx (1)
EditContext(120-120)
app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx (2)
api/service.ts (1)
goalApi(45-45)utils/date2String.ts (1)
date2StringWithSpliter(7-7)
app/details/edit/[goal_id]/page.tsx (2)
hooks/queries/useGoalWithSubGoalTodo.ts (1)
ConvertedGoalWithSubGoalTodo(50-50)app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx (1)
EditContents(121-121)
hooks/queries/useSubGoalTodosInfiniites.ts (3)
api/generated/motimo/Api.ts (1)
TodoRs(296-325)lib/fetching/template/fetchTemplate.ts (1)
templateFetch(53-53)types/todoList.ts (1)
TodoItemsInfo(7-7)
components/group/GroupChatItem.tsx (1)
components/icons/HeartIcon.tsx (1)
HeartIcon(11-38)
components/main/TodoList/TodoList.tsx (2)
hooks/queries/useSubGoalTodosInfiniites.ts (3)
SubGoalTodoInfinite(189-189)useSubGoalTodosIncompleteOrTodayInfinite(185-185)useObservingExist(187-187)api/service.ts (1)
todoApi(44-44)
🪛 Biome (1.9.4)
utils/subGoalTodo2TodoItemList.ts
[error] 13-13: 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)
app/details/edit/[goal_id]/_components/GoalEdit/GoalEdit.tsx
[error] 58-63: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 121-127: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
hooks/queries/useGoalWithSubGoalTodo.ts
[error] 27-27: 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/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.tsx
[error] 26-38: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
app/details/edit/[goal_id]/_components/SubGoalEdit/SubGoalEdit.tsx
[error] 46-58: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 79-88: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 122-127: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 144-149: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 29-74: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
[error] 191-191: 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] 211-213: 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] 89-112: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
[error] 112-136: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
components/details/ListCard/ListCard.tsx
[error] 118-160: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
🪛 GitHub Actions: CI Pipeline
components/main/GoalMenuContainer/GoalMenuContainer.tsx
[warning] 25-25: The 'goalMenuInfoList' logical expression could make the dependencies of useEffect Hook (at line 56) change on every render. To fix this, wrap the initialization of 'goalMenuInfoList' in its own useMemo() Hook. (react-hooks/exhaustive-deps)
[warning] 45-45: React Hook useEffect has missing dependencies: 'goalMenuInfoList' and 'selectedGoalIdx'. Either include them or remove the dependency array. (react-hooks/exhaustive-deps)
[warning] 45-45: React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked. (react-hooks/exhaustive-deps)
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx
[warning] 106-106: React Hook useEffect has a missing dependency: 'subGoals'. Either include it or remove the dependency array. If 'setTodoInfo' needs the current value of 'subGoals', you can also switch to useReducer instead of useState and read 'subGoals' in the reducer. (react-hooks/exhaustive-deps)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
[warning] 75-75: React Hook useEffect has a missing dependency: 'openModalCompletingGoal'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx
[error] 159-159: React Hook "useModal" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return? (react-hooks/rules-of-hooks)
🧰 Additional context used
📓 Path-based instructions (4)
components/**/*
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
Component should be created in components/
Files:
components/shared/package.jsoncomponents/shared/Banner/Banner.tsxcomponents/group/ReactionModal.tsxcomponents/shared/GoalMenu/GoalMenu.tsxcomponents/shared/Modal/ModalCompletingGoal/ModalCompletingGoal.tsxcomponents/shared/TodoItem/TodoItem.tsxcomponents/shared/TextField/TextField.tsxcomponents/shared/Modal/ModalAddingGoal/ModalAddingGoal.tsxcomponents/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsxcomponents/shared/Modal/ModalDeletingSubGoal/ModalDeletingSubGoal.tsxcomponents/shared/AppBar/AppBar.tsxcomponents/shared/Modal/ModalDeletingAccount/ModalDeletingAccount.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.tsxcomponents/details/TabMenu/TabMenu.tsxcomponents/group/GroupItem.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsxcomponents/details/GoalData/GoalData.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.stories.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.tsxcomponents/details/EditInfo/EditInfo.stories.tsxcomponents/details/GoalData/GoalData.stories.tsxcomponents/details/TabMenu/TabMenu.stories.tsxcomponents/details/EditInfo/EditInfo.tsxcomponents/details/ListCard/ListCard.stories.tsxcomponents/main/GoalMenuContainer/GoalMenuContainer.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsxcomponents/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsxcomponents/main/GoalTitleArea/GoalTitleArea.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.tsxcomponents/details/ListCard/ListCard.tsxcomponents/group/GroupChatItem.tsxcomponents/main/GoalCard/GoalCard.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.tsxcomponents/main/TodoList/TodoList.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.tsxcomponents/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx
components/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For every styling, use tailwind css.
Files:
components/shared/Banner/Banner.tsxcomponents/group/ReactionModal.tsxcomponents/shared/GoalMenu/GoalMenu.tsxcomponents/shared/Modal/ModalCompletingGoal/ModalCompletingGoal.tsxcomponents/shared/TodoItem/TodoItem.tsxcomponents/shared/TextField/TextField.tsxcomponents/shared/Modal/ModalAddingGoal/ModalAddingGoal.tsxcomponents/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsxcomponents/shared/Modal/ModalDeletingSubGoal/ModalDeletingSubGoal.tsxcomponents/shared/AppBar/AppBar.tsxcomponents/shared/Modal/ModalDeletingAccount/ModalDeletingAccount.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.tsxcomponents/details/TabMenu/TabMenu.tsxcomponents/group/GroupItem.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsxcomponents/details/GoalData/GoalData.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.stories.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.tsxcomponents/details/EditInfo/EditInfo.stories.tsxcomponents/details/GoalData/GoalData.stories.tsxcomponents/details/TabMenu/TabMenu.stories.tsxcomponents/details/EditInfo/EditInfo.tsxcomponents/details/ListCard/ListCard.stories.tsxcomponents/main/GoalMenuContainer/GoalMenuContainer.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsxcomponents/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsxcomponents/main/GoalTitleArea/GoalTitleArea.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.tsxcomponents/details/ListCard/ListCard.tsxcomponents/group/GroupChatItem.tsxcomponents/main/GoalCard/GoalCard.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.tsxcomponents/main/TodoList/TodoList.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.tsxcomponents/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx
{components/**/*.{js,jsx,ts,tsx},**/*.css}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For tokens, use tokens.css (mdc:app/tokens.css).
Files:
components/shared/Banner/Banner.tsxcomponents/group/ReactionModal.tsxcomponents/shared/GoalMenu/GoalMenu.tsxcomponents/shared/Modal/ModalCompletingGoal/ModalCompletingGoal.tsxcomponents/shared/TodoItem/TodoItem.tsxcomponents/shared/TextField/TextField.tsxcomponents/shared/Modal/ModalAddingGoal/ModalAddingGoal.tsxcomponents/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsxcomponents/shared/Modal/ModalDeletingSubGoal/ModalDeletingSubGoal.tsxcomponents/shared/AppBar/AppBar.tsxcomponents/shared/Modal/ModalDeletingAccount/ModalDeletingAccount.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.tsxcomponents/details/TabMenu/TabMenu.tsxcomponents/group/GroupItem.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsxcomponents/details/GoalData/GoalData.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.stories.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.tsxcomponents/details/EditInfo/EditInfo.stories.tsxcomponents/details/GoalData/GoalData.stories.tsxcomponents/details/TabMenu/TabMenu.stories.tsxcomponents/details/EditInfo/EditInfo.tsxcomponents/details/ListCard/ListCard.stories.tsxcomponents/main/GoalMenuContainer/GoalMenuContainer.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsxcomponents/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsxcomponents/main/GoalTitleArea/GoalTitleArea.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsxcomponents/details/Modals/ModalExitingEdit/ModalExitingEdit.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.tsxcomponents/details/ListCard/ListCard.tsxcomponents/group/GroupChatItem.tsxcomponents/main/GoalCard/GoalCard.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.tsxcomponents/main/TodoList/TodoList.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.tsxcomponents/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx
components/**/*.stories.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
components/**/*.stories.{js,jsx,ts,tsx}: If Component is created, add storybook files as well.
TheDefaultexample of storybook should be namedPrimary
Files:
components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsxcomponents/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsxcomponents/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsxcomponents/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsxcomponents/details/SubGoalEditItem/SubGoalEditItem.stories.tsxcomponents/details/EditInfo/EditInfo.stories.tsxcomponents/details/GoalData/GoalData.stories.tsxcomponents/details/TabMenu/TabMenu.stories.tsxcomponents/details/ListCard/ListCard.stories.tsxcomponents/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsxcomponents/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsxcomponents/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx
🧠 Learnings (18)
components/shared/Banner/Banner.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to {components//*.{js,jsx,ts,tsx},/*.css} : For tokens, use tokens.css (mdc:app/tokens.css).
components/shared/TextField/TextField.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to {components//*.{js,jsx,ts,tsx},/*.css} : For tokens, use tokens.css (mdc:app/tokens.css).
package.json (3)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.{js,jsx,ts,tsx} : For every styling, use tailwind css.
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
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-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
components/details/TabMenu/TabMenu.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.{js,jsx,ts,tsx} : For every styling, use tailwind css.
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to {components//*.{js,jsx,ts,tsx},/*.css} : For tokens, use tokens.css (mdc:app/tokens.css).
components/group/GroupItem.tsx (1)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to {components//*.{js,jsx,ts,tsx},/*.css} : For tokens, use tokens.css (mdc:app/tokens.css).
components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
next.config.ts (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to {components//*.{js,jsx,ts,tsx},/*.css} : For tokens, use tokens.css (mdc:app/tokens.css).
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/icons/**/* : For icon and svg, create component at components/icons.
components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/EditInfo/EditInfo.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/GoalData/GoalData.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/TabMenu/TabMenu.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/ListCard/ListCard.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (2)
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The Default example of storybook should be named Primary
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-21T07:45:37.405Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
🧬 Code Graph Analysis (21)
components/group/GroupItem.tsx (1)
components/icons/BellIcon.tsx (1)
BellIcon(11-51)
app/group/[group_id]/page.tsx (1)
api/hooks.ts (1)
useGroupDetail(112-112)
components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (9)
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (1)
Primary(40-65)components/details/GoalData/GoalData.stories.tsx (1)
Primary(27-40)components/details/EditInfo/EditInfo.stories.tsx (1)
Primary(27-36)components/details/ListCard/ListCard.stories.tsx (1)
Primary(27-51)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (1)
Primary(27-37)components/details/TabMenu/TabMenu.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (1)
Primary(27-36)
lib/fetching/postTodoResult.ts (1)
lib/fetching/template/fetchTemplate.ts (1)
templateFetch(53-53)
components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (8)
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (1)
Primary(40-65)components/details/GoalData/GoalData.stories.tsx (1)
Primary(27-40)components/details/EditInfo/EditInfo.stories.tsx (1)
Primary(27-36)components/details/ListCard/ListCard.stories.tsx (1)
Primary(27-51)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (1)
Primary(27-36)
components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (5)
components/details/EditInfo/EditInfo.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (1)
Primary(27-37)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (1)
Primary(27-36)
utils/subGoalTodo2TodoItemList.ts (2)
api/generated/motimo/Api.ts (1)
SubGoalWithTodosRs(644-663)types/todoList.ts (1)
TodoItemsInfo(7-7)
components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (9)
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (1)
Primary(40-65)components/details/GoalData/GoalData.stories.tsx (1)
Primary(27-40)components/details/EditInfo/EditInfo.stories.tsx (1)
Primary(27-36)components/details/ListCard/ListCard.stories.tsx (1)
Primary(27-51)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (1)
Primary(27-37)components/details/TabMenu/TabMenu.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (1)
Primary(27-36)
components/details/EditInfo/EditInfo.stories.tsx (5)
components/details/GoalData/GoalData.stories.tsx (1)
Primary(27-40)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/TabMenu/TabMenu.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (1)
Primary(27-37)
components/details/TabMenu/TabMenu.stories.tsx (8)
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (1)
Primary(40-65)components/details/GoalData/GoalData.stories.tsx (1)
Primary(27-40)components/details/EditInfo/EditInfo.stories.tsx (1)
Primary(27-36)components/details/ListCard/ListCard.stories.tsx (1)
Primary(27-51)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (1)
Primary(27-37)
app/details/edit/[goal_id]/_components/GoalEdit/GoalEdit.tsx (5)
api/hooks.ts (1)
useGoals(104-104)app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx (1)
EditContext(120-120)utils/date2String.ts (1)
date2StringWithSpliter(7-7)components/shared/Button/Button.tsx (1)
Button(77-77)api/service.ts (1)
goalApi(45-45)
app/adding-goal/page.tsx (2)
api/service.ts (1)
goalApi(45-45)utils/date2String.ts (1)
date2StringWithSpliter(7-7)
hooks/queries/useGoalWithSubGoalTodo.ts (4)
api/generated/motimo/Api.ts (1)
GoalWithSubGoalTodoRs(623-642)components/main/TodoList/TodoList.tsx (1)
TodoListProps(191-191)api/hooks.ts (1)
useGoalWithSubGoals(106-106)types/todoList.ts (1)
TodoItemsInfo(7-7)
hooks/queries/useGroupChatInfinite.ts (2)
api/generated/motimo/Api.ts (4)
GroupJoinContent(418-418)GroupLeaveContent(420-420)TodoCompletedContent(476-480)TodoResultSubmittedContent(482-491)api/service.ts (1)
groupApi(47-47)
components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (3)
components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
Primary(27-36)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (1)
Primary(27-37)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
Primary(27-36)
app/details/edit/[goal_id]/_components/SubGoalEdit/SubGoalEdit.tsx (1)
app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx (1)
EditContext(120-120)
app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx (2)
api/service.ts (1)
goalApi(45-45)utils/date2String.ts (1)
date2StringWithSpliter(7-7)
app/details/edit/[goal_id]/page.tsx (2)
hooks/queries/useGoalWithSubGoalTodo.ts (1)
ConvertedGoalWithSubGoalTodo(50-50)app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx (1)
EditContents(121-121)
hooks/queries/useSubGoalTodosInfiniites.ts (3)
api/generated/motimo/Api.ts (1)
TodoRs(296-325)lib/fetching/template/fetchTemplate.ts (1)
templateFetch(53-53)types/todoList.ts (1)
TodoItemsInfo(7-7)
components/group/GroupChatItem.tsx (1)
components/icons/HeartIcon.tsx (1)
HeartIcon(11-38)
components/main/TodoList/TodoList.tsx (2)
hooks/queries/useSubGoalTodosInfiniites.ts (3)
SubGoalTodoInfinite(189-189)useSubGoalTodosIncompleteOrTodayInfinite(185-185)useObservingExist(187-187)api/service.ts (1)
todoApi(44-44)
🪛 Biome (1.9.4)
utils/subGoalTodo2TodoItemList.ts
[error] 13-13: 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)
app/details/edit/[goal_id]/_components/GoalEdit/GoalEdit.tsx
[error] 58-63: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 121-127: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
hooks/queries/useGoalWithSubGoalTodo.ts
[error] 27-27: 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/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.tsx
[error] 26-38: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
app/details/edit/[goal_id]/_components/SubGoalEdit/SubGoalEdit.tsx
[error] 46-58: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 79-88: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 122-127: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 144-149: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 29-74: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
[error] 191-191: 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] 211-213: 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] 89-112: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
[error] 112-136: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
components/details/ListCard/ListCard.tsx
[error] 118-160: Avoid using unnecessary Fragment.
A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment
(lint/complexity/noUselessFragments)
🪛 GitHub Actions: CI Pipeline
components/main/GoalMenuContainer/GoalMenuContainer.tsx
[warning] 25-25: The 'goalMenuInfoList' logical expression could make the dependencies of useEffect Hook (at line 56) change on every render. To fix this, wrap the initialization of 'goalMenuInfoList' in its own useMemo() Hook. (react-hooks/exhaustive-deps)
[warning] 45-45: React Hook useEffect has missing dependencies: 'goalMenuInfoList' and 'selectedGoalIdx'. Either include them or remove the dependency array. (react-hooks/exhaustive-deps)
[warning] 45-45: React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked. (react-hooks/exhaustive-deps)
components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx
[warning] 106-106: React Hook useEffect has a missing dependency: 'subGoals'. Either include it or remove the dependency array. If 'setTodoInfo' needs the current value of 'subGoals', you can also switch to useReducer instead of useState and read 'subGoals' in the reducer. (react-hooks/exhaustive-deps)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
[warning] 75-75: React Hook useEffect has a missing dependency: 'openModalCompletingGoal'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx
[error] 159-159: React Hook "useModal" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return? (react-hooks/rules-of-hooks)
🔇 Additional comments (43)
components/shared/package.json (1)
3-3: LGTM! Standard version bump reflects UI component additions.The patch version increment from
1.0.4to1.0.5appropriately reflects the new UI components and modal refactoring mentioned in the summary.components/shared/Banner/Banner.tsx (1)
11-11: Verify the overflow change doesn't hide intended content.The change from
overflow-x-hiddentooverflow-hiddennow hides both horizontal and vertical overflow. Ensure this doesn't unintentionally clip text content that should be visible.components/shared/Modal/ModalAddingGoal/ModalAddingGoal.tsx (1)
18-18: LGTM! Improved component naming consistency.The renaming from
BodytoModalBodyimproves code clarity and aligns with similar refactoring across other modal components in the shared library.Also applies to: 44-44
components/shared/Modal/ModalDeletingSubGoal/ModalDeletingSubGoal.tsx (1)
21-21: LGTM! Consistent component naming refactoring.The renaming from
BodytoModalBodymaintains consistency with the modal component refactoring pattern.Also applies to: 49-49
components/shared/AppBar/AppBar.tsx (2)
4-4: LGTM! Improved event handling with proper TypeScript typing.The updated prop signature provides access to the mouse event object, enabling better event handling capabilities for consumers of this component.
Also applies to: 12-12
41-41: LGTM! Added explicit button type for form safety.Adding
type="button"prevents the button from accidentally submitting forms when the AppBar is used within form contexts, which is a good defensive programming practice.components/shared/Modal/ModalDeletingAccount/ModalDeletingAccount.tsx (1)
50-61: LGTM! Clean refactoring for naming consistency.The renaming from
BodytoModalBodyaligns with the consistent pattern being applied across modal components and improves code clarity.components/shared/TodoItem/TodoItem.tsx (1)
111-111: Good improvement for consistent icon sizing.Adding explicit
width={20}andheight={20}props ensures the CheckSvg renders consistently at the intended size, matching the container dimensions.netlify.toml (1)
1-2: LGTM! Proper Netlify configuration for Next.js deployment.The configuration correctly declares the Next.js plugin, aligning with the package.json dependency addition and enabling proper Next.js deployment on Netlify.
components/group/ReactionModal.tsx (1)
30-34: Good improvements for button functionality and form handling.Adding the explicit
onClickhandler ensures the close button properly triggers the modal close action, and thetype="button"attribute prevents unintended form submissions.components/shared/Modal/ModalAddingSubGoal/ModalAddingSubGoal.tsx (2)
41-41: Rename looks good
Body→ModalBodyimproves clarity and matches the pattern used across other modal components.
62-88: LGTM – no functional changes, only the renameThe internal logic remains untouched; no issues detected.
api/service.ts (1)
48-48: No remaining references topokeApi
The only occurrence is the commented-out export in api/service.ts:48. It’s safe to remove this export without breaking imports.components/shared/Modal/ModalCompletingGoal/ModalCompletingGoal.tsx (2)
25-26: Consistent naming confirmed
ModalBodyrename is consistent with other modal components; no further action required.
50-66: No issues with renamed componentStatic content only; implementation unaffected.
utils/calcLeftDay.ts (2)
1-4: Verify the calculation direction matches the intended semantics.The function name
calcLeftDaysuggests calculating remaining days, but the parameter semantics are unclear. Ifdaterepresents a target date anddueDatedefaults to the current date, the calculationdate - dueDatewill return negative values for past dates.Please verify the intended behavior:
- Should the function return positive values for future dates and negative for past dates?
- Or should it always return the absolute difference?
Consider renaming parameters for clarity, e.g.,
targetDateandreferenceDate.
5-11: Fix the mathematical calculation error in day difference computation.The division order is incorrect and will produce wrong results. The current calculation divides by each time unit sequentially instead of dividing by the total milliseconds per day.
Apply this diff to fix the calculation:
return Math.floor( - (new Date(date).getTime() - new Date(dueDate).getTime()) / - 1000 / - 24 / - 60 / - 60, + (new Date(date).getTime() - new Date(dueDate).getTime()) / + (1000 * 60 * 60 * 24), );The corrected version properly calculates milliseconds per day (86,400,000) as a single divisor.
Likely an incorrect or invalid review comment.
utils/subGoalTodo2TodoItemList.ts (1)
5-17: LGTM - Well-structured data transformation.The function properly handles optional data, provides sensible defaults, and uses appropriate type checking with the enum comparison.
next.config.ts (1)
65-74: LGTM: Production rewrites configuration looks correct.The explicit production environment handling ensures API requests are properly proxied to the backend server. The fallback to empty array for other environments is appropriate.
components/details/EditInfo/EditInfo.tsx (1)
11-29: LGTM: Component implementation follows best practices.The component correctly uses TypeScript interfaces, Tailwind CSS classes, and follows React functional component patterns. The conditional text rendering based on the type prop is well implemented.
components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx (1)
11-30: LGTM: Clean component implementation with proper navigation.The component follows React best practices, uses Next.js router correctly, and implements proper TypeScript interfaces. The AppBar integration with back navigation is well done.
components/group/GroupItem.tsx (1)
23-28: LGTM: Code formatting improvements enhance readability.The formatting changes improve code consistency and readability without affecting functionality. The component continues to follow React best practices and uses Tailwind CSS appropriately.
Also applies to: 35-36, 60-65, 76-76, 88-88
lib/fetching/postTodoResult.ts (2)
4-26: LGTM: Well-structured API function with proper FormData handling.The function correctly constructs FormData for multipart requests, handles optional file uploads, and uses proper TypeScript typing. The async/await pattern and templateFetch usage follow established patterns.
13-13: Memo parameter mapping is correctVerified that the generated
TodoResultRqinterface definescontent?: string, so mappingmemotocontentmatches the API spec. No changes required.components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx (1)
25-36: LGTM! Storybook implementation follows guidelines correctly.The story implementation correctly follows the coding guidelines requirement for the Primary story name and includes proper argTypes and args structure consistent with other modal stories in the codebase.
components/details/GoalData/GoalData.stories.tsx (1)
1-58: LGTM! Well-structured Storybook story file.The story file follows project conventions correctly:
- Uses
Primarystory naming as per guidelines- Proper argTypes configuration for component props
- Good default values for testing the component
- Consistent with other story files in the project
components/details/EditInfo/EditInfo.stories.tsx (1)
1-54: LGTM! Proper Storybook story implementation.The story file correctly implements:
Primarystory naming convention- Select control for the
typeprop with appropriate options- Clean structure consistent with project patterns
components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx (1)
1-55: LGTM! Consistent Storybook story structure.The story file properly implements:
Primarystory naming per project conventions- Appropriate default props including callback functions
- Good sample data for testing the component
- Structure consistent with other story files
components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx (1)
1-54: LGTM! Well-implemented modal story file.The story file correctly follows project patterns:
Primarystory naming convention- Proper async callback handling for
onDeleteGoal- Appropriate title path including Modals subdirectory
- Consistent structure with other modal stories
components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.tsx (1)
1-62: LGTM! Well-implemented modal component with proper structure.The component follows good practices:
- Proper TypeScript interfaces extending
ModalCommon- Correct use of Tailwind CSS classes per coding guidelines
- Good Modal compound component usage
- Appropriate event handling for both callbacks
components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx (1)
1-55: Well-structured Storybook story following project conventions.The story correctly follows the project's conventions with the "Primary" story name as required by the coding guidelines. The structure and typing are consistent with other story files in the codebase.
The implementation properly:
- Uses the required "Primary" export name
- Includes appropriate TypeScript types
- Provides mock functions for callbacks
- Follows the established story pattern
components/details/TabMenu/TabMenu.stories.tsx (1)
1-55: Excellent Storybook story implementation.The story file correctly implements all project conventions and follows the established patterns. The "Primary" story name matches the coding guidelines, and the component props are appropriately configured.
The implementation demonstrates:
- Proper adherence to the "Primary" story naming requirement
- Consistent structure with other story files
- Appropriate mock props for the TabMenu component
- Good TypeScript typing and organization
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (2)
27-36: Well-designed wrapper pattern for stateful component.The
Wrappercomponent properly manages the bottom sheet's open state, which is essential for demonstrating the component's behavior in Storybook. This pattern allows interactive testing of the open/close functionality.
40-65: Comprehensive story configuration with proper controls.The story provides excellent control configuration for testing different states of the bottom sheet, including date and month selection options. The
renderprop approach correctly integrates with the wrapper for state management.The implementation excels in:
- Detailed
argTypeswith appropriate control types- Proper integration of stateful wrapper
- Comprehensive prop configuration for testing scenarios
components/main/GoalMenuContainer/GoalMenuContainer.tsx (1)
47-56: Add missing dependency touseEffect.The effect runs when
goalMenuInfoListchanges but doesn't include it in the dependency array.Apply this diff:
updateSizes(); - }, [goalMenuInfoList]); + }, [goalMenuInfoList]);Consider also adding a ResizeObserver for more robust size tracking when the container dimensions change due to window resizing or other layout changes.
Likely an incorrect or invalid review comment.
components/details/ListCard/ListCard.stories.tsx (1)
1-69: Storybook story correctly follows naming conventions.The story file is well-structured with the
Primarystory correctly named as per the coding guidelines. Good job including example data and control configurations.components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsx (1)
1-61: Well-structured Storybook story with good test coverage.The story correctly follows naming conventions with
Primaryas the main story. TheLongTextvariant is a thoughtful addition for testing text overflow scenarios.components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx (1)
260-264: Good improvement: Usingidas the React key.Using
subGoalIdas the key instead of title provides more stable React reconciliation, especially if titles can be edited.components/group/groupRoom/GroupChatRoom/GroupChatRoom.stories.tsx (1)
1-54: LGTM! Follows Storybook conventions correctly.The story file properly follows the established pattern with the
Primarystory naming convention as required by the coding guidelines. The metadata setup is consistent with other story files in the codebase.components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx (1)
1-54: LGTM! Consistent with modal story patterns.The story file correctly follows the established pattern for modal components, with appropriate callback functions in the
Primarystory args. The structure matches other modal stories in the codebase.app/adding-goal/page.tsx (1)
14-24: Good state management and validation approach.The state structure is well-organized and the form validation appropriately prevents submission without a required goal title. The disabled button styling provides clear visual feedback to users.
Also applies to: 162-175
app/details/edit/[goal_id]/_components/SubGoalEdit/SubGoalEdit.tsx (1)
82-85: Clarify or implement commented order update logic.The order update logic is commented out, which suggests incomplete implementation of the reordering feature. Either implement this logic or add a comment explaining why it's not needed.
components/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet.tsx (1)
243-282: Well-implemented form controlsThe memo section with character counter and the conditional submit button are properly implemented. Good use of form validation by requiring emotion selection.
| <form | ||
| className="flex-1 flex flex-col" | ||
| id="goalAdding" | ||
| onSubmit={async () => { | ||
| const res = await goalApi.createGoal({ | ||
| isPeriodByMonth: goalAddInfo.durationType === "month", | ||
| title: goalAddInfo.goal, | ||
| dueDate: | ||
| goalAddInfo.durationType === "month" | ||
| ? undefined | ||
| : date2StringWithSpliter( | ||
| goalAddInfo.durationValue as Date, | ||
| "-", | ||
| ), | ||
| month: | ||
| goalAddInfo.durationType === "month" | ||
| ? (goalAddInfo.durationValue as number) | ||
| : undefined, | ||
| subGoals: goalAddInfo.subGoals.map((subGoalName) => ({ | ||
| title: subGoalName, | ||
| })), | ||
| }); | ||
| if (res) { | ||
| router.back(); | ||
| } | ||
| }} | ||
| > |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add error handling and loading states for form submission.
The form submission lacks proper error handling and user feedback during API calls. Consider the following improvements:
- Add loading state management
- Handle API errors gracefully
- Explicitly prevent form default behavior
- Provide user feedback for both success and error states
+ const [isSubmitting, setIsSubmitting] = useState(false);
<form
className="flex-1 flex flex-col"
id="goalAdding"
- onSubmit={async () => {
+ onSubmit={async (e) => {
+ e.preventDefault();
+ if (isSubmitting) return;
+
+ setIsSubmitting(true);
+ try {
const res = await goalApi.createGoal({
isPeriodByMonth: goalAddInfo.durationType === "month",
title: goalAddInfo.goal,
dueDate:
goalAddInfo.durationType === "month"
? undefined
: date2StringWithSpliter(
goalAddInfo.durationValue as Date,
"-",
),
month:
goalAddInfo.durationType === "month"
? (goalAddInfo.durationValue as number)
: undefined,
subGoals: goalAddInfo.subGoals.map((subGoalName) => ({
title: subGoalName,
})),
});
if (res) {
router.back();
}
+ } catch (error) {
+ console.error('Failed to create goal:', error);
+ // Add user notification for error
+ } finally {
+ setIsSubmitting(false);
+ }
}}
>📝 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.
| <form | |
| className="flex-1 flex flex-col" | |
| id="goalAdding" | |
| onSubmit={async () => { | |
| const res = await goalApi.createGoal({ | |
| isPeriodByMonth: goalAddInfo.durationType === "month", | |
| title: goalAddInfo.goal, | |
| dueDate: | |
| goalAddInfo.durationType === "month" | |
| ? undefined | |
| : date2StringWithSpliter( | |
| goalAddInfo.durationValue as Date, | |
| "-", | |
| ), | |
| month: | |
| goalAddInfo.durationType === "month" | |
| ? (goalAddInfo.durationValue as number) | |
| : undefined, | |
| subGoals: goalAddInfo.subGoals.map((subGoalName) => ({ | |
| title: subGoalName, | |
| })), | |
| }); | |
| if (res) { | |
| router.back(); | |
| } | |
| }} | |
| > | |
| // Add loading state for form submission | |
| const [isSubmitting, setIsSubmitting] = useState(false); | |
| <form | |
| className="flex-1 flex flex-col" | |
| id="goalAdding" | |
| onSubmit={async (e) => { | |
| e.preventDefault(); | |
| if (isSubmitting) return; | |
| setIsSubmitting(true); | |
| try { | |
| const res = await goalApi.createGoal({ | |
| isPeriodByMonth: goalAddInfo.durationType === "month", | |
| title: goalAddInfo.goal, | |
| dueDate: | |
| goalAddInfo.durationType === "month" | |
| ? undefined | |
| : date2StringWithSpliter( | |
| goalAddInfo.durationValue as Date, | |
| "-", | |
| ), | |
| month: | |
| goalAddInfo.durationType === "month" | |
| ? (goalAddInfo.durationValue as number) | |
| : undefined, | |
| subGoals: goalAddInfo.subGoals.map((subGoalName) => ({ | |
| title: subGoalName, | |
| })), | |
| }); | |
| if (res) { | |
| router.back(); | |
| } | |
| } catch (error) { | |
| console.error('Failed to create goal:', error); | |
| // TODO: show user-facing error notification | |
| } finally { | |
| setIsSubmitting(false); | |
| } | |
| }} | |
| > |
🤖 Prompt for AI Agents
In app/adding-goal/page.tsx around lines 35 to 61, the form submission handler
lacks error handling, loading state management, and does not prevent the default
form submission behavior. To fix this, add a loading state variable to track the
API call status, use event.preventDefault() at the start of the onSubmit handler
to stop default form submission, wrap the API call in a try-catch block to
handle errors gracefully, and update the UI to provide user feedback for
loading, success, and error states accordingly.
| style={{ | ||
| // 한줄로 만들기 위해 | ||
| letterSpacing: "-1px", | ||
| }} | ||
| > |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Replace inline styles with Tailwind CSS utilities.
According to the coding guidelines, Tailwind CSS should be used for all styling. Replace the inline letterSpacing style with Tailwind's letter-spacing utilities.
<p
className="self-stretch justify-start text-label-alternative text-sm font-normal font-['Pretendard'] leading-none"
- style={{
- // 한줄로 만들기 위해
- letterSpacing: "-1px",
- }}
+ className="self-stretch justify-start text-label-alternative text-sm font-normal font-['Pretendard'] leading-none tracking-tight"
>Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In app/adding-goal/page.tsx around lines 113 to 117, replace the inline style
setting letterSpacing to "-1px" with the equivalent Tailwind CSS utility class.
Remove the inline style object and add the appropriate Tailwind class for letter
spacing (e.g., tracking-tight or a custom class if needed) directly to the
element's className attribute to comply with the styling guidelines.
| useEffect(() => { | ||
| if (allSubGoalCompleted && !goalDetail?.isJoinedGroup) | ||
| openModalCompletingGoal(); | ||
| }, [allSubGoalCompleted, goalDetail?.isJoinedGroup]); |
There was a problem hiding this comment.
Fix missing dependency in useEffect
The openModalCompletingGoal function should be included in the dependency array or wrapped with useCallback to prevent potential stale closure issues.
+ const openModalCompletingGoal = useCallback(() => {
openModal(
<ModalCompletingGoal
onClose={closeModal}
onCompleteGoal={async () => {
const res = await goalApi.goalComplete(goalId);
if (res) {
// 토스트
closeModal();
}
}}
onWait={closeModal}
/>,
);
- };
+ }, [openModal, closeModal, goalId]);
+
useEffect(() => {
if (allSubGoalCompleted && !goalDetail?.isJoinedGroup)
openModalCompletingGoal();
- }, [allSubGoalCompleted, goalDetail?.isJoinedGroup]);
+ }, [allSubGoalCompleted, goalDetail?.isJoinedGroup, openModalCompletingGoal]);🧰 Tools
🪛 GitHub Actions: CI Pipeline
[warning] 75-75: React Hook useEffect has a missing dependency: 'openModalCompletingGoal'. Either include it or remove the dependency array. (react-hooks/exhaustive-deps)
🤖 Prompt for AI Agents
In app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx around lines 72
to 75, the useEffect hook is missing the openModalCompletingGoal function in its
dependency array, which can cause stale closure issues. To fix this, either add
openModalCompletingGoal to the dependency array or wrap the
openModalCompletingGoal function with useCallback to ensure it has a stable
reference and is properly tracked by the effect.
| <button className="w-12 h-8 p-2 bg-background-normal rounded inline-flex justify-center items-center gap-2"> | ||
| <Link href={`/details/edit/${goalId}`}> | ||
| <p className="flex-1 text-center justify-center text-label-alternative text-xs font-semibold font-['SUIT_Variable'] leading-none"> | ||
| 편집 | ||
| </p> | ||
| </Link> | ||
| </button> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Fix nested interactive elements and improve accessibility.
Similar to the previous file, nesting a Link inside a button creates accessibility issues. Also, the button lacks proper semantic meaning.
- <button className="w-12 h-8 p-2 bg-background-normal rounded inline-flex justify-center items-center gap-2">
- <Link href={`/details/edit/${goalId}`}>
- <p className="flex-1 text-center justify-center text-label-alternative text-xs font-semibold font-['SUIT_Variable'] leading-none">
- 편집
- </p>
- </Link>
- </button>
+ <Link
+ href={`/details/edit/${goalId}`}
+ className="w-12 h-8 p-2 bg-background-normal rounded inline-flex justify-center items-center gap-2"
+ aria-label="목표 편집"
+ >
+ <span className="text-center text-label-alternative text-xs font-semibold font-['SUIT_Variable'] leading-none">
+ 편집
+ </span>
+ </Link>📝 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.
| <button className="w-12 h-8 p-2 bg-background-normal rounded inline-flex justify-center items-center gap-2"> | |
| <Link href={`/details/edit/${goalId}`}> | |
| <p className="flex-1 text-center justify-center text-label-alternative text-xs font-semibold font-['SUIT_Variable'] leading-none"> | |
| 편집 | |
| </p> | |
| </Link> | |
| </button> | |
| <Link | |
| href={`/details/edit/${goalId}`} | |
| className="w-12 h-8 p-2 bg-background-normal rounded inline-flex justify-center items-center gap-2" | |
| aria-label="목표 편집" | |
| > | |
| <span className="text-center text-label-alternative text-xs font-semibold font-['SUIT_Variable'] leading-none"> | |
| 편집 | |
| </span> | |
| </Link> |
🤖 Prompt for AI Agents
In app/details/[goal_id]/page.tsx around lines 26 to 32, avoid nesting the Link
component inside a button as it causes accessibility issues. Replace the button
element with a single Link styled as a button by applying the button's classes
directly to the Link component. This ensures proper semantic meaning and
improves accessibility.
| import TodoResultBottomSheet from "@/components/shared/BottomSheets/TodoResultBottomSheet/TodoResultBottomSheet"; | ||
| import { postTodoResult } from "@/lib/fetching/postTodoResult"; | ||
| import { | ||
| TodoResultRqEmotionEnum, | ||
| TodoResultRsEmotionEnum, | ||
| } from "@/api/generated/motimo/Api"; | ||
| import { useSubGoalTodosAllInfinite } from "@/hooks/queries/useSubGoalTodosInfiniites"; |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Remove unused imports or confirm if they're needed.
Several imports appear to be unused in this component. Consider removing them to improve code cleanliness.
🏁 Script executed:
#!/bin/bash
# Check if these imports are actually used in the file
rg -n "TodoResultBottomSheet|postTodoResult|TodoResultRqEmotionEnum|TodoResultRsEmotionEnum|useSubGoalTodosAllInfinite" app/details/edit/\[goal_id\]/page.tsxLength of output: 494
Remove unused imports in app/details/edit/[goal_id]/page.tsx
The following imports are not referenced anywhere in this file and should be removed to keep the code clean and avoid confusion:
TodoResultBottomSheet(line 16)postTodoResult(line 17)TodoResultRqEmotionEnum,TodoResultRsEmotionEnum(lines 19–20)useSubGoalTodosAllInfinite(line 22)
Please delete these import statements or re-introduce their usage if they’re intended for immediate development.
🤖 Prompt for AI Agents
In app/details/edit/[goal_id]/page.tsx between lines 16 and 22, there are
several imports including TodoResultBottomSheet, postTodoResult,
TodoResultRqEmotionEnum, TodoResultRsEmotionEnum, and useSubGoalTodosAllInfinite
that are not used anywhere in the file. To fix this, remove these unused import
statements to clean up the code and avoid confusion, unless you plan to use them
imminently, in which case ensure their usage is added.
| if (targetRef.current) { | ||
| observer.disconnect(); |
There was a problem hiding this comment.
Potential memory leak: observer.disconnect() should use the actual element
The cleanup function references targetRef.current, but this value might be different from when the observer was set up. Store the observed element to ensure proper cleanup.
if (targetRef.current) {
observer.observe(targetRef.current);
}
+ const observedElement = targetRef.current;
return () => {
- if (targetRef.current) {
- observer.disconnect();
- }
+ if (observedElement) {
+ observer.unobserve(observedElement);
+ }
+ observer.disconnect();
};📝 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.
| if (targetRef.current) { | |
| observer.disconnect(); | |
| if (targetRef.current) { | |
| observer.observe(targetRef.current); | |
| } | |
| const observedElement = targetRef.current; | |
| return () => { | |
| if (observedElement) { | |
| observer.unobserve(observedElement); | |
| } | |
| observer.disconnect(); | |
| }; |
🤖 Prompt for AI Agents
In hooks/queries/useSubGoalTodosInfiniites.ts around lines 175 to 176, the
cleanup function calls observer.disconnect() using targetRef.current, which may
have changed since the observer was created. To fix this, store the element that
was originally observed in a variable when setting up the observer, and use that
stored element for disconnecting the observer in the cleanup function to ensure
proper cleanup and avoid potential memory leaks.
| observer.disconnect(); | ||
| } | ||
| }; | ||
| }, [exist, targetRef.current]); |
There was a problem hiding this comment.
Remove targetRef.current from useEffect dependencies
Including targetRef.current in the dependency array is problematic because React doesn't track ref mutations. This could lead to the effect not re-running when expected or running too often.
- }, [exist, targetRef.current]);
+ }, [exist, fetchNextPage]);🤖 Prompt for AI Agents
In hooks/queries/useSubGoalTodosInfiniites.ts at line 179, remove
targetRef.current from the useEffect dependency array because React does not
track changes to ref.current, which can cause incorrect effect execution. Keep
only the necessary dependencies like exist to ensure the effect runs correctly.
| const templateFetch = async <T>({ | ||
| apiUrl, | ||
| method, | ||
| body, | ||
| options, | ||
| headerWithOutAuthorization, | ||
| onFetchNonOk, | ||
| onErrorCatch, | ||
| }: { | ||
| apiUrl: string; | ||
| method: "GET" | "PUT" | "PATCH" | "POST" | "DELETE"; | ||
| body?: BodyInit; | ||
| options?: RequestInit; | ||
| headerWithOutAuthorization?: object; | ||
| onFetchNonOk?: (fetchRes: Response) => void; | ||
| onErrorCatch?: (error: unknown) => void; | ||
| }) => { | ||
| try { | ||
| // const token = localStorage.getItem("access_token"); | ||
| const token = useAuthStore.getState().accessToken; | ||
| const res = await fetch(apiUrl, { | ||
| ...options, | ||
| method: method, | ||
| headers: { | ||
| ...headerWithOutAuthorization, | ||
| // ...(autoContentType ? {} : { "Content-Type": "application/json" }), | ||
| Authorization: `Bearer ${token}`, | ||
| }, | ||
|
|
||
| body: | ||
| method === "PUT" || method === "POST" || method === "PATCH" | ||
| ? body | ||
| : undefined, | ||
| }); | ||
| if (!res.ok) { | ||
| if (onFetchNonOk) onFetchNonOk(res); | ||
| // onFetchNonOk에서 throw을 안 할수도 있어서 | ||
| else throw new Error(`HTTP 에러! status:${res.status}`); | ||
| } | ||
|
|
||
| const result: T = await res.json(); | ||
| return result; | ||
| } catch (e) { | ||
| if (onErrorCatch) onErrorCatch(e); | ||
| console.error(`fetch error: ${e}`); | ||
| } | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Fix inconsistent return type handling.
The function returns T on success but may return undefined in the catch block. This creates type inconsistency. Either make the return type T | undefined or explicitly handle the error case.
- const templateFetch = async <T>({
+ const templateFetch = async <T>({
apiUrl,
method,
body,
options,
headerWithOutAuthorization,
onFetchNonOk,
onErrorCatch,
}: {
apiUrl: string;
method: "GET" | "PUT" | "PATCH" | "POST" | "DELETE";
body?: BodyInit;
options?: RequestInit;
headerWithOutAuthorization?: object;
onFetchNonOk?: (fetchRes: Response) => void;
onErrorCatch?: (error: unknown) => void;
- }) => {
+ }): Promise<T | undefined> => {
try {
// ... existing code ...
const result: T = await res.json();
return result;
} catch (e) {
if (onErrorCatch) onErrorCatch(e);
console.error(`fetch error: ${e}`);
+ return undefined;
}
};📝 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.
| const templateFetch = async <T>({ | |
| apiUrl, | |
| method, | |
| body, | |
| options, | |
| headerWithOutAuthorization, | |
| onFetchNonOk, | |
| onErrorCatch, | |
| }: { | |
| apiUrl: string; | |
| method: "GET" | "PUT" | "PATCH" | "POST" | "DELETE"; | |
| body?: BodyInit; | |
| options?: RequestInit; | |
| headerWithOutAuthorization?: object; | |
| onFetchNonOk?: (fetchRes: Response) => void; | |
| onErrorCatch?: (error: unknown) => void; | |
| }) => { | |
| try { | |
| // const token = localStorage.getItem("access_token"); | |
| const token = useAuthStore.getState().accessToken; | |
| const res = await fetch(apiUrl, { | |
| ...options, | |
| method: method, | |
| headers: { | |
| ...headerWithOutAuthorization, | |
| // ...(autoContentType ? {} : { "Content-Type": "application/json" }), | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| body: | |
| method === "PUT" || method === "POST" || method === "PATCH" | |
| ? body | |
| : undefined, | |
| }); | |
| if (!res.ok) { | |
| if (onFetchNonOk) onFetchNonOk(res); | |
| // onFetchNonOk에서 throw을 안 할수도 있어서 | |
| else throw new Error(`HTTP 에러! status:${res.status}`); | |
| } | |
| const result: T = await res.json(); | |
| return result; | |
| } catch (e) { | |
| if (onErrorCatch) onErrorCatch(e); | |
| console.error(`fetch error: ${e}`); | |
| } | |
| }; | |
| const templateFetch = async <T>({ | |
| apiUrl, | |
| method, | |
| body, | |
| options, | |
| headerWithOutAuthorization, | |
| onFetchNonOk, | |
| onErrorCatch, | |
| }: { | |
| apiUrl: string; | |
| method: "GET" | "PUT" | "PATCH" | "POST" | "DELETE"; | |
| body?: BodyInit; | |
| options?: RequestInit; | |
| headerWithOutAuthorization?: object; | |
| onFetchNonOk?: (fetchRes: Response) => void; | |
| onErrorCatch?: (error: unknown) => void; | |
| }): Promise<T | undefined> => { | |
| try { | |
| // const token = localStorage.getItem("access_token"); | |
| const token = useAuthStore.getState().accessToken; | |
| const res = await fetch(apiUrl, { | |
| ...options, | |
| method: method, | |
| headers: { | |
| ...headerWithOutAuthorization, | |
| // ...(autoContentType ? {} : { "Content-Type": "application/json" }), | |
| Authorization: `Bearer ${token}`, | |
| }, | |
| body: | |
| method === "PUT" || method === "POST" || method === "PATCH" | |
| ? body | |
| : undefined, | |
| }); | |
| if (!res.ok) { | |
| if (onFetchNonOk) onFetchNonOk(res); | |
| // onFetchNonOk에서 throw을 안 할수도 있어서 | |
| else throw new Error(`HTTP 에러! status:${res.status}`); | |
| } | |
| const result: T = await res.json(); | |
| return result; | |
| } catch (e) { | |
| if (onErrorCatch) onErrorCatch(e); | |
| console.error(`fetch error: ${e}`); | |
| return undefined; | |
| } | |
| }; |
🤖 Prompt for AI Agents
In lib/fetching/template/fetchTemplate.ts from lines 5 to 51, the function
returns a value of type T on success but returns undefined in the catch block,
causing inconsistent return types. To fix this, update the function's return
type to T | undefined to reflect that it may return undefined on error, or
modify the catch block to throw the error or return a default value of type T to
maintain consistent return types.
| loader: "@svgr/webpack", | ||
| options: { | ||
| icon: true, | ||
| icon: false, |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify impact of changing SVG icon option to false.
The icon option for @svgr/webpack was changed from true to false. This affects how SVG files are transformed - when icon is true, SVGR adds default width/height props and removes width/height attributes from the SVG, making it more suitable for icon usage.
🏁 Script executed:
#!/bin/bash
# Description: Check if existing SVG icons depend on the icon: true behavior
# Expected: Find SVGs that might be affected by this change
echo "Searching for SVG imports in components..."
rg -A 3 "import.*\.svg" --type tsx --type ts
echo "Checking for hardcoded width/height in SVG components..."
ast-grep --pattern 'width={$_}' | head -20
ast-grep --pattern 'height={$_}' | head -20Length of output: 383
🏁 Script executed:
#!/bin/bash
# Broader search for SVG imports and width/height props across JS/TS files
echo "Searching for SVG imports across JS/TS files..."
rg -n "import .*\.svg" --glob "*.ts*" --glob "*.js*"
rg -n "from .*\.svg" --glob "*.ts*" --glob "*.js*"
echo "Searching for JSX width/height props..."
rg -n "width\s*=\s*{[^}]+}" --glob "*.ts*" --glob "*.js*"
rg -n "height\s*=\s*{[^}]+}" --glob "*.ts*" --glob "*.js*"Length of output: 13854
🏁 Script executed:
#!/bin/bash
# Look for any explicit width/height props on SVG components in TSX files
echo "Searching for explicit width props on imported SVG components..."
rg -n "<[A-Z][A-Za-z0-9]*Svg[^>]*width=" --glob "*.tsx"
echo "Searching for explicit height props on imported SVG components..."
rg -n "<[A-Z][A-Za-z0-9]*Svg[^>]*height=" --glob "*.tsx"Length of output: 2216
🏁 Script executed:
#!/bin/bash
# Find SVG component usages without explicit width/height props to assess impact
echo "SVG usages without width or height props:"
rg -n "<[A-Z][A-Za-z0-9]*Svg[^>]*>" --glob "*.tsx" \
| grep -vE "width\s*=" | grep -vE "height\s*=" | head -20Length of output: 2114
Potential Break in SVG Icon Sizing from icon: false Change
By disabling SVGR’s icon option, default 1em sizing and automatic removal of <svg> width/height attributes are no longer applied. Any <*Svg/> components without explicit width/height props will now render at their raw SVG dimensions, likely causing visual regressions.
Impacted usages without explicit sizing (first 10 examples shown):
components/details/SubGoalEditItem/SubGoalEditItem.tsx:21–<DraggableSvg />components/details/SubGoalEditItem/SubGoalEditItem.tsx:36–<EditSvg />components/details/SubGoalEditItem/SubGoalEditItem.tsx:45–<TrashBinSvg />components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.tsx:40–<CloseSvg />components/details/ListCard/ListCard.tsx:91–<LeftArrowSvg />components/details/ListCard/ListCard.tsx:107–<RightArrowSvg />components/details/GoalData/GoalData.tsx:25–<CompletionSvg />components/details/EditInfo/EditInfo.tsx:16–<WarningInfoSvg />components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.tsx:66–<CloseSvg />components/shared/TextField/TextField.tsx:63–<WarningCircleSvg />
Actions required:
- Add explicit
width/heightprops to all icon components, or - Revert to
icon: truefor consistent default sizing, or - Provide a shared wrapper/
Iconcomponent that enforces sizing.
Please update the configuration or code to ensure all SVG icons render at the intended dimensions.
🤖 Prompt for AI Agents
In next.config.ts at line 41, the SVGR option `icon` is set to false, which
disables default 1em sizing and removal of SVG width/height attributes, causing
icons without explicit size props to render at raw dimensions and break layout.
To fix this, either revert the `icon` option to true to restore default sizing
behavior, or ensure all SVG icon components used across the codebase have
explicit width and height props set, or implement a shared Icon wrapper
component that enforces consistent sizing for all SVG icons.
| }, | ||
| "devDependencies": { | ||
| "@chromatic-com/storybook": "^3.0.0", | ||
| "@netlify/plugin-nextjs": "^5.11.4", |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify the Netlify plugin version for security and compatibility.
The addition of @netlify/plugin-nextjs is appropriate for Next.js deployment on Netlify. However, please ensure this version is current and secure.
🌐 Web query:
What is the latest version of @netlify/plugin-nextjs and are there any security advisories for version 5.11.4?
💡 Result:
The latest version of @netlify/plugin-nextjs as of July 2025 is 5.11.6[7]. This is confirmed by the official npm package listing, which states version 5.11.6 was published 7 days ago[7].
Regarding security advisories for version 5.11.4:
- There are no public security advisories or CVEs specific to 5.11.4 listed in the top security databases or in official Netlify communication at this time[2][3][8].
- Netlify recently addressed CVE-2025-32421, but clarified that Netlify’s CDN setup renders Next.js sites (including those using @netlify/plugin-nextjs) not vulnerable to this cache poisoning risk[2].
- The upgrade documentation strongly recommends using the latest adapter version to benefit from ongoing security and stability improvements[1][7].
Summary table:
| Plugin Version | Latest (July 2025) | Security Advisories for 5.11.4 |
|---|---|---|
| @netlify/plugin-nextjs | 5.11.6[7] | None known or published as of July 2025[2][3][8] |
If you are on 5.11.4 and have security concerns, Netlify's best practice is to upgrade to the latest version to ensure you have all recent security fixes and enhancements[1][7].
Citations:
- 1: https://docs.netlify.com/build/frameworks/framework-setup-guides/nextjs/legacy-runtime/upgrading-or-reverting-adapter/
- 2: https://www.netlify.com/changelog/security-update-next-js-sites-on-netlify-not-vulnerable-to-cve-2025-32421/
- 3: https://security.snyk.io/package/npm/@netlify%2Fplugin-nextjs/4.41.3-experimental-waf-passthrough.0
- 4: https://github.com/reflektor-digital-inc/netlify-plugin-nextjs
- 5: fix: resolve next-server from next app directory and not from plugin opennextjs/opennextjs-netlify#2059
- 6: https://www.npmjs.com/package/@netlify/plugin-nextjs/v/4.4.3?activeTab=versions
- 7: https://www.npmjs.com/package/@netlify/plugin-nextjs
- 8: https://answers.netlify.com/t/build-issues-when-upgrading-form-netlify-plugin-nextjs-4-to-netlify-plugin-nextjs-5/122137
- 9: https://github.com/netlify/netlify-plugin-nextjs/releases
- 10: https://answers.netlify.com/t/outdated-plugins-732-pm-netlify-plugin-nextjs-4-41-3/137838
Upgrade @netlify/plugin-nextjs to the latest version (5.11.6)
No known security advisories exist for 5.11.4, but v5.11.6 was released July 2025 with the latest fixes and improvements.
Please update in package.json (around line 39):
- "@netlify/plugin-nextjs": "^5.11.4",
+ "@netlify/plugin-nextjs": "^5.11.6",📝 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.
| "@netlify/plugin-nextjs": "^5.11.4", | |
| "@netlify/plugin-nextjs": "^5.11.6", |
🤖 Prompt for AI Agents
In package.json at line 39, update the version of "@netlify/plugin-nextjs" from
"^5.11.4" to "^5.11.6" to use the latest released version with recent fixes and
improvements. Modify the version string only, keeping the rest of the line
intact.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx (1)
235-236: Clean up commented codeConsider removing the commented-out
fileNameandphotoUrlproperties or implement them if they're needed for future functionality.diaryText={content.content} - // fileName={content["fileName"]} - // photoUrl="" hasReaction={messageInfo.hasUserReacted}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
api/generated/motimo/Api.tsis excluded by!**/generated/**
📒 Files selected for processing (4)
components/group/GroupChat.stories.tsx(14 hunks)components/group/GroupChat.tsx(3 hunks)components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx(1 hunks)package.json(0 hunks)
📓 Path-based instructions (3)
components/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For every styling, use tailwind css.
Files:
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx
{components/**/*.{js,jsx,ts,tsx},**/*.css}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For tokens, use tokens.css (mdc:app/tokens.css).
Files:
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx
components/**/*
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
Component should be created in components/
Files:
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx
💤 Files with no reviewable changes (1)
- package.json
✅ Files skipped from review due to trivial changes (2)
- components/group/GroupChat.tsx
- components/group/GroupChat.stories.tsx
🧰 Additional context used
📓 Path-based instructions (3)
components/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For every styling, use tailwind css.
Files:
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx
{components/**/*.{js,jsx,ts,tsx},**/*.css}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For tokens, use tokens.css (mdc:app/tokens.css).
Files:
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx
components/**/*
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
Component should be created in components/
Files:
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx
🔇 Additional comments (4)
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx (4)
1-35: LGTM: Clean imports and type mappingThe imports are well-organized and the
reactionTypeMapsprovides a clean abstraction between API enums and internal reaction types.
40-63: Good infinite scrolling implementationThe infinite scrolling setup with intersection observer and
useGroupChatInfinitehook is well implemented. The observer pattern for loading more messages when reaching the top is appropriate for a chat interface.
167-173: Good fix: Hook moved to top levelThe
useModalhook is now properly called at the top level of the component, resolving the previous React hooks rule violation.
148-149: Good use of design tokens and Tailwind CSSProper usage of design system tokens like
bg-background-assistiveandtext-label-normalalong with Tailwind CSS classes follows the coding guidelines.
불필요 콘솔도 제거
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx (1)
263-287: Remove commented code.This appears to be an old implementation of TodoResultMessage that has been integrated into the TodoMessage component. Keeping commented code reduces maintainability.
-// interface TodoResultMessageProps { -// messageInfo: GroupMessageItemRs; -// userId: string; -// } -// const TodoResultMessage = ({ messageInfo, userId }: TodoResultMessageProps) => { -// const message = messageInfo.message as TodoResultMessage; -// const content = message.content; -// return ( -// <> -// <GroupChatItem -// id={messageInfo.messageId} -// mainText="투두 기록을 남겼어요!" -// style="todo" -// type={messageInfo.userId === userId ? "me" : "member"} -// userName={messageInfo.userName} -// checkboxLabel={content.todoTitle} -// diaryText={content.content} -// // fileName={content["fileName"]} -// // photoUrl="" -// hasUserReacted={messageInfo.hasUserReacted} -// reactionCount={messageInfo.reactionCount} -// /> -// </> -// ); -// };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
app/group/[id]/page.tsx(1 hunks)components/group/GroupChat.tsx(2 hunks)components/group/GroupChatItem.tsx(5 hunks)components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx(1 hunks)components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsx(1 hunks)components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx(1 hunks)components/main/GoalCard/GoalCard.tsx(0 hunks)hooks/queries/useGroupChatInfinite.ts(1 hunks)
💤 Files with no reviewable changes (1)
- components/main/GoalCard/GoalCard.tsx
🚧 Files skipped from review as they are similar to previous changes (5)
- components/group/GroupChat.tsx
- components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx
- hooks/queries/useGroupChatInfinite.ts
- components/group/GroupChatItem.tsx
- components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsx
🧰 Additional context used
📓 Path-based instructions (3)
components/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For every styling, use tailwind css.
Files:
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx
{components/**/*.{js,jsx,ts,tsx},**/*.css}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For tokens, use tokens.css (mdc:app/tokens.css).
Files:
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx
components/**/*
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
Component should be created in components/
Files:
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx
🧬 Code Graph Analysis (2)
app/group/[id]/page.tsx (2)
.storybook/nextjs-mock.ts (2)
useParams(30-30)useRouter(24-24)api/hooks.ts (1)
useGroupDetail(165-165)
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx (5)
api/hooks.ts (1)
useMyProfile(162-162)hooks/queries/useSubGoalTodosInfiniites.ts (1)
useObservingExist(187-187)api/generated/motimo/Api.ts (5)
GroupMessageItemRs(467-494)GroupChatRs(425-436)TodoCompletedContent(502-506)TodoResultSubmittedContent(508-517)MessageReactionContent(496-500)components/group/GroupChatItem.tsx (1)
GroupChatItem(100-260)api/service.ts (1)
groupApi(48-48)
⏰ 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 (3)
app/group/[id]/page.tsx (1)
1-20: LGTM!The page component is well-structured with clean separation of concerns. The use of dedicated components for header and chat room promotes modularity.
components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx (2)
1-37: Well-organized imports and type mappings.The imports are properly structured and the reaction type mappings provide a clean abstraction between API enums and UI component types.
161-177: Clean notification message implementation.The NotiMessage component correctly handles both join and leave notifications with appropriate messaging.
| case GroupMessageContentTypeEnum.MESSAGE_REACTION: { | ||
| const content = (messageInfo.message as TodoReactionMessage).content; | ||
| const refId = content.referenceMessageId; | ||
| const refUserName = | ||
| data?.reduce((acc, pageInfo) => { | ||
| const found = pageInfo.messages.findIndex( | ||
| (message) => message.messageId === refId, | ||
| ); | ||
| if (found !== -1) { | ||
| return pageInfo.messages[found].userName; | ||
| } | ||
| return acc; | ||
| }, "") ?? ""; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Optimize the referenced username lookup.
The current implementation uses reduce to find the referenced username, which continues iterating even after finding the match. This is inefficient for large chat histories.
Replace the reduce operation with a more efficient approach:
- const refUserName =
- data?.reduce((acc, pageInfo) => {
- const found = pageInfo.messages.findIndex(
- (message) => message.messageId === refId,
- );
- if (found !== -1) {
- return pageInfo.messages[found].userName;
- }
- return acc;
- }, "") ?? "";
+ let refUserName = "";
+ if (data && refId) {
+ for (const pageInfo of data) {
+ const message = pageInfo.messages.find(
+ (msg) => msg.messageId === refId
+ );
+ if (message) {
+ refUserName = message.userName;
+ break;
+ }
+ }
+ }📝 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.
| case GroupMessageContentTypeEnum.MESSAGE_REACTION: { | |
| const content = (messageInfo.message as TodoReactionMessage).content; | |
| const refId = content.referenceMessageId; | |
| const refUserName = | |
| data?.reduce((acc, pageInfo) => { | |
| const found = pageInfo.messages.findIndex( | |
| (message) => message.messageId === refId, | |
| ); | |
| if (found !== -1) { | |
| return pageInfo.messages[found].userName; | |
| } | |
| return acc; | |
| }, "") ?? ""; | |
| case GroupMessageContentTypeEnum.MESSAGE_REACTION: { | |
| const content = (messageInfo.message as TodoReactionMessage).content; | |
| const refId = content.referenceMessageId; | |
| - const refUserName = | |
| - data?.reduce((acc, pageInfo) => { | |
| - const found = pageInfo.messages.findIndex( | |
| - (message) => message.messageId === refId, | |
| - ); | |
| - if (found !== -1) { | |
| - return pageInfo.messages[found].userName; | |
| - } | |
| - return acc; | |
| - }, "") ?? ""; | |
| + let refUserName = ""; | |
| + if (data && refId) { | |
| + for (const pageInfo of data) { | |
| + const message = pageInfo.messages.find( | |
| + (msg) => msg.messageId === refId | |
| + ); | |
| + if (message) { | |
| + refUserName = message.userName; | |
| + break; | |
| + } | |
| + } | |
| + } |
🤖 Prompt for AI Agents
In components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx around lines 96 to
108, the code uses reduce to find the referenced username, which iterates over
all pages even after finding a match. To optimize, replace the reduce with a
loop or find method that stops searching once the referenced message is found,
returning the username immediately to avoid unnecessary iterations over the
entire data set.
| interface TodoMessageProps { | ||
| type: | ||
| | GroupMessageContentTypeEnum.TODO_COMPLETE | ||
| | GroupMessageContentTypeEnum.TODO_RESULT_SUBMIT; | ||
| messageInfo: GroupMessageItemRs; | ||
| userId: string; | ||
| mutate: SWRInfiniteKeyedMutator<GroupChatRs[]>; | ||
| } | ||
| type TodoCompleteContent = { | ||
| content: TodoCompletedContent; | ||
| }; | ||
| type TodoResultMessage = { | ||
| content: TodoResultSubmittedContent; | ||
| }; | ||
| const TodoMessage = ({ | ||
| type, | ||
| messageInfo, | ||
| userId, | ||
| mutate, | ||
| }: TodoMessageProps) => { | ||
| const { openModal, closeModal } = useModal(); | ||
|
|
||
| const message = | ||
| type === GroupMessageContentTypeEnum.TODO_COMPLETE | ||
| ? (messageInfo.message as TodoCompleteContent) | ||
| : (messageInfo.message as TodoResultMessage); | ||
| const content = message.content; | ||
| return ( | ||
| <> | ||
| <GroupChatItem | ||
| id={messageInfo.messageId} | ||
| mainText={ | ||
| type === GroupMessageContentTypeEnum.TODO_COMPLETE | ||
| ? "투두를 완료했어요!" | ||
| : "투두 기록을 남겼어요!" | ||
| } | ||
| style="todo" | ||
| type={messageInfo.userId === userId ? "me" : "member"} | ||
| userName={messageInfo.userName} | ||
| checkboxLabel={content?.todoTitle ?? ""} | ||
| diaryText={ | ||
| type === GroupMessageContentTypeEnum.TODO_RESULT_SUBMIT | ||
| ? (message as TodoResultMessage).content.content | ||
| : undefined | ||
| } | ||
| // fileName={content["fileName"]} | ||
| // photoUrl="" | ||
|
|
||
| hasUserReacted={messageInfo.hasUserReacted} | ||
| reactionCount={messageInfo.reactionCount} | ||
| onReactionClick={ | ||
| messageInfo.hasUserReacted | ||
| ? undefined | ||
| : () => { | ||
| openModal( | ||
| <ReactionModal | ||
| onClose={() => closeModal()} | ||
| onLeaveReaction={async (selectedType) => { | ||
| const emotionEnumVal = Object.entries( | ||
| reactionTypeMaps, | ||
| ).find( | ||
| ([key, val]) => val === selectedType, | ||
| )![0] as unknown as UpsertGroupReactionParamsTypeEnum; | ||
|
|
||
| const res = await groupApi.upsertGroupReaction( | ||
| messageInfo.messageId, | ||
| { | ||
| type: emotionEnumVal, | ||
| }, | ||
| ); | ||
| if (res) { | ||
| closeModal(); | ||
| mutate(); | ||
| } | ||
| }} | ||
| />, | ||
| ); | ||
| } | ||
| } | ||
| /> | ||
| </> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify fileType usage per PR objectives.
The PR objectives mention sending fileType in chat GET requests, but the current implementation only uses fileName and fileUrl from TodoResultSubmittedContent.
🏁 Script executed:
#!/bin/bash
# Search for fileType property in TodoResultSubmittedContent or related types
ast-grep --pattern 'fileType'
# Also search with ripgrep for broader context
rg -A 5 -B 5 'fileType|TodoResultSubmittedContent'Length of output: 37480
Add fileType support for todo result messages
TodoResultSubmittedContent only includes fileUrl but not fileType, despite PR objectives calling for sending and rendering fileType. To fix:
• In api/generated/motimo/Api.ts – extend TodoResultSubmittedContent to include fileType?: string
• In components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx – unpack and pass message.content.fileType to GroupChatItem
• In components/group/GroupChatItem.tsx – add a fileType prop and render it (e.g. choose icon or preview based on type)
• Update Storybook stories to supply fileType and verify rendering
🤖 Prompt for AI Agents
In components/group/groupRoom/GroupChatRoom/GroupChatRoom.tsx between lines 179
and 261, the TodoResultSubmittedContent type lacks the fileType property, which
is needed for rendering file type info. First, update
api/generated/motimo/Api.ts to extend TodoResultSubmittedContent by adding an
optional fileType string property. Then, in GroupChatRoom.tsx, extract
message.content.fileType and pass it as a new prop to GroupChatItem. Next,
modify components/group/GroupChatItem.tsx to accept the fileType prop and render
it appropriately (e.g., display an icon or preview based on the file type).
Finally, update the Storybook stories to include fileType in the test data and
verify the rendering works as expected.
| type="back" | ||
| title={groupRoomName} | ||
| onBackClick={() => { | ||
| router.back(); |
There was a problem hiding this comment.
여기 back 말고 /group 으로 가게 고정 해주실 수 있을까요?
member 페이지 갔다가 잘못 꼬이면 뒤로가기가 무한 반복되는 경우가 생기는거같아요
There was a problem hiding this comment.
상세 페이지로부터 진입할 때만 뒤로가기,
나머지는 그룹 페이지로 이동하도록 수정했습니다.
스토리북에서의 작동을 위해 외부에서 주입하도록 변경
상세 페이지로부터의 이동은 그냥 뒤로가기로, 나머지는 group페이지로 이동하도록 수정 group페이지로부터 채팅방 이동 시 무한 로딩 생겨서.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx (1)
24-26: Address the previous review feedback about navigation.Based on the past review comment, there was a request to make the back navigation go to
/groupinstead of using browser back to prevent infinite loops when coming from member pages.The previous reviewer requested that the back navigation should go to
/groupinstead of using browser back. However, this component receivesonBackClickas a prop, so the navigation logic should be handled by the parent component. Let me verify how this is being used:#!/bin/bash # Description: Check how GroupRoomHeader is used and if the navigation issue is addressed # Find usages of GroupRoomHeader component rg -A 10 -B 5 "GroupRoomHeader" --type tsx --type ts # Look for navigation patterns in group pages rg -A 5 -B 5 "onBackClick|router.push.*group|router.back" app/group/
🧹 Nitpick comments (4)
components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx (4)
5-5: Remove unused import.The
useRouterimport is not used in this component and should be removed to keep the code clean.-import { useRouter } from "next/navigation";
7-11: Consider adding JSDoc comments for better documentation.The props interface would benefit from documentation to clarify the purpose of each callback function.
interface GroupRoomHeaderProps { + /** The name of the group chat room to display in the header */ groupRoomName: string; + /** Callback function to navigate to the member list page */ routeToMember: () => void; + /** Callback function to handle back navigation */ onBackClick: () => void; }
18-19: Remove unnecessary React Fragment.The empty fragment wrapper is unnecessary since you're returning a single
headerelement.return ( - <> <header className="flex items-center gap-5 fixed top-0 w-[360px] bg-white"> {/* header content */} </header> - </> );Also applies to: 38-39
24-26: Simplify callback function.The arrow function wrapper is unnecessary since you can pass the prop function directly.
onBackClick={() => { - onBackClick(); - }} + onBackClick={onBackClick}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx(1 hunks)app/group/[id]/page.tsx(1 hunks)components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsx(1 hunks)components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.stories.tsx
- app/group/[id]/page.tsx
🧰 Additional context used
📓 Path-based instructions (3)
components/**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For every styling, use tailwind css.
Files:
components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx
{components/**/*.{js,jsx,ts,tsx},**/*.css}
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
For tokens, use tokens.css (mdc:app/tokens.css).
Files:
components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx
components/**/*
📄 CodeRabbit Inference Engine (.cursor/rules/global-rule.mdc)
Component should be created in components/
Files:
components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx
⏰ 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
| }: GroupRoomHeaderProps) => { | ||
| return ( | ||
| <> | ||
| <header className="flex items-center gap-5 fixed top-0 w-[360px] bg-white"> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Fix responsive design and add z-index for proper layering.
The fixed width of w-[360px] makes the component non-responsive. Also, fixed headers should have a z-index to ensure proper layering. Additionally, there's a double space in the className.
- <header className="flex items-center gap-5 fixed top-0 w-[360px] bg-white">
+ <header className="flex items-center gap-5 fixed top-0 w-full max-w-[360px] bg-white z-10">📝 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.
| <header className="flex items-center gap-5 fixed top-0 w-[360px] bg-white"> | |
| <header className="flex items-center gap-5 fixed top-0 w-full max-w-[360px] bg-white z-10"> |
🤖 Prompt for AI Agents
In components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx at line 20,
replace the fixed width class w-[360px] with a responsive width class such as
w-full or a max-width variant to make the header responsive. Add a z-index class
like z-10 to ensure the fixed header layers correctly above other content. Also,
remove the double space between "items-center" and "gap-5" in the className
string.
| <button | ||
| onClick={() => { | ||
| routeToMember(); | ||
| }} | ||
| type="button" | ||
| className="w-10 h-10 text-label-alternative" | ||
| > | ||
| <PeopleSvg /> | ||
| </button> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve accessibility and simplify onClick handler.
The button lacks proper accessibility attributes and the onClick handler can be simplified.
<button
- onClick={() => {
- routeToMember();
- }}
+ onClick={routeToMember}
type="button"
- className="w-10 h-10 text-label-alternative"
+ className="w-10 h-10 text-label-alternative"
+ aria-label="View group members"
>
<PeopleSvg />
</button>🤖 Prompt for AI Agents
In components/group/groupRoom/GroupRoomHeader/GroupRoomHeader.tsx around lines
28 to 36, improve the button's accessibility by adding appropriate attributes
such as aria-label to describe its purpose. Simplify the onClick handler by
passing the routeToMember function directly instead of wrapping it in an arrow
function.
대기중 api
Summary by CodeRabbit
New Features
Refactor
Bug Fixes
Chores