feat: add advance payment indicator in payment request screens and improve code formatting

This commit is contained in:
Vaibhav Surve 2025-11-21 16:57:37 +05:30
parent 2c98ac359c
commit 603e7ee7e5
2 changed files with 94 additions and 32 deletions

View File

@ -119,8 +119,9 @@ class _PaymentRequestDetailScreenState extends State<PaymentRequestDetailScreen>
final request = controller.paymentRequest.value;
if ((controller.errorMessage.value ).isNotEmpty) {
return Center(child: MyText.bodyMedium(controller.errorMessage.value));
if ((controller.errorMessage.value).isNotEmpty) {
return Center(
child: MyText.bodyMedium(controller.errorMessage.value));
}
if (request == null) {
@ -152,7 +153,8 @@ class _PaymentRequestDetailScreenState extends State<PaymentRequestDetailScreen>
request: request,
colorParser: _parseColor,
employeeInfo: employeeInfo,
onEdit: () => _openEditPaymentRequestBottomSheet(request),
onEdit: () =>
_openEditPaymentRequestBottomSheet(request),
),
const Divider(height: 30, thickness: 1.2),
_Logs(
@ -272,8 +274,7 @@ class _PaymentRequestDetailScreenState extends State<PaymentRequestDetailScreen>
message: success
? 'Status updated successfully'
: 'Failed to update status',
type:
success ? SnackbarType.success : SnackbarType.error,
type: success ? SnackbarType.success : SnackbarType.error,
);
if (success) await controller.fetchPaymentRequestDetail();
@ -323,8 +324,8 @@ class _PaymentRequestDetailScreenState extends State<PaymentRequestDetailScreen>
),
MySpacing.height(2),
GetBuilder<ProjectController>(builder: (_) {
final name =
projectController.selectedProject?.name ?? 'Select Project';
final name = projectController.selectedProject?.name ??
'Select Project';
return Row(
children: [
const Icon(Icons.work_outline,
@ -409,12 +410,37 @@ class _HeaderState extends State<_Header> with UIMixin {
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
MyText.bodyMedium(
'ID: ${widget.request.paymentRequestUID ?? '-'}',
fontWeight: 700,
fontSize: 14,
),
// 🔥 ADVANCE CHIP show only if true
if (widget.request.isAdvancePayment == true) ...[
const SizedBox(width: 8),
Container(
padding:
const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.orange.shade700,
borderRadius: BorderRadius.circular(4),
),
child: const Text(
'ADVANCE',
style: TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
),
),
],
],
),
if (canEdit)
IconButton(
onPressed: widget.onEdit,
@ -513,17 +539,17 @@ class _Logs extends StatelessWidget {
final last = updatedBy?.lastName ?? '';
final initials =
'${first.isNotEmpty ? first[0] : ''}${last.isNotEmpty ? last[0] : ''}';
final name = ((first + ' ' + last).trim().isNotEmpty)
? '$first $last'
: '-';
final name =
((first + ' ' + last).trim().isNotEmpty) ? '$first $last' : '-';
final updatedAt = log.updatedAt;
final timeAgo = (updatedAt != null)
? timeago.format(updatedAt.toUtc().add(const Duration(hours: 5, minutes: 30)))
? timeago.format(updatedAt
.toUtc()
.add(const Duration(hours: 5, minutes: 30)))
: '-';
final nextStatusColor =
colorParser(log.nextStatus?.color ?? '');
final nextStatusColor = colorParser(log.nextStatus?.color ?? '');
return TimelineTile(
alignment: TimelineAlign.start,
@ -667,14 +693,18 @@ class _DetailsTable extends StatelessWidget {
_labelValueRow("Transaction ID:", request.paidTransactionId ?? ''),
_labelValueRow("Payee:", request.payee ?? '-'),
_labelValueRow("Project:", request.project?.name ?? '-'),
_labelValueRow("Expense Category:", request.expenseCategory?.name ?? '-'),
_labelValueRow(
"Expense Category:", request.expenseCategory?.name ?? '-'),
// Amounts
_labelValueRow("Amount:", _formatCurrencyAmount(currencySymbol, request.amount)),
_labelValueRow(
"Amount:", _formatCurrencyAmount(currencySymbol, request.amount)),
if (request.baseAmount != null)
_labelValueRow("Base Amount:", _formatCurrencyAmount(currencySymbol, request.baseAmount)),
_labelValueRow("Base Amount:",
_formatCurrencyAmount(currencySymbol, request.baseAmount)),
if (request.taxAmount != null)
_labelValueRow("Tax Amount:", _formatCurrencyAmount(currencySymbol, request.taxAmount)),
_labelValueRow("Tax Amount:",
_formatCurrencyAmount(currencySymbol, request.taxAmount)),
if (request.expenseCategory?.noOfPersonsRequired == true)
_labelValueRow("Additional Persons Required:", "Yes"),
if (request.expenseCategory?.isAttachmentRequried == true)
@ -706,27 +736,36 @@ class _DetailsTable extends StatelessWidget {
format: 'dd MMM yyyy'),
),
if (request.paidBy != null)
_labelValueRow("Paid By:", "${request.paidBy?.firstName ?? ''} ${request.paidBy?.lastName ?? ''}".trim()),
_labelValueRow(
"Paid By:",
"${request.paidBy?.firstName ?? ''} ${request.paidBy?.lastName ?? ''}"
.trim()),
// Flags
_labelValueRow(
"Advance Payment:", (request.isAdvancePayment ?? false) ? "Yes" : "No"),
_labelValueRow(
"Expense Created:", (request.isExpenseCreated ?? false) ? "Yes" : "No"),
_labelValueRow("Advance Payment:",
(request.isAdvancePayment ?? false) ? "Yes" : "No"),
_labelValueRow("Expense Created:",
(request.isExpenseCreated ?? false) ? "Yes" : "No"),
_labelValueRow("Active:", (request.isActive ?? false) ? "Yes" : "No"),
// Recurring Payment Info
if (request.recurringPayment != null) ...[
const SizedBox(height: 6),
MyText.bodySmall("Recurring Payment Info:", fontWeight: 600),
_labelValueRow("Recurring ID:", request.recurringPayment?.recurringPaymentUID ?? '-'),
_labelValueRow("Amount:", _formatCurrencyAmount(currencySymbol, request.recurringPayment?.amount)),
_labelValueRow("Variable Amount:", (request.recurringPayment?.isVariable ?? false) ? "Yes" : "No"),
_labelValueRow("Recurring ID:",
request.recurringPayment?.recurringPaymentUID ?? '-'),
_labelValueRow(
"Amount:",
_formatCurrencyAmount(
currencySymbol, request.recurringPayment?.amount)),
_labelValueRow("Variable Amount:",
(request.recurringPayment?.isVariable ?? false) ? "Yes" : "No"),
],
// Description & Attachments
_labelValueRow("Description:", request.description ?? '-'),
_labelValueRow("Attachment:", (request.attachments ?? []).isNotEmpty ? "Yes" : "No"),
_labelValueRow("Attachment:",
(request.attachments ?? []).isNotEmpty ? "Yes" : "No"),
],
);
}

View File

@ -355,7 +355,6 @@ class _PaymentRequestMainScreenState extends State<PaymentRequestMainScreen>
child: InkWell(
borderRadius: BorderRadius.circular(8),
onTap: () {
// Navigate to detail screen, passing the payment request ID
Get.to(() => PaymentRequestDetailScreen(paymentRequestId: item.id));
},
child: Padding(
@ -366,6 +365,30 @@ class _PaymentRequestMainScreenState extends State<PaymentRequestMainScreen>
Row(
children: [
MyText.bodyMedium(item.expenseCategory.name, fontWeight: 600),
// -------------------------------
// ADV CHIP (only if advance)
// -------------------------------
if (item.isAdvancePayment == true) ...[
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.orange.withOpacity(0.2),
borderRadius: BorderRadius.circular(4),
border: Border.all(color: Colors.orange),
),
child: const Text(
"ADV",
style: TextStyle(
fontSize: 10,
color: Colors.orange,
fontWeight: FontWeight.bold,
),
),
),
],
],
),
const SizedBox(height: 6),