/// Widget: Invoice Card /// /// Displays invoice information in a card format. library; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:intl/intl.dart'; import 'package:worker/core/database/models/enums.dart'; import 'package:worker/core/theme/colors.dart'; import 'package:worker/features/orders/data/models/invoice_model.dart'; /// Invoice Card Widget /// /// Displays invoice details in a card with status indicator and payment summary. class InvoiceCard extends StatelessWidget { /// Invoice to display final InvoiceModel invoice; /// Tap callback final VoidCallback? onTap; /// Payment button callback final VoidCallback? onPaymentTap; const InvoiceCard({ required this.invoice, this.onTap, this.onPaymentTap, super.key, }); @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final currencyFormatter = NumberFormat.currency( locale: 'vi_VN', symbol: 'đ', decimalDigits: 0, ); return Card( margin: const EdgeInsets.only(bottom: 12), elevation: 1, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), clipBehavior: Clip.antiAlias, child: InkWell( onTap: onTap, child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Invoice number and Order ID row Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Invoice number Text( 'Mã hoá đơn #${invoice.invoiceNumber}', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w700, color: colorScheme.onSurface, ), ), const SizedBox(height: 4), // Order ID if (invoice.orderId != null) Text( 'Đơn hàng: #${invoice.orderId}', style: TextStyle( fontSize: 12, color: colorScheme.onSurfaceVariant, ), ), ], ), // Status badge _buildStatusBadge(), ], ), const SizedBox(height: 12), // Invoice dates _buildDetailRow( context, 'Ngày hóa đơn:', _formatDate(invoice.issueDate), ), const SizedBox(height: 6), _buildDetailRow( context, 'Hạn thanh toán:', _formatDate(invoice.dueDate), ), const SizedBox(height: 12), // Payment summary section Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: colorScheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(8), ), child: Column( spacing: 2, children: [ _buildPaymentRow( context, 'Tổng tiền:', currencyFormatter.format(invoice.totalAmount), fontWeight: FontWeight.w600, ), if (invoice.amountPaid > 0) ...[ const SizedBox(height: 6), _buildPaymentRow( context, 'Đã thanh toán:', currencyFormatter.format(invoice.amountPaid), valueColor: AppColors.success, ), ], const Divider(), if (invoice.amountRemaining > 0) ...[ const SizedBox(height: 6), _buildPaymentRow( context, 'Còn lại:', currencyFormatter.format(invoice.amountRemaining), valueColor: invoice.isOverdue ? AppColors.danger : AppColors.warning, fontWeight: FontWeight.w600, ), ], ], ), ), const SizedBox(height: 12), // Action button _buildActionButton(context), ], ), ), ), ); } /// Build detail row Widget _buildDetailRow(BuildContext context, String label, String value) { final colorScheme = Theme.of(context).colorScheme; return Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, spacing: 8, children: [ Text( label, style: TextStyle(fontSize: 14, color: colorScheme.onSurfaceVariant), ), Text( value, style: TextStyle( fontSize: 14, color: colorScheme.onSurface, fontWeight: FontWeight.bold, ), ), ], ); } /// Build payment summary row Widget _buildPaymentRow( BuildContext context, String label, String value, { Color? valueColor, FontWeight? fontWeight, }) { final colorScheme = Theme.of(context).colorScheme; return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: TextStyle(fontSize: 13, color: colorScheme.onSurfaceVariant), ), Text( value, style: TextStyle( fontSize: 14, fontWeight: fontWeight ?? FontWeight.w400, color: valueColor ?? colorScheme.onSurface, ), ), ], ); } /// Build status badge Widget _buildStatusBadge() { return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: _getStatusColor(invoice.status).withValues(alpha: 0.1), borderRadius: BorderRadius.circular(16), border: Border.all( color: _getStatusColor(invoice.status).withValues(alpha: 0.3), width: 1, ), ), child: Text( _getStatusText(invoice.status).toUpperCase(), style: TextStyle( fontSize: 12, fontWeight: FontWeight.w700, color: _getStatusColor(invoice.status), ), ), ); } /// Build action button Widget _buildActionButton(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final isPaid = invoice.status == InvoiceStatus.paid || invoice.isPaid; final buttonText = isPaid ? 'Đã hoàn tất' : 'Thanh toán'; final buttonColor = isPaid ? AppColors.success : colorScheme.primary; return SizedBox( width: double.infinity, child: ElevatedButton( onPressed: isPaid ? null : onPaymentTap, style: ElevatedButton.styleFrom( backgroundColor: buttonColor, disabledBackgroundColor: colorScheme.surfaceContainerHighest, foregroundColor: colorScheme.surface, disabledForegroundColor: colorScheme.onSurfaceVariant, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), elevation: 0, ), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, spacing: 8, children: [ FaIcon(FontAwesomeIcons.creditCard, size: 18), Text( buttonText, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w600), ), ], ), ), ); } /// Get status color Color _getStatusColor(InvoiceStatus status) { switch (status) { case InvoiceStatus.draft: return AppColors.grey500; case InvoiceStatus.issued: return const Color(0xFFF59E0B); // yellow for unpaid case InvoiceStatus.partiallyPaid: return AppColors.info; // blue for partial case InvoiceStatus.paid: return AppColors.success; // green for paid case InvoiceStatus.overdue: return AppColors.danger; // red for overdue case InvoiceStatus.cancelled: return AppColors.grey500; case InvoiceStatus.refunded: return const Color(0xFFF97316); // orange } } /// Get status text in Vietnamese String _getStatusText(InvoiceStatus status) { switch (status) { case InvoiceStatus.draft: return 'Nháp'; case InvoiceStatus.issued: return 'Chưa thanh toán'; case InvoiceStatus.partiallyPaid: return 'Một phần'; case InvoiceStatus.paid: return 'Đã thanh toán'; case InvoiceStatus.overdue: return 'Quá hạn'; case InvoiceStatus.cancelled: return 'Đã hủy'; case InvoiceStatus.refunded: return 'Đã hoàn tiền'; } } /// Format date to dd/MM/yyyy String _formatDate(DateTime date) { return DateFormat('dd/MM/yyyy').format(date); } }