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
3 changes: 3 additions & 0 deletions public/assets/event-manage/details/Clock.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions src/entities/host/ui/HostEditForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import useHostChannelInfo from '../hook/useHostChannelInfoHook';
import { useHostInfoSave } from '../../../features/host/hook/useHostInfoHook';
import { hostInfoSchema } from '../../../shared/lib/formValidation';
import DefaultTextField from '../../../../design-system/ui/textFields/DefaultTextField';
import TertiaryButton from '../../../../design-system/ui/buttons/TertiaryButton';
import MultilineTextField from '../../../../design-system/ui/textFields/MultilineTextField';

const HostEditForm = () => {
const { id } = useParams<{ id: string }>();
const hostChannelId = Number(id);

const [email, setEmail] = useState('');
const [channelDescription, setChannelDescription] = useState('');

const { data: hostInfo } = useHostChannelInfo(hostChannelId);
const { handleSave } = useHostInfoSave(hostChannelId, hostInfo!, email, channelDescription);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

위험한 Non-null assertion 사용

hostInfo!와 같은 non-null assertion 사용은 hostInfoundefined일 때 런타임 오류를 발생시킬 수 있습니다. 조건부 렌더링이나 적절한 기본값 처리를 고려해보세요.

-  const { handleSave } = useHostInfoSave(hostChannelId, hostInfo!, email, channelDescription);
+  const { handleSave } = useHostInfoSave(hostChannelId, hostInfo, email, channelDescription);

또는 컴포넌트 전체를 조건부로 렌더링하는 방식을 고려하세요.

🤖 Prompt for AI Agents
In src/entities/host/ui/HostEditForm.tsx at line 18, the non-null assertion
operator (!) is used on hostInfo, which can cause runtime errors if hostInfo is
undefined. To fix this, add a conditional check to ensure hostInfo is defined
before calling useHostInfoSave, or provide a safe default value for hostInfo.
Alternatively, wrap the entire component or relevant parts in a conditional
rendering block that only renders when hostInfo is available.


const emailValidation = hostInfoSchema.safeParse({ email });

useEffect(() => {
if (hostInfo?.result.email) setEmail(hostInfo.result.email);
if (hostInfo?.result.channelDescription) setChannelDescription(hostInfo.result.channelDescription);
}, [hostInfo]);

return (
<div className="flex flex-col gap-4 md:gap-8 px-8 md:px-6 mb-4 md:mb-8">
<div className="flex flex-col gap-2">
<DefaultTextField
label="대표 이메일"
detail="채널 혹은, 채널에서 주최하는 이벤트에 대해 문의 할 수 있는 메일로 작성해주세요."
value={email}
onChange={e => setEmail(e.target.value)}
className="h-12"
labelClassName="sm:text-base md:text-lg"
errorMessage={!emailValidation.success ? emailValidation.error.errors[0].message : ''}
/>
<TertiaryButton
type="button"
label="수정하기"
size="large"
color="pink"
onClick={handleSave}
disabled={!emailValidation.success}
/>
Comment on lines +39 to +46
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

중복된 저장 기능 개선 필요

두 개의 저장 버튼이 동일한 handleSave 함수를 호출하고 있습니다. 각각의 필드에 대해 독립적인 저장 기능을 제공하거나, 하나의 통합된 저장 버튼을 사용하는 것이 더 나은 UX를 제공할 수 있습니다.

이메일 필드에만 유효성 검사를 적용하고 있는 것도 일관성 측면에서 검토가 필요합니다.

Also applies to: 55-55

🤖 Prompt for AI Agents
In src/entities/host/ui/HostEditForm.tsx around lines 39 to 46 and line 55,
there are two save buttons both calling the same handleSave function, which
causes redundant saving behavior. Refactor the code to either provide
independent save functions for each field or consolidate into a single save
button to improve UX. Additionally, review and apply consistent validation logic
across all relevant fields, not just the email field, to maintain uniform
validation standards.

</div>
<div className="flex flex-col gap-2">
<MultilineTextField
label="채널에 대한 설명"
value={channelDescription}
onChange={e => setChannelDescription(e.target.value)}
className="h-24 mb-8"
/>
<TertiaryButton type="button" label="수정하기" size="large" color="pink" onClick={handleSave} />
</div>
</div>
);
};

export default HostEditForm;
32 changes: 32 additions & 0 deletions src/entities/host/ui/HostInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import ProfileCircle from '../../../../design-system/ui/Profile';
import { formatProfilName } from '../../../shared/lib/formatProfileName';
import { HostChannelInfoResponse } from '../model/hostChannelInfo';

const HostInfo = ({ hostInfo }: { hostInfo?: HostChannelInfoResponse }) => {
return (
<div className="flex flex-col px-8 md:px-12 gap-6">
<div className="flex flex-col gap-4 py-4">
<p className="text-xl text-black font-semibold">대표 이메일</p>
<p>{hostInfo?.result.email}</p>
</div>
<div className="flex flex-col gap-4 lg:gap-6">
<p className="text-xl text-black font-semibold">멤버 목록</p>
<div className="flex flex-wrap gap-x-5 gap-y-4 lg:gap-x-10 lg:gap-y-6 text-sm md:text-16 lg:text-base">
{hostInfo?.result.hostChannelMembers.map(user => (
<ProfileCircle
key={user.id}
id={user.id}
profile="userProfile"
name={formatProfilName(user.memberName)}
className="w-12 h-12 md:w-13 md:h-13 lg:w-14 lg:h-14"
>
{user.memberName}
</ProfileCircle>
))}
</div>
</div>
</div>
);
};

export default HostInfo;
30 changes: 30 additions & 0 deletions src/entities/host/ui/MemberInvite.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Dispatch, SetStateAction } from 'react';
import TertiaryButton from '../../../../design-system/ui/buttons/TertiaryButton';
import MemberEmailInput from '../../../features/menu/ui/MemberEmailInput';

const MemberInvite = ({
emails,
setEmails,
handleInviteMembers,
}: {
emails: string[];
setEmails: Dispatch<SetStateAction<string[]>>;
handleInviteMembers: () => void;
}) => {
return (
<div className="flex flex-col gap-2 px-8 md:px-6 mb-4">
<div className="flex flex-col">
<h1 className="font-bold text-black text-lg">멤버 등록</h1>
<p className="text-placeholderText text-10 md:text-13">
추가할 회원의 이메일을 입력한 뒤, 엔터를 눌러 검색해 주세요.
<br />
삭제하려면 추가된 이메일 아이콘의 x를 눌러주세요.
</p>
</div>
<MemberEmailInput emails={emails} setEmails={setEmails} />
<TertiaryButton type="button" label="전송" size="large" color="pink" onClick={handleInviteMembers} />
</div>
);
};

export default MemberInvite;
4 changes: 2 additions & 2 deletions src/entities/user/ui/BookmarkList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ const BookmarkList = () => {
const { data } = useBookmarks();
const navigate = useNavigate();

const sortedData = data ? [...data].sort((a, b) => a.id - b.id) : [];
const visibleEvents = sortedData.slice(0, 2);
if (!data) return null;
const visibleEvents = data.slice(0, 2);

return (
<div className="w-full h-full max-h-84 bg-white border-[0.5px] rounded-[10px] px-5 md:px-7 py-4 md:py-5">
Expand Down
3 changes: 2 additions & 1 deletion src/features/host/hook/useHostInfoHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { HostChannelInfoResponse } from '../../../entities/host/model/hostChanne
export const useHostInfoSave = (
hostChannelId: number,
hostInfo: HostChannelInfoResponse,
email: string,
channelDescription: string
) => {
const queryClient = useQueryClient();
Expand All @@ -17,7 +18,7 @@ export const useHostInfoSave = (
hostChannelId,
profileImageUrl: hostInfo.result.profileImageUrl,
hostChannelName: hostInfo.result.hostChannelName,
hostEmail: hostInfo.result.email,
hostEmail: email,
channelDescription,
};

Expand Down
2 changes: 2 additions & 0 deletions src/features/ticket/model/ticketInformation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export interface ReadTicketResponse {
ticketDescription: string;
ticketPrice: number;
availableQuantity: number;
startDate: string;
endDate: string;
}

export interface TicketOptionChoice {
Expand Down
18 changes: 12 additions & 6 deletions src/pages/event/ui/host/HostCreationPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import basicProfile from '../../../../../public/assets/event-manage/creation/BasicProfile.png';
import addImage from '../../../../../public/assets/event-manage/creation/AddImage.svg';
import DefaultTextField from '../../../../../design-system/ui/textFields/DefaultTextField';
import MultilineTextField from '../../../../../design-system/ui/textFields/MultilineTextField';
Expand Down Expand Up @@ -57,14 +56,21 @@ const HostCreationPage = ({ onValidationChange }: HostCreationPageProps) => {
}));
}, [hostChannelName, hostEmail, channelDescription, setHostState]);

useEffect(() => {
return () => {
setHostState({
profileImageUrl: '',
hostChannelName: '',
hostEmail: '',
channelDescription: '',
});
};
}, [setHostState]);

return (
<div className="flex flex-col gap-5 px-4">
<div className="relative flex items-center justify-center mb-4">
<img
src={previewUrl || basicProfile}
alt="기본 프로필 이미지"
className="w-24 h-24 object-cover rounded-full"
/>
<img src={previewUrl || ''} alt="기본 프로필 이미지" className="w-24 h-24 object-cover rounded-full" />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

프로필 이미지 처리 일관성 문제

빈 문자열을 사용하면 깨진 이미지 아이콘이 표시될 수 있습니다. useImageUpload.ts에서는 basicProfile을 기본 이미지로 사용하는데, 여기서는 제거하여 일관성이 부족합니다.

다음 중 하나의 방식으로 해결하세요:

  1. 기본 이미지를 사용하는 방식:
+import basicProfile from '../../../../../public/assets/event-manage/creation/BasicProfile.png';
-<img src={previewUrl || ''} alt="기본 프로필 이미지" className="w-24 h-24 object-cover rounded-full" />
+<img src={previewUrl || basicProfile} alt="기본 프로필 이미지" className="w-24 h-24 object-cover rounded-full" />
  1. 또는 이미지가 없을 때 placeholder 컴포넌트 사용:
-<img src={previewUrl || ''} alt="기본 프로필 이미지" className="w-24 h-24 object-cover rounded-full" />
+{previewUrl ? (
+  <img src={previewUrl} alt="기본 프로필 이미지" className="w-24 h-24 object-cover rounded-full" />
+) : (
+  <div className="w-24 h-24 bg-gray-200 rounded-full flex items-center justify-center">
+    <span className="text-gray-500">이미지</span>
+  </div>
+)}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<img src={previewUrl || ''} alt="기본 프로필 이미지" className="w-24 h-24 object-cover rounded-full" />
// Add to the top of src/pages/event/ui/host/HostCreationPage.tsx
import basicProfile from '../../../../../public/assets/event-manage/creation/BasicProfile.png';
// …
// Replace the existing <img> line at around line 73:
<img
src={previewUrl || basicProfile}
alt="기본 프로필 이미지"
className="w-24 h-24 object-cover rounded-full"
/>
🤖 Prompt for AI Agents
In src/pages/event/ui/host/HostCreationPage.tsx at line 73, the img tag uses an
empty string as the fallback for the src attribute, causing broken image icons
when no previewUrl is available. To fix this, replace the empty string fallback
with the default image URL (basicProfile) used in useImageUpload.ts to maintain
consistency, or alternatively, conditionally render a placeholder component when
previewUrl is not present instead of rendering an img with an empty src.

<button
type="button"
onClick={() => fileInputRef.current?.click()}
Expand Down
85 changes: 9 additions & 76 deletions src/pages/menu/ui/myHost/HostEditPage.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,22 @@
import { useEffect, useState } from 'react';
import { useState } from 'react';
import HostDetailLayout from '../../../../shared/ui/backgrounds/HostDetailLayout';
import ProfileCircle from '../../../../../design-system/ui/Profile';
import MultilineTextField from '../../../../../design-system/ui/textFields/MultilineTextField';
import DefaultTextField from '../../../../../design-system/ui/textFields/DefaultTextField';
import TertiaryButton from '../../../../../design-system/ui/buttons/TertiaryButton';
import { useParams } from 'react-router-dom';
import MemberEmailInput from '../../../../features/menu/ui/MemberEmailInput';
import useHostChannelInfo from '../../../../entities/host/hook/useHostChannelInfoHook';
import { useHostInfoSave } from '../../../../features/host/hook/useHostInfoHook';
import { useInviteMembers } from '../../../../features/host/hook/useInviteHostHook';
import HostInfo from '../../../../entities/host/ui/HostInfo';
import HostEditForm from '../../../../entities/host/ui/HostEditForm';
import MemberInvite from '../../../../entities/host/ui/MemberInvite';

const HostEditPage = () => {
const { id } = useParams<{ id: string }>();
const [selectedHost, setSelectedHost] = useState(true);
const [selectedInfo, setSelectedInfo] = useState(false);
const [channelDescription, setChannelDescription] = useState('');
const [emails, setEmails] = useState<string[]>([]);

const hostChannelId = Number(id);
const { data: hostInfo } = useHostChannelInfo(hostChannelId);
const { inviteMembers } = useInviteMembers(hostChannelId);

const { handleSave } = useHostInfoSave(hostChannelId, hostInfo!, channelDescription);

const handeHostInfoClick = () => {
setSelectedHost(true);
setSelectedInfo(false);
Expand All @@ -34,16 +28,9 @@ const HostEditPage = () => {

const handleInviteMembers = () => {
if (!hostInfo?.result.id) return;

inviteMembers(emails, () => setEmails([]));
};

useEffect(() => {
if (hostInfo?.result.channelDescription && channelDescription === '') {
setChannelDescription(hostInfo.result.channelDescription);
}
}, [hostInfo, channelDescription]);

return (
<HostDetailLayout>
<div className="relative overflow-y-auto">
Expand All @@ -69,67 +56,13 @@ const HostEditPage = () => {
</div>
</div>

{selectedHost && (
<div className="flex flex-col px-8 md:px-12 gap-6">
<div className="flex flex-col gap-4 py-4">
<p className="text-xl text-black font-semibold">대표 이메일</p>
<p>{hostInfo?.result.email}</p>
</div>
<div className="flex flex-col gap-4 lg:gap-6">
<p className="text-xl text-black font-semibold">멤버 목록</p>
<div className="flex flex-wrap gap-x-5 gap-y-4 lg:gap-x-10 lg:gap-y-6 text-sm md:text-16 lg:text-base">
{hostInfo?.result.hostChannelMembers.map(user => (
<ProfileCircle
key={user.id}
id={user.id}
profile="userProfile"
name={user.memberName.slice(1)}
className="w-12 h-12 md:w-13 md:h-13 lg:w-14 lg:h-14 text-sm md:text-16 lg:text-base"
>
{user.memberName}
</ProfileCircle>
))}
</div>
</div>
</div>
)}
{selectedHost && <HostInfo hostInfo={hostInfo} />}

{selectedInfo && (
<div className="flex flex-col gap-8 px-8 md:px-6">
<DefaultTextField
label="대표 이메일"
detail="채널 혹은, 채널에서 주최하는 이벤트에 대해 문의 할 수 있는 메일로 작성해주세요."
value={hostInfo?.result.email || ''}
className="h-12"
labelClassName="sm:text-base md:text-lg"
/>
<div className="flex flex-col gap-2">
<MultilineTextField
label="채널에 대한 설명"
value={channelDescription}
onChange={e => setChannelDescription(e.target.value)}
className="h-24 mb-8"
/>
<TertiaryButton type="button" label="저장하기" size="large" color="pink" onClick={handleSave} />
</div>
<div className="flex flex-col gap-2">
<div className="flex flex-col">
<h1 className="font-bold text-black text-lg">멤버 등록</h1>
<p className="text-placeholderText text-10 md:text-13">
이메일로 회원을 검색해 추가 할 수 있습니다. 삭제 하려면 추가된 이메일 아이콘의 x를 눌러주세요.{' '}
</p>
</div>
<MemberEmailInput emails={emails} setEmails={setEmails} />
<TertiaryButton
type="button"
label="전송"
size="large"
color="pink"
onClick={handleInviteMembers}
className="mb-4"
/>
</div>
</div>
<>
<HostEditForm />
<MemberInvite emails={emails} setEmails={setEmails} handleInviteMembers={handleInviteMembers} />
</>
)}
</div>
</HostDetailLayout>
Expand Down
8 changes: 4 additions & 4 deletions src/shared/hooks/useImageUpload.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useRef, useState, useCallback, useEffect } from 'react';
import { uploadFile } from '../../features/event/hooks/usePresignedUrlHook';
import { convertImageToWebP } from '../lib/convertImageToWebP';
export const DEFAULT_BASIC_PROFILE = 'https://gotogetherbucket.s3.ap-northeast-2.amazonaws.com/default.png';
import basicProfile from '../../../public/assets/event-manage/creation/BasicProfile.png';

const useImageUpload = ({
value,
Expand All @@ -19,9 +19,9 @@ const useImageUpload = ({
useEffect(() => {
if (value) {
setPreviewUrl(value);
} else if (useDefaultImage && previewUrl !== DEFAULT_BASIC_PROFILE) {
setPreviewUrl(DEFAULT_BASIC_PROFILE);
onSuccess?.(DEFAULT_BASIC_PROFILE);
} else if (useDefaultImage && previewUrl !== basicProfile) {
setPreviewUrl(basicProfile);
onSuccess?.(basicProfile);
}
}, [value, onSuccess, useDefaultImage, previewUrl]);

Expand Down
3 changes: 2 additions & 1 deletion src/shared/lib/formValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const formSchema = z.object({
.regex(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/, '올바른 이메일 형식이어야 합니다.'),
phone: z
.string()
.regex(/^[0-9]{3}-[0-9]{3,4}-[0-9]{4}$/, '연락처는 휴대전화 번호 형식(예: 010-1234-5678)이어야 합니다.')
.regex(/^[0-9]{3}-[0-9]{3,4}-[0-9]{4}$/, '연락처는 휴대전화 번호 형식(예: 010-1234-5678)이어야 합니다.'),
});
export const organizerFormSchema = formSchema.pick({ email: true, phone: true });
export const eventTitleSchema = z.object({
Expand All @@ -21,6 +21,7 @@ export const hostCreationSchema = z.object({
channelDescription: z.string().min(5, '채널 설명은 최소 두 글자 이상이어야 합니다.'),
});
export const myPageSchema = formSchema.pick({ name: true, phone: true });
export const hostInfoSchema = formSchema.pick({ email: true });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

타입 정의 누락

새로운 hostInfoSchema에 대한 타입 정의가 누락되었습니다. 다른 스키마들과 일관성을 위해 타입을 추가해야 합니다.

다음 diff를 적용하여 타입 정의를 추가하세요:

export type FormData = z.infer<typeof formSchema>;
export type OrganizerFormData = z.infer<typeof organizerFormSchema>;
export type EventTitleFormData = z.infer<typeof eventTitleSchema>;
export type HostCreationFormData = z.infer<typeof hostCreationSchema>;
+export type HostInfoFormData = z.infer<typeof hostInfoSchema>;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const hostInfoSchema = formSchema.pick({ email: true });
export type FormData = z.infer<typeof formSchema>;
export type OrganizerFormData = z.infer<typeof organizerFormSchema>;
export type EventTitleFormData = z.infer<typeof eventTitleSchema>;
export type HostCreationFormData = z.infer<typeof hostCreationSchema>;
export type HostInfoFormData = z.infer<typeof hostInfoSchema>;
🤖 Prompt for AI Agents
In src/shared/lib/formValidation.ts at line 24, the new hostInfoSchema is
missing a type definition. To maintain consistency with other schemas, define
and export a corresponding TypeScript type for hostInfoSchema using the
appropriate utility (e.g., infer or type alias) from the form validation
library. Add this type definition immediately after the schema declaration.


export type FormData = z.infer<typeof formSchema>;
export type OrganizerFormData = z.infer<typeof organizerFormSchema>;
Expand Down
14 changes: 13 additions & 1 deletion src/widgets/event/ui/TicketInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useTickets } from '../../../features/ticket/hooks/useTicketHook';
import { useOrderTicket } from '../../../features/ticket/hooks/useOrderHook';
import { readTicketOptions } from '../../../features/ticket/api/ticketOption';
import useAuthStore from '../../../app/provider/authStore';
import clock from '../../../../public/assets/event-manage/details/Clock.svg';

const TicketInfo = ({ eventId }: { eventId: number }) => {
const limitNum = 4;
Expand Down Expand Up @@ -84,7 +85,9 @@ const TicketInfo = ({ eventId }: { eventId: number }) => {
{data.result.map(ticket => (
<div key={ticket.ticketId} className="bg-gray1 px-3 py-3 md:px-6 md:py-4 rounded-[10px] mb-3">
<div className="flex justify-between items-center">
<div className="flex flex-col gap-2"> {/* w-[230px] */}
<div className="flex flex-col gap-2">
{' '}
{/* w-[230px] */}
<div className="flex items-center gap-2 md:gap-4">
<span className="font-bold text-base md:text-md">{ticket.ticketName}</span> {/* w-[170px] */}
</div>
Expand Down Expand Up @@ -123,6 +126,15 @@ const TicketInfo = ({ eventId }: { eventId: number }) => {
/>
</div>
</div>
<div className="w-full bg-[#E4EFFF] border px-4 py-3 rounded-[5px] mt-2">
<div className="flex items-center gap-2">
<img src={clock} alt="시계 아이콘" className="w-4 h-4 md:w-5 md:h-5" />
<span className="text-sm font-semibold">
구매 가능기간: {new Date(ticket.startDate).toLocaleDateString()} ~{' '}
{new Date(ticket.endDate).toLocaleDateString()}
Comment on lines +133 to +134
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

날짜 로케일 설정을 명시적으로 지정해주세요.

toLocaleDateString()을 사용할 때 한국 로케일을 명시적으로 지정하여 일관된 날짜 형식을 보장하는 것이 좋습니다.

다음과 같이 수정하는 것을 권장합니다:

-                구매 가능기간: {new Date(ticket.startDate).toLocaleDateString()} ~{' '}
-                {new Date(ticket.endDate).toLocaleDateString()}
+                구매 가능기간: {new Date(ticket.startDate).toLocaleDateString('ko-KR')} ~{' '}
+                {new Date(ticket.endDate).toLocaleDateString('ko-KR')}
🤖 Prompt for AI Agents
In src/widgets/event/ui/TicketInfo.tsx around lines 133 to 134, the usage of
toLocaleDateString() does not specify the locale, which can lead to inconsistent
date formats. Fix this by explicitly passing 'ko-KR' as the locale argument to
toLocaleDateString() for both startDate and endDate to ensure consistent Korean
date formatting.

</span>
</div>
</div>
</div>
))}
</div>
Expand Down