Skip to content

[FE] 어드민 회원관리 페이지 수정, 게시판 익명 기능 추가, 회원가입 버튼 중복 클릭 수정, 로그 표시 수정#301

Merged
discipline24 merged 2 commits intomainfrom
20260312_#288-기능개선관리자-회원관리-ui-변경
Mar 12, 2026

Hidden character warning

The head ref may contain hidden characters: "20260312_#288-\uae30\ub2a5\uac1c\uc120\uad00\ub9ac\uc790-\ud68c\uc6d0\uad00\ub9ac-ui-\ubcc0\uacbd"
Merged

[FE] 어드민 회원관리 페이지 수정, 게시판 익명 기능 추가, 회원가입 버튼 중복 클릭 수정, 로그 표시 수정#301
discipline24 merged 2 commits intomainfrom
20260312_#288-기능개선관리자-회원관리-ui-변경

Conversation

@sangkyu39
Copy link
Contributor

@sangkyu39 sangkyu39 commented Mar 12, 2026

어드민 회원관리 페이지 grade 추가 및 ui 수정
게시판 익명 기능 추가
회원가입 버튼 중복 클릭수정

Summary by CodeRabbit

  • New Features

    • 익명 게시글·댓글 작성 및 익명 옵션 추가
    • 회원 신분 등급 시스템 도입(신입/준정회원/정회원)
    • 관리자 회원 관리에 행위 메뉴(액션 메뉴) 및 등급 변경 모달 추가
  • Improvements

    • 회원가입/인증 중 로딩 상태 및 버튼 비활성화 개선
    • 활동 로그 문구에 사용자 표시 형식 변경(“님이” 추가)
    • 포스트 편집/삭제 메뉴를 작성자 권한에 따라 표시
    • 역할/등급 레이블·뱃지 및 관련 UI 스타일 정리

Copilot AI review requested due to automatic review settings March 12, 2026 06:19
@sangkyu39 sangkyu39 linked an issue Mar 12, 2026 that may be closed by this pull request
@coderabbitai
Copy link

coderabbitai bot commented Mar 12, 2026

Walkthrough

관리자 멤버·대시보드 UI 개선, 신분(grade) 기반 회원 관리 도입, 게시물/댓글 익명 옵션 추가 및 관련 API/페이지/모달·스타일 변경을 포함한 프론트엔드 기능 및 인터페이스 수정 집합입니다.

Changes

Cohort / File(s) Summary
관리자 대시보드 / 활동 로그
frontend/src/components/AdminDashboard/AdminDashboard.jsx, frontend/src/utils/adminHomeData.js
대시보드 역할 레이블 매핑 추가 및 role 정규화; 활동 로그 메시지에 사용자명 뒤에 "님이" 삽입.
관리자 멤버 관리 (로직·API)
frontend/src/components/AdminMemberManage/AdminMemberManage.jsx, frontend/src/utils/adminMembersData.js, frontend/src/utils/adminUserApi.js
신분(grade) 개념(NEW/ASSOCIATE/REGULAR) 도입, 선배 승격 API/함수가 신분 변경으로 대체됨(updateAdminUserGrade / changeAdminMemberGrade).
관리자 멤버 관리 (UI/스타일)
frontend/src/components/AdminMemberManage/AdminMemberManage.module.css, frontend/src/components/AdminMemberManage/AdminMemberManage.jsx
행별 케밥 버튼 액션 메뉴 추가, 신분 컬럼 추가, 테이블 높이/스크롤 조정, 외부 클릭으로 메뉴 닫기 로직 등 UI 변경.
프로필/멤버 표시 변경
frontend/src/components/AdminHome/MemberList.jsx, frontend/src/components/mypage/ProfileCard.jsx
SYSTEM_ADMIN 라벨을 '관리자'로 변경·통일, PENDING_MEMBER 매핑 추가, 역할 표시의 기본값 변경 및 스타일 그룹화 조정.
게시물 익명 기능 (페이지·모달·API)
frontend/src/pages/Board.jsx, frontend/src/components/Board/Modal.jsx, frontend/src/utils/boardApi.js, frontend/src/components/Board/Modal.module.css
Modal에 isAnonymous/setIsAnonymous props 추가 및 UI 체크박스 도입, 게시물 생성 페이로드에 anonymous 포함, 모달 레이어 스타일 조정.
댓글/답글 익명 기능 및 PostDetail 권한
frontend/src/components/Board/PostDetail/CommentSection.jsx, frontend/src/pages/PostDetail.jsx, frontend/src/pages/PostDetail.module.css, frontend/src/components/Board/PostDetail/PostView.jsx
댓글·답글에 익명 체크박스 추가 및 onAddComment/onSubmitReply 시 익명 플래그 전달, PostDetail에서 현재 사용자 조회로 게시물 소유자 판정 후 canManagePost로 편집/삭제 메뉴 조건부 렌더링, 관련 스타일 추가.
회원가입 UX/로딩 개선
frontend/src/components/signup/SignUpForm.jsx
검증/가입 흐름에 별도 abort 컨트롤 및 isCheckingVerification/isSigningUp 로딩 플래그 추가, 중복 요청 방지 및 버튼 상태/레이블 업데이트.

Sequence Diagram

sequenceDiagram
    participant User
    participant Board as Board.jsx
    participant Modal as Modal.jsx
    participant API as boardApi.js
    participant PostDetail as PostDetail.jsx
    participant CommentSection as CommentSection.jsx

    User->>Board: 게시물 작성 모달 열기
    Board->>Modal: 전달(isAnonymous, setIsAnonymous)
    User->>Modal: 익명 체크 후 저장
    Modal->>Board: setIsAnonymous(true)
    Board->>API: createPost(postData + anonymous)
    API-->>Board: 생성 응답

    User->>PostDetail: 상세 보기 진입
    PostDetail->>CommentSection: 댓글 UI 렌더
    User->>CommentSection: 댓글 작성(익명 체크)
    CommentSection->>API: createComment({ text, anonymous })
    API-->>CommentSection: 댓글 생성 응답
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

Suggested Labels

FE

Suggested Reviewers

  • DongEun02
  • gxuoo
  • discipline24

Poem

🐰 케밥을 눌러 메뉴가 탁,
익명으로 쓱쓱, 마음은 착!
신분 바꾸고 라벨도 새로,
대시보드와 댓글이 웃음 소리~
토끼가 축하해요, 훌륭한 변화요! 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경사항의 주요 내용들을 정확하게 반영하고 있습니다. 어드민 회원관리 페이지 수정, 게시판 익명 기능, 회원가입 중복 클릭 수정, 로그 표시 수정 등 핵심 변경사항들이 모두 포함되어 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 20260312_#288-기능개선관리자-회원관리-ui-변경

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 and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

어드민 회원관리 UI를 개선하고(grade/액션 메뉴 등), 게시판에 익명 작성 기능을 추가하며, 회원가입(인증 확인/회원가입) 버튼 중복 클릭을 방지하는 PR입니다.

Changes:

  • 게시글/댓글 익명 작성 옵션 추가 및 관련 UI 반영
  • 어드민 회원관리에서 회원 신분(grade) 변경 기능 및 테이블/액션 메뉴 UI 개선
  • 회원가입 플로우에서 인증 확인/회원가입 버튼 중복 요청 방지 및 문구 개선

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
frontend/src/utils/boardApi.js 게시글/댓글 생성 API에 anonymous 전송 추가
frontend/src/utils/adminUserApi.js 관리자 사용자 grade 변경 API로 교체
frontend/src/utils/adminMembersData.js 관리자 회원 grade 변경 API로 교체
frontend/src/utils/adminHomeData.js 최근 활동 메시지 문구 수정(“님이”)
frontend/src/pages/PostDetail.module.css 댓글/대댓글 작성 영역 레이아웃 및 익명 옵션 스타일 추가
frontend/src/pages/PostDetail.jsx 현재 사용자 조회 및 게시글 관리 가능 여부 계산, 댓글/대댓글 익명 전송
frontend/src/pages/Board.jsx 게시글 작성 시 익명 옵션 상태 추가 및 Modal로 전달
frontend/src/components/signup/SignUpForm.jsx 인증 확인/회원가입 중복 클릭 방지 및 로딩 문구 처리
frontend/src/components/mypage/ProfileCard.jsx 역할 라벨 일부 수정 및 기본 표시값 변경
frontend/src/components/Board/PostDetail/PostView.jsx 게시글 수정/삭제 메뉴를 canManagePost일 때만 노출
frontend/src/components/Board/PostDetail/CommentSection.jsx 댓글/대댓글 작성 시 익명 체크박스 추가
frontend/src/components/Board/Modal.module.css 모달 z-index 조정 및 익명 옵션/액션 row 스타일 추가
frontend/src/components/Board/Modal.jsx 게시글 작성 모달에 익명 체크박스 UI 추가
frontend/src/components/AdminMemberManage/AdminMemberManage.module.css 테이블 스크롤/액션 메뉴(케밥) UI 스타일 추가
frontend/src/components/AdminMemberManage/AdminMemberManage.jsx grade 변경 기능 추가, 케밥 액션 메뉴 도입, role 라벨 정비
frontend/src/components/AdminHome/MemberList.jsx 관리자 역할 라벨 및 뱃지 색상 로직 일부 수정
frontend/src/components/AdminDashboard/AdminDashboard.jsx 대시보드 역할 라벨 normalize 및 활동 로그 문구(“님이”) 수정

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/components/AdminMemberManage/AdminMemberManage.jsx (1)

184-203: ⚠️ Potential issue | 🟠 Major

조기 반환 시 로딩 상태 미해제 가능성

Lines 186-189, 192-195, 198-201에서 유효성 검사 실패 시 return하지만, isChangingById가 이미 true로 설정된 상태입니다. 이 경우 로딩 상태가 해제되지 않아 해당 회원의 버튼이 영구적으로 비활성화될 수 있습니다.

🐛 수정 제안
     try {
       if (type === 'role') {
         if (!ROLE_OPTIONS.includes(value)) {
           window.alert('유효하지 않은 권한입니다.');
+          setIsChangingById((prev) => ({ ...prev, [member.id]: false }));
           return;
         }
         await changeAdminMemberRole({ userId: member.id, role: value });
       } else if (type === 'status') {
         if (!STATUS_OPTIONS.includes(value)) {
           window.alert('유효하지 않은 상태입니다.');
+          setIsChangingById((prev) => ({ ...prev, [member.id]: false }));
           return;
         }
         await changeAdminMemberStatus({ userId: member.id, status: value });
       } else {
         if (!GRADE_OPTIONS.includes(value)) {
           window.alert('유효하지 않은 신분입니다.');
+          setIsChangingById((prev) => ({ ...prev, [member.id]: false }));
           return;
         }
         await changeAdminMemberGrade({ userId: member.id, grade: value });
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/AdminMemberManage/AdminMemberManage.jsx` around lines
184 - 203, Validation returns inside the try block can exit early while
isChangingById remains true; move the validation checks
(ROLE_OPTIONS/STATUS_OPTIONS/GRADE_OPTIONS) to before setting isChangingById, or
ensure isChangingById is cleared on all exits by wrapping the operation in a
try/finally and setting isChangingById[member.id] = false in the finally; apply
this to the code paths around isChangingById, the validation branches, and the
calls to changeAdminMemberRole/changeAdminMemberStatus/changeAdminMemberGrade so
the loading state is always unset on validation failure or after the async call.
🧹 Nitpick comments (2)
frontend/src/components/Board/Modal.module.css (1)

11-11: z-index 계층 구조 확인 필요

z-index: 1200으로 변경하여 Header(1001)보다 위에 표시되는 것은 적절합니다. 다만, CreateSubBoardModal.module.css의 overlay는 여전히 z-index: 1000입니다. 두 모달이 동시에 열리는 시나리오가 있다면 계층 구조가 의도대로인지 확인해 주세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/Board/Modal.module.css` at line 11, The overlay
z-index in CreateSubBoardModal.module.css (currently 1000) is lower than the
Modal.module.css z-index (1200) and Header (1001), which can cause incorrect
stacking when both modals open; update the overlay rule in
CreateSubBoardModal.module.css (the .overlay or equivalent overlay class) to
match or exceed 1200 (or refactor both modal overlays to use a shared CSS
variable/constant so Modal.module.css and CreateSubBoardModal.module.css use the
same stacking value) to ensure the intended stacking order relative to Header
(z-index: 1001).
frontend/src/components/AdminHome/MemberList.jsx (1)

1-8: ROLE_LABELS 상수의 중복 정의 - 중앙화 권장

ROLE_LABELSMemberList.jsx, AdminMemberManage.jsx, AdminDashboard.jsx 세 파일에 독립적으로 정의되어 있습니다. 향후 역할 레이블 변경 시 동기화 누락 위험이 있습니다.

공유 상수 파일(예: src/constants/roleLabels.js)로 추출하는 것을 권장합니다.

♻️ 제안된 중앙화 예시
// src/constants/roleLabels.js
export const ROLE_LABELS = {
  SYSTEM_ADMIN: '관리자',
  PRESIDENT: '회장',
  VICE_PRESIDENT: '부회장',
  TEAM_LEADER: '팀장',
  TEAM_MEMBER: '일반',
  PENDING_MEMBER: '대기회원',
};

그 후 각 컴포넌트에서 import하여 사용:

import { ROLE_LABELS } from '../../constants/roleLabels';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/AdminHome/MemberList.jsx` around lines 1 - 8,
ROLE_LABELS is duplicated across MemberList.jsx, AdminMemberManage.jsx, and
AdminDashboard.jsx; extract it into a single shared constant (e.g., create
src/constants/roleLabels.js exporting ROLE_LABELS) and replace the local
definitions in those components with an import (import { ROLE_LABELS } from
'...'). Update any references to ROLE_LABELS in MemberList.jsx,
AdminMemberManage.jsx, and AdminDashboard.jsx to use the imported constant and
remove the duplicated local definitions so changes to labels are centralized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/components/signup/SignUpForm.jsx`:
- Around line 309-311: The shared abortRef.current is being reused by multiple
handlers so one request can cancel another; update the handlers that call
abortRef.current.abort() (the signup submission, verification check, and resend
verification handlers) to use separate AbortController instances per request
instead of a single shared abortRef, e.g., create a new AbortController inside
each handler (or maintain distinct refs like
abortRefVerify/abortRefResend/abortRefSignup) and pass that controller.signal to
the fetch/axios call, and only call abort() on that handler's controller so
other in-flight actions are not cancelled.

In `@frontend/src/pages/PostDetail.jsx`:
- Around line 88-104: The ownership check currently falls back to comparing
names which can misgrant access; update the logic in PostDetail.jsx to determine
isPostOwner using only ID comparison: derive postAuthorId (post?.user?.id ||
post?.userId || post?.createdBy?.id) and currentUserId (currentUser?.id ||
currentUser?.userId) and compute isPostOwner = Boolean(post && currentUser &&
postAuthorId && currentUserId && postAuthorId === currentUserId). Remove the
name-based fallbacks (postAuthorName/currentUserName and the postAuthorName ===
currentUserName branch) or gate them behind an explicit, documented fallback
flag if backend sometimes omits IDs. Ensure any UI/logic that relied on
name-based ownership is updated accordingly.

---

Outside diff comments:
In `@frontend/src/components/AdminMemberManage/AdminMemberManage.jsx`:
- Around line 184-203: Validation returns inside the try block can exit early
while isChangingById remains true; move the validation checks
(ROLE_OPTIONS/STATUS_OPTIONS/GRADE_OPTIONS) to before setting isChangingById, or
ensure isChangingById is cleared on all exits by wrapping the operation in a
try/finally and setting isChangingById[member.id] = false in the finally; apply
this to the code paths around isChangingById, the validation branches, and the
calls to changeAdminMemberRole/changeAdminMemberStatus/changeAdminMemberGrade so
the loading state is always unset on validation failure or after the async call.

---

Nitpick comments:
In `@frontend/src/components/AdminHome/MemberList.jsx`:
- Around line 1-8: ROLE_LABELS is duplicated across MemberList.jsx,
AdminMemberManage.jsx, and AdminDashboard.jsx; extract it into a single shared
constant (e.g., create src/constants/roleLabels.js exporting ROLE_LABELS) and
replace the local definitions in those components with an import (import {
ROLE_LABELS } from '...'). Update any references to ROLE_LABELS in
MemberList.jsx, AdminMemberManage.jsx, and AdminDashboard.jsx to use the
imported constant and remove the duplicated local definitions so changes to
labels are centralized.

In `@frontend/src/components/Board/Modal.module.css`:
- Line 11: The overlay z-index in CreateSubBoardModal.module.css (currently
1000) is lower than the Modal.module.css z-index (1200) and Header (1001), which
can cause incorrect stacking when both modals open; update the overlay rule in
CreateSubBoardModal.module.css (the .overlay or equivalent overlay class) to
match or exceed 1200 (or refactor both modal overlays to use a shared CSS
variable/constant so Modal.module.css and CreateSubBoardModal.module.css use the
same stacking value) to ensure the intended stacking order relative to Header
(z-index: 1001).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 44b9eda2-82d3-4341-9727-e60ae8680fdf

📥 Commits

Reviewing files that changed from the base of the PR and between f910327 and 8f0c787.

📒 Files selected for processing (17)
  • frontend/src/components/AdminDashboard/AdminDashboard.jsx
  • frontend/src/components/AdminHome/MemberList.jsx
  • frontend/src/components/AdminMemberManage/AdminMemberManage.jsx
  • frontend/src/components/AdminMemberManage/AdminMemberManage.module.css
  • frontend/src/components/Board/Modal.jsx
  • frontend/src/components/Board/Modal.module.css
  • frontend/src/components/Board/PostDetail/CommentSection.jsx
  • frontend/src/components/Board/PostDetail/PostView.jsx
  • frontend/src/components/mypage/ProfileCard.jsx
  • frontend/src/components/signup/SignUpForm.jsx
  • frontend/src/pages/Board.jsx
  • frontend/src/pages/PostDetail.jsx
  • frontend/src/pages/PostDetail.module.css
  • frontend/src/utils/adminHomeData.js
  • frontend/src/utils/adminMembersData.js
  • frontend/src/utils/adminUserApi.js
  • frontend/src/utils/boardApi.js

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/components/signup/SignUpForm.jsx (1)

122-140: ⚠️ Potential issue | 🟡 Minor

abort 발생 시 오류 토스트가 표시되고 로딩 상태가 잘못 초기화됩니다.

사용자가 이전 요청이 진행 중일 때 "재전송"을 클릭하면:

  1. 이전 요청이 abort되어 axios 인터셉터에서 오류로 처리됨
  2. 이전 요청의 catch 블록이 "오류가 발생했습니다." 토스트를 표시 (혼란스러운 UX)
  3. 이전 요청의 finally 블록이 isSending = false로 설정하여 새 요청이 진행 중인데도 버튼이 활성화됨 (기능 버그)

handleCheckVerificationNumber처럼 조기 반환 가드를 추가하거나, 활성 요청 추적 방식을 개선해야 합니다.

🛠️ 제안 수정안
   const handleSendVerificationNumber = async (e) => {
     e.preventDefault();

+    if (isSending) {
+      return;
+    }

     abortRefSend.current?.abort();
     abortRefSend.current = new AbortController();
+    const currentController = abortRefSend.current;

     setIsSending(true);

     try {
-      await sendVerificationNumber({ email }, abortRefSend.current.signal);
+      await sendVerificationNumber({ email }, currentController.signal);
       setVerificationSent(true);
       toast.success('인증번호가 발송되었습니다.');
     } catch (error) {
+      if (!error.status) {
+        return; // abort된 요청은 무시
+      }
       console.log(error);
       toast.error('오류가 발생했습니다.');
     } finally {
-      setIsSending(false);
+      if (abortRefSend.current === currentController) {
+        setIsSending(false);
+      }
     }
   };

error.status가 undefined인 경우는 abort된 요청이므로 에러 메시지 없이 무시할 수 있습니다. 조기 반환 가드(if (isSending) return;)를 추가하면 더욱 명확합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/signup/SignUpForm.jsx` around lines 122 - 140, The
send flow in handleSendVerificationNumber incorrectly treats aborted requests as
errors and can reset isSending for a newer request; fix by adding an early guard
(if (isSending) return;) at the top of handleSendVerificationNumber, create and
capture a local AbortController (e.g., const controller = new AbortController())
before aborting the previous one, assign abortRefSend.current = controller, pass
controller.signal to sendVerificationNumber, and in the catch block ignore
aborts by checking controller.signal.aborted (or error.name === 'CanceledError')
so you don't call toast.error for aborted requests; in finally only call
setIsSending(false) if abortRefSend.current === controller to avoid turning off
the loading state for a newer request.
🧹 Nitpick comments (2)
frontend/src/components/signup/SignUpForm.jsx (2)

142-165: handleSendVerificationNumber와 동일한 abort 처리 문제가 있습니다.

early return guard가 있지만, abort된 요청의 finally 블록이 새 요청 진행 중에 isCheckingVerificationfalse로 설정하는 문제가 동일하게 존재합니다. 위의 제안과 같은 패턴으로 수정을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/signup/SignUpForm.jsx` around lines 142 - 165, The
abort handling in handleCheckVerificationNumber has the same race as
handleSendVerificationNumber: the finally block unconditionally calls
setIsCheckingVerification(false) even if a newer request has replaced
abortRefCheck.current; fix by capturing the controller reference at start (const
controller = new AbortController(); abortRefCheck.current = controller) and in
the finally only call setIsCheckingVerification(false) if abortRefCheck.current
=== controller (and similarly only call setVerificationChecked(true) when the
controller matches), so use the unique symbols handleCheckVerificationNumber,
abortRefCheck, isCheckingVerification, setIsCheckingVerification, and
setVerificationChecked to implement this guard.

167-204: 동일한 abort 처리 패턴 적용 권장

회원가입 성공 시 바로 네비게이션되므로 문제 발생 가능성은 낮지만, 일관성을 위해 동일한 abort 처리 패턴을 적용하는 것이 좋습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/signup/SignUpForm.jsx` around lines 167 - 204, In
handleSignUp, after a successful await signUp(...) and before nav('/login'),
clear the controller reference (e.g., set abortRefSignUp.current = null or
undefined) so the same abort-handling pattern used elsewhere is applied and the
pending controller won't be accidentally reused/aborted; keep
abortRefSignUp.current?.abort() at the start and ensure signUp, abortRefSignUp,
and nav are the referenced symbols you update.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@frontend/src/components/signup/SignUpForm.jsx`:
- Around line 122-140: The send flow in handleSendVerificationNumber incorrectly
treats aborted requests as errors and can reset isSending for a newer request;
fix by adding an early guard (if (isSending) return;) at the top of
handleSendVerificationNumber, create and capture a local AbortController (e.g.,
const controller = new AbortController()) before aborting the previous one,
assign abortRefSend.current = controller, pass controller.signal to
sendVerificationNumber, and in the catch block ignore aborts by checking
controller.signal.aborted (or error.name === 'CanceledError') so you don't call
toast.error for aborted requests; in finally only call setIsSending(false) if
abortRefSend.current === controller to avoid turning off the loading state for a
newer request.

---

Nitpick comments:
In `@frontend/src/components/signup/SignUpForm.jsx`:
- Around line 142-165: The abort handling in handleCheckVerificationNumber has
the same race as handleSendVerificationNumber: the finally block unconditionally
calls setIsCheckingVerification(false) even if a newer request has replaced
abortRefCheck.current; fix by capturing the controller reference at start (const
controller = new AbortController(); abortRefCheck.current = controller) and in
the finally only call setIsCheckingVerification(false) if abortRefCheck.current
=== controller (and similarly only call setVerificationChecked(true) when the
controller matches), so use the unique symbols handleCheckVerificationNumber,
abortRefCheck, isCheckingVerification, setIsCheckingVerification, and
setVerificationChecked to implement this guard.
- Around line 167-204: In handleSignUp, after a successful await signUp(...) and
before nav('/login'), clear the controller reference (e.g., set
abortRefSignUp.current = null or undefined) so the same abort-handling pattern
used elsewhere is applied and the pending controller won't be accidentally
reused/aborted; keep abortRefSignUp.current?.abort() at the start and ensure
signUp, abortRefSignUp, and nav are the referenced symbols you update.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c7313b9e-b282-474d-9c33-8add1fb0b608

📥 Commits

Reviewing files that changed from the base of the PR and between 8f0c787 and bb6faff.

📒 Files selected for processing (2)
  • frontend/src/components/signup/SignUpForm.jsx
  • frontend/src/pages/PostDetail.jsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/pages/PostDetail.jsx

Copy link
Contributor

@discipline24 discipline24 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다~

@discipline24 discipline24 merged commit 9e3b2da into main Mar 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🚀 [기능개선][관리자] 회원관리 UI 변경 ❗ [버그][회원가입] 버튼 중복 클릭 방지 처리 요청

3 participants