11import { 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' ;
33import { Header , LineItems } from '../../elements' ;
4+ import { useClipboard } from '../../hooks' ;
5+ import { Check , Copy } from '../../icons' ;
46import { useRouter } from '../../router' ;
57import { common } from '../../styledSystem' ;
68import { 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+ }
0 commit comments