diff --git a/src/api/adapters/store.adapter.ts b/src/api/adapters/store.adapter.ts index 888b174..2102676 100644 --- a/src/api/adapters/store.adapter.ts +++ b/src/api/adapters/store.adapter.ts @@ -1,5 +1,4 @@ -import type { StoreDetailDataDTO } from "@/api/dto/store.dto"; -import type { BreakTime, RestaurantDetail } from "@/types/store"; +import type { BreakTime, RestaurantDetail, StoreDetailDataDTO } from "@/types/store"; export function toRestaurantDetail(dto: StoreDetailDataDTO): RestaurantDetail { const breakTime = toBreakTime(dto.breakStartTime, dto.breakEndTime); diff --git a/src/api/axios.ts b/src/api/axios.ts index 2cfabb6..5606ff9 100644 --- a/src/api/axios.ts +++ b/src/api/axios.ts @@ -1,7 +1,7 @@ import axios, { type AxiosError, type InternalAxiosRequestConfig } from "axios"; import { useAuthStore } from "@/stores/useAuthStore"; -import type { ApiError } from "@/types/api"; +import type { ApiError, ApiResponseWithFlags } from "@/types/api"; import { isApiResponse, normalizeApiError } from "./api.error"; import { clearAuth, postRefresh } from "./auth"; @@ -38,13 +38,6 @@ api.interceptors.request.use((config: InternalAxiosRequestConfig) => { let refreshPromise: ReturnType | null = null; -type ApiResponseWithFlags = { - code?: string; - message?: string; - success?: boolean; - isSuccess?: boolean; -}; - api.interceptors.response.use( (res) => { const data = res.data; diff --git a/src/api/bookings.ts b/src/api/bookings.ts index 024635c..2e5feb7 100644 --- a/src/api/bookings.ts +++ b/src/api/bookings.ts @@ -1,33 +1,6 @@ -import { api } from "./axios"; - -type ApiBookingStatus = "PENDING" | "CONFIRMED" | "COMPLETED" | "CANCELED"; - -interface Booking { - bookingId: number; - storeName: string; - storeAddress: string; - bookingDate: string; - bookingTime: string; - partySize: number; - tableNumbers: string; - amount: number | null; - paymentMethod: string; - status: ApiBookingStatus; -} +import type { ApiBookingStatus, BookingResponse, GetBookingParams } from "@/types/booking"; -interface BookingResponse { - bookingList: Booking[]; - listSize: number; - totalPage: number; - totalElements: number; - isFirst: boolean; - isLast: boolean; -} - -type GetBookingParams = { - page: number; - status?: ApiBookingStatus; -}; +import { api } from "./axios"; export const getBookings = async ( status?: ApiBookingStatus, diff --git a/src/api/dto/store.dto.ts b/src/api/dto/store.dto.ts deleted file mode 100644 index ce40038..0000000 --- a/src/api/dto/store.dto.ts +++ /dev/null @@ -1,37 +0,0 @@ -export type CategoryDTO = "KOREAN" | "CHINESE" | "JAPANESE" | "WESTERN" | "CAFE"; - -export type DayDTO = - | "MONDAY" - | "TUESDAY" - | "WEDNESDAY" - | "THURSDAY" - | "FRIDAY" - | "SATURDAY" - | "SUNDAY"; - -export type BusinessHourDTO = { - day: DayDTO; - openTime: string | null; - closeTime: string | null; - isClosed: boolean; -}; - -export type StoreDetailDataDTO = { - storeId: number | string; - storeName: string; - description: string; - address: string; - phone: string; - category: CategoryDTO; - rating: number; - reviewCount: number | null; - mainImageUrl?: string | null; - tableImageUrls: string[] | null; - businessHours: BusinessHourDTO[] | null; - breakStartTime?: string | null; - breakEndTime?: string | null; - isOpenNow?: boolean; - - depositAmount: number; - depositRate?: number | null; -}; diff --git a/src/api/endpoints/bookings.ts b/src/api/endpoints/bookings.ts index 9619b5b..10f993b 100644 --- a/src/api/endpoints/bookings.ts +++ b/src/api/endpoints/bookings.ts @@ -1,41 +1,9 @@ -import { api } from "../axios"; - -type APiResult = { - isSucceess?: boolean; - success?: boolean; - code?: string; - message?: string; - result: T; -}; +import type { ApiResponse } from "@/types/api"; +import type { UserBookingsResult } from "@/types/booking"; -type BookingListItem = { - bookingId: number; - storeName: string; - storeAddress: string; - bookingDate: string; - bookingTime: { - hour: number; - minute: number; - second: number; - nano: number; - }; - partySize: number; - tableNumbers: string; - amount: number; - paymentMethod: string; - status: string; -}; - -type UserBookingsResult = { - bookingList: BookingListItem[]; - listSize: number; - totalPage: number; - totalElements: number; - isFirst: boolean; - isLast: boolean; -}; +import { api } from "../axios"; export async function getUserBookings(page = 1) { - const res = await api.get>(`/api/v1/users/bookings?page=${page}`); + const res = await api.get>(`/api/v1/users/bookings?page=${page}`); return res.data.result; } diff --git a/src/api/endpoints/member.ts b/src/api/endpoints/member.ts index 07cb053..cb5d337 100644 --- a/src/api/endpoints/member.ts +++ b/src/api/endpoints/member.ts @@ -1,61 +1,41 @@ -import { api } from "../axios"; +import type { ApiResponse } from "@/types/api"; +import type { + ChangePasswordRequest, + ChangePasswordResponse, + MemberInfo, + PatchMemberInfo, +} from "@/types/member"; -type ApiEnvelope = { - isSuccess?: boolean; - success?: boolean; - code?: string; - message?: string; - result: T; -}; +import { api } from "../axios"; -type MemberInfo = { - id: number; - profileImage: string | null; - email: string; - name: string; - phoneNumber: string; -}; export async function getMemberInfo() { - const res = await api.get>("/api/v1/member/info"); + const res = await api.get>("/api/v1/member/info"); if (!res.data.isSuccess || !res.data.result) { throw new Error(res.data.message ?? "회원정보 조회 실패"); } return res.data.result; } -type PatchMemberInfo = { - name: string; - phoneNumber: string; -}; - export async function patchMemberInfo(body: PatchMemberInfo) { - const res = await api.patch>("/api/v1/member/info", body); + const res = await api.patch>("/api/v1/member/info", body); + if (!res.data?.isSuccess) { + throw new Error(res.data?.message ?? "회원정보 수정 실패"); + } return res.data.result; } export async function putProfileImage(file: File) { const formData = new FormData(); formData.append("profileImage", file); - const res = await api.put>("/api/v1/member/profile-image", formData); + const res = await api.put>("/api/v1/member/profile-image", formData); if (!res.data.isSuccess) { throw new Error(res.data.message ?? "프로필 업로드 실패"); } return res.data.result; } -type ChangePasswordRequest = { - currentPassword: string; - newPassword: string; - newPasswordConfirm: string; -}; - -type ChangePasswordResponse = { - change: boolean; - changeAt: string; - message: string; -}; export async function putChangePassword(body: ChangePasswordRequest) { - const res = await api.put>("/api/v1/member/password", body); + const res = await api.put>("/api/v1/member/password", body); if (!res.data?.isSuccess) { throw new Error(res.data.message ?? "비밀번호 변경에 실패했습니다"); } diff --git a/src/api/endpoints/menus.ts b/src/api/endpoints/menus.ts index 39a0184..5d58373 100644 --- a/src/api/endpoints/menus.ts +++ b/src/api/endpoints/menus.ts @@ -1,31 +1,10 @@ -import type { MenuCategory, MenuItem } from "@/types/menus"; +import type { ApiResponse } from "@/types/api"; +import type { MenuCategory, MenuItem, MenuListResult } from "@/types/menus"; import { api } from "../axios"; -type ApiResult = { - isSuccess?: boolean; - success?: boolean; - code?: string; - message?: string; - result: T; -}; - -type MenuDto = { - menuId: number; - name: string; - description?: string; - price: number; - category: MenuCategory | string; - imageUrl?: string; - isSoldOut: boolean; -}; - -type MenuListResult = { - menus: MenuDto[]; -}; - export async function getMenus(storeId: string): Promise { - const { data } = await api.get>(`/api/v1/stores/${storeId}/menus`); + const { data } = await api.get>(`/api/v1/stores/${storeId}/menus`); if (!data?.isSuccess) { throw { status: 0, diff --git a/src/api/endpoints/payments.ts b/src/api/endpoints/payments.ts index 5cb528e..827b32a 100644 --- a/src/api/endpoints/payments.ts +++ b/src/api/endpoints/payments.ts @@ -1,23 +1,10 @@ -import { api } from "../axios"; - -type ApiEnvelope = { - isSuccess?: boolean; - success?: boolean; - code?: string; - message?: string; - result: T; -}; +import type { ApiResponse } from "@/types/api"; +import type { PaymentConfirmResult, PaymentRequestResult } from "@/types/payment"; -type PaymentRequestResult = { - paymentId: number; - bookingId: number; - orderId: string; - amount: number; - requestedAt: string; -}; +import { api } from "../axios"; export async function requestPayment(body: { bookingId: number }) { - const res = await api.post>(`/api/v1/payments/request`, body); + const res = await api.post>(`/api/v1/payments/request`, body); if (!res.data?.isSuccess) { throw { status: 0, @@ -28,23 +15,12 @@ export async function requestPayment(body: { bookingId: number }) { return res.data.result; } -type PaymentConfirmResult = { - paymentId: number; - status: string; - approvedAt: string; - orderId: string; - amount: number; - paymentMethod: string; - paymentProvider: string; - receiptUrl: string; -}; - export async function confirmPayment(body: { paymentKey: string; orderId: string; amount: number; }) { - const res = await api.post>("/api/v1/payments/confirm", body); + const res = await api.post>("/api/v1/payments/confirm", body); if (!res.data?.isSuccess) { throw new Error(res.data?.message ?? "결제 승인에 실패했습니다."); } diff --git a/src/api/endpoints/reservations.ts b/src/api/endpoints/reservations.ts index 9ce56c4..23a6b53 100644 --- a/src/api/endpoints/reservations.ts +++ b/src/api/endpoints/reservations.ts @@ -1,27 +1,19 @@ -import { api } from "../axios"; - -type ApiResult = { - isSuccess: boolean; - code: string; - message: string; - result: T; -}; - -type GetAvailableTimesParams = { - storeId: string | number; - date: string; - partySize: number; - isSplitAccepted: boolean; -}; +import type { ApiResponse } from "@/types/api"; +import type { + AvailableTablesResult, + AvailableTimesResult, + CreateBookingBody, + CreateBookingResult, + GetAvailableTablesParams, + GetAvailableTimesParams, +} from "@/types/reservation"; -type AvailableTimesResult = { - availableTimes: string[]; -}; +import { api } from "../axios"; export async function getAvailableTimes(params: GetAvailableTimesParams): Promise { const { storeId, ...query } = params; - const { data } = await api.get>( + const { data } = await api.get>( `/api/v1/stores/${storeId}/bookings/available-times`, { params: query }, ); @@ -36,36 +28,9 @@ export async function getAvailableTimes(params: GetAvailableTimesParams): Promis return data.result?.availableTimes ?? []; } -type SeatsTypes = "WINDOW" | "GENERAL" | string; - -type AvailableTable = { - tableId: number; - tableNumber: string; - tableSeats: number; - seatsType: SeatsTypes; - gridX: number; - gridY: number; - widthSpan: number; - heightSpan: number; -}; -export type GetAvailableTablesParams = { - storeId: string | number; - date: string; - time: string; - partySize: number; - isSplitAccepted: boolean; - seatsType?: string; -}; - -type AvailableTablesResult = { - rows: number; - cols: number; - tables: AvailableTable[]; -}; - export async function getAvailableTables(params: GetAvailableTablesParams) { const { storeId, ...query } = params; - const { data } = await api.get>( + const { data } = await api.get>( `/api/v1/stores/${storeId}/bookings/available-tables`, { params: query }, ); @@ -80,33 +45,12 @@ export async function getAvailableTables(params: GetAvailableTablesParams) { return data.result; } -type CreateBookingBody = { - date: string; - time: string; - partySize: number; - tableIds: number[]; - menuItems: { menuId: number; quantity: number }[]; - isSplitAccepted: boolean; -}; - -export type CreateBookingResult = { - bookingId: number; - status: "PENDING" | "CONFIRMED" | string; - storeName: string; - date: string; - time: string; - partySize: number; - totalDeposit: number; - paymentId?: number; - orderId: string; -}; - export async function createBooking(params: { storeId: string | number; body: CreateBookingBody; }): Promise { const { storeId, body } = params; - const { data } = await api.post>( + const { data } = await api.post>( `/api/v1/stores/${storeId}/bookings`, body, ); diff --git a/src/api/inquiry.ts b/src/api/inquiry.ts index 36c2a08..a09db77 100644 --- a/src/api/inquiry.ts +++ b/src/api/inquiry.ts @@ -1,8 +1,6 @@ -import type { - ResponseInquiryDTO, - SupportFormValues, -} from "@/components/customer-support/support.schema"; +import type { SupportFormValues } from "@/components/customer-support/support.schema"; import type { ApiResponse } from "@/types/api"; +import type { ResponseInquiryDTO } from "@/types/inquiry"; import { api } from "./axios"; diff --git a/src/api/owner/menus.ts b/src/api/owner/menus.ts index c00637e..f89661b 100644 --- a/src/api/owner/menus.ts +++ b/src/api/owner/menus.ts @@ -1,67 +1,17 @@ import axios from "axios"; import type { ApiResponse } from "@/types/api"; +import type { + DeleteMenusResponse, + GetMenusResult, + MenuCreateItem, + MenuCreateResult, + MenuUpdateItem, + MenuUpdateResult, +} from "@/types/menus"; import { api } from "../axios"; -interface ServerMenu { - menuId: number; - name: string; - description?: string | null; - price: number; - category?: string | null; - imageUrl?: string | null; - isSoldOut?: boolean; -} - -interface GetMenusResult { - menus: ServerMenu[]; -} - -export interface MenuUpdateItem { - name: string; - description?: string; - price: number; - category: string; - imageKey?: string; -} - -interface MenuUpdateResult { - menuId: number; - name: string; - description?: string; - price: number; - category?: string; - imageUrl?: string; -} - -interface MenuCreateItem { - name: string; - description?: string; - price: number; - category: string; - imageKey?: string; -} - -interface MenuCreateResult { - menus: { - menuId: number; - name: string; - description?: string; - price: number; - category?: string; - imageUrl?: string; - imageKey?: string; - }[]; -} - -interface DeleteMenusResponse { - isSuccess: boolean; - code: string; - result: { deletedMenuIds: number[] }; - message: string; -} - export async function getMenus(storeId: string | number) { const res = await api.get>(`/api/v1/stores/${storeId}/menus`); return res.data; diff --git a/src/api/owner/reservation.ts b/src/api/owner/reservation.ts index f050b7d..459378f 100644 --- a/src/api/owner/reservation.ts +++ b/src/api/owner/reservation.ts @@ -1,43 +1,14 @@ import type { ApiResponse } from "@/types/api"; +import type { + BookingDetailResult, + GetSlotsResult, + PatchBreakTimeRequest, + UpdateSlotRequest, + UpdateSlotResult, +} from "@/types/reservation"; import { api } from "../axios"; -export interface Slot { - time: string; - status: "AVAILABLE" | "BOOKED" | "BLOCKED"; - isAvailable: boolean; - bookingId: number | null; -} - -interface GetSlotsResult { - slots: Slot[]; -} - -export type SlotStatus = "AVAILABLE" | "BLOCKED"; - -export interface UpdateSlotRequest { - targetDate: string; - startTime: string; - status: SlotStatus; -} - -interface UpdateSlotResult { - targetDate: string; - startTime: string; - status: SlotStatus; -} - -interface PatchBreakTimeRequest { - breakStartTime: string; - breakEndTime: string; -} - -interface BookingDetailResult { - bookerName: string; - partySize: number; - amount: number; -} - export const getTableSlots = (storeId: number, tableId: number, date: string) => api.get>(`/api/v1/stores/${storeId}/tables/${tableId}/slots`, { params: { date }, diff --git a/src/api/owner/storeLayout.ts b/src/api/owner/storeLayout.ts index cae1d9e..ee1c760 100644 --- a/src/api/owner/storeLayout.ts +++ b/src/api/owner/storeLayout.ts @@ -1,49 +1,10 @@ import axios from "axios"; import type { ApiResponse } from "@/types/api"; -import type { SeatsType } from "@/types/table"; +import type { CreateTableRequest, CreateTableResponse, LayoutResponse } from "@/types/layout"; import { api } from "../axios"; -export interface LayoutTable { - tableId: number; - tableNumber: string; - minSeatCount: number; - maxSeatCount: number; - gridX: number; - gridY: number; - widthSpan: number; - heightSpan: number; - tableImageUrl: string | null; - seatsType: SeatsType; -} - -interface LayoutResponse { - layoutId: number; - totalTableCount: number; - gridInfo: { gridCol: number; gridRow: number }; - tables: LayoutTable[]; -} - -export interface CreateTableRequest { - gridX: number; - gridY: number; - minSeatCount: number; - maxSeatCount: number; - seatsType: SeatsType; -} - -interface CreateTableResponse { - tableId: number; - tableNumber: string; - minSeatCount: number; - maxSeatCount: number; - seatsType: string; - gridX: number; - gridY: number; - tableImageUrl: string | null; -} - export const getActiveLayout = async (storeId: number): Promise => { try { const res = await api.get(`/api/v1/stores/${storeId}/layouts`); diff --git a/src/api/owner/stores.ts b/src/api/owner/stores.ts index 4d8c6df..68f0cef 100644 --- a/src/api/owner/stores.ts +++ b/src/api/owner/stores.ts @@ -1,56 +1,14 @@ import { api } from "@/api/axios"; import type { ApiResponse } from "@/types/api"; -import type { UpdateStoreResponse } from "@/types/store"; - -interface StoreDetail { - storeId: number; - storeName: string; - description: string; - address: string; - phone: string; - businessHours?: BusinessHour[]; - isApproved: boolean; - rating?: number; - reviewCount?: number; -} - -interface BusinessHour { - day: "MONDAY" | "TUESDAY" | "WEDNESDAY" | "THURSDAY" | "FRIDAY" | "SATURDAY" | "SUNDAY"; - openTime: string | null; - closeTime: string | null; - isClosed: boolean; -} - -export interface MyStore { - storeId: number; - storeName: string; - address: string; - category: string; - rating: number; - totalBookingCount: number; - reviewCount: number; - mainImageUrl: string; - isOpenNow: boolean; -} - -interface MyStoreResponse { - isSuccess: boolean; - code: string; - message: string; - result: { - stores: MyStore[]; - }; -} - -export interface TableImage { - tableImageId: number; - tableImageUrl: string; -} - -interface TableImagesResponse { - storeId: number; - tableImages: TableImage[]; -} +import type { + BusinessHour, + MyStore, + MyStoreResponse, + StoreDetail, + TableImage, + TableImagesResponse, + UpdateStoreResponse, +} from "@/types/store"; export function getStore(storeId: number | string) { return api.get>(`/api/v1/stores/${storeId}`); diff --git a/src/api/owner/table.ts b/src/api/owner/table.ts index 2cec825..602f2b0 100644 --- a/src/api/owner/table.ts +++ b/src/api/owner/table.ts @@ -1,33 +1,15 @@ import type { AxiosProgressEvent } from "axios"; import type { ApiResponse } from "@/types/api"; +import type { + DeleteTableImageResult, + PatchTableRequest, + UpdatedTable, + UploadTableImageResult, +} from "@/types/table"; import { api } from "../axios"; -interface UploadTableImageResult { - tableId: number; - tableImageUrl: string; -} - -interface DeleteTableImageResult { - tableId: number; -} - -export interface PatchTableRequest { - tableNumber?: string; - minSeatCount?: number; - maxSeatCount?: number; - seatsType?: "GENERAL" | "WINDOW" | "ROOM" | "BAR" | "OUTDOOR"; -} - -export interface UpdatedTable { - tableId: number; - tableNumber: string; - minSeatCount: number; - maxSeatCount: number; - seatsType: string; -} - export const uploadTableImage = ( storeId: number, tableId: number, diff --git a/src/components/customer-support/support.schema.ts b/src/components/customer-support/support.schema.ts index 51f8155..e17ccfa 100644 --- a/src/components/customer-support/support.schema.ts +++ b/src/components/customer-support/support.schema.ts @@ -25,8 +25,3 @@ export const supportSchema = z.object({ }); export type SupportFormValues = z.infer; - -export interface ResponseInquiryDTO { - id: number; - createdAt: string; -} diff --git a/src/components/main/FeatureCard.tsx b/src/components/main/FeatureCard.tsx index ec4e7f3..415a8fd 100644 --- a/src/components/main/FeatureCard.tsx +++ b/src/components/main/FeatureCard.tsx @@ -1,13 +1,13 @@ import type { ReactNode } from "react"; -type Props = { +interface Props { title: string; desc: string; icon: ReactNode; iconBg: string; className?: string; style?: React.CSSProperties; -}; +} export default function FeatureCard({ title, desc, icon, iconBg, className, style }: Props) { return ( diff --git a/src/components/main/Header.tsx b/src/components/main/Header.tsx index b1cc564..0184f5d 100644 --- a/src/components/main/Header.tsx +++ b/src/components/main/Header.tsx @@ -10,10 +10,10 @@ import { LoginDialog } from "../auth/LoginDialog"; import { SignupDialog } from "../auth/SignupDialog"; import { Button } from "../ui/button"; -type NavItem = { +interface NavItem { label: string; href: string; -}; +} export default function Header() { const [scrolled, setScrolled] = useState(false); diff --git a/src/components/map/KakaoMap.tsx b/src/components/map/KakaoMap.tsx index 88df73e..6690476 100644 --- a/src/components/map/KakaoMap.tsx +++ b/src/components/map/KakaoMap.tsx @@ -10,7 +10,7 @@ import type { } from "@/types/map"; import type { RestaurantSummary } from "@/types/store"; -type Props = { +interface Props { center: LatLng; markers: RestaurantSummary[]; selectedId?: number | null; @@ -18,7 +18,7 @@ type Props = { className?: string; defaultLevel?: number; selectedLevel?: number; -}; +} const toNum = (v: unknown) => { const n = typeof v === "string" ? parseFloat(v) : Number(v); return Number.isFinite(n) ? n : null; diff --git a/src/components/owner/AddTableModal.tsx b/src/components/owner/AddTableModal.tsx index da1ac8e..69453e4 100644 --- a/src/components/owner/AddTableModal.tsx +++ b/src/components/owner/AddTableModal.tsx @@ -1,7 +1,7 @@ import { Check, X } from "lucide-react"; import React, { useEffect, useRef, useState } from "react"; -import type { CreateTableRequest } from "@/api/owner/storeLayout"; +import type { CreateTableRequest } from "@/types/layout"; import type { SeatsType } from "@/types/table"; interface AddTableModalProps { diff --git a/src/components/owner/BreakTimeModal.tsx b/src/components/owner/BreakTimeModal.tsx index 8ddf6fa..504c5b2 100644 --- a/src/components/owner/BreakTimeModal.tsx +++ b/src/components/owner/BreakTimeModal.tsx @@ -1,10 +1,7 @@ import { Clock, X } from "lucide-react"; import React, { useState } from "react"; -export interface BreakTime { - start: string; - end: string; -} +import type { BreakTime } from "@/types/store"; interface Props { openTime: string; diff --git a/src/components/owner/MenuManagement.tsx b/src/components/owner/MenuManagement.tsx index b33810f..fd6ec94 100644 --- a/src/components/owner/MenuManagement.tsx +++ b/src/components/owner/MenuManagement.tsx @@ -15,7 +15,7 @@ interface Category { label: string; } -type ServerMenu = { +interface MenuDraft { menuId?: number | string; name?: string; description?: string; @@ -25,7 +25,7 @@ type ServerMenu = { imageKey?: string; isSoldOut?: boolean; isActive?: boolean; -}; +} type CategoryType = "ALL" | MenuCategory; @@ -48,7 +48,7 @@ const MenuManagement: React.FC = ({ storeId }) => { const [isModalOpen, setIsModalOpen] = useState(false); const [editingMenu, setEditingMenu] = useState(null); - const mapServerToLocal = (s: ServerMenu, restaurantId?: string): MenuItem => ({ + const mapServerToLocal = (s: MenuDraft, restaurantId?: string): MenuItem => ({ id: String(s.menuId ?? `MENU_${crypto.randomUUID()}`), restaurantId: restaurantId ?? "", name: s.name ?? "", @@ -86,7 +86,7 @@ const MenuManagement: React.FC = ({ storeId }) => { try { const res = await getMenus(restaurantId); if (res.isSuccess && res.result && Array.isArray(res.result.menus)) { - const serverMenus = (res.result.menus as ServerMenu[]).map((menu) => + const serverMenus = (res.result.menus as MenuDraft[]).map((menu) => mapServerToLocal(menu, restaurantId), ); diff --git a/src/components/owner/StoreSettings.tsx b/src/components/owner/StoreSettings.tsx index 274b8dc..908ea76 100644 --- a/src/components/owner/StoreSettings.tsx +++ b/src/components/owner/StoreSettings.tsx @@ -5,12 +5,11 @@ import { deleteTableImages, getStore, getTableImages, - type TableImage, updateBusinessHours, updateStore, uploadTableImages, } from "@/api/owner/stores"; -import type { Day } from "@/types/store"; +import type { Day, TableImage } from "@/types/store"; interface StoreSettingsProps { storeId?: string; diff --git a/src/components/owner/menuFormModal.tsx b/src/components/owner/menuFormModal.tsx index 9982c7d..dd4b5bb 100644 --- a/src/components/owner/menuFormModal.tsx +++ b/src/components/owner/menuFormModal.tsx @@ -1,14 +1,8 @@ import { X } from "lucide-react"; import React, { useEffect, useState } from "react"; -import { - createMenus, - deleteMenuImage, - type MenuUpdateItem, - updateMenu, - uploadMenuImage, -} from "@/api/owner/menus"; -import type { MenuCategory, MenuItem } from "@/types/menus"; +import { createMenus, deleteMenuImage, updateMenu, uploadMenuImage } from "@/api/owner/menus"; +import type { MenuCategory, MenuItem, MenuUpdateItem } from "@/types/menus"; interface MenuFormModalProps { isOpen: boolean; diff --git a/src/components/owner/tableDashboard.tsx b/src/components/owner/tableDashboard.tsx index dce9772..c14ff97 100644 --- a/src/components/owner/tableDashboard.tsx +++ b/src/components/owner/tableDashboard.tsx @@ -3,20 +3,20 @@ import { Check, Clock, Lightbulb, Pencil, Plus, Store, X } from "lucide-react"; import React, { useEffect, useState } from "react"; import { patchBreakTime } from "@/api/owner/reservation"; +import { createLayout, createTable, deleteTable, getActiveLayout } from "@/api/owner/storeLayout"; +import { patchTableInfo } from "@/api/owner/table"; +import type { CreateTableRequest, LayoutTable } from "@/types/layout"; +import type { BreakTime } from "@/types/store"; import { - createLayout, - createTable, - type CreateTableRequest, - deleteTable, - getActiveLayout, - type LayoutTable, -} from "@/api/owner/storeLayout"; -import { patchTableInfo, type PatchTableRequest, type UpdatedTable } from "@/api/owner/table"; -import { SEATS_TYPE_LABEL, type SeatsType } from "@/types/table"; + type PatchTableRequest, + SEATS_TYPE_LABEL, + type SeatsType, + type UpdatedTable, +} from "@/types/table"; import { getErrorMessage } from "@/utils/error"; import AddTableModal from "./AddTableModal"; -import BreakTimeModal, { type BreakTime } from "./BreakTimeModal"; +import BreakTimeModal from "./BreakTimeModal"; import TableCreateModal from "./TableCreateModal"; import TableDetailModal from "./tableDetailModal"; @@ -241,7 +241,7 @@ const TableDashboard: React.FC = ({ storeId, storeName }) = })), ); - setTableData(mapTablesFromApi(layout.tables, layout.gridInfo.gridCol, tableData)); + setTableData((prev) => mapTablesFromApi(layout.tables, layout.gridInfo.gridCol, prev)); setCreateModalOpen(false); } else { setCreateModalOpen(true); @@ -253,7 +253,8 @@ const TableDashboard: React.FC = ({ storeId, storeName }) = }; fetchLayout(); - }, [storeId, tableData]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [storeId]); const handleCreateLayout = async (columns: number, rows: number) => { if (!storeId) return; diff --git a/src/components/owner/tableDetailModal.tsx b/src/components/owner/tableDetailModal.tsx index 80ba7b5..c49ec0b 100644 --- a/src/components/owner/tableDetailModal.tsx +++ b/src/components/owner/tableDetailModal.tsx @@ -15,7 +15,6 @@ import { } from "lucide-react"; import React, { useEffect, useState } from "react"; -import type { Slot, SlotStatus, UpdateSlotRequest } from "@/api/owner/reservation"; import { cancelBookingByOwner, getBookingDetail, @@ -23,11 +22,11 @@ import { updateTableSlotStatus, } from "@/api/owner/reservation"; import { deleteTableImage, patchTableInfo, uploadTableImage } from "@/api/owner/table"; +import type { BookingDetailResult, Slot, SlotStatus, UpdateSlotRequest } from "@/types/reservation"; +import type { BreakTime } from "@/types/store"; import { SEATS_TYPE_LABEL, type SeatsType } from "@/types/table"; import { getErrorMessage } from "@/utils/error"; -import type { BreakTime } from "./BreakTimeModal"; - interface TableInfo { minCapacity: number; maxCapacity: number; @@ -52,12 +51,6 @@ interface Props { type Step = "DETAIL" | "CALENDAR" | "SLOTS"; -type BookingDetail = { - bookerName: string; - partySize: number; - amount: number; -}; - const TableDetailModal: React.FC = ({ storeId, tableNumber, @@ -82,7 +75,7 @@ const TableDetailModal: React.FC = ({ const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - const [bookingDetail, setBookingDetail] = useState(null); + const [bookingDetail, setBookingDetail] = useState(null); const [detailLoading, setDetailLoading] = useState(false); const [showBookingDetail, setShowBookingDetail] = useState(false); const [detailError, setDetailError] = useState(null); diff --git a/src/components/reservation/modals/PaymentModal.tsx b/src/components/reservation/modals/PaymentModal.tsx index 821a7a2..8ee2224 100644 --- a/src/components/reservation/modals/PaymentModal.tsx +++ b/src/components/reservation/modals/PaymentModal.tsx @@ -4,13 +4,13 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { useNavigate } from "react-router-dom"; import { requestPayment } from "@/api/endpoints/payments"; -import type { CreateBookingResult } from "@/api/endpoints/reservations"; import { useConfirmClose } from "@/hooks/common/useConfirmClose"; import { useModalPresence } from "@/hooks/common/useModalPresence"; import { useDepositRate } from "@/hooks/reservation/useDepositRate"; import { useMenus } from "@/hooks/reservation/useMenus"; import { cn } from "@/lib/utils"; import { useUserId } from "@/stores/useAuthStore"; +import type { CreateBookingResult } from "@/types/reservation"; import type { ReservationDraft } from "@/types/restaurant"; import type { RestaurantDetail } from "@/types/store"; import { calcMenuTotal } from "@/utils/menu"; @@ -19,7 +19,7 @@ import { formatKrw } from "@/utils/money"; import { Button } from "../../ui/button"; -type Props = { +interface Props { open: boolean; onClose: () => void; onOpenChange: (open: boolean) => void; @@ -27,7 +27,7 @@ type Props = { restaurant: RestaurantDetail; draft: ReservationDraft; booking: CreateBookingResult | null; -}; +} type TossPaymentsInstance = Awaited>; type TossWidgetsInstance = ReturnType; diff --git a/src/components/reservation/modals/ReservationCompleteModal.tsx b/src/components/reservation/modals/ReservationCompleteModal.tsx index f62522a..dc1c613 100644 --- a/src/components/reservation/modals/ReservationCompleteModal.tsx +++ b/src/components/reservation/modals/ReservationCompleteModal.tsx @@ -9,13 +9,13 @@ import { toYmd } from "@/utils/date"; import { backdropMotionClass, panelMotionClass } from "@/utils/modalMotion"; import { toHHmm } from "@/utils/time"; -type Props = { +interface Props { open: boolean; restaurant: Pick; draft: Pick; onClose: () => void; autoCloseMs?: number; -}; +} export default function ReservationCompleteModal({ open, diff --git a/src/components/reservation/modals/ReservationConfirmModal.tsx b/src/components/reservation/modals/ReservationConfirmModal.tsx index 14610cc..51cdb8e 100644 --- a/src/components/reservation/modals/ReservationConfirmModal.tsx +++ b/src/components/reservation/modals/ReservationConfirmModal.tsx @@ -1,12 +1,12 @@ import { X } from "lucide-react"; -import type { CreateBookingResult } from "@/api/endpoints/reservations.ts"; import { useConfirmClose } from "@/hooks/common/useConfirmClose"; import { useModalPresence } from "@/hooks/common/useModalPresence"; import { useCreateBooking } from "@/hooks/reservation/useCreateBooking"; import { useDepositRate } from "@/hooks/reservation/useDepositRate"; import { useMenus } from "@/hooks/reservation/useMenus"; import { cn } from "@/lib/utils"; +import type { CreateBookingResult } from "@/types/reservation"; import type { ReservationDraft } from "@/types/restaurant"; import type { RestaurantDetail } from "@/types/store"; import { toYmd } from "@/utils/date"; @@ -18,7 +18,7 @@ import { formatKrw } from "@/utils/money"; import { calcDeposit } from "@/utils/payment"; import { tablePrefLabel } from "@/utils/reservation"; -type Props = { +interface Props { open: boolean; onClose: () => void; onBack: () => void; @@ -26,7 +26,7 @@ type Props = { restaurant: RestaurantDetail; draft: ReservationDraft; booking: CreateBookingResult | null; -}; +} export default function ReservationConfirmModal({ open, diff --git a/src/components/reservation/modals/ReservationMenuModal.tsx b/src/components/reservation/modals/ReservationMenuModal.tsx index b3bb0df..730c2f6 100644 --- a/src/components/reservation/modals/ReservationMenuModal.tsx +++ b/src/components/reservation/modals/ReservationMenuModal.tsx @@ -22,14 +22,14 @@ import { calcDeposit } from "@/utils/payment"; import { Button } from "../../ui/button"; -type Props = { +interface Props { open: boolean; restaurant: RestaurantDetail; onConfirm: (draft: ReservationDraft) => void; onBack: () => void; onClose: () => void; draft: ReservationDraft; -}; +} export default function ReservationMenuModal({ open, diff --git a/src/components/reservation/modals/ReservationModal.tsx b/src/components/reservation/modals/ReservationModal.tsx index 8387850..d2865a7 100644 --- a/src/components/reservation/modals/ReservationModal.tsx +++ b/src/components/reservation/modals/ReservationModal.tsx @@ -24,13 +24,13 @@ import { Calendar } from "../../ui/calendar"; import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover"; import TableMap from "../parts/TableMap"; -type Props = { +interface Props { open: boolean; restaurant: RestaurantDetail; initialDraft?: ReservationDraft; onClickConfirm: (draft: ReservationDraft) => void; onClose: () => void; -}; +} const PEOPLE = [1, 2, 3, 4, 5, 6, 7, 8]; diff --git a/src/components/reservation/parts/TableMap.tsx b/src/components/reservation/parts/TableMap.tsx index a339625..3d46287 100644 --- a/src/components/reservation/parts/TableMap.tsx +++ b/src/components/reservation/parts/TableMap.tsx @@ -1,14 +1,14 @@ import { cn } from "@/lib/utils"; import type { SeatLayout, SeatTable, SeatType } from "@/types/restaurant"; -type Props = { +interface Props { layout: SeatLayout; availableIds: Set; selectedTableId: number | null; seatType: SeatType | null; onSelectTable: (tableId: number) => void; onSelectSeatType: (seatType: SeatType) => void; -}; +} export default function TableMap({ layout, diff --git a/src/components/restaurant/RestaurantCard.tsx b/src/components/restaurant/RestaurantCard.tsx index bb3d4ba..e5bd7e5 100644 --- a/src/components/restaurant/RestaurantCard.tsx +++ b/src/components/restaurant/RestaurantCard.tsx @@ -1,9 +1,9 @@ import { type RestaurantSummary, storeCategoryLabel } from "@/types/store"; -type Props = { +interface Props { restaurant: RestaurantSummary; onClick: () => void; -}; +} export default function RestaurantCard({ restaurant, onClick }: Props) { return ( diff --git a/src/components/restaurant/RestaurantDetailModal.tsx b/src/components/restaurant/RestaurantDetailModal.tsx index b84a90d..b79b9c3 100644 --- a/src/components/restaurant/RestaurantDetailModal.tsx +++ b/src/components/restaurant/RestaurantDetailModal.tsx @@ -9,7 +9,7 @@ import { backdropMotionClass, panelMotionClass } from "@/utils/modalMotion"; import { Button } from "../ui/button"; -type Props = { +interface Props { open: boolean; onOpenChange: (open: boolean) => void; status: "idle" | "loading" | "success" | "error"; @@ -17,7 +17,7 @@ type Props = { errorMessage?: string; onRetry?: () => void; onClickReserve: () => void; -}; +} const DAY_LABEL: Record = { MONDAY: "월", diff --git a/src/components/restaurant/RestaurantList.tsx b/src/components/restaurant/RestaurantList.tsx index 09d93d1..473cce5 100644 --- a/src/components/restaurant/RestaurantList.tsx +++ b/src/components/restaurant/RestaurantList.tsx @@ -2,10 +2,10 @@ import type { RestaurantSummary } from "@/types/store"; import RestaurantCard from "./RestaurantCard"; -type Props = { +interface Props { restaurants: RestaurantSummary[]; onSelect: (restaurant: RestaurantSummary) => void; -}; +} export default function RestaurantList({ restaurants, onSelect }: Props) { return ( diff --git a/src/hooks/common/useInView.ts b/src/hooks/common/useInView.ts index e2a971d..8923b24 100644 --- a/src/hooks/common/useInView.ts +++ b/src/hooks/common/useInView.ts @@ -1,10 +1,10 @@ import { useEffect, useRef, useState } from "react"; -type Options = { +interface Options { threshold?: number | number[]; rootMargin?: string; once?: boolean; -}; +} export function useInView({ threshold = 0.3, diff --git a/src/hooks/reservation/useAvailableTables.ts b/src/hooks/reservation/useAvailableTables.ts index 36d263a..8853fc7 100644 --- a/src/hooks/reservation/useAvailableTables.ts +++ b/src/hooks/reservation/useAvailableTables.ts @@ -1,7 +1,8 @@ import { useQuery } from "@tanstack/react-query"; -import { getAvailableTables, type GetAvailableTablesParams } from "@/api/endpoints/reservations"; +import { getAvailableTables } from "@/api/endpoints/reservations"; import { queryKeys } from "@/query/keys"; +import type { GetAvailableTablesParams } from "@/types/reservation"; export function useAvailableTables(params: GetAvailableTablesParams | null) { return useQuery({ diff --git a/src/hooks/reservation/useAvailableTimes.ts b/src/hooks/reservation/useAvailableTimes.ts index f0f18da..0e023dd 100644 --- a/src/hooks/reservation/useAvailableTimes.ts +++ b/src/hooks/reservation/useAvailableTimes.ts @@ -3,12 +3,12 @@ import { useQuery } from "@tanstack/react-query"; import { getAvailableTimes } from "@/api/endpoints/reservations"; import { queryKeys } from "@/query/keys"; -type AvailableTimesInput = { +interface AvailableTimesInput { storeId?: string | number; date?: string; partySize?: number; isSplitAccepted?: boolean; -}; +} export function useAvailableTimes(input: AvailableTimesInput) { const { storeId, date, partySize, isSplitAccepted } = input; diff --git a/src/hooks/store/useRestaurantDetail.ts b/src/hooks/store/useRestaurantDetail.ts index 22dda3b..acc14f4 100644 --- a/src/hooks/store/useRestaurantDetail.ts +++ b/src/hooks/store/useRestaurantDetail.ts @@ -2,8 +2,8 @@ import { useQuery } from "@tanstack/react-query"; import { toRestaurantDetail } from "@/api/adapters/store.adapter"; import { api } from "@/api/axios"; -import type { StoreDetailDataDTO } from "@/api/dto/store.dto"; import { queryKeys } from "@/query/keys"; +import type { StoreDetailDataDTO } from "@/types/store"; export function useRestaurantDetail(storeId: number | null) { return useQuery({ diff --git a/src/hooks/store/useSearchStores.ts b/src/hooks/store/useSearchStores.ts index 47431c3..7c6a779 100644 --- a/src/hooks/store/useSearchStores.ts +++ b/src/hooks/store/useSearchStores.ts @@ -1,53 +1,13 @@ import { useQuery } from "@tanstack/react-query"; import { api } from "@/api/axios"; -import type { Category, RestaurantSummary } from "@/types/store"; - -type Params = { - keyword: string; - lat: number; - lng: number; - radius?: number; - category?: "KOREAN" | "CHINESE" | "JAPANESE" | "WESTERN" | "CAFE"; - sort?: "DISTANCE" | "RATING"; - page?: number; - limit?: number; - sido?: string; - sigungu?: string; - bname?: string; -}; - -type ApiStoreSummary = { - storeId: number; - name: string; - address: string; - category: Category; - rating: number | null; - reviewCount: number | null; - distance?: number | null; - mainImageUrl?: string | null; - isOpenNow?: boolean | null; - latitude?: number | string | null; - longitude?: number | string | null; - lat?: number | string | null; - lng?: number | string | null; -}; - -type ApiResponse = { - isSuccess: boolean; - code: string; - message: string; - result: { - stores: ApiStoreSummary[]; - pagination: { - page: number; - limit: number; - totalCount: number; - totalPages: number; - hasNext: boolean; - }; - }; -}; +import type { ApiResponse } from "@/types/api"; +import type { + ApiStoreSummary, + RestaurantSummary, + SearchStoreParams, + SearchStoresResult, +} from "@/types/store"; const toNum = (v: unknown): number | undefined => { if (v == null) return undefined; @@ -56,8 +16,8 @@ const toNum = (v: unknown): number | undefined => { }; function toSummary(s: ApiStoreSummary): RestaurantSummary { - const lat = toNum(s.latitude ?? s.lat); - const lng = toNum(s.longitude ?? s.lng); + const lat = toNum(s.latitude); + const lng = toNum(s.longitude); return { id: s.storeId, name: s.name, @@ -72,7 +32,7 @@ function toSummary(s: ApiStoreSummary): RestaurantSummary { }; } -export function useSearchStores(params: Params | null) { +export function useSearchStores(params: SearchStoreParams | null) { return useQuery({ queryKey: ["searchStores", params], enabled: !!params && !!params.keyword, @@ -92,7 +52,7 @@ export function useSearchStores(params: Params | null) { if (params.sigungu) cleanParams.sigungu = params.sigungu; if (params.bname) cleanParams.bname = params.bname; - const res = await api.get("/api/v1/stores/search", { + const res = await api.get>("/api/v1/stores/search", { params: cleanParams, }); diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx index d7d0f3d..3a551dd 100644 --- a/src/pages/SearchPage.tsx +++ b/src/pages/SearchPage.tsx @@ -1,7 +1,6 @@ import { Search } from "lucide-react"; import { useEffect, useMemo, useState } from "react"; -import type { CreateBookingResult } from "@/api/endpoints/reservations"; import KakaoMap from "@/components/map/KakaoMap"; import PaymentModal from "@/components/reservation/modals/PaymentModal"; import ReservationConfirmMoodal from "@/components/reservation/modals/ReservationConfirmModal"; @@ -14,6 +13,7 @@ import { useRestaurantDetail } from "@/hooks/store/useRestaurantDetail"; import { useSearchStores } from "@/hooks/store/useSearchStores"; import type { KakaoAddressSearchResult, KakaoAddressSearchStatus } from "@/types/kakao"; import type { LatLng } from "@/types/map"; +import type { CreateBookingResult } from "@/types/reservation"; import type { ReservationDraft } from "@/types/restaurant"; import type { RestaurantSummary } from "@/types/store"; import { toHHmm } from "@/utils/time"; diff --git a/src/pages/myPage/MyInfoPage.tsx b/src/pages/myPage/MyInfoPage.tsx index 0f1e166..2351030 100644 --- a/src/pages/myPage/MyInfoPage.tsx +++ b/src/pages/myPage/MyInfoPage.tsx @@ -7,11 +7,11 @@ import ProfileAvatar from "@/components/profile/profileAvatar"; import { Button } from "@/components/ui/button"; import { phoneNumber } from "@/utils/phoneNumber"; -type Form = { +interface Form { email: string; nickname: string; phone: string; -}; +} export default function MyInfoPage() { const qc = useQueryClient(); diff --git a/src/pages/myPage/StoreRegistrationPage.tsx b/src/pages/myPage/StoreRegistrationPage.tsx index 319c624..d986515 100644 --- a/src/pages/myPage/StoreRegistrationPage.tsx +++ b/src/pages/myPage/StoreRegistrationPage.tsx @@ -17,12 +17,12 @@ import { useMenuCreate, useMenuImage } from "@/hooks/queries/useMenu"; import { useMainImage, useRegisterStore } from "@/hooks/queries/useStore"; import { getErrorMessage } from "@/utils/error"; -type Step1Data = { +interface Step1Data { name: string; businessNumber: string; startDate: string; isVerified: boolean; -}; +} export default function StoreRegistrationPage() { const { mutateAsync: registerStore } = useRegisterStore(); diff --git a/src/pages/myPage/reservationPage.tsx b/src/pages/myPage/reservationPage.tsx index 0cdfdea..ebb36fd 100644 --- a/src/pages/myPage/reservationPage.tsx +++ b/src/pages/myPage/reservationPage.tsx @@ -6,7 +6,7 @@ import { cn } from "@/lib/utils"; type ReservationStatus = "전체" | "예정된 예약" | "방문 완료" | "취소된 예약"; -type Reservation = { +interface Reservation { id: number; shopName: string; status: "예약 확정" | "방문 완료" | "취소됨"; @@ -17,7 +17,7 @@ type Reservation = { payment: string; method: string; step: string; -}; +} export default function ReservationPage() { const [activeTab, setActiveTab] = useState("전체"); @@ -53,7 +53,9 @@ export default function ReservationPage() { shopName: b.storeName, address: b.storeAddress, date: b.bookingDate, - time: b.bookingTime ?? "--:--", + time: b.bookingTime + ? `${String(b.bookingTime.hour).padStart(2, "0")}:${String(b.bookingTime.minute).padStart(2, "0")}` + : "--:--", people: b.partySize?.toString() ?? "0", payment: `${b.amount?.toLocaleString() ?? 0}원`, method: b.paymentMethod ?? "-", diff --git a/src/pages/myPage/storePage.tsx b/src/pages/myPage/storePage.tsx index eecab15..d09c4d7 100644 --- a/src/pages/myPage/storePage.tsx +++ b/src/pages/myPage/storePage.tsx @@ -2,8 +2,9 @@ import { BarChart3, Calendar, Plus, Star, Store } from "lucide-react"; import { useEffect, useState } from "react"; import { Link, useNavigate } from "react-router-dom"; -import { getMyStores, type MyStore } from "@/api/owner/stores"; +import { getMyStores } from "@/api/owner/stores"; import { cn } from "@/lib/utils"; +import type { MyStore } from "@/types/store"; export default function StorePage() { const [shops, setShops] = useState([]); diff --git a/src/types/api.ts b/src/types/api.ts index ae9c4a9..5774bd2 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -10,3 +10,10 @@ export interface ApiError { code?: string; message: string; } + +export interface ApiResponseWithFlags { + code?: string; + message?: string; + success?: boolean; + isSuccess?: boolean; +} diff --git a/src/types/auth.ts b/src/types/auth.ts index a0f1e66..070af3f 100644 --- a/src/types/auth.ts +++ b/src/types/auth.ts @@ -1,4 +1,4 @@ -export type RequestSignupDto = { +export interface RequestSignupDto { name: string; email: string; password: string; @@ -7,36 +7,36 @@ export type RequestSignupDto = { tosConsent: boolean; privacyConsent: boolean; marketingConsent: boolean; -}; +} -export type ResponseSignupDto = { +export interface ResponseSignupDto { id: number; createdAt: string; -}; +} -export type RequestLoginDto = { +export interface RequestLoginDto { email: string; password: string; -}; +} -export type ResponseLoginDto = { +export interface ResponseLoginDto { id: number; accessToken: string; refreshToken: string | null; -}; +} export type ResponseLogoutDto = string; -export type ResponseRefreshDto = { +export interface ResponseRefreshDto { accessToken: string; -}; +} -export type RequestVerifyOwnerDto = { +export interface RequestVerifyOwnerDto { businessNumber: string; startDate: string; -}; +} -export type ResponseVerifyOwnerDto = { +export interface ResponseVerifyOwnerDto { businessNumber: string; startDate: string; -}; +} diff --git a/src/types/booking.ts b/src/types/booking.ts index 79956fb..428d49e 100644 --- a/src/types/booking.ts +++ b/src/types/booking.ts @@ -1,3 +1,42 @@ -import type { getUserBookings } from "@/api/endpoints/bookings"; +export type ApiBookingStatus = "PENDING" | "CONFIRMED" | "COMPLETED" | "CANCELED"; -export type UserBookingItem = Awaited>["bookingList"][number]; +export interface Pagination { + listSize: number; + totalPage: number; + totalElements: number; + isFirst: boolean; + isLast: boolean; +} + +export interface BookingResponse extends Pagination { + bookingList: BookingListItem[]; +} + +export interface GetBookingParams { + page: number; + status?: ApiBookingStatus; +} + +export interface BookingListItem { + bookingId: number; + storeName: string; + storeAddress: string; + bookingDate: string; + bookingTime: { + hour: number; + minute: number; + second: number; + nano: number; + }; + partySize: number; + tableNumbers: string; + amount: number | null; + paymentMethod: string; + status: ApiBookingStatus; +} + +export interface UserBookingsResult extends Pagination { + bookingList: BookingListItem[]; +} + +export type UserBookingItem = BookingListItem; diff --git a/src/types/inquiry.ts b/src/types/inquiry.ts new file mode 100644 index 0000000..e416757 --- /dev/null +++ b/src/types/inquiry.ts @@ -0,0 +1,4 @@ +export interface ResponseInquiryDTO { + id: number; + createdAt: string; +} diff --git a/src/types/kakao.d.ts b/src/types/kakao.d.ts index 26b7eec..f348c9b 100644 --- a/src/types/kakao.d.ts +++ b/src/types/kakao.d.ts @@ -53,11 +53,9 @@ declare global { } } -export {}; - export type KakaoAddressSearchStatus = "OK" | "ZERO_RESULT" | "ERROR"; -export type KakaoAddressSearchResult = { +export interface KakaoAddressSearchResult { x: string; y: string; -}; +} diff --git a/src/types/layout.ts b/src/types/layout.ts new file mode 100644 index 0000000..3e555c8 --- /dev/null +++ b/src/types/layout.ts @@ -0,0 +1,40 @@ +import type { SeatsType } from "./table"; + +export interface LayoutTable { + tableId: number; + tableNumber: string; + minSeatCount: number; + maxSeatCount: number; + gridX: number; + gridY: number; + widthSpan: number; + heightSpan: number; + tableImageUrl: string | null; + seatsType: SeatsType; +} + +export interface LayoutResponse { + layoutId: number; + totalTableCount: number; + gridInfo: { gridCol: number; gridRow: number }; + tables: LayoutTable[]; +} + +export interface CreateTableRequest { + gridX: number; + gridY: number; + minSeatCount: number; + maxSeatCount: number; + seatsType: SeatsType; +} + +export interface CreateTableResponse { + tableId: number; + tableNumber: string; + minSeatCount: number; + maxSeatCount: number; + seatsType: string; + gridX: number; + gridY: number; + tableImageUrl: string | null; +} diff --git a/src/types/map.ts b/src/types/map.ts index 9252878..9b36474 100644 --- a/src/types/map.ts +++ b/src/types/map.ts @@ -1,7 +1,12 @@ import type { RestaurantSummary } from "./store"; -export type LatLng = { lat: number; lng: number }; -export type MarkerWithLocation = RestaurantSummary & { location: LatLng }; +export interface LatLng { + lat: number; + lng: number; +} +export interface MarkerWithLocation extends RestaurantSummary { + location: LatLng; +} type KakaoMaps = NonNullable["maps"]>; export type KaKaoMapInstance = InstanceType; diff --git a/src/types/member.ts b/src/types/member.ts new file mode 100644 index 0000000..182d4cf --- /dev/null +++ b/src/types/member.ts @@ -0,0 +1,24 @@ +export interface MemberInfo { + id: number; + profileImage: string | null; + email: string; + name: string; + phoneNumber: string; +} + +export interface PatchMemberInfo { + name?: string; + phoneNumber?: string; +} + +export interface ChangePasswordRequest { + currentPassword: string; + newPassword: string; + newPasswordConfirm: string; +} + +export interface ChangePasswordResponse { + change: boolean; + changeAt: string; + message: string; +} diff --git a/src/types/menus.ts b/src/types/menus.ts index 0050881..e105b10 100644 --- a/src/types/menus.ts +++ b/src/types/menus.ts @@ -1,4 +1,4 @@ -export type MenuItem = { +export interface MenuItem { id: string; restaurantId: string; name: string; @@ -11,12 +11,12 @@ export type MenuItem = { isActive: boolean; createdAt?: string; updatedAt?: string; -}; +} -export type SelectedMenu = { +export interface SelectedMenu { menuId: string; quantity: number; -}; +} export type MenuCategory = "MAIN" | "SIDE" | "BEVERAGE" | "ALCOHOL"; @@ -33,27 +33,99 @@ export const UiMenuCategoryLabel: Record = { OTHER: "기타", }; -export type MenuCreateItemDto = { +export interface MenuCreateItemDto { name: string; description?: string; price: number; category: MenuCategory; imageKey?: string; -}; +} -export type RequestMenuCreateDto = { +export interface RequestMenuCreateDto { menus: MenuCreateItemDto[]; -}; +} -export type ResponseMenuCreateDto = { +export interface ResponseMenuCreateDto { menus: MenuCreateItemDto[]; -}; +} -export type RequestMenuImageDto = { +export interface RequestMenuImageDto { image: File; -}; +} -export type ResponseMenuImageDto = { +export interface ResponseMenuImageDto { imageKey: string; imageUrl: string; -}; +} + +export interface ServerMenu { + menuId: number; + name: string; + description?: string | null; + price: number; + category?: string | null; + imageUrl?: string | null; + isSoldOut?: boolean; +} + +export interface GetMenusResult { + menus: ServerMenu[]; +} + +export interface MenuUpdateItem { + name: string; + description?: string; + price: number; + category: string; + imageKey?: string; +} + +export interface MenuUpdateResult { + menuId: number; + name: string; + description?: string; + price: number; + category?: string; + imageUrl?: string; +} + +export interface MenuCreateItem { + name: string; + description?: string; + price: number; + category: string; + imageKey?: string; +} + +export interface MenuCreateResult { + menus: { + menuId: number; + name: string; + description?: string; + price: number; + category?: string; + imageUrl?: string; + imageKey?: string; + }[]; +} + +export interface DeleteMenusResponse { + isSuccess: boolean; + code: string; + result: { deletedMenuIds: number[] }; + message: string; +} + +export interface MenuDto { + menuId: number; + name: string; + description?: string; + price: number; + category: MenuCategory | string; + imageUrl?: string; + isSoldOut: boolean; +} + +export interface MenuListResult { + menus: MenuDto[]; +} diff --git a/src/types/payment.ts b/src/types/payment.ts index 859d3c0..bbec91e 100644 --- a/src/types/payment.ts +++ b/src/types/payment.ts @@ -1 +1,20 @@ export type { DepositRate } from "@/types/store"; + +export interface PaymentRequestResult { + paymentId: number; + bookingId: number; + orderId: string; + amount: number; + requestedAt: string; +} + +export interface PaymentConfirmResult { + paymentId: number; + status: string; + approvedAt: string; + orderId: string; + amount: number; + paymentMethod: string; + paymentProvider: string; + receiptUrl: string; +} diff --git a/src/types/reservation.ts b/src/types/reservation.ts new file mode 100644 index 0000000..e4f2179 --- /dev/null +++ b/src/types/reservation.ts @@ -0,0 +1,94 @@ +export interface Slot { + time: string; + status: "AVAILABLE" | "BOOKED" | "BLOCKED"; + isAvailable: boolean; + bookingId: number | null; +} + +export interface GetSlotsResult { + slots: Slot[]; +} + +export type SlotStatus = "AVAILABLE" | "BLOCKED"; + +export interface UpdateSlotRequest { + targetDate: string; + startTime: string; + status: SlotStatus; +} + +export interface UpdateSlotResult { + targetDate: string; + startTime: string; + status: SlotStatus; +} + +export interface PatchBreakTimeRequest { + breakStartTime: string; + breakEndTime: string; +} + +export interface BookingDetailResult { + bookerName: string; + partySize: number; + amount: number; +} + +export interface GetAvailableTimesParams { + storeId: string | number; + date: string; + partySize: number; + isSplitAccepted: boolean; +} + +export interface AvailableTimesResult { + availableTimes: string[]; +} + +export type SeatsTypes = "WINDOW" | "GENERAL" | string; + +export interface AvailableTable { + tableId: number; + tableNumber: string; + tableSeats: number; + seatsType: SeatsTypes; + gridX: number; + gridY: number; + widthSpan: number; + heightSpan: number; +} +export type GetAvailableTablesParams = { + storeId: string | number; + date: string; + time: string; + partySize: number; + isSplitAccepted: boolean; + seatsType?: string; +}; + +export interface AvailableTablesResult { + rows: number; + cols: number; + tables: AvailableTable[]; +} + +export interface CreateBookingBody { + date: string; + time: string; + partySize: number; + tableIds: number[]; + menuItems: { menuId: number; quantity: number }[]; + isSplitAccepted: boolean; +} + +export interface CreateBookingResult { + bookingId: number; + status: "PENDING" | "CONFIRMED" | string; + storeName: string; + date: string; + time: string; + partySize: number; + totalDeposit: number; + paymentId?: number; + orderId: string; +} diff --git a/src/types/restaurant.ts b/src/types/restaurant.ts index 516fa30..a6ad897 100644 --- a/src/types/restaurant.ts +++ b/src/types/restaurant.ts @@ -4,7 +4,7 @@ export const SEATS = ["일반석", "창가석", "룸/프라이빗", "바(Bar)석 export type SeatType = (typeof SEATS)[number]; export type TablePref = "split_ok" | "one_table"; -export type ReservationDraft = { +export interface ReservationDraft { people: number; date: Date; time?: string; @@ -13,9 +13,9 @@ export type ReservationDraft = { tableId: number; tableNo: number | null; selectedMenus: SelectedMenu[]; -}; +} -export type SeatTable = { +export interface SeatTable { id: number; tableNo: number; minPeople: number; @@ -24,10 +24,10 @@ export type SeatTable = { gridX: number; gridY: number; imageUrl?: string; -}; +} -export type SeatLayout = { +export interface SeatLayout { gridCols: number; gridRows: number; tables: SeatTable[]; -}; +} diff --git a/src/types/store.ts b/src/types/store.ts index c9d0d82..4f5b679 100644 --- a/src/types/store.ts +++ b/src/types/store.ts @@ -1,3 +1,5 @@ +import type { ApiResponse } from "./api"; + export type Category = "KOREAN" | "CHINESE" | "JAPANESE" | "WESTERN" | "CAFE"; export type Day = @@ -9,12 +11,12 @@ export type Day = | "SATURDAY" | "SUNDAY"; -export type Location = { +export interface Location { lat: number; lng: number; -}; +} -export type RestaurantSummary = { +export interface RestaurantSummary { id: number; name: string; address: string; @@ -25,21 +27,21 @@ export type RestaurantSummary = { thumbnailUrl?: string; isOpenNow?: boolean; location?: Location; -}; +} -export type BusinessHour = { +export interface BusinessHour { day: Day; openTime: string | null; closeTime: string | null; isClosed: boolean; -}; +} -export type BreakTime = { +export interface BreakTime { start: string; end: string; -}; +} -export type RestaurantDetail = { +export interface RestaurantDetail { id: number; name: string; description: string; @@ -56,7 +58,7 @@ export type RestaurantDetail = { isOpenNow?: boolean; location?: Location; depositRate?: number; -}; +} export const storeCategoryLabel: Record = { KOREAN: "한식", @@ -68,13 +70,13 @@ export const storeCategoryLabel: Record = { export type DepositRate = "TEN" | "TWENTY" | "THIRTY" | "FORTY" | "FIFTY"; -export type BusinessNumberDto = { +export interface BusinessNumberDto { name: string; businessNumber: string; startDate: string; -}; +} -export type RequestStoreCreateDto = { +export interface RequestStoreCreateDto { storeName: string; businessNumberDto?: BusinessNumberDto; description?: string; @@ -89,31 +91,128 @@ export type RequestStoreCreateDto = { depositRate: DepositRate; bookingIntervalMinutes: number; businessHours: BusinessHour[]; -}; +} -export type ResponseStoreCreateDto = { storeId: number }; +export interface ResponseStoreCreateDto { + storeId: number; +} -export type RequestMainImageDto = { +export interface RequestMainImageDto { mainImage: File; -}; +} -export type ResponseMainImageDto = { +export interface ResponseMainImageDto { storeId: number; mainImageUrl: string; -}; +} -export type UpdateStoreResponse = { +export interface UpdateStoreResponse { storeId: number; storeName: string; description: string; phoneNumber: string; -}; +} -export type AddressSearchResult = { +export interface AddressSearchResult { address: string; addressType: string; bname: string; buildingName: string; sido: string; sigungu: string; -}; +} + +export interface StoreDetail { + storeId: number; + storeName: string; + description: string; + address: string; + phone: string; + businessHours?: BusinessHour[]; + isApproved: boolean; + rating?: number; + reviewCount?: number; +} + +export interface MyStore { + storeId: number; + storeName: string; + address: string; + category: Category; + rating: number; + totalBookingCount: number; + reviewCount: number; + mainImageUrl: string; + isOpenNow: boolean; +} + +export type MyStoreResponse = ApiResponse<{ stores: MyStore[] }>; + +export interface TableImage { + tableImageId: number; + tableImageUrl: string; +} + +export interface TableImagesResponse { + storeId: number; + tableImages: TableImage[]; +} + +export interface StoreDetailDataDTO { + storeId: number | string; + storeName: string; + description: string; + address: string; + phone: string; + category: Category; + rating: number; + reviewCount: number | null; + mainImageUrl?: string | null; + tableImageUrls: string[] | null; + businessHours: BusinessHour[] | null; + breakStartTime?: string | null; + breakEndTime?: string | null; + isOpenNow?: boolean; + + depositAmount: number; + depositRate?: number | null; +} + +export interface SearchStoreParams { + keyword: string; + lat: number; + lng: number; + radius?: number; + category?: Category; + sort?: "DISTANCE" | "RATING"; + page?: number; + limit?: number; + sido?: string; + sigungu?: string; + bname?: string; +} + +export interface ApiStoreSummary { + storeId: number; + name: string; + address: string; + category: Category; + rating: number | null; + reviewCount: number | null; + distance?: number | null; + mainImageUrl?: string | null; + isOpenNow?: boolean | null; + latitude?: number | string | null; + longitude?: number | string | null; +} + +export interface SearchStoresResult { + stores: ApiStoreSummary[]; + pagination: { + page: number; + limit: number; + totalCount: number; + totalPages: number; + hasNext: boolean; + }; +} diff --git a/src/types/table.ts b/src/types/table.ts index 54aefd3..29da64f 100644 --- a/src/types/table.ts +++ b/src/types/table.ts @@ -7,3 +7,27 @@ export const SEATS_TYPE_LABEL: Record = { BAR: "바 좌석", OUTDOOR: "야외석", }; + +export interface UploadTableImageResult { + tableId: number; + tableImageUrl: string; +} + +export interface DeleteTableImageResult { + tableId: number; +} + +export interface PatchTableRequest { + tableNumber?: string; + minSeatCount?: number; + maxSeatCount?: number; + seatsType?: SeatsType; +} + +export interface UpdatedTable { + tableId: number; + tableNumber: string; + minSeatCount: number; + maxSeatCount: number; + seatsType: SeatsType; +}