Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"useNx": false,
"npmClient": "pnpm",
"version": "4.28.8",
"version": "4.29.0-beta.5",
"command": {
"version": {
"preid": "beta"
Expand Down
2 changes: 1 addition & 1 deletion packages/react-components/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@commercelayer/react-components",
"version": "4.28.8",
"version": "4.29.0-beta.5",
"description": "The Official Commerce Layer React Components",
"main": "lib/cjs/index.js",
"module": "lib/esm/index.js",
Expand Down
78 changes: 39 additions & 39 deletions packages/react-components/src/components/errors/Errors.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
import { useContext, useMemo, type JSX } from 'react';
import Parent from '#components/utils/Parent'
import GiftCardContext from '#context/GiftCardContext'
import OrderContext from '#context/OrderContext'
import AddressContext from '#context/AddressContext'
import getAllErrors from '#components-utils/getAllErrors'
import LineItemContext from '#context/LineItemContext'
import LineItemChildrenContext from '#context/LineItemChildrenContext'
import type { CodeErrorType } from '#typings/errors'
import CustomerContext from '#context/CustomerContext'
import PaymentMethodContext from '#context/PaymentMethodContext'
import PaymentMethodChildrenContext from '#context/PaymentMethodChildrenContext'
import ShipmentContext from '#context/ShipmentContext'
import type { ChildrenFunction } from '#typings/index'
import InStockSubscriptionContext from '#context/InStockSubscriptionContext'
import { type JSX, useContext, useMemo } from "react"
import Parent from "#components/utils/Parent"
import getAllErrors from "#components-utils/getAllErrors"
import AddressContext from "#context/AddressContext"
import CustomerContext from "#context/CustomerContext"
import GiftCardContext from "#context/GiftCardContext"
import InStockSubscriptionContext from "#context/InStockSubscriptionContext"
import LineItemChildrenContext from "#context/LineItemChildrenContext"
import LineItemContext from "#context/LineItemContext"
import OrderContext from "#context/OrderContext"
import PaymentMethodChildrenContext from "#context/PaymentMethodChildrenContext"
import PaymentMethodContext from "#context/PaymentMethodContext"
import ShipmentContext from "#context/ShipmentContext"
import type { CodeErrorType } from "#typings/errors"
import type { ChildrenFunction } from "#typings/index"

export type TResourceError =
| 'addresses'
| 'billing_address'
| 'gift_cards'
| 'gift_card_or_coupon_code'
| 'line_items'
| 'orders'
| 'payment_methods'
| 'prices'
| 'shipments'
| 'shipping_address'
| 'customer_address'
| 'sku_options'
| 'variant'
| 'in_stock_subscriptions'
| "addresses"
| "billing_address"
| "gift_cards"
| "gift_card_or_coupon_code"
| "line_items"
| "orders"
| "payment_methods"
| "prices"
| "shipments"
| "shipping_address"
| "customer_address"
| "sku_options"
| "variant"
| "in_stock_subscriptions"
type ErrorChildrenComponentProps = ChildrenFunction<
Omit<TErrorComponent, 'children'> & { errors: string[] }
Omit<TErrorComponent, "children"> & { errors: string[] }
>

export interface TErrorComponent
extends Omit<JSX.IntrinsicElements['span'], 'children'> {
extends Omit<JSX.IntrinsicElements["span"], "children"> {
/**
* Resource which get the error
*/
Expand Down Expand Up @@ -68,12 +68,12 @@ export function Errors(props: Props): JSX.Element {
const { errors: customerErrors } = useContext(CustomerContext)
const { errors: shipmentErrors } = useContext(ShipmentContext)
const { errors: inStockSubscriptionErrors } = useContext(
InStockSubscriptionContext
InStockSubscriptionContext,
)
const {
errors: paymentMethodErrors,
currentPaymentMethodType,
currentPaymentMethodId
currentPaymentMethodId,
} = useContext(PaymentMethodContext)
const { lineItem } = useContext(LineItemChildrenContext)
const allErrors = useMemo(
Expand All @@ -87,8 +87,8 @@ export function Errors(props: Props): JSX.Element {
...(paymentMethodErrors?.filter(
(v) =>
v.field === currentPaymentMethodType &&
payment?.id === currentPaymentMethodId
) || [])
payment?.id === currentPaymentMethodId,
) || []),
],
[
giftCardErrors,
Expand All @@ -97,12 +97,12 @@ export function Errors(props: Props): JSX.Element {
customerErrors,
shipmentErrors,
inStockSubscriptionErrors,
paymentMethodErrors
]
paymentMethodErrors,
],
).filter((v, k, a) => v?.code !== a[k - 1]?.code)
const addressesErrors = useMemo(
() => [...(addressErrors || [])],
[addressErrors]
[addressErrors],
)
const msgErrors = getAllErrors({
allErrors: [...allErrors, ...addressesErrors],
Expand All @@ -111,7 +111,7 @@ export function Errors(props: Props): JSX.Element {
props: p,
lineItem,
resource,
returnHtml: !children
returnHtml: !children,
})
const parentProps = { messages, resource, field, errors: msgErrors, ...p }
return children ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export function PlaceOrderButton(props: Props): JSX.Element {
setPaymentSource,
setPaymentMethodErrors,
currentCustomerPaymentSourceId,
errors: paymentMethodErrors,
} = useContext(PaymentMethodContext)
const { order, setOrderErrors, errors } = useContext(OrderContext)
const isFree = order?.total_amount_with_taxes_cents === 0
Expand Down Expand Up @@ -142,15 +143,20 @@ export function PlaceOrderButton(props: Props): JSX.Element {
currentPaymentMethodType,
order?.id,
paymentSource?.id,
order?.total_amount_with_taxes_cents
order?.total_amount_with_taxes_cents,
])
useEffect(() => {
if (errors && errors.length > 0) {
if (
(errors && errors.length > 0) ||
(paymentMethodErrors && paymentMethodErrors.length > 0)
) {
setNotPermitted(true)
setIsLoading(false)
setForceDisable(false)
} else {
setNotPermitted(false)
}
}, [errors])
}, [errors?.length, paymentMethodErrors?.length])
// biome-ignore lint/correctness/useExhaustiveDependencies: Need to test
useEffect(() => {
// PayPal redirect flow
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ export function PaymentGateway({
if (order?.payment_source?.id != null) {
setLoading(false)
}
if (!paymentSource) {
setLoading(true)
}
}
if (expressPayments && show) setLoading(false)
if (
Expand All @@ -131,7 +134,7 @@ export function PaymentGateway({
return () => {
setLoading(true)
}
}, [order?.payment_method?.id, show, paymentSource])
}, [order?.payment_method?.id, show, paymentSource?.id])

useEffect(() => {
if (status === "placing") setLoading(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,14 @@ export function AdyenPayment({
const id: string = component._id
if (id.search("scheme") === -1) {
if (ref.current) {
if (id.search("paypal") === -1) {
/**
* For payment methods different from card, we remove the onsubmit handler
* to manage the submission via Adyen Drop-in and the place order button remains disabled
*/
if (
id.search("paypal") === -1 &&
id.search("giftcard") === -1
) {
ref.current.onsubmit = async () => {
return await handleSubmit(
ref.current as unknown as FormEvent<HTMLFormElement>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ export function PaymentSource(props: PaymentSourceProps): JSX.Element {
errors?.length === 0 &&
checkPaymentSourceStatus !== "declined"
) {
setShowCard(true)
if (card.brand !== "giftcard") {
setShowCard(true)
}
}
if (checkPaymentSourceStatus === "declined") {
setShowCard(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,12 @@ function StripePaymentForm({
stripe,
}: StripePaymentFormProps): JSX.Element {
const ref = useRef<null | HTMLFormElement>(null)
const { currentPaymentMethodType, setPaymentMethodErrors, setPaymentRef } =
useContext(PaymentMethodContext)
const {
errors,
currentPaymentMethodType,
setPaymentMethodErrors,
setPaymentRef,
} = useContext(PaymentMethodContext)
const { order, setOrderErrors } = useContext(OrderContext)
const { sdkClient } = useCommerceLayer()
const { setPlaceOrderStatus } = useContext(PlaceOrderContext)
Expand Down Expand Up @@ -176,35 +180,40 @@ function StripePaymentForm({
}

async function handleChange(event: StripePaymentElementChangeEvent) {
console.debug("StripePaymentElement onChange event", { event })
selectedPaymentMethodType = event.value.type
// Handle change events from the PaymentElement
if (
event.complete &&
["apple_pay", "google_pay"].includes(event.value.type)
) {
const sdk = sdkClient()
if (sdk == null) return
if (order == null) return
const { status } = await sdk.orders.retrieve(order?.id, {
fields: ["status"],
})
const isDraftOrder = status === "draft"
if (isDraftOrder) {
/**
* Draft order cannot be placed
*/
setOrderErrors([
{
code: "VALIDATION_ERROR",
resource: "orders",
message: "Draft order cannot be placed",
},
])
setPlaceOrderStatus?.({
status: "disabled",
if (event.complete) {
/**
* Clear payment method errors on complete event
*/
if (errors && errors.length > 0) {
setPaymentMethodErrors([])
}
if (["apple_pay", "google_pay"].includes(event.value.type)) {
const sdk = sdkClient()
if (sdk == null) return
if (order == null) return
// Reset payment method errors
const { status } = await sdk.orders.retrieve(order?.id, {
fields: ["status"],
})
return
const isDraftOrder = status === "draft"
if (isDraftOrder) {
/**
* Draft order cannot be placed
*/
setOrderErrors([
{
code: "VALIDATION_ERROR",
resource: "orders",
message: "Draft order cannot be placed",
},
])
setPlaceOrderStatus?.({
status: "disabled",
})
return
}
}
}
}
Expand Down
19 changes: 9 additions & 10 deletions packages/react-components/src/components/utils/getAllErrors.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import customMessages from '#utils/customMessages'
import type { LineItem } from '@commercelayer/sdk'
import type { BaseError } from '#typings/errors'
import type { TResourceError } from '#components/errors/Errors'

import type { JSX } from "react";
import type { LineItem } from "@commercelayer/sdk"
import type { JSX } from "react"
import type { TResourceError } from "#components/errors/Errors"
import type { BaseError } from "#typings/errors"
import customMessages from "#utils/customMessages"

export interface AllErrorsParams {
allErrors: BaseError[]
messages: BaseError[]
field?: string
props: Omit<JSX.IntrinsicElements['span'], 'ref'>
props: Omit<JSX.IntrinsicElements["span"], "ref">
lineItem?: LineItem | null
resource?: TResourceError
returnHtml?: boolean
}

export type GetAllErrors = <P extends AllErrorsParams>(
params: P
params: P,
) => Array<JSX.Element | string | undefined>

const getAllErrors: GetAllErrors = (params) => {
Expand All @@ -27,7 +26,7 @@ const getAllErrors: GetAllErrors = (params) => {
props,
lineItem,
resource,
returnHtml = true
returnHtml = true,
} = params
return allErrors
.map((v, k): JSX.Element | string | undefined => {
Expand All @@ -39,7 +38,7 @@ const getAllErrors: GetAllErrors = (params) => {
if (objMsg?.message) text = objMsg?.message.trim()
const isEmpty = text.length === 0
if (field) {
if (v.resource === 'line_items') {
if (v.resource === "line_items") {
if (lineItem && v.id === lineItem.id) {
return isEmpty ? undefined : returnHtml ? (
<span key={k} {...props}>
Expand Down
Loading
Loading