feat: add advance payment indicator in payment request screens and improve code formatting
This commit is contained in:
parent
2c98ac359c
commit
603e7ee7e5
@ -26,7 +26,7 @@ class PaymentRequestDetailScreen extends StatefulWidget {
|
|||||||
final String paymentRequestId;
|
final String paymentRequestId;
|
||||||
const PaymentRequestDetailScreen({super.key, required this.paymentRequestId});
|
const PaymentRequestDetailScreen({super.key, required this.paymentRequestId});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<PaymentRequestDetailScreen> createState() =>
|
State<PaymentRequestDetailScreen> createState() =>
|
||||||
_PaymentRequestDetailScreenState();
|
_PaymentRequestDetailScreenState();
|
||||||
}
|
}
|
||||||
@ -119,8 +119,9 @@ class _PaymentRequestDetailScreenState extends State<PaymentRequestDetailScreen>
|
|||||||
|
|
||||||
final request = controller.paymentRequest.value;
|
final request = controller.paymentRequest.value;
|
||||||
|
|
||||||
if ((controller.errorMessage.value ).isNotEmpty) {
|
if ((controller.errorMessage.value).isNotEmpty) {
|
||||||
return Center(child: MyText.bodyMedium(controller.errorMessage.value));
|
return Center(
|
||||||
|
child: MyText.bodyMedium(controller.errorMessage.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request == null) {
|
if (request == null) {
|
||||||
@ -152,7 +153,8 @@ class _PaymentRequestDetailScreenState extends State<PaymentRequestDetailScreen>
|
|||||||
request: request,
|
request: request,
|
||||||
colorParser: _parseColor,
|
colorParser: _parseColor,
|
||||||
employeeInfo: employeeInfo,
|
employeeInfo: employeeInfo,
|
||||||
onEdit: () => _openEditPaymentRequestBottomSheet(request),
|
onEdit: () =>
|
||||||
|
_openEditPaymentRequestBottomSheet(request),
|
||||||
),
|
),
|
||||||
const Divider(height: 30, thickness: 1.2),
|
const Divider(height: 30, thickness: 1.2),
|
||||||
_Logs(
|
_Logs(
|
||||||
@ -272,8 +274,7 @@ class _PaymentRequestDetailScreenState extends State<PaymentRequestDetailScreen>
|
|||||||
message: success
|
message: success
|
||||||
? 'Status updated successfully'
|
? 'Status updated successfully'
|
||||||
: 'Failed to update status',
|
: 'Failed to update status',
|
||||||
type:
|
type: success ? SnackbarType.success : SnackbarType.error,
|
||||||
success ? SnackbarType.success : SnackbarType.error,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (success) await controller.fetchPaymentRequestDetail();
|
if (success) await controller.fetchPaymentRequestDetail();
|
||||||
@ -323,8 +324,8 @@ class _PaymentRequestDetailScreenState extends State<PaymentRequestDetailScreen>
|
|||||||
),
|
),
|
||||||
MySpacing.height(2),
|
MySpacing.height(2),
|
||||||
GetBuilder<ProjectController>(builder: (_) {
|
GetBuilder<ProjectController>(builder: (_) {
|
||||||
final name =
|
final name = projectController.selectedProject?.name ??
|
||||||
projectController.selectedProject?.name ?? 'Select Project';
|
'Select Project';
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.work_outline,
|
const Icon(Icons.work_outline,
|
||||||
@ -410,10 +411,35 @@ class _HeaderState extends State<_Header> with UIMixin {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
MyText.bodyMedium(
|
Row(
|
||||||
'ID: ${widget.request.paymentRequestUID ?? '-'}',
|
children: [
|
||||||
fontWeight: 700,
|
MyText.bodyMedium(
|
||||||
fontSize: 14,
|
'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)
|
if (canEdit)
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -513,17 +539,17 @@ class _Logs extends StatelessWidget {
|
|||||||
final last = updatedBy?.lastName ?? '';
|
final last = updatedBy?.lastName ?? '';
|
||||||
final initials =
|
final initials =
|
||||||
'${first.isNotEmpty ? first[0] : ''}${last.isNotEmpty ? last[0] : ''}';
|
'${first.isNotEmpty ? first[0] : ''}${last.isNotEmpty ? last[0] : ''}';
|
||||||
final name = ((first + ' ' + last).trim().isNotEmpty)
|
final name =
|
||||||
? '$first $last'
|
((first + ' ' + last).trim().isNotEmpty) ? '$first $last' : '-';
|
||||||
: '-';
|
|
||||||
|
|
||||||
final updatedAt = log.updatedAt;
|
final updatedAt = log.updatedAt;
|
||||||
final timeAgo = (updatedAt != null)
|
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 =
|
final nextStatusColor = colorParser(log.nextStatus?.color ?? '');
|
||||||
colorParser(log.nextStatus?.color ?? '');
|
|
||||||
|
|
||||||
return TimelineTile(
|
return TimelineTile(
|
||||||
alignment: TimelineAlign.start,
|
alignment: TimelineAlign.start,
|
||||||
@ -667,14 +693,18 @@ class _DetailsTable extends StatelessWidget {
|
|||||||
_labelValueRow("Transaction ID:", request.paidTransactionId ?? ''),
|
_labelValueRow("Transaction ID:", request.paidTransactionId ?? ''),
|
||||||
_labelValueRow("Payee:", request.payee ?? '-'),
|
_labelValueRow("Payee:", request.payee ?? '-'),
|
||||||
_labelValueRow("Project:", request.project?.name ?? '-'),
|
_labelValueRow("Project:", request.project?.name ?? '-'),
|
||||||
_labelValueRow("Expense Category:", request.expenseCategory?.name ?? '-'),
|
_labelValueRow(
|
||||||
|
"Expense Category:", request.expenseCategory?.name ?? '-'),
|
||||||
|
|
||||||
// Amounts
|
// Amounts
|
||||||
_labelValueRow("Amount:", _formatCurrencyAmount(currencySymbol, request.amount)),
|
_labelValueRow(
|
||||||
|
"Amount:", _formatCurrencyAmount(currencySymbol, request.amount)),
|
||||||
if (request.baseAmount != null)
|
if (request.baseAmount != null)
|
||||||
_labelValueRow("Base Amount:", _formatCurrencyAmount(currencySymbol, request.baseAmount)),
|
_labelValueRow("Base Amount:",
|
||||||
|
_formatCurrencyAmount(currencySymbol, request.baseAmount)),
|
||||||
if (request.taxAmount != null)
|
if (request.taxAmount != null)
|
||||||
_labelValueRow("Tax Amount:", _formatCurrencyAmount(currencySymbol, request.taxAmount)),
|
_labelValueRow("Tax Amount:",
|
||||||
|
_formatCurrencyAmount(currencySymbol, request.taxAmount)),
|
||||||
if (request.expenseCategory?.noOfPersonsRequired == true)
|
if (request.expenseCategory?.noOfPersonsRequired == true)
|
||||||
_labelValueRow("Additional Persons Required:", "Yes"),
|
_labelValueRow("Additional Persons Required:", "Yes"),
|
||||||
if (request.expenseCategory?.isAttachmentRequried == true)
|
if (request.expenseCategory?.isAttachmentRequried == true)
|
||||||
@ -706,27 +736,36 @@ class _DetailsTable extends StatelessWidget {
|
|||||||
format: 'dd MMM yyyy'),
|
format: 'dd MMM yyyy'),
|
||||||
),
|
),
|
||||||
if (request.paidBy != null)
|
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
|
// Flags
|
||||||
_labelValueRow(
|
_labelValueRow("Advance Payment:",
|
||||||
"Advance Payment:", (request.isAdvancePayment ?? false) ? "Yes" : "No"),
|
(request.isAdvancePayment ?? false) ? "Yes" : "No"),
|
||||||
_labelValueRow(
|
_labelValueRow("Expense Created:",
|
||||||
"Expense Created:", (request.isExpenseCreated ?? false) ? "Yes" : "No"),
|
(request.isExpenseCreated ?? false) ? "Yes" : "No"),
|
||||||
_labelValueRow("Active:", (request.isActive ?? false) ? "Yes" : "No"),
|
_labelValueRow("Active:", (request.isActive ?? false) ? "Yes" : "No"),
|
||||||
|
|
||||||
// Recurring Payment Info
|
// Recurring Payment Info
|
||||||
if (request.recurringPayment != null) ...[
|
if (request.recurringPayment != null) ...[
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
MyText.bodySmall("Recurring Payment Info:", fontWeight: 600),
|
MyText.bodySmall("Recurring Payment Info:", fontWeight: 600),
|
||||||
_labelValueRow("Recurring ID:", request.recurringPayment?.recurringPaymentUID ?? '-'),
|
_labelValueRow("Recurring ID:",
|
||||||
_labelValueRow("Amount:", _formatCurrencyAmount(currencySymbol, request.recurringPayment?.amount)),
|
request.recurringPayment?.recurringPaymentUID ?? '-'),
|
||||||
_labelValueRow("Variable Amount:", (request.recurringPayment?.isVariable ?? false) ? "Yes" : "No"),
|
_labelValueRow(
|
||||||
|
"Amount:",
|
||||||
|
_formatCurrencyAmount(
|
||||||
|
currencySymbol, request.recurringPayment?.amount)),
|
||||||
|
_labelValueRow("Variable Amount:",
|
||||||
|
(request.recurringPayment?.isVariable ?? false) ? "Yes" : "No"),
|
||||||
],
|
],
|
||||||
|
|
||||||
// Description & Attachments
|
// Description & Attachments
|
||||||
_labelValueRow("Description:", request.description ?? '-'),
|
_labelValueRow("Description:", request.description ?? '-'),
|
||||||
_labelValueRow("Attachment:", (request.attachments ?? []).isNotEmpty ? "Yes" : "No"),
|
_labelValueRow("Attachment:",
|
||||||
|
(request.attachments ?? []).isNotEmpty ? "Yes" : "No"),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -355,7 +355,6 @@ class _PaymentRequestMainScreenState extends State<PaymentRequestMainScreen>
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// Navigate to detail screen, passing the payment request ID
|
|
||||||
Get.to(() => PaymentRequestDetailScreen(paymentRequestId: item.id));
|
Get.to(() => PaymentRequestDetailScreen(paymentRequestId: item.id));
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@ -366,6 +365,30 @@ class _PaymentRequestMainScreenState extends State<PaymentRequestMainScreen>
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
MyText.bodyMedium(item.expenseCategory.name, fontWeight: 600),
|
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),
|
const SizedBox(height: 6),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user