From 6e99917a344aa1aa4ca1f3ba638e1b795eb3940e Mon Sep 17 00:00:00 2001 From: pricelees Date: Wed, 3 Sep 2025 10:25:16 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=A0=ED=8A=B8=EC=97=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=84=EC=B2=B4=20=EB=94=94=EC=9E=90=EC=9D=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=83=88=EB=A1=9C=EC=9A=B4=20?= =?UTF-8?q?=ED=85=8C=EB=A7=88=20API=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.tsx | 10 + frontend/src/api/apiClient.ts | 14 +- frontend/src/api/theme/themeAPI.ts | 36 ++- frontend/src/api/theme/themeTypes.ts | 110 ++++++++ frontend/src/components/Navbar.tsx | 57 ++-- frontend/src/css/admin-page.css | 17 ++ frontend/src/css/admin-reservation-page.css | 160 +++++++++++ frontend/src/css/admin-theme-edit-page.css | 236 ++++++++++++++++ frontend/src/css/admin-theme-page.css | 121 ++++++++ frontend/src/css/admin-time-page.css | 120 ++++++++ frontend/src/css/admin-waiting-page.css | 81 ++++++ frontend/src/css/home-page-v2.css | 66 +++++ frontend/src/css/login-page-v2.css | 74 +++++ frontend/src/css/navbar.css | 117 ++++++++ frontend/src/css/signup-page-v2.css | 65 +++++ frontend/src/pages/LoginPage.tsx | 4 +- frontend/src/pages/admin/AdminNavbar.tsx | 59 ++-- frontend/src/pages/admin/AdminPage.tsx | 7 +- .../src/pages/admin/AdminThemeEditPage.tsx | 266 ++++++++++++++++++ frontend/src/pages/admin/ReservationPage.tsx | 142 +++++----- frontend/src/pages/admin/ThemePage.tsx | 123 ++++---- frontend/src/pages/admin/TimePage.tsx | 74 ++--- frontend/src/pages/admin/WaitingPage.tsx | 64 +++-- frontend/src/pages/v2/HomePageV2.tsx | 39 +++ frontend/src/pages/v2/LoginPageV2.tsx | 63 +++++ .../src/pages/v2/ReservationStep1PageV21.tsx | 126 +++------ .../src/pages/v2/ReservationStep2PageV21.tsx | 10 +- frontend/src/pages/v2/SignupPageV2.tsx | 70 +++++ src/main/resources/login.http | 55 ++++ 29 files changed, 1993 insertions(+), 393 deletions(-) create mode 100644 frontend/src/css/admin-page.css create mode 100644 frontend/src/css/admin-reservation-page.css create mode 100644 frontend/src/css/admin-theme-edit-page.css create mode 100644 frontend/src/css/admin-theme-page.css create mode 100644 frontend/src/css/admin-time-page.css create mode 100644 frontend/src/css/admin-waiting-page.css create mode 100644 frontend/src/css/home-page-v2.css create mode 100644 frontend/src/css/login-page-v2.css create mode 100644 frontend/src/css/navbar.css create mode 100644 frontend/src/css/signup-page-v2.css create mode 100644 frontend/src/pages/admin/AdminThemeEditPage.tsx create mode 100644 frontend/src/pages/v2/HomePageV2.tsx create mode 100644 frontend/src/pages/v2/LoginPageV2.tsx create mode 100644 frontend/src/pages/v2/SignupPageV2.tsx create mode 100644 src/main/resources/login.http diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 62b831d0..55f77c3e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -20,6 +20,10 @@ import MyReservationPageV2 from './pages/v2/MyReservationPageV2'; import ReservationStep1PageV21 from './pages/v2/ReservationStep1PageV21'; import ReservationStep2PageV21 from './pages/v2/ReservationStep2PageV21'; import ReservationSuccessPageV21 from './pages/v2/ReservationSuccessPageV21'; +import HomePageV2 from './pages/v2/HomePageV2'; +import LoginPageV2 from './pages/v2/LoginPageV2'; +import SignupPageV2 from './pages/v2/SignupPageV2'; +import AdminThemeEditPage from './pages/admin/AdminThemeEditPage'; const AdminRoutes = () => ( @@ -28,6 +32,7 @@ const AdminRoutes = () => ( } /> } /> } /> + } /> } /> @@ -53,6 +58,11 @@ function App() { } /> } /> + {/* V2 Pages */} + } /> + } /> + } /> + {/* V2 Reservation Flow */} } /> } /> diff --git a/frontend/src/api/apiClient.ts b/frontend/src/api/apiClient.ts index 6e488ac3..f72d764c 100644 --- a/frontend/src/api/apiClient.ts +++ b/frontend/src/api/apiClient.ts @@ -28,16 +28,16 @@ async function request( }, }; - if (isRequiredAuth) { - const accessToken = localStorage.getItem('accessToken'); - if (accessToken) { - if (!config.headers) { - config.headers = {}; - } - config.headers['Authorization'] = `Bearer ${accessToken}`; + + const accessToken = localStorage.getItem('accessToken'); + if (accessToken) { + if (!config.headers) { + config.headers = {}; } + config.headers['Authorization'] = `Bearer ${accessToken}`; } + if (method.toUpperCase() !== 'GET') { config.data = data; } diff --git a/frontend/src/api/theme/themeAPI.ts b/frontend/src/api/theme/themeAPI.ts index 6cbe5c3d..b36ca302 100644 --- a/frontend/src/api/theme/themeAPI.ts +++ b/frontend/src/api/theme/themeAPI.ts @@ -1,5 +1,13 @@ -import apiClient from "@_api/apiClient"; -import type { ThemeCreateRequest, ThemeCreateResponse, ThemeRetrieveListResponse } from "./themeTypes"; +import apiClient from '@_api/apiClient'; +import type { + AdminThemeDetailRetrieveResponse, + AdminThemeSummaryRetrieveListResponse, + ThemeCreateRequest, + ThemeCreateRequestV2, ThemeCreateResponse, + ThemeCreateResponseV2, ThemeRetrieveListResponse, + ThemeUpdateRequest, + UserThemeRetrieveListResponse +} from './themeTypes'; export const createTheme = async (data: ThemeCreateRequest): Promise => { return await apiClient.post('/themes', data, true); @@ -16,3 +24,27 @@ export const mostReservedThemes = async (count: number = 10): Promise => { return await apiClient.del(`/themes/${id}`, true); }; + +export const fetchAdminThemes = async (): Promise => { + return await apiClient.get('/admin/themes'); +}; + +export const fetchAdminThemeDetail = async (id: string): Promise => { + return await apiClient.get(`/admin/themes/${id}`); +}; + +export const createThemeV2 = async (themeData: ThemeCreateRequestV2): Promise => { + return await apiClient.post('/admin/themes', themeData); +}; + +export const updateTheme = async (id: string, themeData: ThemeUpdateRequest): Promise => { + await apiClient.patch(`/admin/themes/${id}`, themeData); +}; + +export const deleteTheme = async (id: string): Promise => { + await apiClient.del(`/admin/themes/${id}`); +}; + +export const fetchUserThemes = async (): Promise => { + return await apiClient.get('/v2/themes'); +}; diff --git a/frontend/src/api/theme/themeTypes.ts b/frontend/src/api/theme/themeTypes.ts index 129f1fc1..dd24ed8e 100644 --- a/frontend/src/api/theme/themeTypes.ts +++ b/frontend/src/api/theme/themeTypes.ts @@ -21,3 +21,113 @@ export interface ThemeRetrieveResponse { export interface ThemeRetrieveListResponse { themes: ThemeRetrieveResponse[]; } + + +export interface ThemeV2 { + id: string; + name: string; + description: string; + thumbnailUrl: string; + difficulty: Difficulty; + price: number; + minParticipants: number; + maxParticipants: number; + availableMinutes: number; + expectedMinutesFrom: number; + expectedMinutesTo: number; + isOpen: boolean; + createDate: string; // Assuming ISO string format + updatedDate: string; // Assuming ISO string format + createdBy: string; + updatedBy: string; +} + +export interface ThemeCreateRequestV2 { + name: string; + description: string; + thumbnailUrl: string; + difficulty: Difficulty; + price: number; + minParticipants: number; + maxParticipants: number; + availableMinutes: number; + expectedMinutesFrom: number; + expectedMinutesTo: number; + isOpen: boolean; +} + +export interface ThemeCreateResponseV2 { + id: string; +} + +export interface ThemeUpdateRequest { + name?: string; + description?: string; + thumbnailUrl?: string; + difficulty?: Difficulty; + price?: number; + minParticipants?: number; + maxParticipants?: number; + availableMinutes?: number; + expectedMinutesFrom?: number; + expectedMinutesTo?: number; + isOpen?: boolean; +} + +export interface AdminThemeSummaryRetrieveResponse { + id: string; + name: string; + difficulty: Difficulty; + price: number; + isOpen: boolean; +} + +export interface AdminThemeSummaryRetrieveListResponse { + themes: AdminThemeSummaryRetrieveResponse[]; +} + +export interface AdminThemeDetailRetrieveResponse { + id: string; + name: string; + description: string; + thumbnailUrl: string; + difficulty: Difficulty; + price: number; + minParticipants: number; + maxParticipants: number; + availableMinutes: number; + expectedMinutesFrom: number; + expectedMinutesTo: number; + isOpen: boolean; + createdAt: string; // LocalDateTime in Kotlin, map to string (ISO format) + createdBy: string; + updatedAt: string; // LocalDateTime in Kotlin, map to string (ISO format) + updatedBy: string; +} + +export interface UserThemeRetrieveResponse { + id: string; + name: string; + thumbnailUrl: string; + description: string; + difficulty: Difficulty; + price: number; + minParticipants: number; + maxParticipants: number; + availableMinutes: number; + expectedMinutesFrom: number; + expectedMinutesTo: number; +} + +export interface UserThemeRetrieveListResponse { + themes: UserThemeRetrieveResponse[]; +} + +// @ts-ignore +export enum Difficulty { + VERY_EASY = 'VERY_EASY', + EASY = 'EASY', + NORMAL = 'NORMAL', + HARD = 'HARD', + VERY_HARD = 'VERY_HARD', +} \ No newline at end of file diff --git a/frontend/src/components/Navbar.tsx b/frontend/src/components/Navbar.tsx index 8644022f..82168dba 100644 --- a/frontend/src/components/Navbar.tsx +++ b/frontend/src/components/Navbar.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { useAuth } from 'src/context/AuthContext'; +import 'src/css/navbar.css'; const Navbar: React.FC = () => { const { loggedIn, userName, logout } = useAuth(); @@ -14,42 +15,34 @@ const Navbar: React.FC = () => { } catch (error) { console.error('Logout failed:', error); } - } + }; return ( -