From 46562b151abb2fb93b6a93c5992953624a29d7ca Mon Sep 17 00:00:00 2001 From: thisishwarang <101498590+thisishwarang@users.noreply.github.com> Date: Mon, 30 Sep 2024 23:31:04 +0900 Subject: [PATCH 1/5] =?UTF-8?q?[Feat/#52]=20=EC=A3=BC=EB=AC=B8=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=ED=83=9C=EB=B8=94=EB=A6=BF=20=EB=B7=B0=20=ED=8D=BC?= =?UTF-8?q?=EB=B8=94=EB=A6=AC=EC=8B=B1=20=EC=99=84=EB=A3=8C=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 테블릿 뷰 퍼블리싱 중 * feat: 각 섹션 컴포넌트화 * feat: 주문 확인 퍼블리싱 완료 --- public/svg/ic_refresh.svg | 3 ++ src/App.tsx | 2 + src/assets/svg/IcRefresh.tsx | 15 ++++++ src/assets/svg/index.ts | 1 + src/constants/routePath.ts | 5 ++ .../components/DialButton/DialButton.style.ts | 19 +++++++ .../components/DialButton/DialButton.tsx | 18 +++++++ .../OrderInfoSection.style.ts | 32 ++++++++++++ .../OrderInfoSection/OrderInfoSection.tsx | 45 ++++++++++++++++ .../OrderNumberSearchSection.style.ts | 29 +++++++++++ .../OrderNumberSearchSection.tsx | 51 +++++++++++++++++++ .../OrderTrackingSection.style.ts | 13 +++++ .../OrderTrackingSection.tsx | 25 +++++++++ .../components/PayButton/PayButton.style.ts | 23 +++++++++ .../components/PayButton/PayButton.tsx | 18 +++++++ .../RecentOrderCard/RecentOrderCard.style.ts | 21 ++++++++ .../RecentOrderCard/RecentOrderCard.tsx | 17 +++++++ src/pages/orderCheck/components/index.ts | 15 ++++++ .../orderCheck/page/OrderCheckPage.style.ts | 30 +++++++++++ src/pages/orderCheck/page/OrderCheckPage.tsx | 22 ++++++++ src/routes/index.ts | 9 +++- src/routes/orderCheckRoutes.tsx | 12 +++++ src/styles/global.ts | 8 ++- src/styles/theme.ts | 28 ++++++++++ 24 files changed, 458 insertions(+), 3 deletions(-) create mode 100644 public/svg/ic_refresh.svg create mode 100644 src/assets/svg/IcRefresh.tsx create mode 100644 src/pages/orderCheck/components/DialButton/DialButton.style.ts create mode 100644 src/pages/orderCheck/components/DialButton/DialButton.tsx create mode 100644 src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.style.ts create mode 100644 src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx create mode 100644 src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.style.ts create mode 100644 src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx create mode 100644 src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts create mode 100644 src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx create mode 100644 src/pages/orderCheck/components/PayButton/PayButton.style.ts create mode 100644 src/pages/orderCheck/components/PayButton/PayButton.tsx create mode 100644 src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.style.ts create mode 100644 src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.tsx create mode 100644 src/pages/orderCheck/components/index.ts create mode 100644 src/pages/orderCheck/page/OrderCheckPage.style.ts create mode 100644 src/pages/orderCheck/page/OrderCheckPage.tsx create mode 100644 src/routes/orderCheckRoutes.tsx diff --git a/public/svg/ic_refresh.svg b/public/svg/ic_refresh.svg new file mode 100644 index 0000000..6aeba75 --- /dev/null +++ b/public/svg/ic_refresh.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/App.tsx b/src/App.tsx index 64dc0c6..d3964d2 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,6 +4,7 @@ import { homeRoutes, orderInfoRoutes, adminRoutes, + orderCheckRoutes, } from "@routes"; import GlobalStyle from "@styles/global"; import theme from "@styles/theme"; @@ -15,6 +16,7 @@ const allRoutes = [ ...orderInfoRoutes, ...experienceOrderInfoRoutes, ...adminRoutes, + ...orderCheckRoutes, ]; const router = createBrowserRouter([...allRoutes]); diff --git a/src/assets/svg/IcRefresh.tsx b/src/assets/svg/IcRefresh.tsx new file mode 100644 index 0000000..ebf161e --- /dev/null +++ b/src/assets/svg/IcRefresh.tsx @@ -0,0 +1,15 @@ +import type { SVGProps } from "react"; +const SvgIcRefresh = (props: SVGProps) => ( + + + +); +export default SvgIcRefresh; diff --git a/src/assets/svg/index.ts b/src/assets/svg/index.ts index f3ffe3e..d6e0054 100644 --- a/src/assets/svg/index.ts +++ b/src/assets/svg/index.ts @@ -12,3 +12,4 @@ export { default as IcFix } from "./IcFix"; export { default as IcMainCharacter } from "./IcMainCharacter"; export { default as IcMinus } from "./IcMinus"; export { default as IcPlus } from "./IcPlus"; +export { default as IcRefresh } from "./IcRefresh"; diff --git a/src/constants/routePath.ts b/src/constants/routePath.ts index 8e5251a..4d5f13e 100644 --- a/src/constants/routePath.ts +++ b/src/constants/routePath.ts @@ -22,10 +22,15 @@ const adminPages = { ADMIN_TAB: "/admin/:tab", }; +const orderCheckPages = { + ORDER_CHECK: "/order-check", +}; + export default { ...productHomePages, ...experienceHomePages, ...orderInfoPages, ...experienceProductOrderInfoPages, ...adminPages, + ...orderCheckPages, }; diff --git a/src/pages/orderCheck/components/DialButton/DialButton.style.ts b/src/pages/orderCheck/components/DialButton/DialButton.style.ts new file mode 100644 index 0000000..369750a --- /dev/null +++ b/src/pages/orderCheck/components/DialButton/DialButton.style.ts @@ -0,0 +1,19 @@ +import { Theme, css } from "@emotion/react"; +import { flexGenerator } from "@styles/generator"; + +export const buttonStyle = (index: number) => (theme: Theme) => + css` + ${flexGenerator()}; + padding: 1rem; + width: 15rem; + height: 12.8rem; + border: 1px solid ${theme.color.lightgray3}; + background-color: ${index === 9 || index === 11 + ? theme.color.lightgray2 + : theme.color.white}; + `; + +export const buttonSpan = (theme: Theme) => css` + color: ${theme.color.black}; + ${theme.font["dialNumber-56"]} +`; diff --git a/src/pages/orderCheck/components/DialButton/DialButton.tsx b/src/pages/orderCheck/components/DialButton/DialButton.tsx new file mode 100644 index 0000000..7b088bf --- /dev/null +++ b/src/pages/orderCheck/components/DialButton/DialButton.tsx @@ -0,0 +1,18 @@ +import { ButtonHTMLAttributes } from "react"; +import { buttonSpan, buttonStyle } from "./DialButton.style"; + +export interface DialButtonProps + extends ButtonHTMLAttributes { + onClick: () => void; + index: number; +} + +const DialButton = ({ onClick, index, children }: DialButtonProps) => { + return ( + + ); +}; + +export default DialButton; diff --git a/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.style.ts b/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.style.ts new file mode 100644 index 0000000..50a92fe --- /dev/null +++ b/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.style.ts @@ -0,0 +1,32 @@ +import { css, Theme } from "@emotion/react"; +import { flexGenerator } from "@styles/generator"; + +export const section3Container = (theme: Theme) => css` + ${flexGenerator("column", "start", "start")}; + width: 38rem; + min-height: 100%; + background-color: ${theme.color.white}; +`; +export const section3InfoWrapper = css` + ${flexGenerator("column", "start", "start")}; + gap: 2rem; +`; + +export const section3Div = css` + ${flexGenerator("column", "start", "start")}; + gap: 0.5rem; +`; +export const graySpan = (theme: Theme) => css` + color: ${theme.color.lightgray4}; + ${theme.font["head01-b-24"]} +`; +export const blackSpan = (theme: Theme) => css` + color: ${theme.color.black}; + ${theme.font["orderCheck-36"]} +`; + +export const buttonWrapper = css` + ${flexGenerator("row", "space-between", "center")}; + width: 100%; + margin-top: auto; +`; diff --git a/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx b/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx new file mode 100644 index 0000000..c370b8f --- /dev/null +++ b/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx @@ -0,0 +1,45 @@ +import PayButton from "../PayButton/PayButton"; +import { + blackSpan, + buttonWrapper, + graySpan, + section3Container, + section3Div, + section3InfoWrapper, +} from "./OrderInfoSection.style"; + +const OrderInfoSection = () => { + return ( +
+
+
+ 주문번호 + {1004} +
+
+ 이름 + 유태승 +
+
+ 상품 + {/* api 붙이고 수정 */} + 귤 5kg (2박스) 1개 +
+
+ 총 금액 + {"100,000원"} +
+
+
+ {}}> + 결제취소 + + {}}> + 결제완료 + +
+
+ ); +}; + +export default OrderInfoSection; diff --git a/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.style.ts b/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.style.ts new file mode 100644 index 0000000..3157ef1 --- /dev/null +++ b/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.style.ts @@ -0,0 +1,29 @@ +import { css, Theme } from "@emotion/react"; +import { flexGenerator } from "@styles/generator"; + +export const section2Container = css` + ${flexGenerator("column")}; + width: 45rem; + height: 100%; +`; + +export const orderNumberStyle = (theme: Theme) => css` + ${flexGenerator()} + width: 100%; + height: 12.6rem; + padding: 2rem 0; + border: 1px solid ${theme.color.lightgray3}; + background-color: ${theme.color.white}; +`; + +export const orderNumberSpan = (theme: Theme) => css` + color: ${theme.color.black}; + ${theme.font["dialNumber-72"]} +`; + +export const dialButtonWrapper = css` + width: 100%; + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-template-rows: repeat(4, 1fr); +`; diff --git a/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx b/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx new file mode 100644 index 0000000..cb451e0 --- /dev/null +++ b/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx @@ -0,0 +1,51 @@ +import { useState } from "react"; +import DialButton from "../DialButton/DialButton"; +import { + dialButtonWrapper, + orderNumberSpan, + orderNumberStyle, + section2Container, +} from "./OrderNumberSearchSection.style"; + +const OrderNumberSearchSection = () => { + const [orderNumber, setOrderNumber] = useState(""); + const handleButtonClick = (value: string) => { + if (orderNumber.length < 4) { + setOrderNumber((prev) => prev + value); + } + }; + + const handleDelete = () => { + setOrderNumber((prev) => prev.slice(0, -1)); + }; + + const handleSearch = () => { + alert(`조회할 번호: ${orderNumber}`); + }; + return ( +
+
+ {orderNumber} +
+
+ {["1", "2", "3", "4", "5", "6", "7", "8", "9", "<-", "0", "조회"].map( + (item, i) => ( + { + if (item === "<-") handleDelete(); + else if (item === "조회") handleSearch(); + else handleButtonClick(item); + }} + index={i} + > + {item} + + ) + )} +
+
+ ); +}; + +export default OrderNumberSearchSection; diff --git a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts new file mode 100644 index 0000000..f845cf0 --- /dev/null +++ b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts @@ -0,0 +1,13 @@ +import { css, Theme } from "@emotion/react"; +import { flexGenerator } from "@styles/generator"; + +export const section1Container = (theme: Theme) => css` + ${flexGenerator("column", "start", "start")}; + padding: 2rem; + width: 26.8rem; + height: 100%; + gap: 1.5rem; + border: 1px solid ${theme.color.lightgray3}; + background-color: ${theme.color.white}; + border-radius: 10px; +`; diff --git a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx new file mode 100644 index 0000000..d7e390a --- /dev/null +++ b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx @@ -0,0 +1,25 @@ +import RecentOrderCard from "../RecentOrderCard/RecentOrderCard"; +import { section1Container } from "./OrderTrackingSection.style"; +const recentOrderList = [ + { orderNumber: 1074, senderName: "유태승" }, + { orderNumber: 1074, senderName: "유태승" }, + { orderNumber: 1074, senderName: "유태승" }, + { orderNumber: 1074, senderName: "유태승" }, + { orderNumber: 1074, senderName: "유태승" }, + { orderNumber: 1074, senderName: "유태승" }, +]; +const OrderTrackingSection = () => { + return ( +
+ {recentOrderList.map((order, i) => ( + + ))} +
+ ); +}; + +export default OrderTrackingSection; diff --git a/src/pages/orderCheck/components/PayButton/PayButton.style.ts b/src/pages/orderCheck/components/PayButton/PayButton.style.ts new file mode 100644 index 0000000..dbe3cae --- /dev/null +++ b/src/pages/orderCheck/components/PayButton/PayButton.style.ts @@ -0,0 +1,23 @@ +import { css, Theme } from "@emotion/react"; +import { flexGenerator } from "@styles/generator"; + +export const buttonStyle = (theme: Theme) => css` + ${flexGenerator()}; + width: 18rem; + height: 8.8rem; + padding: 1rem; + border: 1px solid ${theme.color.black}; + border-radius: 20px; + ${theme.font["orderCheck-36"]} +`; + +export const buttonVariant = { + fill: (theme: Theme) => css` + color: ${theme.color.white}; + background-color: ${theme.color.orange}; + `, + stroke: (theme: Theme) => css` + color: ${theme.color.black}; + background-color: ${theme.color.white}; + `, +}; diff --git a/src/pages/orderCheck/components/PayButton/PayButton.tsx b/src/pages/orderCheck/components/PayButton/PayButton.tsx new file mode 100644 index 0000000..285b283 --- /dev/null +++ b/src/pages/orderCheck/components/PayButton/PayButton.tsx @@ -0,0 +1,18 @@ +import { ButtonHTMLAttributes } from "react"; +import { buttonStyle, buttonVariant } from "./PayButton.style"; + +export interface PayButtonProps + extends ButtonHTMLAttributes { + variant: "fill" | "stroke"; + onClick: () => void; +} + +const PayButton = ({ variant, onClick, children }: PayButtonProps) => { + return ( + + ); +}; + +export default PayButton; diff --git a/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.style.ts b/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.style.ts new file mode 100644 index 0000000..c75b2c1 --- /dev/null +++ b/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.style.ts @@ -0,0 +1,21 @@ +import { css, Theme } from "@emotion/react"; +import { flexGenerator } from "@styles/generator"; + +export const cardWrapper = (theme: Theme) => css` + ${flexGenerator()}; + gap: 1rem; + width: 100%; + padding: 1.5rem; + border-radius: 10px; + background-color: ${theme.color.lightorange}; +`; + +export const numberStyle = (theme: Theme) => css` + color: ${theme.color.orange}; + ${theme.font["orderCheck-32"]} +`; + +export const nameStyle = (theme: Theme) => css` + color: ${theme.color.black}; + ${theme.font["orderCheck-32"]} +`; diff --git a/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.tsx b/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.tsx new file mode 100644 index 0000000..de722c8 --- /dev/null +++ b/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.tsx @@ -0,0 +1,17 @@ +import { cardWrapper, nameStyle, numberStyle } from "./RecentOrderCard.style"; + +interface RecentOrderCardProps { + orderNumber: number; + senderName: string; +} + +const RecentOrderCard = ({ orderNumber, senderName }: RecentOrderCardProps) => { + return ( +
+ {orderNumber}번 + {senderName} +
+ ); +}; + +export default RecentOrderCard; diff --git a/src/pages/orderCheck/components/index.ts b/src/pages/orderCheck/components/index.ts new file mode 100644 index 0000000..b3956ba --- /dev/null +++ b/src/pages/orderCheck/components/index.ts @@ -0,0 +1,15 @@ +import DialButton from "./DialButton/DialButton"; +import PayButton from "./PayButton/PayButton"; +import OrderTrackingSection from "./OrderTrackingSection/OrderTrackingSection"; +import RecentOrderCard from "./RecentOrderCard/RecentOrderCard"; +import OrderNumberSearchSection from "./OrderNumberSearchSection/OrderNumberSearchSection"; +import OrderInfoSection from "./OrderInfoSection/OrderInfoSection"; + +export { + DialButton, + PayButton, + OrderTrackingSection, + RecentOrderCard, + OrderNumberSearchSection, + OrderInfoSection, +}; diff --git a/src/pages/orderCheck/page/OrderCheckPage.style.ts b/src/pages/orderCheck/page/OrderCheckPage.style.ts new file mode 100644 index 0000000..4763ffc --- /dev/null +++ b/src/pages/orderCheck/page/OrderCheckPage.style.ts @@ -0,0 +1,30 @@ +import { css, Theme } from "@emotion/react"; +import { flexGenerator } from "@styles/generator"; + +export const orderCheckLayout = (theme: Theme) => css` + ${flexGenerator()}; + position: absolute; + top: 0; + left: 0; + padding: 9.3rem 6.1rem 6.7rem; + gap: 3rem; + width: 100vw; + height: 100%; + background-color: ${theme.color.white}; +`; + +export const refreshButton = (theme: Theme) => css` + position: absolute; + top: 50px; + right: 50px; + ${flexGenerator()}; + width: 8rem; + height: 8rem; + border-radius: 40px; + background-color: ${theme.color.lightorange}; +`; + +export const iconStyle = css` + width: 3.2rem; + height: 3.2rem; +`; diff --git a/src/pages/orderCheck/page/OrderCheckPage.tsx b/src/pages/orderCheck/page/OrderCheckPage.tsx new file mode 100644 index 0000000..c279f8b --- /dev/null +++ b/src/pages/orderCheck/page/OrderCheckPage.tsx @@ -0,0 +1,22 @@ +import { iconStyle, orderCheckLayout, refreshButton } from "./OrderCheckPage.style"; +import { + OrderTrackingSection, + OrderNumberSearchSection, + OrderInfoSection, +} from "../components"; +import { IcRefresh } from "@svg"; + +const OrderCheckPage = () => { + return ( +
+ + + +
+ +
+
+ ); +}; + +export default OrderCheckPage; diff --git a/src/routes/index.ts b/src/routes/index.ts index 874ac1a..8e42b13 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -2,5 +2,12 @@ import homeRoutes from "./homeRoutes"; import orderInfoRoutes from "./orderInfoRoutes"; import experienceOrderInfoRoutes from "./experienceOrderInfoRoutes"; import adminRoutes from "./adminRoutes"; +import orderCheckRoutes from "./orderCheckRoutes"; -export { homeRoutes, orderInfoRoutes, experienceOrderInfoRoutes, adminRoutes}; +export { + homeRoutes, + orderInfoRoutes, + experienceOrderInfoRoutes, + adminRoutes, + orderCheckRoutes, +}; diff --git a/src/routes/orderCheckRoutes.tsx b/src/routes/orderCheckRoutes.tsx new file mode 100644 index 0000000..a06aa70 --- /dev/null +++ b/src/routes/orderCheckRoutes.tsx @@ -0,0 +1,12 @@ +import { routePath } from "@constants"; +import OrderCheckPage from "@pages/orderCheck/page/OrderCheckPage"; +import { RouteType } from "@types"; + +const orderCheckRoutes: RouteType[] = [ + { + path: routePath.ORDER_CHECK, + element: , + }, +]; + +export default orderCheckRoutes; diff --git a/src/styles/global.ts b/src/styles/global.ts index b8a8abe..15561e0 100644 --- a/src/styles/global.ts +++ b/src/styles/global.ts @@ -1,6 +1,6 @@ -import { css } from '@emotion/react'; +import { css } from "@emotion/react"; -import Reset from './reset'; +import Reset from "./reset"; const GlobalStyle = css` ${Reset} @@ -11,6 +11,10 @@ const GlobalStyle = css` :root { --min-width: 375px; --max-width: 430px; + --tablet-min-width: 768px; + --tablet-max-width: 1366px; + --tablet-ratio-width: 1280px; + --tablet-ratio-height: 800px; } html, diff --git a/src/styles/theme.ts b/src/styles/theme.ts index b943515..068da0d 100644 --- a/src/styles/theme.ts +++ b/src/styles/theme.ts @@ -14,6 +14,8 @@ const theme = { red: "#ff2c2c", lightgray1: "#DFE2E7", lightgray2: "#D9D9D9", + lightgray3: "#C4C4C4", + lightgray4: "#B6B6B6", midgray1: "#9FA4AE", midgray2: "#F1F1F1", midgray3: "#6B6F77", @@ -22,6 +24,7 @@ const theme = { background2: "#F5F5F5", orange: "#EC6732", + lightorange: "#FFEDE7", green: "#3CA178", }, font: { @@ -115,6 +118,31 @@ const theme = { font-weight: 400; line-height: 140%; `, + "dialNumber-56": css` + ${PretendardFont} + font-size: 5.6rem; + font-weight: 600; + line-height: normal; + `, + "dialNumber-72": css` + ${PretendardFont} + font-size: 7.2rem; + font-weight: 700; + line-height: normal; + letter-spacing: 10px; + `, + "orderCheck-36": css` + ${PretendardFont} + font-size: 3.6rem; + font-weight: 700; + line-height: normal; + `, + "orderCheck-32": css` + ${PretendardFont} + font-size: 3.2rem; + font-weight: 700; + line-height: normal; + `, }, }; From 9626b86de90fe4eaf08b4336b66606f627177a61 Mon Sep 17 00:00:00 2001 From: thisishwarang <101498590+thisishwarang@users.noreply.github.com> Date: Tue, 1 Oct 2024 02:39:21 +0900 Subject: [PATCH 2/5] =?UTF-8?q?[Feat/#55]=20=EC=A3=BC=EB=AC=B8=EB=B2=88?= =?UTF-8?q?=ED=98=B8=EB=A1=9C=20=EC=A1=B0=ED=9A=8C=20api=20=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20=EC=99=84=EB=A3=8C=20(#56)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 주문 번호로 조회하는 api연결 * feat: 주문 번호 조회 api 연결 및 에러 발생시 alert --- .../useFetchOrderInfoWithOrderNumber.ts | 25 +++++++++++++++++++ src/apis/queryKeys/queryKeys.ts | 1 + .../OrderInfoSection/OrderInfoSection.tsx | 18 +++++++++---- .../OrderNumberSearchSection.tsx | 23 ++++++++++++++--- src/pages/orderCheck/page/OrderCheckPage.tsx | 8 ++++-- src/stores/index.ts | 6 +++++ src/stores/orderInfo.ts | 6 +++++ src/types/index.ts | 1 + src/types/orderInfoWithOrderNumber.ts | 12 +++++++++ 9 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 src/apis/domains/orderCheck/useFetchOrderInfoWithOrderNumber.ts create mode 100644 src/stores/orderInfo.ts create mode 100644 src/types/orderInfoWithOrderNumber.ts diff --git a/src/apis/domains/orderCheck/useFetchOrderInfoWithOrderNumber.ts b/src/apis/domains/orderCheck/useFetchOrderInfoWithOrderNumber.ts new file mode 100644 index 0000000..b3eb09f --- /dev/null +++ b/src/apis/domains/orderCheck/useFetchOrderInfoWithOrderNumber.ts @@ -0,0 +1,25 @@ +import { get } from "@apis/api"; +import { QUERY_KEY } from "@apis/queryKeys/queryKeys"; +import { useQuery } from "@tanstack/react-query"; +import { ApiResponseType, OrderInfoData } from "@types"; + +const getOrderInfo = async ( + orderNumber: number +): Promise => { + try { + const response = await get>( + `api/v1/order/${orderNumber}` + ); + return response.data.data; + } catch { + return null; + } +}; + +export const useFetchOrderInfoWithOrderNumber = (orderNumber: number) => { + return useQuery({ + queryKey: [QUERY_KEY.ORDER_INFO_WITH_ORDER_NUMBER], + queryFn: () => getOrderInfo(orderNumber), + enabled: false, + }); +}; diff --git a/src/apis/queryKeys/queryKeys.ts b/src/apis/queryKeys/queryKeys.ts index 8546ff8..1ce61bc 100644 --- a/src/apis/queryKeys/queryKeys.ts +++ b/src/apis/queryKeys/queryKeys.ts @@ -6,4 +6,5 @@ export const QUERY_KEY = { PRODUCT_LIST: "productList", PRODUCT_LIST_ALL: "productListAll", SAILED_PRODUCT: "sailedProduct", + ORDER_INFO_WITH_ORDER_NUMBER: "orderInfoWithOrderNumber", } as const; diff --git a/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx b/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx index c370b8f..b4219dc 100644 --- a/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx +++ b/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx @@ -1,3 +1,4 @@ +import { orderInfoAtom, previousOrderNumberAtom } from "@stores"; import PayButton from "../PayButton/PayButton"; import { blackSpan, @@ -7,27 +8,34 @@ import { section3Div, section3InfoWrapper, } from "./OrderInfoSection.style"; +import { useAtom } from "jotai"; const OrderInfoSection = () => { + const [previousOrderNumber] = useAtom(previousOrderNumberAtom); + const [orderInfo] = useAtom(orderInfoAtom); return (
주문번호 - {1004} + {previousOrderNumber}
이름 - 유태승 + {orderInfo?.senderName}
상품 - {/* api 붙이고 수정 */} - 귤 5kg (2박스) 1개 + {orderInfo?.orderList.map((order, i) => ( + {`${order.productName} ${order.productCount}개`} + ))}
총 금액 - {"100,000원"} + {orderInfo?.totalPrice}원
diff --git a/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx b/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx index cb451e0..35a6f72 100644 --- a/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx +++ b/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx @@ -1,4 +1,3 @@ -import { useState } from "react"; import DialButton from "../DialButton/DialButton"; import { dialButtonWrapper, @@ -6,9 +5,19 @@ import { orderNumberStyle, section2Container, } from "./OrderNumberSearchSection.style"; +import { useFetchOrderInfoWithOrderNumber } from "@apis/domains/orderCheck/useFetchOrderInfoWithOrderNumber"; +import { useAtom } from "jotai"; +import { + orderInfoAtom, + orderNumberAtom, + previousOrderNumberAtom, +} from "@stores"; const OrderNumberSearchSection = () => { - const [orderNumber, setOrderNumber] = useState(""); + const [orderNumber, setOrderNumber] = useAtom(orderNumberAtom); + const [, setOrderInfo] = useAtom(orderInfoAtom); + const [, setPreviousOrderNumber] = useAtom(previousOrderNumberAtom); + const { refetch } = useFetchOrderInfoWithOrderNumber(Number(orderNumber)); const handleButtonClick = (value: string) => { if (orderNumber.length < 4) { setOrderNumber((prev) => prev + value); @@ -19,8 +28,14 @@ const OrderNumberSearchSection = () => { setOrderNumber((prev) => prev.slice(0, -1)); }; - const handleSearch = () => { - alert(`조회할 번호: ${orderNumber}`); + const handleSearch = async () => { + const result = await refetch(); + if (result.data === null) { + alert("주문번호에 대한 주문내역이 존재하지 않습니다."); + } + setOrderInfo(result?.data ?? null); + setPreviousOrderNumber(orderNumber); + setOrderNumber(""); }; return (
diff --git a/src/pages/orderCheck/page/OrderCheckPage.tsx b/src/pages/orderCheck/page/OrderCheckPage.tsx index c279f8b..f8b9b55 100644 --- a/src/pages/orderCheck/page/OrderCheckPage.tsx +++ b/src/pages/orderCheck/page/OrderCheckPage.tsx @@ -1,4 +1,8 @@ -import { iconStyle, orderCheckLayout, refreshButton } from "./OrderCheckPage.style"; +import { + iconStyle, + orderCheckLayout, + refreshButton, +} from "./OrderCheckPage.style"; import { OrderTrackingSection, OrderNumberSearchSection, @@ -13,7 +17,7 @@ const OrderCheckPage = () => {
- +
); diff --git a/src/stores/index.ts b/src/stores/index.ts index 63be496..b57e9ad 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -3,6 +3,9 @@ import { currentRecipient } from "./currentRecipientIndex"; import { productListAtom } from "./productList"; import { categoryAtom } from "./category"; import { orderNumber } from "./orderNumber"; +import { orderNumberAtom } from "./orderInfo"; +import { previousOrderNumberAtom } from "./orderInfo"; +import { orderInfoAtom } from "./orderInfo"; export { orderPostAtom, @@ -10,4 +13,7 @@ export { productListAtom, categoryAtom, orderNumber, + orderNumberAtom, + previousOrderNumberAtom, + orderInfoAtom, }; diff --git a/src/stores/orderInfo.ts b/src/stores/orderInfo.ts new file mode 100644 index 0000000..091338c --- /dev/null +++ b/src/stores/orderInfo.ts @@ -0,0 +1,6 @@ +import { OrderInfoData } from "@types"; +import { atom } from "jotai"; + +export const orderNumberAtom = atom(""); +export const previousOrderNumberAtom = atom(""); +export const orderInfoAtom = atom(null); diff --git a/src/types/index.ts b/src/types/index.ts index 83ac750..e54a27e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -3,3 +3,4 @@ export * from "./nextStep"; export * from "./commonType"; export * from "./productType"; export * from "./orderType"; +export * from "./orderInfoWithOrderNumber"; diff --git a/src/types/orderInfoWithOrderNumber.ts b/src/types/orderInfoWithOrderNumber.ts new file mode 100644 index 0000000..22caaee --- /dev/null +++ b/src/types/orderInfoWithOrderNumber.ts @@ -0,0 +1,12 @@ +export interface OrderInfo { + productName: string; + productCount: number; + orderState: string; + price: number; +} + +export interface OrderInfoData { + senderName: string; + orderList: OrderInfo[]; + totalPrice: number; +} From 0c411ee172dfd53c4f7a87c2b631521507769189 Mon Sep 17 00:00:00 2001 From: thisishwarang <101498590+thisishwarang@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:26:03 +0900 Subject: [PATCH 3/5] =?UTF-8?q?[Fix/#57]=20=EA=B0=81=EC=A2=85=20qa=20(#58)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/steps/CheckInfo/CheckInfo.tsx | 9 +++++++-- src/hooks/useOrderPostDataChange.ts | 11 +++++++++++ .../OrderTrackingSection.style.ts | 2 +- .../OrderTrackingSection/OrderTrackingSection.tsx | 4 ++-- .../RecentOrderCard/RecentOrderCard.style.ts | 2 +- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/components/common/steps/CheckInfo/CheckInfo.tsx b/src/components/common/steps/CheckInfo/CheckInfo.tsx index 34e76d8..c8b1755 100644 --- a/src/components/common/steps/CheckInfo/CheckInfo.tsx +++ b/src/components/common/steps/CheckInfo/CheckInfo.tsx @@ -28,6 +28,7 @@ const CheckInfo = ({ onNext }: StepProps) => { handleAddReceiver, setOrderNumberState, handleDeleteClick, + resetOrderPostData, } = useOrderPostDataChange(); const { mutateAsync } = usePostOrder(); const receivers = orderPostDataState.recipientInfo; @@ -53,9 +54,13 @@ const CheckInfo = ({ onNext }: StepProps) => { .then((data) => { setOrderNumberState(data); onNext(); + resetOrderPostData(); }) - .catch((error: ErrorType) => { - alert(error.message); + .catch(() => { + alert( + `필수 입력칸을 작성하지 않으셨습니다. \n혹은 이미 주문을 완료하지 않으셨나요?` + ); + navigate(`/${category}`); }); }; diff --git a/src/hooks/useOrderPostDataChange.ts b/src/hooks/useOrderPostDataChange.ts index a853cd5..1d69e4a 100644 --- a/src/hooks/useOrderPostDataChange.ts +++ b/src/hooks/useOrderPostDataChange.ts @@ -108,6 +108,16 @@ export const useOrderPostDataChange = () => { } }; + const resetOrderPostData = () => { + setOrderPostDataState({ + senderName: "", + senderPhone: "", + isPersonalInfoConsent: false, + isMarketingConsent: false, + recipientInfo: [], + }); + }; + return { orderPostDataState, currentRecipientIndex, @@ -119,5 +129,6 @@ export const useOrderPostDataChange = () => { orderNumberState, setOrderNumberState, handleDeleteClick, + resetOrderPostData, }; }; diff --git a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts index f845cf0..5895580 100644 --- a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts +++ b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts @@ -4,7 +4,7 @@ import { flexGenerator } from "@styles/generator"; export const section1Container = (theme: Theme) => css` ${flexGenerator("column", "start", "start")}; padding: 2rem; - width: 26.8rem; + width: 27rem; height: 100%; gap: 1.5rem; border: 1px solid ${theme.color.lightgray3}; diff --git a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx index d7e390a..a0e6dab 100644 --- a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx +++ b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx @@ -1,8 +1,8 @@ import RecentOrderCard from "../RecentOrderCard/RecentOrderCard"; import { section1Container } from "./OrderTrackingSection.style"; const recentOrderList = [ - { orderNumber: 1074, senderName: "유태승" }, - { orderNumber: 1074, senderName: "유태승" }, + { orderNumber: 1029, senderName: "박채연" }, + { orderNumber: 4569, senderName: "유태승" }, { orderNumber: 1074, senderName: "유태승" }, { orderNumber: 1074, senderName: "유태승" }, { orderNumber: 1074, senderName: "유태승" }, diff --git a/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.style.ts b/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.style.ts index c75b2c1..7824572 100644 --- a/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.style.ts +++ b/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.style.ts @@ -5,7 +5,7 @@ export const cardWrapper = (theme: Theme) => css` ${flexGenerator()}; gap: 1rem; width: 100%; - padding: 1.5rem; + padding: 1.5rem 1.2rem; border-radius: 10px; background-color: ${theme.color.lightorange}; `; From c71166f091a963b3b4d6dfb7822bbde95869c550 Mon Sep 17 00:00:00 2001 From: thisishwarang <101498590+thisishwarang@users.noreply.github.com> Date: Sun, 6 Oct 2024 16:21:41 +0900 Subject: [PATCH 4/5] =?UTF-8?q?[Feat/#59]=20=EA=B2=B0=EC=A0=9C=EC=99=84?= =?UTF-8?q?=EB=A3=8C,=20=EA=B2=B0=EC=A0=9C=EC=B7=A8=EC=86=8C,=20=EC=B5=9C?= =?UTF-8?q?=EA=B7=BC=20=EC=A3=BC=EB=AC=B8=2010=EA=B0=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20api=20=EC=97=B0=EA=B2=B0=20(#60)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 결제완료, 결제취소 api 연결 * feat: 최근 주문 10개 가져오는 api 연결 --- .../orderCheck/useFetchRecentOrderNumber.ts | 22 ++++++++++++++++++ .../domains/orderCheck/usePatchPayCancel.ts | 22 ++++++++++++++++++ .../domains/orderCheck/usePatchPayComplete.ts | 23 +++++++++++++++++++ src/apis/queryKeys/queryKeys.ts | 1 + .../common/steps/CheckInfo/CheckInfo.tsx | 2 +- .../OrderInfoSection/OrderInfoSection.tsx | 16 +++++++++++-- .../OrderTrackingSection.style.ts | 1 + .../OrderTrackingSection.tsx | 12 +++------- .../RecentOrderCard/RecentOrderCard.style.ts | 2 +- src/types/index.ts | 1 + src/types/recentOrderType.ts | 4 ++++ 11 files changed, 93 insertions(+), 13 deletions(-) create mode 100644 src/apis/domains/orderCheck/useFetchRecentOrderNumber.ts create mode 100644 src/apis/domains/orderCheck/usePatchPayCancel.ts create mode 100644 src/apis/domains/orderCheck/usePatchPayComplete.ts create mode 100644 src/types/recentOrderType.ts diff --git a/src/apis/domains/orderCheck/useFetchRecentOrderNumber.ts b/src/apis/domains/orderCheck/useFetchRecentOrderNumber.ts new file mode 100644 index 0000000..12aa1d8 --- /dev/null +++ b/src/apis/domains/orderCheck/useFetchRecentOrderNumber.ts @@ -0,0 +1,22 @@ +import { get } from "@apis/api"; +import { QUERY_KEY } from "@apis/queryKeys/queryKeys"; +import { useQuery } from "@tanstack/react-query"; +import { ApiResponseType, RecentOrderType } from "@types"; + +const getRecentOrderNumber = async (): Promise => { + try { + const response = await get>( + "api/v1/order/recent" + ); + return response.data.data; + } catch { + return null; + } +}; + +export const useFetchRecentOrderNumber = () => { + return useQuery({ + queryKey: [QUERY_KEY.RECENT_ORDER_NUMBER], + queryFn: () => getRecentOrderNumber(), + }); +}; diff --git a/src/apis/domains/orderCheck/usePatchPayCancel.ts b/src/apis/domains/orderCheck/usePatchPayCancel.ts new file mode 100644 index 0000000..f04e9e6 --- /dev/null +++ b/src/apis/domains/orderCheck/usePatchPayCancel.ts @@ -0,0 +1,22 @@ +import { patch } from "@apis/api"; +import { useMutation } from "@tanstack/react-query"; +import { MutateResponseType } from "@types"; + +const patchPayCancel = async ( + orderNumber: number +): Promise => { + try { + const response = await patch( + `api/v1/order/cancel/${orderNumber}` + ); + return response.data; + } catch { + return null; + } +}; + +export const usePatchPayCancel = () => { + return useMutation({ + mutationFn: (orderNumber: number) => patchPayCancel(orderNumber), + }); +}; diff --git a/src/apis/domains/orderCheck/usePatchPayComplete.ts b/src/apis/domains/orderCheck/usePatchPayComplete.ts new file mode 100644 index 0000000..518dfd8 --- /dev/null +++ b/src/apis/domains/orderCheck/usePatchPayComplete.ts @@ -0,0 +1,23 @@ +import { patch } from "@apis/api"; +import { useMutation } from "@tanstack/react-query"; +import { MutateResponseType } from "@types"; + +const patchPayComplete = async ( + orderNumber: number +): Promise => { + try { + const response = await patch( + `api/v1/order/pay/${orderNumber}` + ); + return response.data; + } catch { + return null; + } +}; + +export const usePatchPayComplete = () => { + return useMutation({ + mutationFn: (orderNumber: number) => patchPayComplete(orderNumber), + onSuccess: () => {}, + }); +}; diff --git a/src/apis/queryKeys/queryKeys.ts b/src/apis/queryKeys/queryKeys.ts index 1ce61bc..87fb3a2 100644 --- a/src/apis/queryKeys/queryKeys.ts +++ b/src/apis/queryKeys/queryKeys.ts @@ -7,4 +7,5 @@ export const QUERY_KEY = { PRODUCT_LIST_ALL: "productListAll", SAILED_PRODUCT: "sailedProduct", ORDER_INFO_WITH_ORDER_NUMBER: "orderInfoWithOrderNumber", + RECENT_ORDER_NUMBER: "recentOrderNumber", } as const; diff --git a/src/components/common/steps/CheckInfo/CheckInfo.tsx b/src/components/common/steps/CheckInfo/CheckInfo.tsx index c8b1755..266b63f 100644 --- a/src/components/common/steps/CheckInfo/CheckInfo.tsx +++ b/src/components/common/steps/CheckInfo/CheckInfo.tsx @@ -1,5 +1,5 @@ import { Button, Header, ProgressBar } from "@components"; -import { ErrorType, StepProps } from "@types"; +import { StepProps } from "@types"; import { buttonSectionStyle, layoutStyle } from "@pages/orderInfo/styles"; import { checkSpanText, diff --git a/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx b/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx index b4219dc..e2d5f40 100644 --- a/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx +++ b/src/pages/orderCheck/components/OrderInfoSection/OrderInfoSection.tsx @@ -9,10 +9,22 @@ import { section3InfoWrapper, } from "./OrderInfoSection.style"; import { useAtom } from "jotai"; +import { usePatchPayComplete } from "@apis/domains/orderCheck/usePatchPayComplete"; +import { usePatchPayCancel } from "@apis/domains/orderCheck/usePatchPayCancel"; const OrderInfoSection = () => { const [previousOrderNumber] = useAtom(previousOrderNumberAtom); const [orderInfo] = useAtom(orderInfoAtom); + + const { mutate: mutatePayComplete } = usePatchPayComplete(); + const { mutate: mutatePayCancel } = usePatchPayCancel(); + + const handlePayCancel = () => { + mutatePayCancel(Number(previousOrderNumber)); + }; + const handlePayComplete = () => { + mutatePayComplete(Number(previousOrderNumber)); + }; return (
@@ -39,10 +51,10 @@ const OrderInfoSection = () => {
- {}}> + 결제취소 - {}}> + 결제완료
diff --git a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts index 5895580..306187d 100644 --- a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts +++ b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts @@ -10,4 +10,5 @@ export const section1Container = (theme: Theme) => css` border: 1px solid ${theme.color.lightgray3}; background-color: ${theme.color.white}; border-radius: 10px; + overflow: scroll; `; diff --git a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx index a0e6dab..3127ab0 100644 --- a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx +++ b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx @@ -1,17 +1,11 @@ +import { useFetchRecentOrderNumber } from "@apis/domains/orderCheck/useFetchRecentOrderNumber"; import RecentOrderCard from "../RecentOrderCard/RecentOrderCard"; import { section1Container } from "./OrderTrackingSection.style"; -const recentOrderList = [ - { orderNumber: 1029, senderName: "박채연" }, - { orderNumber: 4569, senderName: "유태승" }, - { orderNumber: 1074, senderName: "유태승" }, - { orderNumber: 1074, senderName: "유태승" }, - { orderNumber: 1074, senderName: "유태승" }, - { orderNumber: 1074, senderName: "유태승" }, -]; const OrderTrackingSection = () => { + const { data: recentOrderList } = useFetchRecentOrderNumber(); return (
- {recentOrderList.map((order, i) => ( + {recentOrderList?.map((order, i) => ( css` - ${flexGenerator()}; + ${flexGenerator("row", "space-between", "center")}; gap: 1rem; width: 100%; padding: 1.5rem 1.2rem; diff --git a/src/types/index.ts b/src/types/index.ts index e54a27e..27989bd 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -4,3 +4,4 @@ export * from "./commonType"; export * from "./productType"; export * from "./orderType"; export * from "./orderInfoWithOrderNumber"; +export * from "./recentOrderType"; diff --git a/src/types/recentOrderType.ts b/src/types/recentOrderType.ts new file mode 100644 index 0000000..8acfda9 --- /dev/null +++ b/src/types/recentOrderType.ts @@ -0,0 +1,4 @@ +export interface RecentOrderType { + orderNumber: number; + senderName: string; +} From 9c5762e18f23e1503ece0e89bb9ae1203d0fa39a Mon Sep 17 00:00:00 2001 From: thisishwarang <101498590+thisishwarang@users.noreply.github.com> Date: Sun, 6 Oct 2024 19:09:45 +0900 Subject: [PATCH 5/5] =?UTF-8?q?[Fix/#53]=20=EA=B0=81=EC=A2=85=20QA=20(#61)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 테이블 너비 수정 * feat: 관리자 로그인 추가 * feat: 태블릿 뷰 새로고침, 최근 번호 바로검색 구현 중 * fix: 최근 주문 10개 섹션과 주문 조회 섹션 합친 후 수정 --------- Co-authored-by: Yoo TaeSeung --- src/App.tsx | 12 ++- src/apis/api.ts | 7 ++ src/apis/domains/admin/usePostAdminLogin.ts | 38 +++++++++ src/constants/routePath.ts | 5 ++ .../components/OrderTable/OrderTable.style.ts | 10 +-- .../components/OrderTable/OrderTable.tsx | 6 +- .../Admin/page/AdminLogin/AdminLogin.style.ts | 27 ++++++ .../Admin/page/AdminLogin/AdminLogin.tsx | 63 ++++++++++++++ src/pages/Admin/page/AdminPage/AdminPage.tsx | 2 +- src/pages/Admin/page/AdminPage/index.ts | 5 -- src/pages/Admin/page/index.ts | 6 ++ .../OrderNumberSearchSection.style.ts | 12 +++ .../OrderNumberSearchSection.tsx | 83 ++++++++++++++----- .../OrderTrackingSection.style.ts | 14 ---- .../OrderTrackingSection.tsx | 19 ----- .../RecentOrderCard/RecentOrderCard.tsx | 9 +- src/pages/orderCheck/components/index.ts | 2 - .../orderCheck/page/OrderCheckPage.style.ts | 1 + src/pages/orderCheck/page/OrderCheckPage.tsx | 15 +++- src/routes/PrivateRoute/PrivateRoute.tsx | 14 ++++ src/routes/adminRoutes.tsx | 5 ++ src/routes/authRoutes.tsx | 12 +++ src/routes/index.ts | 2 + src/types/commonType.ts | 4 + src/utils/auth.ts | 7 ++ src/utils/index.ts | 7 +- 26 files changed, 303 insertions(+), 84 deletions(-) create mode 100644 src/apis/domains/admin/usePostAdminLogin.ts create mode 100644 src/pages/Admin/page/AdminLogin/AdminLogin.style.ts create mode 100644 src/pages/Admin/page/AdminLogin/AdminLogin.tsx delete mode 100644 src/pages/Admin/page/AdminPage/index.ts create mode 100644 src/pages/Admin/page/index.ts delete mode 100644 src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts delete mode 100644 src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx create mode 100644 src/routes/PrivateRoute/PrivateRoute.tsx create mode 100644 src/routes/authRoutes.tsx create mode 100644 src/utils/auth.ts diff --git a/src/App.tsx b/src/App.tsx index d3964d2..83b7cbb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,21 +4,29 @@ import { homeRoutes, orderInfoRoutes, adminRoutes, + authRoutes, orderCheckRoutes, } from "@routes"; import GlobalStyle from "@styles/global"; import theme from "@styles/theme"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { createBrowserRouter, RouterProvider } from "react-router-dom"; +import PrivateRoute from "./routes/PrivateRoute/PrivateRoute"; const allRoutes = [ ...homeRoutes, ...orderInfoRoutes, ...experienceOrderInfoRoutes, - ...adminRoutes, + ...authRoutes, ...orderCheckRoutes, ]; -const router = createBrowserRouter([...allRoutes]); + +const protectedRoutes = adminRoutes.map((route) => ({ + ...route, + element: , +})); + +const router = createBrowserRouter([...allRoutes, ...protectedRoutes]); function App() { const queryClient = new QueryClient(); diff --git a/src/apis/api.ts b/src/apis/api.ts index ff30650..97c3b39 100644 --- a/src/apis/api.ts +++ b/src/apis/api.ts @@ -4,6 +4,13 @@ export const instance = axios.create({ baseURL: import.meta.env.VITE_APP_BASE_URL, }); +export const adminInstance = axios.create({ + baseURL: import.meta.env.VITE_APP_BASE_URL, + headers: { + Authorization: `Bearer ${localStorage.getItem("accessToken")}`, + }, +}); + export function get(...args: Parameters) { return instance.get(...args); } diff --git a/src/apis/domains/admin/usePostAdminLogin.ts b/src/apis/domains/admin/usePostAdminLogin.ts new file mode 100644 index 0000000..fe55a72 --- /dev/null +++ b/src/apis/domains/admin/usePostAdminLogin.ts @@ -0,0 +1,38 @@ +import { post } from "@apis/api"; +import { useMutation } from "@tanstack/react-query"; +import { ErrorResponse, CodeResponseType } from "@types"; +import { useNavigate } from "react-router-dom"; + +interface LoginDataType { + username: string; + password: string; +} + +const postAdminLogin = async ( + loginData: LoginDataType +): Promise => { + try { + const response = await post( + `/api/v1/admin/authenticate`, + loginData + ); + return response.data; + } catch (error) { + const errorResponse = error as ErrorResponse; + const errorData = errorResponse.response.data; + throw errorData; + } +}; + +export const usePostAdminLogin = () => { + const navigate = useNavigate(); + return useMutation({ + mutationFn: (loginData: LoginDataType) => postAdminLogin(loginData), + onSuccess: (data) => { + if (data.code === "success") { + localStorage.setItem("accessToken", data.code); + navigate("/admin"); + } + }, + }); +}; diff --git a/src/constants/routePath.ts b/src/constants/routePath.ts index 4d5f13e..4a2014d 100644 --- a/src/constants/routePath.ts +++ b/src/constants/routePath.ts @@ -22,6 +22,10 @@ const adminPages = { ADMIN_TAB: "/admin/:tab", }; +const authPages = { + ADMIN_LOGIN: "/admin/login", +}; + const orderCheckPages = { ORDER_CHECK: "/order-check", }; @@ -32,5 +36,6 @@ export default { ...orderInfoPages, ...experienceProductOrderInfoPages, ...adminPages, + ...authPages, ...orderCheckPages, }; diff --git a/src/pages/Admin/components/OrderTable/OrderTable.style.ts b/src/pages/Admin/components/OrderTable/OrderTable.style.ts index 9f6dd26..964915c 100644 --- a/src/pages/Admin/components/OrderTable/OrderTable.style.ts +++ b/src/pages/Admin/components/OrderTable/OrderTable.style.ts @@ -64,14 +64,10 @@ export const tableStyle = (theme: Theme) => css` } /* 상품명 */ - /* th:nth-of-type(4), + th:nth-of-type(4), td:nth-of-type(4) { - } */ - - /* 주소 */ - /* th:nth-of-type(9), - td:nth-of-type(9) { - } */ + min-width: 20rem; + } `; export const checkboxStyle = css` diff --git a/src/pages/Admin/components/OrderTable/OrderTable.tsx b/src/pages/Admin/components/OrderTable/OrderTable.tsx index ff346fb..ddcaa19 100644 --- a/src/pages/Admin/components/OrderTable/OrderTable.tsx +++ b/src/pages/Admin/components/OrderTable/OrderTable.tsx @@ -159,7 +159,11 @@ const OrderTable = ({ orders }: OrderTableProps) => { {order.orderReceivedDate} {order.orderNumber} - {...order.productList} + + {order.productList.map((product) => { + return
{product}
; + })} + {order.senderName} {order.senderPhone} {order.recipientName} diff --git a/src/pages/Admin/page/AdminLogin/AdminLogin.style.ts b/src/pages/Admin/page/AdminLogin/AdminLogin.style.ts new file mode 100644 index 0000000..6ee29b4 --- /dev/null +++ b/src/pages/Admin/page/AdminLogin/AdminLogin.style.ts @@ -0,0 +1,27 @@ +import { Theme } from "@emotion/react"; +import { css } from "@emotion/react"; +import { flexGenerator } from "@styles/generator"; + +export const loginLayout = css` + width: 100%; + height: 100dvh; + ${flexGenerator()}; + padding: 0 3rem; +`; + +export const formStyle = css` + width: 100%; + ${flexGenerator("column", "flex-start", "flex-start")} +`; + +export const inputWrapper = css` + width: 100%; + ${flexGenerator("column", "flex-start", "flex-start")} + gap: 0.8rem; + + margin-bottom: 2rem; +`; + +export const labelStyle = (theme: Theme) => css` + ${theme.font["head06-b-16"]}; +`; diff --git a/src/pages/Admin/page/AdminLogin/AdminLogin.tsx b/src/pages/Admin/page/AdminLogin/AdminLogin.tsx new file mode 100644 index 0000000..19486c0 --- /dev/null +++ b/src/pages/Admin/page/AdminLogin/AdminLogin.tsx @@ -0,0 +1,63 @@ +import { Button, Input } from "@components"; +import { useState } from "react"; +import { + formStyle, + inputWrapper, + labelStyle, + loginLayout, +} from "./AdminLogin.style"; +import { usePostAdminLogin } from "@apis/domains/admin/usePostAdminLogin"; + +const AdminLogin = () => { + const [adminUsername, setAdminUsername] = useState(""); + const [adminPw, setAdminPw] = useState(""); + + const { mutate } = usePostAdminLogin(); + + const handleUsernameChange = (e: React.ChangeEvent) => { + setAdminUsername(e.target.value); + }; + + const handlePwChange = (e: React.ChangeEvent) => { + setAdminPw(e.target.value); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + mutate({ username: adminUsername, password: adminPw }); + }; + + return ( +
+
+
+ + +
+
+ + +
+ +
+
+ ); +}; + +export default AdminLogin; diff --git a/src/pages/Admin/page/AdminPage/AdminPage.tsx b/src/pages/Admin/page/AdminPage/AdminPage.tsx index e775e6c..0408bdf 100644 --- a/src/pages/Admin/page/AdminPage/AdminPage.tsx +++ b/src/pages/Admin/page/AdminPage/AdminPage.tsx @@ -7,7 +7,7 @@ import { tapLayoutStyle, } from "./AdminPage.style"; import { useNavigate, useParams } from "react-router-dom"; -import { OrderCheck, ProductCheck, DeliveryCheck } from "./"; +import { OrderCheck, ProductCheck, DeliveryCheck } from ".."; const Admin = () => { const { tab = "order" } = useParams<{ tab: string }>(); diff --git a/src/pages/Admin/page/AdminPage/index.ts b/src/pages/Admin/page/AdminPage/index.ts deleted file mode 100644 index 5860163..0000000 --- a/src/pages/Admin/page/AdminPage/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import OrderCheck from "./OrderCheck/OrderCheck"; -import ProductCheck from "./ProductCheck/ProductCheck"; -import DeliveryCheck from "./DeliveryCheck/DeliveryCheck"; - -export { OrderCheck, ProductCheck, DeliveryCheck }; diff --git a/src/pages/Admin/page/index.ts b/src/pages/Admin/page/index.ts new file mode 100644 index 0000000..8712911 --- /dev/null +++ b/src/pages/Admin/page/index.ts @@ -0,0 +1,6 @@ +import OrderCheck from "./AdminPage/OrderCheck/OrderCheck"; +import ProductCheck from "./AdminPage/ProductCheck/ProductCheck"; +import DeliveryCheck from "./AdminPage/DeliveryCheck/DeliveryCheck"; +import AdminLogin from "./AdminLogin/AdminLogin"; + +export { OrderCheck, ProductCheck, DeliveryCheck, AdminLogin }; diff --git a/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.style.ts b/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.style.ts index 3157ef1..410c060 100644 --- a/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.style.ts +++ b/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.style.ts @@ -1,6 +1,18 @@ import { css, Theme } from "@emotion/react"; import { flexGenerator } from "@styles/generator"; +export const section1Container = (theme: Theme) => css` + ${flexGenerator("column", "start", "start")}; + padding: 2rem; + width: 27rem; + height: 100%; + gap: 1.5rem; + border: 1px solid ${theme.color.lightgray3}; + background-color: ${theme.color.white}; + border-radius: 10px; + overflow: scroll; +`; + export const section2Container = css` ${flexGenerator("column")}; width: 45rem; diff --git a/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx b/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx index 35a6f72..dbbe213 100644 --- a/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx +++ b/src/pages/orderCheck/components/OrderNumberSearchSection/OrderNumberSearchSection.tsx @@ -3,6 +3,7 @@ import { dialButtonWrapper, orderNumberSpan, orderNumberStyle, + section1Container, section2Container, } from "./OrderNumberSearchSection.style"; import { useFetchOrderInfoWithOrderNumber } from "@apis/domains/orderCheck/useFetchOrderInfoWithOrderNumber"; @@ -12,12 +13,30 @@ import { orderNumberAtom, previousOrderNumberAtom, } from "@stores"; +import { RecentOrderType } from "@types"; +import RecentOrderCard from "../RecentOrderCard/RecentOrderCard"; +import { useEffect, useState } from "react"; -const OrderNumberSearchSection = () => { +interface OrderTrackingSectionProps { + recentOrderList: RecentOrderType[] | null | undefined; +} + +const OrderNumberSearchSection = ({ + recentOrderList, +}: OrderTrackingSectionProps) => { const [orderNumber, setOrderNumber] = useAtom(orderNumberAtom); const [, setOrderInfo] = useAtom(orderInfoAtom); const [, setPreviousOrderNumber] = useAtom(previousOrderNumberAtom); + const [triggerSearch, setTriggerSearch] = useState(false); const { refetch } = useFetchOrderInfoWithOrderNumber(Number(orderNumber)); + + useEffect(() => { + if (triggerSearch) { + handleSearch(); + setTriggerSearch(false); + } + }, [orderNumber, triggerSearch]); + const handleButtonClick = (value: string) => { if (orderNumber.length < 4) { setOrderNumber((prev) => prev + value); @@ -37,29 +56,47 @@ const OrderNumberSearchSection = () => { setPreviousOrderNumber(orderNumber); setOrderNumber(""); }; + + const handleRecentOrderClick = (orderNumber: string) => { + setOrderNumber(orderNumber); + setTriggerSearch(true); + }; + return ( -
-
- {orderNumber} -
-
- {["1", "2", "3", "4", "5", "6", "7", "8", "9", "<-", "0", "조회"].map( - (item, i) => ( - { - if (item === "<-") handleDelete(); - else if (item === "조회") handleSearch(); - else handleButtonClick(item); - }} - index={i} - > - {item} - - ) - )} -
-
+ <> +
+ {recentOrderList?.map((order, i) => ( + handleRecentOrderClick(order.orderNumber.toString())} + /> + ))} +
+
+
+ {orderNumber} +
+
+ {["1", "2", "3", "4", "5", "6", "7", "8", "9", "<-", "0", "조회"].map( + (item, i) => ( + { + if (item === "<-") handleDelete(); + else if (item === "조회") handleSearch(); + else handleButtonClick(item); + }} + index={i} + > + {item} + + ) + )} +
+
+ ); }; diff --git a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts deleted file mode 100644 index 306187d..0000000 --- a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.style.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { css, Theme } from "@emotion/react"; -import { flexGenerator } from "@styles/generator"; - -export const section1Container = (theme: Theme) => css` - ${flexGenerator("column", "start", "start")}; - padding: 2rem; - width: 27rem; - height: 100%; - gap: 1.5rem; - border: 1px solid ${theme.color.lightgray3}; - background-color: ${theme.color.white}; - border-radius: 10px; - overflow: scroll; -`; diff --git a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx b/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx deleted file mode 100644 index 3127ab0..0000000 --- a/src/pages/orderCheck/components/OrderTrackingSection/OrderTrackingSection.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { useFetchRecentOrderNumber } from "@apis/domains/orderCheck/useFetchRecentOrderNumber"; -import RecentOrderCard from "../RecentOrderCard/RecentOrderCard"; -import { section1Container } from "./OrderTrackingSection.style"; -const OrderTrackingSection = () => { - const { data: recentOrderList } = useFetchRecentOrderNumber(); - return ( -
- {recentOrderList?.map((order, i) => ( - - ))} -
- ); -}; - -export default OrderTrackingSection; diff --git a/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.tsx b/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.tsx index de722c8..82820bd 100644 --- a/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.tsx +++ b/src/pages/orderCheck/components/RecentOrderCard/RecentOrderCard.tsx @@ -3,11 +3,16 @@ import { cardWrapper, nameStyle, numberStyle } from "./RecentOrderCard.style"; interface RecentOrderCardProps { orderNumber: number; senderName: string; + onClick: () => void; } -const RecentOrderCard = ({ orderNumber, senderName }: RecentOrderCardProps) => { +const RecentOrderCard = ({ + orderNumber, + senderName, + onClick, +}: RecentOrderCardProps) => { return ( -
+
{orderNumber}번 {senderName}
diff --git a/src/pages/orderCheck/components/index.ts b/src/pages/orderCheck/components/index.ts index b3956ba..42ca083 100644 --- a/src/pages/orderCheck/components/index.ts +++ b/src/pages/orderCheck/components/index.ts @@ -1,6 +1,5 @@ import DialButton from "./DialButton/DialButton"; import PayButton from "./PayButton/PayButton"; -import OrderTrackingSection from "./OrderTrackingSection/OrderTrackingSection"; import RecentOrderCard from "./RecentOrderCard/RecentOrderCard"; import OrderNumberSearchSection from "./OrderNumberSearchSection/OrderNumberSearchSection"; import OrderInfoSection from "./OrderInfoSection/OrderInfoSection"; @@ -8,7 +7,6 @@ import OrderInfoSection from "./OrderInfoSection/OrderInfoSection"; export { DialButton, PayButton, - OrderTrackingSection, RecentOrderCard, OrderNumberSearchSection, OrderInfoSection, diff --git a/src/pages/orderCheck/page/OrderCheckPage.style.ts b/src/pages/orderCheck/page/OrderCheckPage.style.ts index 4763ffc..558d71d 100644 --- a/src/pages/orderCheck/page/OrderCheckPage.style.ts +++ b/src/pages/orderCheck/page/OrderCheckPage.style.ts @@ -22,6 +22,7 @@ export const refreshButton = (theme: Theme) => css` height: 8rem; border-radius: 40px; background-color: ${theme.color.lightorange}; + cursor: pointer; `; export const iconStyle = css` diff --git a/src/pages/orderCheck/page/OrderCheckPage.tsx b/src/pages/orderCheck/page/OrderCheckPage.tsx index f8b9b55..2bd5d72 100644 --- a/src/pages/orderCheck/page/OrderCheckPage.tsx +++ b/src/pages/orderCheck/page/OrderCheckPage.tsx @@ -4,19 +4,26 @@ import { refreshButton, } from "./OrderCheckPage.style"; import { - OrderTrackingSection, + // OrderTrackingSection, OrderNumberSearchSection, OrderInfoSection, } from "../components"; import { IcRefresh } from "@svg"; +import { useFetchRecentOrderNumber } from "@apis/domains/orderCheck/useFetchRecentOrderNumber"; const OrderCheckPage = () => { + const { data: recentOrderList, refetch } = useFetchRecentOrderNumber(); + + const handleRefresh = () => { + refetch(); + }; + return (
- - + {/* */} + -
+
diff --git a/src/routes/PrivateRoute/PrivateRoute.tsx b/src/routes/PrivateRoute/PrivateRoute.tsx new file mode 100644 index 0000000..86b5038 --- /dev/null +++ b/src/routes/PrivateRoute/PrivateRoute.tsx @@ -0,0 +1,14 @@ +import { ReactNode } from "react"; +import { Navigate } from "react-router-dom"; + +import { isLoggedIn } from "@utils"; + +interface PrivateRouteProps { + element: ReactNode; +} + +const PrivateRoute = ({ element }: PrivateRouteProps) => { + return isLoggedIn() ? element : ; +}; + +export default PrivateRoute; diff --git a/src/routes/adminRoutes.tsx b/src/routes/adminRoutes.tsx index 8e6db02..87e9719 100644 --- a/src/routes/adminRoutes.tsx +++ b/src/routes/adminRoutes.tsx @@ -1,4 +1,5 @@ import { routePath } from "@constants"; +import { AdminLogin } from "@pages/Admin/page"; import { Admin } from "@pages/index"; import { RouteType } from "@types"; import { Navigate } from "react-router-dom"; @@ -8,6 +9,10 @@ const adminRoutes: RouteType[] = [ path: routePath.ADMIN, element: , }, + { + path: routePath.ADMIN_LOGIN, + element: , + }, { path: routePath.ADMIN_TAB, element: , diff --git a/src/routes/authRoutes.tsx b/src/routes/authRoutes.tsx new file mode 100644 index 0000000..92e9bee --- /dev/null +++ b/src/routes/authRoutes.tsx @@ -0,0 +1,12 @@ +import { routePath } from "@constants"; +import { AdminLogin } from "@pages/Admin/page"; +import { RouteType } from "@types"; + +const authRoutes: RouteType[] = [ + { + path: routePath.ADMIN_LOGIN, + element: , + }, +]; + +export default authRoutes; diff --git a/src/routes/index.ts b/src/routes/index.ts index 8e42b13..e0120ea 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -2,6 +2,7 @@ import homeRoutes from "./homeRoutes"; import orderInfoRoutes from "./orderInfoRoutes"; import experienceOrderInfoRoutes from "./experienceOrderInfoRoutes"; import adminRoutes from "./adminRoutes"; +import authRoutes from "./authRoutes"; import orderCheckRoutes from "./orderCheckRoutes"; export { @@ -9,5 +10,6 @@ export { orderInfoRoutes, experienceOrderInfoRoutes, adminRoutes, + authRoutes, orderCheckRoutes, }; diff --git a/src/types/commonType.ts b/src/types/commonType.ts index 961975c..58250f3 100644 --- a/src/types/commonType.ts +++ b/src/types/commonType.ts @@ -32,3 +32,7 @@ export interface OrderNumberType { code: string; data: number; } + +export interface CodeResponseType { + code: string; +} diff --git a/src/utils/auth.ts b/src/utils/auth.ts new file mode 100644 index 0000000..84c959b --- /dev/null +++ b/src/utils/auth.ts @@ -0,0 +1,7 @@ +export const getToken = () => { + return localStorage.getItem("accessToken"); +}; + +export const isLoggedIn = () => { + return getToken() ? true : false; +}; diff --git a/src/utils/index.ts b/src/utils/index.ts index 8642f44..5fdf69c 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,4 +1,3 @@ -import { formatPhoneNumber } from "./phoneNumber"; -import { getTwoDaysLaterDate } from "./getDate"; - -export { formatPhoneNumber, getTwoDaysLaterDate }; +export * from "./phoneNumber"; +export * from "./getDate"; +export * from "./auth";