From aba0e43b931683e4ad4a6f584099780a3bcb373d Mon Sep 17 00:00:00 2001 From: lytrankieio123 Date: Wed, 20 Oct 2021 17:46:03 +0700 Subject: [PATCH] :art: styles: shipping method :%s --- framework/vendure/schema.d.ts | 11 ++- .../set-order-shipping-method-mutation.ts | 35 +++++++ src/components/hooks/order/index.ts | 2 +- .../hooks/order/useSetOrderShippingMethod.tsx | 41 ++++++++ .../checkout/CheckoutInfo/CheckoutInfo.tsx | 5 +- .../ChekoutNotePolicy/ChekoutNotePolicy.tsx | 2 +- .../ShippingInfoForm.module.scss | 19 +--- .../ShippingInfoForm/ShippingInfoForm.tsx | 26 ++--- .../ShippingMethod/ShippingMethod.module.scss | 39 ++++++++ .../ShippingMethod/ShippingMethod.tsx | 94 +++++++++++++++++++ .../ShippingMethodItem.module.scss | 19 ++++ .../ShippingMethodItem/ShippingMethodItem.tsx | 29 ++++++ .../checkout/CheckoutPage/CheckoutPage.tsx | 2 +- 13 files changed, 280 insertions(+), 44 deletions(-) create mode 100644 framework/vendure/utils/mutations/set-order-shipping-method-mutation.ts create mode 100644 src/components/hooks/order/useSetOrderShippingMethod.tsx create mode 100644 src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethod.module.scss create mode 100644 src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethod.tsx create mode 100644 src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethodItem/ShippingMethodItem.module.scss create mode 100644 src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethodItem/ShippingMethodItem.tsx diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index e2a6ab600..6a2778597 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -365,8 +365,17 @@ export type Address = Node & { customFields?: Maybe } +export type SetShippingMethodMutationVariables = Exact<{ + id: Scalars['ID']; +}>; - +export type SetShippingMethodMutation = { + setOrderShippingMethod: + | TestOrderFragmentFragment + | Pick + | Pick + | Pick; +}; export type Asset = Node & { __typename?: 'Asset' diff --git a/framework/vendure/utils/mutations/set-order-shipping-method-mutation.ts b/framework/vendure/utils/mutations/set-order-shipping-method-mutation.ts new file mode 100644 index 000000000..e43331908 --- /dev/null +++ b/framework/vendure/utils/mutations/set-order-shipping-method-mutation.ts @@ -0,0 +1,35 @@ +export const setShippingMethodMutation = /* GraphQL */ ` +mutation SetShippingMethod($id: ID!) { + setOrderShippingMethod(shippingMethodId: $id) { + ...Cart + ...ErrorResult + __typename + } +} + +fragment Cart on Order { + id + code + state + active + shippingLines { + priceWithTax + shippingMethod { + id + code + name + description + __typename + } + __typename + } + + __typename +} + +fragment ErrorResult on ErrorResult { + errorCode + message + __typename +} +` diff --git a/src/components/hooks/order/index.ts b/src/components/hooks/order/index.ts index 7ec92f670..b7d785c92 100644 --- a/src/components/hooks/order/index.ts +++ b/src/components/hooks/order/index.ts @@ -2,4 +2,4 @@ export { default as useSetCustomerForOrder } from './useSetCustomerForOrder' export { default as useSetOrderShippingAddress } from './useSetOrderShippingAddress' export { default as useApplyCouponCode } from './useApplyCouponCode' export { default as useAvailableCountries } from './useAvailableCountries' - +export { default as useSetOrderShippingMethod } from './useSetOrderShippingMethod' diff --git a/src/components/hooks/order/useSetOrderShippingMethod.tsx b/src/components/hooks/order/useSetOrderShippingMethod.tsx new file mode 100644 index 000000000..bed63f72b --- /dev/null +++ b/src/components/hooks/order/useSetOrderShippingMethod.tsx @@ -0,0 +1,41 @@ +import { SetShippingMethodMutation } from '@framework/schema' +import { setShippingMethodMutation } from '@framework/utils/mutations/set-order-shipping-method-mutation' +import { useState } from 'react' +import { CommonError } from 'src/domains/interfaces/CommonError' +import rawFetcher from 'src/utils/rawFetcher' +import { useGetActiveOrder } from '../cart' + + +const useSetOrderShippingMethod = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const { mutate } = useGetActiveOrder() + + const setOrderShippingMethod = (id: string, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + rawFetcher({ + query: setShippingMethodMutation, + variables: { id }, + }) + .then(({ data }) => { + if (data.setOrderShippingMethod.__typename === 'Order') { + fCallBack(true) + mutate() + } else { + fCallBack(false, data.setOrderShippingMethod.message) + } + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, setOrderShippingMethod, error } +} + +export default useSetOrderShippingMethod diff --git a/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.tsx b/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.tsx index 2a0046caf..68a8e71b5 100644 --- a/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.tsx +++ b/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.tsx @@ -9,6 +9,7 @@ import PaymentInfoForm from './components/PaymentInfoForm/PaymentInfoForm' import ShippingInfoForm from './components/ShippingInfoForm/ShippingInfoForm' interface CheckoutInfoProps { onViewCart: () => void + currency?: string } enum CheckoutStep { @@ -17,7 +18,7 @@ enum CheckoutStep { PaymentInfo = 3, } -const CheckoutInfo = ({ onViewCart }: CheckoutInfoProps) => { +const CheckoutInfo = ({ onViewCart, currency = "" }: CheckoutInfoProps) => { const [activeStep, setActiveStep] = useState(1) const [doneSteps, setDoneSteps] = useState([]) const { order } = useGetActiveOrder() @@ -101,7 +102,7 @@ const CheckoutInfo = ({ onViewCart }: CheckoutInfoProps) => { { id: CheckoutStep.ShippingInfo, title: 'Shipping Information', - form: , + form: , }, { id: CheckoutStep.PaymentInfo, diff --git a/src/components/modules/checkout/CheckoutInfo/components/ChekoutNotePolicy/ChekoutNotePolicy.tsx b/src/components/modules/checkout/CheckoutInfo/components/ChekoutNotePolicy/ChekoutNotePolicy.tsx index 9c988ae03..c5cf41955 100644 --- a/src/components/modules/checkout/CheckoutInfo/components/ChekoutNotePolicy/ChekoutNotePolicy.tsx +++ b/src/components/modules/checkout/CheckoutInfo/components/ChekoutNotePolicy/ChekoutNotePolicy.tsx @@ -18,7 +18,7 @@ const ChekoutNotePolicy = memo(() => { { - privacy policy + privacy policy } diff --git a/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.module.scss b/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.module.scss index aa177fc88..5eaefab13 100644 --- a/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.module.scss +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.module.scss @@ -24,22 +24,5 @@ width: 50%; } } - .method{ - width: 100%; - height: 5.6rem; - padding: 1.6rem; - border-radius: 0.8rem; - @apply flex justify-between items-center border border-solid border-line bg-gray; - .left{ - @apply flex; - .name{ - margin-left: 1.6rem; - color: var(--text-active); - } - } - .price{ - font-weight: bold; - color: var(--text-active); - } - } + } \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.tsx b/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.tsx index 459b69324..fb62c0f24 100644 --- a/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.tsx +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.tsx @@ -3,17 +3,19 @@ import React, { useEffect, useRef } from 'react' import { ButtonCommon, InputFiledInForm, SelectFieldInForm } from 'src/components/common' import { useMessage } from 'src/components/contexts' import { useAvailableCountries, useSetOrderShippingAddress } from 'src/components/hooks/order' -import { Shipping } from 'src/components/icons' import { LANGUAGE } from 'src/utils/language.utils' import { CustomInputCommon } from 'src/utils/type.utils' import * as Yup from 'yup' import ChekoutNotePolicy from '../ChekoutNotePolicy/ChekoutNotePolicy' +import ShippingMethod from '../ShippingMethod/ShippingMethod' import s from './ShippingInfoForm.module.scss' interface ShippingInfoFormProps { id: number activeStep: number onConfirm: (id: number) => void + currency: string + } @@ -31,6 +33,7 @@ const displayingErrorMessagesSchema = Yup.object().shape({ const DEFAULT_COUNTRY_CODE = 'MY' const DEFAULT_PROVINCE = 'Sabah' +// TODO: update data const provinceOptions = [ { name: 'Hồ Chí Minh', @@ -46,7 +49,7 @@ const provinceOptions = [ }, ] -const ShippingInfoForm = ({ onConfirm, id, activeStep }: ShippingInfoFormProps) => { +const ShippingInfoForm = ({ onConfirm, id, activeStep , currency}: ShippingInfoFormProps) => { const addressRef = useRef(null) const { setOrderShippingAddress, loading } = useSetOrderShippingAddress() const { showMessageError } = useMessage() @@ -59,10 +62,7 @@ const ShippingInfoForm = ({ onConfirm, id, activeStep }: ShippingInfoFormProps) }, [activeStep]) const handleSubmit = (values: any) => { - console.log("values: ", values) setOrderShippingAddress(values, onSubmitCalBack) - - // onConfirm && onConfirm(id) } const onSubmitCalBack = (isSuccess: boolean, msg?: string) => { @@ -176,21 +176,7 @@ const ShippingInfoForm = ({ onConfirm, id, activeStep }: ShippingInfoFormProps) onEnter={isValid ? submitForm : undefined} /> -
-
-
- -
-
- Standard Delivery Method -
-
-
-
- Free -
-
-
+
diff --git a/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethod.module.scss b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethod.module.scss new file mode 100644 index 000000000..d078368e4 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethod.module.scss @@ -0,0 +1,39 @@ +.shippingMethod { + @apply relative; + .method { + @apply w-full flex justify-between items-center border border-solid border-line bg-gray cursor-pointer; + height: 5.6rem; + padding: 1.6rem; + border-radius: 0.8rem; + .left { + @apply flex; + .name { + margin-left: 1.6rem; + color: var(--text-active); + } + } + .price { + font-weight: bold; + color: var(--text-active); + } + } + + .options { + @apply absolute transition-all duration-200 overflow-hidden; + transform: translateX(-100%); + opacity: 0; + margin-top: 0.8rem; + top: 6rem; + left: 0; + width: 100%; + background: var(--white); + border: 1px solid var(--border-line); + border-radius: 0.8rem; + &.show { + z-index: 10; + opacity: 1; + transform: none; + position: initial; + } + } +} diff --git a/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethod.tsx b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethod.tsx new file mode 100644 index 000000000..c6b1ca845 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethod.tsx @@ -0,0 +1,94 @@ +import { ShippingMethodQuote } from '@framework/schema' +import classNames from 'classnames' +import React, { memo, useState } from 'react' +import { useMessage } from 'src/components/contexts' +import { useSetOrderShippingMethod } from 'src/components/hooks/order' +import { Shipping } from 'src/components/icons' +import s from './ShippingMethod.module.scss' +import ShippingMethodItem from './ShippingMethodItem/ShippingMethodItem' + +const MOCKUP_DATA = [ + { + "id": "1", + "name": "Standard Shipping", + "description": "", + "price": 0, + "priceWithTax": 0, + "code": "standard-shipping" + }, + { + "id": "2", + "name": "Express Shipping", + "description": "", + "price": 1000, + "priceWithTax": 1000, + "code": "express-shipping" + } +] +interface Props { + currency: string +} + +const ShippingMethod = memo(({ currency }: Props) => { + const { setOrderShippingMethod } = useSetOrderShippingMethod() + const [selectedValue, setSelectedValue] = useState(MOCKUP_DATA[0]) + const { showMessageError } = useMessage() + const [isShowOptions, setIsShowOptions] = useState(false) + + const onChange = (id: string) => { + const newValue = MOCKUP_DATA.find(item => item.id === id) + if (newValue) { + setSelectedValue(newValue) + if (newValue?.id) { + setOrderShippingMethod(newValue?.id, onSubmitCalBack) + } + } + setIsShowOptions(false) + } + + const onSubmitCalBack = (isSuccess: boolean, msg?: string) => { + if (!isSuccess) { + showMessageError(msg) + } + } + + const onCollapseOptions = () => { + setIsShowOptions(!isShowOptions) + } + + + return ( +
+
+
+
+ +
+
+ {selectedValue.name} +
+
+
+
+ {selectedValue.price ? `${selectedValue.price / 100} ${currency}` : "Free"} +
+
+
+
+
    + {MOCKUP_DATA.map(item => )} +
+
+
+ ) +}) + +ShippingMethod.displayName = 'ShippingMethod' +export default ShippingMethod diff --git a/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethodItem/ShippingMethodItem.module.scss b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethodItem/ShippingMethodItem.module.scss new file mode 100644 index 000000000..4aa06484c --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethodItem/ShippingMethodItem.module.scss @@ -0,0 +1,19 @@ +.shippingMethodItem { + @apply flex justify-between items-center cursor-pointer transition-all duration-200; + width: 100%; + padding: 1.6rem; + &:hover { + @apply bg-gray; + } + .left { + @apply flex; + .name { + margin-left: 1.6rem; + color: var(--text-active); + } + } + .price { + font-weight: bold; + color: var(--text-active); + } +} diff --git a/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethodItem/ShippingMethodItem.tsx b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethodItem/ShippingMethodItem.tsx new file mode 100644 index 000000000..43685e3db --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethodItem/ShippingMethodItem.tsx @@ -0,0 +1,29 @@ +import React, { memo } from 'react' +import s from './ShippingMethodItem.module.scss' + +interface Props { + id: string + name: string + price: number + currency: string + onSelect: (id: string) => void +} + +const ShippingMethodItem = memo(({ id, name, price, currency, onSelect }: Props) => { + const handleSelect = () => { + onSelect(id) + } + return ( +
  • +
    + {name} +
    +
    + {price ? `${price / 100} ${currency}` : "Free"} +
    +
  • + ) +}) + +ShippingMethodItem.displayName = 'ShippingMethodItem' +export default ShippingMethodItem diff --git a/src/components/modules/checkout/CheckoutPage/CheckoutPage.tsx b/src/components/modules/checkout/CheckoutPage/CheckoutPage.tsx index fcec64922..d467ed2c4 100644 --- a/src/components/modules/checkout/CheckoutPage/CheckoutPage.tsx +++ b/src/components/modules/checkout/CheckoutPage/CheckoutPage.tsx @@ -24,7 +24,7 @@ const CheckoutPage = ({ }: CheckoutPageProps) => { return (
    -
    +