Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
7 changes: 7 additions & 0 deletions .changeset/soft-toys-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@clerk/localizations': patch
'@clerk/clerk-js': patch
'@clerk/types': patch
---

Add localizations for some commerce strings, general cleanups
4 changes: 2 additions & 2 deletions packages/clerk-js/bundlewatch.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{ "path": "./dist/clerk.browser.js", "maxSize": "69.3KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "113KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "53KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "106.3KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "107.5KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
{ "path": "./dist/coinbase*.js", "maxSize": "38KB" },
{ "path": "./dist/createorganization*.js", "maxSize": "5KB" },
Expand All @@ -22,7 +22,7 @@
{ "path": "./dist/keylessPrompt*.js", "maxSize": "6.5KB" },
{ "path": "./dist/pricingTable*.js", "maxSize": "4.02KB" },
{ "path": "./dist/checkout*.js", "maxSize": "7.25KB" },
{ "path": "./dist/paymentSources*.js", "maxSize": "9.15KB" },
{ "path": "./dist/paymentSources*.js", "maxSize": "9.17KB" },
{ "path": "./dist/up-billing-page*.js", "maxSize": "3.0KB" },
{ "path": "./dist/op-billing-page*.js", "maxSize": "3.0KB" },
{ "path": "./dist/sessionTasks*.js", "maxSize": "1KB" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class CommerceInitializedPaymentSource extends BaseResource implements Co

this.externalClientSecret = data.external_client_secret;
this.externalGatewayId = data.external_gateway_id;
this.paymentMethodOrder = data.payment_method_order;
this.paymentMethodOrder = data.payment_method_order ?? ['card'];
return this;
}
}
9 changes: 4 additions & 5 deletions packages/clerk-js/src/core/resources/CommerceSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@ export class CommerceSettings extends BaseResource implements CommerceSettingsRe
return this;
}

// TODO(@commerce): Remove `?.` once we launch.
this.billing.stripePublishableKey = data?.billing?.stripe_publishable_key || '';
this.billing.enabled = data?.billing?.enabled || false;
this.billing.hasPaidUserPlans = data?.billing?.has_paid_user_plans || false;
this.billing.hasPaidOrgPlans = data?.billing?.has_paid_org_plans || false;
this.billing.stripePublishableKey = data.billing.stripe_publishable_key || '';
this.billing.enabled = data.billing.enabled || false;
this.billing.hasPaidUserPlans = data.billing.has_paid_user_plans || false;
this.billing.hasPaidOrgPlans = data.billing.has_paid_org_plans || false;

return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ const OrganizationPlansPageInternal = () => {
paddingBlockEnd: t.space.$4,
})}
>
<Header.BackLink onClick={() => void navigate('../', { searchParams: new URLSearchParams('tab=plans') })}>
<Header.BackLink
onClick={() => void navigate('../', { searchParams: new URLSearchParams('tab=subscriptions') })}
>
<Header.Title
localizationKey={localizationKeys('organizationProfile.plansPage.title')}
textVariant='h2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Header } from '@/ui/elements/Header';
import { LineItems } from '@/ui/elements/LineItems';

import { usePaymentAttemptsContext, useStatements } from '../../contexts';
import { useSubscriberTypeLocalizationRoot } from '../../contexts/components';
import {
Badge,
Box,
Expand All @@ -17,12 +18,13 @@ import {
import { useClipboard } from '../../hooks';
import { Check, Copy } from '../../icons';
import { useRouter } from '../../router';
import { truncateWithEndVisible } from '../../utils/truncateTextWithEndVisible';
import { formatDate, truncateWithEndVisible } from '../../utils';

export const PaymentAttemptPage = () => {
const { params, navigate } = useRouter();
const { isLoading } = useStatements();
const { getPaymentAttemptById } = usePaymentAttemptsContext();
const localizationRoot = useSubscriberTypeLocalizationRoot();

const paymentAttempt = params.paymentAttemptId ? getPaymentAttemptById(params.paymentAttemptId) : null;
const subscriptionItem = paymentAttempt?.subscriptionItem;
Expand All @@ -39,10 +41,6 @@ export const PaymentAttemptPage = () => {
);
}

if (!paymentAttempt) {
return <Text>Payment attempt not found</Text>;
}

return (
<>
<Header.Root
Expand All @@ -56,151 +54,159 @@ export const PaymentAttemptPage = () => {
>
<Header.BackLink onClick={() => void navigate('../../', { searchParams: new URLSearchParams('tab=payments') })}>
<Header.Title
localizationKey={localizationKeys('organizationProfile.billingPage.start.headerTitle__payments')}
localizationKey={localizationKeys(`${localizationRoot}.billingPage.start.headerTitle__payments`)}
textVariant='h2'
/>
</Header.BackLink>
</Header.Root>

<Box
elementDescriptor={descriptors.paymentAttemptRoot}
as='article'
sx={t => ({
borderWidth: t.borderWidths.$normal,
borderStyle: t.borderStyles.$solid,
borderColor: t.colors.$neutralAlpha100,
borderRadius: t.radii.$lg,
overflow: 'clip',
})}
>
{!paymentAttempt ? (
<Text
localizationKey={localizationKeys(`${localizationRoot}.billingPage.paymentHistorySection.notFound`)}
sx={{ textAlign: 'center' }}
/>
) : (
<Box
elementDescriptor={descriptors.paymentAttemptHeader}
as='header'
elementDescriptor={descriptors.paymentAttemptRoot}
as='article'
sx={t => ({
padding: t.space.$4,
background: t.colors.$neutralAlpha25,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'flex-start',
borderWidth: t.borderWidths.$normal,
borderStyle: t.borderStyles.$solid,
borderColor: t.colors.$neutralAlpha100,
borderRadius: t.radii.$lg,
overflow: 'clip',
})}
>
<Span elementDescriptor={descriptors.paymentAttemptHeaderTitleContainer}>
<Heading
elementDescriptor={descriptors.paymentAttemptHeaderTitle}
textVariant='h2'
localizationKey={new Date(
paymentAttempt.paidAt || paymentAttempt.failedAt || paymentAttempt.updatedAt,
).toLocaleString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })}
/>
<Span
sx={t => ({
display: 'flex',
alignItems: 'center',
gap: t.space.$0x25,
color: t.colors.$colorTextSecondary,
})}
>
<CopyButton
copyLabel='Copy payment attempt ID'
text={paymentAttempt.id}
<Box
elementDescriptor={descriptors.paymentAttemptHeader}
as='header'
sx={t => ({
padding: t.space.$4,
background: t.colors.$neutralAlpha25,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'flex-start',
})}
>
<Span elementDescriptor={descriptors.paymentAttemptHeaderTitleContainer}>
<Heading
elementDescriptor={descriptors.paymentAttemptHeaderTitle}
textVariant='h2'
localizationKey={formatDate(
new Date(paymentAttempt.paidAt || paymentAttempt.failedAt || paymentAttempt.updatedAt),
'long',
Comment thread
aeliox marked this conversation as resolved.
Outdated
)}
/>
<Text
colorScheme='secondary'
variant='subtitle'
<Span
sx={t => ({
display: 'flex',
alignItems: 'center',
gap: t.space.$0x25,
color: t.colors.$colorTextSecondary,
})}
>
{truncateWithEndVisible(paymentAttempt.id)}
</Text>
<CopyButton
copyLabel='Copy payment attempt ID'
text={paymentAttempt.id}
/>
<Text
colorScheme='secondary'
variant='subtitle'
>
{truncateWithEndVisible(paymentAttempt.id)}
</Text>
</Span>
</Span>
</Span>
<Badge
elementDescriptor={descriptors.paymentAttemptHeaderBadge}
colorScheme={
paymentAttempt.status === 'paid' ? 'success' : paymentAttempt.status === 'failed' ? 'danger' : 'primary'
}
sx={{ textTransform: 'capitalize' }}
<Badge
elementDescriptor={descriptors.paymentAttemptHeaderBadge}
colorScheme={
paymentAttempt.status === 'paid' ? 'success' : paymentAttempt.status === 'failed' ? 'danger' : 'primary'
}
sx={{ textTransform: 'capitalize' }}
>
{paymentAttempt.status}
</Badge>
</Box>
<Box
elementDescriptor={descriptors.paymentAttemptBody}
sx={t => ({
padding: t.space.$4,
})}
>
{paymentAttempt.status}
</Badge>
</Box>
<Box
elementDescriptor={descriptors.paymentAttemptBody}
sx={t => ({
padding: t.space.$4,
})}
>
{subscriptionItem && (
<LineItems.Root>
<LineItems.Group>
<LineItems.Title title={subscriptionItem.plan.name} />
<LineItems.Description
prefix={subscriptionItem.planPeriod === 'annual' ? 'x12' : undefined}
text={`${subscriptionItem.plan.currencySymbol}${subscriptionItem.planPeriod === 'month' ? subscriptionItem.plan.amountFormatted : subscriptionItem.plan.annualMonthlyAmountFormatted}`}
/>
</LineItems.Group>
<LineItems.Group
borderTop
variant='tertiary'
>
<LineItems.Title title={localizationKeys('commerce.subtotal')} />
<LineItems.Description
text={`${subscriptionItem.amount?.currencySymbol}${subscriptionItem.amount?.amountFormatted}`}
/>
</LineItems.Group>
{subscriptionItem.credit && subscriptionItem.credit.amount.amount > 0 && (
<LineItems.Group variant='tertiary'>
<LineItems.Title title={localizationKeys('commerce.credit')} />
{subscriptionItem && (
<LineItems.Root>
<LineItems.Group>
<LineItems.Title title={subscriptionItem.plan.name} />
<LineItems.Description
text={`- ${subscriptionItem.credit.amount.currencySymbol}${subscriptionItem.credit.amount.amountFormatted}`}
prefix={subscriptionItem.planPeriod === 'annual' ? 'x12' : undefined}
text={`${subscriptionItem.plan.currencySymbol}${subscriptionItem.planPeriod === 'month' ? subscriptionItem.plan.amountFormatted : subscriptionItem.plan.annualMonthlyAmountFormatted}`}
/>
</LineItems.Group>
)}
</LineItems.Root>
)}
</Box>
<Box
elementDescriptor={descriptors.paymentAttemptFooter}
as='footer'
sx={t => ({
paddingInline: t.space.$4,
paddingBlock: t.space.$3,
background: t.colors.$neutralAlpha25,
borderBlockStartWidth: t.borderWidths.$normal,
borderBlockStartStyle: t.borderStyles.$solid,
borderBlockStartColor: t.colors.$neutralAlpha100,
display: 'flex',
justifyContent: 'space-between',
})}
>
<Text
variant='h3'
localizationKey={'Total due'}
elementDescriptor={descriptors.paymentAttemptFooterLabel}
/>
<Span
elementDescriptor={descriptors.paymentAttemptFooterValueContainer}
<LineItems.Group
borderTop
variant='tertiary'
>
<LineItems.Title title={localizationKeys('commerce.subtotal')} />
<LineItems.Description
text={`${subscriptionItem.amount?.currencySymbol}${subscriptionItem.amount?.amountFormatted}`}
/>
</LineItems.Group>
{subscriptionItem.credit && subscriptionItem.credit.amount.amount > 0 && (
<LineItems.Group variant='tertiary'>
<LineItems.Title title={localizationKeys('commerce.credit')} />
<LineItems.Description
text={`- ${subscriptionItem.credit.amount.currencySymbol}${subscriptionItem.credit.amount.amountFormatted}`}
/>
</LineItems.Group>
)}
</LineItems.Root>
)}
</Box>
<Box
elementDescriptor={descriptors.paymentAttemptFooter}
as='footer'
sx={t => ({
paddingInline: t.space.$4,
paddingBlock: t.space.$3,
background: t.colors.$neutralAlpha25,
borderBlockStartWidth: t.borderWidths.$normal,
borderBlockStartStyle: t.borderStyles.$solid,
borderBlockStartColor: t.colors.$neutralAlpha100,
display: 'flex',
alignItems: 'center',
gap: t.space.$2x5,
justifyContent: 'space-between',
})}
>
<Text
variant='caption'
colorScheme='secondary'
elementDescriptor={descriptors.paymentAttemptFooterCurrency}
>
USD
</Text>
<Text
variant='h3'
elementDescriptor={descriptors.paymentAttemptFooterValue}
localizationKey={localizationKeys('commerce.totalDue')}
elementDescriptor={descriptors.paymentAttemptFooterLabel}
/>
<Span
elementDescriptor={descriptors.paymentAttemptFooterValueContainer}
sx={t => ({
display: 'flex',
alignItems: 'center',
gap: t.space.$2x5,
})}
>
{paymentAttempt.amount.currencySymbol}
{paymentAttempt.amount.amountFormatted}
</Text>
</Span>
<Text
variant='caption'
colorScheme='secondary'
elementDescriptor={descriptors.paymentAttemptFooterCurrency}
sx={{ textTransform: 'uppercase' }}
>
{paymentAttempt.amount.currency}
</Text>
<Text
variant='h3'
elementDescriptor={descriptors.paymentAttemptFooterValue}
>
{paymentAttempt.amount.currencySymbol}
{paymentAttempt.amount.amountFormatted}
</Text>
</Span>
</Box>
</Box>
</Box>
)}
</>
);
};
Expand Down
Loading
Loading