mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 20:26:49 +00:00
✨ feat: show bill discount and total
:%s
This commit is contained in:
@@ -93,8 +93,10 @@ export type Cart = {
|
|||||||
// The sum of all the prices of all the items in the cart.
|
// The sum of all the prices of all the items in the cart.
|
||||||
// Duties, taxes and discounts included.
|
// Duties, taxes and discounts included.
|
||||||
totalPrice: number
|
totalPrice: number
|
||||||
|
totalQuantity: number
|
||||||
// Discounts that have been applied on the cart.
|
// Discounts that have been applied on the cart.
|
||||||
discounts?: Discount[]
|
discounts?: Discount[]
|
||||||
|
totalDiscount: number
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
export type Discount = {
|
export type Discount = {
|
||||||
// The value of the discount, can be an amount or percentage
|
// The value of the discount, can be an amount or percentage
|
||||||
value: number
|
value: number
|
||||||
|
description?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Measurement = {
|
export type Measurement = {
|
||||||
|
4
framework/vendure/schema.d.ts
vendored
4
framework/vendure/schema.d.ts
vendored
@@ -3053,7 +3053,9 @@ export type CartFragment = { __typename?: 'Order' } & Pick<
|
|||||||
| 'currencyCode'
|
| 'currencyCode'
|
||||||
> & {
|
> & {
|
||||||
shippingAddress?: Maybe<{ __typename?: 'OrderAddress' } & Pick<OrderAddress, 'streetLine1' | 'fullName' | 'city' | 'province' | 'postalCode' |'countryCode' | 'phoneNumber'>>
|
shippingAddress?: Maybe<{ __typename?: 'OrderAddress' } & Pick<OrderAddress, 'streetLine1' | 'fullName' | 'city' | 'province' | 'postalCode' |'countryCode' | 'phoneNumber'>>
|
||||||
discounts?: Maybe<{ __typename?: 'Discount' } & Pick<Discount, 'type' | 'amount' | 'amountWithTax'>>
|
discounts: Array<
|
||||||
|
{ __typename?: 'Discount' } & Pick<Discount, 'type' | 'description' | 'amount' | 'amountWithTax'>
|
||||||
|
>
|
||||||
customer?: Maybe<{ __typename?: 'Customer' } & Pick<Customer, 'id' | 'firstName' | 'lastName' | 'emailAddress'>>
|
customer?: Maybe<{ __typename?: 'Customer' } & Pick<Customer, 'id' | 'firstName' | 'lastName' | 'emailAddress'>>
|
||||||
lines: Array<
|
lines: Array<
|
||||||
{ __typename?: 'OrderLine' } & Pick<
|
{ __typename?: 'OrderLine' } & Pick<
|
||||||
|
@@ -9,6 +9,12 @@ export const cartFragment = /* GraphQL */ `
|
|||||||
total
|
total
|
||||||
totalWithTax
|
totalWithTax
|
||||||
currencyCode
|
currencyCode
|
||||||
|
discounts {
|
||||||
|
type
|
||||||
|
description
|
||||||
|
amount
|
||||||
|
amountWithTax
|
||||||
|
}
|
||||||
customer {
|
customer {
|
||||||
id
|
id
|
||||||
firstName
|
firstName
|
||||||
|
@@ -36,10 +36,12 @@ export function normalizeFavoriteProductResult(item: Favorite) {
|
|||||||
|
|
||||||
|
|
||||||
export function normalizeCart(order: CartFragment): Cart {
|
export function normalizeCart(order: CartFragment): Cart {
|
||||||
|
console.log("raw rs: ", order)
|
||||||
return {
|
return {
|
||||||
id: order.id.toString(),
|
id: order.id.toString(),
|
||||||
createdAt: order.createdAt,
|
createdAt: order.createdAt,
|
||||||
taxesIncluded: true,
|
taxesIncluded: true,
|
||||||
|
totalQuantity: order.totalQuantity,
|
||||||
lineItemsSubtotalPrice: order.subTotalWithTax / 100,
|
lineItemsSubtotalPrice: order.subTotalWithTax / 100,
|
||||||
currency: { code: order.currencyCode },
|
currency: { code: order.currencyCode },
|
||||||
subtotalPrice: order.subTotalWithTax / 100,
|
subtotalPrice: order.subTotalWithTax / 100,
|
||||||
@@ -58,6 +60,10 @@ export function normalizeCart(order: CartFragment): Cart {
|
|||||||
countryCode: order.shippingAddress?.countryCode || '',
|
countryCode: order.shippingAddress?.countryCode || '',
|
||||||
phoneNumber: order.shippingAddress?.phoneNumber || '',
|
phoneNumber: order.shippingAddress?.phoneNumber || '',
|
||||||
},
|
},
|
||||||
|
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) => ({
|
lineItems: order.lines?.map((l) => ({
|
||||||
id: l.id,
|
id: l.id,
|
||||||
name: l.productVariant.name,
|
name: l.productVariant.name,
|
||||||
|
@@ -1,24 +1,29 @@
|
|||||||
|
import { LineItem } from '@commerce/types/cart'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { ImgWithLink } from '..'
|
||||||
import s from "./CardItemCheckout.module.scss"
|
import s from "./CardItemCheckout.module.scss"
|
||||||
import { ProductProps } from 'src/utils/types.utils'
|
export interface CardItemCheckoutProps extends LineItem {
|
||||||
export interface CardItemCheckoutProps extends ProductProps {
|
currency: { code: string }
|
||||||
quantity:number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const CardItemCheckout = ({imageSrc,name,price,weight,quantity,category}: CardItemCheckoutProps) => {
|
const CardItemCheckout = ({
|
||||||
|
quantity,
|
||||||
|
variant,
|
||||||
|
name,
|
||||||
|
currency }: CardItemCheckoutProps) => {
|
||||||
return (
|
return (
|
||||||
<div className={s.warpper}>
|
<div className={s.warpper}>
|
||||||
<div className={s.image}>
|
<div className={s.image}>
|
||||||
<img src={imageSrc} alt="image" />
|
<ImgWithLink src={variant?.image?.url ?? ''} alt={name} />
|
||||||
</div>
|
</div>
|
||||||
<div className={s.right}>
|
<div className={s.right}>
|
||||||
<div className={s.name}>
|
<div className={s.name}>
|
||||||
{`${name} (${weight})`}
|
{name} {variant?.weight ? `(${variant.weight})` : ''}
|
||||||
</div>
|
</div>
|
||||||
<div className={s.quantity}>
|
<div className={s.quantity}>
|
||||||
Quantity:
|
Quantity:
|
||||||
<div className={s.price}>
|
<div className={s.price}>
|
||||||
{`${quantity} x ${price}`}
|
{`${quantity} x ${variant?.price} ${currency?.code}`}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,30 +1,38 @@
|
|||||||
import React from 'react'
|
import { Cart } from '@commerce/types/cart'
|
||||||
|
import React, { useMemo } from 'react'
|
||||||
import { CardItemCheckout } from '../../../common'
|
import { CardItemCheckout } from '../../../common'
|
||||||
import { CardItemCheckoutProps } from '../../../common/CardItemCheckout/CardItemCheckout'
|
|
||||||
import s from './CheckoutBill.module.scss'
|
import s from './CheckoutBill.module.scss'
|
||||||
import FormPromotionCode from './FormPromotionCode/FormPromotionCode'
|
import FormPromotionCode from './FormPromotionCode/FormPromotionCode'
|
||||||
|
|
||||||
interface CheckoutBillProps {
|
interface CheckoutBillProps {
|
||||||
data: CardItemCheckoutProps[]
|
// data: CardItemCheckoutProps[]
|
||||||
|
data: Cart | null
|
||||||
}
|
}
|
||||||
|
|
||||||
const CheckoutBill = ({ data }: CheckoutBillProps) => {
|
const CheckoutBill = ({ data }: CheckoutBillProps) => {
|
||||||
|
console.log("data here***: ", data)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={s.warpper}>
|
<div className={s.warpper}>
|
||||||
<div className = {s.title}>
|
<div className={s.title}>
|
||||||
Your cart ({data.length})
|
Your cart ({data?.totalQuantity})
|
||||||
</div>
|
</div>
|
||||||
<div className={s.list}>
|
<div className={s.list}>
|
||||||
{data.map((item) => {
|
{data?.lineItems?.map((item) => {
|
||||||
return <CardItemCheckout {...item} key={item.slug} />
|
return <CardItemCheckout {...item} key={item.slug} currency={data?.currency} />
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className={s.bot}>
|
<div className={s.bot}>
|
||||||
<FormPromotionCode/>
|
<FormPromotionCode />
|
||||||
<div className={s.price}>
|
<div className={s.price}>
|
||||||
|
TODO: here
|
||||||
|
<div className={s.line}>
|
||||||
|
Discount {(data?.discounts?.length || 0) > 0 && `(${data?.discounts?.map(item => item.description).join(",")})`}
|
||||||
|
<div className={s.shipping}>{data?.totalDiscount} {data?.currency?.code}</div>
|
||||||
|
</div>
|
||||||
<div className={s.line}>
|
<div className={s.line}>
|
||||||
Subtotal
|
Subtotal
|
||||||
<div className={s.subTotal}>RP 120.500</div>
|
<div className={s.subTotal}>{data?.subtotalPrice} {data?.currency?.code}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={s.line}>
|
<div className={s.line}>
|
||||||
Shipping
|
Shipping
|
||||||
@@ -32,7 +40,7 @@ const CheckoutBill = ({ data }: CheckoutBillProps) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className={s.line}>
|
<div className={s.line}>
|
||||||
Estimated Total
|
Estimated Total
|
||||||
<div className={s.total}>RP 120.500</div>
|
<div className={s.total}>{data?.totalPrice} {data?.currency?.code}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -102,7 +102,7 @@ const CheckoutInfo = ({ onViewCart }: CheckoutInfoProps) => {
|
|||||||
{
|
{
|
||||||
id: CheckoutStep.CustomerInfo,
|
id: CheckoutStep.CustomerInfo,
|
||||||
title: 'Customer Information',
|
title: 'Customer Information',
|
||||||
form: <CustomerInfoForm onConfirm={onConfirm} id={CheckoutStep.CustomerInfo} />,
|
form: <CustomerInfoForm onConfirm={onConfirm} id={CheckoutStep.CustomerInfo} activeStep={activeStep} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: CheckoutStep.ShippingInfo,
|
id: CheckoutStep.ShippingInfo,
|
||||||
@@ -120,7 +120,7 @@ const CheckoutInfo = ({ onViewCart }: CheckoutInfoProps) => {
|
|||||||
const { addProduct } = useAddProductToCart()
|
const { addProduct } = useAddProductToCart()
|
||||||
|
|
||||||
const createOrder = () => {
|
const createOrder = () => {
|
||||||
addProduct({ variantId: "63", quantity: 1 }, handleAddToCartCallback)
|
addProduct({ variantId: "92", quantity: 2 }, handleAddToCartCallback)
|
||||||
}
|
}
|
||||||
const handleAddToCartCallback = (isSuccess: boolean, message?: string) => {
|
const handleAddToCartCallback = (isSuccess: boolean, message?: string) => {
|
||||||
// console.log("after create order: ", isSuccess, message)
|
// console.log("after create order: ", isSuccess, message)
|
||||||
|
@@ -2,6 +2,7 @@ import classNames from 'classnames'
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { MessageCommon } from 'src/components/common'
|
import { MessageCommon } from 'src/components/common'
|
||||||
import { useMessage } from 'src/components/contexts'
|
import { useMessage } from 'src/components/contexts'
|
||||||
|
import { useGetActiveOrder } from 'src/components/hooks/cart'
|
||||||
import IconHide from 'src/components/icons/IconHide'
|
import IconHide from 'src/components/icons/IconHide'
|
||||||
import { CHECKOUT_BILL_DATA } from 'src/utils/demo-data'
|
import { CHECKOUT_BILL_DATA } from 'src/utils/demo-data'
|
||||||
import { CheckoutBill, CheckoutInfo } from '..'
|
import { CheckoutBill, CheckoutInfo } from '..'
|
||||||
@@ -9,29 +10,30 @@ import s from "./CheckoutPage.module.scss"
|
|||||||
interface CheckoutPageProps {
|
interface CheckoutPageProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const CheckoutPage = ({}: CheckoutPageProps) => {
|
const CheckoutPage = ({ }: CheckoutPageProps) => {
|
||||||
const { messages, removeMessage } = useMessage()
|
const { messages, removeMessage } = useMessage()
|
||||||
const [isShow, setIsShow] = useState(false)
|
const [isShow, setIsShow] = useState(false)
|
||||||
|
const { order } = useGetActiveOrder()
|
||||||
|
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
setIsShow(false)
|
setIsShow(false)
|
||||||
}
|
}
|
||||||
const onViewCart =() => {
|
const onViewCart = () => {
|
||||||
setIsShow(true)
|
setIsShow(true)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className={s.warrper}>
|
<div className={s.warrper}>
|
||||||
<MessageCommon messages={messages} onRemove={removeMessage} />
|
<MessageCommon messages={messages} onRemove={removeMessage} />
|
||||||
<div className={s.left}><CheckoutInfo onViewCart = {onViewCart}/></div>
|
<div className={s.left}><CheckoutInfo onViewCart={onViewCart} /></div>
|
||||||
<div className={s.right}><CheckoutBill data={CHECKOUT_BILL_DATA}/></div>
|
<div className={s.right}><CheckoutBill data={order} /></div>
|
||||||
<div className={classNames({ [s.mobile] :true,[s.isShow]: isShow})}>
|
<div className={classNames({ [s.mobile]: true, [s.isShow]: isShow })}>
|
||||||
<div className={s.modal}>
|
<div className={s.modal}>
|
||||||
<div className={s.content}>
|
<div className={s.content}>
|
||||||
<div className={s.head}>
|
<div className={s.head}>
|
||||||
<h3>Your Cart({CHECKOUT_BILL_DATA.length})</h3>
|
<h3>Your Cart({CHECKOUT_BILL_DATA.length})</h3>
|
||||||
<div onClick={onClose}><IconHide/></div>
|
<div onClick={onClose}><IconHide /></div>
|
||||||
</div>
|
</div>
|
||||||
<CheckoutBill data={CHECKOUT_BILL_DATA}/>
|
<CheckoutBill data={CHECKOUT_BILL_DATA} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user