Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions apps/nowait-admin/src/hooks/useGetOrderList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useQuery } from "@tanstack/react-query";
import adminApi from "../utils/AdminApi";

// 주문 데이터 인터페이스
export interface Order {
id: number;
tableId: number;
depositorName: string;
totalPrice: number | null;
status: "WAITING_FOR_PAYMENT" | "COOKING" | "COOKED";
createdAt: string;
}

interface OrderResponse {
success: boolean;
response: Order[];
error: null;
}

// 주문 목록을 가져오는 함수
const fetchOrders = async (): Promise<Order[]> => {
try {
const token = localStorage.getItem("adminToken");
const res = await adminApi.get<OrderResponse>(`/admin/orders/1`, {
headers: {
Authorization: `Bearer ${token}`,
},
});

// 응답 데이터가 유효한지 확인
if (res.data && res.data.success && Array.isArray(res.data.response)) {
return res.data.response;
}

// 응답이 유효하지 않으면 빈 배열 반환
return [];
} catch (error) {
console.error("주문 목록 조회 실패:", error);
// 에러가 발생해도 빈 배열을 반환하여 undefined 방지
return [];
}
};

// 주문 목록을 가져오는 hook
export const useGetOrderList = () => {
return useQuery({
queryKey: ["orders"],
queryFn: fetchOrders,
refetchInterval: 30000, // 30초마다 자동 새로고침
});
};
220 changes: 115 additions & 105 deletions apps/nowait-admin/src/pages/AdminOrders/AdminOrders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,93 +2,53 @@ import { useState } from "react";
import { PaymentCard, CookCard } from "./OrderCard";
import RefreshIcon from "../../assets/refresh.svg?react";
import CookedPage from "./CookedPage";
import { useGetOrderList } from "../../hooks/useGetOrderList";

const AdminOrders = () => {
const [activeTab, setActiveTab] = useState<"전체" | "조리 완료">("전체");

// 통합 주문 데이터
const ordersData = [
{
id: 1,
tableNumber: 5,
minutesAgo: 10,
status: "payment_waiting", // 입금 대기
menus: [
{ name: "김치찌개", quantity: 2 },
{ name: "된장찌개", quantity: 1 },
],
totalAmount: 26000,
createdAt: "오후 6:50",
},
{
id: 2,
tableNumber: 2,
minutesAgo: 5,
status: "payment_waiting", // 입금 대기
menus: [
{ name: "비빔밥", quantity: 1 },
{ name: "된장국", quantity: 1 },
],
totalAmount: 18000,
createdAt: "오후 6:55",
},
{
id: 3,
tableNumber: 7,
minutesAgo: 15,
status: "payment_waiting", // 입금 대기
menus: [
{ name: "불고기", quantity: 2 },
{ name: "냉면", quantity: 1 },
{ name: "공기밥", quantity: 1 },
],
totalAmount: 35000,
createdAt: "오후 6:45",
},
{
id: 4,
tableNumber: 3,
minutesAgo: 20,
status: "cooking", // 조리 중
menus: [
{ name: "메뉴명한줄로떨어져야야야야피피피피", quantity: 1 },
{ name: "된장된장찌개", quantity: 1 },
{ name: "계란후라이", quantity: 1 },
{ name: "달달한 쏘야볶음", quantity: 1 },
],
totalAmount: 28000,
createdAt: "오후 7:24",
},
{
id: 5,
tableNumber: 6,
minutesAgo: 30,
status: "cooked", // 조리 완료
menus: [
{ name: "묵은지 삼겹 김치 말이찜", quantity: 2 },
{ name: "공기밥", quantity: 2 },
{ name: "된장국", quantity: 1 },
],
totalAmount: 23000,
createdAt: "오후 7:24",
},
{
id: 6,
tableNumber: 1,
minutesAgo: 25,
status: "cooked", // 조리 완료
menus: [{ name: "김치볶음밥", quantity: 1 }],
totalAmount: 8000,
createdAt: "오후 19:24",
},
];
// API에서 주문 데이터 가져오기
const { data: orders = [], isLoading, error, refetch } = useGetOrderList();

// 시간 포맷팅 함수 (17:30 형식)
const getFormattedTime = (createdAt: string) => {
const date = new Date(createdAt);
const hours = date.getHours().toString().padStart(2, "0");
const minutes = date.getMinutes().toString().padStart(2, "0");
return `${hours}:${minutes}`;
};

// 시간 포맷팅 함수
const formatTime = (createdAt: string) => {
const date = new Date(createdAt);
const hours = date.getHours();
const minutes = date.getMinutes();
const period = hours >= 12 ? "오후" : "오전";
const displayHours = hours > 12 ? hours - 12 : hours === 0 ? 12 : hours;
return `${period} ${displayHours}:${minutes.toString().padStart(2, "0")}`;
};

// 테스트를 위해 일부 주문을 다른 상태로 변경
const testOrders = orders.map((order, index) => {
if (index % 3 === 1) {
return { ...order, status: "COOKING" as const };
} else if (index % 3 === 2) {
return { ...order, status: "COOKED" as const };
}
return order;
});

// 상태별 데이터 필터링
const paymentWaitingData = ordersData.filter(
(order) => order.status === "payment_waiting"
const paymentWaitingData = testOrders.filter(
(order) => order.status === "WAITING_FOR_PAYMENT"
);
const cookingData = ordersData.filter((order) => order.status === "cooking");
const cookedData = ordersData.filter((order) => order.status === "cooked");
const cookingData = testOrders.filter((order) => order.status === "COOKING");
const cookedData = testOrders.filter((order) => order.status === "COOKED");

// 새로고침 핸들러
const handleRefresh = () => {
refetch();
};

return (
<div className="flex flex-col w-full">
Expand Down Expand Up @@ -117,7 +77,10 @@ const AdminOrders = () => {
</div>
</div>

<div className="flex icon-m items-center justify-center cursor-pointer">
<div
className="flex icon-m items-center justify-center cursor-pointer"
onClick={handleRefresh}
>
<RefreshIcon />
</div>
</div>
Expand All @@ -128,56 +91,103 @@ const AdminOrders = () => {
<div className="flex flex-1 flex-col">
<div className="flex flex-row ml-1.5 gap-1.5">
<div className="text-title-20-bold text-[#363D4A]">입금 대기</div>
<div className="text-title-20-bold text-primary">5</div>
<div className="text-title-20-bold text-primary">
{paymentWaitingData.length}
</div>
</div>

<div className="flex flex-row mt-3.5 border border-black-30 rounded-t-2xl px-5 py-2.5 gap-2.5 bg-white">
<div className="flex flex-row mt-3.5 border border-black-30 rounded-t-2xl px-5 py-2.5 gap-2.5 bg-[#E7ECF0]">
<div className="flex text-14-medium text-black-60">테이블</div>
<div className="flex text-14-medium text-black-60">입금 내역</div>
</div>
<div className="flex flex-col gap-7.5 rounded-b-2xl border border-t-0 border-black-30 h-full bg-white px-6 py-5.5">
{paymentWaitingData.map((payment) => (
<PaymentCard
key={payment.id}
tableNumber={payment.tableNumber}
minutesAgo={payment.minutesAgo}
menuCount={payment.menus.reduce(
(total, menu) => total + menu.quantity,
0
)}
totalAmount={payment.totalAmount}
/>
))}
{isLoading ? (
<div className="flex flex-col items-center justify-center h-full py-20 text-center">
<div className="text-16-medium text-black-60">로딩 중...</div>
</div>
) : paymentWaitingData.length > 0 ? (
paymentWaitingData.map((payment) => (
<PaymentCard
key={payment.id}
tableNumber={payment.tableId}
timeText={getFormattedTime(payment.createdAt)}
depositorName={payment.depositorName}
totalAmount={payment.totalPrice || 0}
/>
))
) : (
<div className="flex flex-col items-center justify-center h-full py-20 text-center">
<div className="text-16-medium text-black-60">
{error
? "데이터를 불러오지 못했습니다."
: "아직 입금 대기 중인 주문이 없어요!"}
</div>
</div>
)}
</div>
</div>

{/* 조리 중 블럭 */}
<div className="flex flex-1 flex-col">
<div className="flex flex-row ml-1.5 gap-1.5">
<div className="text-title-20-bold text-[#363D4A]">조리 중</div>
<div className="text-title-20-bold text-[#363D4A]">3</div>
<div className="text-title-20-bold text-[#363D4A]">
{cookingData.length}
</div>
</div>

<div className="flex flex-row mt-3.5 border border-black-30 rounded-t-2xl px-5 py-2.5 gap-2.5 bg-white">
<div className="flex flex-row mt-3.5 border border-black-30 rounded-t-2xl px-5 py-2.5 gap-2.5 bg-[#E7ECF0]">
<div className="flex text-14-medium text-black-60">테이블</div>
<div className="flex text-14-medium text-black-60 mr-[15ch]">
메뉴
</div>
<div className="flex text-14-medium text-black-60">수량</div>
</div>
<div className="flex flex-col gap-7.5 rounded-b-2xl border border-t-0 border-black-30 h-full bg-white px-6 py-5.5">
{cookingData.map((cooking) => (
<CookCard
key={cooking.id}
tableNumber={cooking.tableNumber}
menus={cooking.menus}
/>
))}
{isLoading ? (
<div className="flex flex-col items-center justify-center h-full py-20 text-center">
<div className="text-16-medium text-black-60">로딩 중...</div>
</div>
) : cookingData.length > 0 ? (
cookingData.map((cooking) => (
<CookCard
key={cooking.id}
tableNumber={cooking.tableId}
menus={[{ name: cooking.depositorName, quantity: 1 }]} // API에서 메뉴 정보가 없으므로 depositorName 사용
/>
))
) : (
<div className="flex flex-col items-center justify-center h-full py-20 text-center">
<div className="text-16-medium text-black-60">
{error
? "데이터를 불러오지 못했습니다."
: "조리 중인 주문이 없어요!"}
</div>
</div>
)}
</div>
</div>
</div>
) : (
<CookedPage cookedOrders={cookedData} />
<CookedPage
cookedOrders={cookedData.map((order, index) => ({
id: order.id,
tableNumber: order.tableId,
depositorName: order.depositorName,
menus:
index % 2 === 0
? [{ name: "김치찌개", quantity: 1 }]
: [
{ name: "김치찌개", quantity: 1 },
{ name: "된장찌개", quantity: 2 },
{ name: "불고기", quantity: 1 },
],
totalAmount: order.totalPrice || 0,
createdAt: getFormattedTime(order.createdAt),
}))}
isLoading={isLoading}
error={error}
/>
)}
</div>
);
Expand Down
Loading