Conversation
vercel 정책 상 prography계정의 레포는 organization이라 유료 플랜이라.
마이너 수정이라 main에서 진행
code형태 아니어야 했기에.
숫자 표기 안되는 문제로 인해.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
app/details/edit/[goal_id]/_components/GoalEdit/GoalEdit.tsx (4)
19-24: Clean up commented code in interface.The interface now properly includes the
goalIdprop, but the commented properties should be removed to improve code clarity.interface GoalEditProps { - // initGoalTitle: string; - // // initDurationValue?: unknown; - // // initDurationType?: unknown; goalId: string; }
56-62: Simplify with optional chaining.The conditional check for
setEditContentscan be simplified using optional chaining as suggested by the static analysis tool.onChange={(e) => - setEditContents && - setEditContents((prev) => ({ + setEditContents?.((prev) => ({ ...prev, goalTitle: e.target.value, })) }
120-125: Simplify with optional chaining.Similar to the form section above, this conditional check can be simplified using optional chaining.
setEditContents && - setEditContents((prev) => ({ + setEditContents?.((prev) => ({ ...prev, durationType: type, durationValue: value, }));
27-29: Remove commented code for cleaner codebase.There are several commented lines throughout the component that should be removed to improve code clarity.
const GoalEdit = ({ - // initDurationValue, - // initDurationType, - // initGoalTitle, goalId, }: GoalEditProps) => { const router = useRouter(); const { mutate } = useGoals(); - // const [goalTitle, setGoalTitle] = useState(initGoalTitle); const nullableContext = useContext(EditContext);<p className="justify-start text-neutral-900 text-sm font-normal font-['Pretendard'] leading-none"> - {/* {`${initDurationType} - ${initDurationValue}`} */} {durationSettingBtnText} </p>Also applies to: 35-35, 79-79
📜 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 (2)
app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx(1 hunks)app/details/edit/[goal_id]/_components/GoalEdit/GoalEdit.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app/details/edit/[goal_id]/_components/EditBody/EditBody.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
app/details/edit/[goal_id]/_components/GoalEdit/GoalEdit.tsx (5)
api/hooks.ts (1)
useGoals(95-95)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)
🪛 Biome (1.9.4)
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)
⏰ 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/details/edit/[goal_id]/_components/GoalEdit/GoalEdit.tsx (3)
26-40: Good component setup with proper hook usage.The component properly initializes all necessary hooks and handles context nullability correctly.
42-45: Well-implemented duration display logic.The ternary logic correctly handles both duration types with proper null checking and uses the appropriate utility function for date formatting.
99-104: Great implementation of goal deletion API!The goal deletion functionality has been properly implemented with the actual API call, replacing the previous console.log placeholder. The async flow correctly handles API call, modal closing, data refresh, and navigation.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx (2)
30-34: Align setter prop casing with React conventions
setopenBottomSheetviolates camel-case expectations (setOpenBottomSheet). Keeping
naming consistent improves DX and avoids ESLint camelcase warnings.If renaming the prop on the component is feasible:
- setopenBottomSheet={setOpen} + setOpenBottomSheet={setOpen}…and update
argTypes/argsaccordingly.Also applies to: 50-58
41-53: Remove dead-controls foropenBottomSheet/ setterThe story wraps the component and overrides
openBottomSheet&setopenBottomSheet,
rendering the corresponding controls ineffective. Expose only the props the user can
actually tweak, or drop the wrapper and let controls drive the state.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
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/GoalData/GoalData.stories.tsx(1 hunks)components/details/ListCard/ListCard.stories.tsx(1 hunks)components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx(1 hunks)components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx(1 hunks)components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx(1 hunks)components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx(1 hunks)components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx(1 hunks)components/details/TabMenu/TabMenu.stories.tsx(1 hunks)
✅ Files skipped from review due to trivial changes (9)
- components/details/EditInfo/EditInfo.stories.tsx
- components/details/Modals/ModalUpdatingSubGoal/ModalUpdatingSubGoal.stories.tsx
- components/details/GoalData/GoalData.stories.tsx
- components/details/Modals/ModalExitingEdit/ModalExitingEdit.stories.tsx
- components/details/TabMenu/TabMenu.stories.tsx
- components/details/ListCard/ListCard.stories.tsx
- components/details/SubGoalEditItem/SubGoalEditItem.stories.tsx
- components/details/Modals/ModalIncompletingSubGoal/ModalIncompletingSubGoal.stories.tsx
- components/details/Modals/ModalDeletingGoal/ModalDeletingGoal.stories.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.tsx
🧰 Additional context used
🧠 Learnings (1)
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-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : The first example name of storybook should be Primary not Default
Learnt from: CR
PR: prography/10th-Motimo-FE#0
File: .cursor/rules/global-rule.mdc:0-0
Timestamp: 2025-07-04T14:17:02.454Z
Learning: Applies to components/**/*.stories.{js,jsx,ts,tsx} : If Component is created, add storybook files as well.
⏰ 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). (2)
- GitHub Check: build
- GitHub Check: chromatic-test
| const Wrapper = ({ args }: { args: typeof Primary.args }) => { | ||
| const [open, setOpen] = useState(true); | ||
| return ( | ||
| <GoalDurationBottomSheet | ||
| {...args} | ||
| openBottomSheet={open} | ||
| setopenBottomSheet={setOpen} | ||
| /> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
Fix forward-reference & simplify Wrapper props
Wrapper’s type annotation uses typeof Primary.args before Primary is declared, which
causes a TS “cannot find name ‘Primary’” error. Accept the story args directly instead of
nesting them:
-const Wrapper = ({ args }: { args: typeof Primary.args }) => {
+const Wrapper: React.FC<
+ Omit<React.ComponentProps<typeof GoalDurationBottomSheet>,
+ "openBottomSheet" | "setopenBottomSheet">
+> = (args) => {
const [open, setOpen] = useState(true);
return (
<GoalDurationBottomSheet
- {...args}
- openBottomSheet={open}
- setopenBottomSheet={setOpen}
+ {...args}
+ openBottomSheet={open}
+ setopenBottomSheet={setOpen}
/>
);
};📝 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 Wrapper = ({ args }: { args: typeof Primary.args }) => { | |
| const [open, setOpen] = useState(true); | |
| return ( | |
| <GoalDurationBottomSheet | |
| {...args} | |
| openBottomSheet={open} | |
| setopenBottomSheet={setOpen} | |
| /> | |
| ); | |
| }; | |
| const Wrapper: React.FC< | |
| Omit<React.ComponentProps<typeof GoalDurationBottomSheet>, | |
| "openBottomSheet" | "setopenBottomSheet"> | |
| > = (args) => { | |
| const [open, setOpen] = useState(true); | |
| return ( | |
| <GoalDurationBottomSheet | |
| {...args} | |
| openBottomSheet={open} | |
| setopenBottomSheet={setOpen} | |
| /> | |
| ); | |
| }; |
🤖 Prompt for AI Agents
In
components/details/BottomSheets/GoalDurationBottomSheet/GoalDurationBottomSheet.stories.tsx
around lines 27 to 36, the Wrapper component uses typeof Primary.args before
Primary is declared, causing a TypeScript error. Fix this by changing Wrapper to
accept the story args directly as its props without referencing Primary.args,
removing the forward reference and simplifying the props type.
이전에는 progress가 100%일 때 뜨도록 했었는데, 목표 완료시 progress가 0이 되는 이슈가 있기도 해서 더 확실한 것으로 수정했습니다.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (2)
48-54: Add error handling for goal completion API call.The API call lacks proper error handling which could leave the user in an inconsistent state if the request fails.
onCompleteGoal={async () => { - const res = await goalApi.goalComplete(goalId); - if (res) { - // 토스트 - closeModal(); - } + try { + const res = await goalApi.goalComplete(goalId); + if (res) { + // 토스트 + closeModal(); + mutateForGoalProgress(); + mutateForSubgoalCompleted(); + } + } catch (error) { + console.error('Failed to complete goal:', error); + // Show error toast or message + } }}
126-139: Fix sub-goal navigation bounds checking.The right navigation logic allows the index to go out of bounds. The condition should check against
length - 1.onLeft={() => setTargetSubGoalIdx((prev) => { - if (prev > 0) return prev - 1; - // 에러 방지 - return prev; + return Math.max(0, prev - 1); }) } onRight={() => setTargetSubGoalIdx((prev) => { - if (prev < (data.subGoals?.length ?? 0)) return prev + 1; - // 에러방지 - return prev; + const maxIndex = (data.subGoals?.length ?? 1) - 1; + return Math.min(maxIndex, prev + 1); }) }
🧹 Nitpick comments (3)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (3)
1-19: Clean up commented imports for better maintainability.Consider removing the commented-out import statements to keep the code clean and focused.
- // import useGoalWithSubGoalTodo from "@/hooks/main/queries/useGoalWithSubGoalTodo"; - // import { toggleGoalCompletion } from "@/lib/fetching/goalFetching"; - // import useGoalDetail from "@/hooks/main/queries/useGoalDetail";
72-94: Remove unnecessary React Fragment.The Fragment wrapper is unnecessary as it contains only one child element.
{allSubGoalCompleted && ( - <> <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> - </> )}
96-119: Remove unnecessary React Fragment.The Fragment wrapper is unnecessary as it contains only one child element.
{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> - </> )}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx(1 hunks)components/details/GoalData/GoalData.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- components/details/GoalData/GoalData.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
[error] 74-97: 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] 97-121: 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 Check: build
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
[failure] 68-68:
Type 'boolean | undefined' is not assignable to type 'boolean'.
🪛 GitHub Actions: CI Pipeline
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
[error] 68-68: TypeScript error TS2322: Type 'boolean | undefined' is not assignable to type 'boolean'.
⏰ 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
바텀시트에서 활성화 관련 불필요 부분 수정 추가.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (2)
61-67: Add error handling for goal completion API call.The API call still lacks proper error handling which could leave the user in an inconsistent state if the request fails.
Apply the previously suggested error handling pattern:
onCompleteGoal={async () => { + try { const res = await goalApi.goalComplete(goalId); if (res) { // 토스트 closeModal(); + // Refresh data after successful completion + mutateForGoalProgress(); + mutateForSubgoalCompleted(); } + } catch (error) { + console.error('Failed to complete goal:', error); + // Show error toast or message + } }}
147-153: Fix bounds checking for sub-goal navigation.The right navigation logic still allows the index to go out of bounds, as previously identified.
onRight={() => setTargetSubGoalIdx((prev) => { - if (prev < (data.subGoals?.length ?? 0)) return prev + 1; + if (prev < (data.subGoals?.length ?? 1) - 1) return prev + 1; // 에러방지 return prev; }) }
🧹 Nitpick comments (3)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (3)
85-108: Remove unnecessary fragments.Static analysis correctly identifies these fragments as unnecessary since they contain single elements.
{allSubGoalCompleted && ( - <> <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> - </> )}
109-133: Remove unnecessary fragment.Static analysis correctly identifies this fragment as unnecessary.
{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> - </> )}
186-211: Simplify boolean assignments.Static analysis correctly identifies unnecessary ternary operators that can be simplified.
onSubmitTodo={async (newTodoInfo) => { - 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; if (isFetchOk) { mutate(); } return isFetchOk; }}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx(1 hunks)app/details/edit/[goal_id]/page.tsx(1 hunks)components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx(3 hunks)
🧬 Code Graph Analysis (1)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (5)
api/hooks.ts (1)
useGoalDetail(96-96)hooks/queries/useSubGoalTodosInfiniites.ts (1)
useSubGoalTodosAllInfinite(186-186)utils/calcLeftDay.ts (1)
calcLeftDay(1-12)api/service.ts (3)
goalApi(45-45)subGoalApi(46-46)todoApi(44-44)utils/date2String.ts (1)
date2StringWithSpliter(7-7)
🪛 Biome (1.9.4)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
[error] 190-190: 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] 210-212: 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] 88-111: 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] 111-135: 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)
🚧 Files skipped from review as they are similar to previous changes (2)
- components/shared/BottomSheets/TodoBottomSheet/TodoBottomSheet.tsx
- app/details/edit/[goal_id]/page.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (5)
api/hooks.ts (1)
useGoalDetail(96-96)hooks/queries/useSubGoalTodosInfiniites.ts (1)
useSubGoalTodosAllInfinite(186-186)utils/calcLeftDay.ts (1)
calcLeftDay(1-12)api/service.ts (3)
goalApi(45-45)subGoalApi(46-46)todoApi(44-44)utils/date2String.ts (1)
date2StringWithSpliter(7-7)
🪛 Biome (1.9.4)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
[error] 190-190: 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] 210-212: 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] 88-111: 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] 111-135: 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)
⏰ 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/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (3)
1-29: LGTM: Clean imports and interface definition.The imports are well-organized and the interface definition is appropriately minimal.
31-55: LGTM: Proper data fetching and completion logic.The data fetching setup is comprehensive and the
allSubGoalCompletedlogic properly addresses the previous hardcoded issue by checking both completion status and ensuring there are actual sub-goals to complete.
169-214: LGTM: Comprehensive TodoBottomSheet integration.The TodoBottomSheet integration handles both creation and updating of todos with proper API calls and state management. The conditional rendering logic and data transformation are well-implemented.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (2)
147-152: Fix array bounds checking for sub-goal navigation.The right navigation logic still allows out-of-bounds array access. When
prevequalslength - 1, the condition allows incrementing tolength, which is invalid for array indexing.Apply this fix:
onRight={() => setTargetSubGoalIdx((prev) => { - if (prev < (data.subGoals?.length ?? 0)) return prev + 1; + const maxIndex = (data.subGoals?.length ?? 1) - 1; + return Math.min(maxIndex, prev + 1); // 에러방지 - return prev; }) }
61-67: Add proper error handling for API calls.Both the goal completion and todo submission lack error handling, which could leave users in inconsistent states.
Apply error handling for goal completion:
onCompleteGoal={async () => { + try { const res = await goalApi.goalComplete(goalId); if (res) { // 토스트 closeModal(); + mutateForGoalProgress(); + mutateForSubgoalCompleted(); } + } catch (error) { + console.error('Failed to complete goal:', error); + // Show error toast or message + } }}And for todo submission:
onSubmitTodo={async (newTodoInfo) => { + try { const isCreating = !newTodoInfo.id; let fetchRes; // ... API calls const isFetchOk = !!fetchRes; if (isFetchOk) { mutate(); } return isFetchOk; + } catch (error) { + console.error('Failed to submit todo:', error); + return false; + } }}Also applies to: 186-211
🧹 Nitpick comments (4)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (4)
187-187: Simplify unnecessary ternary expressions.The boolean assignments can be simplified for better readability.
Apply these fixes:
- const isCreating = newTodoInfo.id ? false : true; + const isCreating = !newTodoInfo.id;- const isFetchOk = fetchRes ? true : false; + const isFetchOk = !!fetchRes;Also applies to: 205-205
86-107: Remove unnecessary React fragments.The fragments are redundant as they only wrap single elements.
Apply these fixes:
{allSubGoalCompleted && !goalDetail?.isCompleted && ( - <> <button type="button" onClick={() => { openModalCompletingGoal(); }} // ... rest of button props > {/* button content */} </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 content */} </div> - </> )}Also applies to: 110-132
47-52: Consider simplifying the completion logic for better readability.While functionally correct, the completion logic could be more readable.
Consider this cleaner approach:
const allSubGoalCompleted = - data.subGoals?.filter((subgoalInfo) => subgoalInfo.isCompleted).length === - data.subGoals?.length && - // 0개 달성이면 안됨. - data.subGoals?.filter((subgoalInfo) => subgoalInfo.isCompleted).length !== - 0; + data.subGoals && + data.subGoals.length > 0 && + data.subGoals.every(subgoal => subgoal.isCompleted);
5-5: Clean up commented-out imports.Remove unused commented imports to keep the code clean.
-// import useGoalWithSubGoalTodo from "@/hooks/main/queries/useGoalWithSubGoalTodo"; -// import { toggleGoalCompletion } from "@/lib/fetching/goalFetching"; -// import useGoalDetail from "@/hooks/main/queries/useGoalDetail";Also applies to: 13-13, 15-15
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx(1 hunks)
🧬 Code Graph Analysis (1)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (5)
api/hooks.ts (1)
useGoalDetail(96-96)hooks/queries/useSubGoalTodosInfiniites.ts (1)
useSubGoalTodosAllInfinite(186-186)utils/calcLeftDay.ts (1)
calcLeftDay(1-12)api/service.ts (3)
goalApi(45-45)subGoalApi(46-46)todoApi(44-44)utils/date2String.ts (1)
date2StringWithSpliter(7-7)
🪛 Biome (1.9.4)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
[error] 190-190: 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] 210-212: 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] 88-111: 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] 111-135: 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)
🧰 Additional context used
🧬 Code Graph Analysis (1)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (5)
api/hooks.ts (1)
useGoalDetail(96-96)hooks/queries/useSubGoalTodosInfiniites.ts (1)
useSubGoalTodosAllInfinite(186-186)utils/calcLeftDay.ts (1)
calcLeftDay(1-12)api/service.ts (3)
goalApi(45-45)subGoalApi(46-46)todoApi(44-44)utils/date2String.ts (1)
date2StringWithSpliter(7-7)
🪛 Biome (1.9.4)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx
[error] 190-190: 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] 210-212: 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] 88-111: 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] 111-135: 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)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: chromatic-test
🔇 Additional comments (1)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (1)
31-217: Well-structured component with good separation of concerns.The component effectively manages goal details, sub-goal navigation, and todo operations with appropriate hook usage and state management.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (2)
61-67: Add error handling for goal completion API call.The API call lacks proper error handling which could leave the user in an inconsistent state if the request fails.
onCompleteGoal={async () => { + try { const res = await goalApi.goalComplete(goalId); if (res) { // 토스트 closeModal(); + // Refresh data after successful completion + mutateForGoalProgress(); + mutateForSubgoalCompleted(); } + } catch (error) { + console.error('Failed to complete goal:', error); + // Show error toast or message + } }}
148-153: Fix bounds checking for sub-goal navigation.The right navigation allows incrementing to an invalid index that's out of bounds for the array.
onRight={() => setTargetSubGoalIdx((prev) => { - if (prev < (data.subGoals?.length ?? 0)) return prev + 1; - // 에러방지 - return prev; + const maxIndex = (data.subGoals?.length ?? 1) - 1; + return Math.min(maxIndex, prev + 1); }) }
🧹 Nitpick comments (4)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (4)
86-109: Remove unnecessary Fragment wrapper.The Fragment is redundant as it only contains a single button element.
{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> - </> )}
110-134: Remove unnecessary Fragment wrapper.The Fragment is redundant as it only contains a single div element.
{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> - </> )}
188-188: Simplify boolean assignment.The ternary operator is unnecessary for this boolean assignment.
- const isCreating = newTodoInfo.id ? false : true; + const isCreating = !newTodoInfo.id;
206-206: Simplify boolean assignment.The ternary operator is unnecessary for this boolean assignment.
- const isFetchOk = fetchRes ? true : false; + const isFetchOk = Boolean(fetchRes);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx(1 hunks)components/details/GoalData/GoalData.stories.tsx(1 hunks)
🧬 Code Graph Analysis (1)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (5)
api/hooks.ts (1)
useGoalDetail(96-96)hooks/queries/useSubGoalTodosInfiniites.ts (1)
useSubGoalTodosAllInfinite(186-186)utils/calcLeftDay.ts (1)
calcLeftDay(1-12)api/service.ts (3)
goalApi(45-45)subGoalApi(46-46)todoApi(44-44)utils/date2String.ts (1)
date2StringWithSpliter(7-7)
🪛 Biome (1.9.4)
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)
🚧 Files skipped from review as they are similar to previous changes (1)
- components/details/GoalData/GoalData.stories.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (5)
api/hooks.ts (1)
useGoalDetail(96-96)hooks/queries/useSubGoalTodosInfiniites.ts (1)
useSubGoalTodosAllInfinite(186-186)utils/calcLeftDay.ts (1)
calcLeftDay(1-12)api/service.ts (3)
goalApi(45-45)subGoalApi(46-46)todoApi(44-44)utils/date2String.ts (1)
date2StringWithSpliter(7-7)
🪛 Biome (1.9.4)
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)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: chromatic-test
🔇 Additional comments (1)
app/details/[goal_id]/_components/DetailsBody/DetailBody.tsx (1)
47-52: LGTM! Proper completion logic implemented.The
allSubGoalCompletedcalculation correctly checks both that all sub-goals are completed and that there's at least one sub-goal present, preventing false positives when no sub-goals exist.
* feat: detail page 수정중 다른 브랜치 작업 위한 임시 커밋 * feat: netlify 배포 세팅 * feat: netlify 배포 세팅 초기화 기존 세팅은 정적 방식이었음. 동적 라우팅이 존재하기 때문에 이전 세팅으로는 빌드가 안 됨. * feat: 배포 404 에러 관련 수정 * feat: 메인페이지 bottom tab bar추가 및 bottom sheet와 함께 모바일 넓이에 맞게 조정 body자체를 scrollbar에 의해 layout shift발생하지 않게 수정하고, bottom sheet에도 적용했습니다. component/shared 패키지 버전 수정에 따른 lock파일 변경이 추가로 있습니다. bottom tabbar의 fixed로 인해 modal과의 z-index차이를 조정했습니다. 상단 AppBar관련해서 배너 상단에 공간을 만들어 ui겹침을 제거했습니다. * feat: 상세-편집 페이지GoalEdit 위치 변경 및 바텀시트와 모달 추가 * feat: 상세-편집 페이지 subGoalEdit 영역 추가 api및 디자인 세부 적용 안됨. * fix: TodoBottomSheet 버그 수정 엔터로 입력하면 높이 이상해지는 버그 수정했습니다. focus관련한 버그여서 blur처리로 수정했습니다. * fix: fetching 반환값 반환하도록 해서 이후 동작 연결되도록 수정 반환값을 보고 결과를 판단하도록 로직을 짰는데, 반환하지 않아서 제대로 작동하지 않았었습니당. * feat: dev서버 배포 전 프록시 및 msw수정 주소 동적 연결되게 수정 및 msw 주석처리. 이외 자잘한 오류 정리 * feat: api gen 최신화 * feat: fetching 함수들 디렉토리 위치 변경에 따른 수정 페이지에 따라 구분되지 않아서 디렉토리 구조 수정 * feat: 상세-편집 페이지 context를 사용한 상태관리와 api연결 * feat: useGoalWithSubGoalTodo반환 타입 변화에 따른 GoalCard수정 fetch관련 훅이 undefined도 반환할 수 있도록 하여, 이를 사용하는 쪽에서 핸들링 하도록 했습니다. * feat: shared의 AppBar수정 type button으로 해서 form에 submit안시키도록 함. event 인자를 받을 수 있도록 변경. shared빌드해서 처리함. * feat: 메인 페이지에서 detail 페이지로 이동 기능 추가 * feat: api 재생성 및 Edit_Pencil svg의 stroke 수정 외부에서 색 넣을 수 있도록 currentColor로 변경 * feat: ModalUpdatingSubGoal 생성 * feat: Edit페이지를 EditBody와 EditHeader 생성해 분리 fetch를 통한 서버 상태와 클라이언트 상태 분리 및 관리 용이하도록. * feat: 세부페이지-편집 EditBody와 EditHeader로 분리함으로 인한 수정 * feat: 모달 동작 및 세부목표 추가 동작 관련 수정 goalId넣어서 fetch동작하도록 함. ModalUpdatingSubGoal로 변경 및 초기 데이터 추가 * fix: 동작 관련 자잘한 수정 GoalEdit은 form에 영향 안 주도록 함. 나머지는 타입, 값, ui자잘한 수정 * feat: GoalDurationBottomSheet absolute로 중앙정렬 렌더링ㄹ 되도록 수정 * feat: 상세페이지 라우팅 적용 * feat: 빌드 에러 관련 컴포넌트 이름 수정 Body였던 컴포넌트 명을 변경(native element와 빌드 시 혼동 방지) * feat: 로그인 리다이렉션 주소 환경변수화 배포 환경에서 주소 바꿀 수 있도록 함. * feat: 메인페이지 수정사항 추가 - GoalMenuContainer 골메뉴 많을 때 가려지도록 overflow hidden추가 * Main page - 로그인 리다이렉션 주소 환경변수화 (prography#36) (prography#37) * feat: 로그인 리다이렉션 주소 환경변수화 배포 환경에서 주소 바꿀 수 있도록 함. * feat: fetching관련 불필요 제거, 타입 정리, 반환값 처리, 이름 변경. lib/fetching으로 사용하기로 했는데 머지 과정에서 lib/main이 남아버려서 제거함. * feat: ModalIncompletingSubGoal 생성 * feat: ListCard 동작 및 fetching 결과 제출 제외 연결 * feat: GoalData 그룹 있을 때 처리 수정 * feat: 목표 상세 컨텐츠 담는 DetailBody생성 * feat: api gen * feat: 목표 상세 ui구조 변경 및 목표 달성 모달 처리 그룹이동 및 목표완료처리 버튼 밖으로 꺼냄. 컴포넌트 책임상. * feat: useGoalWithSubGoalTodo 반환 타입 변경으로 인한 수정 undefined 옵셔널 처리에 따른 수정 * feat: GoalData 데이터 주입 완료. UI제외 완성 * feat: TodoResultBottomSheet 동작 완성 * feat: ListCard에 BottomSheet동작 연결 * feat: d-day계산 추출 및 적용 * feat: 목표 상세 api 훅 생성 추가로 fetching 함수 수정 * feat: GoalData 목표 완료 이모지 추가 및 기타 수정 useGoalDetail에서 goalId만 사용하도록 수정 modalIncompletingSubGoal에서 incompleting함수 실행하도록 수정 * feat: svg관련 icon으로 사용하지 않도록 next config수정 및 detail페이지에서 DetailBody사용 * feat: GoalDurationBottomSheet 오버레이 ui 수정 오버레이 배경색 안먹혔던 것을 수정 * feat: 한 컴포넌트에서 BottomSheet여러개 사용되는 경우 대비 수정. Drawer.Content의 위치 잡아주는 부모요소를 fixed를 통해 위치 고정 * feat: TodoResultBottomSheet 바텀 탭 바 존재할 때 케이스 처리 * feat: 메인 TodoList에서 투구 결과물 제출 관련 바텀시트와 연결 * feat: 상세 페이지에서 바텀 탭바 관련 처리 상세페이지는 필요 없으므로 이에 대해 처리. * feat: 목표 추가 페이지 제작 상세 목표 편집 페이지랑 유사한 부분이 많았는데, 해당 페이지에서 컴포넌트 분리하기 애매해서 걍 새로 만들었습니다. 추후 리팩토링 할 듯 합니다. * feat: 메인 페이지에서 목표 생성 페이지 연결 적용 * feat: formData를 post하는 경우 처리 추후 api처리한 PR머지되면 교체 예정 * feat: 목표 상세 페이지 디자인 적용 편집 및 목표 추가 페이지 제외. close_circle관련 설정 변경으로 인한 TextField에서의 수정(디자인 변화는 없음) * feat: 상세-편집 페이지 디자인 적용 * feat: 상세-목표 추가 페이지 디자인 적용 * feat: 메인 페이지 골 메뉴 좌우 드래그 처리 좌우 드래그를 통해 골 메뉴들을 확인할 수 있도록 수정했습니다. 휠 처리가 필요한지는 QA후에 결정될 것 같슴다 * feat: 세부목표 순서 변경 처리 * feat: 투구 result emotion처리 수정 백엔드에서 enum값이 바뀌어서 수정 * feat: todoItem에서의 처리 관련 mutate 및 세부 페이지로 이동 처리 * feat: api 훅 수정으로 인한 적용부 수정 타입 변환이 필요한 경우 기존 api 훅 래핑한 커스텀 훅으로 처리 * feat: api gen과 마이너 수정 * feat: subgoal에 대한 todo fetch api의 pagination 기반으로의 변경으로 인한 수정 api gen에서의 fetch반환 타입 정의에 버그가 있어 수동으로 fetch제작. 메인 페이지의 GoalCard, TodoList와 상세 페이지의 ListCard에서 새로 만든 훅을 적용. 또한, 기존에 사용하던 api의 반환 타입 변경으로 인해 연관된 영역에서 수정함. * feat: 세부 목표 완료 처리 * feat: 메인페이지 무한스크롤 적용 및 기존 무한스크롤 쿼리 훅 offset처리 수정 기존에는 size만큼 offset이 증가하지 않았어서 수정함. * feat: api gen 및 쓰지 않는 api관련 빌드 에러 수정 찌르기 api가 없어졌고 그룹 api로 통합된 것으로 보임. * feat: package lock 수정(npm 재설치) * feat: .env 파일 삭제 production에서 사용되는 듯 해서. * feat: 배포용 프록시 설정 추가 * feat: 배포 환경 api 프록시 수정 * feat: 상세페이지 목표 제거 api 연결 * feat: GoalDurationBottomSheet 디자인 적용 스타일 적용 안되어있었음 * feat: 상세 페이지 관련 컴포넌트 pr전 스토리북 생성 * feat: 상세 페이지 컴포넌트 스토리 경로 수정 * feat: 목표 완료 시 완료 이미지 뜨도록 수정 이전에는 progress가 100%일 때 뜨도록 했었는데, 목표 완료시 progress가 0이 되는 이슈가 있기도 해서 더 확실한 것으로 수정했습니다. * fix: 배너 y overflow 처리 추가 * feat: 상세 페이지 바텀 시트 추가 바텀시트에서 활성화 관련 불필요 부분 수정 추가. * fix: DetailBody에서 목표 완료 이후 목표 완료시키는 버튼 보이지 않도록 수정 * fix: DetailBody 목표 완료 이후에 목표완료모달 역시 뜨지 않도록 수정 * fix: 목표에서 isCompleted 추가 관련 빌드 에러 수정
* Main page 일단 모킹은 가능하도록 했습니다. (#26) * feat: TodoBottomSheet 완성 비동기 동작의 책임을 외부에 넘겼습니다. * feat: 데이터 페칭 이후 타입 변환의 책임을 비동기 훅으로 변경 비동기 훅은 도메인 별로 커스텀 가능한 것이기 때문에 변경했습니다. * feat: goal 관련 fetching함수 제작 * feat: TodoBottomSheet 동작 수정 초기값 바뀌는 동작 외부에서 key로 제어하지 않고, 내부에서 useEffect로 제어하도록 변경함. key로 제어하면 remount때문에 애니메이션 이상해서. * feat: todo, goal, subGoal에 대한 fethcing과 쿼리 훅 생성 데이터 처리를 쿼리 훅 내부에서 하도록 수정. mutate는 대부분 낙관적 업데이트로 사용하지 않기 때문에 변환 로직으로 덮어쓰지 않았음. * feat: TodoBottomSheet활성화, 선택된 goal관련 zustand store생성 이들 데이터는 멀리 떨어진 컴포넌트 사이에서 사용되기 때문에 전역 상태 사용함. * feat: msw모킹 위한 api 및 db 생성 * feat: 메인 페이지 goal관련 데이터 갖는 GoalCard 컴포넌트 생성 (진행중) * feat: 메인 페이지에 필요한 컴포넌트 생성 및 수정 MainHeader, GoalMenuContainer (임시) 문구 api연결은 아직 안했고, 컴포넌트 구분만 해뒀습니다. GoalMenuContainer는 선택에 대해 zustand로 전역 상태 처리하도록 수정했습니다. * feat: 메인 페이지 연결을 위한 자잘한 수정 fetchTemplate는 위치 변경으로 인한 수정. GoalMenu는 api연결에 필요한 타입 export TodoItem은 UI가 반응형으로 동작하도록 수정 * feat: TodoList 메인페이지 api연결을 위한 수정 쿼리 훅과 zustand 사용해 동작하도록 수정함. edit버튼 클릭에 대한 동작 추가함. UI반응형으로 동작하도록 w-full로 수정함. * fix: 바텀 시트 todo추가 동작 수정, 바텀시트 선택된 subgoal 버튼에 보이도록 수정 todo추가 동작 수정에 대해서, 기존 분기처리 잘못해 update를 실행하던 것을 create실행하도록 수정 * fix: TodoBottomSheet 상태 초기화 수정 initTodoInfo를 매번 object 새로 생성해 넘겨줘서 useEffect가 동작했음. 이에 컴폰너트 내부에서 분해해서 사용하도록 수정함. * feat: GoalCard 모달이 존재하면 바텀시트 닫도록 수정. 이렇지 않으면 dialog가 rule로 지정된 바텀시트에 focus-trap이 걸림. * feat: useModal 수정 바텀시트 사용할 때 모달의 사용을 알 수 있도록 isOpen을 추가함. * feat: TodoList에서 ModalAddingSubGoal 동작 관련 연결 subgoal을 추가할 수 있도록 api제작 및 연결 * fix: 자잘한 UI 에러 수정 * feat: 페칭 및 훅 자잘한 수정 use client추가 및 타입 수정 * feat: useTodoList undefined도 가능하도록 수정. 사용하는 입장에서 undefined반환 값으로 처리 분기할 수 있도록. * feat: cheer, point 관련 fetching 제작 goalFetching에서 불필요 부분 삭제 * feat: 모킹 구조 변경 및 points, cheer 핸들러 추가 관리하기 쉽도록 분리했습니다. * feat: 불필요 부분 삭제 콘솔 제거 및 element정리 * feat: fetch 동작에서 헤더 설정 수정 get요청에서도 authorization등 적용되도록 수정 * feat: 목표 추가 버튼 제작 모달 클릭 후 페이지 이동은 아직 구현하지 않았습니다. 해당 페이지 구현 마친 후 라우팅 추가하겠습니다. * feat: GoalCard와 useGoalWithSubGoalTodo대해 타입 및 props명 변경에 따른 수정 * feat: BottomTabBar Link추가로 페이지 이동할 수 있도록 함. * feat: main페이지에 BottomTabBar추가에 따른 UI수정 (이전 커밋에서 GoalCard에서 pb추가) TodoBottomSheet는 바텀탭바 존재에 따라 위치 변경 가능하도록 수정. 추가로, 여기서, 기본 subGoal 지정. * feat: main page에서 bottom tab bar관련 불필요 패딩 제거. * feat: 로컬 개발 시 msw사용하도록 수정 발표할 때 필요할 것 같아서. * Main page mock ui관련 수정 사항 반영 (#29) 발표할 때 필요할 것 같아서. * feat: 시연 전 ui 수정사항 반영 * Main page mock msw 동작하도록 수정 (#30) * feat: 임시 배포에서도 msw동작하도록 수정 * wip-1 * extract authStore * feat: fix SSR hydration mismatch using Next.js dynamic imports - Replace isClient workarounds with Next.js dynamic imports - Apply { ssr: false } to BottomTabBar and MyPage components - Remove unnecessary useClientOnly and useAuthState hooks - Clean up conditional rendering logic in components - Prevent 'Hydration failed' errors in console - Maintain clean code without workarounds * feat: implement groups page with reusable components - Create GroupEmptyState component for no groups state - Add PendingGroupCard component for individual group cards - Build PendingGroupList component for groups collection - Implement GroupPage main component with AppBar integration - Add comprehensive Storybook stories for all components - Create app/group route with BottomTabBar integration - Download and integrate group empty state image from Figma - Follow component composition pattern for reusability - Include proper TypeScript interfaces and props - Support responsive design with Tailwind CSS * feat: update group page text styles to match Figma design - Apply SUIT font family with 700 weight to section titles - Update font size from 24px (text-2xl) to 20px (text-xl) per Figma spec - Add line-height 1.2em and letter-spacing -1% for precise typography - Improve layout with proper padding (px-4, py-4) around sections - Update GroupPage stories to use GroupData type consistently - Add WithJoinedGroups story for testing joined groups state - Ensure text alignment matches design: left-aligned titles Figma reference: node-id=54330-13373 * remove unused * generate api * fix get access token * implement getJoinedGroups * refactor: Update fetchTemplate to use auth store instead of localStorage * generate api * feat: Add API service wrapper with automatic Bearer token authentication - Create service.ts as centralized API client wrapper - Integrate with useAuthStore for automatic token management - Export individual API groups for convenient usage - Automatically add Bearer token to all API requests via securityWorker * refactor: Implement dynamic API/SWR mapping with type safety - Replace manual hook creation with dynamic useApiQuery function - Add comprehensive type definitions for API client mapping - Implement automatic parameter and return type inference - Add useQuery convenience object for common patterns - Maintain backward compatibility with legacy hook exports - Enable future-proof API integration without manual mapping - Support conditional fetching and custom SWR keys * refactor: Improve API service SWR integration and debugging - Optimize SWR fetcher functions to remove unnecessary async/await - Add debugging capabilities for API response parsing issues - Test useMyProfile hook implementation in MyPage component - Investigate and address API response data handling problems - Update service.ts with better SWR integration patterns * refactor: Replace legacy SWR hooks with centralized service.ts hooks - Remove hooks/main/queries folder with custom SWR hooks - Replace useGoalList with useGoals from service.ts - Replace useGoalWithSubGoalTodo with useGoalWithSubGoals from service.ts - Replace useTodoList with useSubGoalTodos from service.ts - Migrate data conversion logic inline to components - Maintain backward compatibility with existing component interfaces - Consolidate all API calls through centralized service layer - Remove duplicate SWR logic and improve maintainability * refactor: Restructure API service architecture - Move service.ts to api/service.ts for better organization - Separate SWR hooks into api/hooks.ts for modular architecture - Split core API client from SWR functionality - Update all import paths from @/service to @/api/hooks - Maintain clean separation of concerns: - api/service.ts: Core API client and types - api/hooks.ts: SWR-based React hooks - All components updated with new import paths - Build successful with no compilation errors * refactor: Extract useApiQuery into separate module - Create dedicated api/useApiQuery.ts for dynamic API query hook - Remove useApiQuery implementation from api/hooks.ts - Import and re-export useApiQuery from the new module - Maintain full backward compatibility with existing imports - Improve code organization with single responsibility principle - Clean separation between core hook logic and convenience wrappers - Build successful with no compilation errors * feat: Integrate environment variable for API baseUrl - Update api/service.ts to use SWAGGER_URL from .env file - Extract base server URL from SWAGGER_URL automatically - Add getBaseUrl() helper function with URL parsing logic - Maintain fallback to empty string for proxy scenarios - Fix import in MyPage.tsx to use separate useApiQuery module - Environment-driven configuration for better deployment flexibility - Build successful with no compilation errors * add env * fix: Use NEXT_PUBLIC_ prefix for client-side environment variables - Add NEXT_PUBLIC_API_URL to .env file with proper API base URL - Update api/service.ts to use NEXT_PUBLIC_API_URL instead of API_URL - Remove debugging console.log statement - Fix Next.js client-side environment variable access - Ensure proper API URL resolution in production builds - Build successful with correct environment variable usage * feat: Separate environment configurations for dev and local - Add dotenv-cli dependency for explicit env file control - Update package.json scripts: - 'npm run dev': uses .env file - 'npm run local': uses .env.local file (new) - Create .env.local with local development overrides - Add comments to distinguish .env and .env.local usage - Add .env.local to .gitignore for local-only settings - Support different API endpoints for dev vs local environments - Build successful with proper environment variable loading * feat: Configure local API server for npm run local - Add USE_LOCAL_API environment variable to control API destination - Update next.config.ts to dynamically choose between local and remote API - Configure .env for remote API (motimo.kro.kr:8080) in dev mode - Configure .env.local for local API (localhost:8080) in local mode - Set NEXT_PUBLIC_API_URL to empty string in local mode to use Next.js proxy - Enable seamless switching between local and remote API environments - Build successful with conditional proxy configuration * refactor: Complete environment file separation for dev and local - Rename .env to .env.dev for team development settings - Update package.json dev script to use .env.dev explicitly - Add .env.local to .gitignore for local-only settings - Complete isolation: no cross-contamination between environments - Dev mode: only .env.dev loaded (remote API) - Local mode: only .env.local loaded (localhost API) - Build successful with proper environment separation - Teams can share .env.dev while keeping .env.local private * refactor: Replace all templateFetch usage with SWR hooks and direct API calls - Replace templateFetch-based functions with api/hooks.ts SWR hooks for GET requests: - getCheerComment → useCheerPhrase in MainHeader - getPoints → usePoints in MainHeader - Replace templateFetch-based functions with direct API calls for mutations: - deleteTodo → todoApi.deleteById in TodoList - toggleTodo → todoApi.toggleTodoCompletion in TodoList - createNewSubGoalOnGoal → goalApi.addSubGoal in TodoList - createNewTodoOnSubGoal → subGoalApi.createTodo in GoalCard - updateTodo → todoApi.updateTodo in GoalCard - Remove unused createNewGoal import from GoalMenuContainer - Add proper date string conversion for API calls - Eliminate dependency on lib/main/ templateFetch functions - Centralize all API calls through api/service.ts - Build successful with 0 compilation errors * remove: delete legacy templateFetch files - Delete lib/common/fetchTemplate.ts - Delete all lib/main/*Fetching.ts files - All functionality replaced by new API service architecture * chore: remove unused * remove .env.local from gitignore * tidy up * refactor: simplify auth store initialization - Remove redundant getInitialState function - Let persist middleware handle initial state loading automatically - Remove manual localStorage reading to prevent conflicts - Remove skipHydration flag as it's no longer needed - Improve consistency and prevent potential hydration mismatches * feat: improve authentication handling and fix hydration issues - Add NEXT_PUBLIC_FRONTEND_BASE_URL to environment configs - Refactor app/page.tsx to use AuthGuard component for cleaner auth logic - Add immediate client-side hydration to useAuthStore - Create AuthGuard component with dynamic import to avoid SSR issues - Remove complex authentication logic from main page component * refactor: update group page to use new API hooks and types - Replace old useGroupsMe hook with useJoinedGroups from @/api/hooks - Update GroupPage component to use new API types (GoalNotInGroupRs, JoinedGroupRs) - Remove unused imports and dependencies (useAuthStore, useState) - Clean up old hook files and fetching utilities - Simplify group page logic with new API integration * refactor: implement generic-based GroupList with type guards - Convert GroupList to use generics with JoinedGroupRs | GoalNotInGroupRs constraint - Add type guard function isJoinedGroupRs for runtime type checking - Implement conditional rendering based on group type - Update GroupList.stories.tsx to use actual API types instead of mock GroupData - Remove unused GroupData interface and BaseGroupData interface - Add proper type-specific property handling: - JoinedGroupRs: uses lastActiveDate and isNotificationActive - GoalNotInGroupRs: uses undefined for lastActivityDate and false for hasNotification - Fix missing useRouter import - Improve type safety and maintainability * feat: add goal ID routing and error handling for GroupList - Add goal ID as query parameter when navigating to join-random page - Implement error handling for missing goal IDs: - Log error to console with group title for debugging - Show user-friendly alert message - Prevent navigation when goal ID is missing - Improve user experience with proper error feedback * feat: implement join random group page based on Figma design - Create /group/join-random page with Figma design implementation - Add thumbs up illustration with proper positioning and colors - Implement goal information card showing selected goal and period - Add API integration: - useGoalDetail hook to fetch goal information - joinRandomGroup API call for actual group joining - Proper error handling and loading states - Add URL parameter support for goalId from GroupList navigation - Implement user experience features: - Auto-redirect if goalId is missing - Loading states with disabled button - Success/error alert messages - Automatic navigation to group page on success - Add period calculation from goal due date - Create storybook file for development and testing - Follow design tokens and component patterns from existing codebase * add text-center, remove mt-auto * add justify-center * feat: add group detail page and improve group join flow - Add group/[id] page with Figma design implementation - Add SystemMessage component for group notifications - Add UsersGroupIcon for group header - Update group join flow to redirect to specific group page - Add Storybook files for new components - Refactor component exports for consistency Resolves group detail page requirements from Figma design * fix: escape quotes in group detail page title - Fix react/no-unescaped-entities lint error - Use " HTML entities for quotes in JSX * fix: resolve type errors and template literal updates - Fix Next.js 15 params Promise type issue using React.use() - Remove non-existent GroupData type references - Update storybook mock data to match actual API types - Fix JoinedGroupRs and GoalNotInGroupRs type usage - Update quote handling to use template literals All TypeScript compilation errors resolved * fix: wrap useSearchParams in Suspense boundary to fix build error - Extract main component logic into JoinRandomGroupContent - Add LoadingPage component for suspense fallback - Wrap component in Suspense to prevent prerendering error - Resolves Next.js build error about missing suspense boundary * feat: Update environment configuration and build scripts - Rename .env.local to .env.localhost for clarity - Update package.json local script to use .env.localhost - Add NODE_ENV=production to build script - Add .env.production configuration file * fix: Add Next.js router mocking to Storybook - Add React import to .storybook/preview.tsx - Configure nextConfigPath in .storybook/main.ts for proper Next.js integration - Add mockRouterFunctions with console logging for debugging - Configure nextRouter parameter with all required router properties - Resolves 'invariant expected app router to be mounted' error in stories * feat: Complete Next.js router mocking solution for Storybook - Create dedicated nextjs-mock.ts file with proper Next.js navigation exports - Add webpack alias in main.ts to redirect next/navigation imports to mock - Clean up preview.tsx configuration by removing complex decorators - Export all Next.js navigation functions (useRouter, useSearchParams, etc.) - Provides console logging for debugging navigation interactions - Resolves App Router compatibility issues in Storybook stories * feat: Add onboarding completion check and redirect - Add hasCompletedOnboarding check from useAuthStore in onboarding page - Redirect users to home page if they have already completed onboarding - Prevents users from accessing onboarding flow after completion * feat: Implement useOnboardingStore for centralized data management - Create useOnboardingStore with zustand for onboarding form data - Refactor GoalInputScreen to use store instead of props - Refactor PeriodSelectionScreen to use store and call goalApi.createGoal with real data - Refactor CompletionScreen to use store for display data - Simplify onboarding page by removing local state management - Replace hardcoded test data with actual user input in goal creation - Centralize all onboarding data management in dedicated store * Add OAuth state and onboarding completion tracking to auth store * Refactor auth store hydration to use useEffect hook * Fix due date calculation logic for month-based periods * Add error handling for goal creation API call in onboarding * create random group * revert useEffect * wip1 * update api * feat: Update API hooks and fix TypeScript errors - Update hooks.ts to match latest API specification - Fix groupChat hook parameters (page/size -> limit/cursor/direction) - Add missing API hooks (groupDetail, newGroupMessages, notifications) - Fix getJoinedGroup -> getJoinedGroups method name - Update GroupDetailPage to use correct API parameters - Add GetGroupChatParamsDirectionEnum import - Fix data structure access (messages.content -> groupChat.messages) - Resolve all TypeScript compilation errors * feat(group): integrate API data for group details and user profile - Add useGroupDetail hook to fetch dynamic group name - Add useMyProfile hook to get user nickname - Replace hardcoded title with dynamic group name from API - Update system message to use actual user nickname instead of placeholder * refactor(group): improve navigation functionality and clean up components - Remove unused onJoinGroup prop from GroupPage and GroupList - Rename onJoinClick to onClick in GroupItem for consistency - Add actual navigation functionality to group items: * Joined groups navigate to /group/{groupId} * Pending groups navigate to /group/join-random?goalId={id} - Add hover cursor pointer styling to joined group items - Simplify pending group click handler by removing unnecessary error handling - Fix code formatting and indentation * remove unused * refactor(GoalCard): simplify boolean conversion Replace redundant ternary operator with double negation for cleaner code: - reported: todoInfo.todoResultId ? true : false → reported: git diff --cachedtodoInfo.todoResultId * feat(api): enhance error handling and add runtime validation in useApiQuery - Add validation check for API group existence before method access - Wrap method invocation in try-catch for better error reporting - Provide more descriptive error messages with context about which API group and method failed - Improve debugging experience with detailed error information * remove env.local * generate api * sync healthApi * feat: update API service and hooks to match latest generated API - Add healthController API export to service - Fix method names: getGoalWithSubGoalAndTodo → getGoalWithSubGoalAndTodos - Fix method names: getIncompleteOrTodayTodos → getIncompleteOrTodayTodosWithSlice - Add pagination support for sub-goal todos hooks - Add new hooks: completedGoals, health, allSubGoalTodos - Maintain backward compatibility with legacy hook exports - Update all API endpoints to match generated API structure * generate api * fix: update notification hook to use page parameter instead of offset - Change notifications hook to use page (default 0) and size parameters - Align with API specification that expects page/size instead of offset/limit * feat: format lastActivityDate in GroupItem and fix navigation - Add date formatting function to display dates in YYYY.MM.DD format - Change group detail back navigation to use router.push("/group") * Onboarding 중복 클릭 방지 가드 추가 (#43) * use .env.dev for gen * feat: 중복 클릭 방지 가드 추가 - 다음 버튼 API 호출 시 중복 클릭 방지 - 기간 선택 버튼들 중복 클릭 방지 - 달력 날짜 선택 중복 클릭 방지 - 달력 월 네비게이션 중복 클릭 방지 (200ms 딜레이) - 제출 중 로딩 상태 표시 ("처리 중...") - 에러 발생 시 상태 복구로 재시도 가능 * Detail page 및 메인 페이지 ui일부 수정 (#40) * feat: detail page 수정중 다른 브랜치 작업 위한 임시 커밋 * feat: netlify 배포 세팅 * feat: netlify 배포 세팅 초기화 기존 세팅은 정적 방식이었음. 동적 라우팅이 존재하기 때문에 이전 세팅으로는 빌드가 안 됨. * feat: 배포 404 에러 관련 수정 * feat: 메인페이지 bottom tab bar추가 및 bottom sheet와 함께 모바일 넓이에 맞게 조정 body자체를 scrollbar에 의해 layout shift발생하지 않게 수정하고, bottom sheet에도 적용했습니다. component/shared 패키지 버전 수정에 따른 lock파일 변경이 추가로 있습니다. bottom tabbar의 fixed로 인해 modal과의 z-index차이를 조정했습니다. 상단 AppBar관련해서 배너 상단에 공간을 만들어 ui겹침을 제거했습니다. * feat: 상세-편집 페이지GoalEdit 위치 변경 및 바텀시트와 모달 추가 * feat: 상세-편집 페이지 subGoalEdit 영역 추가 api및 디자인 세부 적용 안됨. * fix: TodoBottomSheet 버그 수정 엔터로 입력하면 높이 이상해지는 버그 수정했습니다. focus관련한 버그여서 blur처리로 수정했습니다. * fix: fetching 반환값 반환하도록 해서 이후 동작 연결되도록 수정 반환값을 보고 결과를 판단하도록 로직을 짰는데, 반환하지 않아서 제대로 작동하지 않았었습니당. * feat: dev서버 배포 전 프록시 및 msw수정 주소 동적 연결되게 수정 및 msw 주석처리. 이외 자잘한 오류 정리 * feat: api gen 최신화 * feat: fetching 함수들 디렉토리 위치 변경에 따른 수정 페이지에 따라 구분되지 않아서 디렉토리 구조 수정 * feat: 상세-편집 페이지 context를 사용한 상태관리와 api연결 * feat: useGoalWithSubGoalTodo반환 타입 변화에 따른 GoalCard수정 fetch관련 훅이 undefined도 반환할 수 있도록 하여, 이를 사용하는 쪽에서 핸들링 하도록 했습니다. * feat: shared의 AppBar수정 type button으로 해서 form에 submit안시키도록 함. event 인자를 받을 수 있도록 변경. shared빌드해서 처리함. * feat: 메인 페이지에서 detail 페이지로 이동 기능 추가 * feat: api 재생성 및 Edit_Pencil svg의 stroke 수정 외부에서 색 넣을 수 있도록 currentColor로 변경 * feat: ModalUpdatingSubGoal 생성 * feat: Edit페이지를 EditBody와 EditHeader 생성해 분리 fetch를 통한 서버 상태와 클라이언트 상태 분리 및 관리 용이하도록. * feat: 세부페이지-편집 EditBody와 EditHeader로 분리함으로 인한 수정 * feat: 모달 동작 및 세부목표 추가 동작 관련 수정 goalId넣어서 fetch동작하도록 함. ModalUpdatingSubGoal로 변경 및 초기 데이터 추가 * fix: 동작 관련 자잘한 수정 GoalEdit은 form에 영향 안 주도록 함. 나머지는 타입, 값, ui자잘한 수정 * feat: GoalDurationBottomSheet absolute로 중앙정렬 렌더링ㄹ 되도록 수정 * feat: 상세페이지 라우팅 적용 * feat: 빌드 에러 관련 컴포넌트 이름 수정 Body였던 컴포넌트 명을 변경(native element와 빌드 시 혼동 방지) * feat: 로그인 리다이렉션 주소 환경변수화 배포 환경에서 주소 바꿀 수 있도록 함. * feat: 메인페이지 수정사항 추가 - GoalMenuContainer 골메뉴 많을 때 가려지도록 overflow hidden추가 * Main page - 로그인 리다이렉션 주소 환경변수화 (#36) (#37) * feat: 로그인 리다이렉션 주소 환경변수화 배포 환경에서 주소 바꿀 수 있도록 함. * feat: fetching관련 불필요 제거, 타입 정리, 반환값 처리, 이름 변경. lib/fetching으로 사용하기로 했는데 머지 과정에서 lib/main이 남아버려서 제거함. * feat: ModalIncompletingSubGoal 생성 * feat: ListCard 동작 및 fetching 결과 제출 제외 연결 * feat: GoalData 그룹 있을 때 처리 수정 * feat: 목표 상세 컨텐츠 담는 DetailBody생성 * feat: api gen * feat: 목표 상세 ui구조 변경 및 목표 달성 모달 처리 그룹이동 및 목표완료처리 버튼 밖으로 꺼냄. 컴포넌트 책임상. * feat: useGoalWithSubGoalTodo 반환 타입 변경으로 인한 수정 undefined 옵셔널 처리에 따른 수정 * feat: GoalData 데이터 주입 완료. UI제외 완성 * feat: TodoResultBottomSheet 동작 완성 * feat: ListCard에 BottomSheet동작 연결 * feat: d-day계산 추출 및 적용 * feat: 목표 상세 api 훅 생성 추가로 fetching 함수 수정 * feat: GoalData 목표 완료 이모지 추가 및 기타 수정 useGoalDetail에서 goalId만 사용하도록 수정 modalIncompletingSubGoal에서 incompleting함수 실행하도록 수정 * feat: svg관련 icon으로 사용하지 않도록 next config수정 및 detail페이지에서 DetailBody사용 * feat: GoalDurationBottomSheet 오버레이 ui 수정 오버레이 배경색 안먹혔던 것을 수정 * feat: 한 컴포넌트에서 BottomSheet여러개 사용되는 경우 대비 수정. Drawer.Content의 위치 잡아주는 부모요소를 fixed를 통해 위치 고정 * feat: TodoResultBottomSheet 바텀 탭 바 존재할 때 케이스 처리 * feat: 메인 TodoList에서 투구 결과물 제출 관련 바텀시트와 연결 * feat: 상세 페이지에서 바텀 탭바 관련 처리 상세페이지는 필요 없으므로 이에 대해 처리. * feat: 목표 추가 페이지 제작 상세 목표 편집 페이지랑 유사한 부분이 많았는데, 해당 페이지에서 컴포넌트 분리하기 애매해서 걍 새로 만들었습니다. 추후 리팩토링 할 듯 합니다. * feat: 메인 페이지에서 목표 생성 페이지 연결 적용 * feat: formData를 post하는 경우 처리 추후 api처리한 PR머지되면 교체 예정 * feat: 목표 상세 페이지 디자인 적용 편집 및 목표 추가 페이지 제외. close_circle관련 설정 변경으로 인한 TextField에서의 수정(디자인 변화는 없음) * feat: 상세-편집 페이지 디자인 적용 * feat: 상세-목표 추가 페이지 디자인 적용 * feat: 메인 페이지 골 메뉴 좌우 드래그 처리 좌우 드래그를 통해 골 메뉴들을 확인할 수 있도록 수정했습니다. 휠 처리가 필요한지는 QA후에 결정될 것 같슴다 * feat: 세부목표 순서 변경 처리 * feat: 투구 result emotion처리 수정 백엔드에서 enum값이 바뀌어서 수정 * feat: todoItem에서의 처리 관련 mutate 및 세부 페이지로 이동 처리 * feat: api 훅 수정으로 인한 적용부 수정 타입 변환이 필요한 경우 기존 api 훅 래핑한 커스텀 훅으로 처리 * feat: api gen과 마이너 수정 * feat: subgoal에 대한 todo fetch api의 pagination 기반으로의 변경으로 인한 수정 api gen에서의 fetch반환 타입 정의에 버그가 있어 수동으로 fetch제작. 메인 페이지의 GoalCard, TodoList와 상세 페이지의 ListCard에서 새로 만든 훅을 적용. 또한, 기존에 사용하던 api의 반환 타입 변경으로 인해 연관된 영역에서 수정함. * feat: 세부 목표 완료 처리 * feat: 메인페이지 무한스크롤 적용 및 기존 무한스크롤 쿼리 훅 offset처리 수정 기존에는 size만큼 offset이 증가하지 않았어서 수정함. * feat: api gen 및 쓰지 않는 api관련 빌드 에러 수정 찌르기 api가 없어졌고 그룹 api로 통합된 것으로 보임. * feat: package lock 수정(npm 재설치) * feat: .env 파일 삭제 production에서 사용되는 듯 해서. * feat: 배포용 프록시 설정 추가 * feat: 배포 환경 api 프록시 수정 * feat: 상세페이지 목표 제거 api 연결 * feat: GoalDurationBottomSheet 디자인 적용 스타일 적용 안되어있었음 * feat: 상세 페이지 관련 컴포넌트 pr전 스토리북 생성 * feat: 상세 페이지 컴포넌트 스토리 경로 수정 * feat: 목표 완료 시 완료 이미지 뜨도록 수정 이전에는 progress가 100%일 때 뜨도록 했었는데, 목표 완료시 progress가 0이 되는 이슈가 있기도 해서 더 확실한 것으로 수정했습니다. * fix: 배너 y overflow 처리 추가 * feat: 상세 페이지 바텀 시트 추가 바텀시트에서 활성화 관련 불필요 부분 수정 추가. * fix: DetailBody에서 목표 완료 이후 목표 완료시키는 버튼 보이지 않도록 수정 * fix: DetailBody 목표 완료 이후에 목표완료모달 역시 뜨지 않도록 수정 * fix: 목표에서 isCompleted 추가 관련 빌드 에러 수정 * fix: resolve TypeScript build errors in group components - Fix type mismatch in join-random page by accessing goalDetail.dueDate.dueDate - Update GroupChat stories to use correct GroupMessageContentRs structure - Fix GroupChat component to access message properties correctly - Remove invalid onJoinGroup prop from GroupPage stories * improve: enhance error message construction in useApiQuery for better debugging - Extract proper error message from Error objects instead of converting entire error to string - Maintain fallback for non-Error objects using String() conversion - Improves readability of error messages when API calls fail * feat: add new message notifications to group items - Add hasNewMessages prop to BellIcon component - Show notification dot when either hasNotification or hasNewMessages is true - Integrate useNewGroupMessages hook in GroupItem to fetch new message status - Pass groupId prop to GroupItem and GroupList for message checking - Update GroupList to handle different group types with appropriate IDs * remove: delete .env.production file * fix: simplify default goal title in join random group page * remove: replace all alert() calls with console statements * feat: add Loading component with Lottie animation - Install lottie-react dependency - Add Lottie animation file from LottieFiles - Create reusable Loading component with size variants - Add Storybook stories for different use cases - Export component from shared components index * fix: update Loading component with proper asset loading and styling - Use fetch API to dynamically load Lottie animation JSON - Add fallback CSS spinner while animation loads - Update text styling to match design specs (16px, label-normal color) - Increase size variants for better visibility - Add Loading component usage in join random group page * refactor: use local import for Lottie animation instead of fetch - Move animation JSON file to component directory - Replace async fetch with direct import for better performance - Remove useState, useEffect, and fallback spinner logic - Simplify component code and improve load time * feat: add navigation to member page from group detail * feat: implement group member page with member list and leave group functionality * feat: add date formatting utility and implement poke functionality - Create reusable formatDate utility in lib/date.ts - Replace hardcoded date with dynamic lastOnlineDate formatting - Implement poke notification API call in member page - Refactor GroupItem to use shared date utility * feat: add toast notification for poke functionality * feat: implement leave group functionality with confirmation and navigation * refactor: replace browser confirm with custom Modal for leave group confirmation * feat: implement notification page with AppBar navigation and Figma design * refactor: improve BellIcon prop naming for better clarity * refactor: improve notification page ternary logic - Always render notification count header instead of duplicating - Use conditional rendering for "모두 읽음" button based on notification count - Simplify empty state by removing redundant count display - Remove unnecessary fragment wrapper in notification list * feat: update NotificationIcon component with proper bell icon design Replace eye icon with correct bell notification icon matching Figma specifications * feat: implement infinite scroll for notification page Add automatic loading of next page when user scrolls near bottom with loading indicator * feat: add mock data for testing infinite scroll in notifications Add mock notification generator with 156 items and debug toggle to test infinite scroll functionality * refactor: extract NotificationContent component and move mock data to Storybook - Extract reusable NotificationContent component from notification page - Clean up notification page to use only real API data - Add comprehensive Storybook stories for testing infinite scroll with mock data - Improve component separation and testability * fix: resolve TypeScript errors in AppBar and notification components - Remove invalid hasNotification and onNotificationClick props from AppBar usage - Import and use NotificationItemRsTypeEnum for proper type safety in stories - Change null to undefined for CustomPageNotificationItemRs compatibility - Update AppBar stories to remove non-existent prop controls * fix: improve loading UI for join random group page - Replace ineffective Suspense with proper Loading component display - Show Loading component during goal data fetch and group joining - Remove unused Suspense wrapper and import - Replace button loading text with full-screen Loading component * fix: add input validation and error handling to formatDate function - Add validation for falsy and non-string inputs - Add invalid date detection using isNaN check - Return consistent '--.--.--' fallback for invalid inputs - Add explicit string return type annotation - Prevent "NaN.NN.NN" display in UI for malformed dates * refactor: improve type safety and simplify notification content parsing - Change Notification type property to use strict typing with keyof typeof NOTIFICATION_TYPE_MESSAGES - Remove fragile regex parsing for nickname extraction - Consolidate similar notification types into single case handling - Simplify content rendering to directly use notification content - Reduce code complexity and potential parsing errors * fix: improve timeout handling and error management in group member page - Add useRef to track timeout IDs and prevent memory leaks - Add useEffect cleanup to clear timeouts on component unmount - Standardize toast timeout duration to 2000ms for consistency - Apply proper timeout management to all toast scenarios - Prevent hanging timeouts after component cleanup * fix: resolve TypeScript error in useRef timeout declaration - Add null initial value to useRef<NodeJS.Timeout | null>(null) - Fix missing required argument error in TypeScript compilation - Maintain type safety for timeout reference handling * fix: wrap useSearchParams in Suspense boundary for join-random page - Add Suspense import back to React imports - Wrap JoinRandomGroupContent component that uses useSearchParams() - Add appropriate Loading fallback for page loading state - Resolve Next.js warning about missing Suspense boundary * feat: add Primary story to NotificationContent Storybook - Add Primary story as default example following coding guidelines - Use 25 notifications for moderate, typical usage demonstration - Include proper documentation with story description - Position Primary story before other variants as main example * fix: improve error handling for poke functionality - Add toast notification for poke send failures - Use consistent timeout reference management for error case - Provide user feedback for failed poke attempts instead of silent failures - Maintain consistent 2000ms timeout duration across all scenarios * feat: extract GroupMemberList component and add 7-day poke button logic - Extract member list functionality from page into reusable GroupMemberList component - Add conditional poke button visibility based on 7-day inactivity threshold - Create comprehensive Storybook stories for different member activity scenarios - Update Storybook config to include app directory stories for better component testing * refactor: replace custom spinners with shared Loading component in onboarding - Replace two separate custom spinner divs with consistent Loading component - Merge duplicate loading conditions into single conditional statement - Improve code maintainability and UI consistency * fix: prevent infinite loading when entering onboarding without login - Split merged loading condition into separate hydration and login checks - Ensure non-logged-in users see LoginScreen instead of infinite loading - Improve loading state logic clarity and maintainability --------- Co-authored-by: SangHyeon Lee <67571350+Hys-Lee@users.noreply.github.com>
상세 페이지
(스토리북 작성 전에 다 만들어버리고, 후에 pr용으로 스토리북 작성했어서, 컴포넌트 스토리는 빈약합니다)
메인 페이지
Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Documentation
Chores