fix: (QA/3) 마이페이지, 프로필 수정 페이지 디자인 QA 반영#365
Conversation
Walkthrough편집 프로필 페이지에서 버튼 비활성화 처리를 variant 기반으로 통일하고 커서 스타일을 추가했습니다. 프로필 페이지 일부 레이아웃 패딩을 조정했습니다. 버튼 disabled variant 스타일을 수정했습니다. Input 컴포넌트의 보조 아이콘 선택 로직을 정리하고 multiline 시 아이콘 표시 규칙을 변경했습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant EP as EditProfile Page
participant Btn as Button (variant)
Note over EP,Btn: 각 입력 상태/오류/isSubmitting에 따라 variant 결정
U->>EP: 입력 변경/제출 액션
EP->>EP: 유효성 검사 및 상태 계산
EP->>Btn: variant = disabled | skyblue | blue<br/>className에 cursor-not-allowed 조건 적용
Btn-->>U: 시각적 상태(활성/비활성) 및 클릭 가능 여부 표현
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
MATEBALL-STORYBOOK |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/pages/edit-profile/edit-profile.tsx (1)
280-286: 매칭 조건 수정 버튼: 일회성 잠금 해제 누락 가능성
setIsSubmit(true)로만 잠그면 요청 실패/성공 후에도 복구되지 않을 수 있습니다. mutation 상태 기반으로 제어하거나onSettled에서 해제하세요.
- mutation 상태 노출:
- const { mutate: editMatchCondition } = useMutation(userMutations.EDIT_MATCH_CONDITION()); + const { mutate: editMatchCondition, isPending: isEditMatchConditionPending } = + useMutation(userMutations.EDIT_MATCH_CONDITION());
- 버튼 제어:
- variant={isSubmitDisabled ? 'disabled' : 'blue'} - className={cn(isSubmitDisabled && 'cursor-not-allowed')} + variant={(isSubmitDisabled || isEditMatchConditionPending) ? 'disabled' : 'blue'} + disabled={isSubmitDisabled || isEditMatchConditionPending} + className={cn((isSubmitDisabled || isEditMatchConditionPending) && 'cursor-not-allowed')}
- 저장 클릭 시 자동 해제:
// handleSaveClick 내부 호출부를 이렇게 변경 editMatchCondition( { team: teamValue, genderPreference: genderValue, style: viewStyleValue, teamAllowed: teamValue === NO_TEAM_OPTION ? null : mateTeamValue || null, }, { onSettled: () => setIsSubmit(false) } );필요하시면 위 변경을 반영한 전체 패치도 만들어드릴게요.
🧹 Nitpick comments (2)
src/shared/components/button/button/styles/button-variants.ts (1)
14-14: disabled 변형: bg 중복 및 radius 충돌 가능
bg-gray-100가 중복이며, base(rounded-[1.2rem])와 변형(rounded-[0.8rem])의 radius가 상충합니다. 의도된 디자인이 아니면 radius 오버라이드를 제거하거나 통일하는 편이 안전합니다.- 반복되는
cursor-not-allowed를 각 호출부가 붙이고 있어 분산되어 있습니다. disabled 변형에 포함하면 중복을 줄일 수 있습니다.적용 예:
- disabled: 'rounded-[0.8rem] bg-gray-100 bg-gray-100 text-gray-400', + disabled: 'rounded-[0.8rem] bg-gray-100 text-gray-400 cursor-not-allowed',(디자인이 base와 동일해야 하면
rounded-[0.8rem]를 제거해 통일하세요.)src/pages/profile/profile.tsx (1)
41-70: 상단 고정 섹션의 탭 타겟 확대 제안좌우 패딩을 제거하면서 링크들이 텍스트 영역만 클릭됩니다. 모바일 탭 타겟을 넓히려면 링크/버튼을 block·w-full로 만들어주는 편이 안전합니다. 시각 변화 없이 클릭 가능 영역만 넓어집니다.
- className="cap_14_m py-[0.8rem] text-gray-800" + className="cap_14_m block w-full py-[0.8rem] text-gray-800" ... - className="cap_14_m py-[0.8rem] text-gray-800" + className="cap_14_m block w-full py-[0.8rem] text-gray-800" ... - <button + <button type="button" onClick={() => logout()} aria-label="로그아웃" - className="cap_14_m cursor-pointer py-[0.8rem] text-gray-800" + className="cap_14_m cursor-pointer w-full py-[0.8rem] text-left text-gray-800"
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/pages/edit-profile/edit-profile.tsx(2 hunks)src/pages/profile/profile.tsx(1 hunks)src/shared/components/button/button/styles/button-variants.ts(1 hunks)src/shared/components/input/input.tsx(2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: heesunee
PR: MATEBALL/MATEBALL-CLIENT#78
File: src/pages/sign-up/utils/age-calculate.ts:1-4
Timestamp: 2025-07-09T09:08:46.371Z
Learning: heesunee는 나이 계산 시 한국식 나이 시스템을 사용하므로, 정확한 생일 기반 계산보다는 출생연도 기준의 간단한 계산 방식을 선호합니다.
📚 Learning: 2025-07-09T18:07:41.693Z
Learnt from: heesunee
PR: MATEBALL/MATEBALL-CLIENT#95
File: src/pages/sign-up/components/nickname-step.tsx:28-30
Timestamp: 2025-07-09T18:07:41.693Z
Learning: heesunee는 src/pages/sign-up/components/nickname-step.tsx의 onSubmit 핸들러 API 호출을 쿼리와 함께 통합해서 처리할 예정이므로, 이 부분에 대해 다시 언급하지 않아야 합니다.
Applied to files:
src/pages/edit-profile/edit-profile.tsx
📚 Learning: 2025-07-09T17:24:19.755Z
Learnt from: heesunee
PR: MATEBALL/MATEBALL-CLIENT#94
File: src/pages/sign-up/sign-up.tsx:4-4
Timestamp: 2025-07-09T17:24:19.755Z
Learning: heesunee는 src/pages/sign-up/sign-up.tsx의 isNicknameStep 하드코딩된 값을 퍼널 패턴으로 카카오 통합과 함께 나중에 처리할 예정이므로, 이 부분에 대해 다시 언급하지 않아야 합니다.
Applied to files:
src/pages/edit-profile/edit-profile.tsx
🧬 Code graph analysis (2)
src/pages/edit-profile/edit-profile.tsx (1)
src/shared/libs/cn.ts (1)
cn(4-6)
src/pages/profile/profile.tsx (1)
src/pages/profile/constants/link.ts (2)
REQUEST_LINK(1-1)FEEDBACK_LINK(3-3)
⏰ 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: Cloudflare Pages
🔇 Additional comments (2)
src/shared/components/input/input.tsx (2)
47-52: 멀티라인 메시지 아이콘을 Info로 고정 — 의도와 일치요구사항(한줄 소개 하단 Icon Info 고정)에 정확히 부합합니다. valid 상태에서도 체크 아이콘으로 바뀌지 않아 UX 일관성이 좋아졌습니다.
101-104: Icon name 추출 리팩터링 LGTM
helperIconName도입으로 가독성이 개선되었습니다.
| variant={ | ||
| !!errors.nickname || nicknameVal.trim().length === 0 || isSubmitting | ||
| ? 'disabled' | ||
| : 'skyblue' | ||
| } | ||
| label="중복 확인" | ||
| onClick={handleCheckNickname} | ||
| disabled={!!errors.nickname || nicknameVal.trim().length === 0 || isSubmitting} | ||
| className="cap_14_sb mt-[0.8rem] w-auto px-[1.6rem] py-[0.6rem] disabled:text-white" | ||
| className={cn( | ||
| 'cap_14_sb mt-[0.8rem] w-auto px-[1.6rem] py-[0.6rem]', | ||
| (!!errors.nickname || nicknameVal.trim().length === 0 || isSubmitting) && | ||
| 'cursor-not-allowed', | ||
| )} |
There was a problem hiding this comment.
🛠️ Refactor suggestion
중복 확인 버튼: 시각적 비활성화뿐이라 다중 클릭/중복 요청 가능
isSubmitting은 RHF의 폼 제출 상태라 현재 onClick 흐름에서는 항상 false일 확률이 큽니다. 실제 네트워크 진행 중에도 버튼이 활성으로 남아 스팸 클릭이 가능합니다.checking상태에서도 비활성화되지 않습니다.
- 비활성 조건 상수화(+
checking포함) 및 disabled 속성 복원:
- variant={
- !!errors.nickname || nicknameVal.trim().length === 0 || isSubmitting
- ? 'disabled'
- : 'skyblue'
- }
+ variant={isNicknameCheckDisabled ? 'disabled' : 'skyblue'}
+ disabled={isNicknameCheckDisabled}
...
- (!!errors.nickname || nicknameVal.trim().length === 0 || isSubmitting) &&
+ (isNicknameCheckDisabled) &&- 컴포넌트 상단(훅들 아래)에 보조 상수 추가:
const isNicknameCheckDisabled =
!!errors.nickname || nicknameVal.trim().length === 0 || nicknameStatus === 'checking';🤖 Prompt for AI Agents
In src/pages/edit-profile/edit-profile.tsx around lines 153 to 164, the "중복 확인"
button currently only looks visually disabled and uses isSubmitting (an RHF
submission flag) so it can still be clicked during an ongoing nickname-check;
also it doesn't consider the nicknameStatus checking state. Define a single
boolean constant (e.g. isNicknameCheckDisabled) near the top with the hook
declarations that combines !!errors.nickname, nicknameVal.trim().length === 0,
and nicknameStatus === 'checking' (and optionally isSubmitting if you want); use
that constant for the variant, className conditional (cursor-not-allowed), add
the disabled attribute on the button element, and ensure the onClick
early-returns when disabled to prevent multiple network requests.
| variant={ | ||
| nicknameStatus !== 'available' || nicknameVal.trim().length === 0 || isSubmitting | ||
| ? 'disabled' | ||
| : 'blue' | ||
| } | ||
| className="cap_14_sb mt-[0.8rem] w-auto px-[1.6rem] py-[0.6rem]" | ||
| label="수정" | ||
| onClick={submitNickname} | ||
| className={cn( | ||
| 'cap_14_sb mt-[0.8rem] w-auto px-[1.6rem] py-[0.6rem]', | ||
| (nicknameStatus !== 'available' || nicknameVal.trim().length === 0 || isSubmitting) && | ||
| 'cursor-not-allowed', | ||
| )} |
There was a problem hiding this comment.
🛠️ Refactor suggestion
닉네임 ‘수정’ 버튼: 실제 저장 중 중복 클릭 가능
RHF isSubmitting을 의존해도 이 경로는 trigger + mutate로 진행되어 폼 submit 상태가 아닙니다. Mutation 진행 여부(isPending)로 제어해야 안전합니다.
- mutation 대기 상태 노출:
- const { mutate: editProfile } = useMutation(userMutations.EDIT_PROFILE());
+ const { mutate: editProfile, isPending: isEditProfilePending } =
+ useMutation(userMutations.EDIT_PROFILE());- 버튼 비활성 조건 교체 및 disabled 복원:
- variant={
- nicknameStatus !== 'available' || nicknameVal.trim().length === 0 || isSubmitting
- ? 'disabled'
- : 'blue'
- }
+ variant={isNicknameSubmitDisabled ? 'disabled' : 'blue'}
+ disabled={isNicknameSubmitDisabled}
...
- (nicknameStatus !== 'available' || nicknameVal.trim().length === 0 || isSubmitting) &&
+ (isNicknameSubmitDisabled) &&- 상단에 상수 추가:
const isNicknameSubmitDisabled =
nicknameStatus !== 'available' || nicknameVal.trim().length === 0 || isEditProfilePending;🤖 Prompt for AI Agents
In src/pages/edit-profile/edit-profile.tsx around lines 168 to 179, the nickname
"수정" button currently relies on RHF's isSubmitting which isn't set for the
trigger+mutate flow, allowing duplicate clicks; expose the mutation's pending
state (e.g., isEditProfilePending) from the editProfile mutation, add a
top-level constant isNicknameSubmitDisabled that combines nicknameStatus !==
'available', trimmed nickname empty, and isEditProfilePending, then replace the
current inline conditions with that constant for variant and className, and
restore the button's disabled prop to use isNicknameSubmitDisabled so the button
is visually and functionally disabled during the mutation.
| variant={ | ||
| !!errors.introduction || introductionVal.trim().length === 0 || isSubmitting | ||
| ? 'disabled' | ||
| : 'blue' | ||
| } | ||
| label="수정" | ||
| onClick={submitInformation} | ||
| disabled={!!errors.introduction || introductionVal.trim().length === 0 || isSubmitting} | ||
| className="cap_14_sb mt-[0.8rem] w-auto px-[1.6rem] py-[0.6rem]" | ||
| className={cn( | ||
| 'cap_14_sb mt-[0.8rem] w-auto px-[1.6rem] py-[0.6rem]', | ||
| (!!errors.introduction || introductionVal.trim().length === 0 || isSubmitting) && | ||
| 'cursor-not-allowed', | ||
| )} |
There was a problem hiding this comment.
🛠️ Refactor suggestion
한 줄 소개 ‘수정’ 버튼: 저장 중 재클릭 방지 필요
동일하게 mutation 진행 상태를 반영해 비활성화하고, DOM의 disabled 속성도 함께 설정해 접근성/포커스 이동을 보장하세요.
- variant={
- !!errors.introduction || introductionVal.trim().length === 0 || isSubmitting
- ? 'disabled'
- : 'blue'
- }
+ variant={isIntroSubmitDisabled ? 'disabled' : 'blue'}
+ disabled={isIntroSubmitDisabled}
...
- (!!errors.introduction || introductionVal.trim().length === 0 || isSubmitting) &&
+ (isIntroSubmitDisabled) &&상단에 상수 추가:
const isIntroSubmitDisabled =
!!errors.introduction || introductionVal.trim().length === 0 || isEditProfilePending;
#️⃣ Related Issue
Closes #363
💎 PR Point
📸 Screenshot
Summary by CodeRabbit