Skip to content

[FEAT] 온보딩 페이지 퍼블리싱#22

Merged
KOJ50 merged 16 commits into
mainfrom
feature/#19-login-signup-ui
May 30, 2026
Merged

[FEAT] 온보딩 페이지 퍼블리싱#22
KOJ50 merged 16 commits into
mainfrom
feature/#19-login-signup-ui

Conversation

@KOJ50

@KOJ50 KOJ50 commented May 28, 2026

Copy link
Copy Markdown
Contributor

📢 PR 유형

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

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

📌 관련 이슈번호


✅ Key Changes

파일 구조

  • 컴포넌트에 회원가입 폴더 추가 - 유저 타입 버튼 파일 생성
  • 공통 페이지에서 유저 타입 선택
  • 유저 타입에 따른 회원가입 폴더 내 디자이너/강사 폴더로 구분

회원가입

  • 회원가입 아이디 입력의 경우 한글을 사용할 수 없도록 막음
  • 아이디 입력 시, 6자가 넘지 않으면 오류 메세지를 띄우고 중복확인 버튼을 활성화하지 않도록 추가적으로 설정
  • 비밀번호 입력 시, 조건에 맞지 않으면 조건을 알려주도록 에러메세지 추가하여 기능 구현
  • 비밀번호 확인 입력 시, 비밀번호가 조건에 맞지 않은 상태에서 비밀번호 확인이 입력되면 “비밀번호가 형식에 맞지 않습니다” 에러메세지 추가
  • 이메일 입력 시, 이메일 형식이 맞지 않으면 에러 메세지를 보여주고 인증 번호 받기 버튼 또한 작동하지 않음
  • 인증번호 받기 버튼을 누르면 인증번호 입력 input을 생성하고 타이머 작동
  • 타이머가 작동되는 동안 인증번호 받기 버튼 비활성화
  • 인증번호 입력 input 은 인증번호가 올바르지 않으면 계속 에러 메세지 보여줌. 백엔드에서 인증번호를 4자리로 설정하였으나 입력 input 에 글자 수 제한을 걸지 않음
  • 인증번호가 올바르면 바로 체크표시를 하며 타이머 동작을 멈추고 인증번호 입력 input 를 입력 그대로 비활성화
  • 회원가입이 완료되면 로그인 페이지로 이동하도록 구현
  • 아이디 및 비밀번호, 인증번호는 목데이터 형태로 작성하여 확인가능. 아이디: test1234 비밀번호: test1234 인증번호: 1234
  • 디자이너 step3의 파일 드래그앤드롭 내부의 설명은 기존 컴포넌트의 있는 그대로 사용하였습니다. .pdf .png에 대한 설명이 피그마에 없어 일단 기존 컴포넌트를 이용하였고, pdf와 png만 업로드 허용

📸 스크린샷 or 실행영상

1.mov
2.mov
3.mov

🎸 기타 사항 or 추가 코멘트

  • 로그인 성공 시, 이동 페이지를 어디로 어떻게 설정할지 아직 정하지 않았습니다. API 연동 혹은 코드 리팩토링 과정에서 추가해야할 것 같습니다.
  • 파일 및 폴더 구조에 대한 조언이 필요합니다. 현재 제가 각 페이지에 맞게 구성하기 위해 이와 같이 구성했지만 예외처리 등 리팩토링 및 수정 과정에서 수정하겠습니다.
  • 화면에서 스크롤이 발생하는데 이는 가운데 정렬을 하며 발생하는 것 같습니다. 5월 28일 목요일 일자로 디자인팀에 해당 내용은 전달되긴 했습니다.
  • 기존에 만들기로 한 파일 모달은 사용 위치가 명확하지 않아 보류하였습니다. (필요 시 제작하겠습니닷!)

Summary by CodeRabbit

릴리스 노트

  • New Features
    • 로그인 페이지 추가: ID/비밀번호 입력 및 회원가입 연결
    • 회원가입 프로세스 구현: 디자이너와 강사 유형별 3단계 가입 흐름
    • 회원가입 시 이메일 인증, 약관 동의, 계좌 정보 입력 기능
    • 디자이너 회원가입에 포트폴리오 파일 업로드 기능 추가
    • 은행 선택 드롭다운 컴포넌트 추가
    • 헤더 네비게이션에 로그인/회원가입 링크 추가

Review Change Stack

@KOJ50 KOJ50 self-assigned this May 28, 2026
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: bd33aedd-e370-45ef-bff4-874de1584fec

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

로그인 페이지와 회원가입 선택 화면을 추가하고, 디자이너/강사 회원가입의 3단계/2단계 플로우를 구현합니다. 회원가입 검증, 이메일 인증 타이머, 약관 관리를 위한 상수와 상태 관리 훅을 제공하며, 은행 선택 드롭다운, 타입 버튼 등의 공통 UI 컴포넌트를 추가합니다.

Changes

온보딩 페이지 퍼블리싱

Layer / File(s) Summary
로그인 및 회원가입 진입점
src/app/login/page.tsx, src/app/signup/page.tsx, src/components/common/Header.tsx
로그인 ID/비밀번호 입력 페이지, 회원가입 타입(디자이너/강사) 선택 페이지를 추가하고, Header의 로그인/회원가입 버튼을 Link 기반 라우팅으로 변경합니다.
회원가입 공통 인프라: 상수, 검증, 상태 관리
src/constants/signup.ts, src/lib/hooks/useSignupStep2Form.ts
회원가입 길이 제한, 에러 메시지, 이메일 정규식, 은행 옵션, 디자이너/강사 약관 텍스트를 상수로 정의하고, Step2의 ID/비밀번호/이메일 검증, 인증 타이머, 상태 관리를 useSignupStep2Form 훅에 집중화합니다.
회원가입 공통 UI 컴포넌트
src/components/signup/UserTypeBtn.tsx, src/components/common/dropdown/BankDropdown.tsx, src/components/common/input/InputField.tsx, src/assets/icons/index.ts
회원가입 타입 버튼, 은행 드롭다운(선택/비선택 모드, 키보드/외부 클릭 닫기)을 추가하고, InputField 아이콘 버튼 스타일을 조정하며 Step 및 UserType 아이콘을 export합니다.
디자이너 회원가입 Step1: 기본 정보 및 약관
src/app/signup/designer/step1/page.tsx
이름, 전화번호 입력과 포맷 검증, DESIGNER_TERMS 기반 약관 동의 UI(전체/개별 토글, 상세 모달), 다음 버튼 활성화 조건을 구현합니다.
디자이너 회원가입 Step2: 계정 정보 및 인증
src/app/signup/designer/step2/page.tsx
useSignupStep2Form을 바인딩하여 ID 중복확인, 비밀번호/확인, 이메일 인증번호 요청 및 타이머, 인증 코드 입력(조건부 렌더링)을 구성합니다.
디자이너 회원가입 Step3: 결제 정보 및 포트폴리오
src/app/signup/designer/step3/page.tsx
BankDropdown으로 은행 선택, 계좌번호/예금주 입력, 포트폴리오 파일 업로드(.pdf/.png 확장자만, 최대 3개)를 상태로 관리하고 제출 활성화 조건을 제어합니다.
강사 회원가입 Step1: 기본 정보 및 약관
src/app/signup/instructor/step1/page.tsx
디자이너 Step1과 동일한 구조로 이름, 전화번호, INSTRUCTOR_TERMS 기반 약관 동의, 모달, 다음 활성화 조건을 구현합니다.
강사 회원가입 Step2: 계정 정보 및 인증
src/app/signup/instructor/step2/page.tsx
useSignupStep2Form을 바인딩하여 ID 중복확인, 비밀번호, 이메일 인증번호 요청, 타이머, 인증 코드 입력(조건부)을 강사용으로 구성합니다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Ditda-Official/Ditda-Frontend#18: 디자이너 Step3의 포트폴리오 업로드 기능에서 사용하는 FileUpload 컴포넌트와 useUploadedFiles 훅이 이전 PR에서 추가되었으므로 직접 의존합니다.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 온보딩 페이지 구현이라는 주요 변경사항을 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed PR은 연결된 이슈 #19의 모든 요구사항(로그인 페이지, 회원가입 사용자 유형 선택, 강사/디자이너 단계 1-2, 디자이너 단계 3 구현)을 충족합니다.
Out of Scope Changes check ✅ Passed Header 컴포넌트의 Link 교체는 로그인/회원가입 라우팅 구현과 직접 관련되며, InputField 클래스 수정은 UI 일관성 유지로 범위 내입니다.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/#19-login-signup-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.

@github-actions

Copy link
Copy Markdown

@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: 10

🧹 Nitpick comments (3)
src/components/common/dropdown/BankDropdown.tsx (1)

97-97: ⚡ Quick win

인라인 style 대신 Tailwind 클래스로 통일하는 게 좋습니다

maxHeight를 인라인으로 주입하기보다 Tailwind 유틸리티(또는 해당 값을 감싼 유틸 클래스)로 맞추면 스타일 규칙 일관성이 좋아집니다.

As per coding guidelines, "인라인 style 속성보다 Tailwind 클래스 사용을 권장해주세요."

🤖 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/common/dropdown/BankDropdown.tsx` at line 97, The div in
BankDropdown uses an inline style (style={{ maxHeight: BANK_DROPDOWN_MAX_HEIGHT
}}) which violates the guideline; remove the inline style and apply a Tailwind
utility or a small CSS utility class instead — either convert the constant
BANK_DROPDOWN_MAX_HEIGHT to a matching Tailwind class (e.g., max-h-... or
arbitrary value like max-h-[...]), or create a dedicated utility class (e.g.,
.bank-dropdown-max-h) and add that class to the div with the existing
"overflow-y-auto" so all styling is controlled via classes in the BankDropdown
component.
src/app/signup/designer/step1/page.tsx (1)

173-185: ⚡ Quick win

약관 모달에 기본 대화상자 접근성 속성이 필요합니다.

스크린리더/키보드 사용자 관점에서 role="dialog", aria-modal, 제목 연결(aria-labelledby), 닫기 버튼 aria-label을 추가하는 편이 좋습니다.

제안 수정
-          <section
+          <section
+            role="dialog"
+            aria-modal="true"
+            aria-labelledby="designer-terms-modal-title"
             className="rounded-12 flex h-[792px] w-[612px] flex-col gap-6 bg-white px-6 py-8"
             onClick={event => event.stopPropagation()}
           >
             <header className="border-gray-20 flex items-center justify-between gap-4">
-              <h2 className="text-heading2-sb text-black">{selectedTerm.modalTitle}</h2>
+              <h2 id="designer-terms-modal-title" className="text-heading2-sb text-black">
+                {selectedTerm.modalTitle}
+              </h2>
               <button
                 type="button"
+                aria-label="약관 모달 닫기"
                 className="text-gray-80 flex size-6 shrink-0 cursor-pointer items-center justify-center hover:text-black"
                 onClick={() => setSelectedTermId(null)}
               >
🤖 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/app/signup/designer/step1/page.tsx` around lines 173 - 185, The modal
<section> is missing basic dialog accessibility attributes; add role="dialog"
and aria-modal="true" to the section, give the <h2> (selectedTerm.modalTitle) a
unique id (e.g., modal-title-<termId>) and set aria-labelledby on the section to
that id, and add an accessible label to the Close button (e.g.,
aria-label="Close dialog") where setSelectedTermId(null) is used; ensure the
existing onClick={event => event.stopPropagation()} remains and that CloseIcon
remains unchanged.
src/app/signup/designer/step3/page.tsx (1)

69-75: ⚡ Quick win

계좌번호 입력에 숫자 키패드 힌트를 추가하면 UX가 좋아집니다.

숫자만 허용 중이므로 inputMode="numeric"를 주면 모바일 입력이 더 자연스럽습니다.

🤖 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/app/signup/designer/step3/page.tsx` around lines 69 - 75, Add
inputMode="numeric" to the InputField usage to hint numeric keyboard on mobile:
update the JSX where InputField is rendered (the instance with label="계좌번호",
value={accountNumber}, onChange={handleAccountNumberChange}) to include
inputMode="numeric"; if InputField doesn't accept or forward unknown props,
update the InputField component's props interface to include inputMode?: string
and forward it to the underlying <input> (or native input element) so the prop
actually takes effect.
🤖 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/app/signup/designer/step1/page.tsx`:
- Line 50: isNextEnabled currently only checks phoneNumber existence so
incomplete inputs like "010-1" pass; update the condition to validate that
phoneNumber contains exactly 11 digits by stripping non-digits and checking
length === 11 (e.g., compute digits = phoneNumber.replace(/\D/g, '').length) and
use that in the isNextEnabled expression along with the existing name.trim() and
isAllAgreed checks so the next button only enables when phoneNumber has 11
numeric digits.

In `@src/app/signup/designer/step2/page.tsx`:
- Around line 150-155: The submit Button currently always invokes
router.push("/signup/designer/step3") even when form.isSubmitEnabled is false;
update the onClick handler on the Button (and/or add a guard in the surrounding
click handler) to only call router.push when form.isSubmitEnabled is true (e.g.,
onClick={() => { if (!form.isSubmitEnabled) return;
router.push("/signup/designer/step3"); }}), matching the conditional guard used
in Step1/Step3 flows and preventing bypass of Step2 validation; reference the
Button component, its onClick and router.push usage to locate the change.

In `@src/app/signup/designer/step3/page.tsx`:
- Around line 43-49: The handler handlePortfolioFilesAdded currently only
filters by extension and count; add a size check to enforce the 30MB limit by
filtering files with file.size <= PORTFOLIO_MAX_FILE_SIZE (or define
PORTFOLIO_MAX_FILE_SIZE = 30 * 1024 * 1024 if missing) before slicing by
remainingCount, so only files that pass isPortfolioFile and the size constraint
are passed to handleFilesAdded; ensure any user-facing message/constant used
elsewhere is consistent with this limit.

In `@src/app/signup/instructor/step1/page.tsx`:
- Around line 169-186: Wrap the modal semantics onto the modal container: add
role="dialog" and aria-modal="true" to the section element (or outer modal
container) that renders the content, link the heading used by
selectedTerm.modalTitle via an id (e.g., set an id on the h2 and reference it
with aria-labelledby on the dialog) so the title is announced, and give the
CloseIcon button an accessible name (aria-label or aria-labelledby) instead of
relying on visual-only content; adjust references around setSelectedTermId,
selectedTerm.modalTitle and CloseIcon to locate and update the attributes.
- Around line 87-108: The term-toggle buttons currently only change visually;
update the button elements used for "모두 동의합니다" (onClick=toggleAllTerms, using
isAllAgreed) and each term button (onClick={() => toggleTerm(id)}, using
checkedTerms[id]) to include role="checkbox" and aria-checked set to the boolean
state (aria-checked={isAllAgreed} and aria-checked={checkedTerms[id]}
respectively), so assistive tech receives the checked state; ensure these
attributes are applied to the same element that handles the click (the button
wrapping the CheckIcon) and keep existing handlers (toggleAllTerms/toggleTerm)
and visual markup unchanged.

In `@src/app/signup/page.tsx`:
- Around line 37-45: The icons for the user-type cards are swapped: the card
with type="디자이너" currently uses UserTypeInstructorIcon and the card with
type="강사/교사" uses UserTypeDesignerIcon; update the JSX so the card whose type
prop is "designer" uses UserTypeDesignerIcon and the card whose type prop is
"instructor" uses UserTypeInstructorIcon, and verify each card's isSelected
(selectedType === "designer"/"instructor") and onClick
(setSelectedType("designer"/"instructor")) still match their respective type
strings; check the UserTypeBtn instances, UserTypeDesignerIcon,
UserTypeInstructorIcon, selectedType and setSelectedType references to make the
swap.

In `@src/components/common/Header.tsx`:
- Around line 31-38: The login/signup links are only rendered when isLoggedIn is
false but that flag is initialized to true causing the CTAs to be hidden; update
the Header component to derive authentication from the real auth state (e.g.,
useAuth(), authContext, or a prop like isAuthenticated) or, if this is a
temporary stub, change the initial value of isLoggedIn to false so the
onboarding CTA appears by default; locate the isLoggedIn variable/state used in
Header and adjust its initialization or replace it with the real auth check so
the Link elements for "/login" and "/signup" render correctly.

In `@src/constants/signup.ts`:
- Around line 100-103: The object with id "2" has mismatched text between label
("강사 약관 2") and modalTitle ("강사 약관 제목 3"); update the modalTitle in the signup
constants entry (the object containing id: "2", label, modalTitle, content) so
its modalTitle matches the label (e.g., "강사 약관 2") to avoid user confusion.

In `@src/lib/hooks/useSignupStep2Form.ts`:
- Around line 99-103: handleUserIdCheck currently calls
checkSignupUserIdAvailability(userId) and sets setUserIdCheckStatus based solely
on availability, allowing empty/short IDs to be marked "available"; update
handleUserIdCheck to first validate the userId length (use the same length rules
used elsewhere in this hook) and early-return or set status to "invalid" when it
fails, only calling checkSignupUserIdAvailability if length is valid; also
update the isSubmitEnabled logic to include the same length validation (in
addition to name/email/password checks and the userIdCheckStatus) so submission
cannot be enabled for empty/short IDs. Ensure you reference handleUserIdCheck,
checkSignupUserIdAvailability, setUserIdCheckStatus and the isSubmitEnabled
computation when making these changes.
- Around line 125-133: handleVerificationCodeChange currently sets verified
purely on code match, allowing success after the timer expires; update the
handler to also check the remaining timer before marking verified: after
computing nextCode and calling setVerificationCode, only call
setEmailVerificationStatus("verified") and setVerificationTimer(0) if
nextCode.trim() === SIGNUP_MOCK_EMAIL_VERIFICATION_CODE AND the
verificationTimer (or a derived remaining time state) indicates the timer has
not expired (e.g., verificationTimer > 0); if expired, ensure you reject the
match path (do not change status) and optionally set an expired state.

---

Nitpick comments:
In `@src/app/signup/designer/step1/page.tsx`:
- Around line 173-185: The modal <section> is missing basic dialog accessibility
attributes; add role="dialog" and aria-modal="true" to the section, give the
<h2> (selectedTerm.modalTitle) a unique id (e.g., modal-title-<termId>) and set
aria-labelledby on the section to that id, and add an accessible label to the
Close button (e.g., aria-label="Close dialog") where setSelectedTermId(null) is
used; ensure the existing onClick={event => event.stopPropagation()} remains and
that CloseIcon remains unchanged.

In `@src/app/signup/designer/step3/page.tsx`:
- Around line 69-75: Add inputMode="numeric" to the InputField usage to hint
numeric keyboard on mobile: update the JSX where InputField is rendered (the
instance with label="계좌번호", value={accountNumber},
onChange={handleAccountNumberChange}) to include inputMode="numeric"; if
InputField doesn't accept or forward unknown props, update the InputField
component's props interface to include inputMode?: string and forward it to the
underlying <input> (or native input element) so the prop actually takes effect.

In `@src/components/common/dropdown/BankDropdown.tsx`:
- Line 97: The div in BankDropdown uses an inline style (style={{ maxHeight:
BANK_DROPDOWN_MAX_HEIGHT }}) which violates the guideline; remove the inline
style and apply a Tailwind utility or a small CSS utility class instead — either
convert the constant BANK_DROPDOWN_MAX_HEIGHT to a matching Tailwind class
(e.g., max-h-... or arbitrary value like max-h-[...]), or create a dedicated
utility class (e.g., .bank-dropdown-max-h) and add that class to the div with
the existing "overflow-y-auto" so all styling is controlled via classes in the
BankDropdown component.
🪄 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 Plus

Run ID: e5f41130-a22e-44e5-9b1a-d7d694c1f936

📥 Commits

Reviewing files that changed from the base of the PR and between 9411ead and e19a069.

⛔ Files ignored due to path filters (7)
  • src/assets/icons/icon_step_one_designer.svg is excluded by !**/*.svg
  • src/assets/icons/icon_step_one_instructor.svg is excluded by !**/*.svg
  • src/assets/icons/icon_step_three_designer.svg is excluded by !**/*.svg
  • src/assets/icons/icon_step_two_designer.svg is excluded by !**/*.svg
  • src/assets/icons/icon_step_two_instructor.svg is excluded by !**/*.svg
  • src/assets/icons/icon_user_type_designer.svg is excluded by !**/*.svg
  • src/assets/icons/icon_user_type_instructor.svg is excluded by !**/*.svg
📒 Files selected for processing (14)
  • src/app/login/page.tsx
  • src/app/signup/designer/step1/page.tsx
  • src/app/signup/designer/step2/page.tsx
  • src/app/signup/designer/step3/page.tsx
  • src/app/signup/instructor/step1/page.tsx
  • src/app/signup/instructor/step2/page.tsx
  • src/app/signup/page.tsx
  • src/assets/icons/index.ts
  • src/components/common/Header.tsx
  • src/components/common/dropdown/BankDropdown.tsx
  • src/components/common/input/InputField.tsx
  • src/components/signup/UserTypeBtn.tsx
  • src/constants/signup.ts
  • src/lib/hooks/useSignupStep2Form.ts


const selectedTerm = DESIGNER_TERMS.find(({ id }) => id === selectedTermId);
const isAllAgreed = DESIGNER_TERMS.every(({ id }) => checkedTerms[id]);
const isNextEnabled = isAllAgreed && name.trim().length > 0 && phoneNumber.trim().length > 0;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

전화번호 미완성 상태에서도 다음 단계로 진행됩니다.

현재 isNextEnabled가 전화번호의 “존재 여부”만 확인해서 010-1 같은 입력도 통과합니다. 최소한 숫자 11자리 완성 여부로 게이트하는 게 안전합니다.

제안 수정
-  const isNextEnabled = isAllAgreed && name.trim().length > 0 && phoneNumber.trim().length > 0;
+  const phoneDigits = phoneNumber.replace(/\D/g, "");
+  const isNextEnabled =
+    isAllAgreed &&
+    name.trim().length > 0 &&
+    phoneDigits.length === SIGNUP_MAX_PHONE_NUMBER_LENGTH;
🤖 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/app/signup/designer/step1/page.tsx` at line 50, isNextEnabled currently
only checks phoneNumber existence so incomplete inputs like "010-1" pass; update
the condition to validate that phoneNumber contains exactly 11 digits by
stripping non-digits and checking length === 11 (e.g., compute digits =
phoneNumber.replace(/\D/g, '').length) and use that in the isNextEnabled
expression along with the existing name.trim() and isAllAgreed checks so the
next button only enables when phoneNumber has 11 numeric digits.

Comment thread src/app/signup/designer/step2/page.tsx Outdated
Comment on lines +150 to +155
<Button
className="w-[232px]"
type="button"
variant={form.isSubmitEnabled ? "medium_primary" : "medium_disabled"}
onClick={() => router.push("/signup/designer/step3")}
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

제출 조건이 충족되지 않아도 Step3로 이동됩니다.

Line 154에서 항상 라우팅해서 Step2 검증을 우회할 수 있습니다. Step1/Step3처럼 조건 가드를 넣어 주세요.

제안 수정
               <Button
                 className="w-[232px]"
                 type="button"
                 variant={form.isSubmitEnabled ? "medium_primary" : "medium_disabled"}
-                onClick={() => router.push("/signup/designer/step3")}
+                onClick={() => {
+                  if (form.isSubmitEnabled) router.push("/signup/designer/step3");
+                }}
               >
                 다음
               </Button>
📝 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.

Suggested change
<Button
className="w-[232px]"
type="button"
variant={form.isSubmitEnabled ? "medium_primary" : "medium_disabled"}
onClick={() => router.push("/signup/designer/step3")}
>
<Button
className="w-[232px]"
type="button"
variant={form.isSubmitEnabled ? "medium_primary" : "medium_disabled"}
onClick={() => {
if (form.isSubmitEnabled) router.push("/signup/designer/step3");
}}
>
🤖 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/app/signup/designer/step2/page.tsx` around lines 150 - 155, The submit
Button currently always invokes router.push("/signup/designer/step3") even when
form.isSubmitEnabled is false; update the onClick handler on the Button (and/or
add a guard in the surrounding click handler) to only call router.push when
form.isSubmitEnabled is true (e.g., onClick={() => { if (!form.isSubmitEnabled)
return; router.push("/signup/designer/step3"); }}), matching the conditional
guard used in Step1/Step3 flows and preventing bypass of Step2 validation;
reference the Button component, its onClick and router.push usage to locate the
change.

Comment on lines +43 to +49
const handlePortfolioFilesAdded = (files: File[]) => {
const remainingCount = PORTFOLIO_MAX_FILE_COUNT - uploadedFiles.length;
if (remainingCount <= 0) return;

const portfolioFiles = files.filter(isPortfolioFile).slice(0, remainingCount);
if (portfolioFiles.length > 0) handleFilesAdded(portfolioFiles);
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

포트폴리오 파일 크기(30MB) 제한 검증이 누락되어 있습니다.

현재는 확장자/개수만 제한하고 있어, 안내 문구와 실제 동작이 불일치합니다. handlePortfolioFilesAdded에서 크기 필터를 같이 적용해 주세요.

제안 수정
 const PORTFOLIO_MAX_FILE_COUNT = 3;
 const PORTFOLIO_ALLOWED_EXTENSIONS = [".pdf", ".png"];
+const PORTFOLIO_MAX_FILE_SIZE_BYTES = 30 * 1024 * 1024;

 const isPortfolioFile = (file: File) => {
   const fileName = file.name.toLowerCase();

-  return PORTFOLIO_ALLOWED_EXTENSIONS.some(extension => fileName.endsWith(extension));
+  const isAllowedExtension = PORTFOLIO_ALLOWED_EXTENSIONS.some(extension =>
+    fileName.endsWith(extension),
+  );
+  const isAllowedSize = file.size <= PORTFOLIO_MAX_FILE_SIZE_BYTES;
+  return isAllowedExtension && isAllowedSize;
 };
🤖 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/app/signup/designer/step3/page.tsx` around lines 43 - 49, The handler
handlePortfolioFilesAdded currently only filters by extension and count; add a
size check to enforce the 30MB limit by filtering files with file.size <=
PORTFOLIO_MAX_FILE_SIZE (or define PORTFOLIO_MAX_FILE_SIZE = 30 * 1024 * 1024 if
missing) before slicing by remainingCount, so only files that pass
isPortfolioFile and the size constraint are passed to handleFilesAdded; ensure
any user-facing message/constant used elsewhere is consistent with this limit.

Comment on lines +87 to +108
<button
type="button"
className="flex w-full cursor-pointer items-center gap-4 text-left"
onClick={toggleAllTerms}
>
<CheckIcon isChecked={isAllAgreed} />
<span className="text-heading3-sb text-gray-90">모두 동의합니다</span>
</button>

<div className="bg-gray-20 h-px w-full" />

<div className="flex flex-col gap-3">
{INSTRUCTOR_TERMS.map(({ id, label }) => (
<div key={id} className="flex items-center justify-between gap-4">
<button
type="button"
className="flex min-w-0 cursor-pointer items-center gap-4 text-left"
onClick={() => toggleTerm(id)}
>
<CheckIcon isChecked={checkedTerms[id]} />
<span className="text-heading3-m text-gray-90">{label}</span>
</button>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

약관 동의 토글에 체크 상태 접근성 속성이 필요합니다.

현재는 시각적으로만 체크 상태가 바뀌고, 보조기기에는 상태가 전달되지 않습니다. 커스텀 체크 버튼에 role="checkbox"aria-checked를 추가해 주세요.

♿ 제안 코드
- <button
-   type="button"
-   className="flex w-full cursor-pointer items-center gap-4 text-left"
-   onClick={toggleAllTerms}
- >
+ <button
+   type="button"
+   role="checkbox"
+   aria-checked={isAllAgreed}
+   className="flex w-full cursor-pointer items-center gap-4 text-left"
+   onClick={toggleAllTerms}
+ >
...
- <button
-   type="button"
-   className="flex min-w-0 cursor-pointer items-center gap-4 text-left"
-   onClick={() => toggleTerm(id)}
- >
+ <button
+   type="button"
+   role="checkbox"
+   aria-checked={checkedTerms[id]}
+   aria-label={`${label} 동의`}
+   className="flex min-w-0 cursor-pointer items-center gap-4 text-left"
+   onClick={() => toggleTerm(id)}
+ >
🤖 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/app/signup/instructor/step1/page.tsx` around lines 87 - 108, The
term-toggle buttons currently only change visually; update the button elements
used for "모두 동의합니다" (onClick=toggleAllTerms, using isAllAgreed) and each term
button (onClick={() => toggleTerm(id)}, using checkedTerms[id]) to include
role="checkbox" and aria-checked set to the boolean state
(aria-checked={isAllAgreed} and aria-checked={checkedTerms[id]} respectively),
so assistive tech receives the checked state; ensure these attributes are
applied to the same element that handles the click (the button wrapping the
CheckIcon) and keep existing handlers (toggleAllTerms/toggleTerm) and visual
markup unchanged.

Comment on lines +169 to +186
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-8"
onClick={() => setSelectedTermId(null)}
>
<section
className="rounded-12 flex h-[792px] w-[612px] flex-col gap-6 bg-white px-6 py-8"
onClick={event => event.stopPropagation()}
>
<header className="border-gray-20 flex items-center justify-between gap-4">
<h2 className="text-heading2-sb text-black">{selectedTerm.modalTitle}</h2>
<button
type="button"
className="text-gray-80 flex size-6 shrink-0 cursor-pointer items-center justify-center hover:text-black"
onClick={() => setSelectedTermId(null)}
>
<CloseIcon aria-hidden="true" className="size-6" />
</button>
</header>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

약관 상세 모달에 dialog 접근성 시맨틱이 누락되었습니다.

모달 컨테이너에 role="dialog", aria-modal, 제목 연결을 추가하고 닫기 버튼에 접근 가능한 이름을 부여해 주세요.

♿ 제안 코드
- <section
-   className="rounded-12 flex h-[792px] w-[612px] flex-col gap-6 bg-white px-6 py-8"
-   onClick={event => event.stopPropagation()}
- >
+ <section
+   role="dialog"
+   aria-modal="true"
+   aria-labelledby="instructor-term-modal-title"
+   className="rounded-12 flex h-[792px] w-[612px] flex-col gap-6 bg-white px-6 py-8"
+   onClick={event => event.stopPropagation()}
+ >
...
- <h2 className="text-heading2-sb text-black">{selectedTerm.modalTitle}</h2>
+ <h2 id="instructor-term-modal-title" className="text-heading2-sb text-black">
+   {selectedTerm.modalTitle}
+ </h2>
...
- <button
-   type="button"
-   className="text-gray-80 flex size-6 shrink-0 cursor-pointer items-center justify-center hover:text-black"
-   onClick={() => setSelectedTermId(null)}
- >
+ <button
+   type="button"
+   aria-label="약관 모달 닫기"
+   className="text-gray-80 flex size-6 shrink-0 cursor-pointer items-center justify-center hover:text-black"
+   onClick={() => setSelectedTermId(null)}
+ >
🤖 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/app/signup/instructor/step1/page.tsx` around lines 169 - 186, Wrap the
modal semantics onto the modal container: add role="dialog" and
aria-modal="true" to the section element (or outer modal container) that renders
the content, link the heading used by selectedTerm.modalTitle via an id (e.g.,
set an id on the h2 and reference it with aria-labelledby on the dialog) so the
title is announced, and give the CloseIcon button an accessible name (aria-label
or aria-labelledby) instead of relying on visual-only content; adjust references
around setSelectedTermId, selectedTerm.modalTitle and CloseIcon to locate and
update the attributes.

Comment thread src/app/signup/page.tsx Outdated
Comment on lines +37 to +45
icon={<UserTypeInstructorIcon className="size-20" />}
type="디자이너"
description="외주를 맡고 싶어요!"
isSelected={selectedType === "designer"}
onClick={() => setSelectedType("designer")}
/>
<UserTypeBtn
icon={<UserTypeDesignerIcon className="size-20" />}
type="강사/교사"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

회원 유형 아이콘이 선택 타입과 반대로 매핑되어 있습니다.

Line 37~48에서 designer 선택 카드에 강사 아이콘, instructor 선택 카드에 디자이너 아이콘이 들어가 있어 유형 인지가 뒤바뀝니다.

수정 제안
-                  icon={<UserTypeInstructorIcon className="size-20" />}
+                  icon={<UserTypeDesignerIcon className="size-20" />}
@@
-                  icon={<UserTypeDesignerIcon className="size-20" />}
+                  icon={<UserTypeInstructorIcon className="size-20" />}
📝 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.

Suggested change
icon={<UserTypeInstructorIcon className="size-20" />}
type="디자이너"
description="외주를 맡고 싶어요!"
isSelected={selectedType === "designer"}
onClick={() => setSelectedType("designer")}
/>
<UserTypeBtn
icon={<UserTypeDesignerIcon className="size-20" />}
type="강사/교사"
icon={<UserTypeDesignerIcon className="size-20" />}
type="디자이너"
description="외주를 맡고 싶어요!"
isSelected={selectedType === "designer"}
onClick={() => setSelectedType("designer")}
/>
<UserTypeBtn
icon={<UserTypeInstructorIcon className="size-20" />}
type="강사/교사"
🤖 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/app/signup/page.tsx` around lines 37 - 45, The icons for the user-type
cards are swapped: the card with type="디자이너" currently uses
UserTypeInstructorIcon and the card with type="강사/교사" uses UserTypeDesignerIcon;
update the JSX so the card whose type prop is "designer" uses
UserTypeDesignerIcon and the card whose type prop is "instructor" uses
UserTypeInstructorIcon, and verify each card's isSelected (selectedType ===
"designer"/"instructor") and onClick (setSelectedType("designer"/"instructor"))
still match their respective type strings; check the UserTypeBtn instances,
UserTypeDesignerIcon, UserTypeInstructorIcon, selectedType and setSelectedType
references to make the swap.

Comment on lines +31 to +38
<Link href="/login" className="flex cursor-pointer flex-row items-center gap-1">
<ProfileCircleIcon className="text-gray-70 hover:text-gray-80 size-6" />
<span className="text-body2-m text-gray-80 hover:text-gray-90">로그인</span>
</button>
<button type="button" className="flex cursor-pointer flex-row items-center gap-1">
</Link>
<Link href="/signup" className="flex cursor-pointer flex-row items-center gap-1">
<EnterIcon className="text-gray-70 hover:text-gray-80 size-6" />
<span className="text-body2-m text-gray-80 hover:text-gray-90">회원가입</span>
</button>
</Link>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

로그인/회원가입 링크 분기가 초기 렌더에서 사실상 비활성입니다.

Line 31~38의 링크는 isLoggedInfalse일 때만 보이는데, 현재 초기값이 true라 온보딩 진입 CTA가 기본 화면에서 노출되지 않습니다. 인증 상태 기반 값으로 대체하거나, 임시라면 기본값을 false로 두는 편이 안전합니다.

🤖 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/common/Header.tsx` around lines 31 - 38, The login/signup
links are only rendered when isLoggedIn is false but that flag is initialized to
true causing the CTAs to be hidden; update the Header component to derive
authentication from the real auth state (e.g., useAuth(), authContext, or a prop
like isAuthenticated) or, if this is a temporary stub, change the initial value
of isLoggedIn to false so the onboarding CTA appears by default; locate the
isLoggedIn variable/state used in Header and adjust its initialization or
replace it with the real auth check so the Link elements for "/login" and
"/signup" render correctly.

Comment thread src/constants/signup.ts
Comment on lines +100 to +103
id: "2",
label: "강사 약관 2",
modalTitle: "강사 약관 제목 3",
content: "강사약관2강사약관2강사약관2강사약관2강사약관2강사약관2강사약관2강사약관2강사약관2",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

약관 제목 문구 불일치 수정 필요

label은 "강사 약관 2"인데 modalTitle은 "강사 약관 제목 3"으로 표시되어 사용자에게 혼동을 줍니다. 같은 항목 번호로 맞춰주세요.

🤖 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/constants/signup.ts` around lines 100 - 103, The object with id "2" has
mismatched text between label ("강사 약관 2") and modalTitle ("강사 약관 제목 3"); update
the modalTitle in the signup constants entry (the object containing id: "2",
label, modalTitle, content) so its modalTitle matches the label (e.g., "강사 약관
2") to avoid user confusion.

Comment on lines +99 to +103
const handleUserIdCheck = () => {
const isAvailable = checkSignupUserIdAvailability(userId);
setUserIdCheckStatus(isAvailable ? "available" : "duplicated");
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

아이디 길이 검증 없이 중복확인/제출 가능해집니다

현재는 길이가 유효하지 않아도 handleUserIdCheckavailable 상태가 될 수 있고, isSubmitEnabled도 길이 조건을 직접 보지 않아 빈/짧은 아이디로 제출 조건을 통과할 수 있습니다. 중복확인과 제출 조건 모두 길이 검증을 강제해야 합니다.

제안 수정안
 const handleUserIdCheck = () => {
+  if (!isUserIdLengthValid) {
+    setUserIdCheckStatus("idle");
+    return;
+  }
   const isAvailable = checkSignupUserIdAvailability(userId);
   setUserIdCheckStatus(isAvailable ? "available" : "duplicated");
 };
...
     isSubmitEnabled:
-      isUserIdAvailable && isPasswordValid && isPasswordConfirmValid && isEmailVerified,
+      isUserIdLengthValid &&
+      isUserIdAvailable &&
+      isPasswordValid &&
+      isPasswordConfirmValid &&
+      isEmailVerified,

Also applies to: 162-163

🤖 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/lib/hooks/useSignupStep2Form.ts` around lines 99 - 103, handleUserIdCheck
currently calls checkSignupUserIdAvailability(userId) and sets
setUserIdCheckStatus based solely on availability, allowing empty/short IDs to
be marked "available"; update handleUserIdCheck to first validate the userId
length (use the same length rules used elsewhere in this hook) and early-return
or set status to "invalid" when it fails, only calling
checkSignupUserIdAvailability if length is valid; also update the
isSubmitEnabled logic to include the same length validation (in addition to
name/email/password checks and the userIdCheckStatus) so submission cannot be
enabled for empty/short IDs. Ensure you reference handleUserIdCheck,
checkSignupUserIdAvailability, setUserIdCheckStatus and the isSubmitEnabled
computation when making these changes.

Comment on lines +125 to +133
const handleVerificationCodeChange = (event: ChangeEvent<HTMLInputElement>) => {
const nextCode = event.target.value;

setVerificationCode(nextCode);

if (nextCode.trim() === SIGNUP_MOCK_EMAIL_VERIFICATION_CODE) {
setEmailVerificationStatus("verified");
setVerificationTimer(0);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

인증 타이머 만료 후에도 코드가 인증됩니다

인증번호 일치만으로 verified 처리되어, 타이머가 0이어도 인증이 성공합니다. 만료 이후에는 인증 성공 처리되지 않도록 조건을 추가해야 합니다.

제안 수정안
 const handleVerificationCodeChange = (event: ChangeEvent<HTMLInputElement>) => {
   const nextCode = event.target.value;

   setVerificationCode(nextCode);

-  if (nextCode.trim() === SIGNUP_MOCK_EMAIL_VERIFICATION_CODE) {
+  if (
+    isVerificationTimerActive &&
+    emailVerificationStatus === "sent" &&
+    nextCode.trim() === SIGNUP_MOCK_EMAIL_VERIFICATION_CODE
+  ) {
     setEmailVerificationStatus("verified");
     setVerificationTimer(0);
   }
 };
🤖 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/lib/hooks/useSignupStep2Form.ts` around lines 125 - 133,
handleVerificationCodeChange currently sets verified purely on code match,
allowing success after the timer expires; update the handler to also check the
remaining timer before marking verified: after computing nextCode and calling
setVerificationCode, only call setEmailVerificationStatus("verified") and
setVerificationTimer(0) if nextCode.trim() ===
SIGNUP_MOCK_EMAIL_VERIFICATION_CODE AND the verificationTimer (or a derived
remaining time state) indicates the timer has not expired (e.g.,
verificationTimer > 0); if expired, ensure you reject the match path (do not
change status) and optionally set an expired state.

@waldls waldls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

수고하셨어요~~ 아래 코멘트 한 번만 확인해주세요 !!

  1. 폼 관리의 경우 react-hook-form , zod 써서 관리해보시는 걸 추천드립니다! 지금보다 구현하기 훨씬 쉬울 거예용
  2. 개인적으로는 회원가입 단계별로 페이지 경로 나누지 말고 거의 레이아웃이 비슷하니 강사-디자이너 조건부 렌더링하거나 제가 새 외주 작성에서 했던 것처럼 컨텐츠만 갈아끼는 방식도 있을 것 같습니다! (또는 퍼널 구조 도입!!)

Comment thread src/assets/icons/index.ts Outdated
Comment on lines +34 to +38
export { default as StepOneDesigner } from "@/assets/icons/icon_step_one_designer.svg";
export { default as StepOneInstructor } from "@/assets/icons/icon_step_one_instructor.svg";
export { default as StepThreeDesigner } from "@/assets/icons/icon_step_three_designer.svg";
export { default as StepTwoDesigner } from "@/assets/icons/icon_step_two_designer.svg";
export { default as StepTwoInstructor } from "@/assets/icons/icon_step_two_instructor.svg";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

다른 아이콘들이랑 컨벤션 맞춰서 끝에 Icon 붙여서 내보내면 좋을 것 같아요 !!

Comment thread src/app/signup/designer/step1/page.tsx Outdated
Comment on lines +130 to +142
/>
<InputField
label="전화번호"
inputMode="numeric"
maxLength={SIGNUP_MAX_PHONE_NUMBER_LENGTH + 2}
placeholder="010-0000-0000"
type="tel"
value={phoneNumber}
onClear={() => setPhoneNumber("")}
onChange={handlePhoneNumberChange}
/>
</div>
</div>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

여기 placeholder 피그마에는 전화번호를 입력해주세요 인데 디자인팀과 변경 합의된걸까요?!

@KOJ50 KOJ50 May 29, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

맵핑할 때 알아보려고 잠시 변경해놓은 부분인데 그대로 올린 것 같습니다..! 수정하겠습니닷!!

Comment on lines +21 to +27
},
default: {
button: "border-gray-20 bg-gray-10 hover:border-purple-40 hover:bg-purple-40",
icon: "text-gray-60 group-hover:text-white",
type: "text-gray-60 group-hover:text-white",
description: "text-gray-60 group-hover:text-white",
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

UserTypeBtn 호버액션 조금만 더 부드럽게 해주시면 좋을 것 같아용 지금 너무 팍팍 바뀌는 느낌이 나서 수정하면 좋을 것 같습니다

Comment on lines +68 to +83
};

return (
<div className={cn("relative w-full", className)} ref={dropdownRef}>
<button
aria-expanded={isOpen}
className={cn(
"rounded-8 border-gray-30 flex h-14 w-full cursor-pointer items-center justify-between border bg-white p-4 text-left outline-none",
"hover:bg-gray-10 focus-visible:bg-gray-10",
disabled && "bg-gray-10 cursor-not-allowed text-gray-50",
)}
disabled={disabled}
type="button"
onClick={() => setIsOpen(prev => !prev)}
>
<span

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Image

여기두 scrollbar-hide로 스크롤바 숨겨주세용

Comment on lines +77 to +80
<div className="flex w-full items-center justify-between">
<h1 className="text-title2-b text-black">회원가입</h1>
<StepOneInstructor className="h-8 w-[138px] shrink-0" />
</div>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Image

여기 피그마처럼 영역 잡고 벌려야할 것 같아요 !!

Image

Comment on lines +121 to +144
</div>

<InputField
label="이름"
maxLength={SIGNUP_MAX_NAME_LENGTH}
placeholder="이름을 입력해주세요"
value={name}
onClear={() => setName("")}
onChange={handleNameChange}
/>
<InputField
label="전화번호"
inputMode="numeric"
maxLength={SIGNUP_MAX_PHONE_NUMBER_LENGTH + 2}
placeholder="010-0000-0000"
type="tel"
value={phoneNumber}
onClear={() => setPhoneNumber("")}
onChange={handlePhoneNumberChange}
/>
</div>
</div>

<div className="flex w-full items-start justify-between">

@waldls waldls May 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

인풋 포커싱 될 때 보라색으로 살짝 border 생기면서 약간 높이가 늘어나서 그런지

Image

이 부분 아래가 살짝 먹어들어가는 현상이 발생하는 데 확인 한번만 부탁해용 (컴포넌트 내부의 코드를 수정해야할 것 같아용)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

위의 코드들을 수정하고 보니 지금은 생기지 않는 것 같습니다! 저도 border가 생기면서 높이가 조금 늘어난 부분 때문일 것으로 예상했는데 이 현상이 발생하지 않아서 수정된 코드에서 확인부탁드립니다!!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

image

디자이너 화면에서 동일한 문제 발생하는 것 같아요...! @KOJ50

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

@waldls waldls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

수고 많으셨습니다 👍

@KOJ50 KOJ50 merged commit 578f8d7 into main May 30, 2026
2 checks passed
@KOJ50 KOJ50 deleted the feature/#19-login-signup-ui branch May 30, 2026 14:54
@coderabbitai coderabbitai Bot mentioned this pull request Jun 22, 2026
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 온보딩 페이지 퍼블리싱

2 participants