Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7f0776e
fix: 반응형 수정 & 가격 formatNumber & confirm 모달 연결
hong0121 Sep 11, 2025
b3584c8
fix(main): 반응형에 따른 리스트 뷰 사이즈 변경시 현재 페이지네이션의 데이터가 빈값일 때 값이 있는 페이지네이션이 …
LeeTaegyung Sep 12, 2025
a8698f8
fix(token): 모바일에서 무한 로딩 이슈 수정
LeeTaegyung Sep 12, 2025
db1caae
fix(toast): 토스트 하이드레이션 에러 수정
LeeTaegyung Sep 12, 2025
d2b1c74
fix(AuthProvider): 마이페이지에서 새로고침시 로그인 페이지로 이동되는 버그 수정
LeeTaegyung Sep 12, 2025
2ec09b9
Merge branch 'dev' into feature/MycreateExperiencesPage
hong0121 Sep 12, 2025
58b3a30
Merge pull request #46 from hong0121/feature/MycreateExperiencesPage
hong0121 Sep 12, 2025
2213e9c
fix: 알려진 버그 수정
Squarecat-meow Sep 12, 2025
f0cbccc
Merge branch 'dev' of https://github.com/hong0121/global-nomad-fronte…
LeeTaegyung Sep 12, 2025
e22f0fd
fix(queries): 체험 삭제 로직 재작성
Squarecat-meow Sep 12, 2025
ef1f605
fix(rootLayout): 페이지에서 useSearchParams() 사용시 Suspense 적용
LeeTaegyung Sep 12, 2025
077c4a8
fix(Reservation): 예약 성공, 실패 토스트 작성
Squarecat-meow Sep 12, 2025
8b153aa
fix(Dropdown): 체험수정에서 Dropdown 선택 안됨 & reset 버그 수정
Squarecat-meow Sep 12, 2025
3463045
Merge branch 'dev' into saeron-jung/primitive
Squarecat-meow Sep 12, 2025
6eb317d
feat(NotiModal): 유저 알람 모달 UI, 조회 API 연결
sinyroom Sep 11, 2025
ddfa680
feat(NotiModal): 알람 삭제 API 작성
sinyroom Sep 11, 2025
1eedd52
reafactor(NotiModal): 유틸함수 분리, 리액트 쿼리로 변경
sinyroom Sep 11, 2025
83a6f00
style(scrollbar): 스크롤바 숨기도록 설정
sinyroom Sep 11, 2025
19f2705
chore(types): 알람 타입 수정
sinyroom Sep 11, 2025
ca1cd2e
feat(NotiModal): 알람이 없을 경우 문구 표시
sinyroom Sep 11, 2025
e986912
feat(NotiModal): 무한스크롤 기능 구현, 알람 types 수정
sinyroom Sep 12, 2025
bb478e1
Merge pull request #48 from sinyroom/feature/activity-detail
sinyroom Sep 12, 2025
2aa805e
Merge pull request #49 from LeeTaegyung/fix/auth
LeeTaegyung Sep 12, 2025
efbbac9
Merge pull request #50 from Squarecat-meow/saeron-jung/primitive
Squarecat-meow Sep 12, 2025
dfa3df2
refactor: 최종 리팩토링
hong0121 Sep 14, 2025
43b49ad
refactor: 무한루프 해결
hong0121 Sep 14, 2025
76a20a8
Merge pull request #51 from hong0121/feature/MycreateExperiencesPage
hong0121 Sep 15, 2025
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
7 changes: 7 additions & 0 deletions public/images/icons/ActiveBellIcon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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.
63 changes: 46 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 All @@ -38,7 +39,7 @@ interface ExperiencesFormData {

export default function MyCreateExperiencesPage() {
const dropdownItems = [
{ id: 1, title: '문화 예술' },
{ id: 1, title: '문화 · 예술' },
{ id: 2, title: '식음료' },
{ id: 3, title: '스포츠' },
{ id: 4, title: '투어' },
Expand All @@ -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,11 +113,14 @@ export default function MyCreateExperiencesPage() {
? await uploadActivityImages(subImages)
: [];

console.log('업로드 후 소개 이미지 URL:', subImageUrls);
const categoryTitle =
dropdownItems.find((item) => item.id === Number(data.category))
?.title ?? '';

// 4️⃣ payload 생성
const payload = {
...data,
category: categoryTitle,
schedules,
bannerImageUrl: bannerUrl,
subImageUrls,
Expand All @@ -128,9 +139,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 +181,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
29 changes: 25 additions & 4 deletions src/app/(global)/(mypage)/myInfo/_components/myExperiences.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,21 @@
import MyExperienceCard from '@/src/components/pages/myExperiences/MyExperienceCard';
import Button from '@/src/components/primitives/Button';
import LoadingSpinner from '@/src/components/primitives/LoadingSpinner';
import { useQuery } from '@tanstack/react-query';
import { useMutation, useQuery } from '@tanstack/react-query';
import Image from 'next/image';
import BackIcon from '@/public/images/icons/BackIcon.svg';
import { useContext } from 'react';
import { useContext, useState } from 'react';
import { TabContext } from '../pageContext';
import { queries } from '@/src/services/primitives/queries';
import ConfirmModal from '@/src/components/primitives/modal/ConfirmModal';
import Link from 'next/link';

export default function MyExperiencesPage() {
const [isModalVisible, setIsModalVisible] = useState(false);
const [selectedExperience, setSelectedExperience] = useState<number>(0);
const { setIsTabOpen } = useContext(TabContext);
const { data, isPending } = useQuery(queries.myExperiencesOptions());
const mutation = useMutation(queries.myExperiencesMutationOptions());

return (
<section className='flex flex-col items-center gap-8'>
Expand All @@ -31,14 +36,21 @@ export default function MyExperiencesPage() {
</p>
</div>
</div>
<Button size='lg'>체험 등록하기</Button>
<Link href={'/myCreateExperiences'}>
<Button size='lg'>체험 등록하기</Button>
</Link>
</div>
{!isPending ? (
<>
{data && data.totalCount !== 0 ? (
<>
{data.activities.map((activity) => (
<MyExperienceCard data={activity} key={activity.id} />
<MyExperienceCard
data={activity}
key={activity.id}
callbackId={setSelectedExperience}
setIsModalVisible={setIsModalVisible}
/>
))}
</>
) : (
Expand All @@ -59,6 +71,15 @@ export default function MyExperiencesPage() {
) : (
<LoadingSpinner />
)}
<ConfirmModal
onConfirm={() => {
mutation.mutate(selectedExperience);
setIsModalVisible(false);
}}
onCancel={() => setIsModalVisible(false)}
isOpen={isModalVisible}
message='정말 체험을 삭제하시겠습니까?'
/>
</section>
);
}
2 changes: 1 addition & 1 deletion src/app/(global)/(mypage)/myInfo/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export default function MypageLayout() {
<TabContext.Provider value={{ tab, setTab, isTabOpen, setIsTabOpen }}>
<section
id='my-info-body'
className='w-full pt-[85px] pb-[64px] overflow-hidden md:pt-[120px] md:pb-[54px] h-full'
className='w-full pt-[85px] pb-[64px] overflow-hidden md:pt-[120px] md:pb-[54px]'
>
<div
className={cn(
Expand Down
Loading