Skip to content

Commit

Permalink
Merge pull request #585 from commercelayer/fix/save-customer-payment-…
Browse files Browse the repository at this point in the history
…adyen

Fix save customer card payment provided by Adyen
  • Loading branch information
acasazza authored Oct 24, 2024
2 parents 10a0434 + 68ab481 commit cf498c2
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 96 deletions.
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.15.11",
"version": "4.15.12-beta.4",
"command": {
"version": {
"preid": "beta"
Expand Down
4 changes: 2 additions & 2 deletions 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.15.11",
"version": "4.15.12-beta.4",
"description": "The Official Commerce Layer React Components",
"main": "lib/cjs/index.js",
"module": "lib/esm/index.js",
Expand Down Expand Up @@ -180,7 +180,7 @@
"dependencies": {
"@adyen/adyen-web": "^5.66.1",
"@commercelayer/organization-config": "^1.4.8",
"@commercelayer/sdk": "6.13.0",
"@commercelayer/sdk": "^6.13.0",
"@stripe/react-stripe-js": "^2.8.0",
"@stripe/stripe-js": "^4.3.0",
"@tanstack/react-table": "^8.17.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import addressReducer, {
import { type BaseError } from '#typings/errors'
import OrderContext from '#context/OrderContext'
import CommerceLayerContext from '#context/CommerceLayerContext'
import { setCustomerOrderParam } from '#utils/localStorage'

interface Props {
children: ReactNode
Expand Down Expand Up @@ -64,6 +65,16 @@ export function AddressesContainer(props: Props): JSX.Element {
const [state, dispatch] = useReducer(addressReducer, addressInitialState)
const { order, orderId, updateOrder } = useContext(OrderContext)
const config = useContext(CommerceLayerContext)
useEffect(() => {
setCustomerOrderParam(
'_save_billing_address_to_customer_address_book',
'false'
)
setCustomerOrderParam(
'_save_shipping_address_to_customer_address_book',
'false'
)
}, [])
useEffect(() => {
dispatch({
type: 'setShipToDifferentAddress',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ interface Props {
* Customer type
*/
isGuest?: boolean
/**
* The page size
* default: 10
*/
addressesPageSize?: QueryPageSize
}

/**
Expand All @@ -54,7 +59,7 @@ interface Props {
* </span>
*/
export function CustomerContainer(props: Props): JSX.Element {
const { children, isGuest } = props
const { children, isGuest, addressesPageSize: pageSize } = props
const [state, dispatch] = useReducer(customerReducer, customerInitialState)
const {
order,
Expand Down Expand Up @@ -112,7 +117,8 @@ export function CustomerContainer(props: Props): JSX.Element {
void getCustomerAddresses({
config,
dispatch,
isOrderAvailable: withoutIncludes != null
isOrderAvailable: withoutIncludes != null,
pageSize
})
}
if (order?.available_customer_payment_sources) {
Expand Down Expand Up @@ -216,7 +222,8 @@ export function CustomerContainer(props: Props): JSX.Element {
await getCustomerAddresses({
config,
dispatch,
isOrderAvailable: withoutIncludes != null
isOrderAvailable: withoutIncludes != null,
pageSize
})
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ export function PlaceOrderButton(props: Props): JSX.Element {
if (
!isValid &&
// @ts-expect-error no type
checkPaymentSource.payment_response?.resultCode === 'Authorised'
checkPaymentSource?.payment_response?.resultCode === 'Authorised'
) {
isValid = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ type Props = {
}
)

let loadingResource = false

export function PaymentMethod({
children,
className,
Expand All @@ -74,6 +76,7 @@ export function PaymentMethod({
}: Props): JSX.Element {
const [loading, setLoading] = useState(true)
const [paymentSelected, setPaymentSelected] = useState('')
const [paymentSourceCreated, setPaymentSourceCreated] = useState(false)
const {
paymentMethods,
currentPaymentMethodId,
Expand Down Expand Up @@ -119,7 +122,13 @@ export function PaymentMethod({
}
}, [!isEmpty(paymentMethods), expressPayments])
useEffect(() => {
if (paymentMethods != null) {
if (
paymentMethods != null &&
!paymentSourceCreated &&
!loadingResource &&
!isEmpty(paymentMethods)
) {
loadingResource = true
if (autoSelectSinglePaymentMethod != null && !expressPayments) {
const autoSelect = async (): Promise<void> => {
const isSingle = paymentMethods.length === 1
Expand Down Expand Up @@ -148,6 +157,7 @@ export function PaymentMethod({
attributes
})
if (ps && paymentMethod && onClick != null) {
setPaymentSourceCreated(true)
onClick({ payment: paymentMethod, order, paymentSource: ps })
setTimeout(() => {
setLoading(false)
Expand All @@ -170,7 +180,7 @@ export function PaymentMethod({
void autoSelect()
}
}
}, [paymentMethods, expressPayments])
}, [order?.payment_source != null])
useEffect(() => {
if (paymentMethods) {
const isSingle = paymentMethods.length === 1
Expand All @@ -187,6 +197,7 @@ export function PaymentMethod({
if (currentPaymentMethodId) setPaymentSelected(currentPaymentMethodId)
return () => {
setLoading(true)
setPaymentSelected('')
}
}, [paymentMethods, currentPaymentMethodId])
const components = paymentMethods
Expand Down Expand Up @@ -233,7 +244,11 @@ export function PaymentMethod({
className={`${className ?? ''} ${
isActive && activeClass != null ? activeClass : ''
}`}
onClick={onClickable}
onClick={(e) => {
if (onClickable != null) {
void onClickable(e)
}
}}
{...p}
>
<PaymentMethodChildrenContext.Provider value={paymentMethodProps}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import { type PaymentSourceProps } from './PaymentSource'
import { setCustomerOrderParam } from '#utils/localStorage'
import type { CoreOptions } from '@adyen/adyen-web/dist/types/core/types'
import Parent from '#components/utils/Parent'
import getBrowserInfo, { cleanUrlBy } from '#utils/browserInfo'
import browserInfo, { cleanUrlBy } from '#utils/browserInfo'
import PlaceOrderContext from '#context/PlaceOrderContext'
import OrderContext from '#context/OrderContext'
import omit from '#utils/omit'
// import omit from '#utils/omit'
import type UIElement from '@adyen/adyen-web/dist/types/components/UIElement'
import { getPublicIP } from '#utils/getPublicIp'

Expand Down Expand Up @@ -88,15 +88,17 @@ export function AdyenPayment({
}
const [loadAdyen, setLoadAdyen] = useState(false)
const [checkout, setCheckout] = useState<UIElement<any> | undefined>()
// const [showSaveToWallet, setShowSaveToWallet] = useState(true)
const {
setPaymentSource,
paymentSource,
setPaymentMethodErrors,
currentPaymentMethodType,
setPaymentRef
setPaymentRef,
currentCustomerPaymentSourceId
} = useContext(PaymentMethodContext)
const { order } = useContext(OrderContext)
const { placeOrderButtonRef } = useContext(PlaceOrderContext)
const { placeOrderButtonRef, setPlaceOrder } = useContext(PlaceOrderContext)
const ref = useRef<null | HTMLFormElement>(null)
const handleSubmit = async (
e: any,
Expand Down Expand Up @@ -125,30 +127,6 @@ export function AdyenPayment({
}
setPaymentRef({ ref })
}
const browserInfo = getBrowserInfo()
const shopperIp = await getPublicIP()
const attributes: any = {
payment_request_data: {
payment_method: state.data.paymentMethod,
shopperInteraction: 'Ecommerce',
recurringProcessingModel: 'CardOnFile',
origin: window.location.origin,
return_url: window.location.href,
redirect_from_issuer_method: 'GET',
shopper_ip: shopperIp,
browser_info: {
acceptHeader:
'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
...browserInfo
}
}
}
paymentSource &&
(await setPaymentSource({
paymentSourceId: paymentSource.id,
paymentResource: 'adyen_payments',
attributes
}))
}
}
const handleOnAdditionalDetails = async (
Expand Down Expand Up @@ -209,12 +187,9 @@ export function AdyenPayment({
state: any,
component: UIElement<any>
): Promise<boolean> => {
const saveCustomer = document.getElementById(
'save_payment_source_to_customer_wallet'
) as HTMLInputElement
const url = cleanUrlBy()
const shopperIp = await getPublicIP()
let control = await setPaymentSource({
const control = await setPaymentSource({
paymentSourceId: paymentSource?.id,
paymentResource: 'adyen_payments'
})
Expand All @@ -223,58 +198,35 @@ export function AdyenPayment({
if (controlCode === 'Authorised') {
return true
}

const paymentDataAvailable =
// @ts-expect-error no type
Object.keys(control?.payment_request_data).length > 0
const paymentMethodSelected =
// @ts-expect-error no type
control?.payment_request_data?.payment_method?.type
const paymentMethod = !saveCustomer?.checked
? omit(state.data.paymentMethod, [
'encryptedCardNumber',
'encryptedExpiryMonth',
'encryptedExpiryYear'
])
: state.data.paymentMethod

if (
!paymentDataAvailable ||
paymentMethodSelected !== state.data.paymentMethod.type
) {
control = await setPaymentSource({
paymentSourceId: paymentSource?.id,
paymentResource: 'adyen_payments',
attributes: {
payment_request_data: {
...state.data,
payment_method: paymentMethod,
return_url: url,
origin: window.location.origin,
redirect_from_issuer_method: 'GET',
shopper_ip: shopperIp
}
}
})
}
const attributes: any = {
payment_request_data: {
...state.data,
payment_method: paymentMethod,
payment_method: state.data.paymentMethod,
return_url: url,
origin: window.location.origin,
redirect_from_issuer_method: 'GET',
shopper_ip: shopperIp
},
_authorize: 1
shopper_ip: shopperIp,
shopperInteraction: 'Ecommerce',
recurringProcessingModel: 'CardOnFile',
browser_info: {
...browserInfo()
}
}
}
delete attributes.payment_request_data.paymentMethod
try {
const res = await setPaymentSource({
await setPaymentSource({
paymentSourceId: paymentSource?.id,
paymentResource: 'adyen_payments',
attributes
})
const res = await setPaymentSource({
paymentSourceId: paymentSource?.id,
paymentResource: 'adyen_payments',
attributes: {
_authorize: 1
}
})
// @ts-expect-error no type
const action = res?.payment_response?.action
if (component && action) {
Expand All @@ -283,8 +235,19 @@ export function AdyenPayment({
}
// @ts-expect-error no type
const resultCode = res?.payment_response?.resultCode
// @ts-expect-error no type
const issuerType = res?.payment_instrument?.issuer_type
if (['Authorised', 'Pending', 'Received'].includes(resultCode)) {
if (placeOrderButtonRef?.current != null) {
if (
['apple pay', 'google pay'].includes(issuerType) &&
setPlaceOrder != null
) {
await setPlaceOrder({
paymentSource: res,
currentCustomerPaymentSourceId
})
return true
} else if (placeOrderButtonRef?.current != null) {
if (placeOrderButtonRef.current.disabled) {
placeOrderButtonRef.current.disabled = false
}
Expand Down
11 changes: 9 additions & 2 deletions packages/react-components/src/reducers/CustomerReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,18 +150,25 @@ export interface GetCustomerAddresses {
* Order details
*/
isOrderAvailable?: boolean
/**
* The page size
* default: 10
*/
pageSize?: QueryPageSize
}

export async function getCustomerAddresses({
config,
dispatch,
isOrderAvailable
isOrderAvailable,
pageSize = 10
}: GetCustomerAddresses): Promise<void> {
try {
const addresses = [] as Address[]
const sdk = getSdk(config)
const customerAddresses = await sdk.customer_addresses.list({
include: ['address']
include: ['address'],
pageSize
})
customerAddresses.forEach((customerAddress) => {
if (customerAddress.address) {
Expand Down
7 changes: 6 additions & 1 deletion packages/react-components/src/reducers/OrderReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,12 @@ export async function addToCart(
}
})
}
if (buyNowMode && id && config?.accessToken != null && config?.endpoint != null) {
if (
buyNowMode &&
id &&
config?.accessToken != null &&
config?.endpoint != null
) {
const params = `${id}?accessToken=${config.accessToken ?? ''}`
const { domain, slug } = getDomain(config.endpoint)
const href = getApplicationLink({
Expand Down
Loading

0 comments on commit cf498c2

Please sign in to comment.