= ({
테이블 관리
{storeName && (
-
- · {storeName}
-
+ · {storeName}
)}
@@ -621,9 +558,7 @@ const TableDashboard: React.FC = ({
{breakTimes.length > 0 && (
-
- 브레이크 타임 목록
-
+
브레이크 타임 목록
{breakTimes.map((bt, idx) => (
@@ -636,11 +571,7 @@ const TableDashboard: React.FC
= ({
{bt.start} ~ {bt.end}
-
- 📅 총 테이블 수
-
+
📅 총 테이블 수
{config.columns * config.rows}개
@@ -694,46 +623,50 @@ const TableDashboard: React.FC
= ({
gridTemplateColumns: `repeat(${config.columns}, minmax(150px, 1fr))`,
}}
>
- {Array.from({ length: config.columns * config.rows }).map(
- (_, i: number) => {
- const id = i + 1;
- const table = getTableData(id);
- const style = getTableStyle(table.maxCapacity);
-
- const extraStyle = table.isSaved
- ? ""
- : "opacity-50 border-dashed";
-
- return (
- {
- if (!table.isSaved) return;
- if (!table.isEditingCapacity) {
- setSelectedTable(id);
- }
- }}
- className={`border-2 ${style.border} ${extraStyle} rounded-lg p-4 ${style.bg} flex flex-col items-center cursor-pointer ${style.hover} transition-all relative group aspect-square justify-center w-36 md:w-40`}
- >
-
- {table.isEditingCapacity ? (
-
인원 설정
- ) : table.isEditingNum ? (
-
e.stopPropagation()}
- >
-
- updateTable(id, {
- numValue: Number(e.target.value),
- })
+ {Array.from({ length: config.columns * config.rows }).map((_, i: number) => {
+ const id = i + 1;
+ const table = getTableData(id);
+ const style = getTableStyle(table.maxCapacity);
+
+ const extraStyle = table.isSaved ? "" : "opacity-50 border-dashed";
+
+ return (
+
{
+ if (!table.isSaved) return;
+ if (!table.isEditingCapacity) {
+ setSelectedTable(id);
+ }
+ }}
+ className={`border-2 ${style.border} ${extraStyle} rounded-lg p-4 ${style.bg} flex flex-col items-center cursor-pointer ${style.hover} transition-all relative group aspect-square justify-center w-36 md:w-40`}
+ >
+
+ {table.isEditingCapacity ? (
+
인원 설정
+ ) : table.isEditingNum ? (
+
e.stopPropagation()}>
+
+ updateTable(id, {
+ numValue: Number(e.target.value),
+ })
+ }
+ onBlur={() => {
+ updateTable(id, { isEditingNum: false });
+ const tableId = getTableData(id).tableId;
+ if (tableId > 0) {
+ handlePatchTableInfo(tableId, {
+ tableNumber: table.numValue,
+ });
}
- onBlur={() => {
+ }}
+ onKeyDown={(e) => {
+ if (e.key === "Enter") {
updateTable(id, { isEditingNum: false });
const tableId = getTableData(id).tableId;
if (tableId > 0) {
@@ -741,177 +674,153 @@ const TableDashboard: React.FC
= ({
tableNumber: table.numValue,
});
}
- }}
- onKeyDown={(e) => {
- if (e.key === "Enter") {
- updateTable(id, { isEditingNum: false });
- const tableId = getTableData(id).tableId;
- if (tableId > 0) {
- handlePatchTableInfo(tableId, {
- tableNumber: table.numValue,
- });
- }
- }
- }}
- />
- 번
-
- ) : (
- <>
- {table.numValue}번 테이블
+ }
+ }}
+ />
+
번
+
+ ) : (
+ <>
+ {table.numValue}번 테이블
+
+
+ >
+ )}
+
-
- {table.isEditingCapacity ? (
-
e.stopPropagation()}
- >
-
-
-
- {table.minCapacity}
-
-
-
-
-
-
-
- ~
-
-
-
+
+ {table.isEditingCapacity ? (
+
e.stopPropagation()}
+ >
+
+
+
{table.minCapacity}
+
+
+
-
-
-
- ) : (
- <>
-
{
- e.stopPropagation();
- startEditingCapacity(id);
- }}
- className={`${style.badge} text-white px-2 py-2 rounded-sm text-xs shadow-md min-w-15 text-center transition-transform active:scale-95`}
+
+
-
- {SEATS_TYPE_LABEL[table.seatsType]}
-
- >
- )}
-
+
+
+
+
+
+ ) : (
+ <>
+
{
+ e.stopPropagation();
+ startEditingCapacity(id);
+ }}
+ className={`${style.badge} text-white px-2 py-2 rounded-sm text-xs shadow-md min-w-15 text-center transition-transform active:scale-95`}
+ >
+ {table.minCapacity}~{table.maxCapacity}인
+
+
+ {SEATS_TYPE_LABEL[table.seatsType]}
+
+ >
+ )}
- );
- },
- )}
+
+ );
+ })}
-
+
- Tip: 테이블을 클릭하면 상세 정보를 확인하고 예약 시간대를
- 관리할 수 있습니다.
+ Tip: 테이블을 클릭하면 상세 정보를 확인하고 예약 시간대를 관리할 수 있습니다.
-
소형
- (4인 이하)
+
소형 (4인 이하)
-
중형
- (5~8인)
+
중형 (5~8인)
-
단체석
- (9인 이상)
+
단체석 (9인 이상)
@@ -921,12 +830,8 @@ const TableDashboard: React.FC
= ({
-
- 등록된 테이블이 없습니다
-
-
- 테이블을 생성하여 가게 관리를 시작하세요
-
+ 등록된 테이블이 없습니다
+ 테이블을 생성하여 가게 관리를 시작하세요
@@ -509,11 +480,7 @@ const TableDetailModal: React.FC
= ({
{previewUrl && (
-

+
)}
@@ -565,10 +532,7 @@ const TableDetailModal: React.FC = ({
>
-
@@ -593,9 +557,7 @@ const TableDetailModal: React.FC
= ({
테이블 유형
-
- {SEATS_TYPE_LABEL[tableInfo.seatsType]}
-
+
{SEATS_TYPE_LABEL[tableInfo.seatsType]}
@@ -609,9 +571,7 @@ const TableDetailModal: React.FC = ({
-
- 예약 가능한 시간대
-
+
예약 가능한 시간대
{slots.filter((s) => s.isAvailable).length}개 예약 가능
@@ -620,18 +580,14 @@ const TableDetailModal: React.FC
= ({
-
- 테이블 타입 및 좌석 정보
-
+
테이블 타입 및 좌석 정보
🎉
-
+
{tableTypeStyle[tableType].label}
@@ -674,10 +630,7 @@ const TableDetailModal: React.FC
= ({
{["일", "월", "화", "수", "목", "금", "토"].map((d) => (
-
+
{d}
))}
@@ -691,15 +644,7 @@ const TableDetailModal: React.FC = ({
const isTodayFlag = dateObj.getTime() === today.getTime();
const weekDay = dateObj.getDay();
- const weekDayKorean = [
- "일",
- "월",
- "화",
- "수",
- "목",
- "금",
- "토",
- ][weekDay];
+ const weekDayKorean = ["일", "월", "화", "수", "목", "금", "토"][weekDay];
const isClosedDay = closedDays.includes(weekDayKorean);
@@ -722,16 +667,8 @@ const TableDetailModal: React.FC = ({
}`}
>
{day}
- {isTodayFlag && (
-
- 오늘
-
- )}
- {isClosedDay && (
-
- 휴무
-
- )}
+ {isTodayFlag && 오늘}
+ {isClosedDay && 휴무}
);
})}
@@ -743,9 +680,7 @@ const TableDetailModal: React.FC = ({
날짜를 선택하여 예약 시간대를 관리하세요
-
- 과거 날짜는 선택할 수 없습니다
-
+ 과거 날짜는 선택할 수 없습니다
@@ -759,9 +694,7 @@ const TableDetailModal: React.FC
= ({
)}
- {error && (
- {error}
- )}
+ {error && {error}
}
{showBookingDetail && (
@@ -776,15 +709,10 @@ const TableDetailModal: React.FC
= ({
예약자:{" "}
-
- {bookingDetail.bookerName}
-
+ {bookingDetail.bookerName}
- 인원:{" "}
-
- {bookingDetail.partySize}명
-
+ 인원: {bookingDetail.partySize}명
결제된 예약금:{" "}
@@ -794,9 +722,7 @@ const TableDetailModal: React.FC = ({
) : (
-
- 상세 정보가 없습니다.
-
+ 상세 정보가 없습니다.
)}
diff --git a/src/components/reservation/modals/PaymentModal.tsx b/src/components/reservation/modals/PaymentModal.tsx
index 3d9934c..d8e9276 100644
--- a/src/components/reservation/modals/PaymentModal.tsx
+++ b/src/components/reservation/modals/PaymentModal.tsx
@@ -1,21 +1,23 @@
-import type { ReservationDraft } from "@/types/restaurant";
-import type { RestaurantDetail } from "@/types/store";
-import { useEffect, useMemo, useRef, useState } from "react";
-import { formatKrw } from "@/utils/money";
-import { Button } from "../../ui/button";
-import { X } from "lucide-react";
-import { useMenus } from "@/hooks/reservation/useMenus";
-import { useDepositRate } from "@/hooks/reservation/useDepositRate";
-import { calcMenuTotal } from "@/utils/menu";
-import { useConfirmClose } from "@/hooks/common/useConfirmClose";
-import type { CreateBookingResult } from "@/api/endpoints/reservations";
-import { requestPayment } from "@/api/endpoints/payments";
import { loadTossPayments } from "@tosspayments/tosspayments-sdk";
+import { X } from "lucide-react";
+import { useEffect, useMemo, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
-import { useUserId } from "@/stores/useAuthStore";
+
+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 { ReservationDraft } from "@/types/restaurant";
+import type { RestaurantDetail } from "@/types/store";
+import { calcMenuTotal } from "@/utils/menu";
import { backdropMotionClass, panelMotionClass } from "@/utils/modalMotion";
+import { formatKrw } from "@/utils/money";
+
+import { Button } from "../../ui/button";
type Props = {
open: boolean;
@@ -29,13 +31,9 @@ type Props = {
type TossPaymentsInstance = Awaited
>;
type TossWidgetsInstance = ReturnType;
-type PaymentMethodWidgetInstance = Awaited<
- ReturnType
->;
+type PaymentMethodWidgetInstance = Awaited>;
-type AgreementWidgetInstance = Awaited<
- ReturnType
->;
+type AgreementWidgetInstance = Awaited>;
export default function PaymentModal({
open,
@@ -56,11 +54,7 @@ export default function PaymentModal({
return calcMenuTotal(menus, draft.selectedMenus);
}, [menus, draft.selectedMenus]);
- const amount = booking?.totalDeposit ?? 0;
-
- const paymentMethodWidgetRef = useRef(
- null,
- );
+ const paymentMethodWidgetRef = useRef(null);
const agreementWidgetRef = useRef(null);
const widgetsRef = useRef(null);
@@ -78,9 +72,8 @@ export default function PaymentModal({
const handleRequestClose = useConfirmClose(onClose);
const userId = useUserId();
- const [_payAmount, setPayAmount] = useState(
- booking?.totalDeposit ?? 0,
- );
+ const [payAmount, setPayAmount] = useState(booking?.totalDeposit ?? 0);
+ const amount = payAmount;
useEffect(() => {
setPayAmount(booking?.totalDeposit ?? 0);
}, [booking?.totalDeposit]);
@@ -102,9 +95,7 @@ export default function PaymentModal({
if (agreementContainer) {
agreementContainer.innerHTML = "";
}
- const clientKey = import.meta.env.VITE_TOSS_CLIENT_KEY as
- | string
- | undefined;
+ const clientKey = import.meta.env.VITE_TOSS_CLIENT_KEY as string | undefined;
if (!clientKey) throw new Error("VITE_TOSS_CLIENT_KEY가 없습니다.");
if (!userId) {
throw new Error("로그인 정보가 없어 결제를 진행할 수 없습니다.");
@@ -242,9 +233,7 @@ export default function PaymentModal({
결제 금액
-
- {formatKrw(amount)}원
-
+
{formatKrw(amount)}원
메뉴 총액 {formatKrw(menuTotal)}원 * {Math.round(rate * 100)}%
diff --git a/src/components/reservation/modals/ReservationCompleteModal.tsx b/src/components/reservation/modals/ReservationCompleteModal.tsx
index 5090491..f62522a 100644
--- a/src/components/reservation/modals/ReservationCompleteModal.tsx
+++ b/src/components/reservation/modals/ReservationCompleteModal.tsx
@@ -1,3 +1,6 @@
+import { CircleCheck } from "lucide-react";
+import { useEffect } from "react";
+
import { useModalPresence } from "@/hooks/common/useModalPresence";
import { cn } from "@/lib/utils";
import type { ReservationDraft } from "@/types/restaurant";
@@ -5,8 +8,6 @@ import type { RestaurantDetail } from "@/types/store";
import { toYmd } from "@/utils/date";
import { backdropMotionClass, panelMotionClass } from "@/utils/modalMotion";
import { toHHmm } from "@/utils/time";
-import { CircleCheck } from "lucide-react";
-import { useEffect } from "react";
type Props = {
open: boolean;
diff --git a/src/components/reservation/modals/ReservationConfirmModal.tsx b/src/components/reservation/modals/ReservationConfirmModal.tsx
index f08aabf..14610cc 100644
--- a/src/components/reservation/modals/ReservationConfirmModal.tsx
+++ b/src/components/reservation/modals/ReservationConfirmModal.tsx
@@ -1,3 +1,5 @@
+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";
@@ -15,7 +17,6 @@ import { backdropMotionClass, panelMotionClass } from "@/utils/modalMotion";
import { formatKrw } from "@/utils/money";
import { calcDeposit } from "@/utils/payment";
import { tablePrefLabel } from "@/utils/reservation";
-import { X } from "lucide-react";
type Props = {
open: boolean;
@@ -164,8 +165,7 @@ export default function ReservationConfirmModal({
결제 유형
사전 결제
- 예약금:{" "}
- {isCalculating ? "계산중 .." : `${formatKrw(depositAmount)}원`}
+ 예약금: {isCalculating ? "계산 중 .." : `${formatKrw(depositAmount)}원`}
예약 확정을 위해 예약금 결제가 필요합니다.(노쇼 방지 목적)
@@ -174,9 +174,7 @@ export default function ReservationConfirmModal({
예약 취소시 예약금은 환불이 어렵습니다.
-
- 위 내용으로 예약을 진행할까요?
-
+ 위 내용으로 예약을 진행할까요?
- {createBookingMutation.isPending
- ? "예약 생성중"
- : "예약금 결제하기"}
+ {createBookingMutation.isPending ? "예약 생성 중" : "예약금 결제하기"}
diff --git a/src/components/reservation/modals/ReservationMenuModal.tsx b/src/components/reservation/modals/ReservationMenuModal.tsx
index b589f7b..b3bb0df 100644
--- a/src/components/reservation/modals/ReservationMenuModal.tsx
+++ b/src/components/reservation/modals/ReservationMenuModal.tsx
@@ -1,25 +1,26 @@
-import type { ReservationDraft } from "@/types/restaurant";
import { Minus, Plus, X } from "lucide-react";
-import { Button } from "../../ui/button";
+import { useEffect, useMemo, useState } from "react";
+
+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 {
- type SelectedMenu,
type MenuItem,
- type MenuCategory,
+ type SelectedMenu,
type UiCategory,
- MenuCategoryLabel,
+ UiMenuCategoryLabel,
} from "@/types/menus";
-import { useMenus } from "@/hooks/reservation/useMenus";
-import { useEffect, useMemo, useState } from "react";
+import type { ReservationDraft } from "@/types/restaurant";
+import type { RestaurantDetail } from "@/types/store";
+import { toDepositRate } from "@/utils/depositRate";
import { calcMenuTotal } from "@/utils/menu";
-import { cn } from "@/lib/utils";
+import { backdropMotionClass, panelMotionClass } from "@/utils/modalMotion";
import { formatKrw } from "@/utils/money";
-import { useDepositRate } from "@/hooks/reservation/useDepositRate";
import { calcDeposit } from "@/utils/payment";
-import { useConfirmClose } from "@/hooks/common/useConfirmClose";
-import { toDepositRate } from "@/utils/depositRate";
-import type { RestaurantDetail } from "@/types/store";
-import { useModalPresence } from "@/hooks/common/useModalPresence";
-import { backdropMotionClass, panelMotionClass } from "@/utils/modalMotion";
+
+import { Button } from "../../ui/button";
type Props = {
open: boolean;
@@ -40,9 +41,7 @@ export default function ReservationMenuModal({
}: Props) {
const { activeMenus } = useMenus(restaurant.id);
- const [selectedMenus, setSelectedMenus] = useState(
- draft.selectedMenus ?? [],
- );
+ const [selectedMenus, setSelectedMenus] = useState(draft.selectedMenus ?? []);
useEffect(() => {
const nextMenus = draft.selectedMenus ?? [];
@@ -111,9 +110,7 @@ export default function ReservationMenuModal({
if (q === 0) return prev.filter((p) => p.menuId !== menu.id);
if (exists) {
- return prev.map((p) =>
- p.menuId === menu.id ? { ...p, quantity: q } : p,
- );
+ return prev.map((p) => (p.menuId === menu.id ? { ...p, quantity: q } : p));
}
return [...prev, { menuId: menu.id, quantity: q }];
@@ -163,8 +160,7 @@ export default function ReservationMenuModal({
{restaurant.name} 메뉴선택
- 원하시는 메뉴를 미리 선택할 수 있어요. 메뉴당 최대수량은
- 20개입니다.
+ 원하시는 메뉴를 미리 선택할 수 있어요. 메뉴당 최대수량은 20개입니다.
) : (
- (["MAIN", "SIDE", "BEVERAGE", "ALCOHOL"] as MenuCategory[]).map(
- (cat) => {
- const list = grouped[cat];
- if (list.length === 0) return null;
- const safeLabel = MenuCategoryLabel[cat] ?? "기타";
+ (["MAIN", "SIDE", "BEVERAGE", "ALCOHOL", "OTHER"] as UiCategory[]).map((cat) => {
+ const list = grouped[cat];
+ if (list.length === 0) return null;
+ const safeLabel = UiMenuCategoryLabel[cat] ?? "기타";
- return (
-
- {safeLabel}
-
- {list.map((menu) => {
- const qty = qtyMap.get(Number(menu.id)) ?? 0;
- const img =
- menu.imageUrl && menu.imageUrl.trim().length > 0
- ? menu.imageUrl
- : "/modernKoreaRestaurant.jpg";
- return (
-
-
- {/* 음식사진 */}
-
-

- {menu.isSoldOut && (
-
-
- 품절
-
-
+ return (
+
+ {safeLabel}
+
+ {list.map((menu) => {
+ const qty = qtyMap.get(Number(menu.id)) ?? 0;
+ const img =
+ menu.imageUrl && menu.imageUrl.trim().length > 0
+ ? menu.imageUrl
+ : "/modernKoreaRestaurant.jpg";
+ return (
+
+
+ {/* 음식사진 */}
+
+

- {/* 내용 */}
-
-
-
-
-
- {menu.name}
+ />
+ {menu.isSoldOut && (
+
+
+ 품절
+
+
+ )}
+
+ {/* 내용 */}
+
+
+
+
+
{menu.name}
+ {menu.description ? (
+
+ {menu.description}
- {menu.description ? (
-
- {menu.description}
-
- ) : null}
-
- {qty > 0 ? (
-
- {qty}개
-
) : null}
-
- {formatKrw(menu.price)}원
-
+ {qty > 0 ? (
+
+ {qty}개
+
+ ) : null}
- {/* 수량 조절 */}
-
-
-
dec(menu)}
- disabled={qty === 0 || menu.isSoldOut}
- aria-label={`${menu.name} 수량 감소`}
- >
-
-
-
{qty}
-
= 20) &&
- "opacity-40 cursor-not-allowed",
- )}
- onClick={() => inc(menu)}
- disabled={menu.isSoldOut || qty >= 20}
- aria-label={`${menu.name} 수량증가`}
- >
-
-
-
+
+ {formatKrw(menu.price)}원
+
+
+ {/* 수량 조절 */}
+
+
+
dec(menu)}
+ disabled={qty === 0 || menu.isSoldOut}
+ aria-label={`${menu.name} 수량 감소`}
+ >
+
+
+
{qty}
+
= 20) &&
+ "opacity-40 cursor-not-allowed",
+ )}
+ onClick={() => inc(menu)}
+ disabled={menu.isSoldOut || qty >= 20}
+ aria-label={`${menu.name} 수량증가`}
+ >
+
+
- );
- })}
-
-
- );
- },
- )
+
+ );
+ })}
+
+
+ );
+ })
)}
@@ -303,9 +293,7 @@ export default function ReservationMenuModal({
메뉴 총액: {""}
-
- {formatKrw(totalPrice)}
-
+ {formatKrw(totalPrice)}
@@ -333,9 +321,7 @@ export default function ReservationMenuModal({
-
- 실제 결제는 다음 단계에서 진행됩니다
-
+
실제 결제는 다음 단계에서 진행됩니다
diff --git a/src/components/reservation/modals/ReservationModal.tsx b/src/components/reservation/modals/ReservationModal.tsx
index a877b4c..8387850 100644
--- a/src/components/reservation/modals/ReservationModal.tsx
+++ b/src/components/reservation/modals/ReservationModal.tsx
@@ -1,26 +1,28 @@
+import { CalendarIcon, Clock3, Users, X } from "lucide-react";
+import { useEffect, useMemo, useRef, useState } from "react";
+
+import { useConfirmClose } from "@/hooks/common/useConfirmClose";
+import { useModalPresence } from "@/hooks/common/useModalPresence";
+import { useAvailableTables } from "@/hooks/reservation/useAvailableTables";
+import { useAvailableTimes } from "@/hooks/reservation/useAvailableTimes";
+import { useDepositRate } from "@/hooks/reservation/useDepositRate";
+import { cn } from "@/lib/utils";
import {
- SEATS,
type ReservationDraft,
type SeatLayout,
+ SEATS,
type SeatType,
type TablePref,
} from "@/types/restaurant";
-import { useEffect, useMemo, useRef, useState } from "react";
-import { CalendarIcon, Clock3, Users, X } from "lucide-react";
-import { cn } from "@/lib/utils";
-import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover";
-import { Calendar } from "../../ui/calendar";
-import { Button } from "../../ui/button";
-import { startOfTodayInKst, toYmd } from "@/utils/date";
-import TableMap from "../parts/TableMap";
-import { useConfirmClose } from "@/hooks/common/useConfirmClose";
-import { useDepositRate } from "@/hooks/reservation/useDepositRate";
-import { useAvailableTimes } from "@/hooks/reservation/useAvailableTimes";
-import { useAvailableTables } from "@/hooks/reservation/useAvailableTables";
-import { seatsTypeToSeatType } from "@/utils/reservation";
import type { RestaurantDetail } from "@/types/store";
-import { useModalPresence } from "@/hooks/common/useModalPresence";
+import { startOfTodayInKst, toYmd } from "@/utils/date";
import { backdropMotionClass, panelMotionClass } from "@/utils/modalMotion";
+import { seatsTypeToSeatType } from "@/utils/reservation";
+
+import { Button } from "../../ui/button";
+import { Calendar } from "../../ui/calendar";
+import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover";
+import TableMap from "../parts/TableMap";
type Props = {
open: boolean;
@@ -110,8 +112,7 @@ export default function ReservationModal({
gridCols: data.cols,
tables: data.tables.map((t) => ({
id: t.tableId,
- tableNo:
- parseInt((t.tableNumber ?? "").replace(/\D/g, ""), 10) || t.tableId,
+ tableNo: parseInt((t.tableNumber ?? "").replace(/\D/g, ""), 10) || t.tableId,
seatType: seatsTypeToSeatType(t.seatsType),
minPeople: 1,
maxPeople: t.tableSeats,
@@ -147,14 +148,10 @@ export default function ReservationModal({
}, [timesQuery.data]);
const timeUi = useMemo(() => {
- if (!dateYmd)
- return { msg: "날짜를 먼저 선택해주세요", times: [] as string[] };
- if (timesQuery.isLoading)
- return { msg: "예약 가능시간 기다리는중..", times: [] };
- if (timesQuery.isError)
- return { msg: "휴무일 입니다. 다른 날짜를 선택해주세요", times: [] };
- if (times.length === 0)
- return { msg: "예약 가능한 시간이 없어요", times: [] };
+ if (!dateYmd) return { msg: "날짜를 먼저 선택해주세요", times: [] as string[] };
+ if (timesQuery.isLoading) return { msg: "예약 가능시간 기다리는중..", times: [] };
+ if (timesQuery.isError) return { msg: "휴무일 입니다. 다른 날짜를 선택해주세요", times: [] };
+ if (times.length === 0) return { msg: "예약 가능한 시간이 없어요", times: [] };
return { msg: null as string | null, times };
}, [dateYmd, timesQuery.isLoading, timesQuery.isError, times]);
@@ -168,8 +165,7 @@ export default function ReservationModal({
const prevDepsRef = useRef({ people, date, time });
useEffect(() => {
const prev = prevDepsRef.current;
- const changed =
- prev.people !== people || prev.date !== date || prev.time !== time;
+ const changed = prev.people !== people || prev.date !== date || prev.time !== time;
prevDepsRef.current = { people, date, time };
if (!changed) return;
const raf = requestAnimationFrame(() => {
@@ -203,9 +199,7 @@ export default function ReservationModal({
{restaurant.name}
-
- {restaurant.address}
-
+
{restaurant.address}
시간대
- {timeUi.msg ? (
-
{timeUi.msg}
- ) : null}
+ {timeUi.msg ?
{timeUi.msg}
: null}
{timeUi.times.map((t) => {
const active = time === t;
@@ -331,9 +323,7 @@ export default function ReservationModal({
})}
{noAvailableSeats ? (
-
- 예약 가능한 좌석이 없어요.{" "}
-
+
예약 가능한 좌석이 없어요.
) : null}
@@ -344,14 +334,10 @@ export default function ReservationModal({
)}
{!layout && canQueryTables && !availableTablesQuery.isLoading && (
-
- 테이블 배치 정보가 없어요.
-
+
테이블 배치 정보가 없어요.
)}
{!layout && canQueryTables && availableTablesQuery.isLoading && (
-
- 테이블 정보를 불러오는중..
-
+
테이블 정보를 불러오는중..
)}
{layout && canQueryTables && !noAvailableSeats && (
@@ -392,9 +378,7 @@ export default function ReservationModal({
) : null}
-
- 테이블 떨어져도 상관없어요
-
+
테이블 떨어져도 상관없어요
인원이 많을 경우 여러 테이블로 나누어 앉을 수 있습니다
@@ -430,13 +414,11 @@ export default function ReservationModal({
사전결제
-
- {Math.round(depositRate * 100)}% 정책
-
+ {Math.round(depositRate * 100)}% 정책
- 예약금은 메뉴 선택 후 메뉴 총액의{" "}
- {Math.round(depositRate * 100)}%로 계산됩니다.
+ 예약금은 메뉴 선택 후 메뉴 총액의 {Math.round(depositRate * 100)}%로
+ 계산됩니다.
예약 확정을 위해 예약금 결제가 필요합니다.
@@ -451,8 +433,7 @@ export default function ReservationModal({
onClick={() => {
if (!date || !time || !selectedTableId || !seatType) return;
const selectedTableNo =
- layout?.tables.find((t) => t.id === selectedTableId)?.tableNo ??
- null;
+ layout?.tables.find((t) => t.id === selectedTableId)?.tableNo ?? null;
onClickConfirm({
people,
date,
diff --git a/src/components/reservation/parts/TableMap.tsx b/src/components/reservation/parts/TableMap.tsx
index 237c14f..a339625 100644
--- a/src/components/reservation/parts/TableMap.tsx
+++ b/src/components/reservation/parts/TableMap.tsx
@@ -22,8 +22,7 @@ export default function TableMap({
? (layout.tables.find((t) => t.id === selectedTableId) ?? null)
: null;
- const activeSeatType: SeatType | null =
- selectedTable?.seatType ?? seatType ?? null;
+ const activeSeatType: SeatType | null = selectedTable?.seatType ?? seatType ?? null;
const shouldDimOthers = activeSeatType !== null;
@@ -37,8 +36,7 @@ export default function TableMap({
예약 불가
- {" "}
- 선택됨
+ 선택됨
다른 좌석유형
@@ -56,13 +54,9 @@ export default function TableMap({
{layout.tables.map((t: SeatTable) => {
const isAvailable = availableIds.has(t.id);
const isSelected = selectedTableId === t.id;
- const isActiveType = activeSeatType
- ? t.seatType === activeSeatType
- : true;
+ const isActiveType = activeSeatType ? t.seatType === activeSeatType : true;
const peopleText =
- t.minPeople === t.maxPeople
- ? `${t.minPeople}명`
- : `${t.minPeople}~${t.maxPeople}명`;
+ t.minPeople === t.maxPeople ? `${t.minPeople}명` : `${t.minPeople}~${t.maxPeople}명`;
return (
{t.tableNo}번
-
- {peopleText}
-
+
{peopleText}
);
diff --git a/src/components/restaurant/RestaurantCard.tsx b/src/components/restaurant/RestaurantCard.tsx
index 8e45b2e..bb3d4ba 100644
--- a/src/components/restaurant/RestaurantCard.tsx
+++ b/src/components/restaurant/RestaurantCard.tsx
@@ -1,4 +1,4 @@
-import { storeCategoryLabel, type RestaurantSummary } from "@/types/store";
+import { type RestaurantSummary, storeCategoryLabel } from "@/types/store";
type Props = {
restaurant: RestaurantSummary;
@@ -14,9 +14,7 @@ export default function RestaurantCard({ restaurant, onClick }: Props) {
>
-
- {restaurant.name}
-
+
{restaurant.name}
{storeCategoryLabel[restaurant.category]} • {restaurant.address}
diff --git a/src/components/restaurant/RestaurantDetailModal.tsx b/src/components/restaurant/RestaurantDetailModal.tsx
index b972483..b84a90d 100644
--- a/src/components/restaurant/RestaurantDetailModal.tsx
+++ b/src/components/restaurant/RestaurantDetailModal.tsx
@@ -1,11 +1,13 @@
-import type { Day, RestaurantDetail } from "@/types/store";
import { Clock, X } from "lucide-react";
-import { Button } from "../ui/button";
import { useNavigate } from "react-router-dom";
+
+import { useModalPresence } from "@/hooks/common/useModalPresence";
+import { cn } from "@/lib/utils";
import { useAuthStore } from "@/stores/useAuthStore";
+import type { Day, RestaurantDetail } from "@/types/store";
import { backdropMotionClass, panelMotionClass } from "@/utils/modalMotion";
-import { cn } from "@/lib/utils";
-import { useModalPresence } from "@/hooks/common/useModalPresence";
+
+import { Button } from "../ui/button";
type Props = {
open: boolean;
@@ -52,9 +54,7 @@ function formatBusinessHours(
return `${DAY_LABEL[day]}: ${open} - ${close}`;
});
- const breakLine = breakTime
- ? `브레이크타임: ${breakTime.start} - ${breakTime.end}`
- : null;
+ const breakLine = breakTime ? `브레이크타임: ${breakTime.start} - ${breakTime.end}` : null;
return { lines, breakLine };
}
@@ -114,9 +114,7 @@ export default function RestaurantDetailModal({
-
- 잠시만 기다려 주세요..
-
+
잠시만 기다려 주세요..
);
@@ -174,9 +172,7 @@ export default function RestaurantDetailModal({
if (status !== "success") return null;
if (!restaurant) return null;
- const tableImageUrls = Array.isArray(restaurant.tableImageUrls)
- ? restaurant.tableImageUrls
- : [];
+ const tableImageUrls = Array.isArray(restaurant.tableImageUrls) ? restaurant.tableImageUrls : [];
const { lines: hourLines, breakLine } = formatBusinessHours(
restaurant.businessHours,
restaurant.breakTime,
@@ -233,9 +229,7 @@ export default function RestaurantDetailModal({
{hourLines.map((t) => (
{t}
))}
- {breakLine ? (
-
{breakLine}
- ) : null}
+ {breakLine ?
{breakLine}
: null}
@@ -258,10 +252,7 @@ export default function RestaurantDetailModal({
) : (
{tableImageUrls.map((url, idx) => (
-
+

(
onSelect(r)} />
- {idx !== restaurants.length - 1 ? (
-
- ) : null}
+ {idx !== restaurants.length - 1 ? : null}
))}
diff --git a/src/components/restaurant/RestaurantListSkeleton.tsx b/src/components/restaurant/RestaurantListSkeleton.tsx
index 2e7ad6f..a06ef38 100644
--- a/src/components/restaurant/RestaurantListSkeleton.tsx
+++ b/src/components/restaurant/RestaurantListSkeleton.tsx
@@ -1,10 +1,6 @@
import RestaurantCardSkeleton from "./RestaurantCardSkeleton";
-export default function RestaurantListSkeleton({
- count = 8,
-}: {
- count?: number;
-}) {
+export default function RestaurantListSkeleton({ count = 8 }: { count?: number }) {
return (
void;
@@ -17,12 +19,7 @@ interface CompleteModalProps {
data: Partial
;
}
-export default function CompleteModal({
- isOpen,
- onClose,
- autoCloseMs,
- data,
-}: CompleteModalProps) {
+export default function CompleteModal({ isOpen, onClose, autoCloseMs, data }: CompleteModalProps) {
useEffect(() => {
if (!isOpen) return;
const t = window.setTimeout(() => {
@@ -38,16 +35,12 @@ export default function CompleteModal({
가게 등록 완료!
-
- 잠시 후 '내 가게 관리' 페이지로 이동합니다.
-
+ 잠시 후 '내 가게 관리' 페이지로 이동합니다.
가게 이름
-
- {data.storeName || "-"}
-
+ {data.storeName || "-"}
음식 종류
@@ -57,15 +50,11 @@ export default function CompleteModal({
주소
-
- {data.address || "-"}
-
+ {data.address || "-"}
전화번호
-
- {data.phoneNumber || "-"}
-
+ {data.phoneNumber || "-"}
운영 시간
diff --git a/src/components/store-registration/ConfirmModal.tsx b/src/components/store-registration/ConfirmModal.tsx
index a1cdd06..4f0f56a 100644
--- a/src/components/store-registration/ConfirmModal.tsx
+++ b/src/components/store-registration/ConfirmModal.tsx
@@ -1,3 +1,5 @@
+import type { ReactNode } from "react";
+
import {
Dialog,
DialogContent,
@@ -5,7 +7,6 @@ import {
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
-import type { ReactNode } from "react";
interface ConfirmModalProps {
isOpen: boolean;
@@ -39,18 +40,14 @@ export default function ConfirmModal({
{title}
-
- {description}
-
+ {description}
{confirmLabel}
diff --git a/src/components/store-registration/Menu.schema.ts b/src/components/store-registration/Menu.schema.ts
index 3899f15..0284784 100644
--- a/src/components/store-registration/Menu.schema.ts
+++ b/src/components/store-registration/Menu.schema.ts
@@ -31,9 +31,7 @@ export const MenuSchema = z.object({
.refine(
(file) => {
if (!file || typeof file === "string") return true;
- return file instanceof File
- ? ACCEPTED_IMAGE_TYPES.includes(file.type)
- : true;
+ return file instanceof File ? ACCEPTED_IMAGE_TYPES.includes(file.type) : true;
},
{
message: ".jpg, .png 형식의 이미지만 업로드 가능합니다.",
diff --git a/src/components/store-registration/MenuItemInput.tsx b/src/components/store-registration/MenuItemInput.tsx
index 93244b5..d98adca 100644
--- a/src/components/store-registration/MenuItemInput.tsx
+++ b/src/components/store-registration/MenuItemInput.tsx
@@ -1,24 +1,20 @@
+import { Trash2, Upload, X } from "lucide-react";
+import { type ChangeEvent, type MouseEvent, useEffect, useMemo, useRef } from "react";
import {
- Controller,
- useWatch,
type Control,
+ Controller,
type FieldErrors,
type UseFormRegister,
type UseFormSetValue,
type UseFormTrigger,
+ useWatch,
} from "react-hook-form";
-import type { MenuFormValues } from "./Menu.schema";
-import {
- useEffect,
- useMemo,
- useRef,
- type ChangeEvent,
- type MouseEvent,
-} from "react";
-import { Trash2, Upload, X } from "lucide-react";
+
import { Label } from "@/components/ui/label";
import { MenuCategoryLabel } from "@/types/menus";
+import type { MenuFormValues } from "./Menu.schema";
+
interface MenuItemInputProps {
index: number;
onDelete: () => void;
@@ -95,10 +91,7 @@ export default function MenuItemInput({
-
diff --git a/src/components/store-registration/StoreInfo.schema.ts b/src/components/store-registration/StoreInfo.schema.ts
index c2cb404..2f4f0ab 100644
--- a/src/components/store-registration/StoreInfo.schema.ts
+++ b/src/components/store-registration/StoreInfo.schema.ts
@@ -1,12 +1,6 @@
import { z } from "zod";
-const StoreCategoryEnum = z.enum([
- "KOREAN",
- "CHINESE",
- "JAPANESE",
- "WESTERN",
- "CAFE",
-]);
+const StoreCategoryEnum = z.enum(["KOREAN", "CHINESE", "JAPANESE", "WESTERN", "CAFE"]);
const DepositRateEnum = z.enum(["TEN", "TWENTY", "THIRTY", "FORTY", "FIFTY"]);
@@ -47,9 +41,7 @@ export const StoreInfoSchema = z
}
return Number(val);
},
- z
- .number()
- .min(30, { message: "예약 시간 간격은 최소 30분이어야 합니다." }),
+ z.number().min(30, { message: "예약 시간 간격은 최소 30분이어야 합니다." }),
),
openTime: z.string().min(1),
@@ -63,17 +55,12 @@ export const StoreInfoSchema = z
.refine((file) => file === undefined || file.size <= MAX_FILE_SIZE, {
message: "이미지 크기는 1MB 이하여야 합니다.",
})
- .refine(
- (file) =>
- file === undefined || ACCEPTED_IMAGE_TYPES.includes(file.type),
- {
- message: ".jpg, .png 형식의 이미지만 업로드 가능합니다.",
- },
- ),
+ .refine((file) => file === undefined || ACCEPTED_IMAGE_TYPES.includes(file.type), {
+ message: ".jpg, .png 형식의 이미지만 업로드 가능합니다.",
+ }),
})
.refine((data) => data.latitude !== 0 && data.longitude !== 0, {
- message:
- "선택하신 주소는 위치 확인이 어렵습니다. 정확한 주소를 다시 선택하세요.",
+ message: "선택하신 주소는 위치 확인이 어렵습니다. 정확한 주소를 다시 선택하세요.",
path: ["address"],
});
diff --git a/src/components/store-registration/StoreTransform.utils.ts b/src/components/store-registration/StoreTransform.utils.ts
index 5ddd4e4..a82269f 100644
--- a/src/components/store-registration/StoreTransform.utils.ts
+++ b/src/components/store-registration/StoreTransform.utils.ts
@@ -1,4 +1,5 @@
import type { BusinessHour, Day, RequestStoreCreateDto } from "@/types/store";
+
import type { StoreInfoFormValues } from "./StoreInfo.schema";
const formatSido = (sido: string): string => {
@@ -31,10 +32,7 @@ const formatTimeToBackend = (timeStr: string | undefined): string => {
return timeStr;
};
-const formatCoordinate = (
- value: number | string | undefined,
- name: string,
-): number => {
+const formatCoordinate = (value: number | string | undefined, name: string): number => {
if (value == null || value === undefined || value === "") {
throw new Error(`${name} 정보가 누락되었습니다. 주소를 다시 검색해주세요.`);
}
@@ -58,8 +56,7 @@ export const transformToRegister = (
longitude,
} = step2Data;
- const fullAddress =
- detailAddress && address ? `${address} ${detailAddress}` : address || "";
+ const fullAddress = detailAddress && address ? `${address} ${detailAddress}` : address || "";
const weekDays: Day[] = [
"MONDAY",
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index 46b3a48..dfe944f 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -1,6 +1,6 @@
-import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
+import * as React from "react";
import { cn } from "@/lib/utils";
@@ -14,17 +14,15 @@ const buttonVariants = cva(
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
- secondary:
- "bg-secondary text-secondary-foreground hover:bg-secondary/80",
- ghost:
- "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
- sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
- icon: "size-9",
+ "default": "h-9 px-4 py-2 has-[>svg]:px-3",
+ "sm": "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
+ "lg": "h-10 rounded-md px-6 has-[>svg]:px-4",
+ "icon": "size-9",
"icon-sm": "size-8",
"icon-lg": "size-10",
},
diff --git a/src/components/ui/calendar.tsx b/src/components/ui/calendar.tsx
index e5504fa..9655c31 100644
--- a/src/components/ui/calendar.tsx
+++ b/src/components/ui/calendar.tsx
@@ -1,17 +1,9 @@
+import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
import * as React from "react";
-import {
- ChevronDownIcon,
- ChevronLeftIcon,
- ChevronRightIcon,
-} from "lucide-react";
-import {
- DayPicker,
- getDefaultClassNames,
- type DayButton,
-} from "react-day-picker";
+import { type DayButton, DayPicker, getDefaultClassNames } from "react-day-picker";
-import { cn } from "@/lib/utils";
import { Button, buttonVariants } from "@/components/ui/button";
+import { cn } from "@/lib/utils";
function Calendar({
className,
@@ -38,16 +30,12 @@ function Calendar({
)}
captionLayout={captionLayout}
formatters={{
- formatMonthDropdown: (date) =>
- date.toLocaleString("default", { month: "short" }),
+ formatMonthDropdown: (date) => date.toLocaleString("default", { month: "short" }),
...formatters,
}}
classNames={{
root: cn("w-fit", defaultClassNames.root),
- months: cn(
- "flex gap-4 flex-col md:flex-row relative",
- defaultClassNames.months,
- ),
+ months: cn("flex gap-4 flex-col md:flex-row relative", defaultClassNames.months),
month: cn("flex flex-col w-full gap-4", defaultClassNames.month),
nav: cn(
"flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between",
@@ -75,10 +63,7 @@ function Calendar({
"relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md",
defaultClassNames.dropdown_root,
),
- dropdown: cn(
- "absolute bg-popover inset-0 opacity-0",
- defaultClassNames.dropdown,
- ),
+ dropdown: cn("absolute bg-popover inset-0 opacity-0", defaultClassNames.dropdown),
caption_label: cn(
"select-none font-medium",
captionLayout === "label"
@@ -93,10 +78,7 @@ function Calendar({
defaultClassNames.weekday,
),
week: cn("flex w-full mt-2", defaultClassNames.week),
- week_number_header: cn(
- "select-none w-(--cell-size)",
- defaultClassNames.week_number_header,
- ),
+ week_number_header: cn("select-none w-(--cell-size)", defaultClassNames.week_number_header),
week_number: cn(
"text-[0.8rem] select-none text-muted-foreground",
defaultClassNames.week_number,
@@ -108,10 +90,7 @@ function Calendar({
: "[&:first-child[data-selected=true]_button]:rounded-l-md",
defaultClassNames.day,
),
- range_start: cn(
- "rounded-l-md bg-accent",
- defaultClassNames.range_start,
- ),
+ range_start: cn("rounded-l-md bg-accent", defaultClassNames.range_start),
range_middle: cn("rounded-none", defaultClassNames.range_middle),
range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
today: cn(
@@ -122,43 +101,24 @@ function Calendar({
"text-muted-foreground aria-selected:text-muted-foreground",
defaultClassNames.outside,
),
- disabled: cn(
- "text-muted-foreground opacity-50",
- defaultClassNames.disabled,
- ),
+ disabled: cn("text-muted-foreground opacity-50", defaultClassNames.disabled),
hidden: cn("invisible", defaultClassNames.hidden),
...classNames,
}}
components={{
Root: ({ className, rootRef, ...props }) => {
- return (
-
- );
+ return
;
},
Chevron: ({ className, orientation, ...props }) => {
if (orientation === "left") {
- return (
-
- );
+ return
;
}
if (orientation === "right") {
- return (
-
- );
+ return
;
}
- return (
-
- );
+ return
;
},
DayButton: CalendarDayButton,
WeekNumber: ({ children, ...props }) => {
diff --git a/src/components/ui/checkbox.tsx b/src/components/ui/checkbox.tsx
index fa2bdb0..6ee1d4f 100644
--- a/src/components/ui/checkbox.tsx
+++ b/src/components/ui/checkbox.tsx
@@ -1,13 +1,10 @@
-import * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { CheckIcon } from "lucide-react";
+import * as React from "react";
import { cn } from "@/lib/utils";
-function Checkbox({
- className,
- ...props
-}: React.ComponentProps
) {
+function Checkbox({ className, ...props }: React.ComponentProps) {
return (
) {
+function Dialog({ ...props }: React.ComponentProps) {
return ;
}
-function DialogTrigger({
- ...props
-}: React.ComponentProps) {
+function DialogTrigger({ ...props }: React.ComponentProps) {
return ;
}
-function DialogPortal({
- ...props
-}: React.ComponentProps) {
+function DialogPortal({ ...props }: React.ComponentProps) {
return ;
}
-function DialogClose({
- ...props
-}: React.ComponentProps) {
+function DialogClose({ ...props }: React.ComponentProps) {
return ;
}
@@ -82,10 +74,7 @@ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
);
@@ -95,19 +84,13 @@ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
);
}
-function DialogTitle({
- className,
- ...props
-}: React.ComponentProps) {
+function DialogTitle({ className, ...props }: React.ComponentProps) {
return (
) {
+function Label({ className, ...props }: React.ComponentProps) {
return (
) {
+function Popover({ ...props }: React.ComponentProps) {
return ;
}
-function PopoverTrigger({
- ...props
-}: React.ComponentProps) {
+function PopoverTrigger({ ...props }: React.ComponentProps) {
return ;
}
@@ -37,10 +33,8 @@ function PopoverContent({
);
}
-function PopoverAnchor({
- ...props
-}: React.ComponentProps) {
+function PopoverAnchor({ ...props }: React.ComponentProps) {
return ;
}
-export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
+export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };
diff --git a/src/components/ui/separator.tsx b/src/components/ui/separator.tsx
index 72c18e3..ee78360 100644
--- a/src/components/ui/separator.tsx
+++ b/src/components/ui/separator.tsx
@@ -1,7 +1,7 @@
"use client";
-import * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator";
+import * as React from "react";
import { cn } from "@/lib/utils";
diff --git a/src/hooks/common/useConfirmClose.ts b/src/hooks/common/useConfirmClose.ts
index 216f9ad..e108669 100644
--- a/src/hooks/common/useConfirmClose.ts
+++ b/src/hooks/common/useConfirmClose.ts
@@ -1,8 +1,6 @@
export function useConfirmClose(onClose: () => void) {
return () => {
- const ok = window.confirm(
- "예약이 확정되지 않았습니다.\n예약화면을 벗어나시겠습니까?",
- );
+ const ok = window.confirm("예약이 확정되지 않았습니다.\n예약화면을 벗어나시겠습니까?");
if (ok) onClose();
};
}
diff --git a/src/hooks/queries/useAuth.ts b/src/hooks/queries/useAuth.ts
index c77a2c2..7029e86 100644
--- a/src/hooks/queries/useAuth.ts
+++ b/src/hooks/queries/useAuth.ts
@@ -1,14 +1,11 @@
+import { useMutation } from "@tanstack/react-query";
+
import { patchVerifyOwner, postLogin, postSignup } from "@/api/auth";
import type { LoginFormValues } from "@/components/auth/Login.schema";
import type { SignupFormValues } from "@/components/auth/Signup.schema";
import type { BusinessAuthFormValues } from "@/components/store-registration/BusinessAuth.schema";
import { useAuthActions } from "@/stores/useAuthStore";
-import type {
- ResponseLoginDto,
- ResponseVerifyOwnerDto,
- ResponseSignupDto,
-} from "@/types/auth";
-import { useMutation } from "@tanstack/react-query";
+import type { ResponseLoginDto, ResponseSignupDto, ResponseVerifyOwnerDto } from "@/types/auth";
export const useEmailSignup = () => {
return useMutation({
@@ -44,9 +41,7 @@ export const useVerifyOwner = () => {
return useMutation({
mutationFn: (data: BusinessAuthFormValues) => patchVerifyOwner(data),
onSuccess: () => {
- alert(
- "사업자 인증이 완료되었습니다. \n사장님 권한 적용을 위해 반드시 재로그인해주세요.",
- );
+ alert("사업자 인증이 완료되었습니다. \n사장님 권한 적용을 위해 반드시 재로그인해주세요.");
},
onError: (error) => {
console.error("사장 인증 실패:", error);
diff --git a/src/hooks/queries/useMenu.ts b/src/hooks/queries/useMenu.ts
index 5187599..6c046d1 100644
--- a/src/hooks/queries/useMenu.ts
+++ b/src/hooks/queries/useMenu.ts
@@ -1,17 +1,13 @@
+import { useMutation } from "@tanstack/react-query";
+
import { postMenuCreate, postMenuImage } from "@/api/menu";
import type { RequestMenuCreateDto, RequestMenuImageDto } from "@/types/menus";
-import { useMutation } from "@tanstack/react-query";
// 메뉴 등록 훅
export const useMenuCreate = () => {
return useMutation({
- mutationFn: ({
- storeId,
- body,
- }: {
- storeId: number;
- body: RequestMenuCreateDto;
- }) => postMenuCreate(storeId, body),
+ mutationFn: ({ storeId, body }: { storeId: number; body: RequestMenuCreateDto }) =>
+ postMenuCreate(storeId, body),
onError: (error) => {
console.error("메뉴 등록 실패", error);
},
@@ -21,13 +17,8 @@ export const useMenuCreate = () => {
// 메뉴 이미지 등록 훅
export const useMenuImage = () => {
return useMutation({
- mutationFn: ({
- storeId,
- body,
- }: {
- storeId: number;
- body: RequestMenuImageDto;
- }) => postMenuImage(storeId, body),
+ mutationFn: ({ storeId, body }: { storeId: number; body: RequestMenuImageDto }) =>
+ postMenuImage(storeId, body),
onError: (error) => {
console.error("메뉴 이미지 등록 실패:", error);
},
diff --git a/src/hooks/queries/useStore.ts b/src/hooks/queries/useStore.ts
index 0c28d7c..eb8dd8f 100644
--- a/src/hooks/queries/useStore.ts
+++ b/src/hooks/queries/useStore.ts
@@ -1,4 +1,5 @@
import { useMutation } from "@tanstack/react-query";
+
import { postMainImage, postRegisterStore } from "@/api/store";
import type { RequestMainImageDto, RequestStoreCreateDto } from "@/types/store";
@@ -15,13 +16,8 @@ export const useRegisterStore = () => {
// 식당 대표 이미지 등록 훅
export const useMainImage = () => {
return useMutation({
- mutationFn: ({
- storeId,
- body,
- }: {
- storeId: number;
- body: RequestMainImageDto;
- }) => postMainImage(storeId, body),
+ mutationFn: ({ storeId, body }: { storeId: number; body: RequestMainImageDto }) =>
+ postMainImage(storeId, body),
onError: (error) => {
console.error("대표 이미지 등록 실패:", error);
},
diff --git a/src/hooks/reservation/useAvailableTables.ts b/src/hooks/reservation/useAvailableTables.ts
index b5d44fe..36d263a 100644
--- a/src/hooks/reservation/useAvailableTables.ts
+++ b/src/hooks/reservation/useAvailableTables.ts
@@ -1,10 +1,8 @@
-import {
- getAvailableTables,
- type GetAvailableTablesParams,
-} from "@/api/endpoints/reservations";
-import { queryKeys } from "@/query/keys";
import { useQuery } from "@tanstack/react-query";
+import { getAvailableTables, type GetAvailableTablesParams } from "@/api/endpoints/reservations";
+import { queryKeys } from "@/query/keys";
+
export function useAvailableTables(params: GetAvailableTablesParams | null) {
return useQuery({
queryKey: params
diff --git a/src/hooks/reservation/useAvailableTimes.ts b/src/hooks/reservation/useAvailableTimes.ts
index 1d7b042..f0f18da 100644
--- a/src/hooks/reservation/useAvailableTimes.ts
+++ b/src/hooks/reservation/useAvailableTimes.ts
@@ -1,6 +1,7 @@
+import { useQuery } from "@tanstack/react-query";
+
import { getAvailableTimes } from "@/api/endpoints/reservations";
import { queryKeys } from "@/query/keys";
-import { useQuery } from "@tanstack/react-query";
type AvailableTimesInput = {
storeId?: string | number;
diff --git a/src/hooks/reservation/useCreateBooking.ts b/src/hooks/reservation/useCreateBooking.ts
index 23678a9..adf8cc6 100644
--- a/src/hooks/reservation/useCreateBooking.ts
+++ b/src/hooks/reservation/useCreateBooking.ts
@@ -1,6 +1,7 @@
-import { createBooking } from "@/api/endpoints/reservations";
import { useMutation } from "@tanstack/react-query";
+import { createBooking } from "@/api/endpoints/reservations";
+
export function useCreateBooking() {
return useMutation({
mutationFn: createBooking,
diff --git a/src/hooks/reservation/useMenus.ts b/src/hooks/reservation/useMenus.ts
index 4200c80..b09a629 100644
--- a/src/hooks/reservation/useMenus.ts
+++ b/src/hooks/reservation/useMenus.ts
@@ -1,12 +1,11 @@
+import { useQuery } from "@tanstack/react-query";
+
import { getMenus } from "@/api/endpoints/menus";
import { queryKeys } from "@/query/keys";
-import { useQuery } from "@tanstack/react-query";
export function useMenus(storeId?: string | number) {
const query = useQuery({
- queryKey: storeId
- ? queryKeys.restaurant.menus(storeId)
- : ["restaurant", "menus", "disabled"],
+ queryKey: storeId ? queryKeys.restaurant.menus(storeId) : ["restaurant", "menus", "disabled"],
queryFn: () => getMenus(String(storeId)),
enabled: !!storeId,
});
diff --git a/src/hooks/store/useRestaurantDetail.ts b/src/hooks/store/useRestaurantDetail.ts
index ccf24da..22dda3b 100644
--- a/src/hooks/store/useRestaurantDetail.ts
+++ b/src/hooks/store/useRestaurantDetail.ts
@@ -1,8 +1,9 @@
+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 { useQuery } from "@tanstack/react-query";
export function useRestaurantDetail(storeId: number | null) {
return useQuery({
diff --git a/src/hooks/store/useSearchStores.ts b/src/hooks/store/useSearchStores.ts
index 53b9aea..47431c3 100644
--- a/src/hooks/store/useSearchStores.ts
+++ b/src/hooks/store/useSearchStores.ts
@@ -1,6 +1,7 @@
+import { useQuery } from "@tanstack/react-query";
+
import { api } from "@/api/axios";
import type { Category, RestaurantSummary } from "@/types/store";
-import { useQuery } from "@tanstack/react-query";
type Params = {
keyword: string;
diff --git a/src/layouts/PublicLayout.tsx b/src/layouts/PublicLayout.tsx
index 75ee56a..7503de1 100644
--- a/src/layouts/PublicLayout.tsx
+++ b/src/layouts/PublicLayout.tsx
@@ -1,16 +1,12 @@
-import { logout } from "@/api/auth";
-import { getMemberInfo } from "@/api/endpoints/member";
-import { Button } from "@/components/ui/button";
-import {
- useAuthStore,
- useAuthToken,
- useIsAuthenticated,
- useUserId,
-} from "@/stores/useAuthStore";
import { isAxiosError } from "axios";
import { useEffect } from "react";
import { Link, Outlet, useNavigate } from "react-router-dom";
+import { logout } from "@/api/auth";
+import { getMemberInfo } from "@/api/endpoints/member";
+import { Button } from "@/components/ui/button";
+import { useAuthStore, useAuthToken, useIsAuthenticated, useUserId } from "@/stores/useAuthStore";
+
export default function PublicLayout() {
const nav = useNavigate();
const isAuthenticated = useIsAuthenticated();
@@ -30,9 +26,8 @@ export default function PublicLayout() {
let parsedId: number | null = null;
if (typeof rawId === "number") parsedId = rawId;
- if (typeof rawId === "string" && /^\d+$/.test(rawId))
- parsedId = Number(rawId);
- if (parsedId != null && Number.isFinite(parsedId)) {
+ if (typeof rawId === "string" && /^\d+$/.test(rawId)) parsedId = Number(rawId);
+ if (parsedId != null && Number.isFinite(parsedId) && Number.isSafeInteger(parsedId)) {
setUserId(parsedId);
} else {
console.warn("[member/info] invalid id:", rawId, member);
diff --git a/src/layouts/myPageLayout.tsx b/src/layouts/myPageLayout.tsx
index 0b78669..0e8272f 100644
--- a/src/layouts/myPageLayout.tsx
+++ b/src/layouts/myPageLayout.tsx
@@ -1,5 +1,6 @@
-import { Outlet, NavLink } from "react-router-dom";
import { Calendar, Crown, Settings, Store, User } from "lucide-react";
+import { NavLink, Outlet } from "react-router-dom";
+
import { cn } from "@/lib/utils";
const sidebarItems = [
@@ -27,17 +28,13 @@ export default function MyPageLayout() {
className={({ isActive }) =>
cn(
"relative flex h-12 items-center gap-3 px-5 py-7 text-md font-medium transition",
- isActive
- ? "bg-blue-50 text-blue-600"
- : "text-gray-700 hover:bg-gray-100",
+ isActive ? "bg-blue-50 text-blue-600" : "text-gray-700 hover:bg-gray-100",
)
}
>
{({ isActive }) => (
<>
- {isActive && (
-
- )}
+ {isActive && }
{label}
>
diff --git a/src/lib/kakao.ts b/src/lib/kakao.ts
index 8bcda8b..201e80c 100644
--- a/src/lib/kakao.ts
+++ b/src/lib/kakao.ts
@@ -7,9 +7,7 @@ export function loadKakaoMapSdk(): Promise {
const key = import.meta.env.VITE_KAKAO_JS_KEY as string | undefined;
if (!key) {
- return Promise.reject(
- new Error("VITE_KAKAO_JS_KEY가 .env에 없습니다. (.env 확인)"),
- );
+ return Promise.reject(new Error("VITE_KAKAO_JS_KEY가 .env에 없습니다. (.env 확인)"));
}
loadingPromise = new Promise((resolve, reject) => {
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index a5ef193..365058c 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -1,4 +1,4 @@
-import { clsx, type ClassValue } from "clsx";
+import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
diff --git a/src/main.tsx b/src/main.tsx
index 6bfc5a8..b03cc65 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -1,10 +1,13 @@
-import { StrictMode } from "react";
-import { createRoot } from "react-dom/client";
import "./index.css";
-import App from "./App.tsx";
+
import { QueryClientProvider } from "@tanstack/react-query";
+import { StrictMode } from "react";
+import { createRoot } from "react-dom/client";
+
import { queryClient } from "@/query/queryClient.ts";
+import App from "./App.tsx";
+
createRoot(document.getElementById("root")!).render(
diff --git a/src/pages/CustomerSupportPage.tsx b/src/pages/CustomerSupportPage.tsx
index ae1e9ee..2559723 100644
--- a/src/pages/CustomerSupportPage.tsx
+++ b/src/pages/CustomerSupportPage.tsx
@@ -1,8 +1,9 @@
+import { ChevronLeft, CircleHelp } from "lucide-react";
+import { Link } from "react-router-dom";
+
import SupportContact from "@/components/customer-support/SupportContact";
import SupportFAQ from "@/components/customer-support/SupportFAQ";
import SupportHero from "@/components/customer-support/SupportHero";
-import { ChevronLeft, CircleHelp } from "lucide-react";
-import { Link } from "react-router-dom";
export default function CustomerSupportPage() {
return (
@@ -27,9 +28,7 @@ export default function CustomerSupportPage() {
diff --git a/src/pages/LoginErrorPage.tsx b/src/pages/LoginErrorPage.tsx
index 3c9d3ba..877bf4f 100644
--- a/src/pages/LoginErrorPage.tsx
+++ b/src/pages/LoginErrorPage.tsx
@@ -1,6 +1,6 @@
+import { AlertCircle, Home } from "lucide-react";
import React from "react";
import { useNavigate } from "react-router-dom";
-import { AlertCircle, Home } from "lucide-react";
const LoginErrorPage: React.FC = () => {
const navigate = useNavigate();
@@ -17,9 +17,7 @@ const LoginErrorPage: React.FC = () => {
Error
-
- 로그인에 실패했습니다
-
+
로그인에 실패했습니다
소셜 로그인 연결 중 문제가 발생했습니다.
diff --git a/src/pages/NotFound.tsx b/src/pages/NotFound.tsx
index 2f7928d..42f4d57 100644
--- a/src/pages/NotFound.tsx
+++ b/src/pages/NotFound.tsx
@@ -1,6 +1,6 @@
+import { ArrowLeft, Home, Search } from "lucide-react";
import React from "react";
import { useNavigate } from "react-router-dom";
-import { Search, Home, ArrowLeft } from "lucide-react";
const NotFound: React.FC = () => {
const navigate = useNavigate();
@@ -25,9 +25,7 @@ const NotFound: React.FC = () => {
404
-
- 페이지를 찾을 수 없습니다
-
+
페이지를 찾을 수 없습니다
요청하신 페이지가 삭제되었거나 주소가 올바르지 않습니다.
diff --git a/src/pages/OAuthCallbackPage.tsx b/src/pages/OAuthCallbackPage.tsx
index bea0dd1..7620ba6 100644
--- a/src/pages/OAuthCallbackPage.tsx
+++ b/src/pages/OAuthCallbackPage.tsx
@@ -1,6 +1,7 @@
+import { Loader2 } from "lucide-react";
import React, { useEffect } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
-import { Loader2 } from "lucide-react";
+
import { useAuthActions } from "@/stores/useAuthStore";
const OAuthCallbackPage: React.FC = () => {
@@ -31,9 +32,7 @@ const OAuthCallbackPage: React.FC = () => {
-
- 로그인 처리 중...
-
+ 로그인 처리 중...
잠시만 기다려 주시면
diff --git a/src/pages/ReservationCompletePage.tsx b/src/pages/ReservationCompletePage.tsx
index 533cc06..5131a5b 100644
--- a/src/pages/ReservationCompletePage.tsx
+++ b/src/pages/ReservationCompletePage.tsx
@@ -1,9 +1,10 @@
+import { useEffect, useMemo, useState } from "react";
+import { useNavigate, useSearchParams } from "react-router-dom";
+
import { getUserBookings } from "@/api/endpoints/bookings";
import ReservationCompleteModal from "@/components/reservation/modals/ReservationCompleteModal";
import type { UserBookingItem } from "@/types/booking";
import { toHHmm } from "@/utils/time";
-import { useEffect, useMemo, useState } from "react";
-import { useNavigate, useSearchParams } from "react-router-dom";
export default function ReservationCompletePage() {
const [sp] = useSearchParams();
diff --git a/src/pages/SearchPage.tsx b/src/pages/SearchPage.tsx
index c0fd923..d7d0f3d 100644
--- a/src/pages/SearchPage.tsx
+++ b/src/pages/SearchPage.tsx
@@ -1,24 +1,22 @@
-import { useEffect, useMemo, useState } from "react";
import { Search } from "lucide-react";
-import RestaurantList from "@/components/restaurant/RestaurantList";
-import type { ReservationDraft } from "@/types/restaurant";
-import RestaurantDetailModal from "@/components/restaurant/RestaurantDetailModal";
-import ReservationModal from "@/components/reservation/modals/ReservationModal";
-import ReservationConfirmMoodal from "@/components/reservation/modals/ReservationConfirmModal";
+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";
import ReservationMenuModal from "@/components/reservation/modals/ReservationMenuModal";
-import type { RestaurantSummary } from "@/types/store";
-import KakaoMap from "@/components/map/KakaoMap";
+import ReservationModal from "@/components/reservation/modals/ReservationModal";
+import RestaurantDetailModal from "@/components/restaurant/RestaurantDetailModal";
+import RestaurantList from "@/components/restaurant/RestaurantList";
+import RestaurantListSkeleton from "@/components/restaurant/RestaurantListSkeleton";
import { useRestaurantDetail } from "@/hooks/store/useRestaurantDetail";
import { useSearchStores } from "@/hooks/store/useSearchStores";
-import type { CreateBookingResult } from "@/api/endpoints/reservations";
-import { toHHmm } from "@/utils/time";
-import RestaurantListSkeleton from "@/components/restaurant/RestaurantListSkeleton";
-import type {
- KakaoAddressSearchResult,
- KakaoAddressSearchStatus,
-} from "@/types/kakao";
+import type { KakaoAddressSearchResult, KakaoAddressSearchStatus } from "@/types/kakao";
import type { LatLng } from "@/types/map";
+import type { ReservationDraft } from "@/types/restaurant";
+import type { RestaurantSummary } from "@/types/store";
+import { toHHmm } from "@/utils/time";
function isValidLatLng(loc: unknown): loc is LatLng {
return (
@@ -74,9 +72,7 @@ export default function SearchPage() {
const [draft, setDraft] = useState(null);
const [paymentOpen, setPaymentOpen] = useState(false);
- const [coords, setCoords] = useState<{ lat: number; lng: number } | null>(
- null,
- );
+ const [coords, setCoords] = useState<{ lat: number; lng: number } | null>(null);
const [hasSearched, setHasSearched] = useState(false);
const FALLBACK_COORDS = { lat: 37.5665, lng: 126.978 };
const [mapCenter, setMapCenter] = useState(FALLBACK_COORDS);
@@ -91,9 +87,7 @@ export default function SearchPage() {
lng: number;
} | null>(null);
const searchQuery = useSearchStores(
- searchParams
- ? { ...searchParams, radius: 50, sort: "DISTANCE", page: 1, limit: 20 }
- : null,
+ searchParams ? { ...searchParams, radius: 50, sort: "DISTANCE", page: 1, limit: 20 } : null,
);
const results = useMemo(() => searchQuery.data ?? [], [searchQuery.data]);
@@ -110,9 +104,7 @@ export default function SearchPage() {
const normalizeDraft = (d: ReservationDraft): ReservationDraft => {
const normalizedTime = toHHmm(d.time);
const safeTime =
- !normalizedTime || normalizedTime.includes("undefined")
- ? undefined
- : normalizedTime;
+ !normalizedTime || normalizedTime.includes("undefined") ? undefined : normalizedTime;
return {
...d,
@@ -188,8 +180,7 @@ export default function SearchPage() {
return;
}
navigator.geolocation.getCurrentPosition(
- (pos) =>
- resolve({ lat: pos.coords.latitude, lng: pos.coords.longitude }),
+ (pos) => resolve({ lat: pos.coords.latitude, lng: pos.coords.longitude }),
() => resolve(FALLBACK_COORDS),
{ enableHighAccuracy: false, timeout: 5000 },
);
@@ -320,10 +311,7 @@ export default function SearchPage() {
검색 결과가 없어요.