Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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 public/images/icons/CalendarIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 41 additions & 17 deletions src/app/(global)/(mypage)/myCreateExperiences/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { useTimeSlotStore } from '@/src/store/TimeSlotStore';
import { useActivityStore } from '@/src/store/useActivityStore';
import { openDaumPostcode } from '@/src/utils/daumPostcode';
import { format } from 'date-fns';
import Image from 'next/image';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { useForm, SubmitHandler, Controller } from 'react-hook-form';
Expand Down Expand Up @@ -46,7 +47,6 @@ export default function MyCreateExperiencesPage() {
} = useForm<ExperiencesFormData>({ mode: 'onBlur' });
const [isAlertOpen, setIsAlertOpen] = useState(false);
const [isConfirmOpen, setIsConfirmOpen] = useState(false);

const router = useRouter();

const handleAddressClick = async () => {
Expand All @@ -58,32 +58,40 @@ export default function MyCreateExperiencesPage() {
}
};

const handleBackClick = () => {
setIsConfirmOpen(true);
};

const handleCloseModal = () => {
router.back();
};

const handleConfirm = () => {
setIsConfirmOpen(false);
router.back();
};

const handleCancel = () => {
setIsConfirmOpen(false);
};

const formatNumber = (value?: number) => {
if (value === undefined || value === null) return '';
return value.toLocaleString();
};
const { timeSlots } = useTimeSlotStore();
const selectedDate = useReservationStore(
(state) => state.dateSelector.selectedDate
);
const { bannerImages, subImages } = useActivityStore();

const onSubmit: SubmitHandler<ExperiencesFormData> = async (data) => {
console.log('소개 이미지 상태:', subImages);
try {
// 1️⃣ schedules 변환
const schedules: Schedule[] = timeSlots
.filter((slot) => slot.startTime && slot.endTime)
.map((slot) => ({
date: selectedDate ? format(selectedDate, 'yyyy-MM-dd') : '',
date: selectedDate ? format(selectedDate, 'yyyy-MM-dd') : 'yy/mm/dd',
startTime: slot.startTime!,
endTime: slot.endTime!,
}));
Expand All @@ -97,8 +105,6 @@ export default function MyCreateExperiencesPage() {
? await uploadActivityImages(subImages)
: [];

console.log('업로드 후 소개 이미지 URL:', subImageUrls);

// 4️⃣ payload 생성
const payload = {
...data,
Expand All @@ -120,9 +126,19 @@ export default function MyCreateExperiencesPage() {
<div>
<form
onSubmit={handleSubmit(onSubmit)}
className='flex flex-col gap-[30px]'
className='flex flex-col gap-[30px] mt-[78px] mb-[53px] px-6 lg:w-[700px] lg:mx-auto'
>
<h1 className='font-bold text-18 text-gray-950'>내 체험 등록</h1>
<div className='flex justify-between'>
<h1 className='font-bold text-18 text-gray-950'>내 체험 등록</h1>
<button onClick={handleBackClick}>
<Image
src='/images/icons/BackIcon.svg'
alt='BackIcon'
width={24}
height={24}
/>
</button>
</div>
<FormInput
label='제목'
variant='experience'
Expand Down Expand Up @@ -159,16 +175,24 @@ export default function MyCreateExperiencesPage() {
errorMessage={errors.description?.message}
{...register('description', { required: '필수 입력 항목입니다.' })}
/>
<FormInput
label='가격'
type='number'
variant='experience'
placeholder='체험 금액을 입력해 주세요'
errorMessage={errors.price?.message}
{...register('price', {
valueAsNumber: true,
required: '필수 입력 항목입니다.',
})}
<Controller
name='price'
control={control}
rules={{ required: '필수 입력 항목입니다.' }}
render={({ field }) => (
<FormInput
label='가격'
variant='experience'
placeholder='체험 금액을 입력해 주세요'
value={formatNumber(field.value)}
onChange={(e) => {
const raw = e.target.value.replace(/,/g, '');
const parsed = raw === '' ? undefined : Number(raw);
field.onChange(parsed);
}}
errorMessage={errors.price?.message}
/>
)}
/>
<FormInput
label='주소'
Expand Down
77 changes: 57 additions & 20 deletions src/app/(global)/(mypage)/myUpdateExperiences/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import { useTimeSlotStore } from '@/src/store/TimeSlotStore';
import { useActivityStore } from '@/src/store/useActivityStore';
import { openDaumPostcode } from '@/src/utils/daumPostcode';
import AlertModal from '@/src/components/primitives/modal/AlertModal';
import ConfirmModal from '@/src/components/primitives/modal/ConfirmModal';
import Image from 'next/image';

interface Schedule {
date: string;
Expand All @@ -46,6 +48,7 @@ export default function MyUpdateExperiencesPage() {
const { id } = useParams<{ id: string }>();
const router = useRouter();
const [isAlertOpen, setIsAlertOpen] = useState(false);
const [isConfirmOpen, setIsConfirmOpen] = useState(false);
const [existingSubImages, setExistingSubImages] = useState<
{ id: number; url: string }[]
>([]);
Expand Down Expand Up @@ -79,10 +82,28 @@ export default function MyUpdateExperiencesPage() {
}
};

const handleBackClick = () => {
setIsConfirmOpen(true);
};

const handleConfirm = () => {
setIsConfirmOpen(false);
router.back();
};

const handleCancel = () => {
setIsConfirmOpen(false);
};

const handleCloseModal = () => {
router.back();
};

const formatNumber = (value?: number) => {
if (value === undefined || value === null) return '';
return value.toLocaleString();
};

const { timeSlots, setTimeSlots } = useTimeSlotStore();
const { bannerImages, subImages, setBannerImages, setSubImages } =
useActivityStore();
Expand Down Expand Up @@ -195,18 +216,26 @@ export default function MyUpdateExperiencesPage() {
<div>
<form
onSubmit={handleSubmit(onSubmit)}
className='flex flex-col gap-[30px]'
className='flex flex-col gap-[30px] mt-[78px] mb-[53px] px-6 lg:w-[700px] lg:mx-auto'
>
<h1 className='font-bold text-18 text-gray-950'>체험 수정하기</h1>

<div className='flex justify-between'>
<h1 className='font-bold text-18 text-gray-950'>체험 수정하기</h1>
<button onClick={handleBackClick}>
<Image
src='/images/icons/BackIcon.svg'
alt='BackIcon'
width={24}
height={24}
/>
</button>
</div>
<FormInput
label='제목'
variant='experience'
placeholder='제목을 입력해 주세요'
errorMessage={errors.title?.message}
{...register('title', { required: '필수 입력 항목입니다.' })}
/>

<Controller
name='category'
control={control}
Expand All @@ -228,7 +257,6 @@ export default function MyUpdateExperiencesPage() {
/>
)}
/>

<FormInput
label='설명'
variant='experience'
Expand All @@ -237,19 +265,25 @@ export default function MyUpdateExperiencesPage() {
errorMessage={errors.description?.message}
{...register('description', { required: '필수 입력 항목입니다.' })}
/>

<FormInput
label='가격'
type='number'
variant='experience'
placeholder='체험 금액을 입력해 주세요'
errorMessage={errors.price?.message}
{...register('price', {
valueAsNumber: true,
required: '필수 입력 항목입니다.',
})}
<Controller
name='price'
control={control}
rules={{ required: '필수 입력 항목입니다.' }}
render={({ field }) => (
<FormInput
label='가격'
variant='experience'
placeholder='체험 금액을 입력해 주세요'
value={formatNumber(field.value)}
onChange={(e) => {
const raw = e.target.value.replace(/,/g, '');
const parsed = raw === '' ? undefined : Number(raw);
field.onChange(parsed);
}}
errorMessage={errors.price?.message}
/>
)}
/>

<FormInput
label='주소'
placeholder='주소를 입력해 주세요'
Expand All @@ -258,17 +292,14 @@ export default function MyUpdateExperiencesPage() {
errorMessage={errors.address?.message}
onClick={handleAddressClick}
/>

<AvailableTimeSlots />

<UploadBannerImage
label='배너'
maxImages={1}
files={bannerImages}
setImages={setBannerImages}
existingImages={bannerUrls}
/>

<UploadBannerImage
label='소개'
maxImages={4}
Expand All @@ -289,6 +320,12 @@ export default function MyUpdateExperiencesPage() {
message='체험 등록이 완료되었습니다'
onClose={handleCloseModal}
/>
<ConfirmModal
isOpen={isConfirmOpen}
message='작업 중인 내용이 저장되지 않습니다. 정말 이동하시겠습니까?'
onConfirm={handleConfirm}
onCancel={handleCancel}
/>
</div>
);
}
Loading
Loading