Skip to content

Commit b02e766

Browse files
authored
feat(commerce): Checkout confirm request handles both new/existing payment sources (#5745)
1 parent 6397bfa commit b02e766

File tree

6 files changed

+48
-29
lines changed

6 files changed

+48
-29
lines changed

.changeset/breezy-hairs-smell.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
'@clerk/types': patch
4+
---
5+
6+
Checkout confirm request handles both new/existing payment sources

packages/clerk-js/bundlewatch.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
{ "path": "./dist/waitlist*.js", "maxSize": "1.3KB" },
2222
{ "path": "./dist/keylessPrompt*.js", "maxSize": "6.5KB" },
2323
{ "path": "./dist/pricingTable*.js", "maxSize": "4.02KB" },
24-
{ "path": "./dist/checkout*.js", "maxSize": "4.9KB" },
24+
{ "path": "./dist/checkout*.js", "maxSize": "4.92KB" },
2525
{ "path": "./dist/paymentSources*.js", "maxSize": "8.5KB" },
2626
{ "path": "./dist/up-billing-page*.js", "maxSize": "1.78KB" },
2727
{ "path": "./dist/op-billing-page*.js", "maxSize": "1.76KB" },

packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import type {
33
__experimental_CommerceCheckoutResource,
44
__experimental_CommerceMoney,
55
__experimental_CommercePaymentSourceResource,
6+
__experimental_ConfirmCheckoutParams,
67
ClerkAPIError,
78
ClerkRuntimeError,
89
} from '@clerk/types';
10+
import type { SetupIntent } from '@stripe/stripe-js';
911
import { useMemo, useState } from 'react';
1012

1113
import { useCheckoutContext } from '../../contexts';
@@ -111,10 +113,10 @@ const CheckoutFormElements = ({
111113

112114
const { data: paymentSources } = data || { data: [] };
113115

114-
const confirmCheckout = async ({ paymentSourceId }: { paymentSourceId: string }) => {
116+
const confirmCheckout = async (params: __experimental_ConfirmCheckoutParams) => {
115117
try {
116118
const newCheckout = await checkout.confirm({
117-
paymentSourceId,
119+
...params,
118120
...(subscriberType === 'org' ? { orgId: organization?.id } : {}),
119121
});
120122
onCheckoutComplete(newCheckout);
@@ -131,12 +133,19 @@ const CheckoutFormElements = ({
131133
const data = new FormData(e.currentTarget);
132134
const paymentSourceId = data.get('payment_source_id') as string;
133135

134-
await confirmCheckout({ paymentSourceId });
136+
await confirmCheckout({
137+
paymentSourceId,
138+
...(subscriberType === 'org' ? { orgId: organization?.id } : {}),
139+
});
135140
setIsSubmitting(false);
136141
};
137142

138-
const onAddPaymentSourceSuccess = async (paymentSource: __experimental_CommercePaymentSourceResource) => {
139-
await confirmCheckout({ paymentSourceId: paymentSource.id });
143+
const onAddPaymentSourceSuccess = async (ctx: { stripeSetupIntent?: SetupIntent }) => {
144+
await confirmCheckout({
145+
gateway: 'stripe',
146+
paymentToken: ctx.stripeSetupIntent?.payment_method as string,
147+
...(subscriberType === 'org' ? { orgId: organization?.id } : {}),
148+
});
140149
setIsSubmitting(false);
141150
};
142151

packages/clerk-js/src/ui/components/PaymentSources/AddPaymentSource.tsx

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import { useClerk, useOrganization, useUser } from '@clerk/shared/react';
2-
import type {
3-
__experimental_CommerceCheckoutResource,
4-
__experimental_CommercePaymentSourceResource,
5-
ClerkAPIError,
6-
ClerkRuntimeError,
7-
} from '@clerk/types';
2+
import type { __experimental_CommerceCheckoutResource, ClerkAPIError, ClerkRuntimeError } from '@clerk/types';
83
import { Elements, PaymentElement, useElements, useStripe } from '@stripe/react-stripe-js';
9-
import type { Appearance as StripeAppearance, Stripe } from '@stripe/stripe-js';
4+
import type { Appearance as StripeAppearance, SetupIntent, Stripe } from '@stripe/stripe-js';
105
import { loadStripe } from '@stripe/stripe-js';
116
import { useEffect, useRef, useState } from 'react';
127

@@ -20,7 +15,7 @@ import { animations } from '../../styledSystem';
2015
import { handleError, normalizeColorString } from '../../utils';
2116

2217
type AddPaymentSourceProps = {
23-
onSuccess: (paymentSource: __experimental_CommercePaymentSourceResource) => Promise<void>;
18+
onSuccess: (context: { stripeSetupIntent?: SetupIntent }) => Promise<void>;
2419
checkout?: __experimental_CommerceCheckoutResource;
2520
submitLabel?: LocalizationKey;
2621
cancelAction?: () => void;
@@ -136,7 +131,6 @@ export const AddPaymentSource = (props: AddPaymentSourceProps) => {
136131

137132
const AddPaymentSourceForm = withCardStateProvider(
138133
({ submitLabel, onSuccess, cancelAction, checkout }: AddPaymentSourceProps) => {
139-
const { __experimental_commerce } = useClerk();
140134
const stripe = useStripe();
141135
const elements = useElements();
142136
const { displayConfig } = useEnvironment();
@@ -174,15 +168,9 @@ const AddPaymentSourceForm = withCardStateProvider(
174168
return; // just return, since stripe will handle the error
175169
}
176170

177-
const paymentSource = await __experimental_commerce.addPaymentSource({
178-
gateway: 'stripe',
179-
paymentToken: setupIntent.payment_method as string,
180-
...(subscriberType === 'org' ? { orgId: organization?.id } : {}),
181-
});
171+
await onSuccess({ stripeSetupIntent: setupIntent });
182172

183173
revalidate();
184-
185-
void onSuccess(paymentSource);
186174
} catch (error) {
187175
void handleError(error, [], setSubmitError);
188176
}

packages/clerk-js/src/ui/components/PaymentSources/PaymentSources.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useClerk, useOrganization, useUser } from '@clerk/shared/react';
22
import type { __experimental_CommercePaymentSourceResource } from '@clerk/types';
3+
import type { SetupIntent } from '@stripe/stripe-js';
34
import { Fragment, useRef } from 'react';
45

56
import { RemoveResourceForm } from '../../common';
@@ -15,8 +16,16 @@ import { PaymentSourceRow } from './PaymentSourceRow';
1516

1617
const AddScreen = ({ onSuccess }: { onSuccess: () => void }) => {
1718
const { close } = useActionContext();
19+
const { __experimental_commerce } = useClerk();
20+
const subscriberType = useSubscriberTypeContext();
21+
const { organization } = useOrganization();
1822

19-
const onAddPaymentSourceSuccess = (_: __experimental_CommercePaymentSourceResource) => {
23+
const onAddPaymentSourceSuccess = async (context: { stripeSetupIntent?: SetupIntent }) => {
24+
await __experimental_commerce.addPaymentSource({
25+
gateway: 'stripe',
26+
paymentToken: context.stripeSetupIntent?.payment_method as string,
27+
...(subscriberType === 'org' ? { orgId: organization?.id } : {}),
28+
});
2029
onSuccess();
2130
close();
2231
return Promise.resolve();

packages/types/src/commerce.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,14 @@ export type __experimental_CommercePaymentSourceStatus = 'active' | 'expired' |
7777

7878
export type __experimental_GetPaymentSourcesParams = WithOptionalOrgType<ClerkPaginationParams>;
7979

80+
export type __experimental_PaymentGateway = 'stripe' | 'paypal';
81+
8082
export type __experimental_InitializePaymentSourceParams = WithOptionalOrgType<{
81-
gateway: 'stripe' | 'paypal';
83+
gateway: __experimental_PaymentGateway;
8284
}>;
8385

8486
export type __experimental_AddPaymentSourceParams = WithOptionalOrgType<{
85-
gateway: 'stripe' | 'paypal';
87+
gateway: __experimental_PaymentGateway;
8688
paymentToken: string;
8789
}>;
8890

@@ -156,10 +158,15 @@ export type __experimental_CreateCheckoutParams = WithOptionalOrgType<{
156158
planPeriod: __experimental_CommerceSubscriptionPlanPeriod;
157159
}>;
158160

159-
export type __experimental_ConfirmCheckoutParams = WithOptionalOrgType<{
160-
paymentSourceId?: string;
161-
}>;
162-
161+
export type __experimental_ConfirmCheckoutParams = WithOptionalOrgType<
162+
| {
163+
paymentSourceId?: string;
164+
}
165+
| {
166+
paymentToken?: string;
167+
gateway?: __experimental_PaymentGateway;
168+
}
169+
>;
163170
export interface __experimental_CommerceCheckoutResource extends ClerkResource {
164171
id: string;
165172
externalClientSecret: string;

0 commit comments

Comments
 (0)