diff --git a/src/components/views/PageComponent/OrderStatus.css b/src/components/views/PageComponent/OrderStatus.css index e4560c8..23e6b7c 100644 --- a/src/components/views/PageComponent/OrderStatus.css +++ b/src/components/views/PageComponent/OrderStatus.css @@ -1,6 +1,5 @@ .status-container { width: 100%; - height: 94vh; } .status-nav-bar__wrapper { @@ -221,22 +220,27 @@ white-space: nowrap; } -.status-detail__wrapper{ +.status-detail__wrapper { display: flex; justify-content: flex-end; } .status-detail { - display: inline-block; - font-size: 0.625rem; - font-family: "Pretendard Variable"; - font-weight: 500; + display: flex; + width: 5.5625rem; + height: 1.5rem; + flex-shrink: 0; border-radius: 0.625rem; - border: 1px solid #838383; - /* height: 1.5em; */ - line-height: 1.5em; - margin: calc((1.5em - 2px) / 2) 0; - padding: 1% 4%; + border: 1px solid #4f4f4f; + color: #4f4f4f; + font-family: "Pretendard Variable"; + font-size: 0.6875rem; + font-style: normal; + font-weight: 700; + line-height: 130%; /* 0.89375rem */ + letter-spacing: -0.00688rem; + align-items: center; + justify-content: center; } /* 주문 취소 */ diff --git a/src/components/views/PageComponent/OrderStatus.jsx b/src/components/views/PageComponent/OrderStatus.jsx index fb780d4..7e8d719 100644 --- a/src/components/views/PageComponent/OrderStatus.jsx +++ b/src/components/views/PageComponent/OrderStatus.jsx @@ -1,87 +1,60 @@ -import axios from "axios"; -import React, { useEffect, useState } from "react"; +import React, { useState, useEffect, useMemo } from "react"; import { Link, useLocation } from "react-router-dom"; import logo from "../../../assets/images/berry.png"; import cancleLogo from "../../../assets/images/icon_cancleLogo.png"; -// import berry from "../../../assets/images/berry.svg"; import clock from "../../../assets/images/icon_clock.svg"; import close from "../../../assets/images/icon_close.svg"; import refresh from "../../../assets/images/icon_refresh.svg"; import Modal from "../../views/Modal/Modal"; import "./OrderStatus.css"; - -import { message } from "antd"; import moment from "moment/moment"; import Progressbar from "../ProgressBar/ProgressBar"; +import useFetchCurrentOrder from "../../../hooks/useFetchCurrentOrder"; +import useCancelOrder from "../../../hooks/useCancelOrder"; function OrderStatus() { - const apiUrl = process.env.REACT_APP_API_ROOT; const location = useLocation(); const params = new URLSearchParams(location.search); const orderId = params.get("orderId"); const [degree, setDegree] = useState(0); const [isOpen, setIsOpen] = useState(false); - const [statusList, setStatusList] = useState({}); - // const navigate = useNavigate(); + const [refreshKey, setRefreshKey] = useState(0); + const { cancels, estimatedTime, inout, name, orderName, orderNum, progress } = + useFetchCurrentOrder(orderId, refreshKey); + const cancelOrder = useCancelOrder(); - const progressList = { - ORDER: 0, - MAKE: 1, - COMPLETE: 2, - PICKUP: 3, - CANCEL: 4, - }; + const progressList = useMemo( + () => ({ + ORDER: 0, + MAKE: 1, + COMPLETE: 2, + PICKUP: 3, + CANCEL: 4, + }), + [] + ); useEffect(() => { - fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const fetchData = () => { - const config = { - withCredentials: true, - }; - - axios - .get(`${apiUrl}/api/v1/order/current?orderId=${orderId}`, config) - .then((res) => { - setStatusList(res.data); - const curPro = res.data.progress; - setDegree(progressList[curPro]); - }) - .catch((err) => {}); - }; + if (progress) { + const currentProgress = progressList[progress]; + setDegree(currentProgress); + } + }, [progress, progressList]); - const refreshDegree = () => { - fetchData(); + // 주문 상태 새로고침 함수 + const refreshOrderStatus = () => { + setRefreshKey((prevKey) => prevKey + 1); }; - const handleCancle = async () => { - setIsOpen((prev) => !prev); - const config = { - withCredentials: true, - }; - const body = { - orderId: orderId, - }; - - // navigate("/orderHistory"); - setDegree(4); - - const response = await axios.post( - `${apiUrl}/api/v1/order/toss/cancel`, - body, - config - ); - if (response.status === 200) { - console.log(response); - if (response.data.message === "취소 성공") { - message.success("주문 취소되었습니다."); - fetchData(); - setDegree(4); - } - } else { - message.error("주문 취소에 실패하였습니다."); + const handleCancel = async () => { + try { + await cancelOrder(orderId); // 주문 취소 요청 + setDegree(progressList.CANCEL); // 취소 상태로 UI 업데이트 + } catch (error) { + console.error("주문 취소 중 오류 발생:", error); + // 오류 처리 로직 (선택적) + } finally { + setIsOpen(false); // 성공, 실패, 예외에 관계없이 모달 닫기 } }; @@ -104,7 +77,7 @@ function OrderStatus() { src={refresh} className="refresh-btn" alt={refresh} - onClick={refreshDegree} + onClick={refreshOrderStatus} /> )} @@ -116,17 +89,17 @@ function OrderStatus() { - {moment(statusList?.estimatedTime, "HH:mm:ss.SSS").diff( + {moment(estimatedTime, "HH:mm:ss.SSS").diff( moment(), "minutes" ) < 0 ? 0 - : moment(statusList?.estimatedTime, "HH:mm:ss.SSS").diff( + : moment(estimatedTime, "HH:mm:ss.SSS").diff( moment(), "minutes" )} 분 후 - {" "} + 수령 가능! @@ -165,7 +138,7 @@ function OrderStatus() {
{logo}
- {statusList?.orderNum}번 + {orderNum}번
@@ -176,36 +149,38 @@ function OrderStatus() {
주문매장 - {statusList?.name} + {name}
주문내역
- {statusList?.orderName} + {orderName}
수령방식
- {statusList?.inout === 1 ? "매장" : "픽업"} + + {inout === 1 ? "매장" : "픽업"} +
{degree === 4 && (
취소사유 - {statusList?.cancels?.split(",")[1]?.split("=")[1]} + + {cancels?.split(",")[1]?.split("=")[1]} +
)}
-
- - 주문상세 - -
+ +
주문상세
+
)} @@ -236,7 +211,7 @@ function OrderStatus() { {isOpen && ( diff --git a/src/components/views/PageComponent/OrderStorage.jsx b/src/components/views/PageComponent/OrderStorage.jsx index 2708870..8310a77 100644 --- a/src/components/views/PageComponent/OrderStorage.jsx +++ b/src/components/views/PageComponent/OrderStorage.jsx @@ -1,7 +1,8 @@ -import axios from "axios"; -import React, { useEffect, useState } from "react"; +import React from "react"; import { Link } from "react-router-dom"; import "./OrderStorage.css"; +import useFetchNewOrderHistory from "../../../hooks/useFetchNewOrderHistory"; +import useFetchOldOrderHistory from "../../../hooks/useFetchOldOrderHistory"; import Header from "../Header/Header"; import StateBox from "../StateBox/StateBox"; @@ -9,39 +10,18 @@ import StateBox from "../StateBox/StateBox"; import empty from "../../../assets/images/storage_empty.svg"; function OrderStorage() { - const apiUrl = process.env.REACT_APP_API_ROOT; - const [newStorageList, setNewStorageList] = useState([]); - const [oldStorageList, setOldStorageList] = useState([]); + const newStorageList = useFetchNewOrderHistory(); + const oldStorageList = useFetchOldOrderHistory(); const progressList = { - "ORDER": 0, - "MAKE": 1, - "COMPLETE": 2, - "PICKUP": 3, - "CANCEL": 4, - "FAIL": 5 + ORDER: 0, + MAKE: 1, + COMPLETE: 2, + PICKUP: 3, + CANCEL: 4, + FAIL: 5, }; - useEffect(() => { - const config = { - withCredentials: true - }; - - axios.get(`${apiUrl}/api/v1/order/history/new`, config) - .then((res) => { - setNewStorageList(res.data.receipts); - }) - .catch((err) => {}); - - axios.get(`${apiUrl}/api/v1/order/history/old`, config) - .then((res) => { - setOldStorageList(res.data.receipts?.reverse()); - }) - .catch((err) => {}); - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - return (
{newStorageList?.length || oldStorageList?.length ? ( <> - {newStorageList?.length ? newStorageList?.map((e, i) => ( - - - - )) : (<>)} - {oldStorageList?.length ? oldStorageList?.map((e, i) => ( - - - - )) : (<>)} + {newStorageList?.length ? ( + newStorageList?.map((e, i) => ( + + + + )) + ) : ( + <> + )} + {oldStorageList?.length ? ( + oldStorageList?.map((e, i) => ( + + + + )) + ) : ( + <> + )} ) : (
diff --git a/src/components/views/Quickorder/QuickOrder.jsx b/src/components/views/Quickorder/QuickOrder.jsx index dd95281..25c4b94 100644 --- a/src/components/views/Quickorder/QuickOrder.jsx +++ b/src/components/views/Quickorder/QuickOrder.jsx @@ -1,36 +1,10 @@ -import axios from "axios"; -import React, { useEffect, useState } from "react"; +import React from "react"; import { Link } from "react-router-dom"; - import profile_icon from "../../../assets/images/profile_icon.png"; +import useFetchQuickOrder from "../../../hooks/useFetchQuickOrder"; const QuickOrderComponent = ({ isAuth }) => { - const apiRoot = process.env.REACT_APP_API_ROOT; - const [quickOrder, setQuickOrder] = useState([]); - - useEffect(() => { - const fetchData = async () => { - const config = { - withCredentials: true, - }; - - // 바로주문 - if (isAuth) { - try { - const response1 = await axios.get( - `${apiRoot}/api/v1/order/history/fast`, - config - ); - setQuickOrder(response1.data.receipts?.reverse()); - } catch (error) { - console.error("quickOrder Error fetching data:", error); - } - } - }; - - fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isAuth]); + const quickOrder = useFetchQuickOrder(isAuth); return ( <> diff --git a/src/hooks/useCancelOrder.jsx b/src/hooks/useCancelOrder.jsx new file mode 100644 index 0000000..79bad2c --- /dev/null +++ b/src/hooks/useCancelOrder.jsx @@ -0,0 +1,30 @@ +import axios from "axios"; +import { message } from "antd"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/order/toss/cancel`; + +const useCancelOrder = () => { + const cancelOrder = async (orderId) => { + try { + const response = await axios.post( + apiUrl, + { orderId }, + { withCredentials: true } + ); + if (response.status === 200 && response.data.message === "취소 성공") { + message.success("주문 취소되었습니다."); + } else { + message.error("주문 취소에 실패하였습니다."); + } + } catch (error) { + console.error("주문 취소 중 오류 발생:", error); + message.error("주문 취소 중 오류가 발생하였습니다."); + } + }; + + return cancelOrder; +}; + +export default useCancelOrder; diff --git a/src/hooks/useDeleteAccount.jsx b/src/hooks/useDeleteAccount.jsx new file mode 100644 index 0000000..2da89fa --- /dev/null +++ b/src/hooks/useDeleteAccount.jsx @@ -0,0 +1,34 @@ +// hooks/useDeleteAccount.js +import axios from "axios"; +import { message } from "antd"; +import { useNavigate } from "react-router-dom"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/user/remove`; + +const useDeleteAccount = (removeCookie, setIsAuth) => { + const navigate = useNavigate(); + + const deleteAccount = async () => { + try { + const response = await axios.get(apiUrl, { + withCredentials: true, + }); + console.log(response); + removeCookie("accessToken", { domain: process.env.REACT_APP_DOMAIN }); + removeCookie("JSESSIONID", { domain: process.env.REACT_APP_DOMAIN }); + setIsAuth(false); + message.success("회원탈퇴에 성공하셨습니다."); + navigate("/"); + } catch (error) { + console.error("Error during account deletion:", error); + message.error("회원탈퇴 실패. 관리자에게 문의하세요."); + navigate("/"); + } + }; + + return deleteAccount; +}; + +export default useDeleteAccount; diff --git a/src/hooks/useDeleteCartItem.jsx b/src/hooks/useDeleteCartItem.jsx new file mode 100644 index 0000000..c5f6089 --- /dev/null +++ b/src/hooks/useDeleteCartItem.jsx @@ -0,0 +1,26 @@ +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; + +const useDeleteCartItem = () => { + const deleteCartItem = async (itemId, paymentData, setPaymentData) => { + try { + await axios.delete(`${apiRoot}/${apiVer}/order/cart?idx=${itemId}`, { + withCredentials: true, + }); + + // 로컬 상태 갱신 + const updatedCarts = paymentData.carts.filter( + (cartItem) => cartItem.idx !== itemId + ); + setPaymentData({ ...paymentData, carts: updatedCarts }); + } catch (error) { + console.error(error); + } + }; + + return deleteCartItem; +}; + +export default useDeleteCartItem; diff --git a/src/hooks/useFetchCartCount.jsx b/src/hooks/useFetchCartCount.jsx new file mode 100644 index 0000000..c0b4e85 --- /dev/null +++ b/src/hooks/useFetchCartCount.jsx @@ -0,0 +1,27 @@ +import axios from "axios"; +import { useEffect, useState } from "react"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/order/cart/count`; + +const useFetchCartCount = () => { + const [totalCount, setTotalCount] = useState(0); + + useEffect(() => { + const fetchCartCount = async () => { + try { + const response = await axios.get(apiUrl, { withCredentials: true }); + setTotalCount(response.data.count); + } catch (error) { + console.error("장바구니 갯수 조회 중 오류 발생:", error); + } + }; + + fetchCartCount(); + }, []); + + return totalCount; +}; + +export default useFetchCartCount; diff --git a/src/hooks/useFetchCartData.jsx b/src/hooks/useFetchCartData.jsx new file mode 100644 index 0000000..13e05e4 --- /dev/null +++ b/src/hooks/useFetchCartData.jsx @@ -0,0 +1,58 @@ +// 장바구니 확인 +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; + +const useFetchCartData = (cartId) => { + // const [paymentData, setPaymentData] = useState(null); + const [cartIdApi, setCartIdApi] = useState(0); + const [carts, setCarts] = useState([]); + const [edit, setEdit] = useState(false); + const [imgUrl, setImgUrl] = useState(""); + const [inOut, setInOut] = useState(1); + const [isOpened, setIsOpened] = useState(false); + const [name, setName] = useState(""); + const [storeId, setStoreId] = useState(0); + const [totalPrice, setTotalPrice] = useState(0); + + useEffect(() => { + const fetchData = async () => { + try { + const apiUrl = cartId + ? `${apiRoot}/api/v1/order/cart?cartId=${cartId}` + : `${apiRoot}/api/v1/order/cart`; + const response = await axios.get(apiUrl, { withCredentials: true }); + setCartIdApi(response.data.cartId); + setCarts(response.data.carts); + setEdit(response.data.edit); + setImgUrl(response.data.imgUrl); + setInOut(response.data.inOut); + setIsOpened(response.data.isOpened); + setName(response.data.name); + setStoreId(response.data.storeId); + setTotalPrice(response.data.totalPrice); + } catch (error) { + console.error(error); + } + }; + + fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [cartId]); + + return { + cartIdApi, + carts, + edit, + imgUrl, + inOut, + isOpened, + name, + storeId, + totalPrice, + setTotalPrice, // totalPrice 상태 업데이트 함수 추가 + }; +}; + +export default useFetchCartData; diff --git a/src/hooks/useFetchCoupons.jsx b/src/hooks/useFetchCoupons.jsx new file mode 100644 index 0000000..61cf1d6 --- /dev/null +++ b/src/hooks/useFetchCoupons.jsx @@ -0,0 +1,30 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/coupon`; + +const useFetchCoupons = () => { + const [coupons, setCoupons] = useState([]); + + useEffect(() => { + const fetchCoupons = async () => { + try { + const response = await axios.get(apiUrl, { + withCredentials: true, + }); + setCoupons(response.data.coupons); + } catch (error) { + console.error("Error fetching coupons:", error); + } + }; + + fetchCoupons(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return coupons; +}; + +export default useFetchCoupons; diff --git a/src/hooks/useFetchCurrentOrder.jsx b/src/hooks/useFetchCurrentOrder.jsx new file mode 100644 index 0000000..a99f66e --- /dev/null +++ b/src/hooks/useFetchCurrentOrder.jsx @@ -0,0 +1,42 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; + +const useFetchCurrentOrder = (orderId, refreshKey) => { + const [cancels, setCancels] = useState(null); + const [estimatedTime, setEstimatedTime] = useState(null); + const [inout, setInout] = useState(1); + const [name, setName] = useState(""); + const [orderName, setOrderName] = useState(""); + const [orderNum, setOrderNum] = useState(""); + const [progress, setProgress] = useState(""); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await axios.get( + `${apiRoot}/${apiVer}/order/current?orderId=${orderId}`, + { withCredentials: true } + ); + setCancels(response.data.cancels); + setEstimatedTime(response.data.estimatedTime); + setInout(response.data.inout); + setName(response.data.name); + setOrderName(response.data.orderName); + setOrderNum(response.data.orderNum); + setProgress(response.data.progress); + } catch (error) { + console.error("Error fetching current order status:", error); + } + }; + + fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [orderId, refreshKey]); // refreshKey를 의존성 배열에 추가 + + return { cancels, estimatedTime, inout, name, orderName, orderNum, progress }; +}; + +export default useFetchCurrentOrder; diff --git a/src/hooks/useFetchEvent.jsx b/src/hooks/useFetchEvent.jsx new file mode 100644 index 0000000..1deee12 --- /dev/null +++ b/src/hooks/useFetchEvent.jsx @@ -0,0 +1,30 @@ +import axios from "axios"; +import { useState, useEffect } from "react"; + +const useFetchEvent = (storeId) => { + const [eventImgUrl, setEventImgUrl] = useState(""); + const [takeOutEvent, setTakeOutEvent] = useState(""); + const apiRoot = process.env.REACT_APP_API_ROOT; + const version = "api/v1"; + + useEffect(() => { + const fetchEvent = async () => { + try { + const response = await axios.get( + `${apiRoot}/${version}/store/${storeId}/event` + ); + setEventImgUrl(response.data.eventImgUrl); + setTakeOutEvent(response.data.takeOutEvent); + } catch (error) { + console.error("Error fetching event data:", error); + } + }; + + fetchEvent(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [storeId]); + + return { eventImgUrl, takeOutEvent }; +}; + +export default useFetchEvent; diff --git a/src/hooks/useFetchEventBanners.jsx b/src/hooks/useFetchEventBanners.jsx new file mode 100644 index 0000000..95d987f --- /dev/null +++ b/src/hooks/useFetchEventBanners.jsx @@ -0,0 +1,30 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/event/banner`; + +const useFetchEventBanners = () => { + const [eventBanners, setEventBanners] = useState([]); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await axios.get(apiUrl, { + withCredentials: true, + }); + setEventBanners(response.data.banners); + } catch (error) { + console.error("Error fetching data:", error); + } + }; + + fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return eventBanners; +}; + +export default useFetchEventBanners; diff --git a/src/hooks/useFetchEvents.jsx b/src/hooks/useFetchEvents.jsx new file mode 100644 index 0000000..8a90292 --- /dev/null +++ b/src/hooks/useFetchEvents.jsx @@ -0,0 +1,28 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/event/main`; + +const useFetchEvents = () => { + const [events, setEvents] = useState([]); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await axios.get(apiUrl, { withCredentials: true }); + setEvents(response.data.mainEvents); + } catch (error) { + console.error("Error fetching events data:", error); + } + }; + + fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return events; +}; + +export default useFetchEvents; diff --git a/src/hooks/useFetchFastOrderHistory.jsx b/src/hooks/useFetchFastOrderHistory.jsx new file mode 100644 index 0000000..d40db95 --- /dev/null +++ b/src/hooks/useFetchFastOrderHistory.jsx @@ -0,0 +1,27 @@ +import axios from "axios"; +import { useState, useEffect } from "react"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/order/history/fast`; + +const useFetchFastOrderHistory = () => { + const [storageList, setStorageList] = useState([]); + + useEffect(() => { + const fetchFastOrderHistory = async () => { + try { + const response = await axios.get(apiUrl, { withCredentials: true }); + setStorageList(response.data.receipts?.reverse()); + } catch (error) { + console.error("Error fetching fast order history:", error); + } + }; + + fetchFastOrderHistory(); + }, []); + + return storageList; +}; + +export default useFetchFastOrderHistory; diff --git a/src/hooks/useFetchFoodOptionInfo.jsx b/src/hooks/useFetchFoodOptionInfo.jsx new file mode 100644 index 0000000..57556c2 --- /dev/null +++ b/src/hooks/useFetchFoodOptionInfo.jsx @@ -0,0 +1,35 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; + +const useFetchFoodOptionInfo = (storeId, foodieId, inout) => { + const [category, setCategory] = useState([]); + const [imgUrl, setImgUrl] = useState(""); + const [name, setName] = useState(""); + const [price, setPrice] = useState(0); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await axios.get( + `${apiRoot}/${apiVer}/order/${storeId}?foody_id=${foodieId}&inout=${inout}`, + { withCredentials: true } + ); + setCategory(response.data?.category); + setImgUrl(response.data?.imgUrl); + setName(response.data?.name); + setPrice(response.data?.price); + } catch (error) { + console.error("Error fetching food option info:", error); + } + }; + fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [storeId, foodieId, inout]); + + return { category, imgUrl, name, price }; +}; + +export default useFetchFoodOptionInfo; diff --git a/src/hooks/useFetchNewOrderHistory.jsx b/src/hooks/useFetchNewOrderHistory.jsx new file mode 100644 index 0000000..82c0ada --- /dev/null +++ b/src/hooks/useFetchNewOrderHistory.jsx @@ -0,0 +1,28 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/order/history/new`; + +const useFetchNewOrderHistory = () => { + const [newStorageList, setNewStorageList] = useState([]); + + useEffect(() => { + const fetchNewOrderHistory = async () => { + try { + const response = await axios.get(apiUrl, { withCredentials: true }); + setNewStorageList(response.data.receipts); + } catch (error) { + console.error("Error fetching new order history:", error); + } + }; + + fetchNewOrderHistory(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return newStorageList; +}; + +export default useFetchNewOrderHistory; diff --git a/src/hooks/useFetchOldOrderHistory.jsx b/src/hooks/useFetchOldOrderHistory.jsx new file mode 100644 index 0000000..911d985 --- /dev/null +++ b/src/hooks/useFetchOldOrderHistory.jsx @@ -0,0 +1,30 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; + +const useFetchOldOrderHistory = () => { + const [oldStorageList, setOldStorageList] = useState([]); + + useEffect(() => { + const fetchOldOrderHistory = async () => { + try { + const response = await axios.get( + `${apiRoot}/${apiVer}/order/history/old`, + { withCredentials: true } + ); + setOldStorageList(response.data.receipts?.reverse()); + } catch (error) { + console.error("Error fetching old order history:", error); + } + }; + + fetchOldOrderHistory(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return oldStorageList; +}; + +export default useFetchOldOrderHistory; diff --git a/src/hooks/useFetchOrderDetails.jsx b/src/hooks/useFetchOrderDetails.jsx new file mode 100644 index 0000000..920449d --- /dev/null +++ b/src/hooks/useFetchOrderDetails.jsx @@ -0,0 +1,63 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; + +const useFetchOrderDetails = (orderId) => { + const [cancelReason, setCancelReason] = useState(""); + const [cart, setCart] = useState([]); + const [inout, setInout] = useState(0); + const [method, setMethod] = useState(""); + // const [orderId, setOrderId] = useState(""); + const [orderNumber, setOrderNumber] = useState(""); + const [orderStatus, setOrderStatus] = useState(""); + const [orderTime, setOrderTime] = useState(""); + const [salePrice, setSalePrice] = useState(0); + const [storeName, setStoreName] = useState(""); + const [storePhone, setStorePhone] = useState(""); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await axios.get( + `${apiRoot}/${apiVer}/order/receipt?orderId=${orderId}`, + { withCredentials: true } + ); + setCancelReason(response.data.cancelReason); + setCart(response.data.cart); + setInout(response.data.inout); + setMethod(response.data.method); + // setOrderId(response.data.orderId); + setOrderNumber(response.data.orderNumber); + setOrderStatus(response.data.orderStatus); + setOrderTime(response.data.orderTime); + setSalePrice(response.data.salePrice); + setStoreName(response.data.storeName); + setStorePhone(response.data.storePhone); + } catch (error) { + console.error("Error fetching order details:", error); + } + }; + + if (orderId) { + fetchData(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [orderId]); + + return { + cancelReason, + cart, + inout, + method, + orderNumber, + orderStatus, + orderTime, + salePrice, + storeName, + storePhone, + }; +}; + +export default useFetchOrderDetails; diff --git a/src/hooks/useFetchPaymentFail.jsx b/src/hooks/useFetchPaymentFail.jsx new file mode 100644 index 0000000..182a13a --- /dev/null +++ b/src/hooks/useFetchPaymentFail.jsx @@ -0,0 +1,24 @@ +import { useEffect } from "react"; +import axios from "axios"; + +const useFetchPaymentFail = (message, orderId, code) => { + const apiRoot = process.env.REACT_APP_API_ROOT; + const apiVer = "api/v1"; + + useEffect(() => { + axios + .get( + `${apiRoot}/${apiVer}/order/toss/fail?message=${message}&orderId=${orderId}&code=${code}`, + { withCredentials: true } + ) + .then((response) => { + console.log(response); + }) + .catch((error) => { + console.error("Error sending fail URL request:", error); + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [message, orderId, code]); +}; + +export default useFetchPaymentFail; diff --git a/src/hooks/useFetchQuickOrder.jsx b/src/hooks/useFetchQuickOrder.jsx new file mode 100644 index 0000000..c05aadc --- /dev/null +++ b/src/hooks/useFetchQuickOrder.jsx @@ -0,0 +1,32 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; + +const useFetchQuickOrder = (isAuth) => { + const [quickOrder, setQuickOrder] = useState([]); + + useEffect(() => { + const fetchData = async () => { + if (isAuth) { + try { + const response = await axios.get( + `${apiRoot}/${apiVer}/order/history/fast`, + { withCredentials: true } + ); + setQuickOrder(response.data.receipts?.reverse()); + } catch (error) { + console.error("Error fetching quick order data:", error); + } + } + }; + + fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isAuth]); + + return quickOrder; +}; + +export default useFetchQuickOrder; diff --git a/src/hooks/useFetchSearch.jsx b/src/hooks/useFetchSearch.jsx new file mode 100644 index 0000000..d6c0462 --- /dev/null +++ b/src/hooks/useFetchSearch.jsx @@ -0,0 +1,26 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/board/search`; + +const useFetchSearch = () => { + const [stores, setStores] = useState([]); + + useEffect(() => { + axios + .get(apiUrl, { withCredentials: true }) + .then((response) => { + setStores(response.data.stores); + }) + .catch((error) => { + console.error("Error fetching data:", error); + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return stores; +}; + +export default useFetchSearch; diff --git a/src/hooks/useFetchStoreInfo.jsx b/src/hooks/useFetchStoreInfo.jsx new file mode 100644 index 0000000..e20a3b5 --- /dev/null +++ b/src/hooks/useFetchStoreInfo.jsx @@ -0,0 +1,39 @@ +import axios from "axios"; +import { useState, useEffect } from "react"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; + +const useFetchStoreInfo = (storeId) => { + // const [caffeeInfo, setCaffeeInfo] = useState(null); + const [address, setAddress] = useState(null); + const [imgs, setImgs] = useState([]); + const [name, setName] = useState(""); + const [openTime, setOpenTime] = useState(""); + const [phone, setPhone] = useState(""); + const [status, setStatus] = useState(false); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await axios.get( + `${apiRoot}/${apiVer}/store/${storeId}` + ); + // setCaffeeInfo(response.data); + setAddress(response.data.address); + setImgs(response.data.imgs); + setName(response.data.name); + setOpenTime(response.data.openTime); + setPhone(response.data.phone); + setStatus(response.data.status); + } catch (error) { + console.error("Error fetching store info:", error); + } + }; + fetchData(); + }, [storeId]); + + return { address, imgs, name, openTime, phone, status }; +}; + +export default useFetchStoreInfo; diff --git a/src/hooks/useFetchStoreMenu.jsx b/src/hooks/useFetchStoreMenu.jsx new file mode 100644 index 0000000..6a9f042 --- /dev/null +++ b/src/hooks/useFetchStoreMenu.jsx @@ -0,0 +1,27 @@ +import axios from "axios"; +import { useState, useEffect } from "react"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; + +const useFetchStoreMenu = (storeId, inout) => { + const [menu, setMenu] = useState([]); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await axios.get( + `${apiRoot}/${apiVer}/store/${storeId}/menu?inout=${inout}` + ); + setMenu(response.data); + } catch (error) { + console.error("Error fetching store menu:", error); + } + }; + fetchData(); + }, [storeId, inout]); + + return menu; +}; + +export default useFetchStoreMenu; diff --git a/src/hooks/useFetchStores.jsx b/src/hooks/useFetchStores.jsx new file mode 100644 index 0000000..d2bd8a6 --- /dev/null +++ b/src/hooks/useFetchStores.jsx @@ -0,0 +1,30 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/board/store`; + +const useFetchStores = () => { + const [stores, setStores] = useState([]); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await axios.get(apiUrl, { + withCredentials: true, + }); + setStores(response.data.stores); + } catch (error) { + console.error("Error fetching data:", error); + } + }; + + fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return stores; +}; + +export default useFetchStores; diff --git a/src/hooks/useFetchUserInfo.jsx b/src/hooks/useFetchUserInfo.jsx new file mode 100644 index 0000000..ca906d5 --- /dev/null +++ b/src/hooks/useFetchUserInfo.jsx @@ -0,0 +1,35 @@ +import { useState, useEffect } from "react"; +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/user/info`; + +const useFetchUserInfo = () => { + // const [userInfo, setUserInfo] = useState({ name: "", phone: "", email: "" }); + const [email, setEmail] = useState(""); + const [name, setName] = useState(""); + const [phone, setPhone] = useState(""); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await axios.get(apiUrl, { + withCredentials: true, + }); + setEmail(response.data.email); + setName(response.data.name); + setPhone(response.data.phone); + } catch (error) { + console.error("Error fetching user info:", error); + } + }; + + fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return { email, name, phone }; +}; + +export default useFetchUserInfo; diff --git a/src/hooks/useInterval.jsx b/src/hooks/useInterval.jsx index b15385f..d6c1e07 100644 --- a/src/hooks/useInterval.jsx +++ b/src/hooks/useInterval.jsx @@ -16,6 +16,7 @@ function useInterval(callback, delay) { const intervalId = setInterval(tick, delay); return () => clearInterval(intervalId); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [delay]); } diff --git a/src/hooks/useLogout.jsx b/src/hooks/useLogout.jsx new file mode 100644 index 0000000..4b92364 --- /dev/null +++ b/src/hooks/useLogout.jsx @@ -0,0 +1,32 @@ +import axios from "axios"; +import { message } from "antd"; +import { useNavigate } from "react-router-dom"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; + +const useLogout = (removeCookie, setIsAuth) => { + const navigate = useNavigate(); + + const logout = async () => { + try { + const response = await axios.get(`${apiRoot}/${apiVer}/user/logout`, { + withCredentials: true, + }); + console.log(response); + removeCookie("accessToken", { domain: process.env.REACT_APP_DOMAIN }); + removeCookie("JSESSIONID", { domain: process.env.REACT_APP_DOMAIN }); + setIsAuth(false); + message.success("로그아웃에 성공하셨습니다."); + navigate("/"); + } catch (error) { + console.error("Error during logout:", error); + message.error("로그아웃 실패. 관리자에게 문의하세요."); + navigate("/"); + } + }; + + return logout; +}; + +export default useLogout; diff --git a/src/hooks/usePaymentSuccess.jsx b/src/hooks/usePaymentSuccess.jsx new file mode 100644 index 0000000..ec7d96d --- /dev/null +++ b/src/hooks/usePaymentSuccess.jsx @@ -0,0 +1,39 @@ +import axios from "axios"; +import { useState, useEffect } from "react"; + +const usePaymentSuccess = (paymentType, orderId, paymentKey, amount) => { + const [paymentResult, setPaymentResult] = useState({ + status: null, + message: "", + }); + const apiRoot = process.env.REACT_APP_API_ROOT; + const apiVer = "api/v1"; + + useEffect(() => { + const fetchPaymentResult = async () => { + try { + const response = await axios.get( + `${apiRoot}/${apiVer}/order/toss/success?paymentType=${paymentType}&orderId=${orderId}&paymentKey=${paymentKey}&amount=${amount}`, + { withCredentials: true } + ); + setPaymentResult({ + status: response.status, + message: response.data.message, + }); + } catch (error) { + console.error("Error fetching payment success:", error); + setPaymentResult({ + status: "error", + message: "결제 확인 중 오류가 발생했습니다.", + }); + } + }; + + fetchPaymentResult(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [paymentType, orderId, paymentKey, amount]); + + return paymentResult; +}; + +export default usePaymentSuccess; diff --git a/src/hooks/usePostCoupon.jsx b/src/hooks/usePostCoupon.jsx new file mode 100644 index 0000000..e54e51d --- /dev/null +++ b/src/hooks/usePostCoupon.jsx @@ -0,0 +1,38 @@ +import axios from "axios"; +import { message } from "antd"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/coupon`; + +const usePostCoupon = () => { + const postCoupon = async ( + couponCode, + couponId, + couponIssued, + setCouponIssued + ) => { + if (couponIssued) { + message.warning("쿠폰을 이미 받았어요!"); + return; + } + + try { + const response = await axios.post( + apiUrl, + { couponCode, couponId }, + { withCredentials: true } + ); + console.log(response); + message.success("쿠폰 받기 완료!"); + setCouponIssued(true); + } catch (error) { + console.error("Error fetching data:", error); + message.error("쿠폰 받기에 실패했습니다."); + } + }; + + return postCoupon; +}; + +export default usePostCoupon; diff --git a/src/hooks/useRequestPayment.jsx b/src/hooks/useRequestPayment.jsx new file mode 100644 index 0000000..b469400 --- /dev/null +++ b/src/hooks/useRequestPayment.jsx @@ -0,0 +1,24 @@ +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/order/toss`; + +const useRequestPayment = () => { + const requestPayment = async (cartId, couponId, paymentWidget) => { + try { + const body = { cartId, couponId }; + const response = await axios.post(apiUrl, body, { + withCredentials: true, + }); + paymentWidget?.requestPayment(response.data); + } catch (error) { + console.error("Error during payment request:", error); + // 에러 처리 로직 + } + }; + + return requestPayment; +}; + +export default useRequestPayment; diff --git a/src/hooks/useResetCart.jsx b/src/hooks/useResetCart.jsx new file mode 100644 index 0000000..8d58da6 --- /dev/null +++ b/src/hooks/useResetCart.jsx @@ -0,0 +1,23 @@ +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/order/cart/reset`; + +const useResetCart = () => { + const resetCart = async () => { + try { + const response = await axios.delete(apiUrl, { + withCredentials: true, + }); + return response; + } catch (error) { + console.error("Error resetting cart:", error); + throw error; + } + }; + + return resetCart; +}; + +export default useResetCart; diff --git a/src/hooks/useUpdateCart.jsx b/src/hooks/useUpdateCart.jsx new file mode 100644 index 0000000..c3e4376 --- /dev/null +++ b/src/hooks/useUpdateCart.jsx @@ -0,0 +1,23 @@ +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; +const apiUrl = `${apiRoot}/${apiVer}/order/cart`; + +const useUpdateCart = () => { + const updateCart = async (body) => { + try { + const response = await axios.post(apiUrl, body, { + withCredentials: true, + }); + return response; + } catch (error) { + console.error("Error updating cart:", error); + throw error; + } + }; + + return updateCart; +}; + +export default useUpdateCart; diff --git a/src/hooks/useUpdateCartItem.jsx b/src/hooks/useUpdateCartItem.jsx new file mode 100644 index 0000000..bddce7c --- /dev/null +++ b/src/hooks/useUpdateCartItem.jsx @@ -0,0 +1,22 @@ +import axios from "axios"; + +const apiRoot = process.env.REACT_APP_API_ROOT; +const apiVer = "api/v1"; + +const useUpdateCartItem = () => { + const updateCartItem = async (idx, count, price) => { + try { + await axios.put( + `${apiRoot}/${apiVer}/order/cart?idx=${idx}&count=${count}`, + { price: price }, + { withCredentials: true } + ); + } catch (error) { + console.error(error); + } + }; + + return updateCartItem; +}; + +export default useUpdateCartItem; diff --git a/src/pages/CafeSearch/CafeSearch.jsx b/src/pages/CafeSearch/CafeSearch.jsx index f7b5419..5c9423c 100644 --- a/src/pages/CafeSearch/CafeSearch.jsx +++ b/src/pages/CafeSearch/CafeSearch.jsx @@ -1,33 +1,12 @@ -import axios from "axios"; -import React, { useEffect, useState } from "react"; +import React from "react"; import { Link } from "react-router-dom"; import store_not_open_icon from "../../assets/images/store_not_open_icon.svg"; -// import search_cafedream from "../../assets/images/search_cafedream.svg"; -// import search_harang from "../../assets/images/search_harang.svg"; -// import search_orda from "../../assets/images/search_orda.svg"; import Header from "../../components/views/Header/Header"; import "./CafeSearch.css"; +import useFetchSearch from "../../hooks/useFetchSearch"; function CafeSearch() { - const apiRoot = process.env.REACT_APP_API_ROOT; - - const [stores, setStores] = useState([]); - /* verypick 가게 정보 */ - useEffect(() => { - // Fetch data from the backend API - const config = { - withCredentials: true, - }; - axios - .get(`${apiRoot}/api/v1/board/search`, config) - .then((response) => { - setStores(response.data.stores); - }) - .catch((error) => { - console.error("Error fetching data:", error); - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const stores = useFetchSearch(); return (
@@ -38,49 +17,55 @@ function CafeSearch() { linkTo: "/", }} /> +
- {stores.map((item) => ( -
- -
- search_cafe - {!item.status && ( -
- closedImage -
- )} -
-
{item.name}
-
-
- {item.status ? "영업중" : "영업종료"} + {stores.map((item) => { + const idx = item?.idx; + const name = item?.name; + const address = item?.address; + const status = item?.status; + // const time = item?.time; + const imgUrl = item?.imgUrl; + + return ( +
+ +
+ search_cafe + {!status && ( +
+ closedImage +
+ )} +
+
{name}
+
+
+ {status ? "영업중" : "영업종료"} +
+ {/*    */} + {/*
{time}
*/}
- {/*    */} - {/*
{item.time}
*/} +
{address}
-
{item.address}
-
- -
- ))} + +
+ ); + })}
); diff --git a/src/pages/HomePage/Homepage.jsx b/src/pages/HomePage/Homepage.jsx index a7aabde..58f19c4 100644 --- a/src/pages/HomePage/Homepage.jsx +++ b/src/pages/HomePage/Homepage.jsx @@ -1,35 +1,31 @@ -import { message } from "antd"; -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { Link, useNavigate } from "react-router-dom"; import "slick-carousel/slick/slick-theme.css"; import "slick-carousel/slick/slick.css"; -// import event_icon from "../../assets/images/event_icon.svg"; -// import home_cafedream from "../../assets/images/home_cafedream.svg"; -// import home_harang from "../../assets/images/home_harang.svg"; -// import home_orda from "../../assets/images/home_orda.svg"; -import axios from "axios"; import { useRecoilValue } from "recoil"; import { isAuthenticatedState } from "../../Atom/status"; import eventTextIcon from "../../assets/images/icon_eventText.svg"; import Modal from "../../components/views/Modal/Modal"; -//import profile_icon from "../../assets/images/profile_icon.svg"; import store_not_open from "../../assets/images/store_not_open.svg"; import Header from "../../components/views/Header/Header"; import NavBar from "../../components/views/NavBar/NavBar"; import NavBar2 from "../../components/views/NavBar/NavBar2"; import QuickOrderComponent from "../../components/views/Quickorder/QuickOrder"; import "./Homepage.css"; +import usePostCoupon from "../../hooks/usePostCoupon"; +import useFetchStores from "../../hooks/useFetchStores"; +import useFetchEventBanners from "../../hooks/useFetchEventBanners"; function Homepage() { const navigate = useNavigate(); + const postCoupon = usePostCoupon(); + const stores = useFetchStores(); + const eventBanners = useFetchEventBanners(); // const isLoggedIn = window.localStorage.getItem("isAuthenticated"); - const apiRoot = process.env.REACT_APP_API_ROOT; // const [cookies] = useCookies(["accessToken"]); // const [loggedIn, setLoggedIn] = useState(false); const isAuth = useRecoilValue(isAuthenticatedState); //const [quickOrder, setQuickOrder] = useState([]); - const [stores, setStores] = useState([]); - const [eventBanner, setEventBanner] = useState([]); const [couponIssued, setCouponIssued] = useState(false); const [notLoggedInbannerClick, setnotLoggedInbannerClick] = useState(false); @@ -43,69 +39,9 @@ function Homepage() { }; const handleCouponClick = (couponCode, couponId) => { - const config = { - withCredentials: true, - }; - - if (couponIssued) { - return; - } - - axios - .post( - `${apiRoot}/api/v1/coupon`, - { - couponCode, - couponId, - }, - config - ) - .then((response) => { - console.log(response); - message.success("쿠폰 받기 완료!"); - setCouponIssued(true); - }) - .catch((error) => { - console.error("couponIssued Error fetching data:", error); - message.warning("쿠폰을 이미 받았어요!"); - }); + postCoupon(couponCode, couponId, couponIssued, setCouponIssued); }; - useEffect(() => { - console.log("실행"); - const fetchData = async () => { - const config = { - withCredentials: true, - }; - - // 베리pick - try { - const response2 = await axios.get( - `${apiRoot}/api/v1/board/store`, - config - ); - setStores(response2.data.stores); - } catch (error) { - console.error("stores Error fetching data:", error); - } - - // 이벤트 배너 - try { - const response3 = await axios.get( - `${apiRoot}/api/v1/event/banner`, - config - ); - setEventBanner(response3.data.banners); - } catch (error) { - console.error("eventBanner Error fetching data:", error); - } - }; - - fetchData(); - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - return ( //
@@ -119,7 +55,7 @@ function Homepage() { {/* 이벤트 div */}
{isAuth - ? eventBanner.map((item) => ( + ? eventBanners.map((item) => ( handleCouponClick(item.couponCode, item.idx)} /> )) - : eventBanner.map((item) => ( + : eventBanners.map((item) => ( { - const config = { - withCredentials: true, - }; - axios - .get(`${apiRoot}/api/v1/coupon`, config) - .then((response) => { - setCouponCheck(response.data.coupons); - }) - .catch((error) => { - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const couponCheck = useFetchCoupons(); return (
@@ -73,15 +41,6 @@ function CouponPage() {
)} - - {/* {dummyCouponItems.map((item) => ( -
-
{item.name}
-
{item.content}
-
{item.date}
-
{item.limit}
-
- ))} */}
); diff --git a/src/pages/MyPage/EventingPage/EventingPage.jsx b/src/pages/MyPage/EventingPage/EventingPage.jsx index e02ed44..1bc4cdd 100644 --- a/src/pages/MyPage/EventingPage/EventingPage.jsx +++ b/src/pages/MyPage/EventingPage/EventingPage.jsx @@ -1,13 +1,12 @@ -import React, { useEffect, useState } from "react"; +import React from "react"; import { Link } from "react-router-dom"; import Slider from "react-slick"; import "slick-carousel/slick/slick-theme.css"; import "slick-carousel/slick/slick.css"; import styled from "styled-components"; -//import eventing1 from "../../../assets/images/eventing1.svg"; -import axios from "axios"; import Header from "../../../components/views/Header/Header"; import "./EventingPage.css"; +import useFetchEvents from "../../../hooks/useFetchEvents"; const StyleSlider = styled(Slider)` width: 100%; @@ -28,26 +27,7 @@ const EventingImg = styled.img` `; function EventingPage() { - const apiRoot = process.env.REACT_APP_API_ROOT; - - // const dummyEventingItems = [ - // { - // events: [ - // { - // idx: 1, - // imgUrl: eventing1, - // }, - // { - // idx: 2, - // imgUrl: eventing1, - // }, - // { - // idx: 3, - // imgUrl: eventing1, - // }, - // ], - // }, - // ]; + const events = useFetchEvents(); const settings = { dots: true, @@ -58,21 +38,6 @@ function EventingPage() { centerMode: true, }; - const [mypageEventing, setMypageEventing] = useState([]); - useEffect(() => { - const config = { - withCredentials: true, - }; - axios - .get(`${apiRoot}/api/v1/event/main`, config) - .then((response) => { - setMypageEventing(response.data.mainEvents); - }) - .catch((error) => { - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - return (
- {/* - {dummyEventingItems[0].events.map((event) => ( - - ))} - */} - {mypageEventing.map((item) => ( + {events.map((item) => ( diff --git a/src/pages/MyPage/MyPage.jsx b/src/pages/MyPage/MyPage.jsx index 1e750eb..be93b1f 100644 --- a/src/pages/MyPage/MyPage.jsx +++ b/src/pages/MyPage/MyPage.jsx @@ -1,36 +1,15 @@ -// import React, { useEffect, useState } from "react"; -import axios from "axios"; -import React, { useEffect, useState } from "react"; +import React from "react"; import { Link } from "react-router-dom"; import { useRecoilState } from "recoil"; import { isAuthenticatedState } from "../../Atom/status"; import profile_icon from "../../assets/images/profile_icon.png"; import Header from "../../components/views/Header/Header"; import "./MyPage.css"; +import useFetchUserInfo from "../../hooks/useFetchUserInfo"; function Mypage() { - // const [isAuth, setIsAuth] = useRecoilState(isAuthenticatedState); const [isAuth] = useRecoilState(isAuthenticatedState); - const apiUrl = process.env.REACT_APP_API_ROOT; - const [userName, setUserName] = useState(""); - - useEffect(() => { - const config = { - withCredentials: true, - }; - - axios - .get(`${apiUrl}/api/v1/user/info`, config) - .then((response) => { - const { name } = response.data; - setUserName(name); - }) - .catch((error) => { - console.error("Error fetching user info:", error); - // Handle error, e.g., redirect to login page - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const { name: userName } = useFetchUserInfo(); return (
diff --git a/src/pages/MyPage/MyprofilePage/MyprofilePage.jsx b/src/pages/MyPage/MyprofilePage/MyprofilePage.jsx index 5adedbe..5f2dc61 100644 --- a/src/pages/MyPage/MyprofilePage/MyprofilePage.jsx +++ b/src/pages/MyPage/MyprofilePage/MyprofilePage.jsx @@ -1,91 +1,27 @@ -import { message } from "antd"; -import axios from "axios"; -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { useCookies } from "react-cookie"; -import { useNavigate } from "react-router-dom"; import { useSetRecoilState } from "recoil"; import { getAuthenticatedSelector } from "../../../Atom/status"; import profile_icon from "../../../assets/images/profile_icon.svg"; import Header from "../../../components/views/Header/Header"; import Modal from "../../../components/views/Modal/Modal"; import "./MyprofilePage.css"; +import useLogout from "../../../hooks/useLogout"; +import useDeleteAccount from "../../../hooks/useDeleteAccount"; +import useFetchUserInfo from "../../../hooks/useFetchUserInfo"; function MyprofilePage() { - const navigate = useNavigate(); - const apiUrl = process.env.REACT_APP_API_ROOT; const [, , removeCookie] = useCookies(["accessToken", "JSESSIONID"]); const setIsAuth = useSetRecoilState(getAuthenticatedSelector); const [isOpen, setIsOpen] = useState(false); const [isBye, setIsBye] = useState(false); + const { email, name, phone } = useFetchUserInfo(); + const logout = useLogout(removeCookie, setIsAuth); + const deleteAccount = useDeleteAccount(removeCookie, setIsAuth); const byeText = "계정탈퇴 시, 개인정보 및 레디베리에 저장된 데이터는
약관에 따라 3개월 이후 삭제됩니다. 계속하겠습니까?"; - const handleLogout = async () => { - try { - const config = { - withCredentials: true, - }; - const response = await axios.get(apiUrl + "/api/v1/user/logout", config); - console.log(response); - removeCookie("accessToken", { domain: process.env.REACT_APP_DOMAIN }); - removeCookie("JSESSIONID", { domain: process.env.REACT_APP_DOMAIN }); - setIsAuth(false); - message.success("로그아웃에 성공하셨습니다."); - navigate("/"); - } catch (error) { - alert("관리자에게 문의하세요."); - navigate("/"); - } - }; - - const handleLogdelete = async () => { - try { - const config = { - withCredentials: true, - }; - const response = await axios.get(apiUrl + "/api/v1/user/remove", config); - console.log(response); - removeCookie("accessToken", { domain: process.env.REACT_APP_DOMAIN }); - removeCookie("JSESSIONID", { domain: process.env.REACT_APP_DOMAIN }); - setIsAuth(false); - message.success("회원탈퇴에 성공하셨습니다."); - navigate("/"); - } catch (error) { - alert("관리자에게 문의하세요."); - navigate("/"); - } - }; - - const [userData, setUserData] = useState({ - name: "", - phone: "", - email: "", - }); - - useEffect(() => { - const config = { - withCredentials: true, - }; - - axios - .get(`${apiUrl}/api/v1/user/info`, config) - .then((response) => { - const { name, phone, email } = response.data; - setUserData({ name, phone, email }); - }) - .catch((error) => { - console.error("Error fetching user info:", error); - // Handle error, e.g., redirect to login page - }); - }, [apiUrl]); - - // const dummyUserItems = { - // name: "바나나", - // phone: "010-1234-5678", - // email: "1223v@naver.com", - // }; - return (
+
기본정보
+
이름
-
{userData.name}
+
{name}
이메일
-
{userData.email}
+
{email}
휴대폰
-
{userData.phone}
+
{phone}
+
setIsOpen(true)}> 로그아웃 @@ -130,7 +69,7 @@ function MyprofilePage() { {isOpen && ( @@ -138,7 +77,7 @@ function MyprofilePage() { {isBye && ( } /> diff --git a/src/pages/OrderDetail/OrderDetail.jsx b/src/pages/OrderDetail/OrderDetail.jsx index 0d92521..31be06b 100644 --- a/src/pages/OrderDetail/OrderDetail.jsx +++ b/src/pages/OrderDetail/OrderDetail.jsx @@ -1,32 +1,26 @@ -import axios from "axios"; -import React, { useEffect, useState } from "react"; +import React from "react"; import { useLocation } from "react-router-dom"; import Header from "../../components/views/Header/Header"; import "./OrderDetail.css"; +import useFetchOrderDetails from "../../hooks/useFetchOrderDetails"; const OrderDetail = () => { - const apiUrl = process.env.REACT_APP_API_ROOT; const location = useLocation(); const params = new URLSearchParams(location.search); const orderId = params.get("orderId"); const { state } = useLocation(); - - const [detailData, setDetailData] = useState({}); - - useEffect(() => { - const config = { - withCredentials: true, - }; - - axios - .get(`${apiUrl}/api/v1/order/receipt?orderId=${orderId}`, config) - .then((res) => { - setDetailData(res.data); - }) - .catch((err) => {}); - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const { + cancelReason, + cart, + inout, + method, + orderNumber, + orderStatus, + orderTime, + salePrice, + storeName, + storePhone, + } = useFetchOrderDetails(orderId); return (
@@ -41,48 +35,62 @@ const OrderDetail = () => {
- {detailData?.orderStatus === "CANCEL" ? ( + {orderStatus === "CANCEL" ? ( - 주문 취소 - {detailData?.cancelReason === null ? : ({detailData?.cancelReason?.split(",")[1]?.split("=")[1]})} + 주문 취소 + {cancelReason === null ? ( + + ) : ( + ({cancelReason?.split(",")[1]?.split("=")[1]}) + )} ) : ( 주문 완료 )} - {detailData?.storeName} + + {storeName} +
- 주문일시: {detailData?.orderTime} - 주문번호: {detailData?.orderId} - 가게전화: {detailData?.storePhone} - 수령방식: {detailData?.inout === 1 ? "매장" : "픽업"} + 주문일시: {orderTime} + 주문번호: {orderNumber} + 결제방식: {method} + 가게전화: {storePhone} + 수령방식: {inout === 1 ? "매장" : "픽업"}
+
+
- {detailData?.cart?.carts?.map((e) => ( + {cart?.carts?.map((e) => (
americano
+
- {e.name} X {e.count} + + {e.name} X {e.count} + +
{e.options?.map((option, idx) => ( - <> + <> + + [{option.categoryName}] {option.name} + + {idx !== e.options?.length - 1 && ( - [{option.categoryName}] {option.name} + / - {idx !== e.options?.length - 1 && (/)} - - ) - )} - {/* - {e?.count} - */} -
+ )} + + ))}
+
+
{e.totalPrice && @@ -95,35 +103,50 @@ const OrderDetail = () => {
))}
+
+
상품금액 - { - detailData?.cart?.totalPrice?.toString() - .replace(/\B(?=(\d{3})+(?!\d))/g, ",") - }원 + + {cart?.totalPrice + ?.toString() + .replace(/\B(?=(\d{3})+(?!\d))/g, ",")} + 원 +
+
할인금액 - { - detailData?.salePrice && - (detailData?.salePrice === 0 ? - 0 : - `(-) ${detailData?.salePrice !== undefined && !isNaN(detailData?.salePrice) && - detailData?.salePrice?.toString() - .replace(/\B(?=(\d{3})+(?!\d))/g, ",")}`) - }원 + + {salePrice && + (salePrice === 0 + ? 0 + : `(-) ${ + salePrice !== undefined && + !isNaN(salePrice) && + salePrice + ?.toString() + .replace(/\B(?=(\d{3})+(?!\d))/g, ",") + }`)} + 원 +
+
총 결제금액 - { - detailData?.salePrice !== undefined && !isNaN(detailData?.salePrice) && - (detailData?.cart?.totalPrice - detailData?.salePrice).toString() - .replace(/\B(?=(\d{3})+(?!\d))/g, ",") - }원 + + {salePrice !== undefined && + !isNaN(salePrice) && + (cart?.totalPrice - salePrice) + .toString() + .replace(/\B(?=(\d{3})+(?!\d))/g, ",")} + 원 +
+
diff --git a/src/pages/OrderProcessPage/OrderProcessPage.jsx b/src/pages/OrderProcessPage/OrderProcessPage.jsx index 18df5b4..5b1becf 100644 --- a/src/pages/OrderProcessPage/OrderProcessPage.jsx +++ b/src/pages/OrderProcessPage/OrderProcessPage.jsx @@ -1,4 +1,3 @@ -import axios from "axios"; import React, { useEffect, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import minus from "../../assets/images/icon_minus.png"; @@ -11,6 +10,9 @@ import Header from "../../components/views/Header/Header"; import Modal from "../../components/views/Modal/Modal"; import TEXT from "../../constants/text"; import "./OrderProcess.css"; +import useFetchFoodOptionInfo from "../../hooks/useFetchFoodOptionInfo"; +import useUpdateCart from "../../hooks/useUpdateCart"; +import useResetCart from "../../hooks/useResetCart"; const OrderProcessPage = () => { let navigate = useNavigate(); @@ -20,26 +22,25 @@ const OrderProcessPage = () => { const inout = params.get("inout"); const foodieId = params.get("foodie_id"); const status = params.get("status"); + const { category, imgUrl, name, price } = useFetchFoodOptionInfo( + storeId, + foodieId, + inout + ); + const updateCart = useUpdateCart(); + const resetCart = useResetCart(); const [optionOpen, setOptionOpen] = useState(false); - const [foodOptionInfo, setFoodOptionInfo] = useState({}); const [orderCnt, setOrderCnt] = useState(1); const [isOpen, setIsOpen] = useState(false); const [modalTitle, setModalTitle] = useState(""); - - useEffect(() => { - const fetchData = async () => { - try { - const response = await axios.get( - `${process.env.REACT_APP_API_ROOT}/api/v1/order/${storeId}?foody_id=${foodieId}&inout=${inout}`, - { withCredentials: true } - ); - setFoodOptionInfo(response.data); - } catch (error) { - } - }; - fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const [activeToggles, setActiveToggles] = useState( + category?.filter((el) => el?.essential).map(() => false) + ); + const [selectedRadioTexts, setSelectedRadioTexts] = useState([]); + const [totalAmount, setTotalAmount] = useState(price); + const [prevRadioPrice, setPrevRadioPrice] = useState(category?.map(() => 0)); + const [optionIdx, setOptionIdx] = useState([]); + const [essentialOptionIdx, setEssentialOptionIdx] = useState({}); const handleCartUpdate = () => { let body = { @@ -50,25 +51,21 @@ const OrderProcessPage = () => { inout: inout, }; - axios - .post(`${process.env.REACT_APP_API_ROOT}/api/v1/order/cart`, body, { - withCredentials: true, - }) + updateCart(body) .then((res) => { + // 성공적으로 처리된 경우의 로직 setOptionIdx( - foodOptionInfo?.category + category ?.filter((el) => el?.essential) ?.map((e) => e?.options[0]?.idx) ); setEssentialOptionIdx( - foodOptionInfo?.category + category ?.filter((e) => e.essential) ?.map((cate) => cate.options[0].idx) ); navigate(`/store?storeId=${storeId}&inout=${inout}`); }) - - // 여기에서 상태 업데이트 또는 다른 로직 수행 가능 .catch((error) => { let title = "에러 발생"; // 에러가 발생한 경우에 대한 로직 @@ -91,91 +88,31 @@ const OrderProcessPage = () => { const handleCancle = () => { setIsOpen((prev) => !prev); - const apiRoot = process.env.REACT_APP_API_ROOT; - const apiUrl = `${apiRoot}/api/v1/order/cart/reset`; - - // Axios를 사용한 DELETE 요청 - const response = axios.delete(apiUrl, { withCredentials: true }); - console.log(response); - // 성공적으로 처리된 경우에 대한 로직 - - let body = { - storeId: storeId, - foodieId: foodieId, - options: [...essentialOptionIdx, ...optionIdx], - count: orderCnt, - inout: inout, - }; - - axios - .post(`${process.env.REACT_APP_API_ROOT}/api/v1/order/cart`, body, { - withCredentials: true, + resetCart() + .then(() => { + // 성공적으로 리셋된 후, 장바구니 업데이트 로직 + let body = { + storeId: storeId, + foodieId: foodieId, + options: [...essentialOptionIdx, ...optionIdx], + count: orderCnt, + inout: inout, + }; + + return updateCart(body); // 장바구니 업데이트 함수 호출, body 데이터 전달 }) - .then((res) => { + .then(() => { + // 장바구니 업데이트 후의 로직 navigate(`/store?storeId=${storeId}&inout=${inout}`); }) - - // 여기에서 상태 업데이트 또는 다른 로직 수행 가능 .catch((error) => { - // 에러가 발생한 경우에 대한 로직 - console.error("Error resetting cart", error); + // 에러 처리 로직 + console.error("Error in cart operation", error); }); - // 모달을 닫습니다. - setIsOpen(false); + setIsOpen((prev) => !prev); }; - const [activeToggles, setActiveToggles] = useState( - foodOptionInfo?.category?.filter((el) => el?.essential).map(() => false) - ); - const [selectedRadioTexts, setSelectedRadioTexts] = useState( - foodOptionInfo && - foodOptionInfo.category - ?.filter((el) => el?.essential) - .map((e) => `${e.options[0]?.name}`) - ); - const [totalAmount, setTotalAmount] = useState( - foodOptionInfo && foodOptionInfo.price && foodOptionInfo?.price - ); - const [prevRadioPrice, setPrevRadioPrice] = useState( - foodOptionInfo?.category?.map(() => 0) - ); - const [optionIdx, setOptionIdx] = useState([]); - const [essentialOptionIdx, setEssentialOptionIdx] = useState({}); - - useEffect(() => { - setActiveToggles( - foodOptionInfo?.category?.filter((e) => e?.essential).map(() => false) - ); - setSelectedRadioTexts( - foodOptionInfo.category - ?.filter((el) => el?.essential) - .map((e) => `${e?.options[0]?.name}`) - ); - setTotalAmount( - orderCnt && - orderCnt * - (foodOptionInfo?.price + - parseInt( - foodOptionInfo?.category - ?.filter((el) => el?.essential) - .map((e) => parseInt(e?.options[0]?.price)) - .reduce((prev, curr) => prev + curr, 0) - )) - ); - setPrevRadioPrice( - foodOptionInfo?.category - ?.filter((el) => el?.essential) - ?.map((e) => e?.options[0]?.price) - ); - setEssentialOptionIdx( - foodOptionInfo?.category - ?.filter((e) => e?.essential) - ?.map((cate) => cate?.options[0]?.idx) - ); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [foodOptionInfo]); - const handleToggle = (index) => { setActiveToggles((prevToggles) => { const toggles = [...prevToggles]; @@ -229,6 +166,48 @@ const OrderProcessPage = () => { setOrderCnt((prev) => (prev === 1 ? 1 : newOrderCnt)); }; + useEffect(() => { + setTotalAmount(price); + }, [price]); + + useEffect(() => { + if (category && category.length > 0) { + const essentialOptions = category + .filter((el) => el?.essential) + .map((e) => e.options[0]?.name); + setSelectedRadioTexts(essentialOptions); + } + }, [category]); + + useEffect(() => { + setActiveToggles(category?.filter((e) => e?.essential).map(() => false)); + setSelectedRadioTexts( + category + ?.filter((el) => el?.essential) + .map((e) => `${e?.options[0]?.name}`) + ); + setTotalAmount( + orderCnt && + orderCnt * + (price + + parseInt( + category + ?.filter((el) => el?.essential) + .map((e) => parseInt(e?.options[0]?.price)) + .reduce((prev, curr) => prev + curr, 0) + )) + ); + setPrevRadioPrice( + category?.filter((el) => el?.essential)?.map((e) => e?.options[0]?.price) + ); + setEssentialOptionIdx( + category + ?.filter((e) => e?.essential) + ?.map((cate) => cate?.options[0]?.idx) + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [category, price, orderCnt]); + return (
{ menuImg -
- {foodOptionInfo?.name} -
+
{name}
- {foodOptionInfo?.category?.length ? - foodOptionInfo.category + {category?.length ? ( + category .filter((c, i) => c?.essential) .map((category, index) => (
{ )}
)) - : ( - <> - )} - {foodOptionInfo?.category?.filter((e) => !e?.essential).length ? ( + ) : ( + <> + )} + {category?.filter((e) => !e?.essential).length ? (
{ }} > {optionOpen && - foodOptionInfo?.category?.length && - foodOptionInfo.category + category?.length && + category .filter((c, i) => !c.essential) .map((category, index) => ( diff --git a/src/pages/PackagingStatusPage/PackagingStatusPage.jsx b/src/pages/PackagingStatusPage/PackagingStatusPage.jsx index 9842520..c066d2c 100644 --- a/src/pages/PackagingStatusPage/PackagingStatusPage.jsx +++ b/src/pages/PackagingStatusPage/PackagingStatusPage.jsx @@ -1,34 +1,33 @@ -import axios from "axios"; -import React, { useEffect, useState } from "react"; +import React from "react"; import { Link, useLocation } from "react-router-dom"; import takeIn from "../../assets/images/take_in.svg"; import takeOut from "../../assets/images/take_out.svg"; import Header from "../../components/views/Header/Header"; import "./PackagingStatusPage.css"; +import useFetchEvent from "../../hooks/useFetchEvent"; const PackagingStatusPage = () => { const location = useLocation(); const params = new URLSearchParams(location.search); const storeId = params.get("storeId"); - const apiRoot = process.env.REACT_APP_API_ROOT; + const { eventImgUrl, takeOutEvent } = useFetchEvent(storeId); - const [event, setEvent] = useState(null); - useEffect(() => { - // API 엔드포인트 - const apiUrl = `${apiRoot}/api/v1/store/${storeId}/event`; + // useEffect(() => { + // // API 엔드포인트 + // const apiUrl = `${apiRoot}/api/v1/store/${storeId}/event`; - // axios 라이브러리를 사용하여 API에 GET 요청 보내기 - axios - .get(apiUrl) - .then((response) => { - // API 응답을 상태에 저장 - setEvent(response.data); - }) - .catch((error) => { - console.error("Error fetching store data:", error); - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); // 두 번째 인자로 빈 배열을 전달하여 컴포넌트가 마운트될 때만 실행 + // // axios 라이브러리를 사용하여 API에 GET 요청 보내기 + // axios + // .get(apiUrl) + // .then((response) => { + // // API 응답을 상태에 저장 + // setEvent(response.data); + // }) + // .catch((error) => { + // console.error("Error fetching store data:", error); + // }); + // // eslint-disable-next-line react-hooks/exhaustive-deps + // }, []); // 두 번째 인자로 빈 배열을 전달하여 컴포넌트가 마운트될 때만 실행 return (
@@ -40,7 +39,7 @@ const PackagingStatusPage = () => { promotion @@ -69,9 +68,7 @@ const PackagingStatusPage = () => { alt="takeOut" /> 가져갈게요 - - {event?.takeOutEvent} - + {takeOutEvent}
diff --git a/src/pages/PaymentPage/ApplyCouponPage.jsx b/src/pages/PaymentPage/ApplyCouponPage.jsx index cc1bd36..6e90808 100644 --- a/src/pages/PaymentPage/ApplyCouponPage.jsx +++ b/src/pages/PaymentPage/ApplyCouponPage.jsx @@ -1,9 +1,8 @@ import Header from "../../components/views/Header/Header"; -import { useEffect, useState } from "react"; -import axios from "axios"; import { Link, useLocation } from "react-router-dom"; import "./ApplyCouponPage.css"; import empty from "../../assets/images/storage_empty.svg"; +import useFetchCoupons from "../../hooks/useFetchCoupons"; const ApplyCouponPage = () => { const location = useLocation(); @@ -11,24 +10,7 @@ const ApplyCouponPage = () => { const storeId = params.get("storeId"); const inout = params.get("inout"); const cartId = params.get("cartId"); - const apiRoot = process.env.REACT_APP_API_ROOT; - const [coupon, setCoupon] = useState(null); - // const [selectedCoupon, setSelectedCoupon] = useState(null); - - useEffect(() => { - const fetchData = async () => { - try { - const response = await axios.get(`${apiRoot}/api/v1/coupon`, { - withCredentials: true, - }); - setCoupon(response.data); - } catch (error) { - console.error(error); - } - }; - fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const coupons = useFetchCoupons(); return (
@@ -41,9 +23,9 @@ const ApplyCouponPage = () => { />
- {coupon && coupon.coupons.length > 0 ? ( + {coupons && coupons.length > 0 ? (
- {coupon.coupons.map((item) => ( + {coupons.map((item) => ( { }} className="coupon-page__coupon-item" key={item.couponId} - // onClick={() => setSelectedCoupon(item)} style={{ textDecoration: "none" }} >
diff --git a/src/pages/PaymentPage/PaymentPage.jsx b/src/pages/PaymentPage/PaymentPage.jsx index b13cdad..c0ca178 100644 --- a/src/pages/PaymentPage/PaymentPage.jsx +++ b/src/pages/PaymentPage/PaymentPage.jsx @@ -1,12 +1,13 @@ import { loadPaymentWidget } from "@tosspayments/payment-widget-sdk"; -import axios from "axios"; -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect, useRef } from "react"; import { Link, useLocation } from "react-router-dom"; import noImageMenu from "../../assets/images/no_image_menu.svg"; import takeIn from "../../assets/images/take_in.svg"; import takeOut from "../../assets/images/take_out.svg"; import Header from "../../components/views/Header/Header"; import "./PaymentPage.css"; +import useFetchCartData from "../../hooks/useFetchCartData"; +import useRequestPayment from "../../hooks/useRequestPayment"; const clientKey = process.env.REACT_APP_TOSS_CLIENT_KEY; const customerKey = "OSlBWOomTvjxwqJTcNtEB"; @@ -14,33 +15,19 @@ const customerKey = "OSlBWOomTvjxwqJTcNtEB"; const PaymentPage = () => { const location = useLocation(); const params = new URLSearchParams(location.search); - const storeId = params.get("storeId"); - const inout = params.get("inout"); const cartId = params.get("cartId"); const couponId = params.get("couponId"); const salePrice = params.get("salePrice"); - const apiRoot = process.env.REACT_APP_API_ROOT; const paymentWidgetRef = useRef(null); const paymentMethodsWidgetRef = useRef(null); - const [paymentData, setPaymentData] = useState(null); - const [price, setPrice] = useState(paymentData?.totalPrice); + const { carts, edit, imgUrl, inOut, isOpened, name, storeId, totalPrice } = + useFetchCartData(cartId); + const requestPayment = useRequestPayment(); - useEffect(() => { - const fetchData = async () => { - try { - const response = await axios.get( - `${apiRoot}/api/v1/order/cart?cartId=${cartId}`, - { withCredentials: true } - ); - setPaymentData(response.data); - setPrice(response.data.totalPrice); - } catch (error) { - console.error(error); - } - }; - fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + const paymentRequest = () => { + const paymentWidget = paymentWidgetRef.current; + requestPayment(cartId, couponId, paymentWidget); + }; useEffect(() => { (async () => { @@ -55,7 +42,7 @@ const PaymentPage = () => { // https://docs.tosspayments.com/reference/widget-sdk#renderpaymentmethods선택자-결제-금액-옵션 const paymentMethodsWidget = paymentWidget.renderPaymentMethods( "#payment-page__payment-widget", - { value: price - salePrice }, + { value: totalPrice - salePrice }, // 렌더링하고 싶은 결제 UI의 variantKey // 아래 variantKey는 문서용 테스트키와 연동되어 있습니다. 멀티 UI를 직접 만들고 싶다면 계약이 필요해요. // https://docs.tosspayments.com/guides/payment-widget/admin#멀티-결제-ui @@ -72,7 +59,7 @@ const PaymentPage = () => { paymentWidgetRef.current = paymentWidget; paymentMethodsWidgetRef.current = paymentMethodsWidget; })(); - }, [price, salePrice]); + }, [totalPrice, salePrice]); useEffect(() => { const paymentMethodsWidget = paymentMethodsWidgetRef.current; @@ -84,62 +71,59 @@ const PaymentPage = () => { // ------ 금액 업데이트 ------ // 새로운 결제 금액을 넣어주세요. // https://docs.tosspayments.com/reference/widget-sdk#updateamount결제-금액 - paymentMethodsWidget.updateAmount(price - salePrice); - }, [price, salePrice]); - - const paymentRequest = async () => { - let body = { - cartId: cartId, - couponId: couponId, - }; - - await axios - .post(`${process.env.REACT_APP_API_ROOT}/api/v1/order/toss`, body, { - withCredentials: true, - }) - .then((res) => { - const paymentWidget = paymentWidgetRef.current; - - // ------ '결제하기' 버튼 누르면 결제창 띄우기 ------ - // 더 많은 결제 정보 파라미터는 결제위젯 SDK에서 확인하세요. - // https://docs.tosspayments.com/reference/widget-sdk#requestpayment결제-정보 - paymentWidget?.requestPayment(res.data); - }) - - // 여기에서 상태 업데이트 또는 다른 로직 수행 가능 - .catch((error) => { - // 에러가 발생한 경우에 대한 로직 - console.error("Error resetting cart", error); - // 에러 상태에 대한 처리를 수행하거나 사용자에게 알림 등을 표시할 수 있습니다. - }); - }; + paymentMethodsWidget.updateAmount(totalPrice - salePrice); + }, [totalPrice, salePrice]); + + // const paymentRequest = async () => { + // let body = { + // cartId: cartId, + // couponId: couponId, + // }; + + // await axios + // .post(`${process.env.REACT_APP_API_ROOT}/api/v1/order/toss`, body, { + // withCredentials: t + // const requestPayment = useRequestPayment();rue, + // }) + // .then((res) => { + // const paymentWidget = paymentWidgetRef.current; + + // // ------ '결제하기' 버튼 누르면 결제창 띄우기 ------ + // // 더 많은 결제 정보 파라미터는 결제위젯 SDK에서 확인하세요. + // // https://docs.tosspayments.com/reference/widget-sdk#requestpayment결제-정보 + // paymentWidget?.requestPayment(res.data); + // }) + + // // 여기에서 상태 업데이트 또는 다른 로직 수행 가능 + // .catch((error) => { + // // 에러가 발생한 경우에 대한 로직 + // console.error("Error resetting cart", error); + // // 에러 상태에 대한 처리를 수행하거나 사용자에게 알림 등을 표시할 수 있습니다. + // }); + // }; return (
cafeImg - - {paymentData?.name} - + {name}
- {paymentData?.carts.map((item) => ( + {carts.map((item) => (
{
수령방식
- {inout === "1" ? ( + {inOut === 1 ? ( <> { /> 먹고갈게요 - ) : inout === "2" ? ( + ) : inOut === 2 ? ( <> { )} @@ -239,22 +223,19 @@ const PaymentPage = () => {
상품금액 - {paymentData?.totalPrice && - paymentData.totalPrice - .toString() - .replace(/\B(?=(\d{3})+(?!\d))/g, ",") + "원"} + {totalPrice.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + "원"}
할인금액 - {salePrice && ( - - (-) - {salePrice.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + - "원"} - - )} + + {salePrice > 0 + ? "(-)" + + salePrice.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + + "원" + : "0원"} +
@@ -262,8 +243,8 @@ const PaymentPage = () => {
총 결제 금액 - {paymentData?.totalPrice && - (paymentData.totalPrice - salePrice) + {totalPrice && + (totalPrice - salePrice) .toString() .replace(/\B(?=(\d{3})+(?!\d))/g, ",") + "원"} @@ -274,7 +255,7 @@ const PaymentPage = () => {
- {paymentData?.isOpened ? ( + {isOpened ? (
결제하기
diff --git a/src/pages/PaymentPage/Redirect/PaymentFailPage.jsx b/src/pages/PaymentPage/Redirect/PaymentFailPage.jsx index 5c27852..42e8b48 100644 --- a/src/pages/PaymentPage/Redirect/PaymentFailPage.jsx +++ b/src/pages/PaymentPage/Redirect/PaymentFailPage.jsx @@ -1,8 +1,7 @@ -import axios from "axios"; -import { useEffect } from "react"; import { Link, useLocation } from "react-router-dom"; import paymentFail from "../../../assets/images/payment_fail.png"; import "./PaymentRedirectPage.css"; +import useFetchPaymentFail from "../../../hooks/useFetchPaymentFail"; const PaymentFailPage = () => { const location = useLocation(); @@ -10,22 +9,7 @@ const PaymentFailPage = () => { const message = params.get("message"); const orderId = params.get("orderId"); const code = params.get("code"); - const apiRoot = process.env.REACT_APP_API_ROOT; - - useEffect(() => { - axios - .get( - `${apiRoot}/api/v1/order/toss/fail?message=${message}&orderId=${orderId}&code=${code}`, - { withCredentials: true } - ) - .then((response) => { - console.log(response); - }) - .catch((error) => { - console.error("Error sending fail URL request:", error); - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + useFetchPaymentFail(message, orderId, code); return (
diff --git a/src/pages/PaymentPage/Redirect/PaymentSuccessPage.jsx b/src/pages/PaymentPage/Redirect/PaymentSuccessPage.jsx index 4f85f22..ac30c1b 100644 --- a/src/pages/PaymentPage/Redirect/PaymentSuccessPage.jsx +++ b/src/pages/PaymentPage/Redirect/PaymentSuccessPage.jsx @@ -1,9 +1,9 @@ -import axios from "axios"; -import { useEffect, useState } from "react"; +import React from "react"; import { Link, useLocation, useNavigate } from "react-router-dom"; import paymentSuccess from "../../../assets/images/payment_success.png"; import "./PaymentRedirectPage.css"; import Modal from "../../../components/views/Modal/Modal"; +import usePaymentSuccess from "../../../hooks/usePaymentSuccess"; const PaymentSuccessPage = () => { const location = useLocation(); @@ -12,46 +12,62 @@ const PaymentSuccessPage = () => { const orderId = params.get("orderId"); const paymentKey = params.get("paymentKey"); const amount = params.get("amount"); - const apiRoot = process.env.REACT_APP_API_ROOT; const navigate = useNavigate(); - const [isOpen, setIsOpen] = useState(false); + const { paymentStatus, paymentMessage } = usePaymentSuccess( + paymentType, + orderId, + paymentKey, + amount + ); + const [isOpen, setIsOpen] = React.useState(false); + + React.useEffect(() => { + if (paymentStatus === 200 && paymentMessage) { + if ( + paymentMessage !== "결제 성공." && + paymentMessage !== "Order is already end." + ) { + setIsOpen((prev) => !prev); + } + } + }, [paymentStatus, paymentMessage]); const handleCancle = async () => { setIsOpen((prev) => !prev); navigate(-1); }; - useEffect(() => { - axios - .get( - `${apiRoot}/api/v1/order/toss/success?paymentType=${paymentType}&orderId=${orderId}&paymentKey=${paymentKey}&amount=${amount}`, - { withCredentials: true } - ) - .then((response) => { - console.log(response); - if (response.status === 400) { - navigate(-1); - } else if (response.status === 200) { - if ( - response.message !== "Order is already end." || - response.message !== "결제 성공." - ) { - isOpen && ( - - ); - } - } - }) - .catch((error) => { - console.error("Error sending success URL request:", error); - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + // useEffect(() => { + // axios + // .get( + // `${apiRoot}/api/v1/order/toss/success?paymentType=${paymentType}&orderId=${orderId}&paymentKey=${paymentKey}&amount=${amount}`, + // { withCredentials: true } + // ) + // .then((response) => { + // console.log(response); + // if (response.status === 400) { + // navigate(-1); + // } else if (response.status === 200) { + // if ( + // response.message !== "Order is already end." || + // response.message !== "결제 성공." + // ) { + // isOpen && ( + // + // ); + // } + // } + // }) + // .catch((error) => { + // console.error("Error sending success URL request:", error); + // }); + // // eslint-disable-next-line react-hooks/exhaustive-deps + // }, []); return (
@@ -60,7 +76,9 @@ const PaymentSuccessPage = () => { alt="ReadyVery" className="payment-redirect-page__berry" /> +
결제 완료!
+ { > 주문현황 확인 + + {isOpen && ( + + )}
); }; diff --git a/src/pages/ReadyPage/ReadyPage.jsx b/src/pages/ReadyPage/ReadyPage.jsx index b6ed5bf..2fc775c 100644 --- a/src/pages/ReadyPage/ReadyPage.jsx +++ b/src/pages/ReadyPage/ReadyPage.jsx @@ -1,31 +1,13 @@ -import axios from "axios"; -import React, { useEffect, useState } from "react"; +import React from "react"; import { Link } from "react-router-dom"; import "./ReadyPage.css"; - import Header from "../../components/views/Header/Header"; import StateBox from "../../components/views/StateBox/StateBox"; - import empty from "../../assets/images/storage_empty.svg"; +import useFetchFastOrderHistory from "../../hooks/useFetchFastOrderHistory"; function ReadyPage() { - const apiUrl = process.env.REACT_APP_API_ROOT; - const [storageList, setStorageList] = useState([]); - - useEffect(() => { - const config = { - withCredentials: true - }; - - axios.get(`${apiUrl}/api/v1/order/history/fast`, config) - .then((res) => { - setStorageList(res.data.receipts?.reverse()); - }) - .catch((err) => {}); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - + const storageList = useFetchFastOrderHistory(); return (
diff --git a/src/pages/StoreDetailPage/StoreDetailPage.jsx b/src/pages/StoreDetailPage/StoreDetailPage.jsx index f93e4b5..2787ee1 100644 --- a/src/pages/StoreDetailPage/StoreDetailPage.jsx +++ b/src/pages/StoreDetailPage/StoreDetailPage.jsx @@ -1,135 +1,35 @@ -import axios from "axios"; import React, { useEffect, useState } from "react"; import { Link, useLocation } from "react-router-dom"; import goLeft from "../../assets/images/go_left.svg"; import goRight from "../../assets/images/go_right.svg"; import Header from "../../components/views/Header/Header"; import "./StoreDetailPage.css"; +import useFetchStoreInfo from "../../hooks/useFetchStoreInfo"; +import useFetchStoreMenu from "../../hooks/useFetchStoreMenu"; +import useFetchCartData from "../../hooks/useFetchCartData"; +import useFetchCartCount from "../../hooks/useFetchCartCount"; const StoreDetailPage = () => { const location = useLocation(); const params = new URLSearchParams(location.search); - const storeId = params.get("storeId"); + const storeIdParam = params.get("storeId"); const inout = params.get("inout"); - const apiRoot = process.env.REACT_APP_API_ROOT; - // const scrollRef = useRef(); - // const [isScrollable, setIsScrollable] = useState(false); - const [caffeeInfo, setCaffeeInfo] = useState(null); const [selectedCategory, setSelectedCategory] = useState([]); - const [menu, setMenu] = useState(null); - const [hasResponse, setHasResponse] = useState(false); - const [totalCount, setTotalCount] = useState(0); - const [totalPrice, setTotalPrice] = useState(0); - const [cart, setCart] = useState(null); - - useEffect(() => { - const fetchData = async () => { - try { - const response = await axios.get(`${apiRoot}/api/v1/store/${storeId}`); - setCaffeeInfo(response.data); - } catch (error) { - console.error(error); - } - }; - fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - useEffect(() => { - // API 엔드포인트 - const apiUrl = `${apiRoot}/api/v1/store/${storeId}/menu?inout=${inout}`; - - // axios 라이브러리를 사용하여 API에 GET 요청 보내기 - axios - .get(apiUrl) - .then((response) => { - // API 응답을 상태에 저장 - setMenu(response.data); - setSelectedCategory(response.data.menu[0]); - }) - .catch((error) => { - console.error("Error fetching store data:", error); - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); // 두 번째 인자로 빈 배열을 전달하여 컴포넌트가 마운트될 때만 실행 + const { address, imgs, storeName, openTime, phone, status } = + useFetchStoreInfo(storeIdParam); + const menu = useFetchStoreMenu(storeIdParam, inout); + const { cartIdApi, carts, storeId, totalPrice } = useFetchCartData(); + const totalCount = useFetchCartCount(); const handleCategoryClick = (category) => { setSelectedCategory(category); }; useEffect(() => { - const fetchData = () => { - axios - .get(`${apiRoot}/api/v1/order/cart`, { - withCredentials: true, - }) - .then((response) => { - if (response.data.carts.length > 0) { - setHasResponse(true); - setTotalPrice(response.data.totalPrice); - setCart(response.data); - } - }) - .catch((error) => { - console.error(error); - // 만약 에러가 발생하면 false를 설정 - setHasResponse(false); - }); - }; - - fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [apiRoot, inout]); - - useEffect(() => { - const fetchData = async () => { - try { - const response = await axios.get(`${apiRoot}/api/v1/order/cart/count`, { - withCredentials: true, - }); - setTotalCount(response.data.count); - } catch (error) { - console.error(error); - } - }; - fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - // useEffect(() => { - // const currentRef = scrollRef.current; - - // if (currentRef) { - // const handleScroll = () => { - // const scrollWidth = currentRef.scrollWidth; - // const clientWidth = currentRef.clientWidth; - // setIsScrollable(scrollWidth > clientWidth); - // }; - - // currentRef.addEventListener("scroll", handleScroll); - - // // 컴포넌트가 언마운트될 때 이벤트 리스너 제거 - // return () => { - // if (currentRef) { - // currentRef.removeEventListener("scroll", handleScroll); - // } - // }; - // } - // }, []); - - // const handleGoLeft = () => { - // if (scrollRef.current) { - // // 스크롤을 왼쪽으로 100px 이동 - // scrollRef.current.scrollLeft -= 100; - // } - // }; - - // const handleGoRight = () => { - // if (scrollRef.current) { - // // 스크롤을 오른쪽으로 100px 이동 - // scrollRef.current.scrollLeft += 100; - // } - // }; + if (menu && menu.menu && menu.menu.length > 0) { + setSelectedCategory(menu.menu[0]); + } + }, [menu]); return (
@@ -144,13 +44,13 @@ const StoreDetailPage = () => {
caffee banner
- {caffeeInfo?.name} + {storeName}
@@ -158,7 +58,7 @@ const StoreDetailPage = () => { {"연락처"} - {caffeeInfo?.phone} + {phone}
@@ -170,7 +70,7 @@ const StoreDetailPage = () => { {"주소"} - {caffeeInfo?.address} + {address}
@@ -182,7 +82,7 @@ const StoreDetailPage = () => { {"영업 시간"} - {caffeeInfo?.openTime.split("\n").map((line, index) => ( + {openTime.split("\n").map((line, index) => ( {line}
@@ -234,7 +134,7 @@ const StoreDetailPage = () => { Array.isArray(selectedCategory.menuItems) ? ( selectedCategory.menuItems.map((item, index) => ( @@ -276,9 +176,9 @@ const StoreDetailPage = () => { )}
- {hasResponse && cart.storeId === parseInt(storeId) && ( + {storeId === parseInt(storeIdParam) && carts.length > 0 && (