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;