Skip to content

Commit bffb42a

Browse files
authored
chore(clerk-js, shared): Use experimental paginated hooks for querying commerce data (#6159)
1 parent 5bf85d9 commit bffb42a

File tree

18 files changed

+351
-89
lines changed

18 files changed

+351
-89
lines changed

.changeset/smart-pandas-carry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
---
4+
5+
Use hooks exported from `@clerk/shared` to query commerce data.

.changeset/violet-terms-fix.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@clerk/shared': minor
3+
'@clerk/types': minor
4+
---
5+
6+
Introduce experimental paginated hooks for commerce data.
7+
- `useStatements`
8+
- `usePaymentAttempts`
9+
- `usePaymentMethods`
10+
Prefixed with `__experimental_`

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { Select, SelectButton, SelectOptionList } from '@/ui/elements/Select';
1717
import { Tooltip } from '@/ui/elements/Tooltip';
1818

1919
import { DevOnly } from '../../common/DevOnly';
20-
import { useCheckoutContext, usePaymentSources } from '../../contexts';
20+
import { useCheckoutContext, usePaymentMethods } from '../../contexts';
2121
import { Box, Button, Col, descriptors, Flex, Form, localizationKeys, Text } from '../../customizables';
2222
import { ChevronUpDown, InformationCircle } from '../../icons';
2323
import { handleError } from '../../utils';
@@ -191,8 +191,7 @@ const useCheckoutMutations = () => {
191191
};
192192

193193
const CheckoutFormElements = ({ checkout }: { checkout: CommerceCheckoutResource }) => {
194-
const { data } = usePaymentSources();
195-
const { data: paymentSources } = data || { data: [] };
194+
const { data: paymentSources } = usePaymentMethods();
196195

197196
const [paymentMethodSource, setPaymentMethodSource] = useState<PaymentMethodSource>(() =>
198197
paymentSources.length > 0 ? 'existing' : 'new',

packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptsList.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ import { formatDate, truncateWithEndVisible } from '../../utils';
1212
* -----------------------------------------------------------------------------------------------*/
1313

1414
export const PaymentAttemptsList = () => {
15-
const { data: paymentAttempts, isLoading } = usePaymentAttempts();
15+
const { data: paymentAttempts, isLoading, count } = usePaymentAttempts();
1616
const localizationRoot = useSubscriberTypeLocalizationRoot();
1717

1818
return (
1919
<DataTable
2020
page={1}
2121
onPageChange={_ => {}}
22-
itemCount={paymentAttempts?.total_count || 0}
22+
itemCount={count}
2323
pageCount={1}
2424
itemsPerPage={10}
2525
isLoading={isLoading}
@@ -29,7 +29,7 @@ export const PaymentAttemptsList = () => {
2929
localizationKeys(`${localizationRoot}.billingPage.paymentHistorySection.tableHeader__amount`),
3030
localizationKeys(`${localizationRoot}.billingPage.paymentHistorySection.tableHeader__status`),
3131
]}
32-
rows={(paymentAttempts?.data || []).map(i => (
32+
rows={paymentAttempts.map(i => (
3333
<PaymentAttemptsListRow
3434
key={i.id}
3535
paymentAttempt={i}

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

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useClerk, useOrganization } from '@clerk/shared/react';
22
import type { CommercePaymentSourceResource } from '@clerk/types';
33
import type { SetupIntent } from '@stripe/stripe-js';
4-
import { Fragment, useCallback, useMemo, useRef } from 'react';
4+
import { Fragment, useMemo, useRef } from 'react';
55

66
import { useCardState, withCardStateProvider } from '@/ui/elements/contexts';
77
import { FullHeightLoader } from '@/ui/elements/FullHeightLoader';
@@ -10,7 +10,7 @@ import { ThreeDotsMenu } from '@/ui/elements/ThreeDotsMenu';
1010

1111
import { RemoveResourceForm } from '../../common';
1212
import { DevOnly } from '../../common/DevOnly';
13-
import { usePaymentSources, useSubscriberTypeContext, useSubscriberTypeLocalizationRoot } from '../../contexts';
13+
import { usePaymentMethods, useSubscriberTypeContext, useSubscriberTypeLocalizationRoot } from '../../contexts';
1414
import { localizationKeys } from '../../customizables';
1515
import { Action } from '../../elements/Action';
1616
import { useActionContext } from '../../elements/Action/ActionRoot';
@@ -114,17 +114,13 @@ export const PaymentSources = withCardStateProvider(() => {
114114
const localizationRoot = useSubscriberTypeLocalizationRoot();
115115
const resource = subscriberType === 'org' ? clerk?.organization : clerk.user;
116116

117-
const { data, isLoading, mutate: mutatePaymentSources } = usePaymentSources();
118-
119-
const { data: paymentSources = [] } = data || {};
117+
const { data: paymentMethods, isLoading, revalidate: revalidatePaymentMethods } = usePaymentMethods();
120118

121119
const sortedPaymentSources = useMemo(
122-
() => paymentSources.sort((a, b) => (a.isDefault && !b.isDefault ? -1 : 1)),
123-
[paymentSources],
120+
() => paymentMethods.sort((a, b) => (a.isDefault && !b.isDefault ? -1 : 1)),
121+
[paymentMethods],
124122
);
125123

126-
const revalidatePaymentSources = useCallback(() => void mutatePaymentSources(), [mutatePaymentSources]);
127-
128124
if (!resource) {
129125
return null;
130126
}
@@ -156,15 +152,15 @@ export const PaymentSources = withCardStateProvider(() => {
156152
<PaymentSourceRow paymentSource={paymentSource} />
157153
<PaymentSourceMenu
158154
paymentSource={paymentSource}
159-
revalidate={revalidatePaymentSources}
155+
revalidate={revalidatePaymentMethods}
160156
/>
161157
</ProfileSection.Item>
162158

163159
<Action.Open value={`remove-${paymentSource.id}`}>
164160
<Action.Card variant='destructive'>
165161
<RemoveScreen
166162
paymentSource={paymentSource}
167-
revalidate={revalidatePaymentSources}
163+
revalidate={revalidatePaymentMethods}
168164
/>
169165
</Action.Card>
170166
</Action.Open>
@@ -178,7 +174,7 @@ export const PaymentSources = withCardStateProvider(() => {
178174
</Action.Trigger>
179175
<Action.Open value='add'>
180176
<Action.Card>
181-
<AddScreen onSuccess={revalidatePaymentSources} />
177+
<AddScreen onSuccess={revalidatePaymentMethods} />
182178
</Action.Card>
183179
</Action.Open>
184180
</>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useClerk } from '@clerk/shared/react';
22
import type { CommercePlanResource, CommerceSubscriptionPlanPeriod, PricingTableProps } from '@clerk/types';
33
import { useEffect, useMemo, useState } from 'react';
44

5-
import { usePaymentSources, usePlans, usePlansContext, usePricingTableContext, useSubscriptions } from '../../contexts';
5+
import { usePaymentMethods, usePlans, usePlansContext, usePricingTableContext, useSubscriptions } from '../../contexts';
66
import { Flow } from '../../customizables';
77
import { PricingTableDefault } from './PricingTableDefault';
88
import { PricingTableMatrix } from './PricingTableMatrix';
@@ -60,7 +60,7 @@ const PricingTableRoot = (props: PricingTableProps) => {
6060
};
6161

6262
// Pre-fetch payment sources
63-
usePaymentSources();
63+
usePaymentMethods();
6464

6565
return (
6666
<Flow.Root

packages/clerk-js/src/ui/components/Statements/StatementsList.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ import { truncateWithEndVisible } from '../../utils/truncateTextWithEndVisible';
1313
* -----------------------------------------------------------------------------------------------*/
1414

1515
export const StatementsList = () => {
16-
const { data: statements, isLoading } = useStatements();
16+
const { data: statements, isLoading, count } = useStatements();
1717
const localizationRoot = useSubscriberTypeLocalizationRoot();
1818

1919
return (
2020
<DataTable
2121
page={1}
2222
onPageChange={_ => {}}
23-
itemCount={statements?.total_count || 0}
23+
itemCount={count}
2424
pageCount={1}
2525
itemsPerPage={10}
2626
isLoading={isLoading}
@@ -29,7 +29,7 @@ export const StatementsList = () => {
2929
localizationKeys(`${localizationRoot}.billingPage.statementsSection.tableHeader__date`),
3030
localizationKeys(`${localizationRoot}.billingPage.statementsSection.tableHeader__amount`),
3131
]}
32-
rows={(statements?.data || []).map(i => (
32+
rows={statements.map(i => (
3333
<StatementsListRow
3434
key={i.id}
3535
statement={i}

packages/clerk-js/src/ui/contexts/components/PaymentAttempts.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ export const usePaymentAttemptsContext = () => {
66
const { data: payments } = usePaymentAttempts();
77
const getPaymentAttemptById = useCallback(
88
(paymentAttemptId: string) => {
9-
return payments?.data.find(payment => payment.id === paymentAttemptId);
9+
return payments.find(payment => payment.id === paymentAttemptId);
1010
},
11-
[payments?.data],
11+
[payments],
1212
);
1313

1414
return {

packages/clerk-js/src/ui/contexts/components/Plans.tsx

Lines changed: 39 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { useClerk, useOrganization, useSession, useUser } from '@clerk/shared/react';
1+
import {
2+
__experimental_usePaymentAttempts,
3+
__experimental_usePaymentMethods,
4+
__experimental_useStatements,
5+
useClerk,
6+
useOrganization,
7+
useSession,
8+
useUser,
9+
} from '@clerk/shared/react';
210
import type {
311
Appearance,
412
CommercePlanResource,
@@ -8,7 +16,8 @@ import type {
816
import { useCallback, useMemo } from 'react';
917
import useSWR from 'swr';
1018

11-
import { CommerceSubscription } from '../../../core/resources/internal';
19+
import { CommerceSubscription } from '@/core/resources/CommerceSubscription';
20+
1221
import type { LocalizationKey } from '../../localization';
1322
import { localizationKeys } from '../../localization';
1423
import { getClosestProfileScrollBox } from '../../utils';
@@ -30,51 +39,36 @@ export const usePaymentSourcesCacheKey = () => {
3039
};
3140
};
3241

33-
export const usePaymentSources = () => {
34-
const { organization } = useOrganization();
35-
const { user } = useUser();
36-
const subscriberType = useSubscriberTypeContext();
37-
const cacheKey = usePaymentSourcesCacheKey();
38-
39-
return useSWR(cacheKey, () => (subscriberType === 'org' ? organization : user)?.getPaymentSources({}), dedupeOptions);
40-
};
41-
42-
export const usePaymentAttemptsCacheKey = () => {
43-
const { organization } = useOrganization();
44-
const { user } = useUser();
42+
// TODO(@COMMERCE): Rename payment sources to payment methods at the API level
43+
export const usePaymentMethods = () => {
4544
const subscriberType = useSubscriberTypeContext();
46-
47-
return {
48-
key: `commerce-payment-history`,
49-
userId: user?.id,
50-
args: { orgId: subscriberType === 'org' ? organization?.id : undefined },
51-
};
45+
return __experimental_usePaymentMethods({
46+
for: subscriberType === 'org' ? 'organization' : 'user',
47+
initialPage: 1,
48+
pageSize: 10,
49+
keepPreviousData: true,
50+
});
5251
};
5352

5453
export const usePaymentAttempts = () => {
55-
const { billing } = useClerk();
56-
const cacheKey = usePaymentAttemptsCacheKey();
57-
58-
return useSWR(cacheKey, ({ args, userId }) => (userId ? billing.getPaymentAttempts(args) : undefined), dedupeOptions);
59-
};
60-
61-
export const useStatementsCacheKey = () => {
62-
const { organization } = useOrganization();
63-
const { user } = useUser();
6454
const subscriberType = useSubscriberTypeContext();
65-
66-
return {
67-
key: `commerce-statements`,
68-
userId: user?.id,
69-
args: { orgId: subscriberType === 'org' ? organization?.id : undefined },
70-
};
55+
return __experimental_usePaymentAttempts({
56+
for: subscriberType === 'org' ? 'organization' : 'user',
57+
initialPage: 1,
58+
pageSize: 10,
59+
keepPreviousData: true,
60+
});
7161
};
7262

73-
export const useStatements = () => {
74-
const { billing } = useClerk();
75-
const cacheKey = useStatementsCacheKey();
76-
77-
return useSWR(cacheKey, ({ args, userId }) => (userId ? billing.getStatements(args) : undefined), dedupeOptions);
63+
export const useStatements = (params?: { mode: 'cache' }) => {
64+
const subscriberType = useSubscriberTypeContext();
65+
return __experimental_useStatements({
66+
for: subscriberType === 'org' ? 'organization' : 'user',
67+
initialPage: 1,
68+
pageSize: 10,
69+
keepPreviousData: true,
70+
__experimental_mode: params?.mode,
71+
});
7872
};
7973

8074
export const useSubscriptions = () => {
@@ -181,18 +175,17 @@ export const usePlansContext = () => {
181175
});
182176

183177
// Invalidates cache but does not fetch immediately
184-
const { mutate: mutateStatements } =
185-
useSWR<Awaited<ReturnType<typeof clerk.billing.getStatements>>>(useStatementsCacheKey());
178+
const { revalidate: revalidateStatements } = useStatements({ mode: 'cache' });
186179

187-
const { mutate: mutatePaymentSources } = usePaymentSources();
180+
const { revalidate: revalidatePaymentSources } = usePaymentMethods();
188181

189182
const revalidateAll = useCallback(() => {
190183
// Revalidate the plans and subscriptions
191184
void mutateSubscriptions();
192185
void mutatePlans();
193-
void mutateStatements();
194-
void mutatePaymentSources();
195-
}, [mutateSubscriptions, mutatePlans, mutateStatements, mutatePaymentSources]);
186+
void revalidateStatements();
187+
void revalidatePaymentSources();
188+
}, [mutateSubscriptions, mutatePlans, revalidateStatements, revalidatePaymentSources]);
196189

197190
// should the default plan be shown as active
198191
const isDefaultPlanImplicitlyActiveOrUpcoming = useMemo(() => {

packages/clerk-js/src/ui/contexts/components/Statements.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ export const useStatementsContext = () => {
66
const { data: statements } = useStatements();
77
const getStatementById = useCallback(
88
(statementId: string) => {
9-
return statements?.data.find(statement => statement.id === statementId);
9+
return statements.find(statement => statement.id === statementId);
1010
},
11-
[statements?.data],
11+
[statements],
1212
);
1313

1414
return {

0 commit comments

Comments
 (0)