cashumit/lib/widgets/receipt_total.dart

244 lines
9.2 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:cashumit/providers/receipt_provider.dart';
import 'package:cashumit/utils/currency_format.dart';
import 'package:cashumit/utils/app_text_styles.dart';
class ReceiptTotal extends StatelessWidget {
final double total;
final VoidCallback? onSetTip;
final VoidCallback? onClearTip;
const ReceiptTotal({
super.key,
required this.total,
this.onSetTip,
this.onClearTip,
});
String _fmt(num v) {
final s = v.abs().toStringAsFixed(0).replaceAllMapped(
RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'), (Match m) => '${m[1]},');
return v < 0 ? '-$s' : s;
}
@override
Widget build(BuildContext context) {
final receiptProvider = Provider.of<ReceiptProvider>(context);
final state = receiptProvider.state;
final paymentAmount = state.paymentAmount;
final changeAmount = paymentAmount - total;
final hasSufficientPayment = paymentAmount >= total;
final hasTip = state.hasTip;
final primaryColor = Theme.of(context).colorScheme.primary;
return Container(
width: double.infinity,
padding: const EdgeInsets.all(8.0),
color: Colors.white,
child: SingleChildScrollView(
child: Column(
children: [
// Total - Tap to open payment dialog
GestureDetector(
onTap: () {
receiptProvider.showPaymentTipDialog(context);
},
child: Container(
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey[300]!),
borderRadius: BorderRadius.circular(4),
color: Colors.grey[50],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 4,
child: Text(
'TOTAL:',
style: CourierStyles.big,
),
),
Expanded(
flex: 4,
child: Text(
_fmt(total),
style: CourierStyles.big.copyWith(color: primaryColor),
textAlign: TextAlign.right,
),
),
],
),
),
),
const SizedBox(height: 8),
// Payment Amount Display
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 4,
child: Text(
'BAYAR:',
style: CourierStyles.base
.copyWith(color: Colors.grey[700]),
),
),
Expanded(
flex: 4,
child: Text(
paymentAmount > 0 ? _fmt(paymentAmount) : '0',
style: CourierStyles.base
.copyWith(color: Colors.grey[700]),
textAlign: TextAlign.right,
),
),
],
),
const SizedBox(height: 8),
// Change Amount
if (paymentAmount > 0)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 4,
child: Text(
'KEMBALI:',
style: CourierStyles.base.copyWith(
color: hasSufficientPayment
? Colors.grey[700]
: Colors.red,
),
),
),
Expanded(
flex: 4,
child: Text(
_fmt(changeAmount),
style: CourierStyles.base.copyWith(
color: hasSufficientPayment && changeAmount >= 0
? Colors.green
: Colors.red,
),
textAlign: TextAlign.right,
),
),
],
),
// Tip control: tampilkan hanya jika ada kembalian
if (paymentAmount > total)
Padding(
padding: const EdgeInsets.only(top: 8),
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color:
hasTip ? Colors.orange[50] : Colors.grey[50],
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: hasTip ? Colors.orange : Colors.grey[300]!,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
'SEBAGAI TIP:',
style: CourierStyles.base
.copyWith(color: Colors.grey[700]),
),
),
if (hasTip)
Text(
CurrencyFormat.formatRupiah(state.tipAmount),
style: CourierStyles.bold.copyWith(
color: Colors.orange[800], fontSize: 13),
)
else
Text(
'Tidak',
style: CourierStyles.base
.copyWith(color: Colors.grey[600]),
),
],
),
if (hasTip && state.tipSourceAccountName != null)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
'Sumber: ${state.tipSourceAccountName}',
style: CourierStyles.base.copyWith(
fontSize: 12,
color: Colors.orange[800],
fontStyle: FontStyle.italic,
),
),
),
const SizedBox(height: 6),
Row(
children: [
if (!hasTip)
Expanded(
child: ElevatedButton.icon(
onPressed: onSetTip,
icon: const Icon(Icons.volunteer_activism,
size: 16),
label: const Text('Jadikan Tip',
style: TextStyle(fontSize: 12)),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.orange,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
),
),
)
else
Expanded(
child: OutlinedButton.icon(
onPressed: onClearTip,
icon: const Icon(Icons.close, size: 16),
label: const Text('Batal Tip',
style: TextStyle(fontSize: 12)),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.red,
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
),
),
),
],
),
if (!hasTip)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
'Kembalian sebesar ${CurrencyFormat.formatRupiah(changeAmount)} bisa dijadikan tip ke akun sumber tertentu.',
style: TextStyle(
fontSize: 11,
color: Colors.grey[600],
fontStyle: FontStyle.italic,
),
),
),
],
),
),
),
],
),
),
);
}
}