'use client';
import React, { useState } from 'react';
import { formatCurrency } from '../../../shared/utils/currency.js';
import { Card, Table, Select } from '../../../shared/components/index.js';
import { parseUTCDate, formatDateForDisplay, getDaysBetween, isOverdue, getTodayUTC } from '../../../shared/lib/dates.js';
const DATE_LOCALE = 'fr-FR';
/**
* Public Invoice Payment Page Component
* Allows clients to view and pay invoices via public link
*/
const PaymentPage = ({
invoice,
onPaymentSubmit,
stripeEnabled = false,
interacEnabled = false,
interacEmail = null,
interacCredentials = null,
paymentStatus = null,
token = null,
publicLogoWhite = '',
publicLogoBlack = '',
publicDashboardUrl = '',
}) => {
const [paymentMethod, setPaymentMethod] = useState(
stripeEnabled ? 'stripe' : (interacEnabled ? 'interac' : 'other')
);
const [isProcessing, setIsProcessing] = useState(false);
// Payment method options for Select component
const paymentMethodOptions = [
...(stripeEnabled ? [{ value: 'stripe', label: "Carte de crédit" }] : []),
...(interacEnabled ? [{ value: 'interac', label: "Virement Interac" }] : []),
{ value: 'other', label: "Autre" }
];
if (!invoice) {
return (
Facture non trouvée
La facture que vous recherchez n'existe pas ou a été supprimée.
);
}
const clientName = invoice.company_name || `${invoice.first_name} ${invoice.last_name}`;
const isPaid = invoice.status === 'paid';
const invoiceIsOverdue = isOverdue(invoice.due_date) && !isPaid;
const principalAmount = parseFloat(invoice.total_amount);
const interestAmount = parseFloat(invoice.interest_amount || 0);
const totalWithInterest = principalAmount + interestAmount;
const paidAmount = parseFloat(invoice.paid_amount || 0);
const remainingAmount = totalWithInterest - paidAmount;
const totalAmount = totalWithInterest;
const hasInterest = interestAmount > 0;
const handlePayment = async () => {
if (onPaymentSubmit) {
setIsProcessing(true);
try {
await onPaymentSubmit(paymentMethod);
} finally {
setIsProcessing(false);
}
}
};
// Calculate days remaining
const daysRemaining = getDaysBetween(getTodayUTC(), invoice.due_date);
const dueDateFormatted = formatDateForDisplay(invoice.due_date, DATE_LOCALE);
// Table columns configuration for invoice items
const invoiceItemsColumns = [
{
key: 'name',
label: "Description",
render: (item) => (
{item.name}
{item.description && (
{item.description}
)}
)
},
{
key: 'quantity',
label: "Quantité",
noWrap: false,
render: (item) => (
{item.quantity}
)
},
{
key: 'unit_price',
label: "Prix unitaire",
noWrap: false,
render: (item) => (
{formatCurrency(item.unit_price)}
)
},
{
key: 'total',
label: "Total",
headerAlign: 'right',
noWrap: false,
render: (item) => (
{formatCurrency(item.total)}
)
}
];
const hasLogo = publicLogoWhite || publicLogoBlack;
const logoHref = publicDashboardUrl && publicDashboardUrl.trim() !== '' ? publicDashboardUrl.trim() : null;
return (
{/* Invoice to Pay Header */}
{/* Public logo (black in light theme, white in dark theme); link to dashboard when URL configured */}
{hasLogo && (
)}
{remainingAmount > 0 && (
<>
Facture à payer
Vous avez une facture à payer de {formatCurrency(totalAmount)} avant le {dueDateFormatted}.
>
)}
{remainingAmount === 0 && (
<>
Facture payée
Vous avez une facture de {formatCurrency(totalAmount)} qui a été payée.
>
)}
{(paymentStatus === 'success' || paymentStatus === 'cancelled' || (invoiceIsOverdue && !isPaid)) && (
{/* Status Badge */}
{paymentStatus === 'success' && (
✓ Paiement effectué avec succès !
Vous recevrez un email de confirmation sous peu.
)}
{paymentStatus === 'cancelled' && (
Le paiement a été annulé
Vous pouvez réessayer ci-dessous.
)}
{(invoiceIsOverdue && !isPaid) && (
Cette facture est en retard. Veuillez la payer le plus rapidement possible.
)}
)}
{/* Invoice Details */}
{/* Invoice Amount Section */}
Montant de la facture
{formatCurrency(totalAmount)}
{remainingAmount > 0 && (
Payable avant le {dueDateFormatted} ({daysRemaining > 0 ? `${daysRemaining} jours restants` : 'En retard'})
)}
{remainingAmount === 0 && (
Payable avant le {dueDateFormatted}
)}
{/* Downloads Section */}
Téléchargements
{isPaid && (
)}
{/* Items Table */}
{/* Totals Section */}
{invoice.items && invoice.items.length > 0 && (
{/* Subtotal */}
Sous-total
{formatCurrency(invoice.items.reduce((sum, item) => sum + parseFloat(item.total || 0), 0))}
{/* Interest (if applicable) */}
{hasInterest && (
Intérêt
{formatCurrency(interestAmount)}
)}
{/* Total */}
Total
{formatCurrency(totalWithInterest)}
)}
{/* Notes */}
{invoice.notes && (
Notes
{invoice.notes}
)}
{/* Payment Section */}
{isPaid ? (
Payé en totalité
Payé le {formatDateForDisplay(invoice.paid_at, DATE_LOCALE)}
) : (
Montant à payer
{formatCurrency(remainingAmount)}
{(paymentMethod === 'stripe') && (
)}
{paymentMethod === 'other' && (
Veuillez nous contacter pour les instructions de paiement.
)}
)}
{paymentMethod === 'interac' && interacEnabled && interacEmail && interacCredentials && (
Virement Interac
Veuillez envoyer un virement Interac aux informations suivantes :
Question de sécurité
{interacCredentials.security_question}
Réponse
{interacCredentials.security_answer}
Votre facture sera marquée comme payée une fois que nous aurons traité votre paiement. Veuillez noter que cela peut prendre un certain temps.
)}
);
};
export default PaymentPage;