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
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions apps/nowait-user/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ node_modules
dist
dist-ssr
*.local
yarn.lock

# Editor directories and files
.vscode/*
Expand Down
Binary file added apps/nowait-user/public/default-menu.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 17 additions & 42 deletions apps/nowait-user/src/api/order.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,29 @@
import axios from "axios";
import type {
CreateOrderServerResponse,
OrderDetailsServerResponse,
OrderType,
} from "../types/order/order";

const SERVER_URI = import.meta.env.VITE_SERVER_URI;
export const api = axios.create({
withCredentials: true,
});

interface OrderType {
depositorName: string;
items: { menuId: string; quantity: number }[];
}

interface ServerResponse {
success: boolean;
response: {
orderId: number;
storeId: number;
storeName: string;
sessionId: string;
depositorName: string;
orderItems: { menuId: string; quantity: number }[];
status: string;
totalPrice: number;
};
}

//음식 주문하기
//주문 생성
export const createOrder = async (
storeId: string,
tableId: string,
payload: OrderType
) => {
try {
const res = await axios.post<ServerResponse>(
`${SERVER_URI}/orders/create/${storeId}/${tableId}`,
payload
);
return res.data;
} catch (error) {
console.log(error);
}
): Promise<CreateOrderServerResponse> => {
const res = await api.post(`/orders/create/${storeId}/${tableId}`, payload);
return res.data;
};

//주문내역 가져오기
export const getMyOrderList = async (
//주문 내역 조회
export const getOrderDetails = async (
storeId: string | undefined,
tableId: string
) => {
try {
const res = await axios.get(
`${SERVER_URI}/orders/items/${storeId}/${tableId}`
);
return res.data;
} catch (error) {
console.log(error);
}
): Promise<OrderDetailsServerResponse> => {
const res = await api.get(`/orders/items/${storeId}/${tableId}`);
return res.data;
};
3 changes: 3 additions & 0 deletions apps/nowait-user/src/assets/icon/back.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions apps/nowait-user/src/assets/icon/fullfieldBookmark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions apps/nowait-user/src/components/EmptyPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useNavigate, useParams } from "react-router-dom";
import { SmallActionButton } from "./SmallActionButton";
import Add from "../assets/icon/Add.svg?react";

interface PropsType {
mode: "default" | "orderDetails";
title: string;
buttonText: string;
}

const EmptyPage = ({ mode, title, buttonText }: PropsType) => {
const navigate = useNavigate();
const { storeId } = useParams();
return (
<div className={`min-h-screen flex flex-col justify-center items-center ${mode=== "default"? "bg-white":"bg-black-15"}`}>
<h1 className="whitespace-pre-line text-16-regular text-black-80 mb-5 text-center">
{title}
</h1>
<SmallActionButton
mode={mode}
type="button"
ariaLabel="메뉴 추가"
onClick={() => navigate(`/${storeId}`)}
>
{buttonText}
<Add className="w-4 h-4" fill="currentColor" />
</SmallActionButton>
</div>
);
};

export default EmptyPage;
4 changes: 3 additions & 1 deletion apps/nowait-user/src/components/SmallActionButton.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
interface PropsType {
mode? : "default" | "orderDetails"
type?: "button" | "submit" | "reset";
ariaLabel: string;
children: React.ReactNode;
onClick: () => void;
className?: string;
}
export const SmallActionButton = ({
mode = "default",
type = "button",
children,
onClick,
Expand All @@ -16,7 +18,7 @@ export const SmallActionButton = ({
<button
type={type}
aria-label={ariaLabel}
className={`${className} py-2 px-4 rounded-[12px] border border-[#ececec] text-black-70`}
className={`${className} py-2 px-4 rounded-[12px] border-2 bg-white ${mode==="default" ? "border-[#ececec] text-black-70" : "border-[#dddddd] text-black-80"}`}
onClick={onClick}
>
<p className="flex items-center justify-center gap-1 text-[14px] font-bold">
Expand Down
4 changes: 2 additions & 2 deletions apps/nowait-user/src/components/common/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ const MenuItem = ({ data, mode }: PropsType) => {
<h2 className="text-black-70">{data.price.toLocaleString()}원</h2>
</div>
<img
className="w-[90px] h-[90px] bg-black-25 rounded-[12px] object-cover"
src={`${data.image}` || ""}
className="w-[80px] h-[80px] bg-black-25 rounded-[12px] object-cover"
src={`${data.image}` || "/default-menu.png"}
alt="음식 메뉴 이미지"
/>
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const SuccessMessagePage = ({
<SmallActionButton
type="button"
ariaLabel="주문내역 확인"
onClick={() => navigate(`/${storeId}`)} //주문 내역 페이지로 변경하기
onClick={() => navigate(`/${storeId}/orderDetails`)}
>
주문내역 확인
</SmallActionButton>
Expand Down
21 changes: 21 additions & 0 deletions apps/nowait-user/src/components/order/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Back from "../../assets/icon/back.svg?react";

interface PropsType {
title: string;
}

const Header = ({ title }: PropsType) => {
return (
<div>
<div className="flex justify-between items-center px-5 py-2.5">
<button>
<Back />
</button>
<h1 className="text-title-16-bold">{title}</h1>
<div className="w-2.5"></div>
</div>
</div>
);
};

export default Header;
2 changes: 1 addition & 1 deletion apps/nowait-user/src/pages/order/addMenu/AddMenuPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const AddMenuPage = () => {
return (
<div className="flex flex-col h-screen">
<div className="flex-1 overflow-y-auto px-5">
<h1 className="-mx-5 h-[375px] bg-black-25">
<h1 className="-mx-5">
<img className="w-full" src={image} alt="음식 메뉴 이미지" />
</h1>
<div className="py-8">
Expand Down
16 changes: 15 additions & 1 deletion apps/nowait-user/src/pages/order/home/RedirectToStorePage.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
import { useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { useCartStore } from "../../../stores/cartStore";

const RedirectToStorePage = () => {
const { storeId, tableId } = useParams();
const navigate = useNavigate();
const { cart, clearCart } = useCartStore();

useEffect(() => {
if (storeId && tableId) {
//테이블 아이디 로컬스토리지 저장(다른 방법 생각)
//장바구니에 메뉴를 담고 다른 주점이나 테이블로 이동했을 때 장바구니 초기화
const prevStoreId = localStorage.getItem("storeId");
const prevTableId = localStorage.getItem("tableId");
//이전 storeId, tableId랑 비교
const isDifferentStore = prevStoreId && prevStoreId !== storeId;
const isDifferentTable = prevTableId && prevTableId !== tableId;
//이전 storeId 또는 tableId가 변경 되었고, 장바구니에 메뉴가 담겨있을 시 장바구니 비우기
if ((isDifferentStore || isDifferentTable) && cart.length > 0) {
localStorage.removeItem("depositorName")
clearCart();
}
//테이블 아이디 로컬스토리지 저장
localStorage.setItem("storeId", storeId);
localStorage.setItem("tableId", tableId);
navigate(`/${storeId}`, { replace: true });
}
Expand Down
13 changes: 1 addition & 12 deletions apps/nowait-user/src/pages/order/home/components/StoreHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
import { useNavigate, useParams } from "react-router-dom";
import { getMyOrderList } from "../../../../api/order";

const StoreHeader = () => {
const navigate = useNavigate();
const { storeId } = useParams();
const tableId = localStorage.getItem("tableId");

const getMyOrderListButton = async () => {
try {
const res = await getMyOrderList(storeId, tableId!);
navigate(`/${storeId}/myOrderList`, { state: res });
} catch (error) {
console.log(error);
}
};

return (
<section className="flex justify-between items-start mb-7">
Expand All @@ -22,7 +11,7 @@ const StoreHeader = () => {
<h2 className="text-text-16-medium">5번 테이블</h2>
</div>
<button
onClick={getMyOrderListButton}
onClick={() => navigate(`/${storeId}/orderDetails`)}
className="text-14-semibold bg-black-20 py-2 px-2.5 rounded-[8px] text-black-70 cursor-pointer"
>
주문내역
Expand Down
79 changes: 79 additions & 0 deletions apps/nowait-user/src/pages/order/orderDetails/OrderDetailsPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import EmptyOrderDetails from "./components/EmptyOrderDetails";
import { useQuery } from "@tanstack/react-query";
import { getOrderDetails } from "../../../api/order";
import { useParams } from "react-router-dom";

interface OrderDetailsType {
orderId: string;
menuName: string;
price: number;
quantity: number;
}

const OrderDetailsPage = () => {
const { storeId } = useParams();
const tableId = localStorage.getItem("tableId");

const { data } = useQuery({
queryKey: ["orderDetails", storeId, tableId],
queryFn: () => getOrderDetails(storeId, tableId!),
select: (data) => data.response[0],
});
console.log(data)
//주문내역 status에 따른 값, 컬러 객체
const statusMap = {
WAITING_FOR_PAYMENT: { label: "입금 대기 중", color: "text-black-90" },
COOKING: { label: "조리 중", color: "text-black-90" },
COOKED: { label: "조리 완료", color: "text-black-60" },
};
type OrderStatus = keyof typeof statusMap;
const statusData = statusMap[data?.status as OrderStatus];

//주문내역 없을 시
if (!data || data?.items?.length < 1) return <EmptyOrderDetails />;

return (
<div>
<div className="bg-black-15 min-h-screen py-[30px] px-5">
<h1 className="text-headline-24-bold mb-[23px] text-black-90">
주문내역 <span className="text-primary">{data.items.length}건</span>
</h1>
<ul>
<li className="p-[22px] bg-white rounded-[22px] mb-4">
<div className="mb-7.5">
<h1 className={`text-title-20-bold mb-2${statusData.color} `}>
{statusData.label}
</h1>
<p className="text-14-regular text-black-60">
2025년 7월 1일 19:49
</p>
</div>
<ul className="border-b-1 border-[#ececec] pb-5 mb-5">
{data?.items?.map((item: OrderDetailsType) => {
return (
<li
key={item.orderId}
className="flex justify-between items-center mb-2.5 last:mb-0"
>
<h1 className="text-16-regular text-black-90">
{item?.menuName}
</h1>
<span className="text-16-regular text-black-60">
{item?.quantity}
</span>
</li>
);
})}
</ul>
<div className="flex justify-between items-center">
<h1 className="text-16-semibold">결제금액</h1>
<h2 className="text-16-semibold">36,000원</h2>
</div>
</li>
</ul>
</div>
</div>
);
};

export default OrderDetailsPage;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import EmptyPage from "../../../../components/EmptyPage";

const EmptyOrderDetails = () => {
return (
<EmptyPage
mode="orderDetails"
title={`주문 내역이 없습니다.\n첫 주문을 시작해 보세요.`}
buttonText="주문하기"
/>
);
};

export default EmptyOrderDetails;
3 changes: 3 additions & 0 deletions apps/nowait-user/src/pages/order/orderList/OrderListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { AnimatePresence } from "framer-motion";
import EmptyCart from "./components/EmptyCart";
import { SmallActionButton } from "../../../components/SmallActionButton";
import Add from "../../../assets/icon/Add.svg?react";
import Header from "../../../components/order/Header";

const OrderListPage = () => {
const navigate = useNavigate();
Expand All @@ -18,6 +19,7 @@ const OrderListPage = () => {

return (
<div>
<Header title="장바구니"/>
<section className="flex flex-col flex-grow min-h-screen-dvh pt-7 px-5 pb-[124px]">
<h1 className="text-headline-24-bold mb-5">
주문 총 <span className="text-primary">{cart.length}건</span>
Expand All @@ -37,6 +39,7 @@ const OrderListPage = () => {
})}
</AnimatePresence>
<SmallActionButton
mode="default"
type="button"
ariaLabel="메뉴 추가하기"
onClick={() => navigate(`/${storeId}`)}
Expand Down
Loading