244 lines
9.2 KiB
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,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|