-
Notifications
You must be signed in to change notification settings - Fork 1
[Feature/#199] 나의 푸드트럭 등록 / 수정 api #215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
…Value 분리 / 최적화를 위해 useToast 리팩토링 TODO: 푸드트럭 사진 관련해서도 지역처럼 리팩토링 필요
TODO : 서버에 필요한 형식에 맞게 포맷
TODO: handleSubmitFoodTruckInfo 함수 유효성 검증 추가 / 닉네임 중복 확인 관련 알맞게 로직 추가
TODO: 푸드트럭 등록/수정 form에 대한 전체적인 유효성 검증 확인 및 수정
Walkthrough푸드트럭 등록/수정 흐름을 재구성하고 API 연동·폼 초기화·검증 로직을 추가했으며, 날짜/열거형 유틸·상수·토스트/네비게이션 관련 동작을 다수 수정했습니다. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Form as FoodTruckForm
participant Hook as useFoodTruckForm
participant API as updateMyFoodTruckInfoApi / useFoodTruckDetail
participant Server as Backend
participant Query as ReactQuery
participant Toast as useToast
User->>Form: 수정 페이지 진입 (foodTruckId)
Form->>Hook: useFoodTruckForm(foodTruckId)
Hook->>API: GET /food-trucks/{id}
API->>Server: 요청
Server-->>API: FoodTruckDetailResponse
Hook->>Hook: resetFoodTruckFormValue(response, menus)
Hook-->>Form: formData, isEdit=true, previousName
User->>Form: 폼 수정 및 제출
Form->>Hook: handleSubmitFoodTruckInfo(data)
Hook->>Hook: 이름 변경 시 isNameChecked 검사 (handleCheckName 호출)
Hook->>API: PUT /food-trucks/{id} (updateMyFoodTruckInfoApi)
API->>Server: 요청
Server-->>API: 성공 응답
Hook->>Query: invalidate FOOD_TRUCKS_QUERY_KEY.ALL
Hook->>Toast: 성공 토스트
Hook->>Form: navigate(FOOD_TRUCK_MANAGEMENT)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
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
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 |
빌드 및 린트 결과모든 검사 통과 🎉
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 13
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
src/pages/@owner/upload-food-truck-images/UploadFoodTruckImages.tsx (1)
17-35: 렌더 중toast.error()/navigate()호출로 무한 루프·리렌더 위험Lines 23-26에서 가드 로직이 렌더 경로에서 직접 실행되며, 조기 반환이 없어 Line 28의
useFoodTruckForm(foodTruckIdNumber)이NaN값으로도 호출될 수 있습니다.navigate()호출 시 컴포넌트가 다시 마운트되어 사이드 이펙트가 반복적으로 발동할 수 있으므로, 가드 로직을useEffect로 이동하고 유효한 ID일 때만 훅을 호출하는 구조로 분리해야 합니다.Import 경로에 이중 슬래시 수정
Line 9:
@pages/@owner//food-truck-form/...→@pages/@owner/food-truck-form/...(다른 모든 import에서 단일 슬래시 사용)제안 diff
import { useNavigate, useParams } from 'react-router-dom'; import { FormProvider } from 'react-hook-form'; +import { useEffect } from 'react'; import useToast from '@hooks/use-toast'; import { ROUTES } from '@router/constant/routes'; import Navigation from '@components/layout/navigation/Navigation'; import { Icon } from '@components/icon/Icon'; import ErrorText from '@components/form/error-text/ErrorText'; import { useFoodTruckForm } from '@pages/@owner/food-truck-form/hooks/use-food-truck-form'; import { useUploadImages } from '@pages/@owner/upload-food-truck-images/hooks/use-upload-images'; import { UploadDescription, UploadFooter, UploadImagesGrid, } from '@pages/@owner/upload-food-truck-images/components'; export default function UploadFoodTruckImages() { const navigate = useNavigate(); const toast = useToast(); - const { foodTruckId } = useParams(); + const { foodTruckId } = useParams<{ foodTruckId: string }>(); const foodTruckIdNumber = Number(foodTruckId); - if (!foodTruckId || isNaN(foodTruckIdNumber)) { - toast.error('잘못된 접근입니다.'); - navigate(ROUTES.FOOD_TRUCK_MANAGEMENT); - } - - const methods = useFoodTruckForm(foodTruckIdNumber); + const isValidId = !!foodTruckId && Number.isFinite(foodTruckIdNumber); + useEffect(() => { + if (!isValidId) { + toast.error('잘못된 접근입니다.'); + navigate(ROUTES.FOOD_TRUCK_MANAGEMENT, { replace: true }); + } + }, [isValidId, navigate, toast]); + + if (!isValidId) return null; return ( - <FormProvider {...methods.methods}> - <UploadFoodTruck /> - </FormProvider> + <UploadFoodTruckImagesInner foodTruckIdNumber={foodTruckIdNumber} /> ); } +function UploadFoodTruckImagesInner({ + foodTruckIdNumber, +}: { + foodTruckIdNumber: number; +}) { + const methods = useFoodTruckForm(foodTruckIdNumber); + return ( + <FormProvider {...methods.methods}> + <UploadFoodTruck /> + </FormProvider> + ); +}src/pages/@owner/upload-food-truck-images/hooks/use-upload-images.ts (2)
16-48:location.state.formData직접 접근으로 인한 즉시 크래시 위험 (안전한 접근 + 가드 effect + 조기 bail 필요)Line 21에서
location.state가 없으면(리로드/직접 접근) 바로 런타임 에러가 발생합니다. 또한 Line 32-35는 훅 본문에서 side effect를 실행하는데, 이는 매번 렌더링할 때마다 실행되는 안티패턴입니다.state?.formData로 안전하게 접근하고, side effect는useEffect로 이동하여 redirect/toast 처리하며,formData없을 때 아래 effect/로직이 실행되지 않도록 조기 bail을 추가해주세요.제안 diff
export const useUploadImages = () => { const toast = useToast(); const navigate = useNavigate(); const location = useLocation(); const { foodTruckId } = useParams<{ foodTruckId: string }>(); - const formData = location.state.formData; + const formData = (location.state as { formData?: any } | null | undefined) + ?.formData; const [initialImageUrls, setInitialImageUrls] = useState<string[]>([]); const [images, setImages] = useState<DisplayImage[]>([]); const [error, setError] = useState<string | null>(null); const [imagePreviews, setImagePreviews] = useState<string[]>([]); const { mutateAsync: getPresignedUrl } = useFoodTruckImage(); const { mutateAsync: uploadToS3 } = useUploadImage(); const { mutateAsync: deleteFromS3 } = useDeleteImage(); - if (!formData) { - toast.error('잘못된 접근입니다.'); - navigate(ROUTES.FOOD_TRUCK_MANAGEMENT); - } + useEffect(() => { + if (!formData) { + toast.error('잘못된 접근입니다.'); + navigate(ROUTES.FOOD_TRUCK_MANAGEMENT, { replace: true }); + } + }, [formData, navigate, toast]); useEffect(() => { + if (!formData) return; const existingUrls: string[] = formData.photoUrls || []; setInitialImageUrls(existingUrls);
99-171: 컴포넌트와 훅 간 데이터 관리 접근 방식 통일 필요
UploadFoodTruckImages.tsx는useFoodTruckForm(foodTruckIdNumber)으로 FormProvider를 생성하지만,useUploadImages훅은 location.state.formData에만 의존하고 있어 두 가지 데이터 관리 방식이 혼재되어 있습니다.현재 흐름(FoodTruckPhoto → navigate with state)에서는 작동하지만, 직접 접근이나 페이지 새로고침 시 formData가 undefined가 되어 리다이렉트됩니다. 또한 FormProvider 컨텍스트가 useUploadImages에서 활용되지 않아 불필요한 오버헤드가 발생합니다.
- 옵션 A: useUploadImages가 useFormContext()를 통해 FormProvider의 폼 데이터를 직접 사용하도록 리팩토링
- 옵션 B: useUploadImages에 formData를 명시적으로 props로 전달하고 FormProvider 제거
둘 중 하나로 정리할 것을 권장합니다.
src/pages/@owner/set-region/SetRegion.tsx (2)
12-29: 훅이 유효성 검증 전에 호출됨 + 렌더 단계 사이드이펙트 without early return = 크리티컬SetRegion 컴포넌트가 여러 React 규칙을 위반하고 있습니다:
Line 18:
useFoodTruckForm(foodTruckIdNumber)가 Line 20의 유효성 검증보다 먼저 호출되어,NaN값으로 훅이 실행될 수 있습니다.Line 20-23: 유효성 검증 실패 시
toast.error()와navigate()를 렌더링 중에 호출하지만return null이 없어서, 컴포넌트가 계속 렌더링되고 무한 루프나 예상치 못한 동작이 발생할 수 있습니다.SetRegionContent (Line 36, 52-60):
location.state.formData접근 시location.state가 존재하는지 확인하지 않아 undefined 오류 발생 가능useRegion(formData, foodTruckId)호출이if (!formData)검증보다 먼저 있어서, undefined 값으로 훅이 실행됩니다.해결: (1) 모든 훅 호출 전에 유효성 검증, (2) 사이드이펙트를
useEffect로 이동, (3) 조건부 리턴 추가, (4) 상태 접근 시 optional chaining 사용.제안된 수정
export default function SetRegion() { const navigate = useNavigate(); const toast = useToast(); const { foodTruckId } = useParams(); const foodTruckIdNumber = Number(foodTruckId); - const methods = useFoodTruckForm(foodTruckIdNumber); - - if (!foodTruckId || isNaN(foodTruckIdNumber)) { - toast.error('잘못된 접근입니다.'); - navigate(ROUTES.FOOD_TRUCK_MANAGEMENT); - } + const isInvalid = !foodTruckId || Number.isNaN(foodTruckIdNumber); + + useEffect(() => { + if (!isInvalid) return; + toast.error('잘못된 접근입니다.'); + navigate(ROUTES.FOOD_TRUCK_MANAGEMENT, { replace: true }); + }, [isInvalid, navigate, toast]); + + if (isInvalid) return null; + + const methods = useFoodTruckForm(foodTruckIdNumber); return ( <FormProvider {...methods.methods}> <SetRegionContent /> </FormProvider> ); } function SetRegionContent() { const { foodTruckId } = useParams(); const navigate = useNavigate(); const location = useLocation(); - const formData = location.state.formData; + const formData = location.state?.formData; + + useEffect(() => { + if (formData) return; + navigate(ROUTES.FOOD_TRUCK_MANAGEMENT); + }, [formData, navigate]); const handleLeftClick = () => { if (!foodTruckId) { navigate(ROUTES.FOOD_TRUCK_MANAGEMENT); return; } const fromPage = location.state?.from; navigate(ROUTES.FOOD_TRUCK_FORM(foodTruckId), { state: { from: fromPage || 'food-truck-form', formData: formData, }, }); }; - const { handleSubmitRegion, handleResetRegionFoodTruck } = useRegion( - formData, - foodTruckId - ); - if (!formData) { + return null; + } + + const { handleSubmitRegion, handleResetRegionFoodTruck } = useRegion( + formData, + foodTruckId + );
32-60:location.state.formData직접 접근은 런타임 에러를 발생시킵니다Line 36의
location.state.formData는location.state가 undefined일 때 즉시 크래시됩니다. 또한 Line 52-55에서useRegion(formData, foodTruckId)를 호출하기 전에 Line 57-60의!formData가드 체크가 있어야 하는데, 현재는 순서가 뒤바뀌어 있습니다.다음과 같이 수정하세요:
const formData = location.state?.formData;로 optional chaining 적용!formData체크를useRegion호출 전으로 이동- 리다이렉트를
useEffect로 감싸서 렌더 중 호출 방지제안 수정
function SetRegionContent() { const { foodTruckId } = useParams(); const navigate = useNavigate(); const location = useLocation(); - const formData = location.state.formData; + const formData = location.state?.formData; + useEffect(() => { + if (formData) return; + navigate(ROUTES.FOOD_TRUCK_MANAGEMENT, { replace: true }); + }, [formData, navigate]); + + if (!formData) return null; + const { handleSubmitRegion, handleResetRegionFoodTruck } = useRegion( formData, foodTruckId ); - - if (!formData) { - navigate(ROUTES.FOOD_TRUCK_MANAGEMENT); - return null; - }src/pages/@owner/food-truck-form/FoodTruckForm.tsx (1)
37-73: 렌더 단계에서 toast/navigate 실행 + 가드보다 먼저 훅 호출 (순서 조정 필요)
useFoodTruckForm(foodTruckIdNumber)가 Line 46에서 먼저 실행되고, invalid-id 가드는 Line 69에서 처리됩니다.foodTruckId가 없거나 NaN이면 훅이 먼저 초기화되며, 내부의useFoodTruckDetail과useMenusQuery도 호출됩니다(쿼리 실행은enabled: !!foodTruckId조건으로 방지되지만, 훅 초기화는 불필요함).더 중요한 문제는 Line 70-72의
toast.error와navigate가 렌더 단계에서 실행된다는 점입니다. early return도 React 렌더 단계 이후에 적용되므로, side-effect가 이미 발생합니다. 가드를 훅 호출 위로 올리고, 네비게이션은useEffect로 옮겨주세요.Proposed fix
export default function FoodTruckForm() { const { foodTruckId } = useParams(); const foodTruckIdNumber = Number(foodTruckId); const navigate = useNavigate(); const location = useLocation(); const toast = useToast(); + const isInvalid = !foodTruckId || isNaN(foodTruckIdNumber); + useEffect(() => { + if (!isInvalid) return; + toast.error('잘못된 접근입니다.'); + navigate(ROUTES.FOOD_TRUCK_MANAGEMENT, { replace: true }); + }, [isInvalid, navigate, toast]); + + if (isInvalid) return null; + const { isEdit, methods, reset, isFormValid, handleSubmit, previousName } = useFoodTruckForm(foodTruckIdNumber); @@ - if (!foodTruckId || isNaN(foodTruckIdNumber)) { - toast.error('잘못된 접근입니다.'); - navigate(ROUTES.FOOD_TRUCK_MANAGEMENT); - return null; - }
🤖 Fix all issues with AI agents
In @apis/http-client.ts:
- Line 77: The generated http-client.ts currently hardcodes baseURL
("http://13.125.207.84:8000") in the axiosConfig; instead update the
swagger-typescript-api generation pipeline (package.json script invoking
swagger-typescript-api) to inject an environment variable (e.g.
VITE_API_BASE_URL) into the generator/template, switch to HTTPS URLs, and add
environment files (.env.development/.env.staging/.env.production) that set
VITE_API_BASE_URL (or pass $VITE_API_BASE_URL into the npm script), or customize
the swagger-typescript-api template so the generated code uses
import.meta.env.VITE_API_BASE_URL (or a runtime config) for baseURL rather than
modifying baseURL in http-client.ts directly.
In @package.json:
- Line 20: Confirm that the URL used by the "swagger-typescript-api" npm script
(http://13.125.207.84:8000/v3/api-docs) is correct: validate with the team that
13.125.207.84:8000 is the intended API server, verify the /v3/api-docs endpoint
returns the OpenAPI JSON/YAML, and switch the script to use HTTPS if the server
supports it (update the script in package.json accordingly) or replace the IP
with the canonical hostname if one exists.
In
@src/pages/@owner/food-truck-form/@section/basic-info-section/FoodTruckName.tsx:
- Around line 9-25: The right-side click handler is wired unconditionally so
checkNameDuplicated can run even when canCheckNameDuplicate is false; update
FoodTruckNameInput to guard the handler and/or disable the button: only pass
checkNameDuplicated to the UI component's handleRightClick when
canCheckNameDuplicate is true (otherwise pass undefined or a no-op), and ensure
the button receives a disabled prop (e.g., disabled={!canCheckNameDuplicate}) so
both click events and keyboard activation are prevented; apply the same change
for the other occurrences mentioned (lines ~35-43) that use handleRightClick and
the duplicate-check control.
In @src/pages/@owner/food-truck-form/api/index.ts:
- Around line 20-30: updateMyFoodTruckInfoApi returns response.data which is
optional on BaseResponseFoodTruckIdResponse and can be undefined; ensure callers
validate it (or add validation here). Either update the caller
(use-mutation-food-truck-form.ts onSuccess) to check that the returned value
from updateMyFoodTruckInfoApi is defined and handle the error path, or modify
updateMyFoodTruckInfoApi to validate response.data and throw a descriptive error
(or return a validated value via a type guard) before returning so callers
always receive a non-undefined payload.
In @src/pages/@owner/food-truck-form/hooks/use-basic-info.ts:
- Around line 40-55: The checkNameDuplicated function calls handleCheckName
which can throw; wrap the await handleCheckName(name) call in a try-catch inside
checkNameDuplicated, and in the catch set consistent form state using
setValue('isNameChecked', true, { shouldValidate: true }) and
setValue('isNameDuplicated', false, { shouldValidate: true }) then
setError('name', { message: /* use error.message or a user-friendly fallback */
}) or use a generic form-level error; ensure clearErrors('name') is only called
when the check succeeds and avoid leaving the form in an inconsistent state.
- Around line 27-34: When updating the name, the code always resets
isNameChecked to false which breaks submit in edit mode when the user reverts to
previousName; change updateName to detect if the new name equals previousName
and in that case set isNameChecked to true and isNameDuplicated to false
(otherwise keep the existing behavior). Modify updateName (which calls setValue)
to conditionally set isNameChecked and isNameDuplicated based on whether name
=== previousName so canCheckNameDuplicate and submission behave correctly.
In @src/pages/@owner/food-truck-form/hooks/use-mutation-food-truck-form.ts:
- Around line 12-33: The onError handler in useMutationFoodTruckForm is unsafe
because error is treated as having a message property; update the useMutation
call to specify the error type (e.g., useMutation<unknown, ApiError,
{foodTruckId:number; data:UpdateFoodTruckInfoApiRequest}, unknown>) or add a
runtime type guard inside onError (check for error && typeof (error as
any).message === 'string' or use Axios.isAxiosError) and then use the guarded
message when calling toast.error; update the mutate alias updateFoodTruckInfo
accordingly to keep types consistent.
In @src/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts:
- Around line 16-23: The schema foodTruckSchema currently allows isNameChecked
to be false (isNameChecked: z.boolean()) so the form can be valid before
duplicate-check; change isNameChecked to require true (e.g., z.literal(true) or
z.boolean().refine(v => v === true, "Name must be checked for duplicates")) and
add a custom error message to the isNameDuplicated refine (isNameDuplicated:
z.boolean().refine(v => v === false, "Name is duplicated") or similar) so both
fields produce clear validation errors and the form is only valid after
duplicate check.
In @src/pages/@owner/menu/hooks/use-menu-register.ts:
- Line 2: The import in use-menu-register.ts currently uses "import { ROUTES }
from '@router/constant/routes';" which is inconsistent with other hooks that use
the project alias "@/router/constant/routes"; update the import statement to use
the same "@/router/constant/routes" alias so ROUTES is imported consistently
across use-menu-register, use-menu-edit, and use-menu-mutations.
In @src/pages/@owner/set-region/hooks/use-region.ts:
- Around line 8-11: The signature useRegion currently declares formData as
required but the implementation uses optional chaining (formData?.regionCodes),
which hides missing data and delays the bug; either remove the optional chaining
and require callers to always pass a valid FoodTruckFormData (use
formData.regionCodes) or change the parameter to optional (formData?:
FoodTruckFormData) and add an early guard in useRegion (e.g., validate/return
default values or throw/redirect) so regionCodes access is safe; update all
references inside useRegion (regionCodes, any uses around lines 49-54) and
adjust callers accordingly to ensure consistency.
In @src/pages/@owner/upload-food-truck-images/UploadFoodTruckImages.tsx:
- Around line 9-10: The import path for useFoodTruckForm has a double slash
which can break module resolution; update the import to use a single slash
(i.e., change the import specifier referencing useFoodTruckForm in
UploadFoodTruckImages.tsx to
'@pages/@owner/food-truck-form/hooks/use-food-truck-form' while keeping the
useUploadImages import unchanged) so both hooks (useFoodTruckForm and
useUploadImages) use valid single-slash paths.
In @src/shared/components/region/hooks/use-region.ts:
- Around line 21-33: The toggle logic in handleSelectRegion can misidentify
regions when RegionResponse.code is optional; update comparisons to prioritize a
stable identifier (use id when present) and fall back to code only when id is
undefined, i.e., replace selectedRegions.some(r => r.code === region.code) and
filter(r => r.code !== region.code) with checks that compare r.id === region.id
if either side has an id, otherwise compare r.code === region.code while
guarding undefined, so selection/deselection uses id first and only uses code as
a guarded fallback.
🧹 Nitpick comments (6)
src/shared/components/region/hooks/use-region.ts (1)
16-18:initialRegions가 나중에 로드/변경되면 현재 state가 초기값을 반영 못할 수 있어요.
useState(initialRegions ?? [])는 최초 렌더에만 적용돼서, 서버에서 기존 지역을 받아온 뒤initialRegions가 업데이트되는 흐름이면 prefill이 안 될 수 있습니다. 의도적으로 “한 번만 초기화”하려는 게 아니라면 동기화 여부를 확인해 주세요.Also applies to: 21-33
src/shared/components/region/components/DepthSection.tsx (1)
57-73:id를 내려주는 변경은 좋고, 이제 선택/키도id기반으로 정리하는 걸 추천합니다.
- 지금은
handleToggleRegion에id를 포함시키지만,isSelected/key는 여전히code기반이라(selectedRegions.some(r => r.code === item.code),key={item.code})code가 optional인 경우 경고/오동작 여지가 있습니다.- 추가로
fullName에서depth1?.name/depth2?.name가null이면 템플릿 문자열에'undefined'가 섞일 수 있어 UI/저장 데이터 품질이 떨어질 수 있습니다.src/pages/@owner/menu/hooks/use-menu-mutations.ts (1)
21-23: 코드 중복:formData추출 로직세 개의 mutation 함수(
useRegisterMenuMutation,useEditMenuMutation,useDeleteMenuMutation)에서 동일한 패턴으로location.state?.formData를 추출하고 있습니다 (Lines 21-23, 72-74, 119-121).이 로직을 별도의 커스텀 훅으로 추출하면 코드 중복을 줄이고 유지보수성을 높일 수 있습니다.
리팩토링 제안
새로운 훅을 생성:
// src/pages/@owner/menu/hooks/use-food-truck-form-data.ts import { useLocation } from 'react-router-dom'; export const useFoodTruckFormData = () => { const location = useLocation(); return location.state?.formData; };그리고 각 mutation에서 사용:
- const location = useLocation(); - - const foodTruckFormData = location.state?.formData; + const foodTruckFormData = useFoodTruckFormData();src/shared/hooks/use-toast.ts (1)
29-32: useMemo 의존성 단순화 고려.현재
useMemo가 네 개의 콜백을 의존성으로 사용하고 있습니다. 모든 콜백이addToast에만 의존하므로,useMemo에서 직접addToast를 의존성으로 사용하여 의존성 체인을 단순화할 수 있습니다.♻️ 제안하는 리팩토링
- return useMemo( - () => ({ success, error, warning, info }), - [success, error, warning, info] - ); + return useMemo( + () => ({ success, error, warning, info }), + [addToast] + );이렇게 하면 의존성 체인이 단순해지고 리렌더링 로직이 더 명확해집니다.
src/pages/@owner/food-truck-form/@section/region-section/RegionSection.tsx (1)
38-42: 중복된 truthiness 체크 단순화 가능33번 라인에서
regionCodes를 빈 배열로 기본값 설정했으므로, 39번 라인의regionCodes &&체크는 불필요합니다. 빈 배열도 truthy하므로 길이만 확인하면 됩니다.♻️ 제안하는 리팩토링
<RegionButton text={ - regionCodes && regionCodes.length > 0 + regionCodes.length > 0 ? regionCodes.map(region => region.name).join(', ') : '' } handleClick={handleClick} />src/pages/@owner/food-truck-form/hooks/use-food-truck-form.ts (1)
84-95: 불필요한async키워드
updateFoodTruckInfo는useMutation의mutate함수이므로 Promise를 반환하지 않습니다.async키워드가 불필요합니다.제안된 수정
- const handleSubmitFoodTruckInfo = async (formData: FoodTruckFormData) => { + const handleSubmitFoodTruckInfo = (formData: FoodTruckFormData) => {
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (33)
apis/data-contracts.tsapis/http-client.tspackage.jsonsrc/pages/@owner/estimate/hooks/use-estimate-form.tssrc/pages/@owner/estimate/utils/format-estimate.tssrc/pages/@owner/food-truck-form/@section/basic-info-section/FoodTruckName.tsxsrc/pages/@owner/food-truck-form/@section/region-section/RegionSection.tsxsrc/pages/@owner/food-truck-form/FoodTruckForm.tsxsrc/pages/@owner/food-truck-form/api/index.tssrc/pages/@owner/food-truck-form/constants/food-truck.tssrc/pages/@owner/food-truck-form/hooks/use-basic-info.tssrc/pages/@owner/food-truck-form/hooks/use-food-truck-form.tssrc/pages/@owner/food-truck-form/hooks/use-mutation-food-truck-form.tssrc/pages/@owner/food-truck-form/schemas/food-truck-form.schema.tssrc/pages/@owner/food-truck-form/utils/format-food-truck-form.tssrc/pages/@owner/food-truck-form/utils/reset-food-truck-form-value.tssrc/pages/@owner/menu/hooks/use-menu-edit.tssrc/pages/@owner/menu/hooks/use-menu-list.tssrc/pages/@owner/menu/hooks/use-menu-mutations.tssrc/pages/@owner/menu/hooks/use-menu-register.tssrc/pages/@owner/set-region/SetRegion.tsxsrc/pages/@owner/set-region/hooks/use-region.tssrc/pages/@owner/upload-food-truck-images/UploadFoodTruckImages.tsxsrc/pages/@owner/upload-food-truck-images/hooks/use-food-truck-image.tssrc/pages/@owner/upload-food-truck-images/hooks/use-upload-images.tssrc/pages/food-truck-detail/hooks/use-food-truck-detail.tssrc/shared/components/region/components/DepthSection.tsxsrc/shared/components/region/hooks/use-region.tssrc/shared/constant/need-electricity.tssrc/shared/constant/payment-method.tssrc/shared/hooks/use-toast.tssrc/shared/utils/date/date-formatter.tssrc/shared/utils/normalize-enum-value.ts
💤 Files with no reviewable changes (1)
- apis/data-contracts.ts
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2026-01-06T04:01:35.227Z
Learnt from: holdn2
Repo: CHA-CALL/ChaCall-FE PR: 214
File: src/pages/@owner/menu/hooks/use-menu-list.ts:61-65
Timestamp: 2026-01-06T04:01:35.227Z
Learning: In src/pages/owner/menu/hooks/use-menu-list.ts, formData validation is only required when navigating to FOOD_TRUCK_FORM (via handleClickBack), not when navigating to MENU_REGISTER (via handleRegister), as MENU_REGISTER doesn't require formData to be defined.
Applied to files:
src/pages/@owner/menu/hooks/use-menu-register.tssrc/pages/@owner/menu/hooks/use-menu-edit.tssrc/pages/food-truck-detail/hooks/use-food-truck-detail.tssrc/pages/@owner/set-region/SetRegion.tsxsrc/pages/@owner/upload-food-truck-images/hooks/use-food-truck-image.tssrc/pages/@owner/food-truck-form/utils/reset-food-truck-form-value.tssrc/pages/@owner/food-truck-form/utils/format-food-truck-form.tssrc/pages/@owner/food-truck-form/@section/basic-info-section/FoodTruckName.tsxsrc/pages/@owner/food-truck-form/hooks/use-food-truck-form.tssrc/pages/@owner/food-truck-form/api/index.tssrc/pages/@owner/set-region/hooks/use-region.tssrc/pages/@owner/food-truck-form/hooks/use-basic-info.tssrc/pages/@owner/upload-food-truck-images/hooks/use-upload-images.tssrc/pages/@owner/menu/hooks/use-menu-mutations.tssrc/pages/@owner/food-truck-form/constants/food-truck.tssrc/pages/@owner/food-truck-form/@section/region-section/RegionSection.tsxsrc/pages/@owner/upload-food-truck-images/UploadFoodTruckImages.tsxsrc/pages/@owner/food-truck-form/schemas/food-truck-form.schema.tssrc/pages/@owner/food-truck-form/hooks/use-mutation-food-truck-form.tssrc/pages/@owner/food-truck-form/FoodTruckForm.tsx
📚 Learning: 2026-01-06T03:26:46.868Z
Learnt from: holdn2
Repo: CHA-CALL/ChaCall-FE PR: 214
File: src/pages/@owner/food-truck-form/utils/format-food-truck-form.ts:15-15
Timestamp: 2026-01-06T03:26:46.868Z
Learning: In the ChaCall-FE codebase, region.id in RegionResponse is marked as optional in the Swagger spec, but in practice it cannot be undefined when used in the food truck form context. Exception handling for invalid region data is already in place elsewhere in the codebase, so non-null assertions on region.id are acceptable in format-food-truck-form.ts.
Applied to files:
src/pages/food-truck-detail/hooks/use-food-truck-detail.tssrc/pages/@owner/set-region/SetRegion.tsxsrc/pages/@owner/food-truck-form/utils/reset-food-truck-form-value.tssrc/pages/@owner/food-truck-form/utils/format-food-truck-form.tssrc/pages/@owner/menu/hooks/use-menu-list.tssrc/pages/@owner/food-truck-form/hooks/use-food-truck-form.tssrc/pages/@owner/set-region/hooks/use-region.tssrc/pages/@owner/food-truck-form/@section/region-section/RegionSection.tsxsrc/pages/@owner/upload-food-truck-images/UploadFoodTruckImages.tsxsrc/pages/@owner/food-truck-form/schemas/food-truck-form.schema.tssrc/pages/@owner/food-truck-form/FoodTruckForm.tsx
📚 Learning: 2026-01-06T03:26:08.240Z
Learnt from: holdn2
Repo: CHA-CALL/ChaCall-FE PR: 214
File: src/pages/@owner/food-truck-form/utils/format-food-truck-form.ts:0-0
Timestamp: 2026-01-06T03:26:08.240Z
Learning: In the ChaCall-FE codebase, region.code in RegionResponse is marked as optional in the Swagger spec, but in practice it cannot be undefined when used in the food truck form context. Exception handling for invalid region data is already in place elsewhere in the codebase, so non-null assertions on region.code are acceptable in format-food-truck-form.ts.
Applied to files:
src/pages/@owner/set-region/SetRegion.tsxsrc/pages/@owner/food-truck-form/utils/reset-food-truck-form-value.tssrc/pages/@owner/food-truck-form/utils/format-food-truck-form.tssrc/shared/components/region/hooks/use-region.tssrc/pages/@owner/set-region/hooks/use-region.tssrc/pages/@owner/food-truck-form/@section/region-section/RegionSection.tsxsrc/pages/@owner/food-truck-form/schemas/food-truck-form.schema.tssrc/pages/@owner/food-truck-form/FoodTruckForm.tsx
📚 Learning: 2026-01-06T04:01:35.227Z
Learnt from: holdn2
Repo: CHA-CALL/ChaCall-FE PR: 214
File: src/pages/@owner/menu/hooks/use-menu-list.ts:61-65
Timestamp: 2026-01-06T04:01:35.227Z
Learning: In src/pages/owner/menu/hooks/use-menu-list.ts, enforce that formData validation is required only when navigating to FOOD_TRUCK_FORM via handleClickBack, and not when navigating to MENU_REGISTER via handleRegister. Implement conditional validation: if destination is FOOD_TRUCK_FORM, require formData to be defined; otherwise allow formData to be undefined. Add clear guards, keep type-safe checks, and create tests for both code paths to prevent regressions.
Applied to files:
src/pages/@owner/menu/hooks/use-menu-list.ts
🧬 Code graph analysis (18)
src/pages/@owner/menu/hooks/use-menu-register.ts (1)
src/router/constant/routes.ts (1)
ROUTES(1-33)
src/pages/food-truck-detail/hooks/use-food-truck-detail.ts (1)
apis/data-contracts.ts (1)
FoodTruckDetailResponse(1426-1516)
src/pages/@owner/set-region/SetRegion.tsx (6)
src/pages/set-region-global/SetRegion.tsx (1)
SetRegion(8-28)src/pages/@owner/food-truck-form/hooks/use-food-truck-form.ts (1)
useFoodTruckForm(38-106)src/router/constant/routes.ts (1)
ROUTES(1-33)src/shared/components/region/hooks/use-region.ts (1)
useRegion(12-49)src/pages/@owner/set-region/hooks/use-region.ts (1)
useRegion(8-55)src/pages/set-region-global/hooks/use-region.ts (1)
useRegion(7-27)
src/pages/@owner/upload-food-truck-images/hooks/use-food-truck-image.ts (1)
src/pages/@owner/upload-food-truck-images/api/index.ts (1)
uploadImage(26-44)
src/pages/@owner/food-truck-form/utils/reset-food-truck-form-value.ts (7)
apis/data-contracts.ts (2)
FoodTruckDetailResponse(1426-1516)MyFoodTruckMenuResponse(1042-1075)src/shared/utils/normalize-enum-value.ts (1)
normalizeEnumValue(1-11)src/shared/constant/available-quantity.ts (1)
AVAILABLE_QUANTITY(1-7)src/shared/constant/need-electricity.ts (1)
NEED_ELECTRICITY(1-5)src/shared/constant/payment-method.ts (1)
PAYMENT_METHOD(1-5)src/shared/constant/food-categories.ts (1)
FOOD_CATEGORIES(1-9)src/shared/utils/date/date-formatter.ts (1)
formatStringDatesToAvailableDates(73-104)
src/pages/@owner/food-truck-form/utils/format-food-truck-form.ts (3)
src/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts (1)
FoodTruckFormData(75-75)src/pages/@owner/food-truck-form/api/index.ts (1)
UpdateFoodTruckInfoApiRequest(4-19)src/shared/utils/date/date-formatter.ts (1)
formatAvailableDatesToString(109-120)
src/pages/@owner/menu/hooks/use-menu-list.ts (2)
src/router/constant/routes.ts (1)
ROUTES(1-33)src/pages/@owner/food-truck-form/utils/navigate-state.tsx (1)
getNavigateState(3-8)
src/shared/components/region/hooks/use-region.ts (1)
src/shared/components/region/constant/region.ts (1)
MAX_SELECTED(1-1)
src/pages/@owner/food-truck-form/hooks/use-food-truck-form.ts (7)
src/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts (2)
FoodTruckFormData(75-75)foodTruckSchema(16-73)src/pages/food-truck-detail/hooks/use-food-truck-detail.ts (1)
useFoodTruckDetail(16-46)src/pages/@owner/menu/hooks/use-menus-query.ts (1)
useMenusQuery(6-25)src/pages/@owner/food-truck-form/hooks/use-mutation-food-truck-form.ts (1)
useMutationFoodTruckForm(12-38)src/pages/@owner/food-truck-form/utils/reset-food-truck-form-value.ts (1)
resetFoodTruckFormValue(13-63)src/pages/@owner/food-truck-form/constants/food-truck.ts (1)
FOOD_TRUCK_ERROR_MESSAGE(37-88)src/pages/@owner/food-truck-form/utils/format-food-truck-form.ts (1)
formatFoodTruckForm(6-25)
src/pages/@owner/food-truck-form/api/index.ts (2)
src/api/apiRequest.ts (1)
apiRequest(28-126)apis/data-contracts.ts (1)
BaseResponseFoodTruckIdResponse(292-298)
src/pages/@owner/set-region/hooks/use-region.ts (3)
src/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts (1)
FoodTruckFormData(75-75)apis/data-contracts.ts (1)
RegionResponse(825-843)src/router/constant/routes.ts (1)
ROUTES(1-33)
src/pages/@owner/food-truck-form/hooks/use-basic-info.ts (3)
src/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts (1)
FoodTruckFormData(75-75)src/pages/@owner/food-truck-onboarding/hooks/use-food-truck-name.ts (1)
useFoodTruckName(7-44)src/pages/@owner/food-truck-form/constants/food-truck.ts (1)
FOOD_TRUCK_ERROR_MESSAGE(37-88)
src/pages/@owner/upload-food-truck-images/hooks/use-upload-images.ts (1)
src/router/constant/routes.ts (1)
ROUTES(1-33)
src/shared/hooks/use-toast.ts (2)
src/shared/utils/toast.ts (1)
ToastAtom(11-17)src/shared/constant/toast.ts (1)
TOAST_TYPE(3-8)
src/pages/@owner/menu/hooks/use-menu-mutations.ts (3)
src/router/constant/routes.ts (1)
ROUTES(1-33)src/pages/@owner/menu/api/index.ts (1)
deleteFoodTruckMenu(71-81)src/shared/querykey/food-trucks.ts (1)
FOOD_TRUCKS_QUERY_KEY(3-44)
src/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts (1)
src/pages/@owner/food-truck-form/constants/food-truck.ts (2)
FOOD_TRUCK_MAX_LENGTH(1-35)FOOD_TRUCK_ERROR_MESSAGE(37-88)
src/pages/@owner/food-truck-form/hooks/use-mutation-food-truck-form.ts (2)
src/pages/@owner/food-truck-form/api/index.ts (1)
UpdateFoodTruckInfoApiRequest(4-19)src/shared/querykey/food-trucks.ts (1)
FOOD_TRUCKS_QUERY_KEY(3-44)
src/shared/utils/date/date-formatter.ts (1)
src/shared/types/available-date.ts (1)
AvailableDate(2-6)
🔇 Additional comments (28)
src/pages/@owner/menu/hooks/use-menu-edit.ts (1)
12-42:formData가undefined일 때 타입 안전성 검토 필요
location.state?.formData는undefined일 수 있으며, Line 40에서 네비게이션 state로 전달됩니다. 메뉴 수정 페이지에서 뒤로가기 시 formData가 없는 경우의 동작을 명확히 정의해야 합니다.use-menu-list.ts의 Line 48-51처럼 formData가 없을 때의 가드 로직을 추가하거나, 이 경우가 발생하지 않음을 보장할 수 있다면 타입 단언을 고려하세요.
src/pages/@owner/menu/hooks/use-menu-mutations.ts (1)
56-58:formData가undefined일 때 타입 안전성 검토 필요
foodTruckFormData는undefined일 수 있지만, navigation state에 직접 전달되고 있습니다. 메뉴 등록/수정/삭제 후 MENU_LIST로 돌아갈 때 formData가 없는 경우를 고려해야 합니다.동일한 이슈가 Lines 103-105, 129-131에도 존재합니다.
src/pages/@owner/menu/hooks/use-menu-list.ts (2)
47-59:formData가드 로직 잘 구현됨
handleClickBack에서 formData가 없을 때 FOOD_TRUCK_MANAGEMENT로 이동하는 가드 로직이 잘 구현되어 있습니다. 이는 학습된 컨텍스트와 일치하며, FOOD_TRUCK_FORM 네비게이션 시 formData가 필수라는 요구사항을 올바르게 반영하고 있습니다.
61-65:MENU_REGISTER네비게이션 시formData처리 개선 필요
handleRegister에서getNavigateState(foodTruckFormData)를 호출하지만,foodTruckFormData는undefined일 수 있습니다.학습된 컨텍스트에 따르면, MENU_REGISTER로 이동할 때는 formData가 필수가 아닙니다. 따라서 다음 중 하나를 적용해야 합니다:
getNavigateState가undefined를 허용하도록 타입 정의 수정- formData가 있을 때만 state를 전달하도록 조건부 처리
- formData가 없을 때 기본값 제공
Based on learnings, MENU_REGISTER doesn't require formData to be defined.
수정 제안
옵션 1: 조건부 state 전달
const handleRegister = (foodTruckId: string) => { navigate(ROUTES.MENU_REGISTER(foodTruckId), { - state: getNavigateState(foodTruckFormData), + state: foodTruckFormData ? getNavigateState(foodTruckFormData) : undefined, }); };옵션 2: getNavigateState를 optional 파라미터로 수정
// navigate-state.tsx에서 export const getNavigateState = (formData?: FoodTruckFormData) => { return { from: 'food-truck-form', formData: formData, }; };⛔ Skipped due to learnings
Learnt from: holdn2 Repo: CHA-CALL/ChaCall-FE PR: 214 File: src/pages/@owner/menu/hooks/use-menu-list.ts:61-65 Timestamp: 2026-01-06T04:01:35.227Z Learning: In src/pages/owner/menu/hooks/use-menu-list.ts, formData validation is only required when navigating to FOOD_TRUCK_FORM (via handleClickBack), not when navigating to MENU_REGISTER (via handleRegister), as MENU_REGISTER doesn't require formData to be defined.Learnt from: holdn2 Repo: CHA-CALL/ChaCall-FE PR: 214 File: src/pages/@owner/food-truck-form/utils/format-food-truck-form.ts:15-15 Timestamp: 2026-01-06T03:26:46.868Z Learning: In the ChaCall-FE codebase, region.id in RegionResponse is marked as optional in the Swagger spec, but in practice it cannot be undefined when used in the food truck form context. Exception handling for invalid region data is already in place elsewhere in the codebase, so non-null assertions on region.id are acceptable in format-food-truck-form.ts.Learnt from: holdn2 Repo: CHA-CALL/ChaCall-FE PR: 214 File: src/pages/@owner/food-truck-form/utils/format-food-truck-form.ts:0-0 Timestamp: 2026-01-06T03:26:08.240Z Learning: In the ChaCall-FE codebase, region.code in RegionResponse is marked as optional in the Swagger spec, but in practice it cannot be undefined when used in the food truck form context. Exception handling for invalid region data is already in place elsewhere in the codebase, so non-null assertions on region.code are acceptable in format-food-truck-form.ts.src/pages/@owner/menu/hooks/use-menu-register.ts (1)
8-21: 이 리뷰는 부정확합니다. 현재 파일의 코드가getNavigateState를 호출하지 않습니다.use-menu-register.ts의
handleClickBack(라인 18-22)은getNavigateState를 호출하지 않습니다. 대신foodTruckFormData를 직접 state 객체에 전달하므로, undefined 값을 전달해도 타입 오류가 발생하지 않습니다. 만약getNavigateState타입 검증이 필요하다면 이는 use-menu-list.ts의handleRegister함수 (라인 61-65)에서 확인해야 합니다.Likely an incorrect or invalid review comment.
src/shared/constant/need-electricity.ts (1)
3-3: 라벨 변경이 적절합니다.'필요 없음'에서 '불필요'로 변경하여 더 간결하고 자연스러운 표현이 되었습니다.
src/pages/food-truck-detail/hooks/use-food-truck-detail.ts (1)
13-13: 쿼리 조건부 실행이 적절합니다.
enabled: !!foodTruckId옵션을 추가하여 유효하지 않은 ID로 불필요한 API 호출을 방지했습니다. React Query의 권장 패턴을 잘 따르고 있습니다.src/shared/utils/normalize-enum-value.ts (1)
1-11: enum 정규화 유틸리티가 잘 구현되었습니다.enum 값을 안전하게 정규화하는 유틸리티 함수입니다.
includes체크로 런타임 안전성을 보장하고, 타입 단언은 체크 후에만 사용되므로 안전합니다.src/pages/@owner/estimate/hooks/use-estimate-form.ts (1)
9-9: 날짜 포매팅 함수명 변경이 적절합니다.
formatEstimateDatesToAvailableDates에서formatStringDatesToAvailableDates로 변경하여 함수의 목적이 더 명확해졌습니다. 문자열 배열을AvailableDate객체로 변환한다는 의미가 잘 드러납니다.Also applies to: 70-70
src/pages/@owner/food-truck-form/constants/food-truck.ts (1)
26-26: 가능한 일정 최대 개수 증가 변경 사항 확인availableDates의 최대 개수가 2에서 4로 증가되었으며, 이 값은 79번 라인의 에러 메시지에 올바르게 반영됩니다.
src/pages/@owner/food-truck-form/@section/region-section/RegionSection.tsx (1)
33-33: 폼 데이터에서 regionCodes 직접 참조formData에서 regionCodes를 직접 읽어오도록 변경된 것을 확인했습니다.
src/pages/@owner/estimate/utils/format-estimate.ts (1)
5-5: 공통 유틸리티 함수로 리팩토링날짜 포맷팅 로직을 공통 유틸리티 함수
formatAvailableDatesToString로 추출하여 코드 중복을 제거했습니다. 유지보수성이 향상됩니다.Also applies to: 21-23, 39-41
src/pages/@owner/upload-food-truck-images/hooks/use-food-truck-image.ts (1)
43-43: 이미지 업로드 사용자 피드백 추가toast 알림을 추가하여 이미지 업로드 성공/실패에 대한 사용자 피드백을 제공합니다. UX 개선에 도움이 됩니다.
Also applies to: 48-53
src/shared/constant/payment-method.ts (1)
3-4: 결제 방법 상수 값이 백엔드 API 계약과 일치하므로 문제없습니다.현재 상수값('계좌이체', '무관')은 백엔드 API 계약(apis/data-contracts.ts)에서 이미 정의된 값과 정확히 일치합니다. normalizeEnumValue 함수가 API에서 반환된 값을 검증하므로 호환성 문제가 발생하지 않습니다.
src/pages/@owner/food-truck-form/utils/format-food-truck-form.ts (1)
6-25: 매핑 자체는 깔끔합니다 (region.id non-null은 현재 컨텍스트에서 수용 가능)
foodTruckServiceAreas: formData.regionCodes.map(region => region.id!)는 “실사용에서 region.id가 undefined가 아니다”는 기존 맥락(예외 처리가 다른 곳에 있음) 기준으로 괜찮아 보입니다. (Based on learnings, ...)
다만 API 스펙상photoUrls/availableDates가 필수 배열이면, 스키마에서 항상[]로 보장되는지 정도만 확인해두면 좋겠습니다.src/pages/@owner/food-truck-form/utils/reset-food-truck-form-value.ts (1)
17-33: enum normalize 실패 시 isError=true 처리: 서버 문자열과 상수 불일치 가능성은 한 번 더 확인 필요현재는
availableQuantity/needElectricity/paymentMethod가 상수에 없으면 바로isError: true인데, 서버가 내려주는 문자열(라벨)이 상수와 100% 일치한다는 전제가 필요합니다. 스웨거 예시/실데이터 기준으로 한 번만 더 맞춰보는 걸 권장합니다.src/pages/@owner/upload-food-truck-images/hooks/use-upload-images.ts (1)
136-139: 이슈 없음 - 현재 코드의 타입이 이미 일치합니다
foodTruckId는useParams<{ foodTruckId: string }>()에서string으로 명확히 타입되어 있으며,useDeleteImage훅의 mutation도{ foodTruckId: string; imageUrls: string[] }로 정의되어 있습니다. 따라서 현재 전달 방식이 올바르며 추가 타입 변환이 필요하지 않습니다.src/pages/@owner/food-truck-form/@section/basic-info-section/FoodTruckName.tsx (1)
45-50: 성공 메시지 조건 변경은 명확합니다
isNameChecked && !isNameDuplicated조건으로 “사용 가능한 이름” 노출하는 흐름이 이전보다 상태 의미가 분명해졌습니다.src/pages/@owner/food-truck-form/hooks/use-mutation-food-truck-form.ts (1)
35-38: 훅 API가 단순해서 사용처가 깔끔합니다
updateFoodTruckInfo만 노출하는 형태는 폼 submit 연동에 적절합니다.src/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts (1)
17-32: name/description max 에러 메시지 정합성 좋아졌습니다
상수 기반 max 제약 + 메시지 매칭이 명확합니다.src/pages/@owner/set-region/hooks/use-region.ts (1)
15-46: 상태 전달 방식(…formData + regionCodes 덮어쓰기)은 일관적입니다
from: 'set-region'+formData를 다시 싣는 패턴이 다른 스텝들과 잘 맞습니다.src/pages/@owner/food-truck-form/FoodTruckForm.tsx (1)
79-98: 등록/수정 타이틀 토글 + previousName 전달은 UX에 도움 됩니다
isEdit기반 타이틀(Line 82)과previousName전달(Line 87)로 수정 흐름이 자연스러워졌습니다.src/shared/utils/date/date-formatter.ts (2)
106-120: 역변환 유틸 추가는 API 포맷/폼 포맷 왕복에 유용합니다
AvailableDate[] -> string[]변환 함수 추가가 포맷 로직 응집도를 높였습니다.
68-105:replaceAll은 프로젝트 타깃에서 완전히 지원됩니다.
tsconfig.app.json에서"target": "ES2022","lib": ["ES2022", "DOM", "DOM.Iterable"]로 명시되어 있으며,String.prototype.replaceAll()은 ES2021에서 도입되었으므로 ES2022 타깃에서 네이티브로 지원됩니다. 라인 79의 코드는 호환성 걱정 없이 안전합니다.src/pages/@owner/food-truck-form/hooks/use-food-truck-form.ts (3)
69-82: LGTM!수정 모드와 등록 모드를 적절히 분기하여 폼 초기화를 처리하고 있습니다.
resetFoodTruckFormValue의 에러 케이스도 토스트로 사용자에게 알려주는 점이 좋습니다.
57-62: LGTM!메뉴 데이터를 올바르게 메모이제이션하고, 페이지네이션 데이터를 평탄화하여 사용하고 있습니다.
38-44: 등록(register)은 다른 페이지에서 별도로 처리되므로 이 훅의 구현은 정상입니다.현재 아키텍처에서 푸드트럭 등록과 수정은 완전히 분리된 흐름입니다. 신규 등록은
/owner/food-truck-onboarding페이지의use-food-truck-input.ts에서createNewFoodTruck으로 처리되며, 등록 완료 후 관리 페이지로 이동합니다. 이 폼은FOOD_TRUCK_FORM경로로 접근할 때만 사용되는데, FoodTruckForm.tsx의 69-72줄에서 유효한foodTruckId가 없으면 즉시 에러를 표시하고 뒤로 이동합니다. 따라서 이 훅은 기존 푸드트럭 수정만 처리하면 되며, 설계가 올바릅니다.Likely an incorrect or invalid review comment.
src/pages/@owner/food-truck-form/hooks/use-basic-info.ts (1)
123-151: LGTM!반환 객체가 잘 구조화되어 있고,
isNameChecked와isNameDuplicated상태가 적절히 노출되어 있습니다.
src/pages/@owner/food-truck-form/@section/basic-info-section/FoodTruckName.tsx
Show resolved
Hide resolved
src/pages/@owner/upload-food-truck-images/UploadFoodTruckImages.tsx
Outdated
Show resolved
Hide resolved
- 푸드트럭 이름 중복 확인 버튼 disabled 상태 추가 - 기존 이름일 때는 중복 여부 관련 없이도 유효성 통과되도록 수정 - checkNameDuplicated 에서 예외 처리 추가 - import 경로 수정
빌드 및 린트 결과모든 검사 통과 🎉
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @src/pages/@owner/food-truck-form/hooks/use-basic-info.ts:
- Around line 45-64: The checkNameDuplicated function can update state for a
stale name if the user changes the input before the API returns; to fix, capture
the name you are checking (e.g., const checkedName = formData.name) before
awaiting handleCheckName(checkedName), then after the await verify that
formData.name === checkedName (or otherwise that the current name matches
checkedName) and only then call setValue/setError/clearErrors; if they differ,
ignore the response. Use checkedName and handleCheckName(checkedName) as the
unique symbols to locate where to add this guard.
🧹 Nitpick comments (1)
src/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts (1)
21-22: refine 검증에 명시적인 에러 메시지를 추가하는 것을 권장합니다.현재
isNameChecked와isNameDuplicated필드의refine호출에 에러 메시지가 없어, 검증 실패 시 사용자에게 명확한 안내가 어려울 수 있습니다.💬 에러 메시지 추가 제안
- isNameChecked: z.boolean().refine(v => v === true), - isNameDuplicated: z.boolean().refine(v => v === false), + isNameChecked: z.boolean().refine(v => v === true, { + message: FOOD_TRUCK_ERROR_MESSAGE.nameDuplicate.notDuplicated, + }), + isNameDuplicated: z.boolean().refine(v => v === false, { + message: FOOD_TRUCK_ERROR_MESSAGE.nameDuplicate.duplicated, + }),이렇게 하면 폼 검증 실패 시
FOOD_TRUCK_ERROR_MESSAGE.nameDuplicate에 정의된 일관된 메시지를 사용자에게 표시할 수 있습니다.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/pages/@owner/food-truck-form/@section/basic-info-section/FoodTruckName.tsxsrc/pages/@owner/food-truck-form/hooks/use-basic-info.tssrc/pages/@owner/food-truck-form/schemas/food-truck-form.schema.tssrc/pages/@owner/menu/hooks/use-menu-mutations.tssrc/pages/@owner/upload-food-truck-images/UploadFoodTruckImages.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- src/pages/@owner/menu/hooks/use-menu-mutations.ts
- src/pages/@owner/food-truck-form/@section/basic-info-section/FoodTruckName.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2026-01-06T04:01:35.227Z
Learnt from: holdn2
Repo: CHA-CALL/ChaCall-FE PR: 214
File: src/pages/@owner/menu/hooks/use-menu-list.ts:61-65
Timestamp: 2026-01-06T04:01:35.227Z
Learning: In src/pages/owner/menu/hooks/use-menu-list.ts, formData validation is only required when navigating to FOOD_TRUCK_FORM (via handleClickBack), not when navigating to MENU_REGISTER (via handleRegister), as MENU_REGISTER doesn't require formData to be defined.
Applied to files:
src/pages/@owner/upload-food-truck-images/UploadFoodTruckImages.tsxsrc/pages/@owner/food-truck-form/hooks/use-basic-info.tssrc/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts
📚 Learning: 2026-01-06T03:26:46.868Z
Learnt from: holdn2
Repo: CHA-CALL/ChaCall-FE PR: 214
File: src/pages/@owner/food-truck-form/utils/format-food-truck-form.ts:15-15
Timestamp: 2026-01-06T03:26:46.868Z
Learning: In the ChaCall-FE codebase, region.id in RegionResponse is marked as optional in the Swagger spec, but in practice it cannot be undefined when used in the food truck form context. Exception handling for invalid region data is already in place elsewhere in the codebase, so non-null assertions on region.id are acceptable in format-food-truck-form.ts.
Applied to files:
src/pages/@owner/upload-food-truck-images/UploadFoodTruckImages.tsxsrc/pages/@owner/food-truck-form/hooks/use-basic-info.tssrc/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts
📚 Learning: 2026-01-06T03:26:08.240Z
Learnt from: holdn2
Repo: CHA-CALL/ChaCall-FE PR: 214
File: src/pages/@owner/food-truck-form/utils/format-food-truck-form.ts:0-0
Timestamp: 2026-01-06T03:26:08.240Z
Learning: In the ChaCall-FE codebase, region.code in RegionResponse is marked as optional in the Swagger spec, but in practice it cannot be undefined when used in the food truck form context. Exception handling for invalid region data is already in place elsewhere in the codebase, so non-null assertions on region.code are acceptable in format-food-truck-form.ts.
Applied to files:
src/pages/@owner/food-truck-form/hooks/use-basic-info.tssrc/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts
🧬 Code graph analysis (3)
src/pages/@owner/upload-food-truck-images/UploadFoodTruckImages.tsx (1)
src/pages/@owner/food-truck-form/hooks/use-food-truck-form.ts (1)
useFoodTruckForm(38-106)
src/pages/@owner/food-truck-form/hooks/use-basic-info.ts (3)
src/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts (1)
FoodTruckFormData(75-75)src/pages/@owner/food-truck-onboarding/hooks/use-food-truck-name.ts (1)
useFoodTruckName(7-44)src/pages/@owner/food-truck-form/constants/food-truck.ts (1)
FOOD_TRUCK_ERROR_MESSAGE(37-88)
src/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts (1)
src/pages/@owner/food-truck-form/constants/food-truck.ts (2)
FOOD_TRUCK_MAX_LENGTH(1-35)FOOD_TRUCK_ERROR_MESSAGE(37-88)
🔇 Additional comments (8)
src/pages/@owner/upload-food-truck-images/UploadFoodTruckImages.tsx (1)
1-9: import 문 추가가 적절합니다.새로운 검증 로직과 폼 초기화에 필요한 의존성들이 올바르게 추가되었습니다.
src/pages/@owner/food-truck-form/hooks/use-basic-info.ts (5)
9-9: useFoodTruckName 훅 통합이 적절합니다.중복 확인 로직을 재사용 가능한 훅으로 분리한 것은 좋은 설계입니다.
handleCheckName을 통해 API 호출과 토스트 메시지 처리가 일관되게 관리됩니다.Also applies to: 21-21
12-12: 함수 시그니처 변경이 적절합니다.
previousName매개변수 추가로 수정 모드에서 기존 이름과의 비교가 가능해졌습니다. 선택적 매개변수로 설계되어 기존 호출 코드와의 호환성도 유지됩니다.
30-39: 이름 변경 시 상태 초기화 로직이 올바릅니다.기존 이름과 동일한 경우 중복 체크를 스킵하고, 다른 경우 체크 상태를 초기화하는 로직이 명확합니다.
61-63: 에러 처리 방식이 적절합니다.빈 catch 블록이지만
useFoodTruckName훅의onError에서 토스트 메시지를 처리하므로 문제없습니다. 주석으로 명시되어 있어 의도가 명확합니다.
140-141: 반환 데이터 구조 변경이 스키마와 일치합니다.
nameDuplicate를isNameChecked와isNameDuplicated로 분리하여 검증 상태를 더 명확하게 표현합니다.src/pages/@owner/food-truck-form/schemas/food-truck-form.schema.ts (2)
8-13: import 문 정리가 적절합니다.새로 추가된 타입과 유틸리티 함수의 import가 스키마에서 사용되고 있으며, 순서도 논리적으로 구성되어 있습니다.
20-20: 에러 메시지 추가로 일관성이 향상되었습니다.
name과description필드의max검증에 상수화된 에러 메시지를 추가하여 코드의 일관성과 유지보수성이 개선되었습니다.Also applies to: 29-32
Glyph8
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
목표한 기능 구현에 흠잡을데 없이 잘 작성해주신 것 같습니다. Ip 노출 문제만 통일된 방식으로 결정되면 완벽하겠습니다.
| "build-storybook": "storybook build", | ||
| "chromatic": "npx chromatic --project-token=chpt_b45a4ae4e58f49f", | ||
| "swagger-typescript-api": "swagger-typescript-api generate -p http://52.79.221.101:8000/v3/api-docs -r -o ./apis --modular -d --extract-request-body --extract-response-body --extract-response-error --axios --clean-output", | ||
| "swagger-typescript-api": "swagger-typescript-api generate -p http://13.125.207.84:8000/v3/api-docs -r -o ./apis --modular -d --extract-request-body --extract-response-body --extract-response-error --axios --clean-output", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
직접 수정을 해보니 package.json에서 환경변수를 써서 처리하는 건 여러 방식 중 하나로 하면 가능한데 생성된 http-client.ts 같은 파일에서는 여전히 노출되는 문제가 있습니다.
그래서 제안하는 방식은, swagger typescript api 스크립트를 별도 파일로 분리 + 요청 완료시 ip주소 문자열을, 환경 변수 사용으로 덮어씌우도록 하는 코드를 추가하는 건 어떨까요?
.then에서 replace( "${apiBaseUrl}", import.meta.env.VITE_API_SERVER_URL );처럼
| // TODO: id 값이 있을 시 푸드트럭 정보 가져오기 | ||
| const { methods, reset, isFormValid, handleSubmit } = useFoodTruckForm(); | ||
| const { isEdit, methods, reset, isFormValid, handleSubmit, previousName } = | ||
| useFoodTruckForm(foodTruckIdNumber); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
프론트 측 문제는 아니지만, url을 바꾸면 푸드트럭 주인이 아니더라도 그 내용이 조회가 가능한 문제가 있습니다.
서버 측에서 적절한 사용자인지 확인을 하는 로직이 추가로 있기 + 임의 문자열로 보이게 하는 처리가 병행되면 좋을 것 같습니다.
📌 Related Issues
✅ 체크 리스트
📄 Tasks
📷 Screenshot
Summary by CodeRabbit
릴리스 노트
새 기능
개선 사항
✏️ Tip: You can customize this high-level summary in your review settings.