diff --git a/src/features/dashboard/hook/useEmailHook.ts b/src/features/dashboard/hook/useEmailHook.ts index f8d807ba..ade397c3 100644 --- a/src/features/dashboard/hook/useEmailHook.ts +++ b/src/features/dashboard/hook/useEmailHook.ts @@ -34,7 +34,7 @@ export const useSendEmail = () => { navigate(`/dashboard/${id}/mailBox`); }, onError: () => { - alert('메일 전송에 실패했습니다. 다시 시도해 주세요.'); + alert(`메일 전송에 실패했습니다. 다시 시도해 주세요.`); }, }); }; diff --git a/src/features/dashboard/model/store/EmailStore.tsx b/src/features/dashboard/model/store/EmailStore.tsx index b279d8ca..cd496191 100644 --- a/src/features/dashboard/model/store/EmailStore.tsx +++ b/src/features/dashboard/model/store/EmailStore.tsx @@ -5,7 +5,7 @@ interface EmailState { title: string; content: string; recipients: string[]; - reservationDate: string; // 2025-05-01T14:00:00.000Z + reservationDate: string; // 2025-05-01T14:00:00 targetType: 'ALL' | 'TICKET'; ticketId: number; setReservationEmailId: (reservationEmailId: number) => void; diff --git a/src/features/event/ui/DatePicker.tsx b/src/features/event/ui/DatePicker.tsx index f2540174..ef37c313 100644 --- a/src/features/event/ui/DatePicker.tsx +++ b/src/features/event/ui/DatePicker.tsx @@ -3,7 +3,7 @@ import DatePicker from 'react-datepicker'; import { ko } from 'date-fns/locale'; import 'react-datepicker/dist/react-datepicker.css'; import { FunnelState } from '../model/FunnelContext'; -import { formatISO } from '../../../shared/lib/date'; +import { formatDateLocalString, extractTimeFromDateString } from '../../../shared/lib/date'; interface DatePickerProps { className?: string; @@ -27,14 +27,30 @@ const EventDatePicker = ({ isLabel = false, }: DatePickerProps) => { const [startDate, setStartDate] = useState( - eventState?.startDate ? new Date(eventState.startDate) : initialStartDate ? new Date(initialStartDate) : new Date() + eventState?.startDate + ? new Date(eventState.startDate) + : initialStartDate + ? new Date(initialStartDate) + : new Date() ); const [endDate, setEndDate] = useState( - eventState?.endDate ? new Date(eventState.endDate) : initialEndDate ? new Date(initialEndDate) : new Date() + eventState?.endDate + ? new Date(eventState.endDate) + : initialEndDate + ? new Date(initialEndDate) + : new Date() + ); + + console.log('startDate', startDate); + console.log('endDate', endDate); + + const [startTime, setStartTime] = useState( + extractTimeFromDateString(eventState?.startDate || initialStartDate, '06:00') + ); + const [endTime, setEndTime] = useState( + extractTimeFromDateString(eventState?.endDate || initialEndDate, '23:00') ); - const [startTime, setStartTime] = useState('06:00'); - const [endTime, setEndTime] = useState('23:00'); useEffect(() => { const start = eventState?.startDate || initialStartDate; @@ -57,6 +73,20 @@ const EventDatePicker = ({ } }, [eventState, initialStartDate, initialEndDate]); + useEffect(() => { + if (eventState?.startDate || initialStartDate) { + const date = new Date(eventState?.startDate || initialStartDate!); + setStartDate(date); + setStartTime(extractTimeFromDateString(eventState?.startDate || initialStartDate, '06:00')); + } + if (eventState?.endDate || initialEndDate) { + const date = new Date(eventState?.endDate || initialEndDate!); + setEndDate(date); + setEndTime(extractTimeFromDateString(eventState?.endDate || initialEndDate, '23:00')); + } + }, [eventState?.startDate, eventState?.endDate, initialStartDate, initialEndDate]); + + const generateTimeOptions = () => { const options = []; for (let i = 0; i < 24; i++) { @@ -73,8 +103,8 @@ const EventDatePicker = ({ useEffect(() => { if (startDate && endDate) { - const startISO = formatISO(startDate, startTime); - const endISO = formatISO(endDate, endTime); + const startISO = formatDateLocalString(startDate, startTime); + const endISO = formatDateLocalString(endDate, endTime); if (setEventState) { setEventState(prev => ({ diff --git a/src/features/event/ui/FileUpload.tsx b/src/features/event/ui/FileUpload.tsx index 3d926e97..b075ef1c 100644 --- a/src/features/event/ui/FileUpload.tsx +++ b/src/features/event/ui/FileUpload.tsx @@ -36,7 +36,7 @@ const FileUpload = ({ return (

배너 사진 첨부

-

1MB 이하의 jpeg, png 파일만 등록할 수 있습니다.

+

4MB 이하의 jpeg, png 파일만 등록할 수 있습니다.

{ useEffect(() => { if (selectedDate) { const formattedDate = new Date(selectedDate); - formattedDate.setHours(parseInt(selectedHour, 10)); - formattedDate.setMinutes(parseInt(selectedMinute, 10)); - formattedDate.setSeconds(0); - formattedDate.setMilliseconds(0); + formattedDate.setHours(Number(selectedHour), Number(selectedMinute), 0, 0); - const isoString = formattedDate.toISOString(); // 2025-05-01T14:00:00.000Z - onChange(isoString); + const year = formattedDate.getFullYear(); + const month = String(formattedDate.getMonth() + 1).padStart(2, '0'); + const day = String(formattedDate.getDate()).padStart(2, '0'); + const hour = String(formattedDate.getHours()).padStart(2, '0'); + const minute = String(formattedDate.getMinutes()).padStart(2, '0'); + + const localString = `${year}-${month}-${day}T${hour}:${minute}:00`; + + onChange(localString); + console.log(localString); } }, [selectedDate, selectedHour, selectedMinute]); diff --git a/src/features/ticket/ui/TicketDatePicker.tsx b/src/features/ticket/ui/TicketDatePicker.tsx index a630e14a..858d6000 100644 --- a/src/features/ticket/ui/TicketDatePicker.tsx +++ b/src/features/ticket/ui/TicketDatePicker.tsx @@ -3,7 +3,7 @@ import DatePicker from 'react-datepicker'; import { ko } from 'date-fns/locale'; import 'react-datepicker/dist/react-datepicker.css'; import { TicketState } from '../model/TicketContext'; -import { formatISO } from '../../../shared/lib/date'; +import { formatDateLocalString } from '../../../shared/lib/date'; interface DatePickerProps { className?: string; @@ -44,8 +44,8 @@ const TicketDatePicker = ({ const timeOptions = generateTimeOptions(); useEffect(() => { - const newStartDate = startDate ? formatISO(startDate, startTime) : ''; - const newEndDate = endDate ? formatISO(endDate, endTime) : ''; + const newStartDate = startDate ? formatDateLocalString(startDate, startTime) : ''; + const newEndDate = endDate ? formatDateLocalString(endDate, endTime) : ''; if (setTicketState) { setTicketState(prev => ({ diff --git a/src/pages/dashboard/ui/EventInfoPage.tsx b/src/pages/dashboard/ui/EventInfoPage.tsx index 0771444b..d72b1c83 100644 --- a/src/pages/dashboard/ui/EventInfoPage.tsx +++ b/src/pages/dashboard/ui/EventInfoPage.tsx @@ -12,12 +12,14 @@ import KakaoMap from '../../../shared/ui/KakaoMap'; import { UpdateEventRequest } from '../../../features/dashboard/model/event'; import { useEventDetail } from '../../../entities/event/hook/useEventHook'; import { formatPhoneNumber } from '../../../shared/utils/phoneFormatter'; +import { useNavigate } from 'react-router-dom'; const EventInfoPage = () => { const queryClient = useQueryClient(); const [selectedOption, setSelectedOption] = useState(''); const { data } = useEventDetail(); const { mutate } = useUpdateEventHook(); + const navigate = useNavigate(); const handleSelect = (option: string) => { setSelectedOption(option); @@ -62,6 +64,7 @@ const EventInfoPage = () => { onSuccess: () => { alert('이벤트 정보가 저장되었습니다.'); queryClient.invalidateQueries({ queryKey: ['eventDetail', data.result.id] }); + navigate(`/dashboard/${data?.result.id}`); }, onError: error => { console.error('Error details:', error); diff --git a/src/pages/event/ui/create-event/EventInfoPage.tsx b/src/pages/event/ui/create-event/EventInfoPage.tsx index af5c17ef..73c16675 100644 --- a/src/pages/event/ui/create-event/EventInfoPage.tsx +++ b/src/pages/event/ui/create-event/EventInfoPage.tsx @@ -28,12 +28,18 @@ const EventInfoPage = ({ onValidationChange }: EventInfoPageProps) => { return (
- +
); diff --git a/src/pages/join/LogoutPage.tsx b/src/pages/join/LogoutPage.tsx index de7d5371..403409d7 100644 --- a/src/pages/join/LogoutPage.tsx +++ b/src/pages/join/LogoutPage.tsx @@ -22,7 +22,8 @@ const LogoutPage = () => { 'code' in error && ( (error as { code?: string }).code === 'TOKEN4001' || - (error as { code?: string }).code === 'TOKEN4004') + (error as { code?: string }).code === 'TOKEN4004' + ) ) { // 토큰 만료로 인한 자동 로그아웃이므로 조용히 처리 console.log('토큰 만료로 인한 자동 로그아웃', error); diff --git a/src/shared/lib/date.ts b/src/shared/lib/date.ts index b54f1bd2..a47ce7d2 100644 --- a/src/shared/lib/date.ts +++ b/src/shared/lib/date.ts @@ -21,6 +21,29 @@ export const formatISO = (date: Date, time: string): string => { const kstDate = new Date(newDate.getTime() + 9 * 60 * 60 * 1000); // UTC+9 return kstDate.toISOString(); }; + +export const extractTimeFromDateString = (dateString?: string, defaultTime = '06:00') => { + if (!dateString) return defaultTime; + const date = new Date(dateString); + const hours = date.getHours().toString().padStart(2, '0'); + const minutes = date.getMinutes().toString().padStart(2, '0'); + return `${hours}:${minutes}`; +} + +export const formatDateLocalString = (date: Date, time: string): string => { + const [hours, minutes] = time.split(':').map(Number); + const newDate = new Date(date); + newDate.setHours(hours, minutes, 0, 0); + + const year = newDate.getFullYear(); + const month = String(newDate.getMonth() + 1).padStart(2, '0'); + const day = String(newDate.getDate()).padStart(2, '0'); + const hour = String(newDate.getHours()).padStart(2, '0'); + const minute = String(newDate.getMinutes()).padStart(2, '0'); + + return `${year}-${month}-${day}T${hour}:${minute}:00`; +}; + export const formatUtcToKst = (utcString: string): string => { const utcDate = new Date(utcString); @@ -35,4 +58,3 @@ export const formatUtcToKst = (utcString: string): string => { return `${year}년 ${month}월 ${day}일 ${hours}:${minutes}`; }; - diff --git a/src/shared/ui/EventCard.tsx b/src/shared/ui/EventCard.tsx index ee39e4a1..33f9885b 100644 --- a/src/shared/ui/EventCard.tsx +++ b/src/shared/ui/EventCard.tsx @@ -133,8 +133,17 @@ const EventCard = ({ onDeleteSuccess?.(id); setIsModalOpen(false); }, - onError: () => { - alert('이벤트 삭제에 실패했습니다.'); + onError: (error: unknown) => { + if ( + typeof error === 'object' && + error !== null && + 'code' in error && + ( + error as { code? : string}).code === "EVENT4002" + ) { + console.log('참여자로 인한 이벤트 삭제 실패'); + alert('구매자가 있는 이벤트는 삭제가 불가합니다.'); + } setIsModalOpen(false); }, });