From 72f60e48592bc4d014fd0822ade95d74a416244c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DESKTOP-6FVFHUO=5C=EA=B8=B0=ED=9B=88?= Date: Wed, 31 Dec 2025 09:00:18 +0900 Subject: [PATCH 01/24] =?UTF-8?q?refactor:=20ButtonIcon=20=EC=84=9C?= =?UTF-8?q?=EB=B8=8C=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20->prop=EC=9C=BC=EB=A1=9C=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=ED=95=A0=EC=88=98=20=EC=9E=88=EA=B2=8C=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?buttonlabel=20->children=20=EB=8C=80=EC=8B=A0=20label=EC=9D=98?= =?UTF-8?q?=20=ED=83=80=EC=9E=85=EC=9D=84=20=EB=A7=8C=EB=93=A4=EA=B3=A0=20?= =?UTF-8?q?label=EC=9D=84=20=EB=82=B4=EB=A0=A4=EC=A4=84=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EA=B2=8C=EB=81=94=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/button/Button.tsx | 58 ++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/components/button/Button.tsx b/components/button/Button.tsx index 6b4206e..7644c58 100644 --- a/components/button/Button.tsx +++ b/components/button/Button.tsx @@ -1,54 +1,52 @@ "use client"; -import { ButtonHTMLAttributes, ReactNode } from "react"; +import { ReactNode, ComponentProps } from "react"; +import { cn } from "@/lib/utils/twmerge"; import { ButtonVariants, buttonIconVariants, buttonLabelVariants, } from "./ButtonVariants"; -import { cn } from "@/lib/utils/twmerge"; -interface ButtonProps extends ButtonHTMLAttributes { +type BaseButtonProps = { variant?: "primary" | "secondary" | "text" | "ghost"; size?: "lg" | "md" | "sm"; -} + leftIcon?: ReactNode; + rightIcon?: ReactNode; +}; + +type ButtonProps = ComponentProps<"button"> & BaseButtonProps; -interface ButtonSubProps { +type ButtonLabelProps = { + label: string; variant?: "primary" | "secondary" | "text" | "ghost"; size?: "lg" | "md" | "sm"; className?: string; - children: ReactNode; -} - -export const ButtonIcon = ({ - variant = "primary", - className, - children, -}: ButtonSubProps) => ( - - {children} - -); +}; export const ButtonLabel = ({ + label, variant = "primary", size = "md", className, - children, -}: ButtonSubProps) => ( - - {children} - -); +}: ButtonLabelProps) => { + return ( + + {label} + + ); +}; -export function Button({ +export const Button = ({ variant = "primary", size = "md", disabled = false, className, children, + leftIcon, + rightIcon, ...props -}: ButtonProps) { +}: ButtonProps) => { return ( ); -} +}; From 4935d50676656a05f658075f15f21c9ee8d509b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DESKTOP-6FVFHUO=5C=EA=B8=B0=ED=9B=88?= Date: Wed, 31 Dec 2025 09:23:37 +0900 Subject: [PATCH 02/24] =?UTF-8?q?refactor:=20ButtonIcon=20=EC=84=9C?= =?UTF-8?q?=EB=B8=8C=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20->prop=EC=9C=BC=EB=A1=9C=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=ED=95=A0=EC=88=98=20=EC=9E=88=EA=B2=8C=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?buttonlabel=20->children=20=EB=8C=80=EC=8B=A0=20label=EC=9D=98?= =?UTF-8?q?=20=ED=83=80=EC=9E=85=EC=9D=84=20=EB=A7=8C=EB=93=A4=EA=B3=A0=20?= =?UTF-8?q?label=EC=9D=84=20=EB=82=B4=EB=A0=A4=EC=A4=84=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EA=B2=8C=EB=81=94=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/button/Button.tsx | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/components/button/Button.tsx b/components/button/Button.tsx index 7644c58..dba216b 100644 --- a/components/button/Button.tsx +++ b/components/button/Button.tsx @@ -17,23 +17,16 @@ type BaseButtonProps = { type ButtonProps = ComponentProps<"button"> & BaseButtonProps; -type ButtonLabelProps = { - label: string; - variant?: "primary" | "secondary" | "text" | "ghost"; - size?: "lg" | "md" | "sm"; - className?: string; +type ButtonLabelProps = ComponentProps & { + label?: string; }; -export const ButtonLabel = ({ - label, - variant = "primary", - size = "md", - className, -}: ButtonLabelProps) => { +export const ButtonLabel = ({ label, children, variant = "primary", size = "md", ...buttonProps }: ButtonLabelProps) => { return ( - - {label} - + ); }; From 453d63565b1c697cdf131444dd1c2db6cad6b4d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?DESKTOP-6FVFHUO=5C=EA=B8=B0=ED=9B=88?= Date: Wed, 31 Dec 2025 09:40:02 +0900 Subject: [PATCH 03/24] =?UTF-8?q?refactor:=20ref=EA=B0=80=20prop=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9E=90=EB=8F=99=EC=A0=84=EB=8B=AC=20componentPro?= =?UTF-8?q?psWithRef=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/button/Button.tsx | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/components/button/Button.tsx b/components/button/Button.tsx index dba216b..b1f3d15 100644 --- a/components/button/Button.tsx +++ b/components/button/Button.tsx @@ -1,6 +1,6 @@ "use client"; -import { ReactNode, ComponentProps } from "react"; +import { ReactNode, ComponentPropsWithRef } from "react"; import { cn } from "@/lib/utils/twmerge"; import { ButtonVariants, @@ -15,21 +15,12 @@ type BaseButtonProps = { rightIcon?: ReactNode; }; -type ButtonProps = ComponentProps<"button"> & BaseButtonProps; +export type ButtonProps = ComponentPropsWithRef<"button"> & BaseButtonProps; -type ButtonLabelProps = ComponentProps & { +export type ButtonLabelProps = ButtonProps & { label?: string; }; -export const ButtonLabel = ({ label, children, variant = "primary", size = "md", ...buttonProps }: ButtonLabelProps) => { - return ( - - ); -}; - export const Button = ({ variant = "primary", size = "md", @@ -38,6 +29,7 @@ export const Button = ({ children, leftIcon, rightIcon, + ref, ...props }: ButtonProps) => { return ( @@ -45,6 +37,7 @@ export const Button = ({ type="button" disabled={disabled} className={cn(ButtonVariants({ variant, size }), className)} + ref={ref} {...props} > {leftIcon && ( @@ -59,3 +52,19 @@ export const Button = ({ ); }; + +export const ButtonLabel = ({ + label, + children, + variant = "primary", + size = "md", + ref, + ...buttonProps +}: ButtonLabelProps) => { + return ( + + ); +}; From a22c112eb3fe65deb8006d9811181908c6b7bc33 Mon Sep 17 00:00:00 2001 From: Choi hee ruk Date: Thu, 1 Jan 2026 21:30:40 +0900 Subject: [PATCH 04/24] =?UTF-8?q?=F0=9F=8E=A8=20Style:=20reservation-view?= =?UTF-8?q?=20SVG=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/icon_delete.svg | 4 ++++ public/icon_earth.svg | 22 ++++++++++++++++++++++ public/icon_star_off.svg | 3 +++ public/icon_star_on.svg | 3 +++ public/icon_warning.svg | 14 ++++++++++++++ 5 files changed, 46 insertions(+) create mode 100644 public/icon_delete.svg create mode 100644 public/icon_earth.svg create mode 100644 public/icon_star_off.svg create mode 100644 public/icon_star_on.svg create mode 100644 public/icon_warning.svg diff --git a/public/icon_delete.svg b/public/icon_delete.svg new file mode 100644 index 0000000..9426e7a --- /dev/null +++ b/public/icon_delete.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/icon_earth.svg b/public/icon_earth.svg new file mode 100644 index 0000000..5f97712 --- /dev/null +++ b/public/icon_earth.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/icon_star_off.svg b/public/icon_star_off.svg new file mode 100644 index 0000000..873fcf7 --- /dev/null +++ b/public/icon_star_off.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icon_star_on.svg b/public/icon_star_on.svg new file mode 100644 index 0000000..f2018df --- /dev/null +++ b/public/icon_star_on.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icon_warning.svg b/public/icon_warning.svg new file mode 100644 index 0000000..7026363 --- /dev/null +++ b/public/icon_warning.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + From 9543318aa750cc50fb9421c4519b01a181953e16 Mon Sep 17 00:00:00 2001 From: Choi hee ruk Date: Thu, 1 Jan 2026 21:31:09 +0900 Subject: [PATCH 05/24] =?UTF-8?q?=F0=9F=8E=A8=20Style:=20MyInfo=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20p-6=20=ED=8C=A8=EB=94=A9=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/myinfo/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/myinfo/page.tsx b/app/myinfo/page.tsx index 6817de5..f9f8df9 100644 --- a/app/myinfo/page.tsx +++ b/app/myinfo/page.tsx @@ -16,7 +16,7 @@ export default function MyInfoPage() {
-
+
{activeMenu === "MY_INFO" && } {activeMenu === "RESERVATIONS" && } {activeMenu === "MY_EXPERIENCE" && } From e7b1e7f989c7ecb1450e5ceec542dfb17a378ce2 Mon Sep 17 00:00:00 2001 From: Choi hee ruk Date: Thu, 1 Jan 2026 21:31:43 +0900 Subject: [PATCH 06/24] =?UTF-8?q?=E2=9C=A8=20Feat:=20ReservationView=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/MyInfo/ReservationView.tsx | 515 +++++++++++++++++++++++++++-- 1 file changed, 493 insertions(+), 22 deletions(-) diff --git a/feature/MyInfo/ReservationView.tsx b/feature/MyInfo/ReservationView.tsx index e5573f7..bd0e524 100644 --- a/feature/MyInfo/ReservationView.tsx +++ b/feature/MyInfo/ReservationView.tsx @@ -1,29 +1,500 @@ "use client"; +import { useState } from "react"; +import Image from "next/image"; +import Button from "@/components/button/Button"; +import ButtonLabel from "@/components/button/Button.Label"; -type Props = { - mode?: "view" | "edit"; - onEdit?: () => void; - onCancel?: () => void; +type ReservationStatus = + | "pending" + | "confirmed" + | "declined" + | "canceled" + | "completed"; + +type Reservation = { + id: number; + title: string; + date: string; + price: number; + people: number; + status: ReservationStatus; +}; + +const STATUS_LABEL: Record = { + pending: "예약 완료", + confirmed: "예약 승인", + canceled: "예약 취소", + declined: "예약 거절", + completed: "체험 완료", }; -export default function ReservationView({ - mode = "view", - onEdit, - onCancel, -}: Props) { -// const { data, loading, error } = useMyInfo(); - -// if (loading) return
로딩중...
; -// if (error || !data) return
에러
; - - return ( -
예약내역 들어갈곳
- // +// empty state 테스트 하는법 +// const reservations: Reservation[] = []; +// 밑에 목데이터들을 주석처리하고 위의 빈 배열을 사용하세요. + +// TODO: API 연동 필요 +// 연동시 목데이터 삭제 필요 + +const reservations: Reservation[] = [ + { + id: 1, + title: "함께 배우는 플로잉 댄스", + date: "2023.02.14 · 11:00 - 12:30", + price: 10000, + people: 1, + status: "pending", + }, + { + id: 2, + title: "내 강아지 인생 사진 찍어주기", + date: "2023.02.11 · 13:00 - 14:00", + price: 35000, + people: 1, + status: "canceled", + }, + { + id: 3, + title: "이색 액티비티 체험", + date: "2023.01.10 · 10:00 - 12:00", + price: 60000, + people: 3, + status: "declined", + }, + { + id: 4, + title: "별과 함께하는 북촌 체험", + date: "2023.01.14 · 15:00 - 16:00", + price: 40000, + people: 2, + status: "completed", + }, + { + id: 5, + title: "요리 클래스 체험", + date: "2023.09.20 · 09:00 - 10:30", + price: 25000, + people: 1, + status: "completed", + }, + { + id: 6, + title: "여행 클래스 체험", + date: "2023.11.20 · 09:00 - 10:30", + price: 37000, + people: 1, + status: "confirmed", + }, +]; + +const STATUS_STYLE: Record< + ReservationStatus, + { badge: string; button: string } +> = { + pending: { + badge: "bg-[var(--color-green-100)] text-[var(--color-green-500)]", + button: "bg-[var(--color-green-100)] text-[var(--color-green-500)]", + }, + confirmed: { + badge: "bg-[var(--color-primary-100)] text-[var(--color-primary-500)]", + button: "bg-[var(--color-primary-100)] text-[var(--color-primary-500)]", + }, + canceled: { + badge: "bg-[var(--color-gray-100)] text-[var(--color-gray-600)]", + button: "bg-[var(--color-gray-100)] text-[var(--color-gray-600)]", + }, + declined: { + badge: "bg-[#FCECEA] text-[#F96767]", + button: "bg-[#FCECEA] text-[#F96767]", + }, + completed: { + badge: "bg-[var(--color-primary-100)] text-[var(--color-primary-500)]", + button: "bg-[var(--color-primary-100)] text-[var(--color-primary-500)]", + }, +}; +// TODO: 공통 모달 컴포넌트로 교체 필요 +// 취소 모달 +function CancelModal({ + isOpen, + onClose, + onConfirm, + reservationTitle, +}: { + isOpen: boolean; + onClose: () => void; + onConfirm: () => void; + reservationTitle: string; +}) { + if (!isOpen) return null; + + return ( +
+
+ +
+ {/* 아이콘 */} + 경고 아이콘 + +

+ 예약을 취소하시겠어요? +

+ +
+ + + +
+
+
+ ); +} +// TODO: 공통 모달 컴포넌트로 교체 필요 +// 후기 작성 모달 +function ReviewModal({ + isOpen, + onClose, + onSubmit, + reservation, +}: { + isOpen: boolean; + onClose: () => void; + onSubmit: (rating: number, content: string) => void; + reservation: Reservation | null; +}) { + const [rating, setRating] = useState(0); + const [content, setContent] = useState(""); + + if (!isOpen || !reservation) return null; + + const handleSubmit = () => { + if (rating === 0) { + alert("별점을 선택해주세요"); + return; + } + onSubmit(rating, content); + setRating(0); + setContent(""); + }; + + const handleClose = () => { + setRating(0); + setContent(""); + onClose(); + }; + + return ( +
+
+
+ {/* 닫기 버튼 영역 */} +
+ +
+ + {/* 내용 영역 */} +
+ {/* 체험 정보 */} +

+ {reservation.title} +

+

+ {reservation.date.replace("·", "/")} ({reservation.people}명) +

+ + {/* 별점 */} +
+ {[1, 2, 3, 4, 5].map((star) => ( + + ))} +
+ + {/* 후기 입력 */} +
+ +