Files
Siro/siro_service/lib/controller/mainController/review_driver_controller.dart

685 lines
27 KiB
Dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:siro_service/constant/box_name.dart';
import 'package:siro_service/constant/links.dart';
import 'package:siro_service/controller/functions/crud.dart';
import 'package:siro_service/main.dart';
import 'package:siro_service/views/widgets/mycircular.dart';
class ReviewDriverController extends GetxController {
var isLoading = true.obs;
var isSaving = false.obs;
var driverId = ''.obs;
var phone = ''.obs;
var serverData = <String, dynamic>{}.obs;
var currentTabIndex = 0.obs;
final Map<String, RxString> docUrls = {
'id_front': ''.obs,
'id_back': ''.obs,
'driver_license': ''.obs,
'driver_license_back': ''.obs,
'car_license_front': ''.obs,
'car_license_back': ''.obs,
'criminal_record': ''.obs,
'profile_picture': ''.obs,
};
final Map<String, String> tabLabels = {
'id_front': 'ID Front',
'id_back': 'ID Back',
'driver_license': 'Driver License',
'driver_license_back': 'License Back',
'car_license_front': 'Car Reg Front',
'car_license_back': 'Car Reg Back',
'criminal_record': 'Criminal Record',
'profile_picture': 'Profile Photo',
};
final Map<String, IconData> tabIcons = {
'id_front': Icons.badge,
'id_back': Icons.badge_outlined,
'driver_license': Icons.drive_eta,
'driver_license_back': Icons.drive_eta_outlined,
'car_license_front': Icons.description,
'car_license_back': Icons.description_outlined,
'criminal_record': Icons.gavel,
'profile_picture': Icons.person,
};
var country = ''.obs;
var countryDetected = false;
/// Get current country code from box or server data
String get currentCountry {
if (country.value.isNotEmpty) return country.value;
final boxCountry = box.read('countryCode')?.toString() ?? '';
if (boxCountry.isNotEmpty) {
country.value = boxCountry;
return boxCountry;
}
final site = serverData['site'] ?? '';
if (site.contains('سوريا') || site.contains('دمشق') || site.contains('حلب')) {
country.value = 'Syria';
return 'Syria';
}
if (site.contains('أردن') || site.contains('عمان') || site.contains('اربد')) {
country.value = 'Jordan';
return 'Jordan';
}
country.value = 'Syria';
return 'Syria';
}
/// Field configuration: which fields appear on which tab, per country
/// Each entry: [key, label, isDate, isGender, isColor, isFuel]
static final Map<String, Map<String, List<List<dynamic>>>> countryFieldConfig = {
'Syria': {
'id_front': [
['firstNameController', 'First Name', false, false, false, false],
['lastNameController', 'Last Name', false, false, false, false],
['fatherNameController', 'Father Name', false, false, false, false],
['motherNameController', 'Mother Name', false, false, false, false],
['nationalNumberController', 'National Number', false, false, false, false],
['gender', 'Gender', false, true, false, false],
['birthdateController', 'Birthdate', true, false, false, false],
['birthPlaceController', 'Birth Place', false, false, false, false],
['bloodTypeController', 'Blood Type', false, false, false, false],
],
'id_back': [
['addressController', 'Address', false, false, false, false],
['governorateController', 'Governorate', false, false, false, false],
['siteController', 'Place of Registration', false, false, false, false],
['maritalStatusController', 'Marital Status', false, false, false, false],
['spouseNameController', 'Spouse Name', false, false, false, false],
['idIssueDateController', 'ID Issue Date', true, false, false, false],
['idExpiryDateController', 'ID Expiry Date', true, false, false, false],
],
'driver_license': [
['licenseNumberController', 'License Number', false, false, false, false],
['licenseCategoryController', 'License Category', false, false, false, false],
['licenseTypeController', 'License Type', false, false, false, false],
['licenseIssueDateController', 'Issue Date', true, false, false, false],
['expiryDateController', 'Expiry Date', true, false, false, false],
],
'driver_license_back': [
['restrictionsController', 'Restrictions', false, false, false, false],
],
'car_license_front': [
['ownerController', 'Owner Name', false, false, false, false],
['carPlateController', 'Car Plate', false, false, false, false],
['makeController', 'Make', false, false, false, false],
['modelController', 'Model', false, false, false, false],
['yearController', 'Year', false, false, false, false],
['color', 'Car Color', false, false, true, false],
],
'car_license_back': [
['vinController', 'VIN / Chassis', false, false, false, false],
['fuel', 'Fuel Type', false, false, false, true],
['engineCapacityController', 'Engine Capacity', false, false, false, false],
['carLicenseExpiryDateController', 'License Expiry', true, false, false, false],
],
'criminal_record': [],
'profile_picture': [
['phoneController', 'Phone Number', false, false, false, false],
['emailController', 'Email', false, false, false, false],
],
},
'Jordan': {
'id_front': [
['firstNameController', 'First Name', false, false, false, false],
['lastNameController', 'Last Name', false, false, false, false],
['nationalNumberController', 'National Number', false, false, false, false],
['gender', 'Gender', false, true, false, false],
['birthdateController', 'Birthdate', true, false, false, false],
['siteController', 'Place of Registration', false, false, false, false],
['governorateController', 'Governorate', false, false, false, false],
],
'id_back': [
['addressController', 'Address', false, false, false, false],
['idIssueDateController', 'ID Issue Date', true, false, false, false],
['idExpiryDateController', 'ID Expiry Date', true, false, false, false],
['bloodTypeController', 'Blood Type', false, false, false, false],
['maritalStatusController', 'Marital Status', false, false, false, false],
['spouseNameController', 'Spouse Name', false, false, false, false],
['occupationController', 'Occupation', false, false, false, false],
],
'driver_license': [
['licenseNumberController', 'License Number', false, false, false, false],
['licenseCategoryController', 'License Category', false, false, false, false],
['licenseIssueDateController', 'Issue Date', true, false, false, false],
['expiryDateController', 'Expiry Date', true, false, false, false],
],
'driver_license_back': [
['restrictionsController', 'Restrictions', false, false, false, false],
],
'car_license_front': [
['ownerController', 'Owner Name', false, false, false, false],
['carPlateController', 'Car Plate', false, false, false, false],
['makeController', 'Make', false, false, false, false],
['modelController', 'Model', false, false, false, false],
['yearController', 'Year', false, false, false, false],
['color', 'Car Color', false, false, true, false],
],
'car_license_back': [
['vinController', 'VIN / Chassis', false, false, false, false],
['fuel', 'Fuel Type', false, false, false, true],
['engineCapacityController', 'Engine Capacity', false, false, false, false],
['passengerCapacityController', 'Passenger Capacity', false, false, false, false],
['carLicenseExpiryDateController', 'License Expiry', true, false, false, false],
],
'criminal_record': [],
'profile_picture': [
['phoneController', 'Phone Number', false, false, false, false],
['emailController', 'Email', false, false, false, false],
],
},
'Egypt': {
'id_front': [
['firstNameController', 'First Name', false, false, false, false],
['lastNameController', 'Last Name', false, false, false, false],
['nationalNumberController', 'National Number', false, false, false, false],
['gender', 'Gender', false, true, false, false],
['birthdateController', 'Birthdate', true, false, false, false],
['governorateController', 'Governorate', false, false, false, false],
],
'id_back': [
['addressController', 'Address', false, false, false, false],
['idIssueDateController', 'ID Issue Date', true, false, false, false],
['idExpiryDateController', 'ID Expiry Date', true, false, false, false],
['occupationController', 'Occupation', false, false, false, false],
['maritalStatusController', 'Marital Status', false, false, false, false],
['religionController', 'Religion', false, false, false, false],
['bloodTypeController', 'Blood Type', false, false, false, false],
['spouseNameController', 'Spouse Name', false, false, false, false],
],
'driver_license': [
['licenseNumberController', 'License Number', false, false, false, false],
['licenseCategoryController', 'License Category', false, false, false, false],
['licenseIssueDateController', 'Issue Date', true, false, false, false],
['expiryDateController', 'Expiry Date', true, false, false, false],
],
'driver_license_back': [
['restrictionsController', 'Restrictions', false, false, false, false],
],
'car_license_front': [
['ownerController', 'Owner Name', false, false, false, false],
['carPlateController', 'Car Plate', false, false, false, false],
['makeController', 'Make', false, false, false, false],
['modelController', 'Model', false, false, false, false],
['yearController', 'Year', false, false, false, false],
['color', 'Car Color', false, false, true, false],
],
'car_license_back': [
['vinController', 'VIN / Chassis', false, false, false, false],
['fuel', 'Fuel Type', false, false, false, true],
['engineCapacityController', 'Engine Capacity', false, false, false, false],
['carLicenseExpiryDateController', 'License Expiry', true, false, false, false],
],
'criminal_record': [],
'profile_picture': [
['phoneController', 'Phone Number', false, false, false, false],
['emailController', 'Email', false, false, false, false],
],
},
};
List<List<dynamic>> getFieldsForTab(String tabKey) {
final c = currentCountry;
final config = countryFieldConfig[c] ?? countryFieldConfig['Syria']!;
return config[tabKey] ?? [];
}
late TextEditingController firstNameController;
late TextEditingController lastNameController;
late TextEditingController phoneController;
late TextEditingController emailController;
late TextEditingController siteController;
late TextEditingController nationalNumberController;
late TextEditingController birthdateController;
late TextEditingController addressController;
late TextEditingController licenseCategoriesController;
late TextEditingController licenseTypeController;
late TextEditingController expiryDateController;
late TextEditingController licenseIssueDateController;
late TextEditingController ownerController;
late TextEditingController carPlateController;
late TextEditingController vinController;
late TextEditingController carLicenseExpiryDateController;
late TextEditingController makeController;
late TextEditingController modelController;
late TextEditingController yearController;
late TextEditingController fatherNameController;
late TextEditingController motherNameController;
late TextEditingController birthPlaceController;
late TextEditingController bloodTypeController;
late TextEditingController maritalStatusController;
late TextEditingController spouseNameController;
late TextEditingController idIssueDateController;
late TextEditingController idExpiryDateController;
late TextEditingController licenseNumberController;
late TextEditingController licenseCategoryController;
late TextEditingController restrictionsController;
late TextEditingController governorateController;
late TextEditingController occupationController;
late TextEditingController religionController;
late TextEditingController engineCapacityController;
late TextEditingController passengerCapacityController;
var selectedGender = ''.obs;
var colorHex = ''.obs;
var colorName = ''.obs;
var selectedFuel = ''.obs;
@override
void onInit() {
super.onInit();
_initializeTextControllers();
final args = Get.arguments;
if (args != null) {
driverId.value = args['driverId'] ?? '';
phone.value = args['phone'] ?? '';
}
fetchData();
}
void _initializeTextControllers() {
firstNameController = TextEditingController();
lastNameController = TextEditingController();
phoneController = TextEditingController();
emailController = TextEditingController();
siteController = TextEditingController();
nationalNumberController = TextEditingController();
birthdateController = TextEditingController();
addressController = TextEditingController();
licenseCategoriesController = TextEditingController();
licenseTypeController = TextEditingController();
expiryDateController = TextEditingController();
licenseIssueDateController = TextEditingController();
ownerController = TextEditingController();
carPlateController = TextEditingController();
vinController = TextEditingController();
carLicenseExpiryDateController = TextEditingController();
makeController = TextEditingController();
modelController = TextEditingController();
yearController = TextEditingController();
fatherNameController = TextEditingController();
motherNameController = TextEditingController();
birthPlaceController = TextEditingController();
bloodTypeController = TextEditingController();
maritalStatusController = TextEditingController();
spouseNameController = TextEditingController();
idIssueDateController = TextEditingController();
idExpiryDateController = TextEditingController();
licenseNumberController = TextEditingController();
licenseCategoryController = TextEditingController();
restrictionsController = TextEditingController();
governorateController = TextEditingController();
occupationController = TextEditingController();
religionController = TextEditingController();
engineCapacityController = TextEditingController();
passengerCapacityController = TextEditingController();
}
Future<void> fetchData() async {
isLoading.value = true;
try {
var response = await CRUD().post(
link: AppLink.getDriverDetailsForActivate,
payload: {'driverId': driverId.value},
);
if (response != 'failure' &&
response['status'] == 'success' &&
(response['message'] as List).isNotEmpty) {
var raw = response['message'][0] as Map<String, dynamic>;
serverData.value =
raw.map((key, value) => MapEntry(key, value?.toString() ?? ''));
_populateControllers();
_populateDocUrls(raw['documents']);
}
} catch (e) {
mySnackeBarError('Failed to load data: $e');
} finally {
isLoading.value = false;
}
}
void _populateDocUrls(dynamic docs) {
if (docs is List) {
for (var doc in docs) {
if (doc is Map && doc['doc_type'] != null && doc['link'] != null) {
String type = doc['doc_type'].toString();
if (docUrls.containsKey(type)) {
docUrls[type]!.value = doc['link'].toString();
}
}
}
}
}
void _populateControllers() {
firstNameController.text = serverData['first_name'] ?? '';
lastNameController.text = serverData['last_name'] ?? '';
phoneController.text = serverData['phone'] ?? '';
emailController.text = serverData['email'] ?? '';
siteController.text = serverData['site'] ?? '';
nationalNumberController.text = serverData['national_number'] ?? '';
birthdateController.text = serverData['birthdate'] ?? '';
addressController.text = serverData['address'] ?? '';
licenseCategoriesController.text = serverData['license_categories'] ?? '';
licenseTypeController.text = serverData['license_type'] ?? '';
expiryDateController.text = serverData['expiry_date'] ?? '';
licenseIssueDateController.text =
serverData['licenseIssueDate'] ?? serverData['issue_date'] ?? '';
selectedGender.value = serverData['gender'] ?? '';
ownerController.text = serverData['owner'] ?? '';
carPlateController.text = serverData['car_plate'] ?? '';
vinController.text = serverData['vin'] ?? '';
carLicenseExpiryDateController.text =
serverData['expiration_date'] ?? '';
makeController.text = serverData['make'] ?? '';
modelController.text = serverData['model'] ?? '';
yearController.text = serverData['year'] ?? '';
selectedFuel.value = serverData['fuel'] ?? '';
fatherNameController.text = serverData['father_name'] ?? '';
motherNameController.text = serverData['mother_name'] ?? '';
birthPlaceController.text = serverData['birth_place'] ?? '';
bloodTypeController.text = serverData['blood_type'] ?? '';
maritalStatusController.text = serverData['marital_status'] ?? '';
spouseNameController.text = serverData['spouse_name'] ?? '';
idIssueDateController.text = serverData['id_issue_date'] ?? '';
idExpiryDateController.text = serverData['id_expiry_date'] ?? '';
licenseNumberController.text = serverData['license_number'] ?? '';
licenseCategoryController.text = serverData['license_category'] ?? '';
restrictionsController.text = serverData['restrictions'] ?? '';
governorateController.text = serverData['governorate'] ?? '';
occupationController.text = serverData['occupation'] ?? '';
religionController.text = serverData['religion'] ?? '';
engineCapacityController.text = serverData['engine_capacity'] ?? '';
passengerCapacityController.text = serverData['passenger_capacity'] ?? '';
// Detect country from server data if available
if (!countryDetected) {
countryDetected = true;
if (serverData['country']?.isNotEmpty == true) {
country.value = serverData['country']!;
} else if (serverData['site']?.isNotEmpty == true) {
final s = serverData['site']!;
if (s.contains('سوريا') || s.contains('دمشق')) {
country.value = 'Syria';
} else if (s.contains('أردن') || s.contains('عمان')) {
country.value = 'Jordan';
} else if (s.contains('مصر') || s.contains('القاهرة')) {
country.value = 'Egypt';
}
}
}
final serverColorName = serverData['color'] ?? '';
final colorOption = kCarColorOptions.firstWhere(
(opt) => opt['key'] == serverColorName,
orElse: () => {'key': serverColorName, 'hex': '#000000'},
);
colorName.value = colorOption['key']!;
colorHex.value = colorOption['hex']!;
phone.value = serverData['phone'] ?? '';
}
Future<void> selectDate(
BuildContext context, TextEditingController controller) async {
DateTime initialDate = DateTime.now();
try {
if (controller.text.isNotEmpty) {
initialDate = DateFormat('yyyy-MM-dd').parse(controller.text);
}
} catch (_) {}
DateTime? pickedDate = initialDate;
await showCupertinoModalPopup<void>(
context: context,
builder: (context) => Container(
height: 280,
color: CupertinoColors.systemBackground.resolveFrom(context),
child: Column(
children: [
SizedBox(
height: 200,
child: CupertinoDatePicker(
initialDateTime: initialDate,
minimumDate: DateTime(1950),
maximumDate: DateTime(2050),
mode: CupertinoDatePickerMode.date,
onDateTimeChanged: (DateTime newDate) {
pickedDate = newDate;
},
),
),
CupertinoButton(
child: const Text('Done'),
onPressed: () {
if (pickedDate != null) {
controller.text =
DateFormat('yyyy-MM-dd').format(pickedDate!);
}
Navigator.of(context).pop();
},
),
],
),
),
);
}
Map<String, dynamic> _buildPayload() {
return {
'driverId': driverId.value,
'phone': phoneController.text,
'first_name': firstNameController.text,
'last_name': lastNameController.text,
'site': siteController.text,
'national_number': nationalNumberController.text,
'gender': selectedGender.value,
'birthdate': birthdateController.text,
'address': addressController.text,
'email': emailController.text,
'license_type': licenseTypeController.text,
'license_categories': licenseCategoriesController.text,
'expiry_date': expiryDateController.text,
'license_issue_date': licenseIssueDateController.text,
'maritalStatus': box.read(BoxName.employeename) ?? 'unknown',
'owner': ownerController.text,
'color': colorName.value,
'color_hex': colorHex.value,
'car_plate': carPlateController.text,
'expiration_date': carLicenseExpiryDateController.text,
'make': makeController.text,
'model': modelController.text,
'fuel': selectedFuel.value,
'year': yearController.text,
'vin': vinController.text,
};
}
Future<void> saveChanges() async {
isSaving.value = true;
try {
var payload = _buildPayload();
payload['status'] = 'pending_review';
var response = await CRUD().post(
link: AppLink.updateDriverToActive,
payload: payload,
);
if (response != 'failure' && response['status'] == 'success') {
mySnackbarSuccess('Data saved successfully');
} else {
mySnackeBarError('Failed to save changes');
}
} catch (e) {
mySnackeBarError('Error: $e');
} finally {
isSaving.value = false;
}
}
Future<void> activateDriver() async {
isSaving.value = true;
try {
var payload = _buildPayload();
var response = await CRUD().post(
link: AppLink.updateDriverToActive,
payload: payload,
);
if (response != 'failure' && response['status'] == 'success') {
mySnackbarSuccess('Driver activated successfully!');
await Future.delayed(const Duration(milliseconds: 500));
Get.back();
} else {
mySnackeBarError('Failed to activate driver');
}
} catch (e) {
mySnackeBarError('Error: $e');
} finally {
isSaving.value = false;
}
}
Future<void> rejectDriver(String reason) async {
if (reason.trim().isEmpty) {
mySnackeBarError('Please enter a rejection reason');
return;
}
isSaving.value = true;
try {
var response = await CRUD().post(
link: AppLink.rejectDriver,
payload: {
'driverId': driverId.value,
'reason': reason.trim(),
},
);
if (response != 'failure' && response['status'] == 'success') {
mySnackbarSuccess('Driver rejected');
await Future.delayed(const Duration(milliseconds: 500));
Get.back();
} else {
mySnackeBarError('Failed to reject driver');
}
} catch (e) {
mySnackeBarError('Error: $e');
} finally {
isSaving.value = false;
}
}
void showRejectDialog() {
final reasonController = TextEditingController();
Get.defaultDialog(
title: 'Reject Driver'.tr,
content: Padding(
padding: const EdgeInsets.all(8),
child: TextField(
controller: reasonController,
maxLines: 3,
decoration: InputDecoration(
hintText: 'Enter rejection reason...'.tr,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
),
),
confirm: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
onPressed: () => rejectDriver(reasonController.text),
child: Text('Reject'.tr, style: const TextStyle(color: Colors.white)),
),
cancel: ElevatedButton(
onPressed: () => Get.back(),
child: Text('Cancel'.tr),
),
);
}
static const List<Map<String, String>> kCarColorOptions = [
{'key': 'white', 'hex': '#FFFFFF'},
{'key': 'black', 'hex': '#000000'},
{'key': 'silver', 'hex': '#C0C0C0'},
{'key': 'gray', 'hex': '#808080'},
{'key': 'gunmetal', 'hex': '#2A3439'},
{'key': 'red', 'hex': '#C62828'},
{'key': 'blue', 'hex': '#1565C0'},
{'key': 'navy', 'hex': '#0D47A1'},
{'key': 'green', 'hex': '#2E7D32'},
{'key': 'darkGreen', 'hex': '#1B5E20'},
{'key': 'beige', 'hex': '#D7CCC8'},
{'key': 'brown', 'hex': '#5D4037'},
{'key': 'maroon', 'hex': '#800000'},
{'key': 'burgundy', 'hex': '#800020'},
{'key': 'yellow', 'hex': '#F9A825'},
{'key': 'orange', 'hex': '#EF6C00'},
{'key': 'gold', 'hex': '#D4AF37'},
{'key': 'bronze', 'hex': '#CD7F32'},
{'key': 'champagne', 'hex': '#EFE1C6'},
{'key': 'purple', 'hex': '#6A1B9A'},
];
static const List<String> kFuelOptions = [
'بنزين',
'ديزل',
'هايبرد',
'كهربائي',
];
Color hexToColor(String code) =>
Color(int.parse(code.substring(1, 7), radix: 16) + 0xFF000000);
void updateColorSelection(String hex) {
colorHex.value = hex;
colorName.value =
kCarColorOptions.firstWhere((o) => o['hex'] == hex)['key']!;
}
@override
void onClose() {
firstNameController.dispose();
lastNameController.dispose();
phoneController.dispose();
emailController.dispose();
siteController.dispose();
nationalNumberController.dispose();
birthdateController.dispose();
addressController.dispose();
licenseCategoriesController.dispose();
licenseTypeController.dispose();
expiryDateController.dispose();
licenseIssueDateController.dispose();
ownerController.dispose();
carPlateController.dispose();
vinController.dispose();
carLicenseExpiryDateController.dispose();
makeController.dispose();
modelController.dispose();
yearController.dispose();
fatherNameController.dispose();
motherNameController.dispose();
birthPlaceController.dispose();
bloodTypeController.dispose();
maritalStatusController.dispose();
spouseNameController.dispose();
idIssueDateController.dispose();
idExpiryDateController.dispose();
licenseNumberController.dispose();
licenseCategoryController.dispose();
restrictionsController.dispose();
governorateController.dispose();
occupationController.dispose();
religionController.dispose();
engineCapacityController.dispose();
passengerCapacityController.dispose();
super.onClose();
}
}