import 'package:flutter/material.dart'; import 'package:cashumit/models/local_receipt.dart'; import 'package:cashumit/services/local_receipt_service.dart'; import 'package:cashumit/services/receipt_service.dart'; import 'package:intl/intl.dart'; class LocalReceiptsScreen extends StatefulWidget { const LocalReceiptsScreen({super.key}); @override State createState() => _LocalReceiptsScreenState(); } class _LocalReceiptsScreenState extends State { List receipts = []; bool isLoading = true; bool isSubmitting = false; @override void initState() { super.initState(); _loadReceipts(); } Future _loadReceipts() async { setState(() { isLoading = true; }); try { final loadedReceipts = await LocalReceiptService.getReceipts(); setState(() { receipts = loadedReceipts; isLoading = false; }); } catch (e) { setState(() { isLoading = false; }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Gagal memuat daftar nota: $e')), ); } } } Future _submitAllReceipts() async { final credentials = await ReceiptService.loadCredentials(); if (credentials == null) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Silakan konfigurasi kredensial FireFly III terlebih dahulu'), ), ); } return; } setState(() { isSubmitting = true; }); try { final result = await LocalReceiptService.submitAllUnsubmittedReceipts( credentials['url']!, credentials['token']!, ); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Berhasil: ${result['successCount']} berhasil, ${result['failureCount']} gagal dari ${result['totalCount']} total nota', ), ), ); } await _loadReceipts(); // Refresh daftar setelah submit } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Gagal mengirim nota: $e')), ); } } finally { setState(() { isSubmitting = false; }); } } Future _deleteReceipt(String receiptId) async { try { await LocalReceiptService.removeReceipt(receiptId); await _loadReceipts(); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Nota berhasil dihapus')), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Gagal menghapus nota: $e')), ); } } } String _formatCurrency(double amount) { final formatter = NumberFormat.currency( locale: 'id_ID', symbol: 'Rp ', decimalDigits: 0, ); return formatter.format(amount).replaceAll('.00', ''); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Nota Tersimpan'), actions: [ IconButton( icon: const Icon(Icons.refresh), onPressed: isLoading ? null : _loadReceipts, ), ], ), body: Column( children: [ // Summary card Container( margin: const EdgeInsets.all(16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.3), spreadRadius: 1, blurRadius: 3, offset: const Offset(0, 2), ), ], ), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Column( children: [ Text( receipts .where((r) => !r.isSubmitted) .length .toString(), style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.orange, ), ), const Text( 'Menunggu', style: TextStyle(color: Colors.grey), ), ], ), Column( children: [ Text( receipts .where((r) => r.isSubmitted) .length .toString(), style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.green, ), ), const Text( 'Terkirim', style: TextStyle(color: Colors.grey), ), ], ), Column( children: [ Text( receipts.length.toString(), style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Colors.blue, ), ), const Text( 'Total', style: TextStyle(color: Colors.grey), ), ], ), ], ), const SizedBox(height: 16), ElevatedButton.icon( onPressed: isSubmitting ? null : _submitAllReceipts, icon: isSubmitting ? const SizedBox( width: 16, height: 16, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(Colors.white), ), ) : const Icon(Icons.sync), label: Text(isSubmitting ? 'Mengirim...' : 'Kirim Semua Nota'), ), ], ), ), // Receipts list Expanded( child: isLoading ? const Center(child: CircularProgressIndicator()) : receipts.isEmpty ? const Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.receipt_outlined, size: 64, color: Colors.grey, ), SizedBox(height: 16), Text( 'Belum ada nota tersimpan', style: TextStyle( fontSize: 16, color: Colors.grey, ), ), ], ), ) : RefreshIndicator( onRefresh: _loadReceipts, child: ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 16), itemCount: receipts.length, itemBuilder: (context, index) { final receipt = receipts[index]; return Card( margin: const EdgeInsets.only(bottom: 8), child: ListTile( contentPadding: const EdgeInsets.all(16), leading: Container( width: 40, height: 40, decoration: BoxDecoration( color: receipt.isSubmitted ? Colors.green.shade100 : Colors.orange.shade100, borderRadius: BorderRadius.circular(20), ), child: Icon( receipt.isSubmitted ? Icons.check_circle : Icons.access_time, color: receipt.isSubmitted ? Colors.green : Colors.orange, size: 20, ), ), title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // Transaction description di kiri Expanded( flex: 2, child: Text( receipt.transactionDescription ?? 'Transaksi Struk Belanja', style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 14, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 8), // Total di kanan Expanded( child: Text( _formatCurrency(receipt.total), style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 14, color: Colors.blue, ), textAlign: TextAlign.right, ), ), ], ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 4), Text( 'Dibuat: ${DateFormat('dd/MM/yyyy HH:mm').format(receipt.createdAt)}', style: const TextStyle(fontSize: 12), ), if (receipt.isSubmitted) Text( 'Dikirim: ${DateFormat('dd/MM/yyyy HH:mm').format(receipt.submittedAt ?? receipt.createdAt)}', style: const TextStyle( fontSize: 12, color: Colors.green, ), ), if (receipt.submissionError != null) Text( 'Error: ${receipt.submissionError}', style: const TextStyle( fontSize: 12, color: Colors.red, ), ), ], ), trailing: PopupMenuButton( onSelected: (String action) { if (action == 'delete') { _showDeleteConfirmation(receipt.id); } }, itemBuilder: (BuildContext context) { return [ const PopupMenuItem( value: 'delete', child: Row( children: [ Icon(Icons.delete, size: 18), SizedBox(width: 8), Text('Hapus'), ], ), ), ]; }, ), ), ); }, ), ), ), ], ), ); } Future _showDeleteConfirmation(String receiptId) async { final result = await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Konfirmasi Hapus'), content: const Text('Apakah Anda yakin ingin menghapus nota ini?'), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), child: const Text('Batal'), ), TextButton( onPressed: () => Navigator.pop(context, true), child: const Text('Hapus'), ), ], ), ); if (result == true) { _deleteReceipt(receiptId); } } }