🎨 styles: shipping method

:%s
This commit is contained in:
lytrankieio123
2021-10-20 17:46:03 +07:00
parent f959ac8ea2
commit aba0e43b93
13 changed files with 280 additions and 44 deletions

View File

@@ -365,8 +365,17 @@ export type Address = Node & {
customFields?: Maybe<Scalars['JSON']>
}
export type SetShippingMethodMutationVariables = Exact<{
id: Scalars['ID'];
}>;
export type SetShippingMethodMutation = {
setOrderShippingMethod:
| TestOrderFragmentFragment
| Pick<OrderModificationError, 'errorCode' | 'message'>
| Pick<IneligibleShippingMethodError, 'errorCode' | 'message'>
| Pick<NoActiveOrderError, 'errorCode' | 'message'>;
};
export type Asset = Node & {
__typename?: 'Asset'

View File

@@ -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
}
`

View File

@@ -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'

View File

@@ -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<CommonError | null>(null)
const { mutate } = useGetActiveOrder()
const setOrderShippingMethod = (id: string,
fCallBack: (isSuccess: boolean, message?: string) => void
) => {
setError(null)
setLoading(true)
rawFetcher<SetShippingMethodMutation>({
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

View File

@@ -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<CheckoutStep[]>([])
const { order } = useGetActiveOrder()
@@ -101,7 +102,7 @@ const CheckoutInfo = ({ onViewCart }: CheckoutInfoProps) => {
{
id: CheckoutStep.ShippingInfo,
title: 'Shipping Information',
form: <ShippingInfoForm onConfirm={onConfirm} id={CheckoutStep.ShippingInfo} activeStep={activeStep} />,
form: <ShippingInfoForm onConfirm={onConfirm} id={CheckoutStep.ShippingInfo} activeStep={activeStep} currency={currency} />,
},
{
id: CheckoutStep.PaymentInfo,

View File

@@ -18,7 +18,7 @@ const ChekoutNotePolicy = memo(() => {
{
<Link href={ROUTE.PRIVACY_POLICY}>
<a>
<strong>privacy policy </strong>
<strong>privacy policy</strong>
</a>
</Link>
}

View File

@@ -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);
}
}
}

View File

@@ -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<CustomInputCommon>(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}
/>
</div>
<div className={s.method}>
<div className={s.left}>
<div className={s.icon}>
<Shipping />
</div>
<div className={s.name}>
Standard Delivery Method
</div>
</div>
<div className={s.right}>
<div className={s.price}>
Free
</div>
</div>
</div>
<ShippingMethod currency={currency}/>
<div className={s.bottom}>
<ChekoutNotePolicy />
<ButtonCommon HTMLType='submit' loading={loading} size="large">

View File

@@ -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;
}
}
}

View File

@@ -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<ShippingMethodQuote>(MOCKUP_DATA[0])
const { showMessageError } = useMessage()
const [isShowOptions, setIsShowOptions] = useState<boolean>(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 (
<div className={s.shippingMethod}>
<div className={s.method} onClick={onCollapseOptions}>
<div className={s.left}>
<div className={s.icon}>
<Shipping />
</div>
<div className={s.name}>
{selectedValue.name}
</div>
</div>
<div className={s.right}>
<div className={s.price}>
{selectedValue.price ? `${selectedValue.price / 100} ${currency}` : "Free"}
</div>
</div>
</div>
<div className={classNames(s.options, { [s.show]: isShowOptions })}>
<ul>
{MOCKUP_DATA.map(item => <ShippingMethodItem
key={item.id}
id={item.id}
name={item.name}
price={item.price}
currency={currency}
onSelect={onChange}
/>)}
</ul>
</div>
</div>
)
})
ShippingMethod.displayName = 'ShippingMethod'
export default ShippingMethod

View File

@@ -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);
}
}

View File

@@ -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 (
<li className={s.shippingMethodItem} key={id} onClick={handleSelect}>
<div className={s.name}>
{name}
</div>
<div className={s.price}>
{price ? `${price / 100} ${currency}` : "Free"}
</div>
</li>
)
})
ShippingMethodItem.displayName = 'ShippingMethodItem'
export default ShippingMethodItem

View File

@@ -24,7 +24,7 @@ const CheckoutPage = ({ }: CheckoutPageProps) => {
return (
<div className={s.warrper}>
<MessageCommon messages={messages} onRemove={removeMessage} />
<div className={s.left}><CheckoutInfo onViewCart={onViewCart} /></div>
<div className={s.left}><CheckoutInfo onViewCart={onViewCart} currency={order?.currency.code}/></div>
<div className={s.right}><CheckoutBill data={order} /></div>
<div className={classNames({ [s.mobile]: true, [s.isShow]: isShow })}>
<div className={s.modal}>