diff --git a/public/img/closeWhite.png b/public/img/closeWhite.png new file mode 100644 index 0000000..7efa016 Binary files /dev/null and b/public/img/closeWhite.png differ diff --git a/public/img/grande.png b/public/img/grande.png new file mode 100644 index 0000000..c2149f9 Binary files /dev/null and b/public/img/grande.png differ diff --git a/src/components/molecules/BasketMenu.tsx b/src/components/molecules/BasketMenu.tsx new file mode 100644 index 0000000..1618ba1 --- /dev/null +++ b/src/components/molecules/BasketMenu.tsx @@ -0,0 +1,80 @@ +import { FC, useEffect, useState } from "react"; +import { BasketMenuType, MenuType } from "../../types/menu"; +import { useSession } from "../../context/basketContext"; + +interface IProps { + basketIdx: number; + menuIdx: number; + menuPrice: number; + menuName: string; + menuImage: string; + orderDetailCount: number; + menuTemperature?: string | null; + menuSize?: string | null; +} + +const BasketMenu: FC = ({ + basketIdx, + menuIdx, + menuName, + menuPrice, + menuImage, + orderDetailCount, + menuTemperature, + menuSize, +}) => { + const { removeBasket, plusMenu, minusMenu } = useSession(); + + const clickMinus = () => { + if (orderDetailCount <= 1) { + return; + } + minusMenu(basketIdx); + }; + + const clickPlus = () => { + plusMenu(basketIdx); + }; + + return ( +
+
+ removeBasket(basketIdx)} + /> +
+
+ +
+

{menuName}

+
+

+ {(menuPrice * orderDetailCount).toLocaleString()}원 +

+
+
clickMinus()} + > + - +
+
+ {orderDetailCount} +
+
clickPlus()} + > + + +
+
+
+
+
+
+ ); +}; + +export default BasketMenu; diff --git a/src/components/molecules/Menu.tsx b/src/components/molecules/Menu.tsx index 0d9edd0..599ea2e 100644 --- a/src/components/molecules/Menu.tsx +++ b/src/components/molecules/Menu.tsx @@ -1,6 +1,5 @@ import { FC, useEffect, useState } from "react"; -import { ApiClient } from "../../apis/apiClient"; -import { MenuType } from "../../types/menu"; +import { BasketMenuType, MenuType } from "../../types/menu"; import { useSession } from "../../context/basketContext"; interface IProps { @@ -9,6 +8,10 @@ interface IProps { menuImage: string; menuPrice: number; categoryIdx: number; + setOpenModalFunc: () => void; + setMenuFunc: (menu: BasketMenuType) => void; + count: number; + setCountFunc: () => void; } const Menu: FC = ({ @@ -17,26 +20,42 @@ const Menu: FC = ({ menuImage, menuPrice, categoryIdx, + setOpenModalFunc, + setMenuFunc, + count, + setCountFunc, }) => { const { addBasket } = useSession(); - type BasketMenuType = { - basketIdx: number; - menuIdx: number; - orderDetailCount: number; - menuTemperature?: string | null; - menuSize?: string | null; - }; - const MenuClick = () => { - alert("ㅎㅇ"); - if (categoryIdx === 4 || categoryIdx === 5) { + if (categoryIdx == 4 || categoryIdx == 5) { + addBasket({ + basketIdx: count, + menuIdx: menuIdx, + menuName: menuName, + menuPrice: menuPrice, + menuImage: menuImage, + orderDetailCount: 1, + }); + setCountFunc(); + return; } + + setMenuFunc({ + basketIdx: count, + menuIdx: menuIdx, + menuName: menuName, + menuPrice: menuPrice, + menuImage: menuImage, + orderDetailCount: 1, + }); + + setOpenModalFunc(); }; return (
-
+
MenuClick()}>

diff --git a/src/components/organisms/BasketCard.tsx b/src/components/organisms/BasketCard.tsx new file mode 100644 index 0000000..c82cd4d --- /dev/null +++ b/src/components/organisms/BasketCard.tsx @@ -0,0 +1,30 @@ +import { FC } from "react"; +import { BasketMenuType, MenuType } from "../../types/menu"; +import BasketMenu from "../molecules/BasketMenu"; + +interface IProps { + basketList?: BasketMenuType[]; +} + +const BasketCard: FC = ({ basketList }) => { + return ( +

+
    + {basketList?.map((menu: BasketMenuType) => ( +
  • + +
  • + ))} +
+
+ ); +}; + +export default BasketCard; diff --git a/src/components/organisms/CustomModal.tsx b/src/components/organisms/CustomModal.tsx index 1e5f019..e8241f9 100644 --- a/src/components/organisms/CustomModal.tsx +++ b/src/components/organisms/CustomModal.tsx @@ -1,22 +1,168 @@ -import React from "react"; +import React, { useRef, useState } from "react"; +import { BasketMenuType } from "../../types/menu"; +import { useSession } from "../../context/basketContext"; const CustomModal = ({ message, modalToggle, + menu, + setCountFunc, }: { message: string; modalToggle: () => void; + menu: BasketMenuType; + setCountFunc: () => void; }) => { + const [temper, setTemper] = useState("hot"); + const [size, setSize] = useState("tall"); + + const { addBasket } = useSession(); + + const clickTemp = (clickedTemp: string) => { + setTemper(clickedTemp); + }; + + const clickSize = (clickedSize: string) => { + setSize(clickedSize); + }; + + const clickConfirm = () => { + if (size == "grande") { + menu.menuPrice += 500; + } else if (size == "venti") { + menu.menuPrice += 1000; + } + + addBasket({ + basketIdx: menu.basketIdx, + menuIdx: menu.menuIdx, + menuName: menu.menuName, + menuPrice: menu.menuPrice, + menuImage: menu.menuImage, + orderDetailCount: 1, + menuTemperature: temper, + menuSize: size, + }); + setCountFunc(); + modalToggle(); + }; + return (
-
-

{message}

- +
+
+ modalToggle()} + /> +
+
+ {message} +
+ {/* 온도영역 */} +
+

온도

+
+
clickTemp("hot")} + > + HOT +
+
clickTemp("ice")} + > + ICE +
+
+
+ {/* 사이즈영역 */} +
+

컵 선택

+
+
clickSize("tall")} + > + +

+ 톨 +

+

355ml

+
+
clickSize("grande")} + > + +

+ 그란데 +

+

473ml

+
+
clickSize("venti")} + > + +

+ 벤티 +

+

591ml

+
+
+
+
+
clickConfirm()} + > + 선택 완료 +
+
); diff --git a/src/components/organisms/MenuCard.tsx b/src/components/organisms/MenuCard.tsx index 0c9bb76..8f27157 100644 --- a/src/components/organisms/MenuCard.tsx +++ b/src/components/organisms/MenuCard.tsx @@ -1,17 +1,24 @@ import { FC } from "react"; -import { MenuType } from "../../types/menu"; +import { BasketMenuType, MenuType } from "../../types/menu"; import Menu from "../molecules/Menu"; interface IProps { data?: MenuType[]; + setOpenModalFunc: () => void; + setMenuFunc: (menu: BasketMenuType) => void; + count: number; + setCountFunc: () => void; } -const MenuCard: FC = ({ data }) => { +const MenuCard: FC = ({ + data, + setOpenModalFunc, + setMenuFunc, + count, + setCountFunc, +}) => { return (
- {/*
-
확인용
-
*/}
    {data?.map((menu: MenuType) => (
  • @@ -21,6 +28,10 @@ const MenuCard: FC = ({ data }) => { menuImage={menu.menuImage} menuPrice={menu.menuPrice} categoryIdx={menu.categoryIdx} + setOpenModalFunc={setOpenModalFunc} + setMenuFunc={setMenuFunc} + count={count} + setCountFunc={setCountFunc} />
  • ))} diff --git a/src/context/basketContext.tsx b/src/context/basketContext.tsx index 4d41264..9984255 100644 --- a/src/context/basketContext.tsx +++ b/src/context/basketContext.tsx @@ -5,10 +5,10 @@ import { useContext, useReducer, } from "react"; -import { BasketMenuType } from "../types/menu"; +import { BasketMenuType, BasketType } from "../types/menu"; type BasketContextProp = { - basket: BasketMenuType[]; + basket: BasketType; // 장바구니에 담는 함수 addBasket: (menu: BasketMenuType) => void; // 장바구니에서 삭제하는 함수 @@ -31,59 +31,66 @@ type Action = } | { type: "removeBasket" | "plusMenu" | "minusMenu"; payload: number }; -const DefaultBasket: BasketMenuType[] = []; +const DefaultBasket: BasketType = { + totalPrice: 0, + basketList: [] as BasketMenuType[], +}; const BasketContext = createContext({ - basket: [] as BasketMenuType[], + basket: { totalPrice: 0, basketList: [] as BasketMenuType[] }, addBasket: (menu: BasketMenuType) => {}, removeBasket: (basketIdx: number) => {}, plusMenu: (basketIdx: number) => {}, minusMenu: (basketIdx: number) => {}, }); -const reducer = ( - basketList: BasketMenuType[], - { type, payload }: Action, -): BasketMenuType[] => { +const reducer = (basket: BasketType, { type, payload }: Action): BasketType => { let newer: BasketMenuType[] = []; + let newer2: number = basket.totalPrice; switch (type) { case "addBasket": - newer = [...basketList, payload]; + newer = [...basket.basketList, payload]; + newer2 += payload.menuPrice; break; case "removeBasket": - for (let i = 0; i < basketList.length; i++) { - let menu = basketList[i]; + for (let i = 0; i < basket.basketList.length; i++) { + let menu = basket.basketList[i]; if (menu.basketIdx == payload) { - i == basketList.length - 1 - ? (newer = basketList.slice(0, i)) + i == basket.basketList.length - 1 + ? (newer = basket.basketList.slice(0, i)) : (newer = [ - ...basketList.slice(0, i), - ...basketList.slice(i + 1, basketList.length), + ...basket.basketList.slice(0, i), + ...basket.basketList.slice(i + 1, basket.basketList.length), ]); + newer2 -= menu.menuPrice * menu.orderDetailCount; break; } } break; case "plusMenu": - for (let i = 0; i < basketList.length; i++) { - let menu = basketList[i]; + for (let i = 0; i < basket.basketList.length; i++) { + let menu = basket.basketList[i]; if (menu.basketIdx == payload) { - newer = [...basketList]; + newer = [...basket.basketList]; + console.log(newer[i].orderDetailCount); newer[i].orderDetailCount++; + console.log("after : " + newer[i].orderDetailCount); + newer2 += menu.menuPrice; break; } } break; case "minusMenu": - for (let i = 0; i < basketList.length; i++) { - let menu = basketList[i]; + for (let i = 0; i < basket.basketList.length; i++) { + let menu = basket.basketList[i]; if (menu.basketIdx == payload) { - newer = [...basketList]; + newer = [...basket.basketList]; newer[i].orderDetailCount--; + newer2 -= menu.menuPrice; break; } } @@ -93,7 +100,12 @@ const reducer = ( break; } - return newer; + let res: BasketType = { + totalPrice: newer2, + basketList: newer, + }; + + return res; }; export const BasketProvider = ({ children }: ProviderProps) => { diff --git a/src/pages/MenuPage.tsx b/src/pages/MenuPage.tsx index 771c436..f100fed 100644 --- a/src/pages/MenuPage.tsx +++ b/src/pages/MenuPage.tsx @@ -1,16 +1,24 @@ import { useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; import { ApiClient } from "../apis/apiClient"; import { useQuery } from "react-query"; import MenuCard from "../components/organisms/MenuCard"; import Category from "../components/ui/Category"; import { CategoryType } from "../types/category"; +import CustomModal from "../components/organisms/CustomModal"; +import { BasketMenuType } from "../types/menu"; +import { useSession } from "../context/basketContext"; +import BasketMenu from "../components/molecules/BasketMenu"; +import BasketCard from "../components/organisms/BasketCard"; const MenuPage = () => { const [categoryIdx, setCategoryIdx] = useState(1); const [categoryList, setCategoryList] = useState([]); const [openModal, setOpenModal] = useState(false); - const navigate = useNavigate(); + const [selectedMenu, setSelectedMenu] = useState(); + const [count, setCount] = useState(1); + + const { basket } = useSession(); + const { isLoading, data } = useQuery({ queryKey: ["menus", categoryIdx], queryFn: () => { @@ -22,7 +30,6 @@ const MenuPage = () => { useEffect(() => { const getCategoryListFunc = async () => { const res = await ApiClient.getInstance().getCategoryList(); - console.log(res); setCategoryList(res); }; getCategoryListFunc(); @@ -32,19 +39,44 @@ const MenuPage = () => { setCategoryIdx(idx); }; + const setOpenModalFunc = () => { + setOpenModal(true); + }; + + const setMenuFunc = (menu: BasketMenuType) => { + setSelectedMenu(menu); + }; + + const setCountFunc = () => { + setCount(count + 1); + }; + return (
    -
    +
    +
    + {openModal && ( + setOpenModal(!openModal)} + menu={selectedMenu!} + setCountFunc={setCountFunc} + /> + )} +
    +
    +
    banner
    +
    {/* 메뉴 버튼 영역 */}
    -
      +
        {categoryList?.map((category: CategoryType) => (
      • {
    {/* 메뉴 선택 영역 */}
    - +
    {/* 장바구니 영역 */} -
      - {categoryList?.map((category: CategoryType, index) => ( -
    • - ))} -
    +
    +
    +

    주문내역

    +

    + 총 가격 : {basket.totalPrice.toLocaleString()}원 +

    +
    + +
    ); }; diff --git a/src/types/menu.d.ts b/src/types/menu.d.ts index ab8cef8..43de1e2 100644 --- a/src/types/menu.d.ts +++ b/src/types/menu.d.ts @@ -10,10 +10,16 @@ type MenuType = { type BasketMenuType = { basketIdx: number; menuIdx: number; + menuName: string; menuPrice: number; + menuImage: string; orderDetailCount: number; menuTemperature?: string | null; menuSize?: string | null; }; +type BasketType = { + totalPrice: number; + basketList: BasketMenuType[]; +}; -export { MenuType, BasketMenuType }; +export { MenuType, BasketMenuType, BasketType };