@@ -2,6 +2,16 @@ import { type KyselyNotNull, sqliteTrue } from "@evolu/common"
22import { Link } from "@tanstack/react-router"
33import { ReceiptIcon } from "lucide-react"
44import { type ReactNode , useMemo } from "react"
5+ import {
6+ Timeline ,
7+ TimelineContent ,
8+ TimelineDate ,
9+ TimelineHeader ,
10+ TimelineIndicator ,
11+ TimelineItem ,
12+ TimelineSeparator ,
13+ TimelineTitle ,
14+ } from "@/components/reui/timeline.tsx"
515import { Badge } from "@/components/ui/badge.tsx"
616import { Button } from "@/components/ui/button.tsx"
717import {
@@ -335,116 +345,122 @@ function PaymentDetailContent({
335345 < CardHeader >
336346 < CardTitle > { t ( "paymentDetail.reconciliations" ) } </ CardTitle >
337347 </ CardHeader >
338- < CardContent className = "flex flex-col gap-3" >
348+ < CardContent >
339349 { reconciliations . length === 0 ? (
340350 < p className = "text-sm text-muted-foreground" >
341351 { t ( "paymentDetail.reconciliations.empty" ) }
342352 </ p >
343353 ) : (
344- reconciliations . map ( ( reconciliation ) => (
345- < div
346- key = { reconciliation . id }
347- className = "rounded-lg border bg-muted/20 p-3"
348- >
349- < div className = "mb-3 flex items-start justify-between gap-4" >
350- < div className = "flex flex-col gap-1" >
351- < span className = "text-sm font-semibold" >
354+ < Timeline value = { reconciliations . length } >
355+ { reconciliations . map ( ( reconciliation , index ) => (
356+ < TimelineItem key = { reconciliation . id } step = { index + 1 } >
357+ < TimelineHeader >
358+ < TimelineDate >
359+ { formatDateTime (
360+ new Date ( reconciliation . claimedAt ) ,
361+ locale
362+ ) }
363+ </ TimelineDate >
364+ < TimelineTitle >
352365 { t ( paymentMethodLabelKey [ reconciliation . transactionKind ] ) }
353- </ span >
354- < span className = "break-all text-xs text-muted-foreground" >
355- { reconciliation . id }
356- </ span >
357- </ div >
358- < Badge variant = "secondary" >
359- { t ( claimSourceLabelKey [ reconciliation . source ] ) }
360- </ Badge >
361- </ div >
362- < div className = "flex flex-col gap-2" >
363- < PaymentDetailRow
364- label = { t ( "paymentDetail.reconciliation.claimedAt" ) }
365- value = { formatDateTime (
366- new Date ( reconciliation . claimedAt ) ,
367- locale
368- ) }
369- />
370- < PaymentDetailRow
371- label = { t ( "paymentDetail.transaction.id" ) }
372- value = {
373- reconciliation . accountTransactionId ??
374- t ( "paymentDetail.emptyValue" )
375- }
376- />
377- < PaymentDetailRow
378- label = { t ( "paymentDetail.transaction.account" ) }
379- value = {
380- reconciliation . accountName ??
381- reconciliation . accountId ??
382- t ( "paymentDetail.emptyValue" )
383- }
384- />
385- < PaymentDetailRow
386- label = { t ( "paymentDetail.transaction.amount" ) }
387- value = { formatMoney (
388- {
389- value : reconciliation . transactionAmount ,
390- currency : reconciliation . transactionCurrency ,
391- } ,
392- locale
393- ) }
394- />
395- < PaymentDetailRow
396- label = { t ( "paymentDetail.transaction.occurredAt" ) }
397- value = { formatDateTime (
398- new Date ( reconciliation . transactionOccurredAt ) ,
399- locale
400- ) }
401- />
402- < PaymentDetailRow
403- label = { t ( "paymentDetail.transaction.recordedAt" ) }
404- value = {
405- reconciliation . transactionRecordedAt === null
406- ? t ( "paymentDetail.emptyValue" )
407- : formatDateTime (
408- new Date ( reconciliation . transactionRecordedAt ) ,
366+ </ TimelineTitle >
367+ </ TimelineHeader >
368+ < TimelineIndicator />
369+ < TimelineSeparator />
370+ < TimelineContent >
371+ < div className = "mt-2 rounded-lg border bg-muted/20 p-3" >
372+ < div className = "mb-3 flex items-start justify-between gap-4" >
373+ < span className = "break-all text-xs text-muted-foreground" >
374+ { reconciliation . id }
375+ </ span >
376+ < Badge variant = "secondary" >
377+ { t ( claimSourceLabelKey [ reconciliation . source ] ) }
378+ </ Badge >
379+ </ div >
380+ < div className = "flex flex-col gap-2" >
381+ < PaymentDetailRow
382+ label = { t ( "paymentDetail.transaction.id" ) }
383+ value = {
384+ reconciliation . accountTransactionId ??
385+ t ( "paymentDetail.emptyValue" )
386+ }
387+ />
388+ < PaymentDetailRow
389+ label = { t ( "paymentDetail.transaction.account" ) }
390+ value = {
391+ reconciliation . accountName ??
392+ reconciliation . accountId ??
393+ t ( "paymentDetail.emptyValue" )
394+ }
395+ />
396+ < PaymentDetailRow
397+ label = { t ( "paymentDetail.transaction.amount" ) }
398+ value = { formatMoney (
399+ {
400+ value : reconciliation . transactionAmount ,
401+ currency : reconciliation . transactionCurrency ,
402+ } ,
403+ locale
404+ ) }
405+ />
406+ < PaymentDetailRow
407+ label = { t ( "paymentDetail.transaction.occurredAt" ) }
408+ value = { formatDateTime (
409+ new Date ( reconciliation . transactionOccurredAt ) ,
409410 locale
410- )
411- }
412- />
413- < PaymentDetailRow
414- label = { t ( "paymentDetail.transaction.source" ) }
415- value = {
416- reconciliation . transactionSource === null
417- ? t ( "paymentDetail.emptyValue" )
418- : t (
419- claimSourceLabelKey [
420- reconciliation . transactionSource
421- ]
422- )
423- }
424- />
425- < PaymentDetailOptionalRow
426- label = { t ( "paymentDetail.transaction.note" ) }
427- value = { reconciliation . transactionNote }
428- />
429- < PaymentDetailOptionalRow
430- label = { t ( "paymentDetail.transaction.variableSymbol" ) }
431- value = { reconciliation . variableSymbol }
432- />
433- < PaymentDetailOptionalRow
434- label = { t ( "paymentDetail.transaction.bankReference" ) }
435- value = { reconciliation . bankReference }
436- />
437- < PaymentDetailOptionalRow
438- label = { t ( "paymentDetail.transaction.sparkTransferId" ) }
439- value = { reconciliation . sparkTransferId }
440- />
441- < PaymentDetailOptionalRow
442- label = { t ( "paymentDetail.transaction.paymentHash" ) }
443- value = { reconciliation . paymentHash }
444- />
445- </ div >
446- </ div >
447- ) )
411+ ) }
412+ />
413+ < PaymentDetailRow
414+ label = { t ( "paymentDetail.transaction.recordedAt" ) }
415+ value = {
416+ reconciliation . transactionRecordedAt === null
417+ ? t ( "paymentDetail.emptyValue" )
418+ : formatDateTime (
419+ new Date (
420+ reconciliation . transactionRecordedAt
421+ ) ,
422+ locale
423+ )
424+ }
425+ />
426+ < PaymentDetailRow
427+ label = { t ( "paymentDetail.transaction.source" ) }
428+ value = {
429+ reconciliation . transactionSource === null
430+ ? t ( "paymentDetail.emptyValue" )
431+ : t (
432+ claimSourceLabelKey [
433+ reconciliation . transactionSource
434+ ]
435+ )
436+ }
437+ />
438+ < PaymentDetailOptionalRow
439+ label = { t ( "paymentDetail.transaction.note" ) }
440+ value = { reconciliation . transactionNote }
441+ />
442+ < PaymentDetailOptionalRow
443+ label = { t ( "paymentDetail.transaction.variableSymbol" ) }
444+ value = { reconciliation . variableSymbol }
445+ />
446+ < PaymentDetailOptionalRow
447+ label = { t ( "paymentDetail.transaction.bankReference" ) }
448+ value = { reconciliation . bankReference }
449+ />
450+ < PaymentDetailOptionalRow
451+ label = { t ( "paymentDetail.transaction.sparkTransferId" ) }
452+ value = { reconciliation . sparkTransferId }
453+ />
454+ < PaymentDetailOptionalRow
455+ label = { t ( "paymentDetail.transaction.paymentHash" ) }
456+ value = { reconciliation . paymentHash }
457+ />
458+ </ div >
459+ </ div >
460+ </ TimelineContent >
461+ </ TimelineItem >
462+ ) ) }
463+ </ Timeline >
448464 ) }
449465 </ CardContent >
450466 </ Card >
0 commit comments