Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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 @@ -54,7 +55,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 @@ -66,32 +66,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 @@ -105,8 +113,6 @@ export default function MyCreateExperiencesPage() {
? await uploadActivityImages(subImages)
: [];

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

// 4️⃣ payload 생성
const payload = {
...data,
Expand All @@ -128,9 +134,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 @@ -160,16 +176,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
80 changes: 60 additions & 20 deletions src/app/(global)/(mypage)/myUpdateExperiences/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ 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';

import Dropdown from '@/src/components/primitives/Dropdown';


interface Schedule {
date: string;
startTime: string;
Expand All @@ -47,6 +52,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 @@ -80,10 +86,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 @@ -196,18 +220,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 @@ -229,7 +261,6 @@ export default function MyUpdateExperiencesPage() {
/>
)}
/>

<FormInput
label='설명'
variant='experience'
Expand All @@ -238,19 +269,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 @@ -259,17 +296,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 @@ -290,6 +324,12 @@ export default function MyUpdateExperiencesPage() {
message='체험 등록이 완료되었습니다'
onClose={handleCloseModal}
/>
<ConfirmModal
isOpen={isConfirmOpen}
message='작업 중인 내용이 저장되지 않습니다. 정말 이동하시겠습니까?'
onConfirm={handleConfirm}
onCancel={handleCancel}
/>
</div>
);
}
Loading