Skip to content

Commit a85d330

Browse files
authored
Merge pull request #76 from summerDev96/fix/my-activity-form
Fix TRI-85: 내 체험 등록/수정 페이지 QA 수정사항 반영
2 parents e0ce7d9 + 646e8d2 commit a85d330

39 files changed

+441
-293
lines changed

src/app/my-activities/activity/[activityId]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ interface ActivityEditPageProps {
88
const ActivityEditPage = async ({ params }: ActivityEditPageProps) => {
99
const { activityId } = await params;
1010
return (
11-
<div className='flex justify-center items-center max-w-[327px] md:max-w-[627px] mx-auto p-16'>
11+
<div className='w-full flex justify-center items-center max-w-[327px] tablet:max-w-[684px] pc:max-w-[700px] mx-auto py-7.5 tablet:py-16'>
1212
{/* 수정 페이지 + 공통 폼 */}
1313
<MyActivityForm mode='EDIT' activityId={activityId} />
1414
</div>

src/app/my-activities/activity/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import MyActivityForm from '@/components/pages/myActivities/MyActivityForm';
22

33
const ActivityRegisterPage = () => {
44
return (
5-
<div className='flex justify-center items-center max-w-[327px] md:max-w-[627px] mx-auto p-16'>
5+
<div className='w-full flex justify-center items-center max-w-[327px] tablet:max-w-[684px] pc:max-w-[700px] mx-auto py-7.5 tablet:py-16'>
66
{/* 등록 페이지 + 공통 폼 */}
77
<MyActivityForm />
88
</div>

src/app/mypage/layout.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
'use client';
2-
import Spinner from '@/components/common/Spinner';
2+
import MypageLoadingOverlay from '@/components/pages/myPage/MypageLoadingOverlay';
33
import SideMenu from '@/components/pages/myPage/SideMenu';
44
import { useScreenSize } from '@/hooks/useScreenSize';
55
import { useUserStore } from '@/store/userStore';
@@ -30,11 +30,12 @@ const MyPageCommonLayout = ({ children }: MyPageCommonLayoutProps) => {
3030

3131
<div
3232
className={clsx(
33-
'pt-2.5 flex-1 min-w-0 min-h-70 tablet:block',
33+
'pt-2.5 flex-1 min-w-0 min-h-80 tablet:block relative',
3434
isMobileMenuPage && 'mobile:hidden',
3535
)}
3636
>
37-
{isPending ? <Spinner /> : children}
37+
{children}
38+
{isPending && <MypageLoadingOverlay />}
3839
</div>
3940
</>
4041
);

src/app/mypage/reservation-list/page.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const ReservationListPage = () => {
1313
const queryClient = useQueryClient();
1414
const pathname = usePathname();
1515
const [selectedStatus, setSelectedStatus] = useState<ReservationStatusWithAll>('all');
16+
const [isInitialLoad, setIsInitialLoad] = useState(true);
1617

1718
const {
1819
reservationListData,
@@ -27,6 +28,12 @@ const ReservationListPage = () => {
2728
refetch();
2829
}, [pathname, selectedStatus, queryClient, refetch]);
2930

31+
useEffect(() => {
32+
if (!isLoading) {
33+
setIsInitialLoad(false);
34+
}
35+
}, [isLoading]);
36+
3037
return (
3138
<div className='flex flex-col gap-7.5'>
3239
{/* 헤더 */}
@@ -37,10 +44,10 @@ const ReservationListPage = () => {
3744
예약내역을 변경 및 취소할 수 있습니다.
3845
</span>
3946
<div className='flex pt-3.5 gap-2 overflow-x-auto whitespace-nowrap scrollbar-hide'>
40-
{reservationListData.length > 0 &&
47+
{(!isInitialLoad || reservationListData.length > 0) &&
4148
(Object.entries(reservationStatusAll) as [ReservationStatusWithAll, string][])
4249
.filter(([value]) => value !== 'declined')
43-
.map(([value, label]) => (
50+
.map(([value, label]: [ReservationStatusWithAll, string]) => (
4451
<Badge
4552
key={value}
4653
variant='outline'

src/app/mypage/reservation-status/page.tsx

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use client';
22
import { getMyActivitiesList } from '@/app/api/myActivities';
3-
import Spinner from '@/components/common/Spinner';
43
import ActivitySelect from '@/components/pages/myPage/ActivitySelect';
54
import ReservationStatusCalendar from '@/components/pages/myPage/ReservationStatusCalendar';
65
import { Label } from '@/components/ui/label';
@@ -10,14 +9,14 @@ import { format } from 'date-fns';
109
import { useOverlay } from '@/hooks/useOverlay';
1110
import { Event as RBCEvent } from 'react-big-calendar';
1211
import ReservedScheduleModal from '@/components/pages/myPage/ReservedScheduleModal';
13-
import Image from 'next/image';
1412
import { useScheduleStore } from '@/store/reservedScheduleStore';
1513
import { getReservationDashboard } from '@/app/api/myReservations';
1614
import clsx from 'clsx';
15+
import EmptyList from '@/components/pages/myPage/EmptyList';
16+
import MypageLoadingOverlay from '@/components/pages/myPage/MypageLoadingOverlay';
1717

1818
const ReservationStatusPage = () => {
1919
const overlay = useOverlay();
20-
const [isInitialLoading, setIsInitialLoading] = useState(true);
2120

2221
const { setStatus } = useScheduleStore();
2322

@@ -108,18 +107,9 @@ const ReservationStatusPage = () => {
108107
};
109108

110109
const ReservationSection = () => {
110+
if (isActivityListLoading) return null;
111111
if (!activityListData?.activities || activityListData?.activities.length === 0) {
112-
return (
113-
<div className='flex flex-col mx-auto'>
114-
<Image
115-
src={'/images/icons/_empty.png'}
116-
width={182}
117-
height={182}
118-
alt='예약 현황 디폴트 이미지'
119-
/>
120-
<span className='text-18-medium text-grayscale-600'>아직 등록한 체험이 없어요</span>
121-
</div>
122-
);
112+
return <EmptyList text='빈 리스트 이미지' />;
123113
}
124114

125115
return (
@@ -141,24 +131,15 @@ const ReservationStatusPage = () => {
141131
);
142132
};
143133

144-
useEffect(() => {
145-
if (!isActivityListLoading && !isReservationListLoading) {
146-
setIsInitialLoading(false);
147-
}
148-
}, [isActivityListLoading, isReservationListLoading]);
149-
150134
useEffect(() => {
151135
if (activityListData && activityListData?.activities?.length > 0) {
152136
setActivityId(String(activityListData?.activities[0].id));
153137
}
154138
}, [activityListData]);
155139

156-
if (isInitialLoading) {
157-
return <Spinner />;
158-
}
159-
160140
return (
161-
<div className='flex flex-col gap-5 pl-4'>
141+
<div className='flex flex-col gap-5 pl-4 relative'>
142+
{(isActivityListLoading || isReservationListLoading) && <MypageLoadingOverlay />}
162143
{/* 헤더 */}
163144
<div className='px-6 sm:px-0 flex flex-col gap-4'>
164145
<div className='flex flex-col md:flex-row w-full justify-between items-start md:items-center gap-4 md:gap-16'>

src/app/mypage/user/page.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import { UserProfile, UserUpdateRequest } from '@/types/user.type';
1616
import { useOverlay } from '@/hooks/useOverlay';
1717
import ConfirmModal from '@/components/common/ConfirmModal';
1818
import { successToast } from '@/lib/utils/toastUtils';
19-
import Spinner from '@/components/common/Spinner';
2019
import clsx from 'clsx';
20+
import MypageLoadingOverlay from '@/components/pages/myPage/MypageLoadingOverlay';
2121

2222
type UserFormValues = {
2323
nickname: string;
@@ -100,12 +100,9 @@ const UserPage = () => {
100100
}
101101
}, [userData, reset, setUser]);
102102

103-
if (isLoading) {
104-
return <Spinner />;
105-
}
106-
107103
return (
108-
<div className='flex flex-col gap-7.5'>
104+
<div className='flex flex-col gap-7.5 relative'>
105+
{isLoading && <MypageLoadingOverlay />}
109106
{/* 헤더 */}
110107
<div className={clsx('flex flex-col w-full items-start gap-8 pl-4')}>
111108
<div className='flex flex-col gap-2.5'>

src/app/mypage/wishlist/page.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Image from 'next/image';
88
import Link from 'next/link';
99
import Spinner from '@/components/common/Spinner';
1010
import ActivityLike from '@/components/home/ActivityLike';
11+
import { wsrvLoader } from '@/components/common/wsrvLoader';
1112

1213
export default function WishList() {
1314
const [isLoading, setIsLoading] = useState(true);
@@ -53,6 +54,7 @@ export default function WishList() {
5354
<Link href={`/activities/${activity.id}`}>
5455
<div className='w-full h-[200px] relative'>
5556
<Image
57+
loader={wsrvLoader}
5658
src={activity.bannerImageUrl}
5759
alt={activity.title}
5860
fill
@@ -80,6 +82,7 @@ export default function WishList() {
8082
<Link href={`/activities/${activity.id}`}>
8183
<div className='w-[126px] h-full relative flex-shrink-0'>
8284
<Image
85+
loader={wsrvLoader}
8386
src={activity.bannerImageUrl}
8487
alt={activity.title}
8588
fill

src/components/common/BasicCalendar.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@ import * as React from 'react';
44
import { DayPicker, getDefaultClassNames } from 'react-day-picker';
55
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react';
66
import 'react-day-picker/style.css';
7+
8+
interface BasicCalendarProps {
9+
isDateInput?: boolean;
10+
}
11+
12+
type Props = BasicCalendarProps & React.ComponentProps<typeof DayPicker>;
13+
714
function BasicCalendar({
15+
isDateInput = false,
816
showOutsideDays = true,
917
formatters,
1018
...props
11-
}: React.ComponentProps<typeof DayPicker>) {
19+
}: Props) {
1220
const defaultClassNames = getDefaultClassNames();
1321
return (
1422
<DayPicker
@@ -20,8 +28,9 @@ function BasicCalendar({
2028
}}
2129
classNames={{
2230
root: `${defaultClassNames.root} w-full flex items-center justify-center`,
23-
day: `w-10 h-10 lg:w-8 lg:h-8 xl:w-10 xl:h-10`,
31+
day: `${isDateInput ? 'w-8 h-8' : 'w-10 h-10 lg:w-8 lg:h-8 xl:w-10 xl:h-10'}`,
2432
day_button: 'w-full h-full',
33+
caption_label: 'flex items-center justify-center pl-3',
2534
}}
2635
modifiersClassNames={{
2736
selected: 'bg-primary-500 text-white font-bold rounded-full',

src/components/common/FormInput.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ interface FormInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
77
label: string;
88
error?: string;
99
className?: string;
10+
labelClassName?: string;
1011
}
1112

1213
// 사용법 다시 적기
@@ -44,10 +45,10 @@ interface FormInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
4445
*/
4546

4647
const FormInput = forwardRef<HTMLInputElement, FormInputProps>(
47-
({ type = 'text', id, label, error, className, ...props }, ref) => {
48+
({ type = 'text', id, label, error, className, labelClassName, ...props }, ref) => {
4849
return (
4950
<div className='flex flex-col w-full'>
50-
<Label htmlFor={id} className='mb-[10px]'>
51+
<Label htmlFor={id} className={clsx('mb-[10px]', labelClassName)}>
5152
{label}
5253
</Label>
5354
<Input

src/components/common/LoadErrorFallback.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { useState, cloneElement, isValidElement, ReactElement } from 'react';
44
import Image from 'next/image';
5+
import { wsrvLoader } from './wsrvLoader';
56

67
interface LoadErrorFallbackProps {
78
children: ReactElement<{ onError?: (e: Event) => void }>;
@@ -11,6 +12,8 @@ interface LoadErrorFallbackProps {
1112
function DefaultImageFallback() {
1213
return (
1314
<Image
15+
loader={wsrvLoader}
16+
loading='lazy'
1417
src='/images/placeholder.svg'
1518
alt='이미지를 불러올 수 없습니다'
1619
width={200}

0 commit comments

Comments
 (0)