diff --git a/framework/commerce/types/cart.ts b/framework/commerce/types/cart.ts index b3d3b1e59..9192436d0 100644 --- a/framework/commerce/types/cart.ts +++ b/framework/commerce/types/cart.ts @@ -1,4 +1,5 @@ -import type { Discount, Measurement, Image } from './common' +import { ShippingMethod } from '@framework/schema'; +import type { Discount, Image, Measurement } from './common'; export type SelectedOption = { // The option's id. @@ -83,6 +84,50 @@ export type Cart = { discounts?: Discount[] } +export type CartCheckout = { + id: string + // ID of the customer to which the cart belongs. + customerId?: string + customer?: { + firstName: string, + lastName: string, + emailAddress: string, + } + shippingAddress?: { + streetLine1: string, + city: string, + province: string, + postalCode: string, + countryCode: string, + phoneNumber: string, + } + // The email assigned to this cart + email?: string + // The date and time when the cart was created. + createdAt: string + // The currency used for this cart + currency: { code: string } + // Specifies if taxes are included in the line items. + taxesIncluded: boolean + lineItems: LineItem[] + // The sum of all the prices of all the items in the cart. + // Duties, taxes, shipping and discounts excluded. + lineItemsSubtotalPrice: number + // Price of the cart before duties, shipping and taxes. + subtotalPrice: number + // The sum of all the prices of all the items in the cart. + // Duties, taxes and discounts included. + totalPrice: number + totalQuantity: number + // Discounts that have been applied on the cart. + discounts?: Discount[] + totalDiscount: number + shippingLine?: { + priceWithTax: number + shippingMethod: ShippingMethod + } +} + /** * Base cart item body used for cart mutations */ diff --git a/framework/commerce/types/common.ts b/framework/commerce/types/common.ts index 06908c464..d3eca1e68 100644 --- a/framework/commerce/types/common.ts +++ b/framework/commerce/types/common.ts @@ -1,6 +1,7 @@ export type Discount = { // The value of the discount, can be an amount or percentage value: number + description?: string } export type Measurement = { diff --git a/framework/vendure/api/operations/get-product.ts b/framework/vendure/api/operations/get-product.ts index 66f798ee1..c16041468 100644 --- a/framework/vendure/api/operations/get-product.ts +++ b/framework/vendure/api/operations/get-product.ts @@ -2,7 +2,7 @@ import { Product } from '@commerce/types/product' import { OperationContext } from '@commerce/api/operations' import { Provider, VendureConfig } from '../' import { GetProductQuery } from '../../schema' -import { getProductQuery, getProductDetailQuery } from '../../utils/queries/get-product-query' +import { getProductQuery } from '../../utils/queries/get-product-query' export default function getProductOperation({ commerce, diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index bde35416c..8756622fd 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -332,17 +332,9 @@ export type SetCustomerForOrderMutation = { __typename?: 'Mutation' } & { >) } -export type SetCustomerForOrderMutation = { __typename?: 'Mutation' } & { - setCustomerForOrder: - | ({ __typename: 'ActiveOrderCustomerFragment' } & Pick) - | ({ __typename: 'AlreadyLoggedInError' } & Pick< - AlreadyLoggedInError, - 'errorCode' | 'message' - >) - | ({ __typename: 'EmailAddressConflictError' } & Pick< - EmailAddressConflictError, - 'errorCode' | 'message' - >) +export type SetOrderShippingAddressMutation = { __typename?: 'Mutation' } & { + setOrderShippingAddress: + | ({ __typename: 'Order' } & Pick) | ({ __typename: 'NoActiveOrderError' } & Pick< NoActiveOrderError, 'errorCode' | 'message' @@ -373,8 +365,24 @@ export type Address = Node & { customFields?: Maybe } +export type SetShippingMethodMutationVariables = Exact<{ + id: Scalars['ID']; +}>; + +export type SetShippingMethodMutation = { + setOrderShippingMethod: + | TestOrderFragmentFragment + | Pick + | Pick + | Pick; +}; +export type GetEligibleMethodsQuery = { + eligibleShippingMethods: Array< + Pick + >; +}; export type Asset = Node & { __typename?: 'Asset' @@ -3126,7 +3134,16 @@ export type CartFragment = { __typename?: 'Order' } & Pick< | 'totalWithTax' | 'currencyCode' > & { - customer?: Maybe<{ __typename?: 'Customer' } & Pick> + shippingAddress?: Maybe<{ __typename?: 'OrderAddress' } & Pick> + discounts: Array< + { __typename?: 'Discount' } & Pick + > + customer?: Maybe<{ __typename?: 'Customer' } & Pick> + shippingLines: Array< + Pick & { + shippingMethod: Pick; + } + > lines: Array< { __typename?: 'OrderLine' } & Pick< OrderLine, @@ -3229,6 +3246,36 @@ export type AdjustOrderLineMutation = { __typename?: 'Mutation' } & { >) } + +export type ApplyCouponCodeMutationVariables = Exact<{ + couponCode: Scalars['String']; +}>; + +export type ApplyCouponCodeMutation = { + applyCouponCode: + | TestOrderFragmentFragment + | Pick + | Pick + | Pick; +}; + +export type ApplyCouponCodeMutation = { __typename?: 'Mutation' } & { + applyCouponCode: + | ({ __typename: 'Order' } & CartFragment) + | ({ __typename: 'CouponCodeExpiredError' } & Pick< + CouponCodeExpiredError, + 'errorCode' | 'message' + >) + | ({ __typename: 'CouponCodeInvalidError' } & Pick< + CouponCodeInvalidError, + 'errorCode' | 'message' + >) + | ({ __typename: 'CouponCodeLimitError' } & Pick< + CouponCodeLimitError, + 'errorCode' | 'message' + >) +} + export type LoginMutationVariables = Exact<{ username: Scalars['String'] password: Scalars['String'] @@ -3384,6 +3431,25 @@ type Favorite = Node & { customer: Customer! } +export type GetAvailableCountriesQueryVariables = Exact<{ [key: string]: never; }>; + + +// export type GetAvailableCountriesQuery = { countries: ( +// { __typename?: 'CountryList' } +// & { items: Array<( +// { __typename?: 'Country' } +// & Pick +// )> } +// ) }; + +export type GetAvailableCountriesQuery = { + availableCountries: + { __typename?: 'CountryList' } + & Array<( + { __typename?: 'Country' } + & Pick + )> +}; type FavouriteOption = Customer & { diff --git a/framework/vendure/utils/mutations/apply-coupon-code-mutation.ts b/framework/vendure/utils/mutations/apply-coupon-code-mutation.ts new file mode 100644 index 000000000..c5b1a9a90 --- /dev/null +++ b/framework/vendure/utils/mutations/apply-coupon-code-mutation.ts @@ -0,0 +1,21 @@ +export const applyCouponCodeMutation = /* GraphQL */ ` +mutation applyCouponCode($couponCode: String!) { + applyCouponCode(couponCode: $couponCode) { + __typename + ... on Order { + id + createdAt + updatedAt + discounts { + type + amount + amountWithTax + } + } + ... on ErrorResult { + errorCode + message + } + } +} +` diff --git a/framework/vendure/utils/mutations/set-order-shipping-address-mutation.ts b/framework/vendure/utils/mutations/set-order-shipping-address-mutation.ts new file mode 100644 index 000000000..ee36fb68d --- /dev/null +++ b/framework/vendure/utils/mutations/set-order-shipping-address-mutation.ts @@ -0,0 +1,25 @@ +export const setOrderShippingAddressMutation = /* GraphQL */ ` +mutation setOrderShippingAddress($input: CreateAddressInput!) { + setOrderShippingAddress(input: $input) { + __typename + ... on Order { + id + createdAt + updatedAt + code + shippingAddress { + streetLine1 + city + province + postalCode + countryCode + phoneNumber + } + } + ... on ErrorResult { + errorCode + message + } + } +} +` 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/framework/vendure/utils/normalize.ts b/framework/vendure/utils/normalize.ts index c095ec030..b9c55680e 100644 --- a/framework/vendure/utils/normalize.ts +++ b/framework/vendure/utils/normalize.ts @@ -1,6 +1,6 @@ -import { Cart } from '@commerce/types/cart' -import { ProductCard, Product } from '@commerce/types/product' -import { CartFragment, SearchResultFragment,Favorite, BlogList } from '../schema' +import { Cart, CartCheckout } from '@commerce/types/cart' +import { Product, ProductCard } from '@commerce/types/product' +import { CartFragment, Favorite, SearchResultFragment, ShippingMethod, BlogList } from '../schema' export function normalizeSearchResult(item: SearchResultFragment): ProductCard { return { @@ -11,10 +11,10 @@ export function normalizeSearchResult(item: SearchResultFragment): ProductCard { price: (item.priceWithTax as any).min / 100, currencyCode: item.currencyCode, productVariantId: item.productVariantId, - productVariantName:item.productVariantName, + productVariantName: item.productVariantName, facetValueIds: item.facetValueIds, collectionIds: item.collectionIds, - + // TODO: // oldPrice: item.price // discount @@ -70,6 +70,63 @@ export function normalizeCart(order: CartFragment): Cart { } } +export function normalizeCartForCheckout(order: CartFragment): CartCheckout { + return { + id: order.id.toString(), + createdAt: order.createdAt, + taxesIncluded: true, + totalQuantity: order.totalQuantity, + lineItemsSubtotalPrice: order.subTotalWithTax / 100, + currency: { code: order.currencyCode }, + subtotalPrice: order.subTotalWithTax / 100, + totalPrice: order.totalWithTax / 100, + customerId: order.customer?.id, + customer: { + firstName: order.customer?.firstName || '', + lastName: order.customer?.lastName || '', + emailAddress: order.customer?.emailAddress || '', + }, + shippingAddress: { + streetLine1: order.shippingAddress?.streetLine1 || '', + city: order.shippingAddress?.city || '', + province: order.shippingAddress?.province || '', + postalCode: order.shippingAddress?.postalCode || '', + countryCode: order.shippingAddress?.countryCode || '', + phoneNumber: order.shippingAddress?.phoneNumber || '', + }, + shippingLine: order.shippingLines[0] ? { + priceWithTax: order.shippingLines[0]?.priceWithTax / 100, + shippingMethod: order.shippingLines[0]?.shippingMethod as ShippingMethod + }: undefined, + totalDiscount: order.discounts?.reduce((total, item) => total + item.amountWithTax, 0) / 100 || 0, + discounts: order.discounts.map(item => { + return { value: item.amountWithTax, description: item.description } + }), + lineItems: order.lines?.map((l) => ({ + id: l.id, + name: l.productVariant.name, + quantity: l.quantity, + slug: l.productVariant.product.slug, + variantId: l.productVariant.id, + productId: l.productVariant.productId, + images: [{ url: l.featuredAsset?.preview + '?preset=thumb' || '' }], + discounts: l.discounts.map((d) => ({ value: d.amount / 100 })), + path: '', + variant: { + id: l.productVariant.id, + name: l.productVariant.name, + sku: l.productVariant.sku, + price: l.discountedUnitPriceWithTax / 100, + listPrice: l.unitPriceWithTax / 100, + image: { + url: l.featuredAsset?.preview + '?preset=thumb' || '', + }, + requiresShipping: true, + }, + })), + } +} + export function normalizeProductCard(product: Product): ProductCard { return { id: product.id, @@ -79,7 +136,7 @@ export function normalizeProductCard(product: Product): ProductCard { price: product.price, currencyCode: product.currencyCode, productVariantId: product.variants?.[0].id.toString(), - productVariantName:product.variants?.[0].name, + productVariantName: product.variants?.[0].name, facetValueIds: product.facetValueIds, collectionIds: product.collectionIds, } diff --git a/framework/vendure/utils/queries/active-order-for-checkout-query.ts b/framework/vendure/utils/queries/active-order-for-checkout-query.ts new file mode 100644 index 000000000..7acedc492 --- /dev/null +++ b/framework/vendure/utils/queries/active-order-for-checkout-query.ts @@ -0,0 +1,116 @@ +export const getActiveOrderForCheckoutQuery = /* GraphQL */ ` +query getActiveOrderForCheckout { + activeOrder { + ...Cart + shippingAddress { + ...OrderAddress + __typename + } + __typename + } +} + +fragment Cart on Order { + id + code + state + active + customer { + id + firstName + lastName + emailAddress + } + lines { + id + featuredAsset { + ...Asset + __typename + } + unitPrice + unitPriceWithTax + quantity + linePriceWithTax + discountedLinePriceWithTax + unitPriceWithTax + discountedUnitPriceWithTax + productVariant { + id + name + price + priceWithTax + stockLevel + productId + product { + slug + } + __typename + } + discounts { + amount + amountWithTax + description + adjustmentSource + type + __typename + } + __typename + } + totalQuantity + subTotal + subTotalWithTax + total + totalWithTax + shipping + shippingWithTax + currencyCode + shippingLines { + priceWithTax + shippingMethod { + id + code + name + description + __typename + } + __typename + } + discounts { + amount + amountWithTax + description + adjustmentSource + type + __typename + } + __typename +} + +fragment Asset on Asset { + id + width + height + name + preview + focalPoint { + x + y + __typename + } + __typename +} + +fragment OrderAddress on OrderAddress { + fullName + company + streetLine1 + streetLine2 + city + province + postalCode + country + phoneNumber + __typename +} +` + diff --git a/framework/vendure/utils/queries/available-countries-query.ts b/framework/vendure/utils/queries/available-countries-query.ts new file mode 100644 index 000000000..f1da8c408 --- /dev/null +++ b/framework/vendure/utils/queries/available-countries-query.ts @@ -0,0 +1,16 @@ +export const availableCountriesQuery = /* GraphQL */ ` +query availableCountriesQuery { + availableCountries { + ...Country + __typename + } +} + +fragment Country on Country { + id + code + name + enabled + __typename +} +` diff --git a/framework/vendure/utils/queries/eligible-shipping-methods-query.ts b/framework/vendure/utils/queries/eligible-shipping-methods-query.ts new file mode 100644 index 000000000..a85b6f102 --- /dev/null +++ b/framework/vendure/utils/queries/eligible-shipping-methods-query.ts @@ -0,0 +1,13 @@ +export const getEligibleShippingMethods = /* GraphQL */ ` +query getEligibleShippingMethods { + eligibleShippingMethods { + id + name + description + price + priceWithTax + metadata + __typename + } +} +` diff --git a/pages/index.tsx b/pages/index.tsx index 62aeca0ab..2bbe38cc9 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -31,8 +31,8 @@ export default function Home({ featuredAndDiscountFacetsValue, veggie, - + {spiceProducts.length>0 && } diff --git a/src/components/common/ButtonCommon/ButtonCommon.module.scss b/src/components/common/ButtonCommon/ButtonCommon.module.scss index 318180ede..69c07c670 100644 --- a/src/components/common/ButtonCommon/ButtonCommon.module.scss +++ b/src/components/common/ButtonCommon/ButtonCommon.module.scss @@ -1,7 +1,7 @@ @import "../../../styles/utilities"; .buttonCommon { - @apply shape-common; + @apply shape-common h-full; &:hover { .inner { @apply shadow-md; diff --git a/src/components/common/CardItemCheckout/CardItemCheckout.tsx b/src/components/common/CardItemCheckout/CardItemCheckout.tsx index e67057aa6..40fbf6b37 100644 --- a/src/components/common/CardItemCheckout/CardItemCheckout.tsx +++ b/src/components/common/CardItemCheckout/CardItemCheckout.tsx @@ -1,24 +1,29 @@ +import { LineItem } from '@commerce/types/cart' import React from 'react' +import { ImgWithLink } from '..' import s from "./CardItemCheckout.module.scss" -import { ProductProps } from 'src/utils/types.utils' -export interface CardItemCheckoutProps extends ProductProps { - quantity:number +export interface CardItemCheckoutProps extends LineItem { + currency: { code: string } } -const CardItemCheckout = ({imageSrc,name,price,weight,quantity,category}: CardItemCheckoutProps) => { +const CardItemCheckout = ({ + quantity, + variant, + name, + currency }: CardItemCheckoutProps) => { return (
- image +
- {`${name} (${weight})`} + {name} {variant?.weight ? `(${variant.weight})` : ''}
- Quantity: + Quantity:
- {`${quantity} x ${price}`} + {`${quantity} x ${variant?.price} ${currency?.code}`}
diff --git a/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx b/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx index ef219d31d..57a6e2b20 100644 --- a/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx +++ b/src/components/common/CartDrawer/components/ProductCartItem/ProductCartItem.tsx @@ -74,7 +74,8 @@ const ProductCartItem = ({ {discounts.length > 0 && (
{/* {oldPrice} */} - {discounts[0]} + {/* TODO: edit the value */} + {discounts[0]?.value}
)}
{variant?.price} {currency?.code}
diff --git a/src/components/common/CheckoutCollapse/CheckoutCollapse.module.scss b/src/components/common/CheckoutCollapse/CheckoutCollapse.module.scss index 9e8e1f8e5..490797c75 100644 --- a/src/components/common/CheckoutCollapse/CheckoutCollapse.module.scss +++ b/src/components/common/CheckoutCollapse/CheckoutCollapse.module.scss @@ -1,51 +1,52 @@ -.warpper{ +.warpper { padding: 2.4rem 0; @apply border-b border-solid border-line; - .note{ + .note { + @apply cursor-pointer; font-size: 1.2rem; line-height: 2rem; letter-spacing: 0.01em; color: var(--text-label); padding: 0 5.6rem; } - .header{ - @apply flex justify-between; - .left{ + .header { + @apply flex justify-between cursor-pointer; + .left { @apply flex items-center; - .number{ + .number { width: 3.2rem; height: 3.2rem; border-radius: 100%; border: 1px solid var(--text-active); color: var(--text-active); @apply flex justify-center items-center font-bold; - &.visible{ + &.visible { background-color: var(--text-active); border: none; color: var(--white); } - &.done{ + &.done { @apply border-2 border-solid border-primary; } } - .title{ + .title { padding-left: 2.4rem; - @apply font-bold select-none cursor-pointer; + @apply font-bold select-none; color: var(--text-active); } } - .edit{ + .edit { @apply font-bold cursor-pointer; text-decoration-line: underline; margin-right: 5.6rem; } } - .body{ + .body { height: 0; @apply overflow-hidden; - &.show{ + &.show { margin-top: 3.2rem; height: initial; } } -} \ No newline at end of file +} diff --git a/src/components/common/CheckoutCollapse/CheckoutCollapse.tsx b/src/components/common/CheckoutCollapse/CheckoutCollapse.tsx index 077b94a79..38314c8cc 100644 --- a/src/components/common/CheckoutCollapse/CheckoutCollapse.tsx +++ b/src/components/common/CheckoutCollapse/CheckoutCollapse.tsx @@ -1,8 +1,6 @@ import classNames from 'classnames' -import { divide } from 'lodash' import React from 'react' import { IconDoneCheckout } from 'src/components/icons' -import { CheckOutForm } from 'src/utils/types.utils' import s from './CheckoutCollapse.module.scss' interface CheckoutCollapseProps { visible: boolean @@ -10,10 +8,11 @@ interface CheckoutCollapseProps { children: React.ReactNode title: string isEdit: boolean - onClose?: (id:number) => void - onOpen?: (id:number) => void - onEditClick?:(id:number) => void - note?:string + onClose: (id: number) => void + onOpen?: (id: number) => void + onEditClick?: (id: number) => void + note?: string + disableEdit?: boolean } const CheckoutCollapse = ({ @@ -24,33 +23,34 @@ const CheckoutCollapse = ({ visible, note, onOpen, - onClose, - onEditClick + onClose, + onEditClick, + disableEdit, }: CheckoutCollapseProps) => { - const handleTitleClick = () => { - if(visible){ - onClose && onClose(id) - }else{ - onOpen && onOpen(id) - } - } + const handleToggle = () => { + if (visible) { + isEdit && onClose(id) + } else if (!disableEdit) { + isEdit && onEditClick && onEditClick(id) + } + } const handleEdit = () => { - onEditClick && onEditClick(id) - } + onEditClick && onEditClick(id) + } return (
-
+
-
- {isEdit?:id} +
+ {isEdit ? : id}
-
+
{title}
- {isEdit &&
{'Edit'}
} + {!disableEdit && isEdit &&
{'Edit'}
}
- {(!visible && isEdit) && (
{note}
) } + {(!visible && isEdit) && (
{note}
)}
{children}
) diff --git a/src/components/common/LayoutCheckout/LayoutCheckout.module.scss b/src/components/common/LayoutCheckout/LayoutCheckout.module.scss index 8a32d20a7..82e8d8a0e 100644 --- a/src/components/common/LayoutCheckout/LayoutCheckout.module.scss +++ b/src/components/common/LayoutCheckout/LayoutCheckout.module.scss @@ -4,8 +4,11 @@ flex-direction: column; min-height: 100vh; > main { + display: flex; flex: 1; position: relative; + max-width: min(100%, 1536px); + margin: auto; } .footer { @apply spacing-horizontal; diff --git a/src/components/common/ModalAuthenticate/ModalAuthenticate.tsx b/src/components/common/ModalAuthenticate/ModalAuthenticate.tsx index 145155268..6b773cf98 100644 --- a/src/components/common/ModalAuthenticate/ModalAuthenticate.tsx +++ b/src/components/common/ModalAuthenticate/ModalAuthenticate.tsx @@ -12,9 +12,11 @@ interface Props { visible: boolean closeModal: () => void mode?: '' | 'register' + initialEmail?: string + disableRedirect ?: boolean } -const ModalAuthenticate = ({ visible, mode, closeModal }: Props) => { +const ModalAuthenticate = ({ visible, mode, closeModal, initialEmail, disableRedirect }: Props) => { const [isLogin, setIsLogin] = useState(true) const { customer } = useActiveCustomer() const router = useRouter() @@ -30,9 +32,11 @@ const ModalAuthenticate = ({ visible, mode, closeModal }: Props) => { useEffect(() => { if (visible && customer) { closeModal() - router.push(ROUTE.ACCOUNT) + if (!disableRedirect) { + router.push(ROUTE.ACCOUNT) + } } - }, [customer, visible, closeModal, router]) + }, [customer, visible, closeModal, router, disableRedirect]) const onSwitch = () => { setIsLogin(!isLogin) @@ -51,7 +55,7 @@ const ModalAuthenticate = ({ visible, mode, closeModal }: Props) => { [s.register]: !isLogin, })} > - +
diff --git a/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx b/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx index 3f4ac6816..8264fc70a 100644 --- a/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx +++ b/src/components/common/ModalAuthenticate/components/FormLogin/FormLogin.tsx @@ -15,6 +15,8 @@ import styles from './FormLogin.module.scss' interface Props { isHide: boolean onSwitch: () => void + initialEmail?: string + } const displayingErrorMessagesSchema = Yup.object().shape({ @@ -24,7 +26,7 @@ const displayingErrorMessagesSchema = Yup.object().shape({ .required(LANGUAGE.MESSAGE.REQUIRED), }) -const FormLogin = ({ onSwitch, isHide }: Props) => { +const FormLogin = ({ onSwitch, isHide, initialEmail = ''}: Props) => { const emailRef = useRef(null) const { loading, login } = useLogin() const { showMessageSuccess, showMessageError } = useMessage() @@ -54,7 +56,7 @@ const FormLogin = ({ onSwitch, isHide }: Props) => { void onCancel?: () => void } @@ -18,16 +18,17 @@ const ModalConfirm = ({ children, title = 'Confirm', loading, + onClose, ...props }: ModalConfirmProps) => { return ( - + {children}
- {cancelText} + {cancelText}
- {okText} + {okText}
) diff --git a/src/components/common/SelectFieldInForm/SelectFieldInForm.module.scss b/src/components/common/SelectFieldInForm/SelectFieldInForm.module.scss new file mode 100644 index 000000000..e50b5e0f5 --- /dev/null +++ b/src/components/common/SelectFieldInForm/SelectFieldInForm.module.scss @@ -0,0 +1,19 @@ +@import "../../../styles/form"; + +.inputWrap { + @extend .formInputWrap; + .inputInner { + select { + @apply w-full; + background-color: var(--white); + padding: 1.6rem 1.6rem; + border: 1px solid var(--border-line); + border-radius: 0.8rem; + &:focus { + outline: none; + border: 1px solid var(--primary); + @apply shadow-md; + } + } + } +} diff --git a/src/components/common/SelectFieldInForm/SelectFieldInForm.tsx b/src/components/common/SelectFieldInForm/SelectFieldInForm.tsx new file mode 100644 index 000000000..3a650fa1c --- /dev/null +++ b/src/components/common/SelectFieldInForm/SelectFieldInForm.tsx @@ -0,0 +1,106 @@ +import classNames from "classnames" +import { Field } from "formik" +import { useMemo } from "react" +import { IconCheck, IconError } from "src/components/icons" +import s from './SelectFieldInForm.module.scss' + + +interface Props { + placeholder?: string + styleType?: 'default' | 'custom' + backgroundTransparent?: boolean + icon?: React.ReactNode + isIconSuffix?: boolean + isShowIconSuccess?: boolean + name: string + error?: string + options: any[] + keyNameOption?: string[] + keyValueOption?: string + nameSeperator?: string + +} + +const SelectFieldInForm = ({ + name, + placeholder, + options, + styleType = 'default', + icon, + backgroundTransparent = false, + isIconSuffix = true, + isShowIconSuccess, + error, + keyNameOption = ['name'], + keyValueOption = 'value', + nameSeperator = " ", + +}: Props) => { + const iconElement = useMemo(() => { + if (error) { + return ( + + {' '} + + ) + } else if (isShowIconSuccess) { + return ( + + {' '} + + ) + } else if (icon) { + return {icon} + } + return <> + }, [icon, error, isShowIconSuccess]) + + return ( +
+
+ {iconElement} + + { + options.map((item) => { + let name = '' + keyNameOption.map((key) => { + if (name) { + name += nameSeperator + } + name += item[key] + }) + name = name.trim() + return + }) + } + + +
+ {error &&
{error}
} +
+ ) +} + +export default SelectFieldInForm diff --git a/src/components/common/index.ts b/src/components/common/index.ts index e2c28e186..754806669 100644 --- a/src/components/common/index.ts +++ b/src/components/common/index.ts @@ -50,6 +50,7 @@ export { default as RecommendedRecipes} from './RecommendedRecipes/RecommendedRe export { default as LayoutCheckout} from './LayoutCheckout/LayoutCheckout' export { default as InputPasswordFiledInForm} from './InputPasswordFiledInForm/InputPasswordFiledInForm' export { default as InputFiledInForm} from './InputFiledInForm/InputFiledInForm' +export { default as SelectFieldInForm} from './SelectFieldInForm/SelectFieldInForm' export { default as MessageCommon} from './MessageCommon/MessageCommon' export { default as FormForgot} from './ForgotPassword/FormForgot/FormForgot' export { default as FormResetPassword} from './ForgotPassword/FormResetPassword/FormResetPassword' diff --git a/src/components/hooks/auth/useLogin.tsx b/src/components/hooks/auth/useLogin.tsx index d38390004..c0125f73a 100644 --- a/src/components/hooks/auth/useLogin.tsx +++ b/src/components/hooks/auth/useLogin.tsx @@ -6,6 +6,7 @@ import { LoginMutation } from '@framework/schema' import { LOCAL_STORAGE_KEY } from 'src/utils/constanst.utils' import { errorMapping } from 'src/utils/errrorMapping' import { loginMutation } from '@framework/utils/mutations/log-in-mutation' +import { useGetActiveOrder } from '../cart' interface LoginInput { username: string @@ -16,6 +17,7 @@ const useLogin = () => { const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const { mutate } = useActiveCustomer() + const { mutate: mutateOrder } = useGetActiveOrder() const login = (options: LoginInput, fCallBack: (isSuccess: boolean, message?: string) => void @@ -34,6 +36,7 @@ const useLogin = () => { if (authToken != null) { localStorage.setItem(LOCAL_STORAGE_KEY.TOKEN, authToken) mutate() + mutateOrder() } fCallBack(true) }) diff --git a/src/components/hooks/cart/useGetActiveOrder.tsx b/src/components/hooks/cart/useGetActiveOrder.tsx index c8898c222..cb7af3f2e 100644 --- a/src/components/hooks/cart/useGetActiveOrder.tsx +++ b/src/components/hooks/cart/useGetActiveOrder.tsx @@ -15,8 +15,7 @@ const query = gql` const useGetActiveOrder = () => { const { data, ...rest } = useSWR([query], gglFetcher) - return { order: data?.activeOrder ? normalizeCart(data!.activeOrder) : null, ...rest } - + return { order: data?.activeOrder ? normalizeCart(data!.activeOrder) : null, ...rest } } export default useGetActiveOrder diff --git a/src/components/hooks/cart/useRemoveProductInCart.tsx b/src/components/hooks/cart/useRemoveProductInCart.tsx index d66fd4306..27fcb8de2 100644 --- a/src/components/hooks/cart/useRemoveProductInCart.tsx +++ b/src/components/hooks/cart/useRemoveProductInCart.tsx @@ -1,11 +1,10 @@ +import { RemoveOrderLineMutation, RemoveOrderLineMutationVariables } from '@framework/schema' +import { removeOrderLineMutation } from '@framework/utils/mutations/remove-order-line-mutation' import { useState } from 'react' import { CommonError } from 'src/domains/interfaces/CommonError' -import rawFetcher from 'src/utils/rawFetcher' -import { AdjustOrderLineMutationVariables,AdjustOrderLineMutation, RemoveOrderLineMutation, RemoveOrderLineMutationVariables } from '@framework/schema' import { errorMapping } from 'src/utils/errrorMapping' +import rawFetcher from 'src/utils/rawFetcher' import { useGetActiveOrder } from '.' -import { adjustOrderLineMutation } from '@framework/utils/mutations/adjust-order-line-mutation' -import { removeOrderLineMutation } from '@framework/utils/mutations/remove-order-line-mutation' const useRemoveProductInCart = () => { const [loading, setLoading] = useState(false) diff --git a/src/components/hooks/order/index.ts b/src/components/hooks/order/index.ts index f644f7917..9c20a24be 100644 --- a/src/components/hooks/order/index.ts +++ b/src/components/hooks/order/index.ts @@ -1,2 +1,8 @@ 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' +export { default as useGetActiveOrderForCheckout } from './useGetActiveOrderForCheckout' +export { default as useEligibleShippingMethods } from './useEligibleShippingMethods' diff --git a/src/components/hooks/order/useApplyCouponCode.tsx b/src/components/hooks/order/useApplyCouponCode.tsx new file mode 100644 index 000000000..329682ed8 --- /dev/null +++ b/src/components/hooks/order/useApplyCouponCode.tsx @@ -0,0 +1,41 @@ +import { ApplyCouponCodeMutation } from '@framework/schema' +import { applyCouponCodeMutation } from '@framework/utils/mutations/apply-coupon-code-mutation' +import { useState } from 'react' +import { CommonError } from 'src/domains/interfaces/CommonError' +import rawFetcher from 'src/utils/rawFetcher' +import { useGetActiveOrderForCheckout } from '.' + + +const useApplyCouponCode = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const { mutate } = useGetActiveOrderForCheckout() + + const applyCouponCode = (couponCode: string, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + rawFetcher({ + query: applyCouponCodeMutation, + variables: { couponCode }, + }) + .then(({ data }) => { + if (data.applyCouponCode.__typename === 'Order') { + fCallBack(true) + mutate() + } else { + fCallBack(false, data.applyCouponCode.message) + } + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, applyCouponCode, error } +} + +export default useApplyCouponCode diff --git a/src/components/hooks/order/useAvailableCountries.tsx b/src/components/hooks/order/useAvailableCountries.tsx new file mode 100644 index 000000000..51099965a --- /dev/null +++ b/src/components/hooks/order/useAvailableCountries.tsx @@ -0,0 +1,14 @@ +import { GetAvailableCountriesQuery } from '@framework/schema' +import { availableCountriesQuery } from '@framework/utils/queries/available-countries-query' +import gglFetcher from 'src/utils/gglFetcher' +import useSWR from 'swr' + +const useAvailableCountries = () => { + const { data, isValidating } = useSWR([availableCountriesQuery], gglFetcher) + return { + countries: data?.availableCountries, + loading: isValidating, + } +} + +export default useAvailableCountries diff --git a/src/components/hooks/order/useEligibleShippingMethods.tsx b/src/components/hooks/order/useEligibleShippingMethods.tsx new file mode 100644 index 000000000..cd4b64019 --- /dev/null +++ b/src/components/hooks/order/useEligibleShippingMethods.tsx @@ -0,0 +1,14 @@ +import { GetEligibleMethodsQuery, ShippingMethodQuote } from '@framework/schema' +import { getEligibleShippingMethods } from '@framework/utils/queries/eligible-shipping-methods-query' +import gglFetcher from 'src/utils/gglFetcher' +import useSWR from 'swr' + +const useEligibleShippingMethods = () => { + const { data, isValidating } = useSWR([getEligibleShippingMethods], gglFetcher) + return { + eligibleShippingMethods: data?.eligibleShippingMethods as ShippingMethodQuote[], + loading: isValidating, + } +} + +export default useEligibleShippingMethods diff --git a/src/components/hooks/order/useGetActiveOrderForCheckout.tsx b/src/components/hooks/order/useGetActiveOrderForCheckout.tsx new file mode 100644 index 000000000..fb69f82be --- /dev/null +++ b/src/components/hooks/order/useGetActiveOrderForCheckout.tsx @@ -0,0 +1,13 @@ +import { ActiveOrderQuery } from '@framework/schema' +import { normalizeCartForCheckout } from '@framework/utils/normalize' +import { getActiveOrderForCheckoutQuery } from '@framework/utils/queries/active-order-for-checkout-query' +import gglFetcher from 'src/utils/gglFetcher' +import useSWR from 'swr' + + +const useGetActiveOrderForCheckout = () => { + const { data, ...rest } = useSWR([getActiveOrderForCheckoutQuery], gglFetcher) + return { order: data?.activeOrder ? normalizeCartForCheckout(data!.activeOrder) : null, ...rest } +} + +export default useGetActiveOrderForCheckout diff --git a/src/components/hooks/order/useSetCustomerForOrder.tsx b/src/components/hooks/order/useSetCustomerForOrder.tsx index a209c107e..028f255cc 100644 --- a/src/components/hooks/order/useSetCustomerForOrder.tsx +++ b/src/components/hooks/order/useSetCustomerForOrder.tsx @@ -3,16 +3,16 @@ import { setCustomerForOrderMutation } from '@framework/utils/mutations/set-cust import { useState } from 'react' import { CommonError } from 'src/domains/interfaces/CommonError' import rawFetcher from 'src/utils/rawFetcher' -import { useGetActiveOrder } from '../cart' +import { useGetActiveOrderForCheckout } from '.' const useSetCustomerForOrder = () => { const [loading, setLoading] = useState(false) const [error, setError] = useState(null) - const { mutate } = useGetActiveOrder() + const { mutate } = useGetActiveOrderForCheckout() const setCustomerForOrder = (input: CreateCustomerInput, - fCallBack: (isSuccess: boolean, message?: string) => void + fCallBack: (isSuccess: boolean, message?: CommonError) => void ) => { setError(null) setLoading(true) @@ -21,17 +21,17 @@ const useSetCustomerForOrder = () => { variables: { input }, }) .then(({ data }) => { - if (data.setCustomerForOrder.__typename === 'ActiveOrderCustomerFragment') { + if (data.setCustomerForOrder.__typename === 'Order') { fCallBack(true) mutate() } else { - fCallBack(false, data.setCustomerForOrder.message) + fCallBack(false, data.setCustomerForOrder) } }) .catch((error) => { setError(error) - fCallBack(false, error.message) + fCallBack(false, error) }) .finally(() => setLoading(false)) } diff --git a/src/components/hooks/order/useSetOrderShippingAddress.tsx b/src/components/hooks/order/useSetOrderShippingAddress.tsx new file mode 100644 index 000000000..be020c48f --- /dev/null +++ b/src/components/hooks/order/useSetOrderShippingAddress.tsx @@ -0,0 +1,42 @@ +import { CreateAddressInput, SetOrderShippingAddressMutation } from '@framework/schema' +import { setOrderShippingAddressMutation } from '@framework/utils/mutations/set-order-shipping-address-mutation' +import { useState } from 'react' +import { CommonError } from 'src/domains/interfaces/CommonError' +import rawFetcher from 'src/utils/rawFetcher' +import { useGetActiveOrderForCheckout } from '.' + + +const useSetOrderShippingAddress = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const { mutate } = useGetActiveOrderForCheckout() + + const setOrderShippingAddress = (input: CreateAddressInput, + fCallBack: (isSuccess: boolean, message?: string) => void + ) => { + setError(null) + setLoading(true) + rawFetcher({ + query: setOrderShippingAddressMutation, + variables: { input }, + }) + .then(({ data }) => { + if (data.setOrderShippingAddress.__typename === 'Order') { + fCallBack(true) + mutate() + } else { + fCallBack(false, data.setOrderShippingAddress.message) + } + + }) + .catch((error) => { + setError(error) + fCallBack(false, error.message) + }) + .finally(() => setLoading(false)) + } + + return { loading, setOrderShippingAddress, error } +} + +export default useSetOrderShippingAddress diff --git a/src/components/hooks/order/useSetOrderShippingMethod.tsx b/src/components/hooks/order/useSetOrderShippingMethod.tsx new file mode 100644 index 000000000..6c4f48f5a --- /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 { useGetActiveOrderForCheckout } from '.' + + +const useSetOrderShippingMethod = () => { + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + const { mutate } = useGetActiveOrderForCheckout() + + 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/CheckoutBill/CheckoutBill.module.scss b/src/components/modules/checkout/CheckoutBill/CheckoutBill.module.scss index 84dea0f06..713a984a5 100644 --- a/src/components/modules/checkout/CheckoutBill/CheckoutBill.module.scss +++ b/src/components/modules/checkout/CheckoutBill/CheckoutBill.module.scss @@ -1,6 +1,7 @@ .warpper { padding: 3.2rem; min-width: 100%; + min-height: 100%; @screen lg { max-width: 56.3rem; @apply flex justify-between flex-col; @@ -14,15 +15,14 @@ display: block; } } + .empty { + @apply flex flex-col justify-center items-center; + } .list { - min-height: 52.8rem; + // min-height: 52.8rem; } .bot { - .promo { - // padding: 3.2rem; - @apply bg-gray flex justify-between items-center; - min-height: 6.4rem; - } + margin-top: auto; .price { margin-top: 3.2rem; .line { diff --git a/src/components/modules/checkout/CheckoutBill/CheckoutBill.tsx b/src/components/modules/checkout/CheckoutBill/CheckoutBill.tsx index 259397980..3e3910c90 100644 --- a/src/components/modules/checkout/CheckoutBill/CheckoutBill.tsx +++ b/src/components/modules/checkout/CheckoutBill/CheckoutBill.tsx @@ -1,41 +1,59 @@ +import { CartCheckout } from '@commerce/types/cart' +import Link from 'next/link' import React from 'react' +import { ROUTE } from 'src/utils/constanst.utils' +import { LANGUAGE } from 'src/utils/language.utils' +import { ButtonCommon, CardItemCheckout, EmptyCommon } from '../../../common' import s from './CheckoutBill.module.scss' -import { CardItemCheckout } from '../../../common' -import { CardItemCheckoutProps } from '../../../common/CardItemCheckout/CardItemCheckout' -import { IconCirclePlus } from 'src/components/icons' +import FormPromotionCode from './FormPromotionCode/FormPromotionCode' interface CheckoutBillProps { - data: CardItemCheckoutProps[] + data: CartCheckout | null } const CheckoutBill = ({ data }: CheckoutBillProps) => { return (
-
- Your cart ({data.length}) -
+
+ Your cart ({data?.totalQuantity || 0}) +
+ { + !data?.totalQuantity && + }
- {data.map((item) => { - return + {data?.lineItems?.map((item) => { + return })}
-
- Apply Promotion Code - -
+
+
+ Discount {(data?.discounts?.length || 0) > 0 && `(${data?.discounts?.map(item => item.description).join(",")})`} +
+ {data?.totalDiscount || 0} {data?.currency?.code} +
+
Subtotal -
RP 120.500
+
+ {data?.subtotalPrice || 0} {data?.currency?.code} +
Shipping -
Free
+
{data?.shippingLine?.priceWithTax || 0} {data?.currency?.code}
Estimated Total -
RP 120.500
+
{data?.totalPrice || 0} {data?.currency?.code}
diff --git a/src/components/modules/checkout/CheckoutBill/FormPromotionCode/FormPromotionCode.module.scss b/src/components/modules/checkout/CheckoutBill/FormPromotionCode/FormPromotionCode.module.scss new file mode 100644 index 000000000..1391a5e00 --- /dev/null +++ b/src/components/modules/checkout/CheckoutBill/FormPromotionCode/FormPromotionCode.module.scss @@ -0,0 +1,19 @@ +.promo { + @apply bg-gray flex justify-between items-center; + min-height: 6.4rem; + .modalPromotion { + min-width: 40rem; + .bottom { + @apply flex justify-end items-center; + margin-top: 3.2rem; + button { + &:first-child { + margin-right: 0.8rem; + @screen md { + margin-right: 3.2rem; + } + } + } + } + } +} diff --git a/src/components/modules/checkout/CheckoutBill/FormPromotionCode/FormPromotionCode.tsx b/src/components/modules/checkout/CheckoutBill/FormPromotionCode/FormPromotionCode.tsx new file mode 100644 index 000000000..aaf8f6b32 --- /dev/null +++ b/src/components/modules/checkout/CheckoutBill/FormPromotionCode/FormPromotionCode.tsx @@ -0,0 +1,97 @@ +import { Form, Formik } from 'formik'; +import React, { useEffect, useRef } from 'react'; +import { ButtonCommon, InputFiledInForm, ModalCommon } from 'src/components/common'; +import { useMessage } from 'src/components/contexts'; +import { useModalCommon } from 'src/components/hooks'; +import { useApplyCouponCode } from 'src/components/hooks/order'; +import { IconCirclePlus } from 'src/components/icons'; +import { LANGUAGE } from 'src/utils/language.utils'; +import { CustomInputCommon } from 'src/utils/type.utils'; +import * as Yup from 'yup'; +import s from './FormPromotionCode.module.scss'; + +const displayingErrorMessagesSchema = Yup.object().shape({ + couponCode: Yup.string().required(LANGUAGE.MESSAGE.REQUIRED), +}) + +const FormPromotionCode = () => { + const { visible, openModal, closeModal } = useModalCommon({ initialValue: false }) + const { showMessageError, showMessageSuccess } = useMessage() + const { applyCouponCode, loading } = useApplyCouponCode() + const inputRef = useRef(null) + + useEffect(() => { + setTimeout(() => { + if (visible) { + inputRef.current?.focus() + } + }, 500); + }, [visible]) + + const handleSubmit = (values: { couponCode: string }) => { + applyCouponCode(values.couponCode, onSubmitCalBack) + } + + const onSubmitCalBack = (isSuccess: boolean, msg?: string) => { + // TODO: + if (isSuccess) { + showMessageSuccess("Applied coupon code successfully.", 5000) + closeModal() + } else { + showMessageError(msg) + } + } + + return ( +
+ Apply Promotion Code + + +
+ + {({ errors, touched, isValid, submitForm }) => ( +
+
+ + +
+
+ + {LANGUAGE.BUTTON_LABEL.CANCEL} + + + Apply promotion code + +
+
+ )} +
+
+
+
+ ); +}; + +export default FormPromotionCode; \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.tsx b/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.tsx index bec1fd132..32cfec5fd 100644 --- a/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.tsx +++ b/src/components/modules/checkout/CheckoutInfo/CheckoutInfo.tsx @@ -1,51 +1,100 @@ -import React, { useState } from 'react' -import { ButtonCommon, Logo } from 'src/components/common' +import React, { useEffect, useState } from 'react' +import { Logo } from 'src/components/common' import CheckoutCollapse from 'src/components/common/CheckoutCollapse/CheckoutCollapse' -import { useAddProductToCart, useGetActiveOrder } from 'src/components/hooks/cart' -import { removeItem } from 'src/utils/funtion.utils' -import { CheckOutForm } from 'src/utils/types.utils' +import { useActiveCustomer } from 'src/components/hooks/auth' +import { useGetActiveOrderForCheckout } from 'src/components/hooks/order' import s from './CheckoutInfo.module.scss' import CustomerInfoForm from './components/CustomerInfoForm/CustomerInfoForm' import PaymentInfoForm from './components/PaymentInfoForm/PaymentInfoForm' import ShippingInfoForm from './components/ShippingInfoForm/ShippingInfoForm' +import ShippingMethod from './components/ShippingMethod/ShippingMethod' interface CheckoutInfoProps { onViewCart: () => void + currency?: string } -const CheckoutInfo = ({ onViewCart }: CheckoutInfoProps) => { - const [active, setActive] = useState(1) - const [done, setDone] = useState([]) - const [info, setInfo] = useState({}) +export enum CheckoutStep { + CustomerInfo = 1, + ShippingAddressInfo = 2, + ShippingMethodInfo = 3, + PaymentInfo = 4, +} - const onEdit = (id: number) => { - setActive(id) - setDone(removeItem(done, id)) - } +const CheckoutInfo = ({ onViewCart, currency = "" }: CheckoutInfoProps) => { + const [activeStep, setActiveStep] = useState(1) + const [doneSteps, setDoneSteps] = useState([]) + const { order } = useGetActiveOrderForCheckout() + const { customer } = useActiveCustomer() - const onConfirm = (id: number, formInfo: CheckOutForm) => { - if (id + 1 > formList.length) { - console.log({ ...info, ...formInfo }) - } else { - if (done.length > 0) { - for (let i = id + 1; i <= formList.length; i++) { - if (!done.includes(i)) { - setActive(i) + useEffect(() => { + if (customer) { + if (!doneSteps.includes(CheckoutStep.CustomerInfo)) { + + if (doneSteps.length > 0) { + for (let i = CheckoutStep.CustomerInfo + 1; i <= Object.keys(CheckoutStep).length; i++) { + if (!doneSteps.includes(i)) { + setActiveStep(i) + } } + } else { + setActiveStep(CheckoutStep.CustomerInfo + 1) } - } else { - setActive(id + 1) + + setDoneSteps([...doneSteps, CheckoutStep.CustomerInfo]) } - setDone([...done, id]) } - setInfo({ ...info, ...formInfo }) + }, [customer, doneSteps]) + + + const onEdit = (id: CheckoutStep) => { + setActiveStep(id) } - const getNote = (id: number) => { + const updateActiveStep = (step: CheckoutStep) => { + if (doneSteps.length > 0) { + for (let i = step + 1; i < Object.keys(CheckoutStep).length; i++) { + if (!doneSteps.includes(i)) { + setActiveStep(i) + return + } + } + } else { + setActiveStep(step + 1) + } + } + + const onConfirm = (step: CheckoutStep) => { + if (step + 1 > formList.length) { + // TODO: checkout + console.log("finish: ", order) + } else { + updateActiveStep(step) + setDoneSteps([...doneSteps, step]) + } + } + + + const getNote = (id: CheckoutStep) => { switch (id) { - case 1: - return `${info.name}, ${info.email}` - case 2: - return `${info.address}, ${info.state}, ${info.city}, ${info.code}, ${info.phone}, ` + case CheckoutStep.CustomerInfo: + if (order?.customer?.emailAddress) { + return `${order?.customer?.firstName} ${order?.customer?.lastName}, ${order?.customer?.emailAddress}` + } else if (customer) { + return `${customer.firstName} ${customer.lastName}, ${customer.emailAddress}` + } else { + return '' + } + case CheckoutStep.ShippingAddressInfo: + if (order?.shippingAddress) { + const { streetLine1, city, province, postalCode, countryCode, phoneNumber } = order.shippingAddress + return `${streetLine1}, ${city}, ${province}, ${postalCode}, ${countryCode}, ${phoneNumber}` + } + return '' + case CheckoutStep.ShippingMethodInfo: + if (order?.shippingLine) { + return `${order?.shippingLine.shippingMethod.name}, ${order?.shippingLine.priceWithTax ? `${order?.shippingLine.priceWithTax} ${currency}` : 'Free'}` || '' + } + return '' default: return "" } @@ -53,39 +102,29 @@ const CheckoutInfo = ({ onViewCart }: CheckoutInfoProps) => { const formList = [ { - id: 1, + id: CheckoutStep.CustomerInfo, title: 'Customer Information', - form: , + form: , }, { - id: 2, - title: 'Shipping Information', - form: , + id: CheckoutStep.ShippingAddressInfo, + title: 'Shipping Address Information', + form: , }, { - id: 3, + id: CheckoutStep.ShippingMethodInfo, + title: 'Shipping Method Information', + form: , + }, + { + id: CheckoutStep.PaymentInfo, title: 'Payment Information', - form: , + form: , }, ] - // TODO: remove - const { addProduct } = useAddProductToCart() - - const createOrder = () => { - addProduct({ variantId: "63", quantity: 1 }, handleAddToCartCallback) - } - const handleAddToCartCallback = (isSuccess: boolean, message?: string) => { - // console.log("after create order: ", isSuccess, message) - - } - - const {order} = useGetActiveOrder() - return (
- test create order - test get active order
View cart
@@ -95,11 +134,13 @@ const CheckoutInfo = ({ onViewCart }: CheckoutInfoProps) => { return {item.form} 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/CustomerInfoForm/CustomerInfoForm.module.scss b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.module.scss index 10dd6ec36..cc415f373 100644 --- a/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.module.scss +++ b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.module.scss @@ -8,11 +8,10 @@ } } .bottom{ + @apply flex flex-col items-start; margin-top: 2.4rem; - @apply flex justify-between items-center; - @screen sm-only { - @apply flex-col items-start; + button { + margin-left: auto; } - } } \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.tsx b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.tsx index 8df2ab1fb..254983dda 100644 --- a/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.tsx +++ b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/CustomerInfoForm.tsx @@ -1,16 +1,23 @@ import { Form, Formik } from 'formik' -import React, { useRef } from 'react' +import React, { useEffect, useRef, useState } from 'react' import { ButtonCommon, InputFiledInForm } from 'src/components/common' +import ModalAuthenticate from 'src/components/common/ModalAuthenticate/ModalAuthenticate' import { useMessage } from 'src/components/contexts' +import { useModalCommon } from 'src/components/hooks' import { useSetCustomerForOrder } from 'src/components/hooks/order' +import { ErrorCode } from 'src/domains/enums/ErrorCode' +import { CommonError } from 'src/domains/interfaces/CommonError' 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 s from './CustomerInfoForm.module.scss' +import ModalConfirmLogin from './ModalConfirmLogin/ModalConfirmLogin' interface Props { - isHide: boolean - onSwitch: () => void + id: number + onConfirm: (id: number) => void + activeStep: number + } const displayingErrorMessagesSchema = Yup.object().shape({ @@ -19,32 +26,49 @@ const displayingErrorMessagesSchema = Yup.object().shape({ emailAddress: Yup.string().email(LANGUAGE.MESSAGE.INVALID_EMAIL).required(LANGUAGE.MESSAGE.REQUIRED), }) -const CustomerInfoForm = ({ onSwitch, isHide }: Props) => { +const CustomerInfoForm = ({ id, onConfirm, activeStep }: Props) => { const firstNameRef = useRef(null) const emailRef = useRef(null) const { setCustomerForOrder, loading } = useSetCustomerForOrder() const { showMessageError } = useMessage() + const [emailAddress, setEmailAddress] = useState('') + const { visible: visibleModalConfirmLogin, closeModal: closeModalConfirmLogin, openModal: openModalConfirmLogin } = useModalCommon({ initialValue: false }) + const { visible: visibleModalAuthen, closeModal: closeModalAuthen, openModal: openModalAuthen } = useModalCommon({ initialValue: false }) + + useEffect(() => { + setTimeout(() => { + firstNameRef.current?.focus() + }, 500); + }, [activeStep]) const handleSubmit = (values: { firstName: string, lastName: string, emailAddress: string }) => { - console.log('on submit: ', values) const { firstName, lastName, emailAddress } = values + setEmailAddress(emailAddress) setCustomerForOrder({ firstName, lastName, emailAddress }, onSubmitCalBack) - // onConfirm && - // onConfirm(id, { - // name: nameRef?.current?.getValue().toString(), - // email: emailRef.current?.getValue().toString(), - // }) } - const onSubmitCalBack = (isSuccess: boolean, msg?: string) => { + const onSubmitCalBack = (isSuccess: boolean, error?: CommonError) => { // TODO: - console.log("result: ", isSuccess, msg) if (isSuccess) { - + onConfirm(id) } else { - console.log("error here") - showMessageError(msg) + if (error?.errorCode === ErrorCode.EmailAddressConflictError) { + // show modal common + openModalConfirmLogin() + } else if (error?.errorCode === ErrorCode.NoActiveOrderError) { + showMessageError("Your cart is empty! Please add items to the cart!") + } else { + showMessageError(error?.message) + } } + } + const handleOpenModalLogin = () => { + closeModalConfirmLogin() + openModalAuthen() + } + const handleCloseModalConfirmLogin = () => { + closeModalConfirmLogin() + emailRef.current?.focus() } return ( @@ -58,7 +82,6 @@ const CustomerInfoForm = ({ onSwitch, isHide }: Props) => { }} validationSchema={displayingErrorMessagesSchema} onSubmit={handleSubmit} - > {({ errors, touched, isValid, submitForm }) => (
@@ -90,12 +113,12 @@ const CustomerInfoForm = ({ onSwitch, isHide }: Props) => { { )}
+ + ) } diff --git a/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/ModalConfirmLogin/ModalConfirmLogin.module.scss b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/ModalConfirmLogin/ModalConfirmLogin.module.scss new file mode 100644 index 000000000..ca70f06a7 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/ModalConfirmLogin/ModalConfirmLogin.module.scss @@ -0,0 +1,5 @@ + +.modalConfirmLogin { + min-width: 40rem; + text-align: center; +} \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/ModalConfirmLogin/ModalConfirmLogin.tsx b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/ModalConfirmLogin/ModalConfirmLogin.tsx new file mode 100644 index 000000000..bf2445eb9 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/CustomerInfoForm/ModalConfirmLogin/ModalConfirmLogin.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { ModalConfirm } from 'src/components/common'; +import { LANGUAGE } from 'src/utils/language.utils'; +import s from './ModalConfirmLogin.module.scss' + +interface Props { + visible: boolean + closeModal: () => void + handleOk: () => void + email: string +} + +const ModalConfirmLogin = ({ visible, closeModal, handleOk, email }: Props) => { + return ( +
+ +
+

Account already exists for email {email}

+

Please signin to continue or use another email

+
+
+
+ ); +}; + +export default ModalConfirmLogin; \ No newline at end of file diff --git a/src/components/modules/checkout/CheckoutInfo/components/PaymentInfoForm/PaymentInfoForm.tsx b/src/components/modules/checkout/CheckoutInfo/components/PaymentInfoForm/PaymentInfoForm.tsx index eac100fb0..de72812c3 100644 --- a/src/components/modules/checkout/CheckoutInfo/components/PaymentInfoForm/PaymentInfoForm.tsx +++ b/src/components/modules/checkout/CheckoutInfo/components/PaymentInfoForm/PaymentInfoForm.tsx @@ -1,19 +1,18 @@ import React from 'react' import { ButtonCommon, TabCommon, TabPane } from 'src/components/common' -import { CheckOutForm } from 'src/utils/types.utils' import BankTransfer from '../BankTransfer/BankTransfer' -import Link from 'next/link' - -import s from './PaymentInfoForm.module.scss' +import ChekoutNotePolicy from '../ChekoutNotePolicy/ChekoutNotePolicy' import CreditCardForm from '../CreditCardForm/CreditCardForm' +import s from './PaymentInfoForm.module.scss' + interface PaymentInfoFormProps { - onConfirm?: (id: number, formInfo: CheckOutForm) => void + onConfirm?: (id: number) => void id: number } const PaymentInfoForm = ({onConfirm,id}: PaymentInfoFormProps) => { const handleConfirmClick = () => { - onConfirm && onConfirm(id,{}) + onConfirm && onConfirm(id) } return (
@@ -29,21 +28,7 @@ const PaymentInfoForm = ({onConfirm,id}: PaymentInfoFormProps) => {
-
- By clicking continue you agree to Casper's{' '} - { - - terms and conditions - - }{' '} - and{' '} - { - - privacy policy - - } - . -
+
Submit Order 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..74d70da48 100644 --- a/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.module.scss +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.module.scss @@ -1,45 +1,20 @@ @import "../../../../../../styles/utilities"; -.warpper{ +.warpper { @apply u-form; @screen md { padding: 0 5.6rem; } - .bottom{ + .bottom { + @apply flex flex-col items-start; margin-top: 2.4rem; - @apply flex justify-between items-center; - .note{ - font-size: 1.2rem; - line-height: 2rem; - } - @screen sm-only { - @apply flex-col items-start; - .button { - padding-top: 2rem; - } + button { + margin-left: auto; } } - .line{ - >div{ + .line { + > div { 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 64fe3ce6e..f9ef80ce6 100644 --- a/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.tsx +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingInfoForm/ShippingInfoForm.tsx @@ -1,17 +1,37 @@ -import React, { useRef } from 'react' -import { ButtonCommon, Inputcommon, SelectCommon } from 'src/components/common' -import s from './ShippingInfoForm.module.scss' -import Link from 'next/link' +import { Form, Formik } from 'formik' +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 { LANGUAGE } from 'src/utils/language.utils' import { CustomInputCommon } from 'src/utils/type.utils' -import { Shipping } from 'src/components/icons' -import { CheckOutForm } from 'src/utils/types.utils' +import * as Yup from 'yup' +import ChekoutNotePolicy from '../ChekoutNotePolicy/ChekoutNotePolicy' +import s from './ShippingInfoForm.module.scss' interface ShippingInfoFormProps { - onConfirm?: (id:number,formInfo:CheckOutForm)=>void - id:number + id: number + activeStep: number + onConfirm: (id: number) => void + } -const option = [ + +const displayingErrorMessagesSchema = Yup.object().shape({ + streetLine1: Yup.string().required(LANGUAGE.MESSAGE.REQUIRED), + city: Yup.string().required(LANGUAGE.MESSAGE.REQUIRED), + province: Yup.string().required(LANGUAGE.MESSAGE.REQUIRED), + postalCode: Yup.number().required(LANGUAGE.MESSAGE.REQUIRED), + countryCode: Yup.string().required(LANGUAGE.MESSAGE.REQUIRED), + phoneNumber: Yup.string().required(LANGUAGE.MESSAGE.REQUIRED), + +}) + +const DEFAULT_COUNTRY_CODE = 'MY' +const DEFAULT_PROVINCE = 'Sabah' + +// TODO: update data +const provinceOptions = [ { name: 'Hồ Chí Minh', value: 'Hồ Chí Minh', @@ -20,79 +40,150 @@ const option = [ name: 'Hà Nội', value: 'Hà Nội', }, + { + name: 'Sabah', + value: 'Sabah', + }, ] -const ShippingInfoForm = ({onConfirm,id}: ShippingInfoFormProps) => { +const ShippingInfoForm = ({ onConfirm, id, activeStep }: ShippingInfoFormProps) => { const addressRef = useRef(null) - const cityRef = useRef(null) - const stateRef = useRef(null) - const codeRef = useRef(null) - const phoneRef = useRef(null) - const handleConfirmClick = () => { - onConfirm && onConfirm(id,{ - address: addressRef?.current?.getValue().toString(), - city: cityRef.current?.getValue().toString(), - state: stateRef?.current?.getValue().toString(), - code: Number(codeRef.current?.getValue()), - phone: Number(phoneRef?.current?.getValue()), - }) + const { setOrderShippingAddress, loading } = useSetOrderShippingAddress() + const { showMessageError } = useMessage() + const { countries } = useAvailableCountries() + + useEffect(() => { + setTimeout(() => { + addressRef.current?.focus() + }, 500); + }, [activeStep]) + + const handleSubmit = (values: any) => { + setOrderShippingAddress(values, onSubmitCalBack) } + const onSubmitCalBack = (isSuccess: boolean, msg?: string) => { + if (isSuccess) { + onConfirm(id) + } else { + showMessageError(msg) + } + } + + return (
- - -
- State - -
- -
-
-
- -
-
- Standard Delivery Method -
-
-
-
- Free -
-
-
-
-
-
- By clicking continue you agree to Casper's{' '} - { - - terms and conditions - - }{' '} - and{' '} - { - - privacy policy - - } - . -
-
- - Continue to Payment - -
+ + {({ errors, touched, isValid, submitForm }) => ( + +
+
+ +
+
+
+ +
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+ + + Continue to Shipping method + +
+
+ + )} +
+
) 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..225f3282a --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethod.module.scss @@ -0,0 +1,28 @@ +.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 { + margin-top: 0.8rem; + width: 100%; + background: var(--white); + border: 1px solid var(--border-line); + border-radius: 0.8rem; + } +} 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..10b3022e2 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethod.tsx @@ -0,0 +1,75 @@ +import { ShippingMethodQuote } from '@framework/schema' +import React, { memo, useState } from 'react' +import { useMessage } from 'src/components/contexts' +import { useEligibleShippingMethods, useSetOrderShippingMethod } from 'src/components/hooks/order' +import { Shipping } from 'src/components/icons' +import { CheckoutStep } from '../../CheckoutInfo' +import s from './ShippingMethod.module.scss' +import ShippingMethodItem from './ShippingMethodItem/ShippingMethodItem' + +interface Props { + currency: string + onConfirm: (id: number) => void + +} + +const ShippingMethod = memo(({ currency, onConfirm }: Props) => { + const { eligibleShippingMethods } = useEligibleShippingMethods() + const { setOrderShippingMethod } = useSetOrderShippingMethod() + const [selectedValue, setSelectedValue] = useState(eligibleShippingMethods ? eligibleShippingMethods[0] : undefined) + const { showMessageError } = useMessage() + + const onChange = (id: string) => { + const newValue = eligibleShippingMethods?.find(item => item.id === id) + if (newValue) { + setSelectedValue(newValue) + if (newValue?.id) { + setOrderShippingMethod(newValue?.id, onSubmitCalBack) + } + } + } + + const onSubmitCalBack = (isSuccess: boolean, msg?: string) => { + if (isSuccess) { + onConfirm(CheckoutStep.ShippingMethodInfo) + } else { + showMessageError(msg) + } + } + + return ( +
+
+
+
+ +
+
+ {selectedValue?.name} +
+
+
+
+ {selectedValue?.price ? `${selectedValue?.price / 100} ${currency}` : "Free"} +
+
+
+
+
    + {eligibleShippingMethods?.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..9d8526629 --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethodItem/ShippingMethodItem.module.scss @@ -0,0 +1,25 @@ +.shippingMethodItem { + @apply w-full flex justify-between items-center cursor-pointer transition-all duration-200; + padding: 1.6rem; + &:hover { + @apply bg-gray; + } + .left { + @apply flex; + .icon { + @apply transition-all duration-200; + opacity: 0; + &.show { + opacity: 1; + } + } + .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..30651168d --- /dev/null +++ b/src/components/modules/checkout/CheckoutInfo/components/ShippingMethod/ShippingMethodItem/ShippingMethodItem.tsx @@ -0,0 +1,38 @@ +import classNames from 'classnames' +import React, { memo } from 'react' +import { IconCheck } from 'src/components/icons' +import s from './ShippingMethodItem.module.scss' + +interface Props { + id: string + name: string + price: number + currency: string + onSelect: (id: string) => void + isActive: boolean + +} + +const ShippingMethodItem = memo(({ id, name, price, currency, isActive, 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.module.scss b/src/components/modules/checkout/CheckoutPage/CheckoutPage.module.scss index ec7b19dc2..bd519be01 100644 --- a/src/components/modules/checkout/CheckoutPage/CheckoutPage.module.scss +++ b/src/components/modules/checkout/CheckoutPage/CheckoutPage.module.scss @@ -1,6 +1,7 @@ @import "../../../../styles/utilities"; .warrper{ - @apply flex w-full h-full absolute; + @apply flex w-full; + min-height: 100%; .right { display: none; @screen lg { @@ -46,10 +47,7 @@ color:var(--text-base); } } - button{ - margin-top: 2rem; - width: 100%; - } + } } } diff --git a/src/components/modules/checkout/CheckoutPage/CheckoutPage.tsx b/src/components/modules/checkout/CheckoutPage/CheckoutPage.tsx index 4755d329e..12e110a7c 100644 --- a/src/components/modules/checkout/CheckoutPage/CheckoutPage.tsx +++ b/src/components/modules/checkout/CheckoutPage/CheckoutPage.tsx @@ -2,6 +2,7 @@ import classNames from 'classnames' import React, { useState } from 'react' import { MessageCommon } from 'src/components/common' import { useMessage } from 'src/components/contexts' +import { useGetActiveOrderForCheckout } from 'src/components/hooks/order' import IconHide from 'src/components/icons/IconHide' import { CHECKOUT_BILL_DATA } from 'src/utils/demo-data' import { CheckoutBill, CheckoutInfo } from '..' @@ -9,29 +10,30 @@ import s from "./CheckoutPage.module.scss" interface CheckoutPageProps { } -const CheckoutPage = ({}: CheckoutPageProps) => { +const CheckoutPage = ({ }: CheckoutPageProps) => { const { messages, removeMessage } = useMessage() const [isShow, setIsShow] = useState(false) + const { order } = useGetActiveOrderForCheckout() const onClose = () => { setIsShow(false) } - const onViewCart =() => { + const onViewCart = () => { setIsShow(true) } return (
    -
    -
    -
    +
    +
    +

    Your Cart({CHECKOUT_BILL_DATA.length})

    -
    +
    - +
    diff --git a/src/utils/funtion.utils.ts b/src/utils/funtion.utils.ts index 25c394487..f5f1cb146 100644 --- a/src/utils/funtion.utils.ts +++ b/src/utils/funtion.utils.ts @@ -1,6 +1,6 @@ import { Collection } from '@commerce/types/collection'; import { Facet } from "@commerce/types/facet"; -import { Product, ProductCard, ProductOption, ProductOptionValues } from "@commerce/types/product"; +import { Product, ProductCard, ProductOptionValues } from "@commerce/types/product"; import { FacetValue, SearchResultSortParameter } from './../../framework/vendure/schema.d'; import { CODE_FACET_DISCOUNT, CODE_FACET_FEATURED, CODE_FACET_FEATURED_VARIANT, FACET, PRODUCT_SORT_OPTION_VALUE } from "./constanst.utils"; import { PromiseWithKey, SelectedOptions, SortOrder } from "./types.utils"; diff --git a/src/utils/language.utils.ts b/src/utils/language.utils.ts index 2005f900d..7a8abd6b4 100644 --- a/src/utils/language.utils.ts +++ b/src/utils/language.utils.ts @@ -5,7 +5,8 @@ export const LANGUAGE = { CONFIRM:'Confirm', ADD_TO_CARD: 'Add to Cart', PREORDER: 'Pre-Order Now', - SIGNIN :'Sign In' + SIGNIN :'Sign In', + CANCEL: 'Cancel', }, PLACE_HOLDER: { SEARCH: 'Search', diff --git a/src/utils/types.utils.ts b/src/utils/types.utils.ts index f3dd654f3..e14a7eb59 100644 --- a/src/utils/types.utils.ts +++ b/src/utils/types.utils.ts @@ -33,18 +33,6 @@ export interface BlogProps { imageSrc: string | null, } -export interface CheckOutForm { - name?: string - email?: string - address?: string - city?: string - state?: string - code?: number - phone?: number - method?: string - shipping_fee?: number -} - export type MouseAndTouchEvent = MouseEvent | TouchEvent export enum SortOrder {