Skip to content

Commit

Permalink
fix: Rehydrate payment source among payment components
Browse files Browse the repository at this point in the history
  • Loading branch information
acasazza committed Apr 5, 2022
1 parent ad739c2 commit 789af62
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 60 deletions.
53 changes: 36 additions & 17 deletions src/components/BraintreePayment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@ import React, {
useRef,
useState,
} from 'react'
import { HostedFieldFieldOptions } from 'braintree-web/modules/hosted-fields'
import {
HostedFieldFieldOptions,
HostedFieldsHostedFieldsFieldName,
} from 'braintree-web/modules/hosted-fields'
import PaymentMethodContext from '#context/PaymentMethodContext'
import isEmpty from 'lodash/isEmpty'
import OrderContext from '#context/OrderContext'
import Parent from './utils/Parent'
import { PaymentSourceProps } from './PaymentSource'
import { setCustomerOrderParam } from '#utils/localStorage'
import promisify from '#utils/promisify'
import { ThreeDSecure } from 'braintree-web'
import { BraintreePayment as BraintreePaymentType } from '@commercelayer/sdk'
import { ThreeDSecureVerifyOptions } from 'braintree-web/modules/three-d-secure'
type BraintreeHostedFields<Type> = {
[Property in keyof Type]: {
label?: string
Expand Down Expand Up @@ -42,6 +48,13 @@ type BraintreePaymentProps = {
locale?: string
}

type SubmitProps = {
event?: FormEvent<HTMLFormElement>
hostedFieldsInstance: HostedFieldsHostedFieldsFieldName
threeDSInstance: ThreeDSecure
paymentSource?: BraintreePaymentType
}

const defaultConfig: BraintreeConfig = {
styles: {
// Style all elements
Expand Down Expand Up @@ -123,11 +136,11 @@ const BraintreePayment: FunctionComponent<BraintreePaymentProps> = ({
} = useContext(PaymentMethodContext)
const { order } = useContext(OrderContext)
const ref = useRef<null | HTMLFormElement>(null)
const handleSubmitForm = async (
event?: FormEvent<HTMLFormElement>,
hostedFieldsInstance?: any,
threeDSInstance?: any
) => {
const handleSubmitForm = async ({
event,
hostedFieldsInstance,
threeDSInstance,
}: SubmitProps) => {
const savePaymentSourceToCustomerWallet =
// @ts-ignore
event?.elements?.['save_payment_source_to_customer_wallet']?.checked
Expand All @@ -145,7 +158,7 @@ const BraintreePayment: FunctionComponent<BraintreePaymentProps> = ({
const verifyCardOptions = {
nonce: payload.nonce,
bin: payload.details.bin,
amount: order?.total_amount_with_taxes_float,
amount: order?.total_amount_with_taxes_float as number,
email: order?.customer_email,
billingAddress: {
givenName: billingAddress?.first_name,
Expand All @@ -160,8 +173,10 @@ const BraintreePayment: FunctionComponent<BraintreePaymentProps> = ({
onLookupComplete: (_data: any, next: any) => {
next()
},
}
const response = await threeDSInstance.verifyCard(verifyCardOptions)
} as ThreeDSecureVerifyOptions
const response = (await threeDSInstance.verifyCard(
verifyCardOptions
)) as any
if (
response.rawCardinalSDKVerificationData.Validated &&
paymentSource
Expand Down Expand Up @@ -221,7 +236,10 @@ const BraintreePayment: FunctionComponent<BraintreePaymentProps> = ({
fields: fields as HostedFieldFieldOptions,
styles: styles,
},
(hostedFieldsErr: any, hostedFieldsInstance: any) => {
(
hostedFieldsErr: any,
hostedFieldsInstance: HostedFieldsHostedFieldsFieldName
) => {
if (hostedFieldsErr) {
console.error(hostedFieldsErr)
return
Expand All @@ -232,7 +250,7 @@ const BraintreePayment: FunctionComponent<BraintreePaymentProps> = ({
authorization,
version: 2,
},
(threeDSecureErr: any, threeDSecureInstance: any) => {
(threeDSecureErr: any, threeDSInstance: ThreeDSecure) => {
if (threeDSecureErr) {
// Handle error in 3D Secure component creation
console.error('3DSecure error', threeDSecureErr)
Expand All @@ -246,12 +264,13 @@ const BraintreePayment: FunctionComponent<BraintreePaymentProps> = ({
])
}
if (ref.current) {
ref.current.onsubmit = () =>
handleSubmitForm(
ref.current as any,
ref.current.onsubmit = (paymentSource: any) =>
handleSubmitForm({
event: ref.current as any,
hostedFieldsInstance,
threeDSecureInstance
)
threeDSInstance,
paymentSource,
})
setPaymentRef({ ref })
}
}
Expand All @@ -271,7 +290,7 @@ const BraintreePayment: FunctionComponent<BraintreePaymentProps> = ({
<form
ref={ref}
id="braintree-form"
onSubmit={handleSubmitForm}
onSubmit={handleSubmitForm as any}
className={containerClassName}
>
<div className={fieldsContainerClassName}>
Expand Down
11 changes: 7 additions & 4 deletions src/components/PaymentGateway.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const PaymentGateway: FunctionComponent<PaymentGatewayProps> = ({
config,
currentPaymentMethodType,
setPaymentSource,
paymentSource,
} = useContext(PaymentMethodContext)
const paymentResource = readonly
? currentPaymentMethodType
Expand All @@ -77,20 +78,22 @@ const PaymentGateway: FunctionComponent<PaymentGatewayProps> = ({
})
getCustomerPaymentSources && (await getCustomerPaymentSources())
}
if (order?.payment_source === null && order?.payment_method.id && show) {
if (!paymentSource && order?.payment_method.id && show) {
setPaymentSources()
}
// @ts-ignore
if (order?.payment_source?.mismatched_amounts && show) {
if (paymentSource?.mismatched_amounts && show) {
setPaymentSources()
}
if (!paymentSource || paymentSource.type !== paymentResource) {
setPaymentSources()
}

setLoading(false)
}
return () => {
setLoading(true)
}
}, [order?.payment_method?.id, show, order?.payment_source?.id])
}, [order?.payment_method?.id, show, paymentSource])
const gatewayConfig = {
readonly,
showCard,
Expand Down
19 changes: 19 additions & 0 deletions src/components/PaymentMethodsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import paymentMethodReducer, {
PaymentMethodConfig,
setPaymentMethodConfig,
PaymentRef,
setPaymentSource,
} from '#reducers/PaymentMethodReducer'
import OrderContext from '#context/OrderContext'
import CommerceLayerContext from '#context/CommerceLayerContext'
Expand Down Expand Up @@ -75,6 +76,22 @@ const PaymentMethodsContainer: React.FunctionComponent<
getPayMethods()
}
}
if (order?.payment_source) {
dispatch({
type: 'setPaymentSource',
payload: {
paymentSource: order?.payment_source,
},
})
}
if (order?.payment_source === null) {
dispatch({
type: 'setPaymentSource',
payload: {
paymentSource: undefined,
},
})
}
}, [order, credentials, include, includeLoaded])
const contextValue = useMemo(() => {
return {
Expand Down Expand Up @@ -115,6 +132,8 @@ const PaymentMethodsContainer: React.FunctionComponent<
...args,
dispatch,
config: credentials,
updateOrder,
orderId: order?.id,
}),
}
}, [state])
Expand Down
12 changes: 7 additions & 5 deletions src/components/PaymentSource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const PaymentSource: FunctionComponent<PaymentSourceProps> = (props) => {
const card = getCardDetails({
paymentType: payment?.payment_source_type as PaymentResource,
customerPayment: {
payment_source: order?.payment_source || paymentSource,
payment_source: paymentSource,
},
})
if (card.brand) setShowCard(true)
Expand All @@ -74,11 +74,13 @@ const PaymentSource: FunctionComponent<PaymentSourceProps> = (props) => {
])
const handleEditClick = async (e: MouseEvent) => {
e.stopPropagation()
paymentSource &&
(await destroyPaymentSource({
paymentSourceId: paymentSource?.id,
if (paymentSource) {
const paymentSourceId = paymentSource?.id
await destroyPaymentSource({
paymentSourceId,
paymentResource: payment?.payment_source_type as PaymentResource,
}))
})
}
setShowCard(!showCard)
setShow(true)
}
Expand Down
20 changes: 12 additions & 8 deletions src/components/PlaceOrderButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,20 @@ const PlaceOrderButton: FunctionComponent<PlaceOrderButtonProps> = (props) => {
useContext(PlaceOrderContext)
const [notPermitted, setNotPermitted] = useState(true)
const [forceDisable, setForceDisable] = useState(disabled)
const { currentPaymentMethodRef, loading, currentPaymentMethodType } =
useContext(PaymentMethodContext)
const {
currentPaymentMethodRef,
loading,
currentPaymentMethodType,
paymentSource,
} = useContext(PaymentMethodContext)
const { order } = useContext(OrderContext)
const isFree = order?.total_amount_with_taxes_cents === 0
useEffect(() => {
if (loading) setNotPermitted(loading)
else {
if (paymentType === currentPaymentMethodType && paymentType) {
const card = getCardDetails({
customerPayment: { payment_source: order?.payment_source },
customerPayment: { payment_source: paymentSource },
paymentType,
})
if (
Expand All @@ -70,7 +74,7 @@ const PlaceOrderButton: FunctionComponent<PlaceOrderButtonProps> = (props) => {
loading,
currentPaymentMethodType,
order,
order?.payment_source,
paymentSource,
])
useEffect(() => {
if (
Expand Down Expand Up @@ -110,7 +114,7 @@ const PlaceOrderButton: FunctionComponent<PlaceOrderButtonProps> = (props) => {
paymentType &&
getCardDetails({
paymentType,
customerPayment: { payment_source: order?.payment_source },
customerPayment: { payment_source: paymentSource },
})
if (
currentPaymentMethodRef?.current?.onsubmit &&
Expand All @@ -123,16 +127,16 @@ const PlaceOrderButton: FunctionComponent<PlaceOrderButtonProps> = (props) => {
// @ts-ignore
isValid = (await currentPaymentMethodRef.current?.onsubmit(
// @ts-ignore
order.payment_source
paymentSource
)) as boolean
} else if (card?.brand) {
isValid = true
}
const placed =
isValid &&
setPlaceOrder &&
(order?.payment_source || isFree) &&
(await setPlaceOrder({ paymentSource: order?.payment_source }))
(paymentSource || isFree) &&
(await setPlaceOrder({ paymentSource: paymentSource }))
setForceDisable(false)
onClick && placed && onClick(placed)
}
Expand Down
11 changes: 6 additions & 5 deletions src/components/StripePayment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,13 @@ const StripePaymentForm: React.FunctionComponent<StripePaymentFormProps> = ({
currentPaymentMethodType,
setPaymentMethodErrors,
setPaymentRef,
paymentSource,
} = useContext(PaymentMethodContext)
const { order } = useContext(OrderContext)
const stripe = useStripe()
const elements = useElements()
useEffect(() => {
if (ref.current && stripe && elements && order?.payment_source?.id) {
if (ref.current && stripe && elements && paymentSource) {
// @ts-ignore
ref.current.onsubmit = (paymentSource?: StripePaymentType) => {
return onSubmit({
Expand All @@ -87,12 +88,12 @@ const StripePaymentForm: React.FunctionComponent<StripePaymentFormProps> = ({
return () => {
setPaymentRef({ ref: { current: null } })
}
}, [ref, stripe, elements, order?.payment_source?.id])
}, [ref, stripe, elements, paymentSource])
const onSubmit = async ({
event,
stripe,
elements,
paymentSource,
paymentSource: ps,
}: OnSubmitArgs): Promise<boolean> => {
if (!stripe) return false

Expand Down Expand Up @@ -126,8 +127,8 @@ const StripePaymentForm: React.FunctionComponent<StripePaymentFormProps> = ({
card: cardElement,
billing_details,
})
const clientSecret = paymentSource?.client_secret
const paymentSourceId = paymentSource?.id
const clientSecret = ps?.client_secret
const paymentSourceId = ps?.id
if (clientSecret) {
const { error, paymentIntent } = await stripe.confirmCardPayment(
clientSecret,
Expand Down
12 changes: 5 additions & 7 deletions src/components/gateways/AdyenGateway.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,11 @@ export default function AdyenGateway(props: AdyenGateway) {
useContext(PaymentMethodContext)
const paymentResource: PaymentResource = 'adyen_payments'
const locale = order?.language_code as StripeElementLocale
const paymentMethods =
// @ts-ignore
order?.payment_source?.payment_methods || paymentSource?.payment_methods
// @ts-ignore
const paymentMethods = paymentSource?.payment_methods
if (!readonly && payment?.id !== currentPaymentMethodId) return null
const clientKey =
// @ts-ignore
order?.payment_source?.public_key || paymentSource?.public_key
// @ts-ignore
const clientKey = paymentSource?.public_key
const environment = jwt(accessToken).test ? 'test' : 'live'
const adyenConfig = config
? getPaymentConfig<'adyenPayment'>(paymentResource, config)
Expand All @@ -60,7 +58,7 @@ export default function AdyenGateway(props: AdyenGateway) {
if (readonly || showCard) {
const card = getCardDetails({
customerPayment: {
payment_source: order?.payment_source || paymentSource,
payment_source: paymentSource,
},
paymentType: paymentResource,
})
Expand Down
7 changes: 3 additions & 4 deletions src/components/gateways/BraintreeGateway.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,8 @@ export default function BraintreeGateway(props: BraintreeGateway) {
const locale = order?.language_code as StripeElementLocale

if (!readonly && payment?.id !== currentPaymentMethodId) return null
const authorization =
// @ts-ignore
order?.payment_source?.client_token || paymentSource?.client_token
// @ts-ignore
const authorization = paymentSource?.client_token
const braintreeConfig = config
? getPaymentConfig<'braintreePayment'>(paymentResource, config)
: {}
Expand All @@ -53,7 +52,7 @@ export default function BraintreeGateway(props: BraintreeGateway) {
if (readonly || showCard) {
const card = getCardDetails({
customerPayment: {
payment_source: order?.payment_source || paymentSource,
payment_source: paymentSource,
},
paymentType: paymentResource,
})
Expand Down
8 changes: 3 additions & 5 deletions src/components/gateways/CheckoutComGateway.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,8 @@ export default function CheckoutComGateway(props: CheckoutComGateway) {
const locale = order?.language_code as StripeElementLocale

if (!readonly && payment?.id !== currentPaymentMethodId) return null

const publicKey =
// @ts-ignore
order?.payment_source?.public_key || paymentSource?.public_key
// @ts-ignore
const publicKey = paymentSource?.public_key
const paymentConfig = config
? getPaymentConfig<'checkoutComPayment'>(paymentResource, config)
: {}
Expand All @@ -55,7 +53,7 @@ export default function CheckoutComGateway(props: CheckoutComGateway) {
if (readonly || showCard) {
const card = getCardDetails({
customerPayment: {
payment_source: order?.payment_source || paymentSource,
payment_source: paymentSource,
},
paymentType: paymentResource,
})
Expand Down
Loading

0 comments on commit 789af62

Please sign in to comment.