Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7872e07
feat: 기존 데이터가 있다면 폼 데이터 초기화
holdn2 Dec 23, 2025
1698113
feat: 메뉴 목록 조회 api를 이용하여 있다면 폼 데이터의 menu가 true 가 되도록 함
holdn2 Dec 23, 2025
35eb0e1
refactor: 다른 페이지 이동 시 getNavigateState 사용하도록 다시 롤백
holdn2 Dec 23, 2025
1d3d9f2
Merge branch 'develop' into feature/#199/food-truck-form-api
holdn2 Jan 3, 2026
535d2a3
code review: zod 스키마에서 수량, 전기, 결제 관련 유효성 검증 기본 string에서 enum으로 수정
holdn2 Jan 3, 2026
93eeb76
code review: normalizeEnumValue의 undefined 반환 처리
holdn2 Jan 3, 2026
017fe67
refactor: 활동가능지역 관련 로직 수정 및 오류 해결 / 가독성 및 유지보수를 위해 resetFoodTruckForm…
holdn2 Jan 3, 2026
ac68c43
code review: 코드 리뷰 반영
holdn2 Jan 3, 2026
102fed4
refactor: 푸드트럭 사진 관련 로직 수정
holdn2 Jan 3, 2026
a7613d7
code review: 코드리뷰 반영. 에러 방지 코드 추가
holdn2 Jan 3, 2026
9e6d4d0
chore: 스웨거 관련 명령어 수정 및 스웨거 업데이트
holdn2 Jan 4, 2026
75372e4
code review: UploadFoodTruckImages에서 훅 호출 전 foodTruckId 유효성 검증
holdn2 Jan 4, 2026
549542b
feat: 나의 푸드트럭 등록 및 수정 api 함수 구현 및 관련 훅 구현
holdn2 Jan 4, 2026
048c595
fix: 메뉴 등록 페이지로 갔다 돌아올 때도 state를 적절히 추가해서 에러가 생기지 않도록 수정함
holdn2 Jan 5, 2026
2f282ed
fix: 메뉴 등록 페이지로 갔다 돌아올 때도 state를 적절히 추가해서 에러가 생기지 않도록 수정함
holdn2 Jan 5, 2026
812888c
feat: 나의푸드트럭 등록/수정 api 연동 완료. 서버와의 오류 해결 필요
holdn2 Jan 5, 2026
a981621
refactor: 서버에서 받는 날짜 형식이 달라도 동일한 반환값을 내도록 함수 수정
holdn2 Jan 6, 2026
328eea5
fix: 서버에서 요청한데로 지역코드가 아닌 id로 보내도록 수정
holdn2 Jan 6, 2026
527735e
code review: formdata가 없을 때의 예외처리 추가
holdn2 Jan 6, 2026
cb80f29
feat: 닉네임 중복 검증 추가
holdn2 Jan 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/pages/@owner/estimate/hooks/use-estimate-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {
} from 'apis/data-contracts';
import { zodResolver } from '@hookform/resolvers/zod';

import { formatEstimateDatesToAvailableDates } from '@utils/date';
import { formatStringDatesToAvailableDates } from '@utils/date';
import {
estimateSchema,
type EstimateFormData,
Expand Down Expand Up @@ -67,7 +67,7 @@ export const useEstimateForm = (
{
location: estimateData.address ?? '',
detailLocation: estimateData.detailAddress ?? '',
availableDates: formatEstimateDatesToAvailableDates(
availableDates: formatStringDatesToAvailableDates(
estimateData.reservationDates ?? []
),
activeTime: estimateData.operationHour ?? undefined,
Expand Down
25 changes: 14 additions & 11 deletions src/pages/@owner/food-truck-form/FoodTruckForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { FormProvider } from 'react-hook-form';
import Navigation from '@layout/navigation/Navigation';
import { Icon } from '@icon/Icon';
import Button from '@ui/button/Button';
import { ROUTES } from '@router/constant/routes';
import useToast from '@hooks/use-toast';

import {
FoodTruckName,
FoodTruckDescription,
Expand All @@ -12,7 +15,6 @@ import {
FoodTruckOption,
FoodTruckPhoto,
} from '@pages/@owner/food-truck-form/@section/basic-info-section/index';

import {
AvailableQuantity,
NeedElectricity,
Expand All @@ -30,8 +32,6 @@ import {
} from '@pages/@owner/food-truck-form/constants/food-truck';
import ActiveTime from '@components/active-time/ActiveTime';
import ActiveDate from '@components/active-date/ActiveDate';
import useFoodTruckDetail from '@pages/food-truck-detail/hooks/use-food-truck-detail';
import { ROUTES } from '@router/constant/routes';

// 메인 컴포넌트
export default function FoodTruckForm() {
Expand All @@ -40,9 +40,10 @@ export default function FoodTruckForm() {

const navigate = useNavigate();
const location = useLocation();
const toast = useToast();

// TODO: id 값이 있을 시 푸드트럭 정보 가져오기
const { methods, reset, isFormValid, handleSubmit } = useFoodTruckForm();
const { isEdit, methods, reset, isFormValid, handleSubmit } =
useFoodTruckForm(foodTruckIdNumber);

const {
formActiveTime,
Expand All @@ -58,25 +59,27 @@ export default function FoodTruckForm() {
handleActiveDateSetValue,
handleActiveDateError,
} = useFoodTruckFormDate(methods);
// 서버에서 활동 가능 지역은 지역코드로 받아야함
const { foodTruckDetailData } = useFoodTruckDetail(foodTruckIdNumber);

useEffect(() => {
if (location.state?.formData && location.state?.from) {
reset(location.state.formData);
}
}, [location.state, reset]);

if (!foodTruckId || isNaN(foodTruckIdNumber)) {
toast.error('잘못된 접근입니다.');
navigate(ROUTES.FOOD_TRUCK_MANAGEMENT);
return null;
}

const handleNavigateBack = () => {
navigate(ROUTES.FOOD_TRUCK_MANAGEMENT);
};

return (
<FormProvider {...methods}>
<Navigation
centerContent={
foodTruckDetailData ? '나의 푸드트럭 수정' : '나의 푸드트럭 등록'
}
centerContent={isEdit ? '나의 푸드트럭 수정' : '나의 푸드트럭 등록'}
leftIcon={<Icon name='ic_back' />}
handleLeftClick={handleNavigateBack}
/>
Expand All @@ -91,7 +94,7 @@ export default function FoodTruckForm() {
handleActiveTimeSetValue={handleActiveTimeSetValue}
handleTimeDiscussRequiredSetValue={handleTimeDiscussRequiredSetValue}
/>
<RegionSection />
<RegionSection foodTruckId={foodTruckId} />
<MenuCategory />
<AvailableQuantity />
<NeedElectricity />
Expand Down
2 changes: 1 addition & 1 deletion src/pages/@owner/food-truck-form/constants/food-truck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const FOOD_TRUCK_MAX_LENGTH = {
},
availableDates: {
min: 1,
max: 2,
max: 4,
},
photoUrls: {
min: 1,
Expand Down
49 changes: 45 additions & 4 deletions src/pages/@owner/food-truck-form/hooks/use-food-truck-form.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { zodResolver } from '@hookform/resolvers/zod';
import { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';

import { formatStringDatesToAvailableDates } from '@utils/date';
import { FOOD_TRUCK_ERROR_MESSAGE } from '@pages/@owner/food-truck-form/constants/food-truck';
import {
foodTruckSchema,
type FoodTruckFormData,
} from '@pages/@owner/food-truck-form/schemas/food-truck-form.schema';
import useFoodTruckDetail from '@pages/food-truck-detail/hooks/use-food-truck-detail';
import { useMenusQuery } from '@pages/@owner/menu/hooks/use-menus-query';

const initialData = {
name: '',
Expand All @@ -25,10 +30,10 @@ const initialData = {
menus: false,
};

export const useFoodTruckForm = (prevData?: FoodTruckFormData) => {
export const useFoodTruckForm = (foodTruckIdNumber: number) => {
const methods = useForm<FoodTruckFormData>({
resolver: zodResolver(foodTruckSchema),
defaultValues: prevData ?? initialData,
defaultValues: initialData,
mode: 'onChange',
});

Expand All @@ -39,6 +44,41 @@ export const useFoodTruckForm = (prevData?: FoodTruckFormData) => {
setError,
} = methods;

// 기존 데이터가 있다면 수정 mode
const [isEdit, setIsEdit] = useState(false);

// 기존 등록 푸드트럭 데이터 조회
const { foodTruckDetailData } = useFoodTruckDetail(foodTruckIdNumber);

// 메뉴 등록 여부를 위한 조회
const { data: menuData } = useMenusQuery(foodTruckIdNumber, '최신순');

useEffect(() => {
if (foodTruckDetailData) {
setIsEdit(true);
reset({
name: foodTruckDetailData.name,
nameDuplicate: true,
description: foodTruckDetailData.description,
phoneNumber: foodTruckDetailData.phoneNumber,
regionCodes: foodTruckDetailData.regionCodes,
availableQuantity: foodTruckDetailData.availableQuantity,
needElectricity: foodTruckDetailData.needElectricity,
paymentMethod: foodTruckDetailData.paymentMethod,
menuCategories: foodTruckDetailData.menuCategories,
photoUrls: foodTruckDetailData.photoUrl,
operatingInfo: foodTruckDetailData.operatingInfo,
option: foodTruckDetailData.option,
availableDates: formatStringDatesToAvailableDates(
foodTruckDetailData.availableDates ?? []
),
activeTime: foodTruckDetailData.activeTime,
timeDiscussRequired: foodTruckDetailData.timeDiscussRequired,
menus: menuData !== undefined,
});
}
}, [foodTruckDetailData, menuData, reset]);

const onSubmit = async (formData: FoodTruckFormData) => {
if (!formData.nameDuplicate) {
setError('name', {
Expand All @@ -47,13 +87,14 @@ export const useFoodTruckForm = (prevData?: FoodTruckFormData) => {
return;
}
if (isValid && formData) {
//TODO: 계좌 등록 제출
// TODO: 푸드트럭 등록 api 호출
alert('푸드트럭 등록 제출');
}
};

return {
// Form methods
isEdit,
methods,
handleSubmit: handleSubmit(onSubmit),
reset,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ import {
FOOD_TRUCK_ERROR_MESSAGE,
FOOD_TRUCK_MAX_LENGTH,
} from '@pages/@owner/food-truck-form/constants/food-truck';
import { AVAILABLE_QUANTITY } from '@constant/available-quantity';
import { NEED_ELECTRICITY } from '@constant/need-electricity';
import { PAYMENT_METHOD } from '@constant/payment-method';
import { FOOD_CATEGORIES } from '@constant/food-categories';

import type { AvailableDate } from '@type/available-date';
import { validateFoodTruckFormTime } from '@pages/@owner/food-truck-form/utils/validate-food-truck-form-time';

Expand All @@ -34,10 +31,10 @@ export const foodTruckSchema = z.object({
FOOD_TRUCK_ERROR_MESSAGE.phoneNumber.required
),
regionCodes: z.array(z.custom<RegionResponse>()),
availableQuantity: z.nativeEnum(AVAILABLE_QUANTITY),
needElectricity: z.nativeEnum(NEED_ELECTRICITY),
paymentMethod: z.nativeEnum(PAYMENT_METHOD),
menuCategories: z.array(z.nativeEnum(FOOD_CATEGORIES)),
availableQuantity: z.string(),
needElectricity: z.string(),
paymentMethod: z.string(),
menuCategories: z.array(z.string()),
photoUrls: z.array(z.string()).min(1, {
message: FOOD_TRUCK_ERROR_MESSAGE.photoUrls.required,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const foodTruckDetailQuery = (foodTruckId: number) => ({
queryKey: FOOD_TRUCKS_QUERY_KEY.DETAIL(foodTruckId),
queryFn: () => getFoodTruckDetail(foodTruckId),
staleTime: 5000,
enabled: !!foodTruckId,
});

export default function useFoodTruckDetail(foodTruckId: number) {
Expand All @@ -19,7 +20,9 @@ export default function useFoodTruckDetail(foodTruckId: number) {
data: foodTruckDetailData,
isPending: isPendingFoodTruckDetail,
isError: isErrorFoodTruckDetail,
} = useQuery<FoodTruckDetailResponse | undefined>(foodTruckDetailQuery(foodTruckId));
} = useQuery<FoodTruckDetailResponse | undefined>(
foodTruckDetailQuery(foodTruckId)
);

const { mutate: updateSaveStatus } =
useUpdateFoodTruckSaveStatus(foodTruckId);
Expand Down
2 changes: 1 addition & 1 deletion src/shared/constant/need-electricity.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const NEED_ELECTRICITY = {
REQUIRED: '필요',
NOT_REQUIRED: '필요 없음',
NOT_REQUIRED: '불필요',
NEED_DISCUSSION: '논의 필요',
} as const;

Expand Down
4 changes: 2 additions & 2 deletions src/shared/constant/payment-method.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const PAYMENT_METHOD = {
CARD: '카드',
BANK_TRANSFER: '계좌 이체',
ANY: '아무거나',
BANK_TRANSFER: '계좌이체',
ANY: '무관',
} as const;

export type PaymentMethodKey = keyof typeof PAYMENT_METHOD;
4 changes: 2 additions & 2 deletions src/shared/utils/date/date-formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ export const formatSelectedDateToSchedules = (
};

/**
* 기존 견적서의 날짜를 AvailableDates 형식으로 포맷하는 함수
* string[] 형식의 날짜를 AvailableDates 형식으로 포맷하는 함수
* ["2025.09.20 ~ 2025.09.20", "2025.09.25 ~ 2025.09.25"]
* -> AvailableDate[]
*/
export const formatEstimateDatesToAvailableDates = (
export const formatStringDatesToAvailableDates = (
estimateDates: string[]
): AvailableDate[] => {
return estimateDates
Expand Down