Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | 15x 4x 3x 3x 2x 3x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 10x 6x 2x 4x 2x 2x 10x 4x 1x 3x 1x 2x 1x 1x 10x | import Box from '@mui/material/Box' import Card from '@mui/material/Card' import CardContent from '@mui/material/CardContent' import Typography from '@mui/material/Typography' import Chip from '@mui/material/Chip' import { useTranslation } from 'react-i18next' import { formatDate, formatCurrency } from '../../utils/format' import type { Invoice } from '../../types/invoices' import { useLanguageStore } from '../../stores/useLanguageStore' import ReceiptIcon from '@mui/icons-material/Receipt' import { useDownloadInvoice } from '../../hooks/useDownloadInvoice' import Tooltip from '@mui/material/Tooltip' import CircularProgress from '@mui/material/CircularProgress' import { useCustomSnackbar } from '../../hooks/useCustomSnackbar' // Définir le mapping statut → couleur du Chip MUI export function getStatusChipColor(status: Invoice['status']): 'success' | 'warning' | 'error' | 'default' | 'info' { switch (status) { case 'paid': return 'success' case 'pending': return 'warning' case 'failed': return 'error' case 'refunded': return 'info' default: return 'default' } } interface InvoiceCardProps { invoice: Invoice } export function InvoiceCard({ invoice }: InvoiceCardProps) { const { t } = useTranslation('invoices') const lang = useLanguageStore(s => s.lang) const { download, downloading } = useDownloadInvoice() const { notify } = useCustomSnackbar() // Formattage date et montant const dateStr = formatDate(invoice.created_at, lang) const amountStr = formatCurrency(invoice.amount, lang, 'EUR') // Texte pour le statut, on peut utiliser i18n ou fallback brut const statusLabel = t(`card.status.${invoice.status}`, invoice.status) const chipColor = getStatusChipColor(invoice.status) // Déterminer si on autorise le téléchargement const canDownload = invoice.status === 'paid' || invoice.status === 'refunded' // Tooltip explicatif let downloadTooltip = t('card.download_invoice') if (!canDownload) { if (invoice.status === 'pending') { downloadTooltip = t('card.download_not_ready') } else if (invoice.status === 'failed') { downloadTooltip = t('card.download_not_available') } else { downloadTooltip = t('card.download_not_available_generic') } } // Handler clic sur l’icône const handleIconClick = () => { if (canDownload) { // Lance le téléchargement ; useDownloadInvoice appellera notify pour succès/erreur download(invoice.invoice_link) } else { // Affiche un message via notify, apparaîtra en bas grâce au provider global if (invoice.status === 'pending') { notify(t('snackbar.pending_message'), 'warning') } else if (invoice.status === 'failed') { notify(t('snackbar.failed_message'), 'error') } else { notify(t('snackbar.unavailable_message'), 'info') } } } return ( <> <Box sx={{ flex: { xs: '1 1 calc(33% - 32px)', md: '1 1 100%' }, minWidth: { xs: 280, md: 'auto' }, maxWidth: { xs: 320, md: '100%' }, }} > <Card sx={{ display: 'flex', flexDirection: { xs: 'column', md: 'row' }, alignItems: { xs: 'stretch', md: 'center' }, p: 2, gap: 1, }} > {/* Zone icône / téléchargement */} <Tooltip title={downloadTooltip}> <Box onClick={handleIconClick} sx={{ cursor: canDownload ? 'pointer' : 'default', width: { xs: '100%', md: 120 }, height: 80, display: 'flex', alignItems: 'center', justifyContent: 'center', bgcolor: 'background.default', borderRadius: 1, position: 'relative', '&:hover': canDownload ? { bgcolor: 'action.hover' } : {}, }} > {downloading && canDownload ? <CircularProgress size={24} /> : <ReceiptIcon fontSize="large" color={canDownload ? 'action' : 'disabled'} /> } </Box> </Tooltip> <CardContent sx={{ flexGrow: 1 }}> {/* Référence / UUID */} <Typography variant="h6"> {t('card.reference')}: {invoice.uuid} </Typography> {/* Date de création */} <Typography variant="body2" sx={{ mt: 0.5 }}> {t('card.date')}: {dateStr} </Typography> {/* Montant */} <Typography variant="body2" sx={{ mt: 0.5 }}> {t('card.amount')}: {amountStr} </Typography> {/* Statut avec Chip */} <Box sx={{ mt: 1 }}> <Chip label={statusLabel} color={chipColor} size="small" /> </Box> </CardContent> </Card> </Box> </> ) } |