[Feat/#106] 사장님 가게 등록 관련 API 연동 #111
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough이 PR은 주소 검색 기능을 새로 추가하고, 상점 정보 편집 폼의 태그/은행/영업시간 처리를 리팩토링하며, 랜덤박스에 픽업 시간 정보를 추가합니다. Changes주소 검색 기능
상점 정보 폼 리팩토링
랜덤박스 픽업 시간 추가
Sequence DiagramsequenceDiagram
participant User as 사용자
participant UI as AddressSearchBottomSheet
participant Debounce as 디바운스 타이머
participant Kakao as Kakao 지도 API
participant Component as 상점 정보 폼
User->>UI: 주소 검색 바텀시트 열기
User->>UI: 주소 입력 (예: "강남")
UI->>Debounce: 입력값 트리거 (250ms 대기)
Debounce->>UI: 디바운스 완료
UI->>Kakao: searchAddressByKakao("강남", 10)
Kakao->>UI: 주소 결과 배열 반환
UI->>UI: 결과 목록 렌더링
User->>UI: 결과 항목 선택
UI->>Component: onSelectAddress(AddressSearchItem)
Component->>Component: inputAddress 상태 업데이트
UI->>UI: 바텀시트 닫기
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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. Review rate limit: 0/1 reviews remaining, refill in 51 minutes and 8 seconds.Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (1)
packages/api/src/models/random-box.ts (1)
25-25: ⚡ Quick win
SaleStatus | string타입 확장으로 인한 타입 안전성 손실
SaleStatus가string리터럴 유니언이라면SaleStatus | string은 단순한string으로 축소되어 타입 안전성이 제거됩니다. 런타임에 예상치 못한 값이 들어오더라도 TypeScript가 경고하지 않게 됩니다.♻️ 수정 제안
- saleStatus: SaleStatus | string; + saleStatus: SaleStatus;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/api/src/models/random-box.ts` at line 25, The saleStatus property is declared as "SaleStatus | string" which collapses the union to plain string and loses type safety; change the declaration on the RandomBox model (the saleStatus field) to use the strong SaleStatus type only, and if external input may contain arbitrary strings add a runtime validation/parse step (e.g., implement and call a parseSaleStatus or validateSaleStatus helper that maps/throws for invalid values) wherever RandomBox instances are created or deserialized so only valid SaleStatus values are assigned.
🤖 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/`(tabs)/mypage/store-info/page.tsx:
- Around line 91-102: The effect watching myStore doesn't initialize bank
account fields so saving can overwrite existing values; update the useEffect
that runs when myStore changes (the function using setStoreName, setStoreEmail,
setInputAddress, setBusinessHours and setSelectedTag) to also
setBankType(myStore.bankType ?? ""), setDepositor(myStore.depositor ?? ""), and
setBankAccount(myStore.bankAccount ?? "") (or corresponding local state setters)
so the local state mirrors existing myStore values and untouched fields are not
saved as empty/undefined.
In `@apps/owner/src/app/signup/register/_components/AddressSearchBottomSheet.tsx`:
- Around line 33-66: The effect in AddressSearchBottomSheet can allow stale,
slow searchAddressByKakao responses to overwrite newer results; update the
effect to cancel/ignore in-flight requests by creating an AbortController or a
local "cancelled" flag for each invocation (tied to debounceRef/useEffect) and
pass/associate it with searchAddressByKakao (or check the flag after await) so
that on cleanup (and when open becomes false) you mark the request cancelled and
skip setResults/setIsSearching if cancelled; ensure you clear debounceRef
timeout as now and also invalidate the current request in the same cleanup so
late responses are ignored.
In `@apps/owner/src/app/signup/register/_components/fields/AccountField.tsx`:
- Line 31: bankKeyword is initialized with useState(getBankLabel(bankType)) but
not updated when the bankType prop changes; add an effect that watches bankType
and calls setBankKeyword(getBankLabel(bankType)) to keep bankKeyword in sync
(use useEffect(() => setBankKeyword(getBankLabel(bankType)), [bankType]));
update references to bankKeyword/setBankKeyword accordingly so the displayed
bank label reflects prop updates.
In `@apps/owner/src/app/signup/register/_components/modals/RandomBoxModal.tsx`:
- Around line 87-88: The current checks in RandomBoxModal around
form.pickupTimeInfo (the two lines checking if (!form.pickupTimeInfo.start)
return; and if (!form.pickupTimeInfo.end) return;) only validate presence and
miss validating ordering; update the validation where the form is
submitted/validated (the submit handler or validation block that contains these
two checks) to also verify that form.pickupTimeInfo.start <
form.pickupTimeInfo.end, and if not, abort submission and surface a clear error
(e.g., set a form error or call the modal/form error handler) so users cannot
submit when the pickup end time is before or equal to the start time. Ensure you
reference and update the same RandomBoxModal validation/submit logic so the new
ordering check runs alongside the existing presence checks.
In `@apps/owner/src/app/signup/register/_utils/business-hours.ts`:
- Around line 17-19: parseBusinessHours가 반환하는 중첩 구조({ weekly: { MON:..., ... }
})와 맞지 않아 toFormValue와 handleSubmit에서 데이터가 유실됩니다: in toFormValue (uses
normalized = parseBusinessHours(source)) 참조 시 normalized.weekly에서 ServerDayKey
(예: "MON"/"TUE")로 조회하도록 변경하고 소문자 day 키 대신 올바른 서버 키로 변환하거나 normalized.weekly 전체를
순회해 값을 가져오세요; in handleSubmit 초기 acc를 얕은 복사({ ...EMPTY_BUSINESS_HOURS })가 아니라
EMPTY_BUSINESS_HOURS.weekly 구조를 유지하도록 깊은/구조적 복사하여 acc.weekly[...] =
"09:00-18:00" 형태로 할당하고 최종 반환/전송도 acc (또는 acc.weekly)를 사용해 weekly 필드가 업데이트되도록
고치세요 (참조: parseBusinessHours, toFormValue, handleSubmit, EMPTY_BUSINESS_HOURS,
BusinessHoursValue, weekly, ServerDayKey).
In `@apps/owner/src/app/signup/register/page.tsx`:
- Around line 90-101: The useEffect that hydrates myStore is missing
initialization of bank fields, so stored draft bank info can be lost; update the
effect to also call the bank-related setters (e.g., setBankType, setDepositor,
setBankAccount) with values from myStore (like myStore.bankType,
myStore.depositor, myStore.bankAccount) using nullish coalescing/defaults or any
existing mapping helpers you use for enums, mirroring the pattern used for
setStoreName/setInputAddress and the edit page logic to ensure existing account
info is prefilled.
In `@apps/owner/src/shared/types/kakao.d.ts`:
- Line 87: 빈 인터페이스로 인해 `@typescript-eslint/no-empty-object-type` 룰 위반이 발생하므로,
KakaoLatLng, KakaoMarkerImage, KakaoSize, KakaoPoint 인터페이스에 실제 멤버를 추가하거나 eslint
억제 주석을 붙여야 합니다; 특히 KakaoLatLng는 getLat(): number와 getLng(): number 메서드를 포함하도록
보완하고, 나머지 인터페이스(KakaoMarkerImage, KakaoSize, KakaoPoint)는 라이브러리 사용 형태에 맞는 최소한의
속성(예: width/height, x/y, url 등)을 선언하거나 불가피하면 interface 선언 바로 위에 /*
eslint-disable `@typescript-eslint/no-empty-object-type` */ 주석을 추가해 lint 실패를
방지하십시오.
In `@packages/api/src/models/random-box.ts`:
- Line 10: Change the saleStatus property type from the overly-broad union to
the exact literal type by updating the saleStatus declaration to use SaleStatus
(e.g., replace any occurrence of "saleStatus: SaleStatus | string" with
"saleStatus: SaleStatus") so the model preserves the discriminated union
benefits; keep pickupTimeInfo as JsonValue since getPickupTimeText expects a
JSON string and calls JSON.parse() on it.
---
Nitpick comments:
In `@packages/api/src/models/random-box.ts`:
- Line 25: The saleStatus property is declared as "SaleStatus | string" which
collapses the union to plain string and loses type safety; change the
declaration on the RandomBox model (the saleStatus field) to use the strong
SaleStatus type only, and if external input may contain arbitrary strings add a
runtime validation/parse step (e.g., implement and call a parseSaleStatus or
validateSaleStatus helper that maps/throws for invalid values) wherever
RandomBox instances are created or deserialized so only valid SaleStatus values
are assigned.
🪄 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: ca47d231-de4a-4355-9be4-7462530978a7
📒 Files selected for processing (12)
apps/owner/src/app/(tabs)/mypage/store-info/page.tsxapps/owner/src/app/signup/register/_apis/searchAddressBykakao.tsapps/owner/src/app/signup/register/_components/AddressSearchBottomSheet.tsxapps/owner/src/app/signup/register/_components/fields/AccountField.tsxapps/owner/src/app/signup/register/_components/modals/RandomBoxModal.tsxapps/owner/src/app/signup/register/_types/address-search.tsapps/owner/src/app/signup/register/_utils/business-hours.tsapps/owner/src/app/signup/register/page.tsxapps/owner/src/shared/types/kakao.d.tsapps/owner/src/shared/utils/bank.tspackages/api/src/models/random-box.tspackages/api/src/models/store.ts
| useEffect(() => { | ||
| if (!myStore) return; | ||
|
|
||
| setStoreName(myStore.storeName ?? ""); | ||
| setStoreEmail(""); | ||
| setStoreEmail(myStore.storeEmail ?? ""); | ||
| setInputAddress(myStore.inputAddress ?? ""); | ||
| setBusinessHours(parseBusinessHours(myStore.businessHours)); | ||
| setSelectedTag(mapStoreTagToLabel(myStore.tag)); | ||
|
|
||
| if (myStore.tag) { | ||
| setSelectedTag(reverseTagMap[myStore.tag as StoreTag] ?? ""); | ||
| } | ||
| }, [myStore]); |
There was a problem hiding this comment.
기존 계좌 정보가 초기화되지 않아 저장 시 값이 지워집니다.
이 effect에서 bankType, depositor, bankAccount를 로컬 상태로 옮기지 않고 있어서 수정 화면이 빈 값으로 열립니다. 사용자가 해당 필드를 건드리지 않고 저장하면 기존 계좌 정보가 "" / undefined로 덮일 수 있습니다.
🔧 수정 예시
useEffect(() => {
if (!myStore) return;
setStoreName(myStore.storeName ?? "");
setStoreEmail(myStore.storeEmail ?? "");
setInputAddress(myStore.inputAddress ?? "");
+ setBankType(myStore.bankType ?? "");
+ setDepositor(myStore.depositor ?? "");
+ setBankAccount(myStore.bankAccount ?? "");
setBusinessHours(parseBusinessHours(myStore.businessHours));
if (myStore.tag) {
setSelectedTag(reverseTagMap[myStore.tag as StoreTag] ?? "");
}
}, [myStore]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/owner/src/app/`(tabs)/mypage/store-info/page.tsx around lines 91 - 102,
The effect watching myStore doesn't initialize bank account fields so saving can
overwrite existing values; update the useEffect that runs when myStore changes
(the function using setStoreName, setStoreEmail, setInputAddress,
setBusinessHours and setSelectedTag) to also setBankType(myStore.bankType ??
""), setDepositor(myStore.depositor ?? ""), and
setBankAccount(myStore.bankAccount ?? "") (or corresponding local state setters)
so the local state mirrors existing myStore values and untouched fields are not
saved as empty/undefined.
| useEffect(() => { | ||
| if (!open) return; | ||
|
|
||
| const trimmedKeyword = keyword.trim(); | ||
|
|
||
| if (!trimmedKeyword) { | ||
| setResults([]); | ||
| setIsSearching(false); | ||
| return; | ||
| } | ||
|
|
||
| if (debounceRef.current) { | ||
| window.clearTimeout(debounceRef.current); | ||
| } | ||
|
|
||
| debounceRef.current = window.setTimeout(async () => { | ||
| try { | ||
| setIsSearching(true); | ||
| const searched = await searchAddressByKakao(trimmedKeyword, 10); | ||
| setResults(searched); | ||
| } catch (error) { | ||
| console.error(error); | ||
| setResults([]); | ||
| } finally { | ||
| setIsSearching(false); | ||
| } | ||
| }, 250); | ||
|
|
||
| return () => { | ||
| if (debounceRef.current) { | ||
| window.clearTimeout(debounceRef.current); | ||
| } | ||
| }; | ||
| }, [keyword, open]); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find and read the file
fd -type f -name "AddressSearchBottomSheet.tsx"Repository: CUK-Compasser/FE
Length of output: 231
🏁 Script executed:
# Fix the command - use -type without dash for fd
fd "AddressSearchBottomSheet.tsx"Repository: CUK-Compasser/FE
Length of output: 211
🏁 Script executed:
# Read the file to verify the code
cat -n "apps/owner/src/app/signup/register/_components/AddressSearchBottomSheet.tsx"Repository: CUK-Compasser/FE
Length of output: 4297
이전 검색 응답이 최신 결과를 덮어쓸 수 있습니다.
지금은 타이머만 정리하고 이미 시작된 searchAddressByKakao() 호출은 무시하지 않아서, 느린 이전 응답이 최신 키워드 결과를 덮어쓸 수 있습니다. BottomSheet를 닫은 뒤 늦게 도착한 응답이 빈 입력창 아래에 이전 결과를 다시 채우는 문제도 생깁니다. cleanup에서 요청을 무효화한 뒤, 응답 반영 전에 그 플래그를 확인해 주세요.
🔧 수정 예시
useEffect(() => {
if (!open) return;
const trimmedKeyword = keyword.trim();
if (!trimmedKeyword) {
setResults([]);
setIsSearching(false);
return;
}
+ let cancelled = false;
+
if (debounceRef.current) {
window.clearTimeout(debounceRef.current);
}
debounceRef.current = window.setTimeout(async () => {
try {
setIsSearching(true);
const searched = await searchAddressByKakao(trimmedKeyword, 10);
+ if (cancelled) return;
setResults(searched);
} catch (error) {
+ if (cancelled) return;
console.error(error);
setResults([]);
} finally {
+ if (cancelled) return;
setIsSearching(false);
}
}, 250);
return () => {
+ cancelled = true;
if (debounceRef.current) {
window.clearTimeout(debounceRef.current);
}
};
}, [keyword, open]);📝 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.
| useEffect(() => { | |
| if (!open) return; | |
| const trimmedKeyword = keyword.trim(); | |
| if (!trimmedKeyword) { | |
| setResults([]); | |
| setIsSearching(false); | |
| return; | |
| } | |
| if (debounceRef.current) { | |
| window.clearTimeout(debounceRef.current); | |
| } | |
| debounceRef.current = window.setTimeout(async () => { | |
| try { | |
| setIsSearching(true); | |
| const searched = await searchAddressByKakao(trimmedKeyword, 10); | |
| setResults(searched); | |
| } catch (error) { | |
| console.error(error); | |
| setResults([]); | |
| } finally { | |
| setIsSearching(false); | |
| } | |
| }, 250); | |
| return () => { | |
| if (debounceRef.current) { | |
| window.clearTimeout(debounceRef.current); | |
| } | |
| }; | |
| }, [keyword, open]); | |
| useEffect(() => { | |
| if (!open) return; | |
| const trimmedKeyword = keyword.trim(); | |
| if (!trimmedKeyword) { | |
| setResults([]); | |
| setIsSearching(false); | |
| return; | |
| } | |
| let cancelled = false; | |
| if (debounceRef.current) { | |
| window.clearTimeout(debounceRef.current); | |
| } | |
| debounceRef.current = window.setTimeout(async () => { | |
| try { | |
| setIsSearching(true); | |
| const searched = await searchAddressByKakao(trimmedKeyword, 10); | |
| if (cancelled) return; | |
| setResults(searched); | |
| } catch (error) { | |
| if (cancelled) return; | |
| console.error(error); | |
| setResults([]); | |
| } finally { | |
| if (cancelled) return; | |
| setIsSearching(false); | |
| } | |
| }, 250); | |
| return () => { | |
| cancelled = true; | |
| if (debounceRef.current) { | |
| window.clearTimeout(debounceRef.current); | |
| } | |
| }; | |
| }, [keyword, open]); |
🤖 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/AddressSearchBottomSheet.tsx`
around lines 33 - 66, The effect in AddressSearchBottomSheet can allow stale,
slow searchAddressByKakao responses to overwrite newer results; update the
effect to cancel/ignore in-flight requests by creating an AbortController or a
local "cancelled" flag for each invocation (tied to debounceRef/useEffect) and
pass/associate it with searchAddressByKakao (or check the flag after await) so
that on cleanup (and when open becomes false) you mark the request cancelled and
skip setResults/setIsSearching if cancelled; ensure you clear debounceRef
timeout as now and also invalidate the current request in the same cleanup so
late responses are ignored.
| }: AccountFieldProps) { | ||
| const [step, setStep] = useState<AccountStep>("bank"); | ||
| const [bankKeyword, setBankKeyword] = useState(bankName); | ||
| const [bankKeyword, setBankKeyword] = useState(getBankLabel(bankType)); |
There was a problem hiding this comment.
bankKeyword 상태가 bankType prop 변경 시 동기화되지 않음
useState(getBankLabel(bankType))는 첫 렌더링 시에만 초기값을 사용합니다. API 응답 이후 부모가 bankType을 갱신해도 bankKeyword는 빈 문자열로 남아, 은행명 입력 필드가 비어 있는 채로 표시됩니다.
🐛 수정 제안 — useEffect로 동기화
const [bankKeyword, setBankKeyword] = useState(getBankLabel(bankType));
+
+ useEffect(() => {
+ if (bankType) {
+ setBankKeyword(getBankLabel(bankType));
+ }
+ }, [bankType]);🤖 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` at
line 31, bankKeyword is initialized with useState(getBankLabel(bankType)) but
not updated when the bankType prop changes; add an effect that watches bankType
and calls setBankKeyword(getBankLabel(bankType)) to keep bankKeyword in sync
(use useEffect(() => setBankKeyword(getBankLabel(bankType)), [bankType]));
update references to bankKeyword/setBankKeyword accordingly so the displayed
bank label reflects prop updates.
| if (!form.pickupTimeInfo.start) return; | ||
| if (!form.pickupTimeInfo.end) return; |
There was a problem hiding this comment.
픽업 종료 시간이 시작 시간보다 이른 경우를 검증하지 않음
현재 비어있는지만 확인할 뿐, start < end 검증이 없어 종료 시간이 시작 시간보다 앞선 값도 제출될 수 있습니다.
🛡️ 수정 제안
if (!form.pickupTimeInfo.start) return;
if (!form.pickupTimeInfo.end) return;
+ if (form.pickupTimeInfo.start >= form.pickupTimeInfo.end) return;📝 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.
| if (!form.pickupTimeInfo.start) return; | |
| if (!form.pickupTimeInfo.end) return; | |
| if (!form.pickupTimeInfo.start) return; | |
| if (!form.pickupTimeInfo.end) return; | |
| if (form.pickupTimeInfo.start >= form.pickupTimeInfo.end) return; |
🤖 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/modals/RandomBoxModal.tsx`
around lines 87 - 88, The current checks in RandomBoxModal around
form.pickupTimeInfo (the two lines checking if (!form.pickupTimeInfo.start)
return; and if (!form.pickupTimeInfo.end) return;) only validate presence and
miss validating ordering; update the validation where the form is
submitted/validated (the submit handler or validation block that contains these
two checks) to also verify that form.pickupTimeInfo.start <
form.pickupTimeInfo.end, and if not, abort submission and surface a clear error
(e.g., set a form error or call the modal/form error handler) so users cannot
submit when the pickup end time is before or equal to the start time. Ensure you
reference and update the same RandomBoxModal validation/submit logic so the new
ordering check runs alongside the existing presence checks.
| useEffect(() => { | ||
| if (!myStore) return; | ||
| if (!myStore) return; | ||
|
|
||
| setStoreName(myStore.storeName ?? ""); | ||
| setStoreEmail(""); | ||
| setStoreEmail(myStore.storeEmail ?? ""); | ||
| setInputAddress(myStore.inputAddress ?? ""); | ||
| setBusinessHours(parseBusinessHours(myStore.businessHours)); | ||
|
|
||
| if (myStore.tag) { | ||
| setSelectedTag(reverseTagMap[myStore.tag as StoreTag] ?? ""); | ||
| } | ||
| }, [myStore]); |
There was a problem hiding this comment.
등록 페이지도 기존 계좌 정보를 hydrate하지 않고 있습니다.
여기도 myStore에서 bankType, depositor, bankAccount를 세팅하지 않아서, 저장된 초안이 있어도 입력창은 비어 보이고 제출 시 기존 값이 비워질 수 있습니다. 위 수정 페이지와 동일하게 초기 상태를 채워 주세요.
🔧 수정 예시
useEffect(() => {
if (!myStore) return;
setStoreName(myStore.storeName ?? "");
setStoreEmail(myStore.storeEmail ?? "");
setInputAddress(myStore.inputAddress ?? "");
+ setBankType(myStore.bankType ?? "");
+ setDepositor(myStore.depositor ?? "");
+ setBankAccount(myStore.bankAccount ?? "");
setBusinessHours(parseBusinessHours(myStore.businessHours));
if (myStore.tag) {
setSelectedTag(reverseTagMap[myStore.tag as StoreTag] ?? "");
}
}, [myStore]);📝 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.
| useEffect(() => { | |
| if (!myStore) return; | |
| if (!myStore) return; | |
| setStoreName(myStore.storeName ?? ""); | |
| setStoreEmail(""); | |
| setStoreEmail(myStore.storeEmail ?? ""); | |
| setInputAddress(myStore.inputAddress ?? ""); | |
| setBusinessHours(parseBusinessHours(myStore.businessHours)); | |
| if (myStore.tag) { | |
| setSelectedTag(reverseTagMap[myStore.tag as StoreTag] ?? ""); | |
| } | |
| }, [myStore]); | |
| useEffect(() => { | |
| if (!myStore) return; | |
| setStoreName(myStore.storeName ?? ""); | |
| setStoreEmail(myStore.storeEmail ?? ""); | |
| setInputAddress(myStore.inputAddress ?? ""); | |
| setBankType(myStore.bankType ?? ""); | |
| setDepositor(myStore.depositor ?? ""); | |
| setBankAccount(myStore.bankAccount ?? ""); | |
| setBusinessHours(parseBusinessHours(myStore.businessHours)); | |
| if (myStore.tag) { | |
| setSelectedTag(reverseTagMap[myStore.tag as StoreTag] ?? ""); | |
| } | |
| }, [myStore]); |
🤖 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 - 101, The
useEffect that hydrates myStore is missing initialization of bank fields, so
stored draft bank info can be lost; update the effect to also call the
bank-related setters (e.g., setBankType, setDepositor, setBankAccount) with
values from myStore (like myStore.bankType, myStore.depositor,
myStore.bankAccount) using nullish coalescing/defaults or any existing mapping
helpers you use for enums, mirroring the pattern used for
setStoreName/setInputAddress and the edit page logic to ensure existing account
info is prefilled.
| }; | ||
| } | ||
|
|
||
| interface KakaoLatLng {} |
There was a problem hiding this comment.
빈 인터페이스 ESLint 오류 — CI 빌드 실패 가능성
KakaoLatLng, KakaoMarkerImage, KakaoSize, KakaoPoint 4개 인터페이스가 @typescript-eslint/no-empty-object-type 오류를 발생시킵니다. ESLint 오류 수준이므로 CI lint 단계에서 실패할 수 있습니다.
의미 있는 멤버를 추가하거나 eslint 억제 주석을 사용하는 방법으로 수정할 수 있습니다. KakaoLatLng는 실제로 getLat()/getLng() 메서드를 가지므로 타입을 보완하는 것이 가장 좋습니다.
🔧 수정 제안
- interface KakaoLatLng {}
+ interface KakaoLatLng {
+ getLat: () => number;
+ getLng: () => number;
+ }
- interface KakaoMarkerImage {}
+ // eslint-disable-next-line `@typescript-eslint/no-empty-object-type`
+ interface KakaoMarkerImage {}
- interface KakaoSize {}
+ // eslint-disable-next-line `@typescript-eslint/no-empty-object-type`
+ interface KakaoSize {}
- interface KakaoPoint {}
+ // eslint-disable-next-line `@typescript-eslint/no-empty-object-type`
+ interface KakaoPoint {}Also applies to: 99-99, 101-101, 103-103
🧰 Tools
🪛 ESLint
[error] 87-87: An empty interface declaration allows any non-nullish value, including literals like 0 and "".
- If that's what you want, disable this lint rule with an inline comment or configure the 'allowInterfaces' rule option.
- If you want a type meaning "any object", you probably want
objectinstead. - If you want a type meaning "any value", you probably want
unknowninstead.
(@typescript-eslint/no-empty-object-type)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/owner/src/shared/types/kakao.d.ts` at line 87, 빈 인터페이스로 인해
`@typescript-eslint/no-empty-object-type` 룰 위반이 발생하므로, KakaoLatLng,
KakaoMarkerImage, KakaoSize, KakaoPoint 인터페이스에 실제 멤버를 추가하거나 eslint 억제 주석을 붙여야
합니다; 특히 KakaoLatLng는 getLat(): number와 getLng(): number 메서드를 포함하도록 보완하고, 나머지
인터페이스(KakaoMarkerImage, KakaoSize, KakaoPoint)는 라이브러리 사용 형태에 맞는 최소한의 속성(예:
width/height, x/y, url 등)을 선언하거나 불가피하면 interface 선언 바로 위에 /* eslint-disable
`@typescript-eslint/no-empty-object-type` */ 주석을 추가해 lint 실패를 방지하십시오.
| stock?: number; | ||
| price?: number; | ||
| buyLimit?: number; | ||
| pickupTimeInfo?: JsonValue; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# pickupTimeInfo 응답 타입을 string으로 사용하는 모든 소비 코드 확인
rg -n "pickupTimeInfo" --type ts -A 3 -B 1Repository: CUK-Compasser/FE
Length of output: 6370
🏁 Script executed:
# Check JsonValue type definition
rg -n "type JsonValue|interface JsonValue" --type ts -A 5Repository: CUK-Compasser/FE
Length of output: 393
🏁 Script executed:
# Find getPickupTimeText function
rg -n "getPickupTimeText" --type ts -B 2 -A 8Repository: CUK-Compasser/FE
Length of output: 2547
🏁 Script executed:
# Check SaleStatus definition
rg -n "enum SaleStatus|type SaleStatus" --type ts -A 10Repository: CUK-Compasser/FE
Length of output: 635
🏁 Script executed:
# Check if there's any JSON serialization/deserialization in API handlers
rg -n "pickupTimeInfo" --type ts packages/api -B 3 -A 3Repository: CUK-Compasser/FE
Length of output: 1193
saleStatus: SaleStatus | string 타입을 SaleStatus로 정정 필요
SaleStatus는 이미 문자열 리터럴 유니온 타입("SOLD_OUT" | "READY" | "CANCELED")이므로, SaleStatus | string은 중복되어 평문 string으로 축약됩니다. 이로 인해 타입 안전성과 판별식 유니온의 이점이 사라집니다. 25번 줄을 saleStatus: SaleStatus로 수정하세요.
pickupTimeInfo의 경우, 요청 시 객체(JsonValue)를 받고 응답 시 JSON 직렬화 문자열로 반환하는 설계입니다. 소비 코드(getPickupTimeText)에서 문자열에 대해 JSON.parse()를 명시적으로 호출하므로 의도적이며 정상 작동합니다.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/api/src/models/random-box.ts` at line 10, Change the saleStatus
property type from the overly-broad union to the exact literal type by updating
the saleStatus declaration to use SaleStatus (e.g., replace any occurrence of
"saleStatus: SaleStatus | string" with "saleStatus: SaleStatus") so the model
preserves the discriminated union benefits; keep pickupTimeInfo as JsonValue
since getPickupTimeText expects a JSON string and calls JSON.parse() on it.
✅ 작업 내용
📝 Description
🚀 설계 의도 및 개선점
weekly(MON~SUN)구조로 리팩토링bankType enum서버 값 분리 처리조회/추가/삭제중심으로 단순화📎 기타 참고사항
Fixes #106
Summary by CodeRabbit
릴리스 노트
New Features
Improvements