Conversation
- 피그마 디자인 시스템 명칭에 맞게 컴포넌트를 리네이밍 - Profile 컴포넌트에 피그마 기준 size variant(S/m/L)를 추가 - Profile이 ProfileImage를 내부적으로 재사용하도록 통합
📝 관련 이슈 |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthrough이 PR은 정산 참여(Join) 플로우와 관련 API/로더/MSW 핸들러를 추가하고, 기존 MemberProfile/MemberProfileImage를 Profile/ProfileImage로 교체하며 라우트와 스토리북을 갱신합니다. Changes
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/features/user-profile/ui/MyProfile/index.tsx (1)
18-28:⚠️ Potential issue | 🟡 MinorOptional chaining 사용이 일관되지 않아 런타임 오류 가능성이 있습니다.
Line 18에서
profile?.profileImageUrl은 optional chaining을 사용하지만, Line 20의profile.name과 Line 27의profile.email은 사용하지 않습니다.profile이undefined일 경우 컴포넌트가 크래시될 수 있습니다.🛡️ 일관된 null 체크 적용 제안
return ( <S.ProfileContainer> <ProfileImage size="36" src={profile?.profileImageUrl} /> <Flex direction="column" flex={1} gap={4}> - <Text variant="body1Sb">{profile.name}</Text> + <Text variant="body1Sb">{profile?.name}</Text> {/* TODO: 디자인 시스템 정비 후 다시 디자인 확인이 필요합니다 (Opacity를 계속 쓰는지?) */} <Text variant="body2R" color="semantic.text.default" style={{ opacity: 0.5 }} > - {profile.email} + {profile?.email} </Text> </Flex>또는 컴포넌트 상단에서 early return 처리:
if (!profile) return null;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/user-profile/ui/MyProfile/index.tsx` around lines 18 - 28, The JSX uses profile?.profileImageUrl but accesses profile.name and profile.email without null checks; update the MyProfile component to consistently guard against undefined profile—either add optional chaining (e.g., profile?.name and profile?.email) where used (ProfileImage, Text elements) or perform an early return at the top of the MyProfile render (e.g., if (!profile) return null) so that ProfileImage, the Text for name, and the Text for email cannot read properties from undefined.
🧹 Nitpick comments (7)
src/entities/group/api/group.ts (1)
47-49: 개발 환경에서 mock 요청이 동작하지 않을 수 있습니다.다른 API 함수들(
getGroupList,assignMember,getUserInfo등)은useMock: true옵션을 사용하는데,getGroupHeader에는 누락되어 있습니다. mock 핸들러(/api/v1/groups/:settlementCode/header)가 존재하므로 개발 환경에서의 일관성을 위해 추가를 검토해 주세요.♻️ useMock 옵션 추가 제안
export const getGroupHeader = ( settlementCode: string ): Promise<GroupHeaderResponse> => { return axiosInstance - .get(`/groups/${settlementCode}/header`) + .get(`/groups/${settlementCode}/header`, { useMock: true }) .then((res) => res.data); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/entities/group/api/group.ts` around lines 47 - 49, getGroupHeader is missing the useMock option so dev mock handler (/api/v1/groups/:settlementCode/header) won't be used; update the axios call in getGroupHeader to include the same useMock: true option used by getGroupList, assignMember, and getUserInfo so the request routes to the mock handler in development and maintains consistency with other API functions.src/shared/ui/ProfileImage/index.tsx (1)
4-10:img대체 텍스트를 받을 수 있게 열어두는 게 좋습니다.Line 10의
<img>에alt전달 경로가 없어 접근성 제어가 제한됩니다.altprop(기본값'')을 추가해 장식/의미 이미지를 호출부에서 선택 가능하게 해주세요.♿ 제안 패치
interface ProfileImageProps { src?: string; size: '36' | '40' | '48' | '68'; + alt?: string; } -function ProfileImage({ src, size }: ProfileImageProps) { - return <S.Image src={src || defaultProfileImg} $size={size} />; +function ProfileImage({ src, size, alt = '' }: ProfileImageProps) { + return <S.Image src={src || defaultProfileImg} alt={alt} $size={size} />; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/ui/ProfileImage/index.tsx` around lines 4 - 10, Add an optional alt prop to the ProfileImage API and forward it to the rendered image: update ProfileImageProps to include alt?: string (default to '' in the component), accept alt in the ProfileImage function signature, and pass alt={alt ?? ''} into S.Image (which currently receives src and $size) so callers can choose decorative or meaningful alt text; reference ProfileImage, ProfileImageProps, S.Image, and defaultProfileImg when making the change.src/mocks/handlers/group.ts (1)
191-196: MSW 라우트 파라미터 검증은 불필요합니다.MSW에서
/api/v1/groups/:settlementCode/members형태의 경로 패턴을 사용하면,params.settlementCode는 항상 존재합니다 (빈 문자열일 수는 있어도undefined가 아님). 이 검증 로직은 도달할 수 없는 코드입니다.🔧 불필요한 검증 제거
http.get('/api/v1/groups/:settlementCode/members', ({ request, params }) => { if (!getIsMocked(request)) return passthrough(); - const { settlementCode } = params; - - if (!settlementCode) { - return HttpResponse.json( - { error: 'settlementCode is required' }, - { status: 400 } - ); - } - return HttpResponse.json({ members: dummyMemberList }); }),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/mocks/handlers/group.ts` around lines 191 - 196, Remove the unreachable MSW route parameter validation that checks if (!settlementCode) and returns HttpResponse.json(...); specifically delete the conditional block that inspects params.settlementCode and returns a 400, and rely on params.settlementCode directly (it will always be defined by the /api/v1/groups/:settlementCode/members route); ensure no other logic expects that early 400 return.src/pages/join/JoinPage.tsx (1)
31-33: 디버깅용 console.log는 프로덕션 전에 제거해 주세요.
console.log('프로필 선택 성공')은 개발 중 유용하지만, 프로덕션 빌드에서는 제거하거나 적절한 로깅 유틸리티로 대체하는 것이 좋습니다.🧹 console.log 제거
assignMember(selectedId, { onSuccess: () => { - console.log('프로필 선택 성공'); navigate(`/expense-detail/${groupToken}`); }, });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/join/JoinPage.tsx` around lines 31 - 33, Remove the debugging console.log from the onSuccess handler in JoinPage.tsx: inside the onSuccess callback (where navigate(`/expense-detail/${groupToken}`) is called), delete console.log('프로필 선택 성공') or replace it with a call to the app's logging utility if persistent logs are required; ensure the onSuccess remains calling navigate with groupToken and no stray console statements remain.src/shared/ui/Profile/index.tsx (1)
47-59: Flex 내부의keyprop은 불필요합니다.
key={id}가 컴포넌트 내부의 Flex에 전달되고 있지만, React의key는 리스트 렌더링 시 부모 컴포넌트에서<Profile key={...} />와 같이 전달해야 합니다. 컴포넌트 내부에서 key를 사용하는 것은 의미가 없습니다.🔧 불필요한 key prop 제거
return ( <Flex - key={id} gap={4} direction="column" alignItems="center" width="fit-content" py={8}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/ui/Profile/index.tsx` around lines 47 - 59, Remove the unnecessary key prop passed into the Flex element inside the Profile component: the Flex JSX has key={id} which is meaningless inside the component body; instead ensure any list rendering of Profile supplies the key at the parent level. Edit the Profile component to delete key={id} from the <Flex ...> element (leave id and handleClick usage intact for logic/props) so only external callers supply keys when mapping arrays.src/shared/ui/Profile/index.style.ts (1)
10-17: DeleteButton에 기본 버튼 스타일 리셋이 누락되었습니다.
<button>요소는 브라우저 기본 스타일(배경색, 테두리 등)을 가지고 있습니다. 일관된 UI를 위해 리셋 스타일을 추가하는 것이 좋습니다.🔧 버튼 리셋 스타일 추가
export const DeleteButton = styled.button` position: absolute; // 자식 요소 width: fit-content; height: fit-content; + padding: 0; + background: transparent; + border: none; + cursor: pointer; &:hover { filter: brightness(0.6); } `;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/shared/ui/Profile/index.style.ts` around lines 10 - 17, The DeleteButton styled component is missing browser default reset styles; update the DeleteButton (styled.button) to reset native button appearance by explicitly setting background: transparent (or none), border: none, padding: 0, margin: 0, outline: none (or outline: 0), appearance: none (-webkit-appearance: none) and cursor: pointer (and optionally line-height: 1) so the component renders consistently across browsers while keeping the existing position: absolute and hover filter behavior.src/pages/join/JoinPage.styles.ts (1)
36-44: 그라데이션 색상이 하드코딩되어 있습니다.
rgba(255, 255, 255, 0)와white가 직접 사용되고 있어 다크 모드 지원 시 문제가 될 수 있습니다. 당장은 문제없지만, 향후 테마 기반 배경색을 사용하는 것을 고려해 주세요.🎨 테마 기반 색상 사용 예시
export const GradientOverlay = styled.div` position: absolute; bottom: 0; left: 0; right: 0; height: 200px; - background: linear-gradient(to bottom, rgba(255, 255, 255, 0), white); + background: linear-gradient( + to bottom, + ${({ theme }) => theme.color.background.primary}00, + ${({ theme }) => theme.color.background.primary} + ); pointer-events: none; `;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/pages/join/JoinPage.styles.ts` around lines 36 - 44, GradientOverlay currently hardcodes colors (rgba(255,255,255,0) and white) which breaks theme/dark-mode; update the styled component GradientOverlay to pull colors from the theme (e.g. theme.colors.background or theme.palette.background) instead of literal values and derive a transparent variant for the top stop (use your theme helper/utility or CSS rgba/transparentize with the theme color and alpha 0), preserving the linear-gradient direction and height; this ensures the gradient respects dark mode and future theme changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/pages/expenseDetail/loader.ts`:
- Line 33: Prettier is flagging the line that assigns myProfile using
profiles.find; fix by applying the project's Prettier formatting to this file
(or run the formatter/IDE auto-format) so the expression const myProfile =
profiles.find((profile) => profile.userId === user.id) ?? null; is reformatted
to match lint rules (or split into multiple lines if configured) and then commit
the formatted change; ensure the symbol myProfile and the profiles.find(...)
expression remain functionally identical after formatting.
- Around line 42-50: The catch currently converts every Axios 401 into a
BoundaryError which breaks the login-redirect flow; update the catch in
loader.ts to distinguish authentication vs authorization: if isAxiosError(error)
and error.response?.status === 401, inspect the request context (e.g.,
error.response.config.url or the caller like getUserInfo) and rethrow the
original error for auth-related endpoints (so the login redirect can run), but
convert only permission-check responses (or non-auth endpoints) into the
BoundaryError; use symbols isAxiosError, BoundaryError and getUserInfo to locate
the logic to implement this conditional behavior.
- Line 26: The redirect call building the returnUrl
(redirect(`/login?returnUrl=/expense-detail/${groupToken}`)) can break if
groupToken contains special characters; update the code in the loader where
redirect is invoked to URL-encode the returnUrl (e.g., wrap the path or the
groupToken with encodeURIComponent) so the query parameter is safe when
redirecting to login.
In `@src/pages/join/loader.ts`:
- Line 22: The LoginPage currently ignores the returnUrl query added by the
loader's redirect (e.g., `/login?returnUrl=/join/${groupToken}`); update the
LoginPage component to read the returnUrl via useSearchParams, and after a
successful login (e.g., in the existing handleSubmit or onLoginSuccess flow)
navigate to that returnUrl instead of always redirecting to home. Concretely:
call const [searchParams] = useSearchParams() to get
searchParams.get('returnUrl'), validate/sanitize the value, and then use
useNavigate() or the existing navigation helper in the success callback of
LoginPage's login handler to route to the returnUrl (fallback to '/' if missing
or invalid). Ensure you reference LoginPage, useSearchParams, useNavigate and
the login success handler when applying the change.
---
Outside diff comments:
In `@src/features/user-profile/ui/MyProfile/index.tsx`:
- Around line 18-28: The JSX uses profile?.profileImageUrl but accesses
profile.name and profile.email without null checks; update the MyProfile
component to consistently guard against undefined profile—either add optional
chaining (e.g., profile?.name and profile?.email) where used (ProfileImage, Text
elements) or perform an early return at the top of the MyProfile render (e.g.,
if (!profile) return null) so that ProfileImage, the Text for name, and the Text
for email cannot read properties from undefined.
---
Nitpick comments:
In `@src/entities/group/api/group.ts`:
- Around line 47-49: getGroupHeader is missing the useMock option so dev mock
handler (/api/v1/groups/:settlementCode/header) won't be used; update the axios
call in getGroupHeader to include the same useMock: true option used by
getGroupList, assignMember, and getUserInfo so the request routes to the mock
handler in development and maintains consistency with other API functions.
In `@src/mocks/handlers/group.ts`:
- Around line 191-196: Remove the unreachable MSW route parameter validation
that checks if (!settlementCode) and returns HttpResponse.json(...);
specifically delete the conditional block that inspects params.settlementCode
and returns a 400, and rely on params.settlementCode directly (it will always be
defined by the /api/v1/groups/:settlementCode/members route); ensure no other
logic expects that early 400 return.
In `@src/pages/join/JoinPage.styles.ts`:
- Around line 36-44: GradientOverlay currently hardcodes colors
(rgba(255,255,255,0) and white) which breaks theme/dark-mode; update the styled
component GradientOverlay to pull colors from the theme (e.g.
theme.colors.background or theme.palette.background) instead of literal values
and derive a transparent variant for the top stop (use your theme helper/utility
or CSS rgba/transparentize with the theme color and alpha 0), preserving the
linear-gradient direction and height; this ensures the gradient respects dark
mode and future theme changes.
In `@src/pages/join/JoinPage.tsx`:
- Around line 31-33: Remove the debugging console.log from the onSuccess handler
in JoinPage.tsx: inside the onSuccess callback (where
navigate(`/expense-detail/${groupToken}`) is called), delete console.log('프로필 선택
성공') or replace it with a call to the app's logging utility if persistent logs
are required; ensure the onSuccess remains calling navigate with groupToken and
no stray console statements remain.
In `@src/shared/ui/Profile/index.style.ts`:
- Around line 10-17: The DeleteButton styled component is missing browser
default reset styles; update the DeleteButton (styled.button) to reset native
button appearance by explicitly setting background: transparent (or none),
border: none, padding: 0, margin: 0, outline: none (or outline: 0), appearance:
none (-webkit-appearance: none) and cursor: pointer (and optionally line-height:
1) so the component renders consistently across browsers while keeping the
existing position: absolute and hover filter behavior.
In `@src/shared/ui/Profile/index.tsx`:
- Around line 47-59: Remove the unnecessary key prop passed into the Flex
element inside the Profile component: the Flex JSX has key={id} which is
meaningless inside the component body; instead ensure any list rendering of
Profile supplies the key at the parent level. Edit the Profile component to
delete key={id} from the <Flex ...> element (leave id and handleClick usage
intact for logic/props) so only external callers supply keys when mapping
arrays.
In `@src/shared/ui/ProfileImage/index.tsx`:
- Around line 4-10: Add an optional alt prop to the ProfileImage API and forward
it to the rendered image: update ProfileImageProps to include alt?: string
(default to '' in the component), accept alt in the ProfileImage function
signature, and pass alt={alt ?? ''} into S.Image (which currently receives src
and $size) so callers can choose decorative or meaningful alt text; reference
ProfileImage, ProfileImageProps, S.Image, and defaultProfileImg when making the
change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e0bb6217-0247-4ee3-bc8e-31e2ba3c66c9
📒 Files selected for processing (30)
src/app/Router.tsxsrc/entities/auth/api/auth.tssrc/entities/group/api/group.tssrc/entities/member/api/assignMember.tssrc/entities/member/api/getProfiles.tssrc/entities/member/model/member.type.tssrc/features/expense-management/ui/MemberExpenses/index.tsxsrc/features/join/api/useAssignMember.tssrc/features/user-profile/ui/MyProfile/index.tsxsrc/mocks/handlers/auth.tssrc/mocks/handlers/group.tssrc/pages/expenseDetail/loader.tssrc/pages/expenseDetail/ui/ExpenseMemberItem/index.tsxsrc/pages/join/JoinPage.styles.tssrc/pages/join/JoinPage.tsxsrc/pages/join/index.tssrc/pages/join/loader.tssrc/pages/memberSetup/ui/AddMember/index.tsxsrc/shared/config/route.tssrc/shared/ui/MemberProfile/index.stories.tssrc/shared/ui/MemberProfile/index.style.tssrc/shared/ui/MemberProfile/index.tsxsrc/shared/ui/MemberProfileImage/index.stories.tssrc/shared/ui/MemberProfileImage/index.tsxsrc/shared/ui/Profile/index.stories.tssrc/shared/ui/Profile/index.style.tssrc/shared/ui/Profile/index.tsxsrc/shared/ui/ProfileImage/index.stories.tssrc/shared/ui/ProfileImage/index.styles.tssrc/shared/ui/ProfileImage/index.tsx
💤 Files with no reviewable changes (5)
- src/shared/ui/MemberProfile/index.tsx
- src/shared/ui/MemberProfile/index.style.ts
- src/shared/ui/MemberProfileImage/index.stories.ts
- src/shared/ui/MemberProfile/index.stories.ts
- src/shared/ui/MemberProfileImage/index.tsx
공유 링크로 진입한 참여자 프로필 선택 → 정산 상세 페이지로 이동하는 플로우 구현 - joinLoader : 인증 확인 → 프로필 선택 여부 확인 → 프로필 목록 반환 - expenseDetailLoader : 정산 상세 페이지 진입 전 프로필 미선택 시 Join 페이지로 리다이렉트
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/mocks/handlers/group.ts (2)
209-209: 디버그용console.log제거를 고려해주세요.Mock 핸들러에 남겨진 로그는 개발 중 콘솔을 어지럽힐 수 있습니다. 필요하다면 주석 처리하거나 제거하는 것이 좋습니다.
♻️ 제거 제안
- console.log(`settlementCode: ${settlementCode}, memberId: ${memberId}`);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/mocks/handlers/group.ts` at line 209, Remove the leftover debug console.log in the mock handler: locate and delete or comment out the line console.log(`settlementCode: ${settlementCode}, memberId: ${memberId}`) in src/mocks/handlers/group.ts (inside the group mock handler function) so the mock no longer emits development logs to the console.
189-196:settlementCode유효성 검증이 불필요합니다.MSW의 path parameter는 URL에서 추출되므로
/api/v1/groups/:settlementCode/members경로로 요청이 도달했다면settlementCode는 항상 존재합니다. 이 검증은 절대400을 반환하지 않습니다.♻️ 불필요한 검증 제거 제안
http.get('/api/v1/groups/:settlementCode/members', ({ request, params }) => { if (!getIsMocked(request)) return passthrough(); - const { settlementCode } = params; - - if (!settlementCode) { - return HttpResponse.json( - { error: 'settlementCode is required' }, - { status: 400 } - ); - } return HttpResponse.json({ members: dummyMemberList }); }),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/mocks/handlers/group.ts` around lines 189 - 196, The guard that checks params.settlementCode and returns HttpResponse.json({ error: 'settlementCode is required' }, { status: 400 }) is unnecessary because MSW path params guarantee settlementCode for the route; remove the if-block that references settlementCode and the associated HttpResponse.json error return so the handler proceeds using params.settlementCode directly (look for the variables settlementCode and the HttpResponse.json call in the handler to delete).src/app/Router.tsx (1)
123-127: Join 라우트 배치가 의도적인지 확인이 필요합니다.
ROUTE.join라우트가protected라우트 외부에 배치되어 있습니다.joinLoader가 자체적으로 인증을 처리하므로 문제는 없지만,expenseDetail과 함께 별도 그룹으로 묶거나 주석을 추가하면 가독성이 향상될 수 있습니다.💡 라우트 그룹화 제안
], }, - // TODO : 로그인 기능으로 변경될 예정 + // 자체 인증 로직을 가진 라우트들 (loader에서 auth 처리) { path: ROUTE.join, element: <LazyJoinPage />, loader: joinLoader, }, { path: ROUTE.expenseDetail, element: <LazyExpenseDetail />, loader: expenseDetailLoader, },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/app/Router.tsx` around lines 123 - 127, 현재 ROUTE.join (element: LazyJoinPage, loader: joinLoader) 가 보호된 라우트 블록 밖에 있어 배치 의도를 명확히 할 필요가 있습니다; joinLoader가 자체 인증을 처리하므로 동작상 문제는 없지만 가독성을 위해 join 라우트를 expenseDetail 등과 함께 별도 그룹으로 묶거나(예: 비인증/인증 분리 그룹) 해당 라우트 위에 간단한 주석을 추가해 의도를 명시하세요. ROUTE.join, LazyJoinPage, joinLoader, expenseDetail 식별자를 찾아 둘을 같은 그룹으로 옮기거나 주석으로 "joinLoader handles auth" 같은 문구를 추가하면 됩니다.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/pages/join/loader.ts`:
- Line 22: The redirect call uses an unencoded returnUrl which can break if
groupToken contains special characters; update the redirect to URL-encode the
returnUrl (e.g., call encodeURIComponent on `/join/${groupToken}`) before
passing it to redirect so the query param is safe; locate the redirect usage
involving user and groupToken in loader.ts and apply encoding consistently
(matching how expenseDetailLoader handles returnUrl).
- Around line 16-22: The call to queryClient.ensureQueryData with getUserInfo
can throw a 401 which currently bubbles to the error boundary; wrap that call in
a try-catch (similar to expenseDetailLoader) and detect authentication failures
(HTTP 401 or auth-specific error) to perform
redirect(`/login?returnUrl=/join/${groupToken}`) instead of letting the error
propagate; ensure you only rethrow non-401 errors so other failures still
surface.
---
Nitpick comments:
In `@src/app/Router.tsx`:
- Around line 123-127: 현재 ROUTE.join (element: LazyJoinPage, loader: joinLoader)
가 보호된 라우트 블록 밖에 있어 배치 의도를 명확히 할 필요가 있습니다; joinLoader가 자체 인증을 처리하므로 동작상 문제는 없지만
가독성을 위해 join 라우트를 expenseDetail 등과 함께 별도 그룹으로 묶거나(예: 비인증/인증 분리 그룹) 해당 라우트 위에 간단한
주석을 추가해 의도를 명시하세요. ROUTE.join, LazyJoinPage, joinLoader, expenseDetail 식별자를 찾아
둘을 같은 그룹으로 옮기거나 주석으로 "joinLoader handles auth" 같은 문구를 추가하면 됩니다.
In `@src/mocks/handlers/group.ts`:
- Line 209: Remove the leftover debug console.log in the mock handler: locate
and delete or comment out the line console.log(`settlementCode:
${settlementCode}, memberId: ${memberId}`) in src/mocks/handlers/group.ts
(inside the group mock handler function) so the mock no longer emits development
logs to the console.
- Around line 189-196: The guard that checks params.settlementCode and returns
HttpResponse.json({ error: 'settlementCode is required' }, { status: 400 }) is
unnecessary because MSW path params guarantee settlementCode for the route;
remove the if-block that references settlementCode and the associated
HttpResponse.json error return so the handler proceeds using
params.settlementCode directly (look for the variables settlementCode and the
HttpResponse.json call in the handler to delete).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2f0c4e4f-b5bd-4022-a17f-8246593e6d02
📒 Files selected for processing (16)
src/app/Router.tsxsrc/entities/auth/api/auth.tssrc/entities/group/api/group.tssrc/entities/member/api/assignMember.tssrc/entities/member/api/getProfiles.tssrc/entities/member/model/member.type.tssrc/features/join/api/useAssignMember.tssrc/mocks/handlers/auth.tssrc/mocks/handlers/group.tssrc/pages/expenseDetail/loader.tssrc/pages/expenseDetail/ui/ExpenseTimeHeader/index.stories.tsxsrc/pages/join/JoinPage.styles.tssrc/pages/join/JoinPage.tsxsrc/pages/join/index.tssrc/pages/join/loader.tssrc/shared/config/route.ts
✅ Files skipped from review due to trivial changes (7)
- src/entities/auth/api/auth.ts
- src/pages/join/index.ts
- src/pages/expenseDetail/ui/ExpenseTimeHeader/index.stories.tsx
- src/shared/config/route.ts
- src/entities/member/api/getProfiles.ts
- src/pages/join/JoinPage.styles.ts
- src/entities/member/model/member.type.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- src/entities/member/api/assignMember.ts
- src/mocks/handlers/auth.ts
- src/features/join/api/useAssignMember.ts
- src/entities/group/api/group.ts
- src/pages/join/JoinPage.tsx
url 인코딩 추가 - #28 (comment) - #28 (comment) prettier 포맷 수정 #28 (comment)
|
@coderabbitai approve |
✅ Actions performedComments resolved and changes approved. |
Deploying moddo-frontend with
|
| Latest commit: |
7c131c9
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://0a566ec7.moddo-frontend.pages.dev |
| Branch Preview URL: | https://feat-md-22.moddo-frontend.pages.dev |
401 응답 시 현재 경로를 redirectTo 쿼리 파라미터에 담아 로그인 페이지로 이동하도록 수정합니다. 또한 localStorage 기반 Authorization 헤더를 제거합니다 (쿠키 기반 인증으로 전환). ref: #28 (comment)
MemberProfileImage 제거, develop에서 사용되던 부분 수정 예정
ongheong
left a comment
There was a problem hiding this comment.
코드 확인했습니다! 정산 참여 플로우에서 사용자 상황별 라우팅과 프로필 선택 로직을 잘 구현해주셔서 감사합니다. 코멘트 몇개 남겼습니다 확인해주시면 감사하겠습니다~!
| {members.map((member) => ( | ||
| <MemberProfile | ||
| <Profile | ||
| key={member.id} |
There was a problem hiding this comment.
여기서 key prop을 넘겨주는 이유가 무엇인가요? Profile 컴포넌트 내부에서 key는 id로 사용되는 것 같아 여쭤봅니당
There was a problem hiding this comment.
여기서 key prop은 map을 이용해서 컴포넌트를 랜더링하고 있기 때문에 넣어 준 것입니다..!!!
https://react.dev/learn/rendering-lists
| '40': '2.5rem', | ||
| '48': '3rem', | ||
| '68': '4.25rem', |
There was a problem hiding this comment.
기존에 sm/md/lg 시멘틱 키로 관리하던 걸 숫자 값으로 바꾸셨는데, 혹시 배경이 있을까요?
There was a problem hiding this comment.
새로 정리된 프로필 컴포넌트의 사이즈 타입이 숫자 타입으로 되어 있더라고요!
일관성을 위해서 숫자 값을 담고 있는 문자열 리터럴로 바꾸었습니다!
https://www.figma.com/design/ZXka9a1g0bxfcNTaYVZZg2/MODDO2?node-id=61-54995&m=dev
💻 작업 내용
공유 링크로 진입한 참여자가 프로필을 선택하고 정산 상세 페이지로 이동하는 플로우를 구현했습니다.
진입 플로우
/join/:groupToken 진입
→ (미로그인) 로그인 페이지로 이동
→ (이미 프로필 선택) /expense-detail/:groupToken으로 이동
→ (프로필 미선택) 프로필 선택 UI 표시
↓ 프로필 선택 후 확인
/expense-detail/:groupToken 진입
주요 변경사항
정산 참여 페이지 (
pages/join)joinLoader: 인증 확인 → 기존 프로필 선택 여부 확인 → 프로필 목록 조회JoinPage: 프로필 그리드 표시정산 상세 로더 교체 (
pages/expenseDetail/loader.ts)groupTokenUrlLoader를expenseDetailLoader로 교체/join으로 리다이렉트useAssignMember훅 (features/join)profiles캐시를 제거해 loader가 최신 데이터를 fetch하도록 함Profile / ProfileImage 컴포넌트 통합
MemberProfile→Profile(size variant S/m/L 추가, ProfileImage 재사용)MemberProfileImage→ProfileImage(size를'36' | '40' | '48' | '68'로 변경)📸 스크린샷
Summary by CodeRabbit
New Features
Refactor
Chores