Skip to content
4 changes: 3 additions & 1 deletion src/features/event/ui/FileUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ interface FileUploadProps {
value?: string;
onChange?: (url: string) => void;
setEventState?: React.Dispatch<React.SetStateAction<FunnelState['eventState']>>;
useDefaultImage?: boolean;
}

const FileUpload = ({ value, onChange, setEventState }: FileUploadProps) => {
const FileUpload = ({ value, onChange, setEventState, useDefaultImage }: FileUploadProps) => {
const { previewUrl, fileInputRef, handleFileChange, handleDrop, setIsDragging, isDragging } = useImageUpload({
value, // 서버에서 받아온 기본 이미지
onSuccess: url => {
onChange?.(url);
setEventState?.(prev => ({ ...prev, bannerImageUrl: url }));
},
useDefaultImage,
});

return (
Expand Down
2 changes: 1 addition & 1 deletion src/pages/bookmark/ui/BookmarkPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const BookmarkPage = () => {
centerContent="관심 있는 이벤트"
rightContent={
<button type="button" className="w-5 z-10" onClick={() => navigate('/search')}>
<img src={searchIcon} alt="Search Icon" />
<img src={searchIcon} alt="Search Icon" className="w-5" />
</button>
}
/>
Expand Down
3 changes: 2 additions & 1 deletion src/pages/dashboard/ui/DashbaordPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import EventOverview from '../../../widgets/dashboard/ui/main/EventOverview';

const DashboardPage = () => {
const { data } = useHostDashboard();
const formattedPrice = data?.totalPrice.toLocaleString();
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

가격 포맷팅 개선에 null 체크 추가가 필요합니다.

숫자를 로케일 형식으로 포맷팅하는 것은 사용자 경험을 크게 개선하는 좋은 변경입니다. 하지만 data?.totalPrice가 undefined일 때 toLocaleString() 메서드 호출 시 에러가 발생할 수 있습니다.

다음과 같이 안전한 포맷팅을 제안합니다:

-  const formattedPrice = data?.totalPrice.toLocaleString();
+  const formattedPrice = data?.totalPrice?.toLocaleString();
📝 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
const formattedPrice = data?.totalPrice.toLocaleString();
const formattedPrice = data?.totalPrice?.toLocaleString();
🤖 Prompt for AI Agents
In src/pages/dashboard/ui/DashbaordPage.tsx at line 11, the code calls
toLocaleString() on data?.totalPrice without checking if totalPrice is defined,
which can cause an error if totalPrice is undefined. To fix this, add a null or
undefined check before calling toLocaleString(), for example by using a
conditional expression or optional chaining combined with a fallback value,
ensuring that toLocaleString() is only called on a valid number.


return (
<DashboardLayout centerContent="대시보드" pinkBg={true}>
Expand All @@ -24,7 +25,7 @@ const DashboardPage = () => {
<TicketRevenue
icon={<img src={cash} alt="돈" className="w-8 md:w-9" />}
title="판매 금액"
value={`${data?.totalPrice || '-'}원`}
value={`${formattedPrice || '-'}원`}
/>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/dashboard/ui/EventDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const EventDetailPage = () => {
<DashboardLayout centerContent="WOOACON 2024">
<div className="flex flex-col gap-5 mt-8 px-7">
<h1 className="text-center text-xl font-bold mb-5">이벤트 상세 정보</h1>
<FileUpload value={bannerImageUrl} onChange={setBannerImageUrl} />
<FileUpload value={bannerImageUrl} onChange={setBannerImageUrl} useDefaultImage={false} />
<TextEditor value={description} onChange={setDescription} />
<LinkInput value={referenceLinks} onChange={setReferenceLinks} />
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/event/ui/create-event/EventInfoPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const EventInfoPage = () => {
const { setEventState } = useFunnelState();
return (
<div className="w-full px-5 space-y-8">
<FileUpload setEventState={setEventState} />
<FileUpload setEventState={setEventState} useDefaultImage={false} />
<TextEditor setEventState={setEventState} />
<LinkInput setEventState={setEventState} />
</div>
Expand Down
16 changes: 7 additions & 9 deletions src/pages/menu/ui/MyPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import DefaultTextField from '../../../../design-system/ui/textFields/DefaultTex
import TertiaryButton from '../../../../design-system/ui/buttons/TertiaryButton';
import { SubmitHandler, useForm } from 'react-hook-form';
import BottomBar from '../../../widgets/main/ui/BottomBar';
import PaymentCard from '../../../widgets/payment/ui/PaymentCard';
import { myPageSchema } from '../../../shared/lib/formValidation';
import { useUserInfo,useUserUpdate } from '../../../features/join/hooks/useUserHook';
import { useUserInfo, useUserUpdate } from '../../../features/join/hooks/useUserHook';
import useAuthStore from '../../../app/provider/authStore';

const MyPage = () => {
const {data, isLoading, error} = useUserInfo();
const { data, isLoading, error } = useUserInfo();
const { mutate: updateUser } = useUserUpdate();
const { setName } = useAuthStore();

Expand All @@ -21,7 +20,7 @@ const MyPage = () => {
formState: { errors },
setValue,
} = useForm({
defaultValues: { name: data?.name || '', phone: data?.phoneNumber || ''},
defaultValues: { name: data?.name || '', phone: data?.phoneNumber || '' },
...myPageSchema,
});
useEffect(() => {
Expand All @@ -31,7 +30,7 @@ const MyPage = () => {
}
}, [data, setValue]);

const onSubmit: SubmitHandler<{ name: string; phone: string }> = (formData) => {
const onSubmit: SubmitHandler<{ name: string; phone: string }> = formData => {
const { name, phone } = formData;
const updatedData = {
id: data?.id || 0,
Expand All @@ -44,7 +43,7 @@ const MyPage = () => {
setName(name);
alert('정보가 성공적으로 업데이트되었습니다.');
},
onError: (err) => {
onError: err => {
alert('정보 업데이트에 실패했습니다. 다시 시도해주세요.');
console.error(err);
},
Expand All @@ -60,10 +59,9 @@ const MyPage = () => {
}

setIsChanged(changeMessage); // 변경 상태 업데이트

};
if (isLoading) {
return <div>로딩 중...</div>;
return <div>로딩 중...</div>;
}
if (error) {
return <div>정보를 불러오는데 실패했습니다. 다시 시도해주세요.</div>;
Expand Down Expand Up @@ -106,7 +104,7 @@ const MyPage = () => {
<TertiaryButton label="저장하기" color="black" size="large" type="submit" className="w-24 h-8" />
</form>
</div>
<PaymentCard title={'등록된 카드'} />
{/* <PaymentCard title={'등록된 카드'} /> */}
<BottomBar />
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/pages/menu/ui/MyTicketPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const MyTicketPage = () => {
}, []);

return (
<TicketHostLayout image={TicketLogo} centerContent="내 티켓" showText={true}>
<TicketHostLayout image={TicketLogo} centerContent="내 티켓" ticketPage={true}>
{/* 이벤트 카드 목록 */}
<div className="grid grid-cols-2 gap-4 mx-6 mt-28 md:grid-cols-2 lg:grid-cols-2 pb-4">
{myTickets.length > 0 ? (
Expand Down
4 changes: 2 additions & 2 deletions src/pages/menu/ui/myHost/MyHostPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ const MyHostPage = () => {
};

return (
<TicketHostLayout image={HostLogo} centerContent="내 호스트">
<div className="flex space-x-5 mt-24 mx-5 overflow-x-auto scrollbar-hide">
<TicketHostLayout image={HostLogo} centerContent="내 호스트" ticketPage={false}>
<div className="flex space-x-5 mt-28 mx-5 overflow-x-auto scrollbar-hide">
{data?.result.length ? (
data.result.map(profile => (
<ProfileCircle
Expand Down
14 changes: 11 additions & 3 deletions src/shared/hooks/useImageUpload.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { useRef, useState, useCallback, useEffect } from 'react';
import { uploadFile } from '../../features/event/hooks/usePresignedUrlHook';

const useImageUpload = ({ value, onSuccess }: { value?: string; onSuccess?: (url: string) => void }) => {
const useImageUpload = ({
value,
onSuccess,
useDefaultImage = true,
}: {
value?: string;
onSuccess?: (url: string) => void;
useDefaultImage?: boolean;
}) => {
const DEFAULT_BASIC_PROFILE = 'https://gotogetherbucket.s3.ap-northeast-2.amazonaws.com/default.png';
const [previewUrl, setPreviewUrl] = useState<string | null>(null);
const [isDragging, setIsDragging] = useState(false);
Expand All @@ -10,11 +18,11 @@ const useImageUpload = ({ value, onSuccess }: { value?: string; onSuccess?: (url
useEffect(() => {
if (value) {
setPreviewUrl(value);
} else {
} else if (useDefaultImage && previewUrl !== DEFAULT_BASIC_PROFILE) {
setPreviewUrl(DEFAULT_BASIC_PROFILE);
onSuccess?.(DEFAULT_BASIC_PROFILE);
}
}, [value, onSuccess]);
}, [value, onSuccess, useDefaultImage, previewUrl]);

const validateFile = (file: File) => {
if (file.size > 500 * 1024) {
Expand Down
29 changes: 18 additions & 11 deletions src/shared/ui/EventCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const EventCard = ({
return (
<div
onClick={onClick}
className="w-full h-full md:h-[300px] sm:h-[280px] max-w-full p-4 bg-white rounded-lg shadow-md cursor-pointer flex flex-col justify-between"
className="w-full max-w-full h-full min-h-[240px] md:min-h-[300px] max-h-full p-4 bg-white rounded-lg shadow-md cursor-pointer flex flex-col justify-between"
>
{/* 이미지 */}
<img src={img} alt={eventTitle} className="object-cover w-full rounded-md sm:h-20 md:h-24 lg:h-28" />
Expand All @@ -47,9 +47,11 @@ const EventCard = ({
<div className="flex flex-col gap-1 mt-4">
<div className="flex justify-between">
<h2 className="text-sm font-semibold line-clamp-2 overflow-hidden">{eventTitle}</h2>
<div className="sm:max-w-10 md:max-w-15">
<Countdown isChecked>{dDay}</Countdown>
</div>
{dDay !== 'false' && (
<div className="sm:max-w-10 md:max-w-15">
<Countdown isChecked>{dDay}</Countdown>
</div>
)}
</div>

<p className="text-xs text-gray-500">{host}</p>
Expand All @@ -67,13 +69,18 @@ const EventCard = ({
{/* 승인 여부 표시 */}
{children}
{/* 해시태그 */}
<div className="flex flex-wrap w-full h-6 mt-2 overflow-hidden text-xs font-semibold text-gray-700 whitespace-nowrap">
{(hashtags ?? []).map((tag, index) => (
<span key={index} className="flex items-center justify-center h-6 px-2 mr-2 bg-gray-200 rounded last:mr-0">
{tag}
</span>
))}
</div>
{hashtags && (
<div className="flex flex-wrap w-full h-6 mt-2 overflow-hidden text-xs font-semibold text-gray-700 whitespace-nowrap">
{(hashtags ?? []).map((tag, index) => (
<span
key={index}
className="flex items-center justify-center h-6 px-2 mr-2 bg-gray-200 rounded last:mr-0"
>
{tag}
</span>
))}
</div>
)}

{/* 대시보드 버튼 */}
{isHostPage && (
Expand Down
12 changes: 9 additions & 3 deletions src/shared/ui/backgrounds/TicketHostLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ interface TicketHostLayoutProps {
image: string;
children: React.ReactNode;
centerContent: string;
showText?: boolean;
ticketPage?: boolean;
}

const TicketHostLayout = ({ image, children, centerContent, showText = false }: TicketHostLayoutProps) => {
const TicketHostLayout = ({ image, children, centerContent, ticketPage = true }: TicketHostLayoutProps) => {
const navigate = useNavigate();
const handleBackClick = () => {
navigate(-1);
Expand All @@ -35,11 +35,17 @@ const TicketHostLayout = ({ image, children, centerContent, showText = false }:
/>
</div>

{showText && (
{ticketPage && (
<div className="absolute left-1/2 transform -translate-x-1/2 top-[calc(150%)] text-placeholderText text-center text-sm whitespace-nowrap">
티켓을 누르면 입장을 위한 QR코드를 확인할 수 있습니다.
</div>
)}

{!ticketPage && (
<p className="absolute left-1/2 transform -translate-x-1/2 top-[calc(150%)] text-placeholderText text-center text-sm whitespace-nowrap">
원을 누르면 주최한 이벤트, 이름을 누르면 호스트 상세 정보 확인이 가능합니다.
</p>
)}
</>
</div>
{children}
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/dashboard/ui/main/TicketRevenue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const TicketRevenue = ({ icon, title, value }: TicketRevenueProps) => {
<div className="flex justify-center items-center w-12 h-12 md:w-14 md:h-14 bg-main rounded-[5px]">{icon}</div>
<div className="flex flex-col">
<span className="text-xs md:text-base text-main font-semibold">{title}</span>
<h2 className="text-2xl font-bold">{value}</h2>
<h2 className="text-16 md:text-xl font-bold">{value}</h2>
</div>
</div>
);
Expand Down
8 changes: 7 additions & 1 deletion src/widgets/main/ui/BottomBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ const BottomBar = () => {
<div
key={index}
className="flex flex-col justify-center items-center w-24 h-20 cursor-pointer"
onClick={() => navigate(item.path)}
onClick={() => {
if (location.pathname === item.path) {
navigate(-1);
} else {
navigate(item.path);
}
}}
Comment on lines +12 to +18
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

네비게이션 로직 개선 제안

현재 탭을 다시 클릭했을 때 뒤로 가기 기능을 추가한 것은 좋은 아이디어입니다. 하지만 몇 가지 개선사항을 제안드립니다:

  1. 전역 location 객체 대신 React Router의 useLocation 훅 사용을 권장합니다.
  2. 히스토리가 없는 경우를 고려해야 합니다.

다음과 같이 개선할 수 있습니다:

-import { useNavigate } from 'react-router-dom';
+import { useNavigate, useLocation } from 'react-router-dom';
import { bottomBar } from '../../../shared/types/bottomBarType';

const BottomBar = () => {
  const navigate = useNavigate();
+  const location = useLocation();
  return (
    <div className="flex justify-between fixed bottom-0 w-full max-w-lg h-20 rounded-t-[10px] bg-white border-t border-t-gray4">
      {bottomBar.map((item, index) => (
        <div
          key={index}
          className="flex flex-col justify-center items-center w-24 h-20 cursor-pointer"
          onClick={() => {
            if (location.pathname === item.path) {
-              navigate(-1);
+              if (window.history.length > 1) {
+                navigate(-1);
+              }
            } else {
              navigate(item.path);
            }
          }}
🤖 Prompt for AI Agents
In src/widgets/main/ui/BottomBar.tsx around lines 12 to 18, replace the use of
the global location object with React Router's useLocation hook to get the
current path. Additionally, enhance the onClick handler to check if there is a
history entry to go back to before calling navigate(-1), preventing errors when
no history exists. This involves importing and using useLocation, storing the
current location, and conditionally navigating back or to the item's path based
on that and history availability.

>
<img src={item.icon} alt={`${item.label}Icon`} className={`${item.iconClassName} object-contain`} />
<span className={`text-sm ${item.label === '관심' ? 'mb-1' : 'mt-2'}`}>{item.label}</span>
Expand Down