From 2e2b71743f4e89b76bea57af25ea8f4d1f3787ac Mon Sep 17 00:00:00 2001 From: pricelees Date: Mon, 18 Aug 2025 15:35:32 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=83=88=EB=A1=9C=EC=9A=B4=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90=EC=9D=98=20=EC=98=88=EC=95=BD=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/api/reservation/reservationAPI.ts | 21 ++- .../src/api/reservation/reservationAPIV2.ts | 150 ------------------ .../src/api/reservation/reservationTypes.ts | 39 +++-- frontend/src/components/Navbar.tsx | 4 +- frontend/src/components/ReservationCard.tsx | 137 ---------------- frontend/src/css/my-reservation-v2.css | 8 +- frontend/src/pages/admin/ReservationPage.tsx | 10 +- frontend/src/pages/v2/MyReservationPageV2.tsx | 111 +++++++++---- .../src/pages/v2/ReservationSuccessPage.tsx | 2 +- 9 files changed, 134 insertions(+), 348 deletions(-) delete mode 100644 frontend/src/components/ReservationCard.tsx diff --git a/frontend/src/api/reservation/reservationAPI.ts b/frontend/src/api/reservation/reservationAPI.ts index 0006f0d8..01a39c4a 100644 --- a/frontend/src/api/reservation/reservationAPI.ts +++ b/frontend/src/api/reservation/reservationAPI.ts @@ -2,14 +2,16 @@ import apiClient from "@_api/apiClient"; import type { AdminReservationCreateRequest, MyReservationRetrieveListResponse, - ReservationPaymentRequest, - ReservationPaymentResponse, ReservationCreateRequest, ReservationCreateResponse, ReservationCreateWithPaymentRequest, + ReservationDetailV2, + ReservationPaymentRequest, + ReservationPaymentResponse, ReservationRetrieveListResponse, ReservationRetrieveResponse, ReservationSearchQuery, + ReservationSummaryListV2, WaitingCreateRequest } from "./reservationTypes"; @@ -81,4 +83,19 @@ export const createPendingReservation = async (data: ReservationCreateRequest): // POST /v2/reservations/{id}/pay export const confirmReservationPayment = async (id: string, data: ReservationPaymentRequest): Promise => { return await apiClient.post(`/v2/reservations/${id}/pay`, data, true); +}; + +// POST /v2/reservations/{id}/cancel +export const cancelReservationV2 = async (id: string, cancelReason: string): Promise => { + return await apiClient.post(`/v2/reservations/${id}/cancel`, { cancelReason }, true); +}; + +// GET /v2/reservations +export const fetchMyReservationsV2 = async (): Promise => { + return await apiClient.get('/v2/reservations', true); +}; + +// GET /v2/reservations/{id}/details +export const fetchReservationDetailV2 = async (id: string): Promise => { + return await apiClient.get(`/v2/reservations/${id}/details`, true); }; \ No newline at end of file diff --git a/frontend/src/api/reservation/reservationAPIV2.ts b/frontend/src/api/reservation/reservationAPIV2.ts index 2f560898..e69de29b 100644 --- a/frontend/src/api/reservation/reservationAPIV2.ts +++ b/frontend/src/api/reservation/reservationAPIV2.ts @@ -1,150 +0,0 @@ -import type { ReservationSummaryV2, ReservationDetailV2 } from './reservationTypes'; - -// --- API 호출 함수 --- - -/** - * 내 예약 목록을 가져옵니다. (V2) - */ -export const fetchMyReservationsV2 = async (): Promise => { - // 실제 API 연동 시 아래 코드로 교체 - // const response = await apiClient.get('/v2/reservations'); - // return response.data; - - // 현재는 목업 데이터를 반환합니다. - console.log('[API] fetchMyReservationsV2 호출'); - return new Promise((resolve) => - setTimeout(() => { - resolve([ - { id: 1, date: '2025-08-20', time: '14:00', themeName: '공포의 방', status: 'CONFIRMED' }, - { id: 2, date: '2025-08-22', time: '19:30', themeName: '신비의 숲', status: 'CONFIRMED' }, - { id: 3, date: '2024-12-25', time: '11:00', themeName: '미래 도시', status: 'CANCELLED' }, - ]); - }, 500) - ); -}; - -/** - * 특정 예약의 상세 정보를 가져옵니다. (V2) - * @param id 예약 ID - */ -export const fetchReservationDetailV2 = async (id: number): Promise => { - // 실제 API 연동 시 아래 코드로 교체 - // const response = await apiClient.get(`/v2/reservations/${id}`); - // return response.data; - - // 현재는 목업 데이터를 반환합니다. - console.log(`[API] fetchReservationDetailV2 호출 (id: ${id})`); - console.log(`[API] fetchReservationDetailV2 호출 (id: ${id})`); - - const mockDetails: { [key: number]: ReservationDetailV2 } = { - 1: { - id: 1, - memberName: '박예약', - memberEmail: 'reserve@example.com', - applicationDateTime: '2025-08-20T13:50:00Z', - payment: { - paymentKey: 'reserve-payment-key', - orderId: 'reserve-order-id', - totalAmount: 50000, - method: 'CARD', - status: 'DONE', - requestedAt: '2025-08-20T13:50:00Z', - approvedAt: '2025-08-20T13:50:05Z', - detail: { - type: 'CARD', - issuerCode: 'SHINHAN', - cardType: 'CHECK', - ownerType: 'PERSONAL', - cardNumber: '5423-****-****-1234', - approvalNumber: '12345678', - installmentPlanMonths: 0, - isInterestFree: true, - } - }, - cancellation: null, - }, - 2: { - id: 2, - memberName: '이간편', - memberEmail: 'easypay@example.com', - applicationDateTime: '2025-08-22T19:20:00Z', - payment: { - paymentKey: 'easypay-card-key', - orderId: 'easypay-card-order-id', - totalAmount: 75000, - method: 'CARD', - status: 'DONE', - requestedAt: '2025-08-22T19:20:00Z', - approvedAt: '2025-08-22T19:20:05Z', - detail: { - type: 'CARD', - issuerCode: 'HYUNDAI', - cardType: 'CREDIT', - ownerType: 'PERSONAL', - cardNumber: '4321-****-****-5678', - approvalNumber: '87654321', - installmentPlanMonths: 3, - isInterestFree: false, - easypayProviderCode: 'NAVERPAY', - } - }, - cancellation: null, - }, - 3: { - id: 3, - memberName: '김취소', - memberEmail: 'cancel@example.com', - applicationDateTime: '2024-12-25T10:50:00Z', - payment: { - paymentKey: 'cancel-payment-key', - orderId: 'cancel-order-id', - totalAmount: 52000, - method: 'EASYPAY_PREPAID', - status: 'CANCELED', - requestedAt: '2024-12-25T10:50:00Z', - approvedAt: '2024-12-25T10:50:05Z', - detail: { - type: 'EASYPAY_PREPAID', - easypayProviderCode: 'TOSSPAY', - amount: 52000, - discountAmount: 0, - } - }, - cancellation: { - cancellationRequestedAt: '2025-01-10T14:59:00Z', - cancellationCompletedAt: '2025-01-10T15:00:00Z', - cancelReason: '개인 사정으로 인한 취소', - }, - } - }; - - return new Promise((resolve) => - setTimeout(() => { - const mockDetail = mockDetails[id] || mockDetails[1]; // Fallback to 1 - resolve(mockDetail); - }, 800) - ); -}; - -/** - * 예약을 취소합니다. (V2) - * @param id 예약 ID - * @param cancelReason 취소 사유 - */ -export const cancelReservationV2 = async (id: number, cancelReason: string): Promise => { - // 실제 API 연동 시 아래 코드로 교체 - // await apiClient.post(`/v2/reservations/${id}/cancel`, { cancelReason }); - - console.log(`[API] cancelReservationV2 호출 (id: ${id}, reason: ${cancelReason})`); - return new Promise((resolve, reject) => { - setTimeout(() => { - if (cancelReason && cancelReason.trim().length > 0) { - // 성공 시, 목업 데이터 업데이트 (실제로는 서버가 처리) - console.log(`Reservation ${id} has been cancelled.`); - resolve(); - } else { - reject(new Error('취소 사유를 반드시 입력해야 합니다.')); - } - }, 800); - }); -}; diff --git a/frontend/src/api/reservation/reservationTypes.ts b/frontend/src/api/reservation/reservationTypes.ts index b73caf8c..5501ed8c 100644 --- a/frontend/src/api/reservation/reservationTypes.ts +++ b/frontend/src/api/reservation/reservationTypes.ts @@ -134,27 +134,38 @@ export interface ReservationPaymentResponse { } export interface ReservationSummaryV2 { - id: number; + id: string; themeName: string; date: string; - time: string; - status: 'CONFIRMED' | 'CANCELLED'; + startAt: string; + status: string; // 'CONFIRMED', 'CANCELED_BY_USER', etc. +} + +export interface ReservationSummaryListV2 { + reservations: ReservationSummaryV2[]; } export interface ReservationDetailV2 { - id: number; - memberName: string; - memberEmail: string; - applicationDateTime: string; // yyyy년 MM월 dd일 HH시 mm분 + id: string; + user: UserDetailV2; + themeName: string; + date: string; + startAt: string; + applicationDateTime: string; payment: PaymentV2; cancellation: CancellationV2 | null; } +export interface UserDetailV2 { + id: string; + name: string; + email: string; +} + export interface PaymentV2 { - paymentKey: string; orderId: string; totalAmount: number; - method: 'CARD' | 'BANK_TRANSFER' | 'EASYPAY_PREPAID'; + method: string; status: 'DONE' | 'CANCELED'; requestedAt: string; approvedAt: string; @@ -167,28 +178,30 @@ export interface CardPaymentDetailV2 { cardType: 'CREDIT' | 'CHECK' | 'GIFT'; ownerType: 'PERSONAL' | 'CORPORATE'; cardNumber: string; + amount: number; approvalNumber: string; installmentPlanMonths: number; isInterestFree: boolean; - easypayProviderCode?: string; + easypayProviderName?: string; easypayDiscountAmount?: number; } export interface BankTransferPaymentDetailV2 { type: 'BANK_TRANSFER'; - bankCode: string; + bankName: string; settlementStatus: string; } export interface EasyPayPrepaidPaymentDetailV2 { type: 'EASYPAY_PREPAID'; - easypayProviderCode: string; + providerName: string; amount: number; discountAmount: number; } export interface CancellationV2 { cancellationRequestedAt: string; // ISO 8601 format - cancellationCompletedAt: string; // ISO 8601 format + cancellationApprovedAt: string; // ISO 8601 format cancelReason: string; + canceledBy: string; } diff --git a/frontend/src/components/Navbar.tsx b/frontend/src/components/Navbar.tsx index 6d6a324d..8644022f 100644 --- a/frontend/src/components/Navbar.tsx +++ b/frontend/src/components/Navbar.tsx @@ -27,7 +27,7 @@ const Navbar: React.FC = () => {