From 842a11a9ae1c41bb9ef88df0f0f1b1e62584d89a Mon Sep 17 00:00:00 2001 From: pricelees Date: Sat, 13 Sep 2025 19:01:30 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20API=20=EC=97=94=EB=93=9C=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EC=A0=95=EB=A6=AC=20=EB=B0=8F=20=ED=94=84?= =?UTF-8?q?=EB=A1=A0=ED=8A=B8=EC=97=94=EB=93=9C=20=EB=AF=B8=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/eslint.config.js | 2 +- frontend/public/vite.svg | 3 +- frontend/src/App.tsx | 4 +- frontend/src/api/apiClient.ts | 2 +- frontend/src/api/auth/authAPI.ts | 2 +- frontend/src/api/payment/paymentAPI.ts | 2 +- ...{reservationAPIV2.ts => reservationAPI.ts} | 2 +- ...ervationTypesV2.ts => reservationTypes.ts} | 22 +-- frontend/src/api/schedule/scheduleAPI.ts | 3 +- frontend/src/api/schedule/scheduleTypes.ts | 14 +- frontend/src/api/theme/themeAPI.ts | 37 +--- frontend/src/api/theme/themeTypes.ts | 59 +----- frontend/src/api/user/userAPI.ts | 2 +- frontend/src/assets/react.svg | 3 +- frontend/src/components/AdminRoute.tsx | 4 +- frontend/src/components/Layout.tsx | 2 +- frontend/src/components/Navbar.tsx | 4 +- frontend/src/context/AuthContext.tsx | 6 +- frontend/src/css/admin-time-page.css | 120 ------------ frontend/src/css/admin-waiting-page.css | 81 -------- frontend/src/css/reservation-v2-1.css | 14 +- frontend/src/css/reservation-v2.css | 175 ------------------ frontend/src/css/reservation.css | 15 -- frontend/src/main.tsx | 5 +- frontend/src/pages/HomePage.tsx | 12 +- frontend/src/pages/LoginPage.tsx | 6 +- frontend/src/pages/MyReservationPage.tsx | 22 ++- frontend/src/pages/ReservationFormPage.tsx | 12 +- frontend/src/pages/ReservationStep1Page.tsx | 23 ++- frontend/src/pages/ReservationStep2Page.tsx | 14 +- frontend/src/pages/ReservationSuccessPage.tsx | 4 +- frontend/src/pages/SignupPage.tsx | 8 +- frontend/src/pages/admin/AdminLayout.tsx | 2 +- frontend/src/pages/admin/AdminNavbar.tsx | 4 +- .../src/pages/admin/AdminSchedulePage.tsx | 24 ++- .../src/pages/admin/AdminThemeEditPage.tsx | 28 +-- frontend/src/pages/admin/AdminThemePage.tsx | 8 +- frontend/vite.config.ts | 2 +- .../payment/web/PaymentController.kt | 6 +- .../reservation/docs/ReservationAPI.kt | 2 +- .../reservation/web/ReservationController.kt | 17 +- .../schedule/web/ScheduleController.kt | 15 +- .../roomescape/theme/web/ThemeController.kt | 2 +- .../roomescape/user/web/UserController.kt | 6 +- 44 files changed, 186 insertions(+), 614 deletions(-) rename frontend/src/api/reservation/{reservationAPIV2.ts => reservationAPI.ts} (97%) rename frontend/src/api/reservation/{reservationTypesV2.ts => reservationTypes.ts} (68%) delete mode 100644 frontend/src/css/admin-time-page.css delete mode 100644 frontend/src/css/admin-waiting-page.css delete mode 100644 frontend/src/css/reservation-v2.css delete mode 100644 frontend/src/css/reservation.css diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index d94e7deb..02c76837 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -3,7 +3,7 @@ import globals from 'globals' import reactHooks from 'eslint-plugin-react-hooks' import reactRefresh from 'eslint-plugin-react-refresh' import tseslint from 'typescript-eslint' -import { globalIgnores } from 'eslint/config' +import {globalIgnores} from 'eslint/config' export default tseslint.config([ globalIgnores(['dist']), diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg index e7b8dfb1..3f42576c 100644 --- a/frontend/public/vite.svg +++ b/frontend/public/vite.svg @@ -1 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 5a75814c..44f1900c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,7 +1,7 @@ -import { Route, BrowserRouter as Router, Routes } from 'react-router-dom'; +import {BrowserRouter as Router, Route, Routes} from 'react-router-dom'; import AdminRoute from './components/AdminRoute'; import Layout from './components/Layout'; -import { AuthProvider } from './context/AuthContext'; +import {AuthProvider} from './context/AuthContext'; import AdminLayout from './pages/admin/AdminLayout'; import AdminPage from './pages/admin/AdminPage'; import AdminSchedulePage from './pages/admin/AdminSchedulePage'; diff --git a/frontend/src/api/apiClient.ts b/frontend/src/api/apiClient.ts index 243b84ae..5871ff7f 100644 --- a/frontend/src/api/apiClient.ts +++ b/frontend/src/api/apiClient.ts @@ -1,4 +1,4 @@ -import axios, { type AxiosError, type AxiosRequestConfig, type Method } from 'axios'; +import axios, {type AxiosError, type AxiosRequestConfig, type Method} from 'axios'; import JSONbig from 'json-bigint'; // Create a JSONbig instance that stores big integers as strings diff --git a/frontend/src/api/auth/authAPI.ts b/frontend/src/api/auth/authAPI.ts index 30c9b215..93216199 100644 --- a/frontend/src/api/auth/authAPI.ts +++ b/frontend/src/api/auth/authAPI.ts @@ -1,5 +1,5 @@ import apiClient from '@_api/apiClient'; -import type { CurrentUserContext, LoginRequest, LoginSuccessResponse } from './authTypes'; +import type {CurrentUserContext, LoginRequest, LoginSuccessResponse} from './authTypes'; export const login = async (data: LoginRequest): Promise => { diff --git a/frontend/src/api/payment/paymentAPI.ts b/frontend/src/api/payment/paymentAPI.ts index c5481ec8..d2923e0b 100644 --- a/frontend/src/api/payment/paymentAPI.ts +++ b/frontend/src/api/payment/paymentAPI.ts @@ -1,5 +1,5 @@ import apiClient from "@_api/apiClient"; -import type { PaymentCancelRequest, PaymentConfirmRequest, PaymentCreateResponseV2 } from "./PaymentTypes"; +import type {PaymentCancelRequest, PaymentConfirmRequest, PaymentCreateResponseV2} from "./PaymentTypes"; export const confirmPayment = async (reservationId: string, request: PaymentConfirmRequest): Promise => { return await apiClient.post(`/payments?reservationId=${reservationId}`, request); diff --git a/frontend/src/api/reservation/reservationAPIV2.ts b/frontend/src/api/reservation/reservationAPI.ts similarity index 97% rename from frontend/src/api/reservation/reservationAPIV2.ts rename to frontend/src/api/reservation/reservationAPI.ts index 9bb14321..f2a80d5e 100644 --- a/frontend/src/api/reservation/reservationAPIV2.ts +++ b/frontend/src/api/reservation/reservationAPI.ts @@ -5,7 +5,7 @@ import type { PendingReservationCreateResponse, ReservationDetailRetrieveResponse, ReservationSummaryRetrieveListResponse -} from './reservationTypesV2'; +} from './reservationTypes'; export const createPendingReservation = async (request: PendingReservationCreateRequest): Promise => { return await apiClient.post('/reservations/pending', request); diff --git a/frontend/src/api/reservation/reservationTypesV2.ts b/frontend/src/api/reservation/reservationTypes.ts similarity index 68% rename from frontend/src/api/reservation/reservationTypesV2.ts rename to frontend/src/api/reservation/reservationTypes.ts index bc6eb4e9..5c19d21a 100644 --- a/frontend/src/api/reservation/reservationTypesV2.ts +++ b/frontend/src/api/reservation/reservationTypes.ts @@ -1,7 +1,7 @@ -import type { PaymentRetrieveResponse } from "@_api/payment/PaymentTypes"; -import type { UserContactRetrieveResponse } from "@_api/user/userTypes"; +import type {PaymentRetrieveResponse} from "@_api/payment/PaymentTypes"; +import type {UserContactRetrieveResponse} from "@_api/user/userTypes"; -export const ReservationStatusV2 = { +export const ReservationStatus = { PENDING: 'PENDING', CONFIRMED: 'CONFIRMED', CANCELED: 'CANCELED', @@ -9,12 +9,12 @@ export const ReservationStatusV2 = { EXPIRED: 'EXPIRED' } as const; -export type ReservationStatusV2 = - | typeof ReservationStatusV2.PENDING - | typeof ReservationStatusV2.CONFIRMED - | typeof ReservationStatusV2.CANCELED - | typeof ReservationStatusV2.FAILED - | typeof ReservationStatusV2.EXPIRED; +export type ReservationStatus = + | typeof ReservationStatus.PENDING + | typeof ReservationStatus.CONFIRMED + | typeof ReservationStatus.CANCELED + | typeof ReservationStatus.FAILED + | typeof ReservationStatus.EXPIRED; export interface PendingReservationCreateRequest { scheduleId: string, @@ -33,7 +33,7 @@ export interface ReservationSummaryRetrieveResponse { themeName: string; date: string; startAt: string; - status: ReservationStatusV2; + status: ReservationStatus; } export interface ReservationSummaryRetrieveListResponse { @@ -54,7 +54,7 @@ export interface ReservationDetail { startAt: string; user: UserContactRetrieveResponse; applicationDateTime: string; - payment: PaymentRetrieveResponse; + payment?: PaymentRetrieveResponse; } export interface MostReservedThemeIdListResponse { diff --git a/frontend/src/api/schedule/scheduleAPI.ts b/frontend/src/api/schedule/scheduleAPI.ts index f828fa2b..87d7d0ac 100644 --- a/frontend/src/api/schedule/scheduleAPI.ts +++ b/frontend/src/api/schedule/scheduleAPI.ts @@ -2,7 +2,8 @@ import apiClient from '../apiClient'; import type { AvailableThemeIdListResponse, ScheduleCreateRequest, - ScheduleCreateResponse, ScheduleDetailRetrieveResponse, + ScheduleCreateResponse, + ScheduleDetailRetrieveResponse, ScheduleRetrieveListResponse, ScheduleUpdateRequest } from './scheduleTypes'; diff --git a/frontend/src/api/schedule/scheduleTypes.ts b/frontend/src/api/schedule/scheduleTypes.ts index 6230cf01..9a08ac1e 100644 --- a/frontend/src/api/schedule/scheduleTypes.ts +++ b/frontend/src/api/schedule/scheduleTypes.ts @@ -1,9 +1,11 @@ -export enum ScheduleStatus { - AVAILABLE = 'AVAILABLE', - HOLD = 'HOLD', - RESERVED = 'RESERVED', - BLOCKED = 'BLOCKED', -} +export type ScheduleStatus = 'AVAILABLE' | 'HOLD' | 'RESERVED' | 'BLOCKED'; + +export const ScheduleStatus = { + AVAILABLE: 'AVAILABLE' as ScheduleStatus, + HOLD: 'HOLD' as ScheduleStatus, + RESERVED: 'RESERVED' as ScheduleStatus, + BLOCKED: 'BLOCKED' as ScheduleStatus, +}; export interface AvailableThemeIdListResponse { themeIds: string[]; diff --git a/frontend/src/api/theme/themeAPI.ts b/frontend/src/api/theme/themeAPI.ts index 1c7566ca..3db475d2 100644 --- a/frontend/src/api/theme/themeAPI.ts +++ b/frontend/src/api/theme/themeAPI.ts @@ -3,29 +3,12 @@ import type { AdminThemeDetailRetrieveResponse, AdminThemeSummaryRetrieveListResponse, ThemeCreateRequest, - ThemeCreateRequestV2, ThemeCreateResponse, - ThemeCreateResponseV2, ThemeListRetrieveRequest, ThemeRetrieveListResponse, - ThemeRetrieveListResponseV2, - ThemeUpdateRequest, - UserThemeRetrieveListResponse + ThemeCreateResponse, + ThemeIdListResponse, + ThemeInfoListResponse, + ThemeUpdateRequest } from './themeTypes'; -export const createTheme = async (data: ThemeCreateRequest): Promise => { - return await apiClient.post('/themes', data, true); -}; - -export const fetchThemes = async (): Promise => { - return await apiClient.get('/themes', true); -}; - -export const mostReservedThemes = async (count: number = 10): Promise => { - return await apiClient.get(`/themes/most-reserved-last-week?count=${count}`, false); -}; - -export const delTheme = async (id: string): Promise => { - return await apiClient.del(`/themes/${id}`, true); -}; - export const fetchAdminThemes = async (): Promise => { return await apiClient.get('/admin/themes'); }; @@ -34,8 +17,8 @@ export const fetchAdminThemeDetail = async (id: string): Promise(`/admin/themes/${id}`); }; -export const createThemeV2 = async (themeData: ThemeCreateRequestV2): Promise => { - return await apiClient.post('/admin/themes', themeData); +export const createTheme = async (themeData: ThemeCreateRequest): Promise => { + return await apiClient.post('/admin/themes', themeData); }; export const updateTheme = async (id: string, themeData: ThemeUpdateRequest): Promise => { @@ -46,10 +29,10 @@ export const deleteTheme = async (id: string): Promise => { await apiClient.del(`/admin/themes/${id}`); }; -export const fetchUserThemes = async (): Promise => { - return await apiClient.get('/v2/themes'); +export const fetchUserThemes = async (): Promise => { + return await apiClient.get('/themes'); }; -export const findThemesByIds = async (request: ThemeListRetrieveRequest): Promise => { - return await apiClient.post('/themes/retrieve', request); +export const findThemesByIds = async (request: ThemeIdListResponse): Promise => { + return await apiClient.post('/themes/retrieve', request); }; diff --git a/frontend/src/api/theme/themeTypes.ts b/frontend/src/api/theme/themeTypes.ts index 7fe1327f..ba28bc0d 100644 --- a/frontend/src/api/theme/themeTypes.ts +++ b/frontend/src/api/theme/themeTypes.ts @@ -1,29 +1,4 @@ -export interface ThemeCreateRequest { - name: string; - description: string; - thumbnail: string; -} - -export interface ThemeCreateResponse { - id: string; - name: string; - description: string; - thumbnail: string; -} - -export interface ThemeRetrieveResponse { - id: string; - name: string; - description: string; - thumbnail: string; -} - -export interface ThemeRetrieveListResponse { - themes: ThemeRetrieveResponse[]; -} - - -export interface ThemeV2 { +export interface AdminThemeDetailResponse { id: string; name: string; description: string; @@ -42,7 +17,7 @@ export interface ThemeV2 { updatedBy: string; } -export interface ThemeCreateRequestV2 { +export interface ThemeCreateRequest { name: string; description: string; thumbnailUrl: string; @@ -56,7 +31,7 @@ export interface ThemeCreateRequestV2 { isOpen: boolean; } -export interface ThemeCreateResponseV2 { +export interface ThemeCreateResponse { id: string; } @@ -105,7 +80,7 @@ export interface AdminThemeDetailRetrieveResponse { updatedBy: string; } -export interface UserThemeRetrieveResponse { +export interface ThemeInfoResponse { id: string; name: string; thumbnailUrl: string; @@ -119,32 +94,14 @@ export interface UserThemeRetrieveResponse { expectedMinutesTo: number; } -export interface UserThemeRetrieveListResponse { - themes: UserThemeRetrieveResponse[]; +export interface ThemeInfoListResponse { + themes: ThemeInfoResponse[]; } -export interface ThemeListRetrieveRequest { +export interface ThemeIdListResponse { themeIds: string[]; } -export interface ThemeRetrieveResponseV2 { - id: string; - name: string; - thumbnailUrl: string; - description: string; - difficulty: Difficulty; - price: number; - minParticipants: number; - maxParticipants: number; - availableMinutes: number; - expectedMinutesFrom: number; - expectedMinutesTo: number; -} - -export interface ThemeRetrieveListResponseV2 { - themes: ThemeRetrieveResponseV2[]; -} - // @ts-ignore export enum Difficulty { VERY_EASY = '매우 쉬움', @@ -154,7 +111,7 @@ export enum Difficulty { VERY_HARD = '매우 어려움', } -export function mapThemeResponse(res: any): UserThemeRetrieveResponse { +export function mapThemeResponse(res: any): ThemeInfoResponse { return { ...res, difficulty: Difficulty[res.difficulty as keyof typeof Difficulty], diff --git a/frontend/src/api/user/userAPI.ts b/frontend/src/api/user/userAPI.ts index 7388f7d7..84a2422d 100644 --- a/frontend/src/api/user/userAPI.ts +++ b/frontend/src/api/user/userAPI.ts @@ -1,5 +1,5 @@ import apiClient from "@_api/apiClient"; -import type { UserContactRetrieveResponse, UserCreateRequest, UserCreateResponse } from "./userTypes"; +import type {UserContactRetrieveResponse, UserCreateRequest, UserCreateResponse} from "./userTypes"; export const signup = async (data: UserCreateRequest): Promise => { return await apiClient.post('/users', data, false); diff --git a/frontend/src/assets/react.svg b/frontend/src/assets/react.svg index 6c87de9b..df634bcc 100644 --- a/frontend/src/assets/react.svg +++ b/frontend/src/assets/react.svg @@ -1 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/frontend/src/components/AdminRoute.tsx b/frontend/src/components/AdminRoute.tsx index e8354014..c238090d 100644 --- a/frontend/src/components/AdminRoute.tsx +++ b/frontend/src/components/AdminRoute.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Navigate, useLocation } from 'react-router-dom'; -import { useAuth } from '../context/AuthContext'; +import {Navigate, useLocation} from 'react-router-dom'; +import {useAuth} from '../context/AuthContext'; const AdminRoute: React.FC<{ children: JSX.Element }> = ({ children }) => { const { loggedIn, role, loading } = useAuth(); diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index e4440f76..5064a970 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -1,4 +1,4 @@ -import React, { type ReactNode } from 'react'; +import React, {type ReactNode} from 'react'; import Navbar from './Navbar'; interface LayoutProps { diff --git a/frontend/src/components/Navbar.tsx b/frontend/src/components/Navbar.tsx index ceff4b6d..8de67e34 100644 --- a/frontend/src/components/Navbar.tsx +++ b/frontend/src/components/Navbar.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Link, useNavigate } from 'react-router-dom'; -import { useAuth } from 'src/context/AuthContext'; +import {Link, useNavigate} from 'react-router-dom'; +import {useAuth} from 'src/context/AuthContext'; import 'src/css/navbar.css'; const Navbar: React.FC = () => { diff --git a/frontend/src/context/AuthContext.tsx b/frontend/src/context/AuthContext.tsx index e7d7868e..e220f436 100644 --- a/frontend/src/context/AuthContext.tsx +++ b/frontend/src/context/AuthContext.tsx @@ -1,6 +1,6 @@ -import { checkLogin as apiCheckLogin, login as apiLogin, logout as apiLogout } from '@_api/auth/authAPI'; -import { PrincipalType, type LoginRequest, type LoginSuccessResponse } from '@_api/auth/authTypes'; -import React, { createContext, useContext, useEffect, useState, type ReactNode } from 'react'; +import {checkLogin as apiCheckLogin, login as apiLogin, logout as apiLogout} from '@_api/auth/authAPI'; +import {type LoginRequest, type LoginSuccessResponse, PrincipalType} from '@_api/auth/authTypes'; +import React, {createContext, type ReactNode, useContext, useEffect, useState} from 'react'; interface AuthContextType { loggedIn: boolean; diff --git a/frontend/src/css/admin-time-page.css b/frontend/src/css/admin-time-page.css deleted file mode 100644 index d9505924..00000000 --- a/frontend/src/css/admin-time-page.css +++ /dev/null @@ -1,120 +0,0 @@ -/* /src/css/admin-time-page.css */ -.admin-time-container { - max-width: 800px; - margin: 40px auto; - padding: 40px; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; - background-color: #f4f6f8; - border-radius: 16px; -} - -.admin-time-container .page-title { - font-size: 32px; - font-weight: 700; - color: #333d4b; - margin-bottom: 30px; - text-align: center; -} - -.section-card { - background-color: #ffffff; - border-radius: 12px; - padding: 24px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); -} - -.table-header { - display: flex; - justify-content: flex-end; - margin-bottom: 20px; -} - -.table-container table { - width: 100%; - border-collapse: collapse; - font-size: 15px; -} - -.table-container th, -.table-container td { - padding: 12px 16px; - text-align: left; - border-bottom: 1px solid #e5e8eb; - vertical-align: middle; -} - -.table-container th { - background-color: #f9fafb; - color: #505a67; - font-weight: 600; -} - -.table-container tr:last-child td { - border-bottom: none; -} - -.table-container tr:hover { - background-color: #f4f6f8; -} - -.form-input { - width: 100%; - padding: 10px 12px; - font-size: 15px; - border: 1px solid #E5E8EB; - border-radius: 8px; - box-sizing: border-box; - transition: border-color 0.2s, box-shadow 0.2s; -} - -.form-input:focus { - outline: none; - border-color: #3182F6; - box-shadow: 0 0 0 3px rgba(49, 130, 246, 0.2); -} - -.btn { - padding: 8px 16px; - font-size: 15px; - font-weight: 600; - border-radius: 8px; - border: none; - cursor: pointer; - transition: background-color 0.2s; -} - -.btn-primary { - background-color: #3182F6; - color: #ffffff; -} - -.btn-primary:hover { - background-color: #1B64DA; -} - -.btn-secondary { - background-color: #F2F4F6; - color: #4E5968; -} - -.btn-secondary:hover { - background-color: #E5E8EB; -} - -.btn-danger { - background-color: #e53e3e; - color: white; -} - -.btn-danger:hover { - background-color: #c53030; -} - -.editing-row td { - padding-top: 20px; - padding-bottom: 20px; -} - -.editing-row .btn { - margin-right: 8px; -} diff --git a/frontend/src/css/admin-waiting-page.css b/frontend/src/css/admin-waiting-page.css deleted file mode 100644 index 4d840945..00000000 --- a/frontend/src/css/admin-waiting-page.css +++ /dev/null @@ -1,81 +0,0 @@ -/* /src/css/admin-waiting-page.css */ -.admin-waiting-container { - max-width: 1200px; - margin: 40px auto; - padding: 40px; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; - background-color: #f4f6f8; - border-radius: 16px; -} - -.admin-waiting-container .page-title { - font-size: 32px; - font-weight: 700; - color: #333d4b; - margin-bottom: 30px; - text-align: center; -} - -.section-card { - background-color: #ffffff; - border-radius: 12px; - padding: 24px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); -} - -.table-container table { - width: 100%; - border-collapse: collapse; - font-size: 15px; -} - -.table-container th, -.table-container td { - padding: 12px 16px; - text-align: left; - border-bottom: 1px solid #e5e8eb; - vertical-align: middle; -} - -.table-container th { - background-color: #f9fafb; - color: #505a67; - font-weight: 600; -} - -.table-container tr:last-child td { - border-bottom: none; -} - -.table-container tr:hover { - background-color: #f4f6f8; -} - -.btn { - padding: 8px 16px; - font-size: 15px; - font-weight: 600; - border-radius: 8px; - border: none; - cursor: pointer; - transition: background-color 0.2s; - margin-right: 8px; -} - -.btn-primary { - background-color: #3182F6; - color: #ffffff; -} - -.btn-primary:hover { - background-color: #1B64DA; -} - -.btn-danger { - background-color: #e53e3e; - color: white; -} - -.btn-danger:hover { - background-color: #c53030; -} diff --git a/frontend/src/css/reservation-v2-1.css b/frontend/src/css/reservation-v2-1.css index 76820556..e8ccbeeb 100644 --- a/frontend/src/css/reservation-v2-1.css +++ b/frontend/src/css/reservation-v2-1.css @@ -327,13 +327,13 @@ } .modal-content { - background-color: #ffffff; - padding: 32px; - border-radius: 16px; - width: 90%; - max-width: 500px; - position: relative; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); + background-color: #ffffff !important; + padding: 32px !important; + border-radius: 16px !important; + width: 90% !important; + max-width: 500px !important; + position: relative !important; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1) !important; } .modal-close-button { diff --git a/frontend/src/css/reservation-v2.css b/frontend/src/css/reservation-v2.css deleted file mode 100644 index f93c3581..00000000 --- a/frontend/src/css/reservation-v2.css +++ /dev/null @@ -1,175 +0,0 @@ -#root .flatpickr-input { - display: none; -} - -#root .modal-backdrop { - position: fixed; - top: 0; - left: 0; - z-index: 1050; - width: 100vw; - height: 100vh; - background-color: rgba(0, 0, 0, 0.5) !important; - display: flex; - justify-content: center; - align-items: center; -} - -#root .modal-dialog { - max-width: 500px; - width: 90%; - margin: 1.75rem auto; -} - -/* Toss-style Modal */ -#root .modal-content { - background-color: #fff !important; - border-radius: 16px; - border: none; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - padding: 1.5rem; - display: flex; - flex-direction: column; - pointer-events: auto; - position: relative; -} - -#root .modal-header { - border-bottom: none; - padding: 0 0 1rem 0; - display: flex; - justify-content: space-between; - align-items: center; -} - -#root .modal-title { - font-size: 1.25rem; - font-weight: 600; -} - -#root .btn-close { - background: transparent; - border: 0; - font-size: 1.5rem; - opacity: 0.5; -} - -#root .modal-body { - padding: 1rem 0; - color: #333; -} - -#root .modal-body p { - margin-bottom: 0.5rem; -} - -#root .modal-footer { - border-top: none; - padding: 1rem 0 0 0; - display: flex; - justify-content: flex-end; - gap: 0.5rem; -} - -/* --- Generic Button Styles --- */ -#root .btn-primary, -#root .modal-footer .btn-primary, -#root .btn-wrapper .btn-primary, -#root .button-group .btn-primary, -#root .success-page-actions .btn-primary { - background-color: #007bff; - border-color: #007bff; - color: #fff; - transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; - padding: 0.75rem 1.5rem; - border-radius: 8px; - text-decoration: none; - font-weight: 500; -} - -#root .btn-secondary, -#root .modal-footer .btn-secondary, -#root .success-page-actions .btn-secondary { - background-color: #f0f2f5; - border-color: #f0f2f5; - color: #333; - padding: 0.75rem 1.5rem; - border-radius: 8px; - text-decoration: none; - font-weight: 500; - transition: background-color 0.15s ease-in-out; -} - -#root .btn-primary:hover, -#root .modal-footer .btn-primary:hover, -#root .btn-wrapper .btn-primary:hover, -#root .button-group .btn-primary:hover, -#root .success-page-actions .btn-primary:hover { - background-color: #0069d9; - border-color: #0062cc; -} - -#root .btn-secondary:hover, -#root .modal-footer .btn-secondary:hover, -#root .success-page-actions .btn-secondary:hover { - background-color: #e2e6ea; -} - - -/* --- Reservation Success Page Styles --- */ -.reservation-success-page { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 3rem 1rem; - text-align: center; - width: 100%; - max-width: 100%; -} - -.reservation-success-page .content-container-title { - font-size: 2rem; - font-weight: 600; - margin-bottom: 1.5rem; - color: #333; -} - -.reservation-info-box { - border: 1px solid #e9ecef; - border-radius: 12px; - padding: 2rem; - background-color: #fff; - min-width: 380px; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); - text-align: left; -} - -.reservation-info-box h3 { - font-size: 1.25rem; - font-weight: 600; - margin-bottom: 1.5rem; - padding-bottom: 1rem; - border-bottom: 1px solid #e9ecef; - text-align: center; -} - -.reservation-info-box .info-item { - font-size: 1.1rem; - margin-bottom: 1rem; - display: flex; - align-items: center; -} - -.reservation-info-box .info-item strong { - font-weight: 500; - color: #495057; - width: 70px; - flex-shrink: 0; -} - -.success-page-actions { - margin-top: 2.5rem; - display: flex; - gap: 1rem; -} diff --git a/frontend/src/css/reservation.css b/frontend/src/css/reservation.css deleted file mode 100644 index de9666b7..00000000 --- a/frontend/src/css/reservation.css +++ /dev/null @@ -1,15 +0,0 @@ -.disabled { - pointer-events: none; - opacity: 0.6; -} - -#theme-slots .theme-slot.active, #time-slots .time-slot.active { - background-color: #0a3711 !important; - color: white; -} - -#time-slots .time-slot.disabled { - background-color: #cccccc; - color: #666666; - cursor: not-allowed; -} diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 2b1afe7d..3493ebf6 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -3,9 +3,8 @@ import ReactDOM from 'react-dom/client'; import App from './App'; import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap/dist/js/bootstrap.bundle.min.js'; -import './css/style.css'; -import './css/reservation.css'; -import './css/toss-style.css'; +import '@_css/style.css'; +import '@_css/toss-style.css'; ReactDOM.createRoot(document.getElementById('root')!).render( diff --git a/frontend/src/pages/HomePage.tsx b/frontend/src/pages/HomePage.tsx index b6381572..a5c22119 100644 --- a/frontend/src/pages/HomePage.tsx +++ b/frontend/src/pages/HomePage.tsx @@ -1,13 +1,13 @@ -import {fetchMostReservedThemeIds} from '@_api/reservation/reservationAPIV2'; +import {fetchMostReservedThemeIds} from '@_api/reservation/reservationAPI'; import '@_css/home-page-v2.css'; import React, {useEffect, useState} from 'react'; import {useNavigate} from 'react-router-dom'; import {findThemesByIds} from '@_api/theme/themeAPI'; -import {type UserThemeRetrieveResponse} from '@_api/theme/themeTypes'; +import {mapThemeResponse, type ThemeInfoResponse} from '@_api/theme/themeTypes'; const HomePage: React.FC = () => { - const [ranking, setRanking] = useState([]); - const [selectedTheme, setSelectedTheme] = useState(null); + const [ranking, setRanking] = useState([]); + const [selectedTheme, setSelectedTheme] = useState(null); const navigate = useNavigate(); useEffect(() => { @@ -26,7 +26,7 @@ const HomePage: React.FC = () => { if (themeIds.length === 0) return; const response = await findThemesByIds({ themeIds: themeIds }); - setRanking(response.themes); + setRanking(response.themes.map(mapThemeResponse)); } catch (err) { console.error('Error fetching ranking:', err); } @@ -35,7 +35,7 @@ const HomePage: React.FC = () => { fetchData(); }, []); - const handleThemeClick = (theme: UserThemeRetrieveResponse) => { + const handleThemeClick = (theme: ThemeInfoResponse) => { setSelectedTheme(theme); }; diff --git a/frontend/src/pages/LoginPage.tsx b/frontend/src/pages/LoginPage.tsx index f4e130a4..db4704d3 100644 --- a/frontend/src/pages/LoginPage.tsx +++ b/frontend/src/pages/LoginPage.tsx @@ -1,6 +1,6 @@ -import React, { useState } from 'react'; -import { useLocation, useNavigate } from 'react-router-dom'; -import { useAuth } from '@_context/AuthContext'; +import React, {useState} from 'react'; +import {useLocation, useNavigate} from 'react-router-dom'; +import {useAuth} from '@_context/AuthContext'; import '@_css/login-page-v2.css'; const LoginPage: React.FC = () => { diff --git a/frontend/src/pages/MyReservationPage.tsx b/frontend/src/pages/MyReservationPage.tsx index 6806e8de..d25d07f8 100644 --- a/frontend/src/pages/MyReservationPage.tsx +++ b/frontend/src/pages/MyReservationPage.tsx @@ -1,8 +1,12 @@ -import { cancelPayment } from '@_api/payment/paymentAPI'; -import type { PaymentRetrieveResponse } from '@_api/payment/PaymentTypes'; -import { cancelReservation, fetchDetailById, fetchSummaryByMember } from '@_api/reservation/reservationAPIV2'; -import { ReservationStatusV2, type ReservationDetail, type ReservationSummaryRetrieveResponse } from '@_api/reservation/reservationTypesV2'; -import React, { useEffect, useState } from 'react'; +import {cancelPayment} from '@_api/payment/paymentAPI'; +import type {PaymentRetrieveResponse} from '@_api/payment/PaymentTypes'; +import {cancelReservation, fetchDetailById, fetchSummaryByMember} from '@_api/reservation/reservationAPI'; +import { + type ReservationDetail, + ReservationStatus, + type ReservationSummaryRetrieveResponse +} from '@_api/reservation/reservationTypes'; +import React, {useEffect, useState} from 'react'; import '@_css/my-reservation-v2.css'; const getReservationStatus = (reservation: ReservationSummaryRetrieveResponse): { className: string, text: string } => { @@ -10,14 +14,14 @@ const getReservationStatus = (reservation: ReservationSummaryRetrieveResponse): const reservationDateTime = new Date(`${reservation.date}T${reservation.startAt}`); switch (reservation.status) { - case ReservationStatusV2.CANCELED: + case ReservationStatus.CANCELED: return { className: 'status-canceled', text: '취소됨' }; - case ReservationStatusV2.CONFIRMED: + case ReservationStatus.CONFIRMED: if (reservationDateTime < now) { return { className: 'status-completed', text: '이용완료' }; } return { className: 'status-confirmed', text: '예약확정' }; - case ReservationStatusV2.PENDING: + case ReservationStatus.PENDING: return { className: 'status-pending', text: '입금대기' }; default: return { className: `status-${reservation.status.toLowerCase()}`, text: reservation.status }; @@ -116,7 +120,7 @@ const CancellationView: React.FC<{

테마: {reservation.themeName}

신청 일시: {formatDisplayDateTime(reservation.applicationDateTime)}

-

결제 금액: {reservation.payment.totalAmount.toLocaleString()}원

+ {reservation.payment &&

결제 금액: {reservation.payment.totalAmount.toLocaleString()}원

}