Skip to content

Commit 45486ac

Browse files
refactor(clerk-js): Invoice page title (#5655)
1 parent ea84f6b commit 45486ac

5 files changed

Lines changed: 103 additions & 11 deletions

File tree

.changeset/forty-peaches-stay.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+
Refactor InvoicePage title and invoice ID UI.

packages/clerk-js/bundlewatch.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"files": [
3-
{ "path": "./dist/clerk.js", "maxSize": "592.5kB" },
3+
{ "path": "./dist/clerk.js", "maxSize": "593kB" },
44
{ "path": "./dist/clerk.browser.js", "maxSize": "74KB" },
55
{ "path": "./dist/clerk.headless*.js", "maxSize": "55KB" },
66
{ "path": "./dist/ui-common*.js", "maxSize": "100KB" },

packages/clerk-js/src/ui/components/Invoices/InvoicePage.tsx

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { useInvoicesContext } from '../../contexts';
2-
import { Badge, Box, Dd, descriptors, Dl, Dt, Heading, Spinner, Text } from '../../customizables';
2+
import { Badge, Box, Button, Dd, descriptors, Dl, Dt, Heading, Icon, Span, Spinner, Text } from '../../customizables';
33
import { Header, LineItems } from '../../elements';
4+
import { useClipboard } from '../../hooks';
5+
import { Check, Copy } from '../../icons';
46
import { useRouter } from '../../router';
57
import { common } from '../../styledSystem';
68
import { colors } from '../../utils';
@@ -76,18 +78,43 @@ export const InvoicePage = () => {
7678
})}
7779
>
7880
<Box
81+
elementDescriptor={descriptors.invoiceHeaderTitleBadgeContainer}
7982
sx={{
8083
display: 'flex',
8184
justifyContent: 'space-between',
82-
alignItems: 'center',
85+
alignItems: 'start',
8386
}}
8487
>
85-
<Heading
86-
textVariant='h2'
87-
elementDescriptor={descriptors.invoiceTitle}
88-
>
89-
{truncateWithEndVisible(invoice.id)}
90-
</Heading>
88+
<Span elementDescriptor={descriptors.invoiceTitleIdContainer}>
89+
<Heading
90+
textVariant='h2'
91+
elementDescriptor={descriptors.invoiceTitle}
92+
>
93+
Invoice ID
94+
</Heading>
95+
<Span
96+
elementDescriptor={descriptors.invoiceIdContainer}
97+
sx={t => ({
98+
display: 'flex',
99+
alignItems: 'center',
100+
gap: t.space.$0x25,
101+
color: t.colors.$colorTextSecondary,
102+
})}
103+
>
104+
<CopyButton
105+
copyLabel='Copy invoice ID'
106+
text={invoice.id}
107+
/>
108+
<Text
109+
elementDescriptor={descriptors.invoiceId}
110+
colorScheme='secondary'
111+
variant='subtitle'
112+
>
113+
{truncateWithEndVisible(invoice.id)}
114+
</Text>
115+
</Span>
116+
</Span>
117+
91118
<Badge
92119
elementDescriptor={descriptors.invoiceBadge}
93120
colorScheme={
@@ -109,14 +136,20 @@ export const InvoicePage = () => {
109136
<Box elementDescriptor={descriptors.invoiceDetailsItem}>
110137
<Dt elementDescriptor={descriptors.invoiceDetailsItemTitle}>
111138
<Text
139+
elementDescriptor={descriptors.invoiceDetailsItemTitleText}
112140
colorScheme='secondary'
113141
variant='body'
114142
>
115143
Created on
116144
</Text>
117145
</Dt>
118146
<Dd elementDescriptor={descriptors.invoiceDetailsItemValue}>
119-
<Text variant='subtitle'>{new Date(invoice.paymentDueOn).toLocaleDateString()}</Text>
147+
<Text
148+
elementDescriptor={descriptors.invoiceDetailsItemValueText}
149+
variant='subtitle'
150+
>
151+
{new Date(invoice.paymentDueOn).toLocaleDateString()}
152+
</Text>
120153
</Dd>
121154
</Box>
122155
<Box
@@ -127,14 +160,20 @@ export const InvoicePage = () => {
127160
>
128161
<Dt elementDescriptor={descriptors.invoiceDetailsItemTitle}>
129162
<Text
163+
elementDescriptor={descriptors.invoiceDetailsItemTitleText}
130164
colorScheme='secondary'
131165
variant='body'
132166
>
133167
Due on
134168
</Text>
135169
</Dt>
136170
<Dd elementDescriptor={descriptors.invoiceDetailsItemValue}>
137-
<Text variant='subtitle'>{new Date(invoice.paymentDueOn).toLocaleDateString()}</Text>
171+
<Text
172+
elementDescriptor={descriptors.invoiceDetailsItemValueText}
173+
variant='subtitle'
174+
>
175+
{new Date(invoice.paymentDueOn).toLocaleDateString()}
176+
</Text>
138177
</Dd>
139178
</Box>
140179
</Dl>
@@ -183,3 +222,34 @@ export const InvoicePage = () => {
183222
</>
184223
);
185224
};
225+
226+
function CopyButton({ text, copyLabel = 'Copy' }: { text: string; copyLabel?: string }) {
227+
const { onCopy, hasCopied } = useClipboard(text);
228+
229+
return (
230+
<Button
231+
elementDescriptor={descriptors.invoiceCopyButton}
232+
variant='unstyled'
233+
onClick={onCopy}
234+
sx={t => ({
235+
color: 'inherit',
236+
width: t.sizes.$4,
237+
height: t.sizes.$4,
238+
padding: 0,
239+
borderRadius: t.radii.$sm,
240+
'&:focus-visible': {
241+
outline: '2px solid',
242+
outlineColor: t.colors.$neutralAlpha200,
243+
},
244+
})}
245+
focusRing={false}
246+
aria-label={hasCopied ? 'Copied' : copyLabel}
247+
>
248+
<Icon
249+
size='sm'
250+
icon={hasCopied ? Check : Copy}
251+
aria-hidden
252+
/>
253+
</Button>
254+
);
255+
}

packages/clerk-js/src/ui/customizables/elementDescriptors.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,12 +343,20 @@ export const APPEARANCE_KEYS = containsAllElementsConfigKeys([
343343
'invoiceRoot',
344344
'invoiceCard',
345345
'invoiceHeader',
346+
'invoiceHeaderContent',
346347
'invoiceTitle',
348+
'invoiceHeaderTitleBadgeContainer',
349+
'invoiceId',
350+
'invoiceIdContainer',
351+
'invoiceTitleIdContainer',
347352
'invoiceBadge',
348353
'invoiceDetails',
349354
'invoiceDetailsItem',
350355
'invoiceDetailsItemTitle',
356+
'invoiceDetailsItemTitleText',
351357
'invoiceDetailsItemValue',
358+
'invoiceDetailsItemValueText',
359+
'invoiceCopyButton',
352360
'invoiceContent',
353361

354362
'menuButton',

packages/types/src/appearance.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,12 +467,20 @@ export type ElementsConfig = {
467467
invoiceRoot: WithOptions;
468468
invoiceCard: WithOptions;
469469
invoiceHeader: WithOptions;
470+
invoiceHeaderContent: WithOptions;
470471
invoiceTitle: WithOptions;
472+
invoiceHeaderTitleBadgeContainer: WithOptions;
473+
invoiceTitleIdContainer: WithOptions;
474+
invoiceId: WithOptions;
475+
invoiceIdContainer: WithOptions;
471476
invoiceBadge: WithOptions;
472477
invoiceDetails: WithOptions;
473478
invoiceDetailsItem: WithOptions;
474479
invoiceDetailsItemTitle: WithOptions;
480+
invoiceDetailsItemTitleText: WithOptions;
475481
invoiceDetailsItemValue: WithOptions;
482+
invoiceDetailsItemValueText: WithOptions;
483+
invoiceCopyButton: WithOptions;
476484
invoiceContent: WithOptions;
477485

478486
menuButton: WithOptions<MenuId>;

0 commit comments

Comments
 (0)