diff --git a/apps/nowait-admin/src/pages/AdminOrders/DetailCard.tsx b/apps/nowait-admin/src/pages/AdminOrders/DetailCard.tsx index 87f0c159..9145028a 100644 --- a/apps/nowait-admin/src/pages/AdminOrders/DetailCard.tsx +++ b/apps/nowait-admin/src/pages/AdminOrders/DetailCard.tsx @@ -4,6 +4,7 @@ import { PaymentCheckModal, CookedModal, CookCompleteModal, + OrderCancelModal, } from "./OrderPageModal"; import type { MenuDetails } from "../../types/order"; import { getTableBackgroundColor } from "../../utils/tableColors"; @@ -34,6 +35,7 @@ const DetailCard = ({ onSuccess, }: DetailCardProps) => { const [showModal, setShowModal] = useState(false); + const [showCancelModal, setShowCancelModal] = useState(false); const menuEntries = menuDetails ? Object.entries(menuDetails) : []; @@ -41,16 +43,30 @@ const DetailCard = ({ setShowModal(true); }; + const handleCancelClick = () => { + setShowCancelModal(true); + }; + const handleCloseModal = () => { setShowModal(false); }; + const handleCloseCancelModal = () => { + setShowCancelModal(false); + }; + const handleModalSuccess = () => { setShowModal(false); onSuccess?.(); onClose(); // 디테일 화면도 닫기 }; + const handleCancelModalSuccess = () => { + setShowCancelModal(false); + onSuccess?.(); + onClose(); // 디테일 화면도 닫기 + }; + // 타입에 따른 설정 const getConfig = () => { if (type === "payment") { @@ -163,9 +179,26 @@ const DetailCard = ({ -
- {config.actionText} -
+ {type === "payment" ? ( +
+
+ 주문 취소 +
+
+ {config.actionText} +
+
+ ) : ( +
+ {config.actionText} +
+ )} {/* Modal 오버레이 */} @@ -185,6 +218,20 @@ const DetailCard = ({ /> )} + + {/* 주문 취소 Modal 오버레이 */} + {showCancelModal && ( +
+ +
+ )} ); }; diff --git a/apps/nowait-admin/src/pages/AdminOrders/OrderPageModal.tsx b/apps/nowait-admin/src/pages/AdminOrders/OrderPageModal.tsx index 86cff3e3..451e4b6a 100644 --- a/apps/nowait-admin/src/pages/AdminOrders/OrderPageModal.tsx +++ b/apps/nowait-admin/src/pages/AdminOrders/OrderPageModal.tsx @@ -1,6 +1,7 @@ import { useUpdateOrderStatus } from "../../hooks/useUpdateOrderStatus"; import { getTableBackgroundColor } from "../../utils/tableColors"; import { DropdownLoader } from "@repo/ui"; +import { cancelOrder } from "../../utils/AdminApi"; // Payment Check Modal interface PaymentCheckModalProps { @@ -196,5 +197,74 @@ const CookCompleteModal = ({ /> ); -export { PaymentCheckModal, CookedModal, CookCompleteModal, OrderStatusModal }; -export type { PaymentCheckModalProps, CookedModalProps, OrderStatusModalProps }; +// Order Cancel Modal +interface OrderCancelModalProps { + orderId: number; + onClose: () => void; + onSuccess?: () => void; +} + +const OrderCancelModal = ({ + orderId, + onClose, + onSuccess, +}: OrderCancelModalProps) => { + const cancelReasons = [ + { id: "SOLD_OUT", label: "메뉴 품절" }, + { id: "SIMPLE_CANCEL", label: "단순 취소" }, + { id: "ETC", label: "기타" }, + ]; + + const handleReasonSelect = async (reason: string) => { + try { + await cancelOrder(orderId, reason); + onSuccess?.(); + onClose(); + } catch (error) { + console.error("주문 취소 실패:", error); + // 에러 처리 (예: 토스트 메시지 표시) + } + }; + + return ( +
e.stopPropagation()} + > +
+
+ 주문 취소 사유를 선택해주세요 +
+
+ 선택 즉시 주문이 취소됩니다. +
+
+ +
+ {cancelReasons.map((reason) => ( +
handleReasonSelect(reason.id)} + > + {reason.label} +
+ ))} +
+
+ ); +}; + +export { + PaymentCheckModal, + CookedModal, + CookCompleteModal, + OrderStatusModal, + OrderCancelModal, +}; +export type { + PaymentCheckModalProps, + CookedModalProps, + OrderStatusModalProps, + OrderCancelModalProps, +}; diff --git a/apps/nowait-admin/src/types/order.ts b/apps/nowait-admin/src/types/order.ts index 19656d22..41575eb9 100644 --- a/apps/nowait-admin/src/types/order.ts +++ b/apps/nowait-admin/src/types/order.ts @@ -1,5 +1,9 @@ // 주문 상태 타입 -export type OrderStatus = "WAITING_FOR_PAYMENT" | "COOKING" | "COOKED"; +export type OrderStatus = + | "WAITING_FOR_PAYMENT" + | "COOKING" + | "COOKED" + | "CANCELLED"; // 메뉴 상세 정보 타입 export interface MenuDetail { diff --git a/apps/nowait-admin/src/utils/AdminApi.tsx b/apps/nowait-admin/src/utils/AdminApi.tsx index d434dc2f..e63db226 100644 --- a/apps/nowait-admin/src/utils/AdminApi.tsx +++ b/apps/nowait-admin/src/utils/AdminApi.tsx @@ -12,7 +12,6 @@ const AdminApi = axios.create({ AdminApi.interceptors.request.use( (config) => { const token = localStorage.getItem("adminToken"); - console.log(token, "토큰 알려줘"); if (token) { config.headers.Authorization = `Bearer ${token}`; } @@ -34,4 +33,24 @@ AdminApi.interceptors.response.use( } ); +// 주문 취소 API +export const cancelOrder = async (orderId: number, reason: string) => { + try { + // 1. 주문 취소 사유 전송 (DELETE) + await AdminApi.delete(`/admin/orders/${orderId}`, { + data: { reason }, + }); + + // 2. 주문 상태를 CANCEL로 변경 (PATCH) + await AdminApi.patch(`/admin/orders/status/${orderId}`, { + orderStatus: "CANCELLED", + }); + + return { success: true }; + } catch (error) { + console.error("주문 취소 실패:", error); + throw error; + } +}; + export default AdminApi;