457 lines
18 KiB
Dart
Executable File
457 lines
18 KiB
Dart
Executable File
import 'package:siro_driver/constant/currency.dart';
|
|
import 'package:local_auth/local_auth.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:siro_driver/constant/finance_design_system.dart';
|
|
import 'package:siro_driver/controller/home/payment/captain_wallet_controller.dart';
|
|
import 'package:siro_driver/views/widgets/mycircular.dart';
|
|
import 'package:siro_driver/views/widgets/elevated_btn.dart';
|
|
import 'package:siro_driver/views/widgets/my_textField.dart';
|
|
import 'package:siro_driver/views/widgets/mydialoug.dart';
|
|
import 'package:siro_driver/views/widgets/error_snakbar.dart';
|
|
import 'package:siro_driver/constant/box_name.dart';
|
|
import 'package:siro_driver/constant/links.dart';
|
|
import 'package:siro_driver/controller/functions/crud.dart';
|
|
import 'package:siro_driver/main.dart';
|
|
import 'package:siro_driver/views/home/my_wallet/payment_history_driver_page.dart';
|
|
import 'package:siro_driver/controller/payment/driver_payment_controller.dart';
|
|
|
|
// Import new widgets
|
|
import 'points_captain.dart';
|
|
import 'transfer_budget_page.dart';
|
|
import 'widgets/balance_card.dart';
|
|
import 'widgets/quick_actions.dart';
|
|
import 'widgets/financial_summary_card.dart';
|
|
import 'widgets/promo_gamification_card.dart';
|
|
import 'widgets/transaction_preview_item.dart';
|
|
|
|
class WalletCaptainRefactored extends StatelessWidget {
|
|
WalletCaptainRefactored({super.key});
|
|
|
|
final CaptainWalletController controller = Get.put(CaptainWalletController());
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
controller.refreshCaptainWallet();
|
|
return Scaffold(
|
|
backgroundColor: FinanceDesignSystem.backgroundColor,
|
|
appBar: AppBar(
|
|
title: Text('Driver Balance'.tr,
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
color: FinanceDesignSystem.primaryDark)),
|
|
backgroundColor: Colors.transparent,
|
|
elevation: 0,
|
|
centerTitle: true,
|
|
leading: IconButton(
|
|
icon: Icon(Icons.arrow_back_ios_new_rounded,
|
|
color: FinanceDesignSystem.primaryDark, size: 20),
|
|
onPressed: () => Get.back(),
|
|
),
|
|
actions: [
|
|
IconButton(
|
|
icon: Icon(Icons.refresh_rounded,
|
|
color: FinanceDesignSystem.primaryDark),
|
|
onPressed: () => controller.refreshCaptainWallet(),
|
|
tooltip: 'Refresh'.tr,
|
|
),
|
|
],
|
|
),
|
|
body: GetBuilder<CaptainWalletController>(
|
|
builder: (controller) {
|
|
if (controller.isLoading) {
|
|
return const Center(child: MyCircularProgressIndicator());
|
|
}
|
|
return SingleChildScrollView(
|
|
padding: const EdgeInsets.symmetric(
|
|
horizontal: FinanceDesignSystem.horizontalPadding,
|
|
vertical: 10),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
// 1. Header / Balance
|
|
BalanceCard(
|
|
balance: controller.totalPoints.toString(),
|
|
isNegative:
|
|
double.tryParse(controller.totalPoints.toString()) !=
|
|
null &&
|
|
double.parse(controller.totalPoints.toString()) <
|
|
-30000,
|
|
lastUpdated: "Just now".tr,
|
|
),
|
|
|
|
const SizedBox(
|
|
height: FinanceDesignSystem.verticalSectionPadding),
|
|
|
|
// 2. Quick Actions
|
|
QuickActionsGrid(
|
|
onAddBalance: () =>
|
|
_showAddBalanceOptions(context, controller),
|
|
onWithdraw: () => addSyrianPaymentMethod(controller),
|
|
onTransfer: () => Get.to(() => TransferBudgetPage()),
|
|
onHistory: () async {
|
|
await Get.put(DriverWalletHistoryController())
|
|
.getArchivePayment();
|
|
Get.to(() => const PaymentHistoryDriverPage());
|
|
},
|
|
),
|
|
|
|
const SizedBox(
|
|
height: FinanceDesignSystem.verticalSectionPadding),
|
|
|
|
// 3. Earnings Summary
|
|
FinancialSummaryCard(
|
|
title: 'Earnings Summary'.tr,
|
|
subtitle: 'ملخص الأرباح'.tr,
|
|
items: [
|
|
SummaryItem(
|
|
icon: Icons.money_rounded,
|
|
label: 'Cash Earnings'.tr,
|
|
amount: controller.totalAmount,
|
|
color: FinanceDesignSystem.successGreen,
|
|
),
|
|
SummaryItem(
|
|
icon: Icons.credit_card_rounded,
|
|
label: 'Card Earnings'.tr,
|
|
amount: controller.totalAmountVisa,
|
|
color: FinanceDesignSystem.accentBlue,
|
|
),
|
|
],
|
|
),
|
|
|
|
const SizedBox(
|
|
height: FinanceDesignSystem.verticalSectionPadding),
|
|
|
|
// 3. Recharge Balance Packages
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text('Recharge Balance'.tr,
|
|
style: FinanceDesignSystem.headingStyle),
|
|
Icon(Icons.info_outline_rounded,
|
|
size: 18, color: Colors.grey.shade400),
|
|
],
|
|
),
|
|
const SizedBox(height: 12),
|
|
SizedBox(
|
|
height: 140, // Increased height for modern cards
|
|
child: ListView(
|
|
scrollDirection: Axis.horizontal,
|
|
physics: const BouncingScrollPhysics(),
|
|
children: [
|
|
PointsCaptain(
|
|
kolor: Colors.blueGrey,
|
|
pricePoint: 100,
|
|
countPoint: '100'),
|
|
PointsCaptain(
|
|
kolor: Colors.brown,
|
|
pricePoint: 200,
|
|
countPoint: '210'),
|
|
PointsCaptain(
|
|
kolor: Colors.amber,
|
|
pricePoint: 400,
|
|
countPoint: '450'),
|
|
PointsCaptain(
|
|
kolor: Colors.orange,
|
|
pricePoint: 1000,
|
|
countPoint: '1100'),
|
|
],
|
|
),
|
|
),
|
|
|
|
const SizedBox(
|
|
height: FinanceDesignSystem.verticalSectionPadding),
|
|
|
|
// 5. Promotions
|
|
Text('Promotions'.tr, style: FinanceDesignSystem.headingStyle),
|
|
const SizedBox(height: 12),
|
|
PromoGamificationCard(
|
|
title: 'Morning Promo'.tr,
|
|
subtitle: "from 7:00am to 10:00am".tr,
|
|
currentProgress: controller.walletDate['message']?[0]
|
|
?['morning_count'] ??
|
|
0,
|
|
targetProgress: 5,
|
|
reward: "+50 ${CurrencyHelper.currency}",
|
|
onTap: () =>
|
|
controller.addDriverWalletFromPromo('Morning Promo', 50),
|
|
),
|
|
const SizedBox(height: 16),
|
|
PromoGamificationCard(
|
|
title: 'Afternoon Promo'.tr,
|
|
subtitle: "from 3:00pm to 6:00 pm".tr,
|
|
currentProgress: controller.walletDate['message']?[0]
|
|
?['afternoon_count'] ??
|
|
0,
|
|
targetProgress: 5,
|
|
reward: "+50 ${CurrencyHelper.currency}",
|
|
onTap: () => controller.addDriverWalletFromPromo(
|
|
'Afternoon Promo', 50),
|
|
),
|
|
|
|
const SizedBox(
|
|
height: FinanceDesignSystem.verticalSectionPadding),
|
|
|
|
// 6. Transactions Preview
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text('Recent Transactions'.tr,
|
|
style: FinanceDesignSystem.headingStyle),
|
|
TextButton(
|
|
onPressed: () async {
|
|
await Get.put(DriverWalletHistoryController())
|
|
.getArchivePayment();
|
|
Get.to(() => const PaymentHistoryDriverPage());
|
|
},
|
|
child: Text('View All'.tr,
|
|
style: TextStyle(
|
|
color: FinanceDesignSystem.accentBlue,
|
|
fontWeight: FontWeight.bold)),
|
|
),
|
|
],
|
|
),
|
|
GetBuilder<DriverWalletHistoryController>(
|
|
init: DriverWalletHistoryController(),
|
|
builder: (historyController) {
|
|
if (historyController.archive.isEmpty) {
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(vertical: 20),
|
|
child: Center(
|
|
child: Text("No transactions yet".tr,
|
|
style: TextStyle(color: Colors.grey.shade400))),
|
|
);
|
|
}
|
|
// Show only last 3
|
|
final lastThree =
|
|
historyController.archive.take(3).toList();
|
|
return Column(
|
|
children: lastThree.map((tx) {
|
|
final double amount =
|
|
double.tryParse(tx['amount']?.toString() ?? '0') ??
|
|
0;
|
|
return TransactionPreviewItem(
|
|
title: amount >= 0 ? 'Credit'.tr : 'Debit'.tr,
|
|
subtitle: tx['created_at'] ?? '',
|
|
amount: amount.abs().toStringAsFixed(0),
|
|
date: tx['created_at']?.split(' ')[0] ?? '',
|
|
type: amount >= 0 ? 'credit' : 'debit',
|
|
onTap: () {},
|
|
);
|
|
}).toList(),
|
|
);
|
|
},
|
|
),
|
|
const SizedBox(height: 40),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
|
|
void _showAddBalanceOptions(
|
|
BuildContext context, CaptainWalletController controller) {
|
|
Get.bottomSheet(
|
|
Container(
|
|
padding: const EdgeInsets.all(24),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
|
|
),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text("Add Balance".tr, style: FinanceDesignSystem.headingStyle),
|
|
const SizedBox(height: 8),
|
|
Text("Select how you want to charge your account".tr,
|
|
style: FinanceDesignSystem.subHeadingStyle),
|
|
const SizedBox(height: 24),
|
|
ListTile(
|
|
leading: Container(
|
|
padding: const EdgeInsets.all(10),
|
|
decoration: BoxDecoration(
|
|
color:
|
|
FinanceDesignSystem.accentBlue.withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(12)),
|
|
child: Icon(Icons.account_balance_wallet_rounded,
|
|
color: FinanceDesignSystem.accentBlue),
|
|
),
|
|
title: Text("Pay from my budget".tr),
|
|
subtitle: Text(
|
|
"${'You have in account'.tr} ${controller.totalAmountVisa}"),
|
|
onTap: () {
|
|
Get.back();
|
|
_showPayFromBudgetDialog(controller);
|
|
},
|
|
),
|
|
const Divider(),
|
|
const SizedBox(height: 16),
|
|
Text("Recharge Balance Packages".tr,
|
|
style: FinanceDesignSystem.subHeadingStyle
|
|
.copyWith(fontWeight: FontWeight.bold)),
|
|
const SizedBox(height: 12),
|
|
SizedBox(
|
|
height: 140,
|
|
child: ListView(
|
|
scrollDirection: Axis.horizontal,
|
|
physics: const BouncingScrollPhysics(),
|
|
children: [
|
|
PointsCaptain(
|
|
kolor: Colors.blueGrey,
|
|
pricePoint: 100,
|
|
countPoint: '100'),
|
|
PointsCaptain(
|
|
kolor: Colors.brown, pricePoint: 200, countPoint: '210'),
|
|
PointsCaptain(
|
|
kolor: Colors.amber, pricePoint: 400, countPoint: '450'),
|
|
PointsCaptain(
|
|
kolor: Colors.orange,
|
|
pricePoint: 1000,
|
|
countPoint: '1100'),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _showPayFromBudgetDialog(CaptainWalletController controller) {
|
|
Get.defaultDialog(
|
|
title: 'Pay from my budget'.tr,
|
|
content: Form(
|
|
key: controller.formKey,
|
|
child: MyTextForm(
|
|
controller: controller.amountFromBudgetController,
|
|
label: '${'You have in account'.tr} ${controller.totalAmountVisa}',
|
|
hint: '${'You have in account'.tr} ${controller.totalAmountVisa}',
|
|
type: TextInputType.number,
|
|
),
|
|
),
|
|
confirm: MyElevatedButton(
|
|
title: 'Pay'.tr,
|
|
onPressed: () async {
|
|
bool isAvailable = await LocalAuthentication().isDeviceSupported();
|
|
if (isAvailable) {
|
|
bool didAuthenticate = await LocalAuthentication().authenticate(
|
|
localizedReason: 'Use Touch ID or Face ID to confirm payment'.tr,
|
|
biometricOnly: true,
|
|
sensitiveTransaction: true,
|
|
);
|
|
if (didAuthenticate) {
|
|
if (double.parse(controller.amountFromBudgetController.text) <
|
|
double.parse(controller.totalAmountVisa)) {
|
|
await controller.payFromBudget();
|
|
} else {
|
|
Get.back();
|
|
mySnackeBarError('Your Budget less than needed'.tr);
|
|
}
|
|
} else {
|
|
MyDialog().getDialog(
|
|
'Authentication failed'.tr, ''.tr, () => Get.back());
|
|
}
|
|
} else {
|
|
MyDialog().getDialog(
|
|
'Biometric Authentication'.tr,
|
|
'You should use Touch ID or Face ID to confirm payment'.tr,
|
|
() => Get.back());
|
|
}
|
|
},
|
|
),
|
|
cancel: MyElevatedButton(title: 'Cancel'.tr, onPressed: () => Get.back()),
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<dynamic> addSyrianPaymentMethod(
|
|
CaptainWalletController captainWalletController) {
|
|
return Get.defaultDialog(
|
|
title: "Insert Payment Details".tr,
|
|
content: Form(
|
|
key: captainWalletController.formKeyAccount,
|
|
child: Column(
|
|
children: [
|
|
Text(
|
|
"Insert your mobile wallet details to receive your money weekly"
|
|
.tr),
|
|
MyTextForm(
|
|
controller: captainWalletController.cardBank,
|
|
label: "Insert mobile wallet number".tr,
|
|
hint: '0912 345 678',
|
|
type: TextInputType.phone),
|
|
const SizedBox(height: 10),
|
|
MyDropDownSyria()
|
|
],
|
|
)),
|
|
confirm: MyElevatedButton(
|
|
title: 'Ok'.tr,
|
|
onPressed: () async {
|
|
if (captainWalletController.formKeyAccount.currentState!
|
|
.validate()) {
|
|
Get.back();
|
|
var res =
|
|
await CRUD().post(link: AppLink.updateAccountBank, payload: {
|
|
"paymentProvider":
|
|
Get.find<SyrianPayoutController>().dropdownValue.toString(),
|
|
"accountNumber":
|
|
captainWalletController.cardBank.text.toString(),
|
|
"id": box.read(BoxName.driverID).toString()
|
|
});
|
|
if (res != 'failure') {
|
|
mySnackbarSuccess('Payment details added successfully'.tr);
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
|
|
class SyrianPayoutController extends GetxController {
|
|
String dropdownValue = box.read(BoxName.countryCode) == 'Syria'
|
|
? 'syriatel'
|
|
: box.read(BoxName.countryCode) == 'Egypt'
|
|
? 'wallet payment'
|
|
: box.read(BoxName.countryCode) == 'Jordan'
|
|
? 'cliq'
|
|
: 'bank transfer';
|
|
void changeValue(String? newValue) {
|
|
if (newValue != null) {
|
|
dropdownValue = newValue;
|
|
update();
|
|
}
|
|
}
|
|
}
|
|
|
|
class MyDropDownSyria extends StatelessWidget {
|
|
const MyDropDownSyria({super.key});
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Get.put(SyrianPayoutController());
|
|
final theme = Theme.of(context);
|
|
return GetBuilder<SyrianPayoutController>(builder: (controller) {
|
|
return DropdownButton<String>(
|
|
value: controller.dropdownValue,
|
|
icon: const Icon(Icons.arrow_drop_down),
|
|
elevation: 16,
|
|
isExpanded: true,
|
|
dropdownColor: theme.cardColor,
|
|
style: TextStyle(color: theme.textTheme.bodyLarge?.color),
|
|
underline: Container(height: 2, color: theme.primaryColor),
|
|
onChanged: (String? newValue) => controller.changeValue(newValue),
|
|
items: (box.read(BoxName.countryCode) == 'Syria'
|
|
? <String>['syriatel', 'mtn cash', 'sham cash']
|
|
: box.read(BoxName.countryCode) == 'Egypt'
|
|
? <String>['wallet payment', 'bank card payment']
|
|
: box.read(BoxName.countryCode) == 'Jordan'
|
|
? <String>['cliq']
|
|
: <String>['bank transfer', 'wallet'])
|
|
.map<DropdownMenuItem<String>>((String value) {
|
|
return DropdownMenuItem<String>(value: value, child: Text(value.tr));
|
|
}).toList(),
|
|
);
|
|
});
|
|
}
|
|
}
|