Skip to content

[Feat] WTH-436: 어드민 회비 관리 설정 페이지 구현#140

Merged
JIN921 merged 16 commits into
developfrom
feat/WTH-436-어드민-회비-설정-구현
Jul 6, 2026

Hidden character warning

The head ref may contain hidden characters: "feat/WTH-436-\uc5b4\ub4dc\ubbfc-\ud68c\ube44-\uc124\uc815-\uad6c\ud604"
Merged

[Feat] WTH-436: 어드민 회비 관리 설정 페이지 구현#140
JIN921 merged 16 commits into
developfrom
feat/WTH-436-어드민-회비-설정-구현

Conversation

@JIN921

@JIN921 JIN921 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

✅ PR 유형

어떤 변경 사항이 있었나요?

  • 새로운 기능 추가
  • 버그 수정
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

📌 관련 이슈번호

  • Closed WTH-436

✅ Key Changes

🆕 회비 관리 설정 페이지 신규 구현

  • /[clubId]/admin/dues/setting 라우트 추가 (DuesSettingPageContent)
  • 총 회비 설정 조회 영역: 기본 정보 / 이월 설정 / 납부 대상 / 계좌 공개를 읽기 전용으로 표시하고, 납부 대상 모달(PaymentTargetModal)로 대상 편집 진입
  • 회비 공개 범위 토글: 전체 회비 내역 공개 여부를 Switch로 제어
  • 회비 대시보드 TopBar의 "설정" 버튼 → 설정 페이지로 이동 연결

🔗 거래내역 상세 조회 API 연동

  • duesApi.getTransaction + useAdminDuesTransactionQuery 추가 — 상세 모달이 열릴 때만(enabled 게이팅) 목록에 없는 메모·영수증 파일 정보를 담은 단건 상세를 조회
  • 상세 응답 도착 전에는 목록 데이터를 폴백으로 사용하고, 도착하면 상세 값으로 대체
  • adminQueryKeys.duesTransaction 쿼리 키 추가

💀 대시보드 로딩 스켈레톤 추가

  • DuesPageSkeleton 추가 — 기수가 선택된 상태에서 대시보드 로딩 중일 때 노출 (미등록 장부/기수 없음 케이스는 제외)

👥 납부 대상 선택 UX 개선

  • 같은 납부 상태의 부원끼리만 다중 선택 가능 (다른 상태 행은 disabled + 안내 툴팁) — 벌크 액션이 일부 대상에게 무의미해지는 것 방지
  • 연락처를 formatPhone으로 포맷 표시
  • 선택 상단 헤더를 MemberSelectHeader 컴포넌트로 분리 (납부 정정 / 환불 처리 / 납부 완료)
  • 사용하지 않던 "멤버정보" 액션 컬럼·버튼, 통계 카드의 액션 버튼 제거

♻️ 공개 여부 토글 훅 추출

  • useDuesVisibilityToggle 추가 — 낙관적 업데이트(즉시 반영 후 실패 시 롤백) 로직을 훅으로 분리해 회비 대시보드/설정 페이지에서 공유

🎛 설정 스텝 헤더 공통화 + 온보딩 안내

  • SetupHeader 추가 — Step1~5 헤더를 통일하고 "다음으로 버튼을 눌러야 변경사항이 저장됩니다" 툴팁 노출
  • SettingResultCardGridonEdit/onEditStep을 optional로 변경 — 미전달 시 수정 버튼을 숨겨 읽기 전용 모드 지원

📱 모바일 반응형 대응

  • 기수 필터, 납부 대상 선택 헤더 등 반응형 레이아웃 적용

🚧 기타

  • 미등록 에러 판별에 DUES_NOT_EXIST_CODE(20100) 추가
  • Prettier 포맷팅 정리

📸 스크린샷 or 실행영상


🎸 기타 사항 or 추가 코멘트

  • 회비 설정 페이지만 만들려 햇는데,,, qa 하기 전 수정할 부분들이 보여서 조금 수정한다는 게,, 조오금 많아졋네용 ㅎㅎ..
  • 회비 설정 페이지에 컴포넌트는 온보딩 컴포넌트를 그대로 재사용 하되, 따로 api 연결은 안 됏습니다! 아직 api가 안 나와서 qa 이후 api 나오는대로 컴포넌트 재구성 및 api 연결 진행할게용

Summary by CodeRabbit

  • New Features

    • 회비 관리에 설정 페이지와 로딩 스켈레톤이 추가되어, 설정 확인과 화면 전환이 더 자연스러워졌습니다.
    • 거래 상세에서 메모와 여러 영수증 첨부를 확인할 수 있게 되었습니다.
    • 부원 선택 작업을 위한 상단 선택 바와 상태별 일괄 처리 기능이 추가되었습니다.
  • Bug Fixes

    • 선택 가능한 부원이 납부 상태별로 제한되어, 혼동되는 선택을 방지합니다.
    • 전화번호 표시와 반응형 레이아웃, 로딩/빈 상태 표시가 개선되었습니다.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bdb5d31a-2390-40db-8ca8-6128cac8274a

📥 Commits

Reviewing files that changed from the base of the PR and between 707ac2c and de83e0a.

📒 Files selected for processing (4)
  • src/components/admin/dues/DuesPageContent.tsx
  • src/components/admin/dues/DuesPaymentStatusPageContent.tsx
  • src/components/admin/dues/MemberSelectHeader.tsx
  • src/types/admin/dues.d.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/admin/dues/DuesPaymentStatusPageContent.tsx
  • src/components/admin/dues/DuesPageContent.tsx

📝 Walkthrough

Walkthrough

회비 설정 페이지, 거래 단건 상세 조회, 납부 상태 기반 선택 UI, 설정 단계 공통 헤더, 로딩 스켈레톤이 추가되었습니다. 거래 상세 모달은 메모와 복수 영수증을 표시하도록 확장됐고, 관리 화면의 일부 버튼과 레이아웃 스타일이 조정됐습니다.

Changes

회비 관리 기능 개편

Layer / File(s) Summary
회비 설정 페이지와 공개 토글
src/app/(private)/[clubId]/admin/dues/setting/page.tsx, src/components/admin/dues/DuesSettingPageContent.tsx, src/hooks/admin/useDuesVisibilityToggle.ts, src/hooks/queries/admin/adminQueryKeys.ts, src/hooks/queries/admin/useAdminDuesQueries.ts, src/hooks/queries/admin/useDuesDashboardQuery.ts, src/lib/apis/adminDues.ts, src/constants/admin/dues.constants.ts, src/components/admin/dues/DuesPageContent.tsx, src/components/admin/dues/DuesPageSkeleton.tsx, src/components/admin/dues/index.ts, src/hooks/admin/index.ts
회비 설정 페이지와 콘텐츠가 추가되고, 공개 여부 토글 훅, 거래 단건 조회 키/API/쿼리, 대시보드 오류 판별 확장, 로딩 스켈레톤과 라우팅 연결이 함께 반영됨.
납부 현황 선택 UI 개편
src/components/admin/dues/DuesPaymentStatusPageContent.tsx, src/components/admin/dues/MemberSelectHeader.tsx, src/components/admin/dues/DuesMemberPaymentTable.tsx, src/components/admin/dues/DuesPaymentSummaryCard.tsx, src/components/admin/dues/index.ts
선택 상태를 기준으로 벌크 액션을 보여주는 헤더가 추가되고, 테이블 선택 제약과 요약 카드/상세 이동 로직이 조정됨.
거래 상세 모달 메모와 영수증
src/components/admin/dues/modal/TransactionDetailModal.tsx, src/types/admin/dues.d.ts
거래 상세 타입이 확장되고, 모달이 메모와 복수 영수증 첨부를 표시하도록 바뀜.
회비 설정 마법사 공통 헤더
src/components/admin/dues/setup/DuesSetupStep1.tsx...DuesSetupStep5.tsx, src/components/admin/dues/setup/components/SetupHeader.tsx, src/components/admin/dues/setup/components/SettingResultCardGrid.tsx, src/components/admin/dues/setup/components/index.ts
각 단계 헤더가 공통 SetupHeader로 교체되고, 결과 카드 수정 버튼은 선택적으로 노출되도록 변경됨.
레이아웃과 필터 스타일 정리
src/app/(private)/[clubId]/admin/layout.tsx, src/components/admin/dues/DuesGenerationFilter.tsx, src/components/admin/dues/DuesTopBar.tsx
관리 레이아웃과 회비 필터/탑바 버튼의 클래스 구성이 조정됨.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DuesPageContent
  participant useAdminDuesTransactionQuery
  participant duesApi
  participant TransactionDetailModal

  DuesPageContent->>useAdminDuesTransactionQuery: selectedTransaction.id, detailOpen 전달
  useAdminDuesTransactionQuery->>duesApi: getTransaction(clubId, accountId, transactionId)
  duesApi-->>useAdminDuesTransactionQuery: TransactionItem 응답
  DuesPageContent->>TransactionDetailModal: detailToTransactionDetail(transactionDetail) 전달
  TransactionDetailModal->>TransactionDetailModal: memo / receipts 렌더링
Loading
sequenceDiagram
  participant DuesPaymentStatusPageContent
  participant DuesMemberPaymentTable
  participant MemberSelectHeader

  DuesMemberPaymentTable->>DuesPaymentStatusPageContent: onSelectionChange(selectedIds)
  DuesPaymentStatusPageContent->>MemberSelectHeader: selectedCount, selectedStatus 전달
  MemberSelectHeader->>DuesPaymentStatusPageContent: onMarkPaid/onRefund/onMarkUnpaid 호출
  DuesPaymentStatusPageContent->>DuesMemberPaymentTable: selectedIds, onSelectionChange 전달
Loading

Possibly related PRs

  • Team-Weeth/weeth-client#126: adminQueryKeys에 회비 거래 상세용 키를 추가한 같은 쿼리 구조 변경과 직접 연결됩니다.
  • Team-Weeth/weeth-client#129: TransactionDetailModal과 관련 타입을 다루는 변경으로, 본 PR의 메모/영수증 확장과 맞닿아 있습니다.
  • Team-Weeth/weeth-client#131: DuesMemberPaymentTable과 납부 상태 선택 흐름을 다루는 같은 영역의 변경입니다.

Suggested labels: ✨ Feature

Suggested reviewers: woneeeee, nabbang6, dalzzy

Poem

🐰 폴짝, 회비 창이 새로 열렸네
선택한 부원들, 상태 맞춰 반짝이네
영수증은 여러 장, 메모도 살며시
설정 헤더는 통일감 있게 쭉쭉
당근 냄새 나는 변경, 아주 좋아요 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 회비 관리 설정 페이지 구현이라는 핵심 변경을 명확히 요약합니다.
Description check ✅ Passed 필수 섹션인 PR 유형, 이슈번호, Key Changes, 기타 사항이 포함되어 전반적으로 템플릿을 잘 따릅니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/WTH-436-어드민-회비-설정-구현

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@JIN921 JIN921 requested review from dalzzy, nabbang6 and woneeeee July 6, 2026 05:51
@JIN921 JIN921 self-assigned this Jul 6, 2026
@JIN921 JIN921 added 🐞 BugFix Something isn't working 📬 API 서버 API 통신 labels Jul 6, 2026
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 통과
Build: 통과

🎉 모든 검증을 통과했습니다!

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

구현한 기능 Preview: https://weeth-h6mjhrncv-weethsite-4975s-projects.vercel.app

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR E2E 테스트 결과

Playwright: 통과

🎉 E2E 테스트를 통과했습니다!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
src/components/admin/dues/DuesGenerationFilter.tsx (1)

61-67: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

   대신 간격 유틸리티 사용 고려.

반응형 줄바꿈 로직(br + 조건부 span) 자체는 정상 동작하지만, tablet 이상에서 간격을   로 하드코딩하는 대신 gap이나 ml-* 같은 Tailwind 유틸리티를 사용하는 편이 유지보수와 국제화 측면에서 더 낫습니다.

♻️ 제안 예시
-        <span className="typo-body1 text-text-alternative">
+        <span className="typo-body1 tablet:inline-flex tablet:items-center tablet:gap-100 text-text-alternative">
           마지막 수정
           <br className="tablet:hidden" />
-          <span className="tablet:inline hidden">&nbsp;&nbsp;</span>
           {lastUpdated ? formatLastUpdated(lastUpdated) : '-'}
         </span>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/admin/dues/DuesGenerationFilter.tsx` around lines 61 - 67, The
spacing between “마지막 수정” and the formatted date in DuesGenerationFilter should
not rely on hardcoded non-breaking spaces. Update the JSX in
DuesGenerationFilter to replace the conditional inline &nbsp;&nbsp; span with a
Tailwind spacing utility such as gap or ml-* while keeping the existing
responsive br behavior and the lastUpdated/formatLastUpdated rendering intact.
src/components/admin/dues/DuesSettingPageContent.tsx (1)

42-66: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

로딩/미등록 상태 처리 누락

DuesPageContentisPending으로 스켈레톤을, isDuesNotRegisteredError로 온보딩 모달을 노출하지만, 이 설정 페이지는 dashboard/status/paymentTargets가 아직 로딩 중이거나 회비가 미등록인 경우에도 아무 가드 없이 0/빈 문자열 등 기본값으로 렌더링됩니다. 사용자가 로딩 중 또는 미등록 상태에서 직접 이 경로로 진입하면 실제로는 의미 없는 "빈" 설정 화면이 노출될 수 있습니다.

같은 패턴(DuesPageSkeleton, isDuesNotRegisteredError)을 재사용해 로딩/미등록 가드를 추가하는 것을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/admin/dues/DuesSettingPageContent.tsx` around lines 42 - 66,
The DuesSettingPageContent flow is missing guards for loading and unregistered
dues states, so it can render a blank/default settings screen while
dashboard/status/paymentTargets are still resolving or when dues are not
registered. Reuse the same pattern as DuesPageContent by checking the relevant
query pending state and isDuesNotRegisteredError, and show DuesPageSkeleton or
the onboarding/modal fallback before using dashboard, status, or
paymentTargets-derived values in DuesSettingPageContent.
src/components/admin/dues/setup/components/SettingResultCardGrid.tsx (1)

108-108: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

동일한 삼항 조건 4회 반복 — 헬퍼로 추출 고려

onEditStep ? () => onEditStep(step) : undefined 패턴이 4곳에서 반복됩니다. 작은 헬퍼 함수로 추출하면 중복을 줄일 수 있습니다.

♻️ 제안
+  const editHandler = (step: number) => (onEditStep ? () => onEditStep(step) : undefined);
+
   return (
     <div className="grid grid-cols-2 gap-400">
       {/* 기본 정보 */}
-      <InfoCard title="기본 정보" onEdit={onEditStep ? () => onEditStep(1) : undefined}>
+      <InfoCard title="기본 정보" onEdit={editHandler(1)}>
         ...
       {/* 이월 설정 */}
-      <InfoCard title="이월 설정" onEdit={onEditStep ? () => onEditStep(3) : undefined}>
+      <InfoCard title="이월 설정" onEdit={editHandler(3)}>
         ...
       {/* 납부 대상 */}
-      <InfoCard title="납부 대상" onEdit={onEditStep ? () => onEditStep(2) : undefined}>
+      <InfoCard title="납부 대상" onEdit={editHandler(2)}>
         ...
       {/* 계좌 공개 */}
-      <InfoCard title="계좌 공개" onEdit={onEditStep ? () => onEditStep(4) : undefined}>
+      <InfoCard title="계좌 공개" onEdit={editHandler(4)}>

Also applies to: 115-115, 141-141, 162-162

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/admin/dues/setup/components/SettingResultCardGrid.tsx` at line
108, The onEdit callback logic in SettingResultCardGrid repeats the same ternary
pattern multiple times, so extract it into a small helper inside the component
(for example, a function that accepts the step and returns the proper handler or
undefined). Update each InfoCard usage to call that helper instead of
duplicating onEditStep ? () => onEditStep(step) : undefined, keeping the
existing behavior intact.
src/components/admin/dues/setup/components/SetupHeader.tsx (1)

5-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Props 타입을 명명된 인터페이스로 분리 고려

파일 내 다른 컴포넌트들(InfoCardProps, SettingResultCardGridProps 등)은 명명된 Props 인터페이스를 export하는 패턴을 따릅니다. SetupHeaderSetupHeaderProps로 분리하면 재사용/테스트 시 일관성이 좋아집니다.

♻️ 제안
-function SetupHeader({ cardinalNumber }: { cardinalNumber: number }) {
+interface SetupHeaderProps {
+  cardinalNumber: number;
+}
+
+function SetupHeader({ cardinalNumber }: SetupHeaderProps) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/admin/dues/setup/components/SetupHeader.tsx` at line 5,
`SetupHeader` is using an inline props type instead of the named props-interface
pattern used elsewhere in this file. Extract the `{ cardinalNumber: number }`
shape into an exported `SetupHeaderProps` interface and update `SetupHeader` to
use it so the component matches `InfoCardProps` and `SettingResultCardGridProps`
for consistency and reuse.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/admin/dues/MemberSelectHeader.tsx`:
- Around line 45-49: MemberSelectHeader currently builds a single actions list
so 납부 정정, 환불 처리, and 납부 완료 are always shown regardless of selection state.
Update MemberSelectHeader to accept and use selectedStatus, and make the action
rendering conditional in the actions array so only paid/confirmed selections
expose 납부 정정 and 환불 처리, while only unpaid selections expose 납부 완료; alternatively
disable the irrelevant actions, but keep the behavior aligned with the bulk API
rules in onMarkUnpaid, onRefund, and onMarkPaid.

In `@src/components/admin/dues/modal/TransactionDetailModal.tsx`:
- Around line 58-90: `detailToTransactionDetail` is dropping detail-only fields,
so the modal loses the category suffix and registrant row when a full admin dues
transaction detail is available. Update the mapping used by
`useAdminDuesTransactionQuery` so `TransactionDetail` also carries `category`
and `registeredByName` from `detail`, and make sure `TransactionDetailModal`
continues to read those fields for `classificationLabel` and `registrant`.

In `@src/hooks/admin/useDuesVisibilityToggle.ts`:
- Around line 14-29: `useDuesVisibilityToggle` keeps `isPublic` in local state
with `useState(true)`, so when `accountId` changes within the same hook instance
the toggle can show a stale value. Update the hook to reset `isPublic` whenever
`accountId` changes and initialize it from the server-provided visibility once
that value is available, using the existing `useDuesVisibilityToggle` and
`handlePublicChange` flow so `DuesPageContent` and `DuesSettingPageContent`
always reflect the current account’s actual state.

---

Nitpick comments:
In `@src/components/admin/dues/DuesGenerationFilter.tsx`:
- Around line 61-67: The spacing between “마지막 수정” and the formatted date in
DuesGenerationFilter should not rely on hardcoded non-breaking spaces. Update
the JSX in DuesGenerationFilter to replace the conditional inline &nbsp;&nbsp;
span with a Tailwind spacing utility such as gap or ml-* while keeping the
existing responsive br behavior and the lastUpdated/formatLastUpdated rendering
intact.

In `@src/components/admin/dues/DuesSettingPageContent.tsx`:
- Around line 42-66: The DuesSettingPageContent flow is missing guards for
loading and unregistered dues states, so it can render a blank/default settings
screen while dashboard/status/paymentTargets are still resolving or when dues
are not registered. Reuse the same pattern as DuesPageContent by checking the
relevant query pending state and isDuesNotRegisteredError, and show
DuesPageSkeleton or the onboarding/modal fallback before using dashboard,
status, or paymentTargets-derived values in DuesSettingPageContent.

In `@src/components/admin/dues/setup/components/SettingResultCardGrid.tsx`:
- Line 108: The onEdit callback logic in SettingResultCardGrid repeats the same
ternary pattern multiple times, so extract it into a small helper inside the
component (for example, a function that accepts the step and returns the proper
handler or undefined). Update each InfoCard usage to call that helper instead of
duplicating onEditStep ? () => onEditStep(step) : undefined, keeping the
existing behavior intact.

In `@src/components/admin/dues/setup/components/SetupHeader.tsx`:
- Line 5: `SetupHeader` is using an inline props type instead of the named
props-interface pattern used elsewhere in this file. Extract the `{
cardinalNumber: number }` shape into an exported `SetupHeaderProps` interface
and update `SetupHeader` to use it so the component matches `InfoCardProps` and
`SettingResultCardGridProps` for consistency and reuse.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8cd7491d-3453-4d15-a685-5fd4581b236e

📥 Commits

Reviewing files that changed from the base of the PR and between 93c4c17 and 707ac2c.

📒 Files selected for processing (28)
  • src/app/(private)/[clubId]/admin/dues/setting/page.tsx
  • src/app/(private)/[clubId]/admin/layout.tsx
  • src/components/admin/dues/DuesGenerationFilter.tsx
  • src/components/admin/dues/DuesMemberPaymentTable.tsx
  • src/components/admin/dues/DuesPageContent.tsx
  • src/components/admin/dues/DuesPageSkeleton.tsx
  • src/components/admin/dues/DuesPaymentStatusPageContent.tsx
  • src/components/admin/dues/DuesPaymentSummaryCard.tsx
  • src/components/admin/dues/DuesSettingPageContent.tsx
  • src/components/admin/dues/DuesTopBar.tsx
  • src/components/admin/dues/MemberSelectHeader.tsx
  • src/components/admin/dues/index.ts
  • src/components/admin/dues/modal/TransactionDetailModal.tsx
  • src/components/admin/dues/setup/DuesSetupStep1.tsx
  • src/components/admin/dues/setup/DuesSetupStep2.tsx
  • src/components/admin/dues/setup/DuesSetupStep3.tsx
  • src/components/admin/dues/setup/DuesSetupStep4.tsx
  • src/components/admin/dues/setup/DuesSetupStep5.tsx
  • src/components/admin/dues/setup/components/SettingResultCardGrid.tsx
  • src/components/admin/dues/setup/components/SetupHeader.tsx
  • src/components/admin/dues/setup/components/index.ts
  • src/constants/admin/dues.constants.ts
  • src/hooks/admin/index.ts
  • src/hooks/admin/useDuesVisibilityToggle.ts
  • src/hooks/queries/admin/adminQueryKeys.ts
  • src/hooks/queries/admin/useAdminDuesQueries.ts
  • src/hooks/queries/admin/useDuesDashboardQuery.ts
  • src/lib/apis/adminDues.ts

Comment thread src/components/admin/dues/MemberSelectHeader.tsx Outdated
Comment thread src/components/admin/dues/modal/TransactionDetailModal.tsx
Comment on lines +14 to +29
export function useDuesVisibilityToggle(clubId: string, accountId: number | null) {
const [isPublic, setIsPublic] = useState(true);

const { mutate: updateMemberVisibility } = useUpdateMemberVisibility(clubId, accountId, {
onError: () => toastError('공개 설정 변경에 실패했습니다.'),
});

const handlePublicChange = (value: boolean) => {
setIsPublic(value);
updateMemberVisibility(value, {
onError: () => setIsPublic(!value),
});
};

return { isPublic, handlePublicChange };
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the hook and its call sites
git ls-files | rg 'src/hooks/admin/useDuesVisibilityToggle\.ts|DuesPageContent\.tsx|DuesSettingPageContent\.tsx|useAdminDuesMutations\.ts|useAdminDuesMutations\.tsx|DuesGenerationFilter'

# Show an outline for the hook file
ast-grep outline src/hooks/admin/useDuesVisibilityToggle.ts --view expanded || true

# Read the hook and the referenced call sites in small slices
for f in \
  src/hooks/admin/useDuesVisibilityToggle.ts \
  src/components/admin/DuesPageContent.tsx \
  src/components/admin/DuesSettingPageContent.tsx \
  src/hooks/mutations/admin/useAdminDuesMutations.ts
do
  if [ -f "$f" ]; then
    echo "===== $f ====="
    wc -l "$f"
    cat -n "$f" | sed -n '1,220p'
  fi
done

Repository: Team-Weeth/weeth-client

Length of output: 9843


🏁 Script executed:

#!/bin/bash
set -euo pipefail

for f in \
  src/components/admin/dues/DuesPageContent.tsx \
  src/components/admin/dues/DuesSettingPageContent.tsx \
  src/components/admin/dues/DuesGenerationFilter.tsx
do
  echo "===== $f ====="
  wc -l "$f"
  cat -n "$f" | sed -n '1,260p'
done

Repository: Team-Weeth/weeth-client

Length of output: 20268


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for member visibility / bank account visibility fields and related dashboard types
rg -n "member-visibility|memberVisibility|isPublic|bankAccountVisible|visible" src types . --glob '!**/*.map' --glob '!**/node_modules/**'

# Inspect the dashboard / dues response types if present
fd -a "dues" src types | sed -n '1,120p'

Repository: Team-Weeth/weeth-client

Length of output: 15840


accountId 변경 시 isPublic을 초기화하세요

useState(true)만 쓰면 같은 훅 인스턴스에서 accountId가 바뀌어도 이전 기수의 토글 값이 그대로 남습니다. DuesPageContent/DuesSettingPageContent처럼 기수 전환이나 지연 로딩으로 accountId가 바뀌는 경로에서는 공개 여부 스위치가 실제 상태와 다르게 보일 수 있으니, 최소한 accountId 변경 시 상태를 리셋하고 서버 값이 생기면 그 값으로 초기화하는 쪽이 안전합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/admin/useDuesVisibilityToggle.ts` around lines 14 - 29,
`useDuesVisibilityToggle` keeps `isPublic` in local state with `useState(true)`,
so when `accountId` changes within the same hook instance the toggle can show a
stale value. Update the hook to reset `isPublic` whenever `accountId` changes
and initialize it from the server-provided visibility once that value is
available, using the existing `useDuesVisibilityToggle` and `handlePublicChange`
flow so `DuesPageContent` and `DuesSettingPageContent` always reflect the
current account’s actual state.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR 테스트 결과

Jest: 통과

🎉 모든 테스트를 통과했습니다!

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

구현한 기능 Preview: https://weeth-ndx4j6krh-weethsite-4975s-projects.vercel.app

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR 검증 결과

TypeScript: 통과
ESLint: 통과
Prettier: 통과
Build: 통과

🎉 모든 검증을 통과했습니다!

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR E2E 테스트 결과

Playwright: 통과

🎉 E2E 테스트를 통과했습니다!

@JIN921 JIN921 merged commit 30a3a2e into develop Jul 6, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📬 API 서버 API 통신 🐞 BugFix Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant