Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
10 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion src/app/(header-nav)/hakgwan/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import AdBannerCarousel from "@/features/banner/components/AdBannerCarousel";
import styles from "./page.module.css";
import { getHakgwanMenus, HakgwanMenuData } from "@/features/menu/services/hakgwanMenuService";
import { getHakgwanMenus, HakgwanMenuData } from "@/features/menu/services/hakgwanMenuService.server";
import MenuPageContainer from "@/features/menu/components/MenuPageContainer";

export default async function HakgwanMainPage() {
Expand Down
2 changes: 1 addition & 1 deletion src/app/(header-nav)/my/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client" // TODO: 추후 로그아웃 정상 구현 후 SSR 변경

import { useRouter } from "next/navigation";
import { logout } from "@/features/auth/api/logoutApi";
import { logout } from "@/features/auth/api/logoutApi.client";

export default function MyMainPage() {
const router = useRouter();
Expand Down
24 changes: 8 additions & 16 deletions src/app/(header-only)/cart/page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
import EmptyCartView from "@/features/cart/components/view/EmptyCartView";
import CartMenuCard from "@/features/cart/components/card/CartMenuCard";
import CartView from "@/features/cart/components/view/CartView";
import { getCartInfo } from "@/features/cart/services/cartService.server";

export default function CartPage() {
return (
// <>
// <CartMenuCard menuId={1}
// imageSrc="/tmp/menu/menu-1.png"
// title="김치제육 덮밥"
// price={6000} />
// <CartMenuCard menuId={1}
// imageSrc="/tmp/menu/menu-1.png"
// title="김치제육 덮밥"
// rank={1}
// price={6000} />
// </>
<EmptyCartView/>
);
export default async function CartPage() {

const cartInfo = await getCartInfo();
const empty = cartInfo.totalQuantity === 0;

return empty ? <EmptyCartView /> : <CartView />
}
22 changes: 22 additions & 0 deletions src/app/(header-only)/order/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"use client";

import { useRouter } from "next/navigation";

export default function OrderPage() {
const router = useRouter();

const onClick = () => {
router.replace("/");
}
return (
<div>
주문 페이지 입니다
<button
className="bg-blue-400"
onClick={onClick}
>
홈 화면 이동
</button>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"use client";
import { apiClient } from "@/shared/lib/api/apiClient";
import { LoginRequest, LoginResponse } from "@/features/auth/types/loginTypes";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"use client";
import { apiClient } from "@/shared/lib/api/apiClient";

export async function logout(): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion src/features/auth/components/form/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useRouter } from "next/navigation";
import { CustomError } from "@/shared/lib/errors/customError";
import { ERROR_MESSAGE } from "@/shared/lib/errors/errorCodes";
import { LoginRequest } from "@/features/auth/types/loginTypes";
import { login } from "@/features/auth/api/loginApi";
import { login } from "@/features/auth/api/loginApi.client";

export default function LoginForm() {
const router = useRouter();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"use client";
import { CartApiResponse, CartRequest } from "@/features/cart/types/cartType";
import { apiClient } from "@/shared/lib/api/apiClient";

Expand Down
11 changes: 11 additions & 0 deletions src/features/cart/api/cartApi.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import "server-only";
import { CartApiResponse } from "@/features/cart/types/cartType";
import { apiServer } from "@/shared/lib/api/apiServer";

/**
* 장바구니 조회 (SSR)
* GET /api/cart
*/
export async function getCart(): Promise<CartApiResponse> {
return await apiServer.get<CartApiResponse>("/api/cart");
}
43 changes: 43 additions & 0 deletions src/features/cart/components/bar/PaymentBar.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
.container {
display: flex;
justify-content: center;
align-items: center;

border-radius: 1.25rem 1.5rem 0 0;
background-color: var(--color-white);

box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.20);

width: 100%;
height: var(--payment-bar-height);

padding-inline: 1.5rem;
padding-top: 1rem;
padding-bottom: 1.25rem;
}

.button {
display: flex;
justify-content: center;
align-items: center;
width: 100%;

border-radius: 1rem;
background-color: var(--color-main);

padding-block: 1.25rem;
}

.label {
color: var(--color-white);
text-align: center;

font-size: var(--text-base);
font-weight: var(--font-bold);
line-height: var(--line-height-single);
letter-spacing: var(--letter-spacing);
}

@theme {
--payment-bar-height: 5.75rem;
}
26 changes: 26 additions & 0 deletions src/features/cart/components/bar/PaymentBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import styles from "./PaymentBar.module.css";
import { formatNumberWithComma } from "@/shared/utils/number/utils";

interface PaymentBarProps {
totalPrice: number;
onClick: () => void;
}

export default function PaymentBar({
totalPrice,
onClick
}: PaymentBarProps) {

const formattedPrice = formatNumberWithComma(totalPrice);

return (
<div className={styles.container}>
<button
onClick={onClick}
className={styles.button}
>
<span className={styles.label}>{formattedPrice}원 결제하기</span>
</button>
</div>
)
}
2 changes: 0 additions & 2 deletions src/features/cart/components/card/CartMenuCard.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
position: relative;
gap: 1rem;

border: 1px solid black;

width: 100%;

background-color: var(--color-white);
Expand Down
20 changes: 20 additions & 0 deletions src/features/cart/components/list/CartMenuList.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.container {
display: flex;
flex-direction: column;
width: 100%;

border-radius: 1rem;
border: 1px solid var(--color-gray-100);
background-color: var(--color-white);

padding-block: 1.25rem;
}

.cardWrapper {
padding-inline: 1.25rem;
}

.separatorWrapper {
padding-inline: 1rem;
padding-block: 1rem;
}
36 changes: 36 additions & 0 deletions src/features/cart/components/list/CartMenuList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { CartInfo } from "@/features/cart/types/cartType";
import CartMenuCard from "@/features/cart/components/card/CartMenuCard";
import SeparationBar from "@/shared/components/bar/SeparationBar";
import React from "react";
import styles from "./CartMenuList.module.css";

interface CartMenuListProps {
cartInfo: CartInfo
}

export default function CartMenuList({
cartInfo,
}: CartMenuListProps) {
return (
<div className={styles.container}>
{cartInfo.cartItems.map((item, index) => (
<React.Fragment key={item.menuId}>
<div className={styles.cardWrapper}>
<CartMenuCard
menuId={item.menuId}
imageSrc={item.menuImageSrc}
title={item.menuName}
price={item.price}
quantity={item.quantity}
/>
</div>
{index < cartInfo.cartItems.length - 1 && (
<div className={styles.separatorWrapper}>
<SeparationBar />
</div>
)}
</React.Fragment>
))}
</div>
);
}
20 changes: 20 additions & 0 deletions src/features/cart/components/view/CartView.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.container {
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;

padding-inline: 1.25rem;
padding-top: 0.75rem;
padding-bottom: var(--payment-bar-height);
}

.paymentBarWrapper {
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);

width: 100%;
max-width: var(--container-3xl);
}
40 changes: 40 additions & 0 deletions src/features/cart/components/view/CartView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"use client";

import CartMenuList from "@/features/cart/components/list/CartMenuList";
import styles from "./CartView.module.css";
import PaymentBar from "@/features/cart/components/bar/PaymentBar";
import { useRouter } from "next/navigation";
import { useCart } from "@/features/cart/hooks/useCart";
import EmptyCartView from "@/features/cart/components/view/EmptyCartView";

export default function CartView() {

const router = useRouter();
const { cartInfo } = useCart();

const handleClick = () => {
router.replace("/order");
}

if (!cartInfo) {
return null;
}

// 장바구니가 비어있으면 EmptyCartView 표시
if (cartInfo.totalQuantity === 0) {
return <EmptyCartView />;
}

return (
<div className={styles.container}>
<CartMenuList cartInfo={cartInfo} />

<div className={styles.paymentBarWrapper}>
<PaymentBar
totalPrice={cartInfo.totalPrice}
onClick={handleClick}
/>
</div>
</div>
);
}
22 changes: 17 additions & 5 deletions src/features/cart/hooks/useCart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { CartInfo, CartRequest } from "@/features/cart/types/cartType";
import { getCartInfo, upsertCartInfo } from "@/features/cart/services/cartService";
import { useCallback, useRef } from "react";
import { useCallback, useMemo, useRef } from "react";
import { getCartInfo, upsertCartInfo } from "@/features/cart/services/cartService.client";

interface UseCartReturn {
cartInfo: CartInfo | undefined,
Expand Down Expand Up @@ -37,6 +37,18 @@ export function useCart(): UseCartReturn {
retry: 1,
});

// menuId 기준으로 순서 정렬
const sortedCartInfo = useMemo(() => {
if (!cartInfo) {
return undefined;
}

return {
...cartInfo,
cartItems: [...cartInfo.cartItems].sort((a, b) => a.menuId - b.menuId)
};
}, [cartInfo]);

const upsertCartMutation = useMutation<CartInfo, Error, CartRequest>({
mutationFn: (request: CartRequest) => upsertCartInfo(request),
onSuccess: (data: CartInfo) => {
Expand All @@ -51,9 +63,9 @@ export function useCart(): UseCartReturn {
* 특정 메뉴의 현재 수량 조회
*/
const getMenuQuantity = useCallback((menuId: number): number => {
const cartItem = cartInfo?.cartItems.find((item) => item.menuId === menuId);
const cartItem = sortedCartInfo?.cartItems.find((item) => item.menuId === menuId);
return cartItem?.quantity ?? 0;
}, [cartInfo]);
}, [sortedCartInfo]);

/**
* 메뉴 1개 추가 (기존 수량 + 1)
Expand Down Expand Up @@ -151,7 +163,7 @@ export function useCart(): UseCartReturn {
}, [getMenuQuantity, upsertCartMutation]);

return {
cartInfo,
cartInfo: sortedCartInfo,
isLoading,
error,
getMenuQuantity,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";
import { CartApiResponse, CartInfo, CartRequest } from "@/features/cart/types/cartType";
import { getCart, upsertCart } from "@/features/cart/api/cartApi";
import { toCartInfo } from "@/features/cart/utils/cartMapper";
import { getCart, upsertCart } from "@/features/cart/api/cartApi.client";

export async function getCartInfo(): Promise<CartInfo> {
const cartApiResponse: CartApiResponse = await getCart();
Expand Down
9 changes: 9 additions & 0 deletions src/features/cart/services/cartService.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import "server-only";
import { CartApiResponse, CartInfo } from "@/features/cart/types/cartType";
import { getCart } from "@/features/cart/api/cartApi.server";
import { toCartInfo } from "@/features/cart/utils/cartMapper";

export async function getCartInfo():Promise<CartInfo> {
const cartApiResponse: CartApiResponse = await getCart();
return toCartInfo(cartApiResponse);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "server-only";
import { apiServer } from "@/shared/lib/api/apiServer";
import { CafeteriaApiResponse } from "@/features/menu/types/cafeteriaType";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "server-only";
import { apiServer } from "@/shared/lib/api/apiServer";
import { CategoryApiResponse } from "@/features/menu/types/categoryType";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import "server-only";
import { apiServer } from "@/shared/lib/api/apiServer";
import { MenuApiResponse } from "@/features/menu/types/menuType";

Expand Down
Loading