Skip to content

[Chore/#65] 매장 등록 페이지 컴포넌트 분리#67

Merged
skyblue1232 merged 1 commit intodevelopfrom
feat/#65/owner-store-register
Mar 26, 2026
Merged

[Chore/#65] 매장 등록 페이지 컴포넌트 분리#67
skyblue1232 merged 1 commit intodevelopfrom
feat/#65/owner-store-register

Conversation

@skyblue1232
Copy link
Copy Markdown
Contributor

@skyblue1232 skyblue1232 commented Mar 26, 2026

가게 등록 페이지 컴포넌트 분리

register
├─ _components
│ ├─ fields
│ │ ├─ StoreNameField.tsx
│ │ ├─ EmailField.tsx
│ │ ├─ StoreAddressField.tsx
│ │ └─ AccountField.tsx
│ ├─ sections
│ │ ├─ BusinessHoursSection.tsx
│ │ ├─ RandomBoxSection.tsx
│ │ ├─ PhotoUploadSection.tsx
│ │ └─ TagSection.tsx
│ └─ RegisterSubmitButton.tsx
├─ _constants
├─ _types
└─ page.tsx

Fixes #65

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 상점 등록 폼 추가: 상점명, 이메일, 주소, 계좌 정보, 영업시간, 랜덤박스, 사진, 태그 등록 기능 포함
    • 상점 등록 완료 버튼 추가

@skyblue1232 skyblue1232 self-assigned this Mar 26, 2026
@skyblue1232 skyblue1232 added the chore 자잘한 수정 label Mar 26, 2026
@github-actions github-actions bot added the feat 기능 구현 및 생성 label Mar 26, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

📝 Walkthrough

둘러보기

이 변경사항은 매장 등록 페이지의 마크업과 UI 로직을 재구조화하여, 단일 파일의 인라인 컴포넌트들을 재사용 가능한 필드 및 섹션 컴포넌트로 분리합니다. 새로운 타입 정의, 상수 데이터, 10개 이상의 프레젠테이션 컴포넌트가 추가되었으며, 메인 페이지에서는 상태 관리 로직을 유지하면서 이들 컴포넌트를 조합합니다.

변경사항

Cohort / File(s) 요약
폼 필드 컴포넌트
apps/owner/src/app/signup/register/_components/fields/EmailField.tsx, StoreNameField.tsx, StoreAddressField.tsx, AccountField.tsx
이메일, 매장명, 주소 검색, 계좌 유형 선택 등 기본 입력 필드를 렌더링하는 단순 프레젠테이션 컴포넌트들입니다.
섹션 컴포넌트
apps/owner/src/app/signup/register/_components/sections/BusinessHoursSection.tsx, PhotoUploadSection.tsx, RandomBoxSection.tsx, TagSection.tsx
영업시간, 사진 업로드, 랜덤박스 목록 관리, 태그 선택 등 복합 섹션을 구성하는 컴포넌트들이며, RandomBoxSection은 선택 상태 토글과 추가/삭제 핸들러를 포함합니다.
제출 버튼 컴포넌트
apps/owner/src/app/signup/register/_components/RegisterSubmitButton.tsx
고정 패딩과 함께 "등록 완료" 버튼을 렌더링하는 단순 컴포넌트입니다.
타입 및 상수 정의
apps/owner/src/app/signup/register/_types/register.ts, _constants/register.ts
BusinessHours, RandomBoxItem, AccountType 타입 정의와 기본 영업시간, 랜덤박스, 태그 옵션 상수를 내보냅니다.
페이지 리팩토링
apps/owner/src/app/signup/register/page.tsx
280줄에서 43줄로 감소했으며, 인라인 마크업을 제거하고 새 컴포넌트들을 임포트하여 조합합니다. 상태 관리와 이벤트 핸들러는 유지됩니다.

예상 코드 리뷰 노력

🎯 3 (Moderate) | ⏱️ ~30 minutes

관련 가능성 있는 PR

제안된 레이블

feat, style

시 (시라는 토끼의 작품)

🐰 폼을 나누고 조각내어
작은 컴포넌트 들뜸 속에
메일, 이름, 주소 춤을 춘다
영업시간과 박스도 함께하니
등록 완료 버튼 아래
우리 매장의 꿈이 피어난다!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 변경 세트의 주요 내용을 명확하게 요약합니다. 매장 등록 페이지를 여러 컴포넌트로 분리한 것이 핵심 변경사항이며, 제목이 이를 정확하게 반영합니다.

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

✨ 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/#65/owner-store-register

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.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
compasser-customer Error Error Mar 26, 2026 4:47pm
compasser-owner Error Error Mar 26, 2026 4:47pm

Copy link
Copy Markdown

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

Caution

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

⚠️ Outside diff range comments (1)
apps/owner/src/app/signup/register/page.tsx (1)

90-92: ⚠️ Potential issue | 🟠 Major

등록 완료 시 폼 데이터 수집 및 유효성 검사가 누락되었습니다.

현재 handleCompleteRegister는 폼 데이터를 수집하거나 유효성을 검사하지 않고 바로 /main으로 이동합니다. 매장명, 이메일, 주소 등 필수 필드 값이 수집되지 않는 상태입니다.

StoreNameField, EmailField 등 필드 컴포넌트에 value/onChange props를 추가하고, 이 페이지에서 해당 상태를 관리해야 실제 등록 로직을 구현할 수 있습니다.

폼 상태 관리 및 유효성 검사 로직을 구현하는 코드를 생성해 드릴까요?

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

In `@apps/owner/src/app/signup/register/page.tsx` around lines 90 - 92,
handleCompleteRegister currently navigates immediately; update the page to
manage form state and validate before redirecting: add local state (e.g.,
useState) for each field used by StoreNameField, EmailField, AddressField, etc.,
pass value and onChange props into those components, implement synchronous
validation in handleCompleteRegister (check required fields, email format, and
any address constraints), show/collect validation errors and prevent calling
router.push("/main") until validation passes, and only then proceed with
submission or navigation; ensure to reference the existing
handleCompleteRegister, StoreNameField, EmailField, and router.push("/main")
when making changes.
🧹 Nitpick comments (6)
apps/owner/src/app/signup/register/_components/sections/RandomBoxSection.tsx (1)

27-36: 선택된 항목 없을 때 삭제 버튼 비활성화 권장

selectedRandomBoxIds가 비어있을 때 "삭제하기" 버튼을 비활성화하면 사용자 경험이 개선됩니다.

♻️ 삭제 버튼 비활성화 제안
           <Button
             type="button"
             kind="register"
             variant="outline-gray"
             fullWidth={false}
             onClick={onDeleteRandomBoxes}
+            disabled={selectedRandomBoxIds.length === 0}
             className="body1-m border border-gray-600 text-gray-600"
           >
             삭제하기
           </Button>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/owner/src/app/signup/register/_components/sections/RandomBoxSection.tsx`
around lines 27 - 36, Disable the "삭제하기" Button in RandomBoxSection.tsx when no
boxes are selected: check the selectedRandomBoxIds array (e.g.,
selectedRandomBoxIds.length === 0) and pass a disabled prop (or set
aria-disabled) to the Button used in the RandomBoxSection component so it's not
clickable when empty; also ensure onDeleteRandomBoxes is not invoked when
disabled.
apps/owner/src/app/signup/register/_constants/register.ts (2)

33-37: 랜덤박스 ID 관리 방식 검토

initialRandomBoxes의 ID가 순차적(1, 2, 3)으로 할당되어 있습니다. 아이템 추가/삭제 시 ID 중복이나 충돌이 발생할 수 있으므로, 새 아이템 추가 시 고유 ID 생성 로직(예: Date.now() 또는 uuid)이 필요합니다.

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

In `@apps/owner/src/app/signup/register/_constants/register.ts` around lines 33 -
37, initialRandomBoxes currently uses hardcoded sequential numeric ids (1,2,3)
which can lead to collisions when items are added/removed; update the creation
flow so new RandomBoxItem entries receive guaranteed-unique ids (e.g., uuidv4()
or Date.now()+random) instead of manual integers, adjust the RandomBoxItem type
to accept the chosen id type (string or number) if necessary, and update any
factory/adder functions that push into initialRandomBoxes (or where new items
are created) to call the new unique-id generator so IDs remain globally unique
across add/remove operations.

39-39: tagOptions에 명시적 타입 추가 권장

다른 상수들과 일관성을 위해 명시적 타입을 추가하는 것이 좋습니다.

♻️ 타입 추가 제안
-export const tagOptions = ["카페", "베이커리", "식당"];
+export const tagOptions: string[] = ["카페", "베이커리", "식당"];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/owner/src/app/signup/register/_constants/register.ts` at line 39, Add an
explicit type annotation to the exported constant tagOptions so its type is
clear and consistent with other constants; update the declaration of tagOptions
(the exported symbol) to include a string[] or readonly string[] type (e.g.,
annotate as string[] or readonly ["카페","베이커리","식당"] depending on desired
mutability) and keep the current array values unchanged.
apps/owner/src/app/signup/register/_components/fields/StoreNameField.tsx (1)

7-9: 접근성 개선: <p> 대신 <label> 사용 권장

스크린 리더 사용자를 위해 <p> 태그 대신 <label> 요소를 사용하고 입력 필드와 연결하는 것이 좋습니다. 현재 구조에서는 레이블과 입력 필드 간의 관계가 명시적으로 설정되어 있지 않습니다.

♻️ 접근성 개선을 위한 제안
-      <p className="body2-m py-[0.2rem] text-default">상점 이름</p>
-      <Input type="text" placeholder="상점 이름을 입력해주세요" />
+      <label className="body2-m py-[0.2rem] text-default">
+        상점 이름
+        <Input type="text" placeholder="상점 이름을 입력해주세요" />
+      </label>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/owner/src/app/signup/register/_components/fields/StoreNameField.tsx`
around lines 7 - 9, The current StoreNameField component uses a <p> for the
field title which is not programmatically associated with the input; change the
title element to a <label> and associate it with the Input by giving the Input a
unique id (e.g., storeName) and setting the label's htmlFor to that id, or
alternatively wrap the Input with the <label>. Update the JSX in
StoreNameField.tsx to use <label className="body2-m py-[0.2rem] text-default"
htmlFor="storeName">상점 이름</label> and add id="storeName" to the Input (or wrap
the Input with the label) so screen readers correctly link the label and the
input.
apps/owner/src/app/signup/register/_components/sections/BusinessHoursSection.tsx (1)

24-33: Button의 커스텀 className이 design-system 스타일과 중복될 수 있습니다.

variant="outline-primary"가 이미 border와 text 색상을 처리하는데, className에서 border border-primary-variant text-primary-variant를 추가로 지정하고 있습니다. 이로 인해 스타일 충돌이나 불필요한 중복이 발생할 수 있습니다.

design-system의 outline-primary 스타일이 요구사항과 맞지 않는다면, 새로운 variant를 추가하거나 className만 사용하는 것이 명확합니다.

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

In
`@apps/owner/src/app/signup/register/_components/sections/BusinessHoursSection.tsx`
around lines 24 - 33, The Button in BusinessHoursSection uses
variant="outline-primary" while also supplying redundant styling via className
("border border-primary-variant text-primary-variant"), which can conflict with
the design-system; remove the duplicate className or replace
variant="outline-primary" with a new design-system variant that matches the
desired look (or keep className and change to a neutral variant like
variant="none" if supported). Update the Button usage in BusinessHoursSection
(the component rendering the Button and its onClick handler
onOpenBusinessHoursModal) accordingly and, if adding a new variant, implement
that variant in the design-system Button component so styles are centralized.
apps/owner/src/app/signup/register/page.tsx (1)

82-88: TODO: 스텁 핸들러 구현 필요.

handleOpenBusinessHoursModalhandleSearchAddress가 현재 console.log만 출력합니다. 실제 모달 및 주소 검색 기능 구현이 필요합니다.

이 핸들러들의 구현을 추적할 이슈를 생성해 드릴까요?

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

In `@apps/owner/src/app/signup/register/page.tsx` around lines 82 - 88, Both
handleOpenBusinessHoursModal and handleSearchAddress are stubs that only log;
implement them to open the business-hours modal and perform address lookup. For
handleOpenBusinessHoursModal, call the modal control used in this component
(e.g., setBusinessHoursModalOpen(true) or dispatch/openModal("BusinessHours"))
and ensure any existing BusinessHoursModal component receives the current hours
state and an onSave callback to update form state (e.g., updateBusinessHours).
For handleSearchAddress, invoke the address-search utility or API used in the
app (e.g., openAddressSearchPopup or addressLookup(query)), handle the async
result, set address-related state fields (street, postcode, coordinates), and
handle errors; if the codebase uses a shared AddressSearchModal or third-party
widget, trigger it and wire its success callback to populate the form. Ensure
both handlers update component state and pass necessary callbacks/props so the
UI reflects changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/owner/src/app/signup/register/_components/fields/AccountField.tsx`:
- Around line 19-40: The Input currently ignores selectedAccountType so its
placeholder and behavior don't change; update the AccountField component to
reflect selectedAccountType by computing a dynamic placeholder (e.g., const
placeholder = selectedAccountType === "bank" ? "계좌번호를 입력해주세요" : "예금주명을 입력해주세요")
and pass it to the Input, or alternatively conditionally render two different
Inputs when selectedAccountType === "bank" vs "holder"; also ensure any
submit/validation handler (e.g., the component's onSubmit or validate method)
checks selectedAccountType to apply the correct validation rules for account
number vs account holder name; keep existing Tag onClick/onSelectAccountType
logic unchanged.

In `@apps/owner/src/app/signup/register/_components/fields/EmailField.tsx`:
- Around line 5-11: EmailField currently renders an uncontrolled Input so the
parent (page.tsx) cannot collect the email; update EmailField to accept props
e.g., value: string and onChange: (e: ChangeEvent<HTMLInputElement>) => void (or
onValueChange) and pass them into the Input component (value={value}
onChange={onChange}) so page.tsx can control the state; also replace the <p>
with a <label> tied to the input via id/htmlFor (add an id prop to the Input and
use the same id on the label) to improve accessibility and ensure EmailField
exports/accepts these props for use by page.tsx.

In `@apps/owner/src/app/signup/register/_components/fields/StoreAddressField.tsx`:
- Around line 13-19: The Input in StoreAddressField lacks a value prop so
selected addresses from the search can't be shown; add local state (e.g., const
[address, setAddress] = useState('')) in the StoreAddressField component, pass
value={address} and onChange={(e) => setAddress(e.target.value)} to the Input,
and update setAddress inside the address selection handler (e.g.,
handleAddressSelect) that receives the search result; ensure the handler is
wired to whatever address-search component you use so selected addresses
populate the Input.

In `@apps/owner/src/app/signup/register/_components/fields/StoreNameField.tsx`:
- Around line 5-11: StoreNameField (and sibling components EmailField and
StoreAddressField) currently render the Input component as uncontrolled, and the
parent page.tsx and RegisterSubmitButton don't collect form state; fix by wiring
a single form state solution: either convert the inputs to controlled components
(add value and onChange props and lift state to the parent page.tsx) or
integrate react-hook-form (register each field in
StoreNameField/EmailField/StoreAddressField using useFormContext or pass
register down), then update RegisterSubmitButton to read the combined form
values (from parent state or formContext) and submit/route with the collected
data; reference the StoreNameField, EmailField, StoreAddressField, page.tsx and
RegisterSubmitButton symbols to locate where to add value/onChange or register
hooks and ensure the collected data is passed to the submit handler.

In
`@apps/owner/src/app/signup/register/_components/sections/PhotoUploadSection.tsx`:
- Around line 13-18: The PhotoUploadSection button lacks functionality and
accessibility labels; add a hidden file input referenced by fileInputRef and
give the button an aria-label (e.g., "Upload photo") and an onClick that calls
fileInputRef.current.click() (identify the button as uploadButton or keep
existing JSX button) and implement a handleFileChange(file: File) or
onFileSelect handler to process the chosen file (validate type/size and update
component state or call a passed prop). Ensure the <input type="file"
accept="image/*" /> has onChange wired to handleFileChange and that you clean up
the ref/state as needed.

---

Outside diff comments:
In `@apps/owner/src/app/signup/register/page.tsx`:
- Around line 90-92: handleCompleteRegister currently navigates immediately;
update the page to manage form state and validate before redirecting: add local
state (e.g., useState) for each field used by StoreNameField, EmailField,
AddressField, etc., pass value and onChange props into those components,
implement synchronous validation in handleCompleteRegister (check required
fields, email format, and any address constraints), show/collect validation
errors and prevent calling router.push("/main") until validation passes, and
only then proceed with submission or navigation; ensure to reference the
existing handleCompleteRegister, StoreNameField, EmailField, and
router.push("/main") when making changes.

---

Nitpick comments:
In `@apps/owner/src/app/signup/register/_components/fields/StoreNameField.tsx`:
- Around line 7-9: The current StoreNameField component uses a <p> for the field
title which is not programmatically associated with the input; change the title
element to a <label> and associate it with the Input by giving the Input a
unique id (e.g., storeName) and setting the label's htmlFor to that id, or
alternatively wrap the Input with the <label>. Update the JSX in
StoreNameField.tsx to use <label className="body2-m py-[0.2rem] text-default"
htmlFor="storeName">상점 이름</label> and add id="storeName" to the Input (or wrap
the Input with the label) so screen readers correctly link the label and the
input.

In
`@apps/owner/src/app/signup/register/_components/sections/BusinessHoursSection.tsx`:
- Around line 24-33: The Button in BusinessHoursSection uses
variant="outline-primary" while also supplying redundant styling via className
("border border-primary-variant text-primary-variant"), which can conflict with
the design-system; remove the duplicate className or replace
variant="outline-primary" with a new design-system variant that matches the
desired look (or keep className and change to a neutral variant like
variant="none" if supported). Update the Button usage in BusinessHoursSection
(the component rendering the Button and its onClick handler
onOpenBusinessHoursModal) accordingly and, if adding a new variant, implement
that variant in the design-system Button component so styles are centralized.

In
`@apps/owner/src/app/signup/register/_components/sections/RandomBoxSection.tsx`:
- Around line 27-36: Disable the "삭제하기" Button in RandomBoxSection.tsx when no
boxes are selected: check the selectedRandomBoxIds array (e.g.,
selectedRandomBoxIds.length === 0) and pass a disabled prop (or set
aria-disabled) to the Button used in the RandomBoxSection component so it's not
clickable when empty; also ensure onDeleteRandomBoxes is not invoked when
disabled.

In `@apps/owner/src/app/signup/register/_constants/register.ts`:
- Around line 33-37: initialRandomBoxes currently uses hardcoded sequential
numeric ids (1,2,3) which can lead to collisions when items are added/removed;
update the creation flow so new RandomBoxItem entries receive guaranteed-unique
ids (e.g., uuidv4() or Date.now()+random) instead of manual integers, adjust the
RandomBoxItem type to accept the chosen id type (string or number) if necessary,
and update any factory/adder functions that push into initialRandomBoxes (or
where new items are created) to call the new unique-id generator so IDs remain
globally unique across add/remove operations.
- Line 39: Add an explicit type annotation to the exported constant tagOptions
so its type is clear and consistent with other constants; update the declaration
of tagOptions (the exported symbol) to include a string[] or readonly string[]
type (e.g., annotate as string[] or readonly ["카페","베이커리","식당"] depending on
desired mutability) and keep the current array values unchanged.

In `@apps/owner/src/app/signup/register/page.tsx`:
- Around line 82-88: Both handleOpenBusinessHoursModal and handleSearchAddress
are stubs that only log; implement them to open the business-hours modal and
perform address lookup. For handleOpenBusinessHoursModal, call the modal control
used in this component (e.g., setBusinessHoursModalOpen(true) or
dispatch/openModal("BusinessHours")) and ensure any existing BusinessHoursModal
component receives the current hours state and an onSave callback to update form
state (e.g., updateBusinessHours). For handleSearchAddress, invoke the
address-search utility or API used in the app (e.g., openAddressSearchPopup or
addressLookup(query)), handle the async result, set address-related state fields
(street, postcode, coordinates), and handle errors; if the codebase uses a
shared AddressSearchModal or third-party widget, trigger it and wire its success
callback to populate the form. Ensure both handlers update component state and
pass necessary callbacks/props so the UI reflects changes.
🪄 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: 267d1898-be4e-4f74-baac-d209fc5cc258

📥 Commits

Reviewing files that changed from the base of the PR and between ebdbc74 and 667bc88.

📒 Files selected for processing (12)
  • apps/owner/src/app/signup/register/_components/RegisterSubmitButton.tsx
  • apps/owner/src/app/signup/register/_components/fields/AccountField.tsx
  • apps/owner/src/app/signup/register/_components/fields/EmailField.tsx
  • apps/owner/src/app/signup/register/_components/fields/StoreAddressField.tsx
  • apps/owner/src/app/signup/register/_components/fields/StoreNameField.tsx
  • apps/owner/src/app/signup/register/_components/sections/BusinessHoursSection.tsx
  • apps/owner/src/app/signup/register/_components/sections/PhotoUploadSection.tsx
  • apps/owner/src/app/signup/register/_components/sections/RandomBoxSection.tsx
  • apps/owner/src/app/signup/register/_components/sections/TagSection.tsx
  • apps/owner/src/app/signup/register/_constants/register.ts
  • apps/owner/src/app/signup/register/_types/register.ts
  • apps/owner/src/app/signup/register/page.tsx

Comment on lines +19 to +40
<div className="flex gap-[0.8rem] pb-[0.4rem]">
<Tag
variant="rounded-rect"
selected={selectedAccountType === "bank"}
changeOnClick={false}
onClick={() => onSelectAccountType("bank")}
>
은행
</Tag>

<Tag
variant="rounded-rect"
selected={selectedAccountType === "holder"}
changeOnClick={false}
onClick={() => onSelectAccountType("holder")}
>
예금주명
</Tag>
</div>

<Input type="text" placeholder="계좌번호를 입력해주세요" />
</div>
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if there's any design spec or other account field implementations

rg -n "계좌|account|bank|holder" apps/owner/src/ --type tsx -C 3

Repository: CUK-Compasser/FE

Length of output: 87


🏁 Script executed:

#!/bin/bash
# Find and read the AccountField.tsx file
find apps/owner/src -name "AccountField.tsx" -type f

Repository: CUK-Compasser/FE

Length of output: 130


🏁 Script executed:

#!/bin/bash
# Search with corrected rg (no explicit file type) for account-related code
rg "계좌|account|bank|holder" apps/owner/src/ -C 2 -l | head -20

Repository: CUK-Compasser/FE

Length of output: 481


🏁 Script executed:

#!/bin/bash
# Read the AccountField.tsx file directly
cat -n "apps/owner/src/app/signup/register/_components/fields/AccountField.tsx"

Repository: CUK-Compasser/FE

Length of output: 1427


🏁 Script executed:

#!/bin/bash
# Search for usage of AccountField component
rg "AccountField" apps/owner/src/ -C 2

Repository: CUK-Compasser/FE

Length of output: 2350


🏁 Script executed:

#!/bin/bash
# Check the AccountType definition
cat -n "apps/owner/src/app/signup/register/_types/register.ts"

Repository: CUK-Compasser/FE

Length of output: 494


🏁 Script executed:

#!/bin/bash
# Read the full register/page.tsx to see how selectedAccountType is used
cat -n "apps/owner/src/app/signup/register/page.tsx" | head -100

Repository: CUK-Compasser/FE

Length of output: 3845


Input 필드가 선택된 계좌 타입을 반영하지 않음

selectedAccountType 상태가 관리되고 있지만 실제로 Input 필드의 동작에 반영되지 않습니다. "은행"을 선택해도, "예금주명"을 선택해도 Input의 placeholder와 로직이 동일하게 "계좌번호를 입력해주세요"로 유지됩니다.

선택된 타입에 따라 다음 중 하나를 구현해야 합니다:

  • Input의 placeholder를 동적으로 변경 (예: "계좌번호" vs "예금주명")
  • 또는 조건부 렌더링으로 다른 입력 필드 표시
  • 또는 form 제출 시 selectedAccountType에 맞게 검증 로직 추가
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/owner/src/app/signup/register/_components/fields/AccountField.tsx`
around lines 19 - 40, The Input currently ignores selectedAccountType so its
placeholder and behavior don't change; update the AccountField component to
reflect selectedAccountType by computing a dynamic placeholder (e.g., const
placeholder = selectedAccountType === "bank" ? "계좌번호를 입력해주세요" : "예금주명을 입력해주세요")
and pass it to the Input, or alternatively conditionally render two different
Inputs when selectedAccountType === "bank" vs "holder"; also ensure any
submit/validation handler (e.g., the component's onSubmit or validate method)
checks selectedAccountType to apply the correct validation rules for account
number vs account holder name; keep existing Tag onClick/onSelectAccountType
logic unchanged.

Comment on lines +5 to +11
export default function EmailField() {
return (
<div className="mt-[3.6rem] w-full">
<p className="body2-m pb-[0.2rem] text-default">이메일</p>
<Input type="email" placeholder="이메일을 입력해주세요" />
</div>
);
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

폼 데이터 수집을 위한 제어 컴포넌트 props가 누락되었습니다.

현재 InputvalueonChange props가 없어서 부모 컴포넌트(page.tsx)에서 이메일 값을 수집할 수 없습니다. 등록 완료 시 실제 폼 데이터를 서버로 전송해야 한다면, 이 필드의 값을 상위에서 관리할 수 있어야 합니다.

또한 <p> 태그 대신 <label>을 사용하고 htmlFor/id로 연결하면 접근성이 향상됩니다.

제어 컴포넌트로 변경하는 제안
+"use client";
+
+import { Input } from "@compasser/design-system";
+
+interface EmailFieldProps {
+  value: string;
+  onChange: (value: string) => void;
+}
+
+export default function EmailField({ value, onChange }: EmailFieldProps) {
   return (
     <div className="mt-[3.6rem] w-full">
-      <p className="body2-m pb-[0.2rem] text-default">이메일</p>
-      <Input type="email" placeholder="이메일을 입력해주세요" />
+      <label htmlFor="email-field" className="body2-m pb-[0.2rem] text-default">
+        이메일
+      </label>
+      <Input
+        id="email-field"
+        type="email"
+        placeholder="이메일을 입력해주세요"
+        value={value}
+        onChange={(e) => onChange(e.target.value)}
+      />
     </div>
   );
 }
📝 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
export default function EmailField() {
return (
<div className="mt-[3.6rem] w-full">
<p className="body2-m pb-[0.2rem] text-default">이메일</p>
<Input type="email" placeholder="이메일을 입력해주세요" />
</div>
);
"use client";
import { Input } from "@compasser/design-system";
interface EmailFieldProps {
value: string;
onChange: (value: string) => void;
}
export default function EmailField({ value, onChange }: EmailFieldProps) {
return (
<div className="mt-[3.6rem] w-full">
<label htmlFor="email-field" className="body2-m pb-[0.2rem] text-default">
이메일
</label>
<Input
id="email-field"
type="email"
placeholder="이메일을 입력해주세요"
value={value}
onChange={(e) => onChange(e.target.value)}
/>
</div>
);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/owner/src/app/signup/register/_components/fields/EmailField.tsx` around
lines 5 - 11, EmailField currently renders an uncontrolled Input so the parent
(page.tsx) cannot collect the email; update EmailField to accept props e.g.,
value: string and onChange: (e: ChangeEvent<HTMLInputElement>) => void (or
onValueChange) and pass them into the Input component (value={value}
onChange={onChange}) so page.tsx can control the state; also replace the <p>
with a <label> tied to the input via id/htmlFor (add an id prop to the Input and
use the same id on the label) to improve accessibility and ensure EmailField
exports/accepts these props for use by page.tsx.

Comment on lines +13 to +19
<div className="mt-[3.6rem] w-full">
<p className="body2-m pb-[0.2rem] text-default">상점 주소</p>

<div className="flex items-end gap-[1rem]">
<div className="min-w-0 flex-1">
<Input type="text" placeholder="상점 주소를 입력해주세요" />
</div>
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

주소 검색 결과 표시를 위한 value prop 필요

주소 검색 후 선택된 주소를 Input에 표시하려면 value prop이 필요합니다. 현재 구조에서는 검색된 주소를 입력 필드에 반영할 방법이 없습니다.

🔧 주소 값 표시를 위한 제안
 interface StoreAddressFieldProps {
+  address: string;
   onSearchAddress: () => void;
 }

 export default function StoreAddressField({
+  address,
   onSearchAddress,
 }: StoreAddressFieldProps) {
   return (
     <div className="mt-[3.6rem] w-full">
-      <p className="body2-m pb-[0.2rem] text-default">상점 주소</p>
+      <label className="body2-m pb-[0.2rem] text-default">상점 주소</label>

       <div className="flex items-end gap-[1rem]">
         <div className="min-w-0 flex-1">
-          <Input type="text" placeholder="상점 주소를 입력해주세요" />
+          <Input type="text" value={address} placeholder="상점 주소를 입력해주세요" readOnly />
         </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/owner/src/app/signup/register/_components/fields/StoreAddressField.tsx`
around lines 13 - 19, The Input in StoreAddressField lacks a value prop so
selected addresses from the search can't be shown; add local state (e.g., const
[address, setAddress] = useState('')) in the StoreAddressField component, pass
value={address} and onChange={(e) => setAddress(e.target.value)} to the Input,
and update setAddress inside the address selection handler (e.g.,
handleAddressSelect) that receives the search result; ensure the handler is
wired to whatever address-search component you use so selected addresses
populate the Input.

Comment on lines +5 to +11
export default function StoreNameField() {
return (
<div className="w-full">
<p className="body2-m py-[0.2rem] text-default">상점 이름</p>
<Input type="text" placeholder="상점 이름을 입력해주세요" />
</div>
);
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check how form data is collected in the parent page component

# Search for form handling patterns in the register page
rg -n -A 10 "StoreNameField" apps/owner/src/app/signup/register/

Repository: CUK-Compasser/FE

Length of output: 3153


🏁 Script executed:

cat -n apps/owner/src/app/signup/register/page.tsx | head -150

Repository: CUK-Compasser/FE

Length of output: 4987


🏁 Script executed:

cat -n apps/owner/src/app/signup/register/_components/RegisterSubmitButton.tsx

Repository: CUK-Compasser/FE

Length of output: 706


🏁 Script executed:

rg -n "export.*Input" apps/owner/src/app/signup/register/_components/ -A 5

Repository: CUK-Compasser/FE

Length of output: 42


🏁 Script executed:

head -20 apps/owner/src/app/signup/register/_components/fields/StoreNameField.tsx

Repository: CUK-Compasser/FE

Length of output: 346


🏁 Script executed:

rg -n "import.*Input" apps/owner/src/app/signup/register/_components/fields/

Repository: CUK-Compasser/FE

Length of output: 569


🏁 Script executed:

cat -n apps/owner/src/app/signup/register/_components/fields/EmailField.tsx

Repository: CUK-Compasser/FE

Length of output: 435


🏁 Script executed:

cat -n apps/owner/src/app/signup/register/_components/fields/StoreAddressField.tsx

Repository: CUK-Compasser/FE

Length of output: 1149


🏁 Script executed:

cat -n apps/owner/src/app/signup/register/_components/fields/AccountField.tsx

Repository: CUK-Compasser/FE

Length of output: 1427


Input 컴포넌트가 제어되지 않으며 폼 데이터 수집 메커니즘이 없습니다

StoreNameFieldInputvalueonChange props가 없어 비제어 컴포넌트로 동작하고 있습니다. 부모 컴포넌트(page.tsx)에서 상점 이름, 이메일, 주소 데이터를 관리하는 상태가 전혀 없으며, RegisterSubmitButton도 폼 데이터를 수집하지 않고 단순히 라우팅만 수행합니다.

EmailFieldStoreAddressField도 동일하게 비제어 Input을 사용하고 있어서 전체 폼의 데이터 수집 방식을 정의해야 합니다 (react-hook-form, ref 기반 수집, 또는 각 컴포넌트의 제어 컴포넌트화).

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

In `@apps/owner/src/app/signup/register/_components/fields/StoreNameField.tsx`
around lines 5 - 11, StoreNameField (and sibling components EmailField and
StoreAddressField) currently render the Input component as uncontrolled, and the
parent page.tsx and RegisterSubmitButton don't collect form state; fix by wiring
a single form state solution: either convert the inputs to controlled components
(add value and onChange props and lift state to the parent page.tsx) or
integrate react-hook-form (register each field in
StoreNameField/EmailField/StoreAddressField using useFormContext or pass
register down), then update RegisterSubmitButton to read the combined form
values (from parent state or formContext) and submit/route with the collected
data; reference the StoreNameField, EmailField, StoreAddressField, page.tsx and
RegisterSubmitButton symbols to locate where to add value/onChange or register
hooks and ensure the collected data is passed to the submit handler.

Comment on lines +13 to +18
<button
type="button"
className="flex h-[18rem] w-full items-center justify-center rounded-[10px] bg-background"
>
<Icon name="Camera" width={24} height={24} />
</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 | 🟡 Minor

업로드 버튼에 실제 기능 및 접근성 레이블 누락

업로드 버튼에 onClick 핸들러가 없어 실제 파일 업로드 기능이 구현되지 않았습니다. 또한 버튼에 aria-label이 없어 스크린 리더 사용자가 버튼의 목적을 알 수 없습니다.

🛠️ 접근성 및 기능 추가를 위한 제안
       <button
         type="button"
         className="flex h-[18rem] w-full items-center justify-center rounded-[10px] bg-background"
+        aria-label="사진 업로드"
+        onClick={onUploadPhoto}
       >
         <Icon name="Camera" width={24} height={24} />
       </button>

파일 업로드 기능을 구현하는 코드를 생성해 드릴까요?

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

In
`@apps/owner/src/app/signup/register/_components/sections/PhotoUploadSection.tsx`
around lines 13 - 18, The PhotoUploadSection button lacks functionality and
accessibility labels; add a hidden file input referenced by fileInputRef and
give the button an aria-label (e.g., "Upload photo") and an onClick that calls
fileInputRef.current.click() (identify the button as uploadButton or keep
existing JSX button) and implement a handleFileChange(file: File) or
onFileSelect handler to process the chosen file (validate type/size and update
component state or call a passed prop). Ensure the <input type="file"
accept="image/*" /> has onChange wired to handleFileChange and that you clean up
the ref/state as needed.

@skyblue1232 skyblue1232 merged commit 02a0ff9 into develop Mar 26, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore 자잘한 수정 feat 기능 구현 및 생성

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 사장님 매장 등록 페이지

1 participant