Conversation
📝 Walkthrough둘러보기이 변경사항은 매장 등록 페이지의 마크업과 UI 로직을 재구조화하여, 단일 파일의 인라인 컴포넌트들을 재사용 가능한 필드 및 섹션 컴포넌트로 분리합니다. 새로운 타입 정의, 상수 데이터, 10개 이상의 프레젠테이션 컴포넌트가 추가되었으며, 메인 페이지에서는 상태 관리 로직을 유지하면서 이들 컴포넌트를 조합합니다. 변경사항
예상 코드 리뷰 노력🎯 3 (Moderate) | ⏱️ ~30 minutes 관련 가능성 있는 PR
제안된 레이블
시 (시라는 토끼의 작품)
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
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/onChangeprops를 추가하고, 이 페이지에서 해당 상태를 관리해야 실제 등록 로직을 구현할 수 있습니다.폼 상태 관리 및 유효성 검사 로직을 구현하는 코드를 생성해 드릴까요?
🤖 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: 스텁 핸들러 구현 필요.
handleOpenBusinessHoursModal과handleSearchAddress가 현재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
📒 Files selected for processing (12)
apps/owner/src/app/signup/register/_components/RegisterSubmitButton.tsxapps/owner/src/app/signup/register/_components/fields/AccountField.tsxapps/owner/src/app/signup/register/_components/fields/EmailField.tsxapps/owner/src/app/signup/register/_components/fields/StoreAddressField.tsxapps/owner/src/app/signup/register/_components/fields/StoreNameField.tsxapps/owner/src/app/signup/register/_components/sections/BusinessHoursSection.tsxapps/owner/src/app/signup/register/_components/sections/PhotoUploadSection.tsxapps/owner/src/app/signup/register/_components/sections/RandomBoxSection.tsxapps/owner/src/app/signup/register/_components/sections/TagSection.tsxapps/owner/src/app/signup/register/_constants/register.tsapps/owner/src/app/signup/register/_types/register.tsapps/owner/src/app/signup/register/page.tsx
| <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> |
There was a problem hiding this comment.
🧩 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 3Repository: 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 fRepository: 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 -20Repository: 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 2Repository: 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 -100Repository: 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.
| 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> | ||
| ); |
There was a problem hiding this comment.
폼 데이터 수집을 위한 제어 컴포넌트 props가 누락되었습니다.
현재 Input에 value와 onChange 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.
| 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.
| <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> |
There was a problem hiding this comment.
주소 검색 결과 표시를 위한 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.
| export default function StoreNameField() { | ||
| return ( | ||
| <div className="w-full"> | ||
| <p className="body2-m py-[0.2rem] text-default">상점 이름</p> | ||
| <Input type="text" placeholder="상점 이름을 입력해주세요" /> | ||
| </div> | ||
| ); |
There was a problem hiding this comment.
🧩 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 -150Repository: CUK-Compasser/FE
Length of output: 4987
🏁 Script executed:
cat -n apps/owner/src/app/signup/register/_components/RegisterSubmitButton.tsxRepository: CUK-Compasser/FE
Length of output: 706
🏁 Script executed:
rg -n "export.*Input" apps/owner/src/app/signup/register/_components/ -A 5Repository: CUK-Compasser/FE
Length of output: 42
🏁 Script executed:
head -20 apps/owner/src/app/signup/register/_components/fields/StoreNameField.tsxRepository: 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.tsxRepository: CUK-Compasser/FE
Length of output: 435
🏁 Script executed:
cat -n apps/owner/src/app/signup/register/_components/fields/StoreAddressField.tsxRepository: CUK-Compasser/FE
Length of output: 1149
🏁 Script executed:
cat -n apps/owner/src/app/signup/register/_components/fields/AccountField.tsxRepository: CUK-Compasser/FE
Length of output: 1427
Input 컴포넌트가 제어되지 않으며 폼 데이터 수집 메커니즘이 없습니다
StoreNameField의 Input은 value와 onChange props가 없어 비제어 컴포넌트로 동작하고 있습니다. 부모 컴포넌트(page.tsx)에서 상점 이름, 이메일, 주소 데이터를 관리하는 상태가 전혀 없으며, RegisterSubmitButton도 폼 데이터를 수집하지 않고 단순히 라우팅만 수행합니다.
EmailField와 StoreAddressField도 동일하게 비제어 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.
| <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> |
There was a problem hiding this comment.
업로드 버튼에 실제 기능 및 접근성 레이블 누락
업로드 버튼에 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.
가게 등록 페이지 컴포넌트 분리
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
릴리스 노트