diff --git a/public/svg/ic_arrow_back.svg b/public/svg/ic_arrow_back.svg new file mode 100644 index 0000000..bc09698 --- /dev/null +++ b/public/svg/ic_arrow_back.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/svg/ic_home.svg b/public/svg/ic_home.svg new file mode 100644 index 0000000..086280f --- /dev/null +++ b/public/svg/ic_home.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/svg/IcArrowBack.tsx b/src/assets/svg/IcArrowBack.tsx new file mode 100644 index 0000000..c7300bb --- /dev/null +++ b/src/assets/svg/IcArrowBack.tsx @@ -0,0 +1,31 @@ +import * as React from "react"; +import type { SVGProps } from "react"; +const SvgIcArrowBack = (props: SVGProps) => ( + + + + + + + + +); +export default SvgIcArrowBack; diff --git a/src/assets/svg/IcHome.tsx b/src/assets/svg/IcHome.tsx new file mode 100644 index 0000000..f3caaa2 --- /dev/null +++ b/src/assets/svg/IcHome.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +import type { SVGProps } from "react"; +const SvgIcHome = (props: SVGProps) => ( + + + +); +export default SvgIcHome; diff --git a/src/assets/svg/index.ts b/src/assets/svg/index.ts index 32d5911..b0fdb5a 100644 --- a/src/assets/svg/index.ts +++ b/src/assets/svg/index.ts @@ -1,3 +1,4 @@ +export { default as IcArrowBack } from "./IcArrowBack"; export { default as IcArrowDown } from "./IcArrowDown"; export { default as IcArrowUp } from "./IcArrowUp"; export { default as IcBack } from "./IcBack"; @@ -10,6 +11,7 @@ export { default as IcCopy } from "./IcCopy"; export { default as IcDelete } from "./IcDelete"; export { default as IcDownload } from "./IcDownload"; export { default as IcFix } from "./IcFix"; +export { default as IcHome } from "./IcHome"; export { default as IcLogout } from "./IcLogout"; export { default as IcMainCharacter } from "./IcMainCharacter"; export { default as IcMinus } from "./IcMinus"; diff --git a/src/components/common/Button/Button.style.ts b/src/components/common/Button/Button.style.ts index b46e3d9..f0b3a6f 100644 --- a/src/components/common/Button/Button.style.ts +++ b/src/components/common/Button/Button.style.ts @@ -1,5 +1,6 @@ import { css, Theme } from "@emotion/react"; import { flexGenerator } from "@styles/generator"; +import { CategoryType } from "@types"; export const buttonStyle = css` ${flexGenerator()} @@ -10,69 +11,93 @@ export const buttonStyle = css` `; export const buttonVariant = { - fill: (theme: Theme) => css` - width: 100%; - height: 4.8rem; - - border-radius: 5px; - - ${theme.font["pretendard-01"]} - color: ${theme.color.white}; - background-color: ${theme.color.orange}; - `, - stroke: (theme: Theme) => css` - width: 100%; - height: 4.8rem; - - border: 1px solid ${theme.color.orange}; - border-radius: 5px; - - ${theme.font["pretendard-01"]} - color: ${theme.color.orange}; - background-color: ${theme.color.white}; - `, - smallStroke: (theme: Theme) => css` - width: 100%; - height: 3rem; - - border: 1px solid ${theme.color.orange}; - border-radius: 4px; - - ${theme.font["subhead-m-14"]} - color: ${theme.color.orange}; - background-color: transparent; - `, - smallFill: (theme: Theme) => css` - width: 100%; - height: 3rem; - - border: 1px solid ${theme.color.orange}; - border-radius: 4px; - - ${theme.font["pretendard-01"]} - color: ${theme.color.white}; - background-color: ${theme.color.orange}; - `, - delete: (theme: Theme) => css` - width: 100%; - height: 3rem; - - border: 1px solid ${theme.color.orange}; - border-radius: 4px; - - ${theme.font["pretendard-01"]} - color: ${theme.color.orange}; - `, - fillLightOrange: (theme: Theme) => css` - width: 100%; - height: 4.8rem; - - border-radius: 5px; - - ${theme.font["pretendard-01"]} - color: ${theme.color.orange}; - background-color: ${theme.color.lightorange}; - `, + fill: (category: CategoryType) => (theme: Theme) => + css` + width: 100%; + height: 4.8rem; + + border-radius: 5px; + + ${theme.font["pretendard-01"]} + color: ${theme.color.white}; + background-color: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + `, + stroke: (category: CategoryType) => (theme: Theme) => + css` + width: 100%; + height: 4.8rem; + + border: 1px solid + ${category === "experience" ? theme.color.green : theme.color.orange}; + border-radius: 5px; + + ${theme.font["pretendard-01"]} + color: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + background-color: ${theme.color.white}; + `, + smallStroke: (category: CategoryType) => (theme: Theme) => + css` + width: 100%; + height: 3rem; + + border: 1px solid + ${category === "experience" ? theme.color.green : theme.color.orange}; + border-radius: 4px; + + ${theme.font["subhead-m-14"]} + color: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + background-color: transparent; + `, + smallFill: (category: CategoryType) => (theme: Theme) => + css` + width: 100%; + height: 3rem; + + border: 1px solid + ${category === "experience" ? theme.color.green : theme.color.orange}; + border-radius: 4px; + + ${theme.font["pretendard-01"]} + color: ${theme.color.white}; + background-color: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + `, + delete: (category: CategoryType) => (theme: Theme) => + css` + width: 100%; + height: 3rem; + + border: 1px solid + ${category === "experience" ? theme.color.green : theme.color.orange}; + border-radius: 4px; + + ${theme.font["pretendard-01"]} + color: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + `, + fillLightColor: (category: CategoryType) => (theme: Theme) => + css` + width: 100%; + height: 4.8rem; + + border-radius: 5px; + + ${theme.font["pretendard-01"]} + color: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + background-color: ${category === "experience" + ? theme.color.lightgreen + : theme.color.lightorange}; + `, }; export const disabledStyle = (theme: Theme) => css` @@ -80,7 +105,14 @@ export const disabledStyle = (theme: Theme) => css` background-color: ${theme.color.lightgray1}; `; -export const iconStyle = css` - width: 1.6rem; - height: 1.6rem; -`; +export const iconStyle = (category: CategoryType) => (theme: Theme) => + css` + width: 1.6rem; + height: 1.6rem; + + & path { + stroke: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + } + `; diff --git a/src/components/common/Button/Button.tsx b/src/components/common/Button/Button.tsx index 320fff6..884399d 100644 --- a/src/components/common/Button/Button.tsx +++ b/src/components/common/Button/Button.tsx @@ -6,6 +6,8 @@ import { iconStyle, } from "./Button.style"; import { IcFix } from "@svg"; +import { useAtom } from "jotai"; +import { categoryAtom } from "@stores"; export interface ButtonProps extends ButtonHTMLAttributes { variant: @@ -14,7 +16,7 @@ export interface ButtonProps extends ButtonHTMLAttributes { | "smallStroke" | "smallFill" | "delete" - | "fillLightOrange"; + | "fillLightColor"; disabled?: boolean; isIcon?: boolean; } @@ -26,14 +28,20 @@ const Button = ({ onClick, children, }: ButtonProps) => { + const [category] = useAtom(categoryAtom); + return ( ); }; diff --git a/src/components/common/CheckBox/CheckBox.style.ts b/src/components/common/CheckBox/CheckBox.style.ts index 65e4f2c..5c1b456 100644 --- a/src/components/common/CheckBox/CheckBox.style.ts +++ b/src/components/common/CheckBox/CheckBox.style.ts @@ -1,6 +1,7 @@ import { Theme } from "@emotion/react"; import { css } from "@emotion/react"; import { flexGenerator } from "@styles/generator"; +import { CategoryType } from "@types"; export const checkboxWrapper = css` ${flexGenerator("row", "start", "center")}; @@ -14,6 +15,15 @@ export const iconStyle = css` height: 2.4rem; `; +export const checkedIconStyle = (category: CategoryType) => (theme: Theme) => + css` + & path { + fill: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + } + `; + export const textStyle = (theme: Theme) => css` color: ${theme.color.black}; ${theme.font["subhead-n-14"]} diff --git a/src/components/common/CheckBox/CheckBox.tsx b/src/components/common/CheckBox/CheckBox.tsx index ec1b32e..fe8ce89 100644 --- a/src/components/common/CheckBox/CheckBox.tsx +++ b/src/components/common/CheckBox/CheckBox.tsx @@ -1,6 +1,13 @@ import { IcCheckbox, IcCheckedTrue } from "@svg"; import { InputHTMLAttributes, ReactNode } from "react"; -import { checkboxWrapper, iconStyle, textStyle } from "./CheckBox.style"; +import { + checkboxWrapper, + checkedIconStyle, + iconStyle, + textStyle, +} from "./CheckBox.style"; +import { useAtom } from "jotai"; +import { categoryAtom } from "@stores"; export interface CheckBoxProps extends InputHTMLAttributes { isChecked: boolean; @@ -9,10 +16,16 @@ export interface CheckBoxProps extends InputHTMLAttributes { } const CheckBox = ({ isChecked, onClick, children }: CheckBoxProps) => { + const [category] = useAtom(categoryAtom); + return (
- {isChecked ? : } + {isChecked ? ( + + ) : ( + + )} {children}
diff --git a/src/components/common/CountProduct/CountProduct.style.ts b/src/components/common/CountProduct/CountProduct.style.ts index c48e797..4f0d14b 100644 --- a/src/components/common/CountProduct/CountProduct.style.ts +++ b/src/components/common/CountProduct/CountProduct.style.ts @@ -11,6 +11,8 @@ export const productNameStyle = (theme: Theme) => css` width: 100%; ${theme.font["subhead-n-16"]}; color: ${theme.color.black}; + white-space: normal; + word-break: keep-all; `; export const productCountWrapper = css` diff --git a/src/components/common/Header/Header.style.ts b/src/components/common/Header/Header.style.ts index 4550b3d..95aa7bf 100644 --- a/src/components/common/Header/Header.style.ts +++ b/src/components/common/Header/Header.style.ts @@ -1,6 +1,7 @@ import { Theme } from "@emotion/react"; import { css } from "@emotion/react"; import { flexGenerator } from "@styles/generator"; +import { CategoryType } from "@types"; export const headerContainer = (theme: Theme) => css` position: fixed; @@ -10,26 +11,60 @@ export const headerContainer = (theme: Theme) => css` max-width: 43rem; height: 6rem; background-color: ${theme.color.white}; + padding: 0 2rem; + + ${flexGenerator()}; `; -export const headerWrapper = css` - ${flexGenerator()} +export const headerSection = css` width: 100%; - height: 6rem; - position: relative; + display: flex; + align-items: center; `; -export const iconStyle = css` - width: 3.8rem; - height: 3rem; - position: absolute; - left: 0.7rem; +export const headerLeft = css` + width: 15%; `; -export const textStyle = (theme: Theme) => css` - position: absolute; - left: 50%; - transform: translateX(-50%); +export const headerTitle = (theme: Theme) => css` + width: 70%; + color: ${theme.color.black}; - ${theme.font["subhead-m-18"]} + ${theme.font["subhead-m-18"]}; + justify-content: center; +`; + +export const headerRight = css` + width: 15%; + justify-content: flex-end; +`; + +export const iconStyle = css` + width: 2.4rem; +`; + +export const confrimModal = css` + width: 30rem; + ${flexGenerator("column")}; + padding: 3rem; +`; + +export const confirmModalText = (category: CategoryType) => (theme: Theme) => + css` + ${theme.font["head06-b-16"]} + color: ${theme.color.black}; + text-align: center; + + & > strong { + color: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + } + `; + +export const buttonWrapper = css` + width: 100%; + margin-top: 2rem; + ${flexGenerator("column")}; + gap: 1rem; `; diff --git a/src/components/common/Header/Header.tsx b/src/components/common/Header/Header.tsx index 52431a6..355e26b 100644 --- a/src/components/common/Header/Header.tsx +++ b/src/components/common/Header/Header.tsx @@ -1,30 +1,86 @@ -import { IcBack } from "@svg"; +import { IcArrowBack, IcHome } from "@svg"; import { + buttonWrapper, + confirmModalText, + confrimModal, headerContainer, - headerWrapper, + headerLeft, + headerRight, + headerSection, + headerTitle, iconStyle, - textStyle, } from "./Header.style"; import { useNavigate } from "react-router-dom"; +import { useAtom } from "jotai"; +import { categoryAtom } from "@stores"; +import { useState } from "react"; +import Modal from "../Modal/Modal"; +import Button from "../Button/Button"; -interface HeaderProps { - text: string; -} - -const Header = ({ text }: HeaderProps) => { +const Header = () => { + const [category] = useAtom(categoryAtom); const navigate = useNavigate(); + const [isModalOpen, setIsModalOpen] = useState(false); + const handleBackClick = () => { navigate(-1); }; + + const handleClickHome = () => { + setIsModalOpen(true); + }; + + const handleModalClose = () => { + setIsModalOpen(false); + }; + + const handleCancel = () => { + setIsModalOpen(false); + }; + + const handleConfirm = () => { + localStorage.clear(); + setIsModalOpen(false); + navigate("/"); + }; + return ( -
-
- - - -

{text}

-
-
+ <> +
+
+ +
+

+ {category === "product" + ? "상품 구매 택배 접수" + : "체험 과일 택배 접수"} +

+
+ +
+
+ {isModalOpen && ( + +
+

+ 홈으로 이동하면 지금까지 작성한 +

+

+ 데이터가 모두 삭제됩니다. +

+

그래도 이동하시겠습니까?

+
+ + +
+
+
+ )} + ); }; diff --git a/src/components/common/Input/Input.style.ts b/src/components/common/Input/Input.style.ts index c5444ed..6288091 100644 --- a/src/components/common/Input/Input.style.ts +++ b/src/components/common/Input/Input.style.ts @@ -1,6 +1,7 @@ import { Theme } from "@emotion/react"; import { css } from "@emotion/react"; import { flexGenerator } from "@styles/generator"; +import { CategoryType } from "@types"; export const inputWrapper = css` ${flexGenerator("column", "flex-start", "flex-start")} @@ -13,25 +14,27 @@ export const labelStyle = (theme: Theme) => css` ${theme.font["subhead-n-16"]} `; -export const inputStyle = (theme: Theme) => css` - width: 100%; - padding: 1.5rem; - border: 1px solid ${theme.color.lightgray1}; - border-radius: 10px; - background-color: ${theme.color.white}; - ${theme.font["subhead-n-16"]} +export const inputStyle = (category: CategoryType) => (theme: Theme) => + css` + width: 100%; + padding: 1.5rem; + border: 1px solid ${theme.color.lightgray1}; + border-radius: 10px; + background-color: ${theme.color.white}; + ${theme.font["subhead-n-16"]} - &::placeholder { - color: ${theme.color.midgray1}; - } + &::placeholder { + color: ${theme.color.midgray1}; + } - &:focus { - outline: none; - border: 1px solid ${theme.color.orange}; - } + &:focus { + outline: none; + border: 1px solid + ${category === "experience" ? theme.color.green : theme.color.orange}; + } - &:disabled { - background-color: ${theme.color.background}; - color: ${theme.color.midgray1}; - } -`; + &:disabled { + background-color: ${theme.color.background}; + color: ${theme.color.midgray1}; + } + `; diff --git a/src/components/common/Input/Input.tsx b/src/components/common/Input/Input.tsx index d8021f1..3bd4a00 100644 --- a/src/components/common/Input/Input.tsx +++ b/src/components/common/Input/Input.tsx @@ -1,5 +1,7 @@ import React, { HTMLAttributes } from "react"; import { inputStyle, inputWrapper, labelStyle } from "./Input.style"; +import { useAtom } from "jotai"; +import { categoryAtom } from "@stores"; export interface InputProps extends HTMLAttributes { value: string | number; @@ -20,6 +22,8 @@ const Input = ({ inputLabel, disabled, }: InputProps) => { + const [category] = useAtom(categoryAtom); + const handleInputChange = (e: React.ChangeEvent) => { if (onChange) { onChange(e); @@ -30,7 +34,7 @@ const Input = ({
{inputLabel && {inputLabel}} css` position: fixed; @@ -10,9 +11,12 @@ export const progressBarContainer = (theme: Theme) => css` background-color: ${theme.color.lightgray1}; `; -export const progressBarStyle = (progress: number) => (theme: Theme) => - css` - width: ${progress}%; - height: 100%; - background-color: ${theme.color.orange}; - `; +export const progressBarStyle = + (progress: number, category: CategoryType) => (theme: Theme) => + css` + width: ${progress}%; + height: 100%; + background-color: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + `; diff --git a/src/components/common/ProgressBar/ProgressBar.tsx b/src/components/common/ProgressBar/ProgressBar.tsx index d8d0e7a..452f5ac 100644 --- a/src/components/common/ProgressBar/ProgressBar.tsx +++ b/src/components/common/ProgressBar/ProgressBar.tsx @@ -1,13 +1,17 @@ import { progressBarContainer, progressBarStyle } from "./ProgressBar.style"; +import { useAtom } from "jotai"; +import { categoryAtom } from "@stores"; interface ProgressBarProps { progress: number; } const ProgressBar = ({ progress }: ProgressBarProps) => { + const [category] = useAtom(categoryAtom); + return (
-
+
); }; diff --git a/src/components/common/steps/CheckInfo/CheckInfo.style.ts b/src/components/common/steps/CheckInfo/CheckInfo.style.ts index b9f9863..61f10bb 100644 --- a/src/components/common/steps/CheckInfo/CheckInfo.style.ts +++ b/src/components/common/steps/CheckInfo/CheckInfo.style.ts @@ -1,5 +1,6 @@ import { Theme, css } from "@emotion/react"; import { flexGenerator } from "@styles/generator"; +import { CategoryType } from "@types"; export const textSection = css` ${flexGenerator("row", "start", "start")}; @@ -40,7 +41,6 @@ export const receiverListSection = css` width: 100%; margin-top: 2.3rem; - margin-bottom: 2rem; `; export const orderItemWrapper = css` @@ -103,15 +103,18 @@ export const confrimModal = css` padding: 3rem; `; -export const confirmModalText = (theme: Theme) => css` - ${theme.font["head06-b-16"]} - color: ${theme.color.black}; - text-align: center; +export const confirmModalText = (category: CategoryType) => (theme: Theme) => + css` + ${theme.font["head06-b-16"]} + color: ${theme.color.black}; + text-align: center; - & > strong { - color: ${theme.color.orange}; - } -`; + & > strong { + color: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + } + `; export const buttonWrapper = css` width: 100%; @@ -119,3 +122,20 @@ export const buttonWrapper = css` ${flexGenerator("column")}; gap: 1rem; `; + +export const totalPriceText = (theme: Theme) => css` + width: 100%; + ${theme.font["head02-b-20"]} + color: ${theme.color.black}; + text-align: right; +`; + +export const footerButtonWrapper = css` + width: 100%; + ${flexGenerator()}; + gap: 1rem; +`; + +export const footerShadow = css` + padding-top: 1rem; +box-shadow: rgba(0, 0, 0, 0.1) 0px -4px 8px;`; diff --git a/src/components/common/steps/CheckInfo/CheckInfo.tsx b/src/components/common/steps/CheckInfo/CheckInfo.tsx index 06f37f7..a80b583 100644 --- a/src/components/common/steps/CheckInfo/CheckInfo.tsx +++ b/src/components/common/steps/CheckInfo/CheckInfo.tsx @@ -1,4 +1,4 @@ -import { Button, Header, Modal, ProgressBar } from "@components"; +import { Button, Modal } from "@components"; import { StepProps } from "@types"; import { buttonSectionStyle, layoutStyle } from "@pages/orderInfo/styles"; import { @@ -8,6 +8,8 @@ import { confirmModalText, confrimModal, editButtonWrapper, + footerButtonWrapper, + footerShadow, head03Style, infoContainer, orderItemInfoWrapper, @@ -17,6 +19,7 @@ import { senderSectionLeft, senderSectionRight, textSection, + totalPriceText, } from "./CheckInfo.style"; import { useNavigate } from "react-router-dom"; import { usePostOrder } from "@apis/domains/service/usePostOrder"; @@ -37,11 +40,16 @@ const CheckInfo = ({ onNext }: StepProps) => { const { mutateAsync } = usePostOrder(); const receivers = orderPostDataState.recipientInfo ?? []; const navigate = useNavigate(); - const [category] = useAtom(categoryAtom); + const [category, setCategory] = useAtom(categoryAtom); const [isModalOpen, setIsModalOpen] = useState(false); const orderCount = receivers.length; + const totalOrderPrice = receivers.reduce( + (acc, receiver) => acc + receiver.orderPrice, + 0 + ); + const handleModalClose = () => { setIsModalOpen(false); }; @@ -64,8 +72,10 @@ const CheckInfo = ({ onNext }: StepProps) => { const handleOrderClick = () => { mutateAsync(orderPostDataState) .then((data) => { + const prevCtergory = category; resetOrderPostData(); localStorage.clear(); + setCategory(prevCtergory); setOrderNumberState(data); onNext(); }) @@ -86,111 +96,115 @@ const CheckInfo = ({ onNext }: StepProps) => { }; return ( - <> -
- -
-
- 이대로 주문하시겠어요? -
-
-
-
보내는 분
- {orderPostDataState.senderName} - {orderPostDataState.senderPhone} -
-
- -
-
-
- {receivers.map((receiver, i) => ( -
-
주문{i + 1}
-
- handleDeleteClick(i)} - /> +
+
+ 이대로 주문하시겠어요? +
+
+
+
보내는 분
+ {orderPostDataState.senderName} + {orderPostDataState.senderPhone} +
+
+ +
+
+
+ {receivers.map((receiver, i) => ( +
+
주문{i + 1}
+
+ handleDeleteClick(i)} + /> +
+
받는 분
+ {receiver.recipientName} + {receiver.recipientPhone} + + {`${receiver.recipientAddress}, ${receiver.recipientAddressDetail}`} + +
+
+
선택상품
+
+ {receiver.productInfo + .filter((product) => product.productCount > 0) + .map((product, j) => ( + + {`${product.productName} ${product.productCount}개`} + + ))} +
+
+ {category === "product" && (
-
받는 분
- {receiver.recipientName} - {receiver.recipientPhone} +
희망 배송일자
- {`${receiver.recipientAddress}, ${receiver.recipientAddressDetail}`} + {receiver.selectedOption === "regular" + ? "일반 배송" + : receiver.deliveryDate}
-
-
선택상품
-
- {receiver.productInfo - .filter((product) => product.productCount > 0) - .map((product, j) => ( - - {`${product.productName} ${product.productCount}개`} - - ))} -
-
- {category === "product" && ( -
-
희망 배송일자
- - {receiver.selectedOption === "regular" - ? "일반 배송" - : receiver.deliveryDate} - -
- )} - - - + )} +
+
주문{i + 1} 금액
+ {`${receiver.orderPrice.toLocaleString()}원`}
-
- ))} -
-
- + +
+
+ ))} +
+
+

{`총 결제금액: ${totalOrderPrice.toLocaleString()}원`}

+
+ -
- {isModalOpen && ( - -
-

- 현재 {`${orderCount}건`}의 주문을 진행 - 중입니다. -

-

{`추가 주문 없이 이대로`}

-

{`주문을 완료하시겠습니까?`}

-
- - -
-
-
- )} -
- +
+ + {isModalOpen && ( + +
+

+ 현재 {`${orderCount}건`}의 주문을 진행 중입니다. +

+

{`추가 주문 없이 이대로`}

+

{`주문을 완료하시겠습니까?`}

+
+ + +
+
+
+ )} +
); }; diff --git a/src/components/common/steps/CheckInfo/Edit/Edit.tsx b/src/components/common/steps/CheckInfo/Edit/Edit.tsx index dee097d..0b0f7b2 100644 --- a/src/components/common/steps/CheckInfo/Edit/Edit.tsx +++ b/src/components/common/steps/CheckInfo/Edit/Edit.tsx @@ -9,8 +9,8 @@ const Edit = () => { const receiverIndex = state.index !== undefined ? state.index : 0; return ( <> -
- +
+ {state.type === "sender" ? ( ) : ( diff --git a/src/components/common/steps/CheckInfo/Edit/EditReceiver/EditReceiver.style.ts b/src/components/common/steps/CheckInfo/Edit/EditReceiver/EditReceiver.style.ts index 1d4759a..51e3111 100644 --- a/src/components/common/steps/CheckInfo/Edit/EditReceiver/EditReceiver.style.ts +++ b/src/components/common/steps/CheckInfo/Edit/EditReceiver/EditReceiver.style.ts @@ -25,6 +25,7 @@ export const addressFormWrapper = css` ${flexGenerator("column", "start", "start")}; gap: 1rem; width: 100%; + margin-bottom: 2rem; `; export const zonecodeWrapper = css` @@ -36,6 +37,7 @@ export const zonecodeWrapper = css` export const selectProductContainer = css` ${flexGenerator("column", "start", "start")}; width: 100%; + margin-bottom: 2rem; `; export const selectProductWrapper = css` diff --git a/src/components/common/steps/CheckInfo/Edit/EditReceiver/EditReceiver.tsx b/src/components/common/steps/CheckInfo/Edit/EditReceiver/EditReceiver.tsx index 2885344..b07f781 100644 --- a/src/components/common/steps/CheckInfo/Edit/EditReceiver/EditReceiver.tsx +++ b/src/components/common/steps/CheckInfo/Edit/EditReceiver/EditReceiver.tsx @@ -42,8 +42,11 @@ interface EditReceiverProps { } const EditReceiver = ({ receiverIndex }: EditReceiverProps) => { - const { orderPostDataState, handleRecipientInputChange } = - useOrderPostDataChange(); + const { + orderPostDataState, + handleRecipientInputChange, + handleChangeOrderPrice, + } = useOrderPostDataChange(); const receiver = orderPostDataState.recipientInfo[receiverIndex] ?? {}; const navigate = useNavigate(); @@ -129,11 +132,17 @@ const EditReceiver = ({ receiverIndex }: EditReceiverProps) => { return product; }); + const totalSum = updatedProductInfo.reduce((sum, product) => { + return sum + product.productCount * product.productPrice; + }, 0); + handleRecipientInputChange( updatedProductInfo, "productInfo", receiverIndex ); + + handleChangeOrderPrice(totalSum, receiverIndex); }; const handleOptionChange = (e: React.ChangeEvent) => { @@ -253,7 +262,13 @@ const EditReceiver = ({ receiverIndex }: EditReceiverProps) => {
-
diff --git a/src/components/common/steps/Complete/Complete.style.ts b/src/components/common/steps/Complete/Complete.style.ts index 41023f7..b706c6c 100644 --- a/src/components/common/steps/Complete/Complete.style.ts +++ b/src/components/common/steps/Complete/Complete.style.ts @@ -1,17 +1,24 @@ import { Theme, css } from "@emotion/react"; import { flexGenerator } from "@styles/generator"; +import { CategoryType } from "@types"; export const layoutStyle = css` ${flexGenerator("column", "center", "center")}; width: 100%; - padding: 13.9rem 2rem 3rem; min-height: 100dvh; `; -export const iconStyle = css` - width: 6.4rem; - height: 6.4rem; -`; +export const iconStyle = (category: CategoryType) => (theme: Theme) => + css` + width: 6.4rem; + height: 6.4rem; + + & > path { + fill: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + } + `; export const spanContainer = css` ${flexGenerator("column")}; @@ -24,15 +31,21 @@ export const spanStyle = (theme: Theme) => css` color: ${theme.color.black}; `; -export const orderNumberWrapper = css` - background-color: #ffede7; - padding: 1rem 1.5rem; - border-radius: 10px; -`; +export const orderNumberWrapper = (category: CategoryType) => (theme: Theme) => + css` + background-color: ${category === "experience" + ? theme.color.lightgreen + : theme.color.lightorange}; + padding: 1rem 1.5rem; + border-radius: 10px; + `; -export const orderNumberStyle = (theme: Theme) => css` - color: ${theme.color.orange}; -`; +export const orderNumberStyle = (category: CategoryType) => (theme: Theme) => + css` + color: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + `; export const lastSpanWrapper = (theme: Theme) => css` ${flexGenerator()}; diff --git a/src/components/common/steps/Complete/Complete.tsx b/src/components/common/steps/Complete/Complete.tsx index 67b8296..696cf85 100644 --- a/src/components/common/steps/Complete/Complete.tsx +++ b/src/components/common/steps/Complete/Complete.tsx @@ -1,4 +1,4 @@ -import { Button, ClipboardButton, Header, ProgressBar } from "@components"; +import { Button, ClipboardButton } from "@components"; import { IcComplete } from "@svg"; import { useNavigate } from "react-router-dom"; import { @@ -32,46 +32,43 @@ const Complete = () => { }; const handleButtonClick = () => { localStorage.clear(); - navigate(`/${category}`); + navigate(`/`); }; return ( - <> -
- -
- -
- 주문이 완료되었어요 - - 주문번호: {orderNumberState} - - - 카운터에서 주문번호로 결제해주세요 - -
-
- {!showAccountInfo && ( - - )} - {showAccountInfo && ( -
-
- NH농협 - -
- - 예금주 제주체험농장 - -
- )} - -
+
+ +
+ 주문이 완료되었어요 + + {`주문번호: `} + {orderNumberState} + + + 카운터에서 주문번호로 결제해주세요 +
- +
+ {!showAccountInfo && ( + + )} + {showAccountInfo && ( +
+
+ NH농협 + +
+ + 예금주 제주체험농장 + +
+ )} + +
+
); }; diff --git a/src/components/common/steps/Receiver1/Receiver1.tsx b/src/components/common/steps/Receiver1/Receiver1.tsx index 1a7f8b0..076aa20 100644 --- a/src/components/common/steps/Receiver1/Receiver1.tsx +++ b/src/components/common/steps/Receiver1/Receiver1.tsx @@ -1,18 +1,22 @@ -import { Button, CheckBox, Header, Input, ProgressBar } from "@components"; +import { Button, CheckBox, Input } from "@components"; import { StepProps } from "@types"; import { buttonSectionStyle, layoutStyle, mainSectionStyle, - orangeTextStyle, + coloredTextStyle, sectionStyle, textStyle, } from "@pages/orderInfo/styles"; import { useState } from "react"; import useOrderPostDataValidation from "src/hooks/useOrderPostDataValidation"; import { useOrderPostDataChange } from "src/hooks/useOrderPostDataChange"; +import { useAtom } from "jotai"; +import { categoryAtom } from "@stores"; const Receiver1 = ({ onNext }: StepProps) => { + const [category] = useAtom(categoryAtom); + const { orderPostDataState, currentRecipientIndex, @@ -50,55 +54,47 @@ const Receiver1 = ({ onNext }: StepProps) => { }; return ( - <> -
- -
-
-
- 받는 분의 -
- 이름과 휴대폰 번호를 입력해주세요 -
-
-
- handleRecipientInputChange(e, "recipientName")} - type="text" - placeholder="이름을 입력하세요" - inputLabel="이름" - disabled={isChecked} - /> - handleRecipientInputChange(e, "recipientPhone")} - type="tel" - placeholder="휴대폰 번호를 입력하세요" - inputLabel="휴대폰 번호" - disabled={isChecked} - /> - - 보내는 사람과 같아요 - -
-
- -
-
- +
+
+
+ 받는 분의 +
+ 이름과 휴대폰 번호를 입력해주세요 +
+
+
+ handleRecipientInputChange(e, "recipientName")} + type="text" + placeholder="이름을 입력하세요" + inputLabel="이름" + disabled={isChecked} + /> + handleRecipientInputChange(e, "recipientPhone")} + type="tel" + placeholder="휴대폰 번호를 입력하세요" + inputLabel="휴대폰 번호" + disabled={isChecked} + /> + + 보내는 사람과 같아요 + +
+
+ +
+
); }; diff --git a/src/components/common/steps/Receiver2/Receiver2.tsx b/src/components/common/steps/Receiver2/Receiver2.tsx index 4e926cc..f640380 100644 --- a/src/components/common/steps/Receiver2/Receiver2.tsx +++ b/src/components/common/steps/Receiver2/Receiver2.tsx @@ -1,9 +1,9 @@ import React, { useEffect, useState } from "react"; -import { Button, Header, Input, ProgressBar } from "@components"; +import { Button, Input } from "@components"; import { buttonSectionStyle, layoutStyle, - orangeTextStyle, + coloredTextStyle, sectionStyle, textStyle, } from "@pages/orderInfo/styles"; @@ -11,6 +11,8 @@ import { StepProps } from "@types"; import { mainSectionStyle, zonecodeWrapper } from "./Receiver2.style"; import { useDaumPostcodePopup } from "react-daum-postcode"; import { useOrderPostDataChange } from "src/hooks/useOrderPostDataChange"; +import { useAtom } from "jotai"; +import { categoryAtom } from "@stores"; const scriptUrl = "https://t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"; @@ -24,6 +26,8 @@ interface DaumPostcodeData { } const Receiver2 = ({ onNext }: StepProps) => { + const [category] = useAtom(categoryAtom); + const { orderPostDataState, currentRecipientIndex, @@ -106,56 +110,50 @@ const Receiver2 = ({ onNext }: StepProps) => { }, [receiver]); return ( - <> -
- -
-
-
- 받는 분의 -
- 주소를 입력해주세요 -
-
-
-
- - -
+
+
+
+ 받는 분의 +
+ 주소를 입력해주세요 +
+
+
+
- - setForm({ ...form, addressDetail: e.target.value }) - } - name="addressDetail" - type="text" - placeholder="상세주소 (예시: 101동 1201호 / 단독주택)" - /> -
-
- -
-
- +
+ + setForm({ ...form, addressDetail: e.target.value })} + name="addressDetail" + type="text" + placeholder="상세주소 (예시: 101동 1201호 / 단독주택)" + /> + +
+ +
+
); }; diff --git a/src/components/common/steps/SelectDeliveryDate/SelectDeliveryDate.tsx b/src/components/common/steps/SelectDeliveryDate/SelectDeliveryDate.tsx index 6d40df2..8dcf824 100644 --- a/src/components/common/steps/SelectDeliveryDate/SelectDeliveryDate.tsx +++ b/src/components/common/steps/SelectDeliveryDate/SelectDeliveryDate.tsx @@ -1,14 +1,8 @@ -import { - Button, - CustomCalendar, - Header, - ProgressBar, - RadioInput, -} from "@components"; +import { Button, CustomCalendar, RadioInput } from "@components"; import { buttonSectionStyle, layoutStyle, - orangeTextStyle, + coloredTextStyle, sectionStyle, textStyle, } from "@pages/orderInfo/styles"; @@ -24,8 +18,12 @@ import { import React, { useState } from "react"; import { getTwoDaysLaterDate } from "@utils"; import { useOrderPostDataChange } from "src/hooks/useOrderPostDataChange"; +import { useAtom } from "jotai"; +import { categoryAtom } from "@stores"; const SelectDeliveryDate = ({ onNext }: StepProps) => { + const [category] = useAtom(categoryAtom); + const { orderPostDataState, currentRecipientIndex, @@ -60,65 +58,61 @@ const SelectDeliveryDate = ({ onNext }: StepProps) => { }; return ( - <> -
- -
-
-
- 희망하는 -
- 배송일자를 선택해주세요 -
+
+
+
+ 희망하는 +
+ 배송일자를 선택해주세요 +
+
+
+
+ +
-
-
- - -
-
- - {selectedOption === "regular" - ? "일반배송은 가능한 가장 빠른 날짜에 발송해드려요." - : "예약배송은 원하시는 날짜에 맞춰 발송해드려요."} - - - {selectedOption === "regular" && ( - - 보통 배송 출발까지 2일정도 소요되지만, -
-
- )} - - 기상 상황에 따라 일정이 변동될 수 있어요. +
+ + {selectedOption === "regular" + ? "일반배송은 가능한 가장 빠른 날짜에 발송해드려요." + : "예약배송은 원하시는 날짜에 맞춰 발송해드려요."} + + + {selectedOption === "regular" && ( + + 보통 배송 출발까지 2일정도 소요되지만, +
-
-
-
- {selectedOption === "scheduled" && ( - )} -
-
-
- -
-
- + + 기상 상황에 따라 일정이 변동될 수 있어요. + + +
+
+ {selectedOption === "scheduled" && ( + + )} +
+ +
+ +
+
); }; diff --git a/src/components/common/steps/SelectProduct/SelectProduct.tsx b/src/components/common/steps/SelectProduct/SelectProduct.tsx index 1d65a5c..b8fc1eb 100644 --- a/src/components/common/steps/SelectProduct/SelectProduct.tsx +++ b/src/components/common/steps/SelectProduct/SelectProduct.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from "react"; -import { Button, CountProduct, Header, ProgressBar } from "@components"; +import { Button, CountProduct } from "@components"; import { buttonSectionStyle, layoutStyle, - orangeTextStyle, + coloredTextStyle, sectionStyle, textStyle, } from "@pages/orderInfo/styles"; @@ -14,7 +14,6 @@ import { useAtom } from "jotai"; import { categoryAtom, productListAtom } from "@stores"; import { useOrderPostDataChange } from "src/hooks/useOrderPostDataChange"; import { ProductList } from "src/stores/productList"; -import { RecipientInfo } from "src/stores/orderPostData"; import { getTwoDaysLaterDate } from "@utils"; const SelectProduct = ({ onNext }: StepProps) => { @@ -24,6 +23,7 @@ const SelectProduct = ({ onNext }: StepProps) => { orderPostDataState, currentRecipientIndex, handleRecipientInputChange, + handleChangeOrderPrice, } = useOrderPostDataChange(); const { data: productList, isLoading } = useFetchProductList(); const [productListState, setProductListState] = useAtom(productListAtom); @@ -31,26 +31,28 @@ const SelectProduct = ({ onNext }: StepProps) => { [] ); - const calculateTotalPrice = (products: ProductList, order: RecipientInfo) => { - console.log("RecipientInfo", order); + const [orderPrice, setOrderPrice] = useState( + orderPostDataState.recipientInfo[currentRecipientIndex]?.orderPrice ?? 0 + ); - return (order.productInfo || []).reduce((total, orderProduct) => { - const product = products.find( - (p) => p.productId === orderProduct.productId - ); + // const calculateTotalPrice = (products: ProductList, order: RecipientInfo) => { + // return (order.productInfo || []).reduce((total, orderProduct) => { + // const product = products.find( + // (p) => p.productId === orderProduct.productId + // ); - if (product) { - total += product.productPrice * orderProduct.productCount; - } + // if (product) { + // total += product.productPrice * orderProduct.productCount; + // } - return total; - }, 0); - }; + // return total; + // }, 0); + // }; - const totalPrice = calculateTotalPrice( - displayedProductList, - orderPostDataState.recipientInfo[currentRecipientIndex] ?? {} - ); + // const totalPrice = calculateTotalPrice( + // displayedProductList, + // orderPostDataState.recipientInfo[currentRecipientIndex] ?? {} + // ); useEffect(() => { if (productList) { @@ -80,6 +82,7 @@ const SelectProduct = ({ onNext }: StepProps) => { productId: product.productId, productName: product.productName, productCount: 0, + productPrice: product.productPrice, })); handleRecipientInputChange( @@ -104,13 +107,21 @@ const SelectProduct = ({ onNext }: StepProps) => { productId: product.productId, productName: product.productName, productCount: newCount, + productPrice: product.productPrice, }; + const totalSum = updatedProductInfo.reduce((sum, product) => { + return sum + product.productCount * product.productPrice; + }, 0); + handleRecipientInputChange( updatedProductInfo, "productInfo", currentRecipientIndex ); + + handleChangeOrderPrice(totalSum, currentRecipientIndex); + setOrderPrice(totalSum); } } }; @@ -132,48 +143,42 @@ const SelectProduct = ({ onNext }: StepProps) => { } return ( - <> -
- -
-
-
- 보내실 상품의 -
- 수량을 선택해주세요 -
-
-
- {displayedProductList.map((product, i) => { - const productCount = - orderPostDataState.recipientInfo[currentRecipientIndex] - ?.productInfo?.[i]?.productCount ?? 0; - return ( - handleCountChange(i, newCount)} - /> - ); - })} -
-
-

{`총 ${totalPrice.toLocaleString()} 원`}

- -
-
- +
+
+
+ 보내실 상품의 +
+ 수량을 선택해주세요 +
+
+
+ {displayedProductList.map((product, i) => { + const productCount = + orderPostDataState.recipientInfo[currentRecipientIndex] + ?.productInfo?.[i]?.productCount ?? 0; + return ( + handleCountChange(i, newCount)} + /> + ); + })} +
+
+

{`총 ${orderPrice.toLocaleString()} 원`}

+ +
+
); }; diff --git a/src/components/common/steps/Sender/Sender.style.ts b/src/components/common/steps/Sender/Sender.style.ts index ea5e248..fe79cbf 100644 --- a/src/components/common/steps/Sender/Sender.style.ts +++ b/src/components/common/steps/Sender/Sender.style.ts @@ -18,10 +18,6 @@ export const textStyle = (theme: Theme) => css` color: ${theme.color.black}; `; -export const orangeTextStyle = (theme: Theme) => css` - color: ${theme.color.orange}; -`; - export const mainSectionStyle = css` ${flexGenerator("column", "start", "start")}; gap: 3rem; diff --git a/src/components/common/steps/Sender/Sender.tsx b/src/components/common/steps/Sender/Sender.tsx index 6dd9fcb..1101395 100644 --- a/src/components/common/steps/Sender/Sender.tsx +++ b/src/components/common/steps/Sender/Sender.tsx @@ -1,17 +1,10 @@ -import { - Button, - CheckBox, - Header, - Input, - Modal, - ProgressBar, -} from "@components"; +import { Button, CheckBox, Input, Modal } from "@components"; import { StepProps } from "@types"; import { buttonSectionStyle, layoutStyle, mainSectionStyle, - orangeTextStyle, + coloredTextStyle, sectionStyle, textStyle, } from "@pages/orderInfo/styles"; @@ -25,8 +18,12 @@ import { import useOrderPostDataValidation from "src/hooks/useOrderPostDataValidation"; import { useOrderPostDataChange } from "src/hooks/useOrderPostDataChange"; import { useState } from "react"; +import { useAtom } from "jotai"; +import { categoryAtom } from "@stores"; const Sender = ({ onNext }: StepProps) => { + const [category] = useAtom(categoryAtom); + const { orderPostDataState, handleInputChange, @@ -58,127 +55,119 @@ const Sender = ({ onNext }: StepProps) => { setIsModalOpen(true); }; return ( - <> -
- -
-
-
- 보내는 분의 -
- 이름과 휴대폰 번호를 입력해주세요 -
-
-
- handleInputChange(e, "senderName")} - type="name" - placeholder="이름을 입력하세요" - inputLabel="이름" - /> - handleInputChange(e, "senderPhone")} - type="tel" - placeholder="휴대폰 번호를 입력하세요" - inputLabel="휴대폰 번호" - /> -
- - [필수] 개인정보 수집 및 이용 동의 - { - e.stopPropagation(); - handleDetailClick("personalInfo"); - }} - css={consentDetail} - > - 더보기 - - - +
+
+ 보내는 분의 +
+ 이름과 휴대폰 번호를 입력해주세요 +
+
+
+ handleInputChange(e, "senderName")} + type="name" + placeholder="이름을 입력하세요" + inputLabel="이름" + /> + handleInputChange(e, "senderPhone")} + type="tel" + placeholder="휴대폰 번호를 입력하세요" + inputLabel="휴대폰 번호" + /> +
+ + [필수] 개인정보 수집 및 이용 동의 + { + e.stopPropagation(); + handleDetailClick("personalInfo"); + }} + css={consentDetail} > - [선택] 마케팅 활용 동의 - { - e.stopPropagation(); - handleDetailClick("marketing"); - }} - css={consentDetail} - > - 더보기 - - -
- {isModalOpen && ( - - {selectedConsent === "personalInfo" ? ( -
-

개인정보 수집 및 이용 동의

-

- [항목] -
- 이름, 휴대폰번호, 주소 -

-

- [목적] -
- 상품 택배배송을 위한 목적 -

-

- [보유 및 이용 기간] -
- 발송일로부터 1년 -

- -
- ) : ( -
-

- 마케팅 목적의 개인정보 수집 및 이용 동의 -

-

- [항목] -
- 이름, 휴대폰번호, 주소 -

-

- [목적] -
- 상품 안내 이벤트 알림서비스 -

-

- [보유 및 이용 기간] -
- 발송일로부터 1년 -

- -
- )} -
- )} -
-
- -
-
- + [선택] 마케팅 활용 동의 + { + e.stopPropagation(); + handleDetailClick("marketing"); + }} + css={consentDetail} + > + 더보기 + + +
+ {isModalOpen && ( + + {selectedConsent === "personalInfo" ? ( +
+

개인정보 수집 및 이용 동의

+

+ [항목] +
+ 이름, 휴대폰번호, 주소 +

+

+ [목적] +
+ 상품 택배배송을 위한 목적 +

+

+ [보유 및 이용 기간] +
+ 발송일로부터 1년 +

+ +
+ ) : ( +
+

+ 마케팅 목적의 개인정보 수집 및 이용 동의 +

+

+ [항목] +
+ 이름, 휴대폰번호, 주소 +

+

+ [목적] +
+ 상품 안내 이벤트 알림서비스 +

+

+ [보유 및 이용 기간] +
+ 발송일로부터 1년 +

+ +
+ )} +
+ )} + +
+ +
+ ); }; diff --git a/src/hooks/useOrderPostDataChange.ts b/src/hooks/useOrderPostDataChange.ts index 1d69e4a..28da48a 100644 --- a/src/hooks/useOrderPostDataChange.ts +++ b/src/hooks/useOrderPostDataChange.ts @@ -75,6 +75,21 @@ export const useOrderPostDataChange = () => { }); }; + const handleChangeOrderPrice = (price: number, index: number) => { + const recipientIndex = index !== undefined ? index : currentRecipientIndex; + setOrderPostDataState((prevState) => { + const updatedRecipientInfo = [...prevState.recipientInfo]; + updatedRecipientInfo[recipientIndex] = { + ...updatedRecipientInfo[recipientIndex], + orderPrice: price, + }; + return { + ...prevState, + recipientInfo: updatedRecipientInfo, + }; + }); + }; + const handleAddReceiver = () => { const newRecipient: RecipientInfo = { recipientName: "", @@ -85,6 +100,7 @@ export const useOrderPostDataChange = () => { selectedOption: "regular", deliveryDate: "", productInfo: [], + orderPrice: 0, }; setOrderPostDataState((prevState) => ({ @@ -125,6 +141,7 @@ export const useOrderPostDataChange = () => { handleRequiredCheckClick, handleOptinalAgreementClick, handleRecipientInputChange, + handleChangeOrderPrice, handleAddReceiver, orderNumberState, setOrderNumberState, diff --git a/src/pages/ExperienceHome/ExperienceHome.tsx b/src/pages/ExperienceHome/ExperienceHome.tsx index de30bc6..eb90623 100644 --- a/src/pages/ExperienceHome/ExperienceHome.tsx +++ b/src/pages/ExperienceHome/ExperienceHome.tsx @@ -9,6 +9,7 @@ import { Button } from "@components"; import { buttonSectionStyle } from "@pages/orderInfo/styles"; import { useAtom } from "jotai"; import { categoryAtom } from "@stores"; +import { CategoryType } from "@types"; const ExperienceHome = () => { const navigate = useNavigate(); @@ -19,7 +20,7 @@ const ExperienceHome = () => { const handleButtonClick = () => { const categoryName = location.pathname.split("/")[1]; localStorage.clear(); - setCategory(categoryName); + setCategory(categoryName as CategoryType); navigate(`/${categoryName}/order-info/sender`); }; diff --git a/src/pages/Home/Home.style.ts b/src/pages/Home/Home.style.ts new file mode 100644 index 0000000..dcd1351 --- /dev/null +++ b/src/pages/Home/Home.style.ts @@ -0,0 +1,63 @@ +import { css, Theme } from "@emotion/react"; +import { flexGenerator } from "@styles/generator"; + +export const homeLayout = css` + ${flexGenerator("column", "flex-start", "flex-start")} + padding: 0 2rem; + min-height: 100dvh; +`; + +export const homeHeader = css` + margin-top: 10dvh; + margin-bottom: 2rem; +`; + +export const homeTitle = (theme: Theme) => css` + color: ${theme.color.black}; + ${theme.font["head01-b-24"]}; + font-size: 3.2rem; +`; + +export const homeSubTitle = (theme: Theme) => css` + color: ${theme.color.lightgray3}; + ${theme.font["head02-b-20"]}; +`; + +export const menuContainer = css` + ${flexGenerator("column")} + width: 100%; + gap: 2rem; +`; + +export const menuButton = (theme: Theme) => css` + ${flexGenerator()} + width: 100%; + height: 20rem; + gap: 2rem; + border: 1px solid ${theme.color.lightgray1}; + padding: 1rem; + border-radius: 1rem; + + box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px; + + &:first-of-type { + background-color: ${theme.color.lightgreen}; + } + &:last-of-type { + background-color: ${theme.color.lightorange}; + } +`; + +export const menuTitle = (theme: Theme) => css` + color: ${theme.color.black}; + ${theme.font["head02-b-20"]}; + text-align: center; +`; + +export const menuImage = css` + height: 100%; + aspect-ratio: 1 / 1; + & img { + width: 100%; + } +`; diff --git a/src/pages/Home/Home.tsx b/src/pages/Home/Home.tsx new file mode 100644 index 0000000..96a549f --- /dev/null +++ b/src/pages/Home/Home.tsx @@ -0,0 +1,63 @@ +import { IcMainCharacter } from "@svg"; +import { + homeHeader, + homeLayout, + homeSubTitle, + homeTitle, + menuButton, + menuContainer, + menuImage, + menuTitle, +} from "./Home.style"; +import { useAtom } from "jotai"; +import { categoryAtom } from "@stores"; +import { useNavigate } from "react-router-dom"; +import { CategoryType } from "@types"; + +const Home = () => { + const navigate = useNavigate(); + + const [, setCategory] = useAtom(categoryAtom); + + const handleButtonClick = (category: CategoryType) => { + localStorage.clear(); + setCategory(category); + navigate(`/${category}/order-info/sender`); + }; + + return ( +
+
+

제주 체험 농장

+

필요한 메뉴를 선택해 주세요

+
+ +
+
handleButtonClick("experience")} + > +
+ 체험 홈 그림 +
+

+ 체험한 과일 +
+ 택배 보내기 +

+
+ +
handleButtonClick("product")}> +
+ +
+

+ 상품 구매
택배 접수 +

+
+
+
+ ); +}; + +export default Home; diff --git a/src/pages/ProductHome/ProductHome.tsx b/src/pages/ProductHome/ProductHome.tsx index ac408c2..357f2f4 100644 --- a/src/pages/ProductHome/ProductHome.tsx +++ b/src/pages/ProductHome/ProductHome.tsx @@ -5,6 +5,7 @@ import { Button } from "@components"; import { buttonSectionStyle } from "@pages/orderInfo/styles"; import { useAtom } from "jotai"; import { categoryAtom } from "@stores"; +import { CategoryType } from "@types"; const ProductHome = () => { const navigate = useNavigate(); @@ -15,7 +16,7 @@ const ProductHome = () => { const handleButtonClick = () => { const categoryName = location.pathname.split("/")[1]; localStorage.clear(); - setCategory(categoryName); + setCategory(categoryName as CategoryType); navigate(`/${categoryName}/order-info/sender`); }; return ( diff --git a/src/pages/experienceOrderInfo/components/ExperienceOrderInfo/ExperienceOrderInfo.tsx b/src/pages/experienceOrderInfo/components/ExperienceOrderInfo/ExperienceOrderInfo.tsx index 05d6b23..ec1ab02 100644 --- a/src/pages/experienceOrderInfo/components/ExperienceOrderInfo/ExperienceOrderInfo.tsx +++ b/src/pages/experienceOrderInfo/components/ExperienceOrderInfo/ExperienceOrderInfo.tsx @@ -2,6 +2,8 @@ import React from "react"; import { CheckInfo, Complete, + Header, + ProgressBar, Receiver1, Receiver2, SelectProduct, @@ -25,21 +27,33 @@ const ExperienceOrderInfo = ({ return ( +
+ nextClickHandler(steps[1])} /> +
+ nextClickHandler(steps[2])} /> +
+ nextClickHandler(steps[3])} /> +
+ nextClickHandler(steps[4])} /> +
+ nextClickHandler(steps[5])} /> +
+ diff --git a/src/pages/index.ts b/src/pages/index.ts index 83b72c2..2c247da 100644 --- a/src/pages/index.ts +++ b/src/pages/index.ts @@ -1,5 +1,6 @@ import ProductHome from "./ProductHome/ProductHome"; import ExperienceHome from "./ExperienceHome/ExperienceHome"; import Admin from "./Admin/page/AdminPage/AdminPage"; +import Home from "./Home/Home"; -export { ProductHome, ExperienceHome, Admin }; +export { ProductHome, ExperienceHome, Admin, Home }; diff --git a/src/pages/orderInfo/components/OrderInfo/OrderInfo.tsx b/src/pages/orderInfo/components/OrderInfo/OrderInfo.tsx index ec46499..9220619 100644 --- a/src/pages/orderInfo/components/OrderInfo/OrderInfo.tsx +++ b/src/pages/orderInfo/components/OrderInfo/OrderInfo.tsx @@ -1,6 +1,8 @@ import { CheckInfo, Complete, + Header, + ProgressBar, Receiver1, Receiver2, SelectDeliveryDate, @@ -26,24 +28,38 @@ const OrderInfo = ({ return ( +
+ nextClickHandler(steps[1])} /> +
+ nextClickHandler(steps[2])} /> +
+ nextClickHandler(steps[3])} /> +
+ nextClickHandler(steps[4])} /> +
+ nextClickHandler(steps[5])} /> +
+ nextClickHandler(steps[6])} /> +
+ diff --git a/src/pages/orderInfo/styles/common.style.ts b/src/pages/orderInfo/styles/common.style.ts index 920b12f..44016b5 100644 --- a/src/pages/orderInfo/styles/common.style.ts +++ b/src/pages/orderInfo/styles/common.style.ts @@ -1,5 +1,6 @@ import { Theme, css } from "@emotion/react"; import { flexGenerator } from "@styles/generator"; +import { CategoryType } from "@types"; export const layoutStyle = css` ${flexGenerator("column", "flex-start")}; @@ -18,9 +19,12 @@ export const textStyle = (theme: Theme) => css` color: ${theme.color.black}; `; -export const orangeTextStyle = (theme: Theme) => css` - color: ${theme.color.orange}; -`; +export const coloredTextStyle = (category: CategoryType) => (theme: Theme) => + css` + color: ${category === "experience" + ? theme.color.green + : theme.color.orange}; + `; export const mainSectionStyle = css` ${flexGenerator("column", "start", "start")}; diff --git a/src/routes/homeRoutes.tsx b/src/routes/homeRoutes.tsx index 2f41f47..ff41179 100644 --- a/src/routes/homeRoutes.tsx +++ b/src/routes/homeRoutes.tsx @@ -1,12 +1,11 @@ import { routePath } from "@constants"; -import { ExperienceHome, ProductHome } from "@pages/index"; +import { ExperienceHome, Home, ProductHome } from "@pages/index"; import { RouteType } from "@types"; -import { Navigate } from "react-router-dom"; const homeRoutes: RouteType[] = [ { path: routePath.HOME, - element: , + element: , }, { path: routePath.PRODUCT_HOME, diff --git a/src/stores/category.ts b/src/stores/category.ts index 23a1fe9..13a088c 100644 --- a/src/stores/category.ts +++ b/src/stores/category.ts @@ -1,3 +1,4 @@ +import { CategoryType } from "@types"; import { atomWithStorage } from "jotai/utils"; -export const categoryAtom = atomWithStorage("categoryAtom", ""); +export const categoryAtom = atomWithStorage("categoryAtom", ""); diff --git a/src/stores/orderPostData.ts b/src/stores/orderPostData.ts index 13c5a4c..5fd847f 100644 --- a/src/stores/orderPostData.ts +++ b/src/stores/orderPostData.ts @@ -4,7 +4,9 @@ export interface ProductInfo { productId: number; productName: string; productCount: number; + productPrice: number; } + export interface RecipientInfo { recipientName: string; recipientPhone: string; @@ -14,6 +16,7 @@ export interface RecipientInfo { productInfo: ProductInfo[]; selectedOption: "regular" | "scheduled"; deliveryDate: string; + orderPrice: number; } export interface OrderPostDataType { diff --git a/src/styles/theme.ts b/src/styles/theme.ts index 3b4d223..553eb1d 100644 --- a/src/styles/theme.ts +++ b/src/styles/theme.ts @@ -21,6 +21,7 @@ const theme = { midgray2: "#F1F1F1", midgray3: "#6B6F77", darkgray: "#3E3F45", + background0: "#F9F9F9", background: "#F6F6F6", background2: "#F5F5F5", diff --git a/src/types/commonType.ts b/src/types/commonType.ts index 03d7bbe..06643e9 100644 --- a/src/types/commonType.ts +++ b/src/types/commonType.ts @@ -39,3 +39,5 @@ export interface CodeResponseType { token: string; }; } + +export type CategoryType = "" | "product" | "experience";