From 8993aa0a6bdd60946323ae5ab4fabc9442cbc857 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sat, 27 Jun 2026 04:21:17 +0300 Subject: [PATCH] Update: 2026-06-27 04:21:17 --- .../syria/driver/register_driver_and_car.php | 7 +- .../controller/admin/kazan_controller.dart | 8 +- .../auth/captin/login_captin_controller.dart | 7 ++ .../auth/syria/registration_controller.dart | 32 ++++-- siro_driver/lib/main.dart | 6 +- .../views/auth/syria/registration_view.dart | 105 +++++++++++++----- 6 files changed, 122 insertions(+), 43 deletions(-) diff --git a/backend/auth/syria/driver/register_driver_and_car.php b/backend/auth/syria/driver/register_driver_and_car.php index bd872d05..6d74a04f 100644 --- a/backend/auth/syria/driver/register_driver_and_car.php +++ b/backend/auth/syria/driver/register_driver_and_car.php @@ -583,13 +583,14 @@ $pwdHashed = password_hash($rawSecret, PASSWORD_DEFAULT); if (isset($con) && $con instanceof PDO && $con->inTransaction()) { $con->rollBack(); } - error_log("register_driver_and_car ERROR: " . $e->getMessage()); - jsonError("Server error"); + $msg = $e->getMessage(); + error_log("register_driver_and_car ERROR: " . $msg); + jsonError("Server error: $msg", 400); } catch (PDOException $e) { if (isset($con) && $con instanceof PDO && $con->inTransaction()) { $con->rollBack(); } error_log("register_driver_and_car PDO: " . $e->getMessage()); - jsonError("Database error."); + jsonError("Database error: " . $e->getMessage()); } ?> \ No newline at end of file diff --git a/siro_admin/lib/controller/admin/kazan_controller.dart b/siro_admin/lib/controller/admin/kazan_controller.dart index 07aa9e43..57bcbbdf 100644 --- a/siro_admin/lib/controller/admin/kazan_controller.dart +++ b/siro_admin/lib/controller/admin/kazan_controller.dart @@ -43,7 +43,13 @@ class KazanController extends GetxController { if (decoded['status'] == "success") { var message = decoded['message']; if (message is List && message.isNotEmpty) { - kazanData.value = Map.from(message[0]); + final match = message.cast>().firstWhere( + (row) => + (row['country'] ?? '').toString().toLowerCase() == + countryParam.toLowerCase(), + orElse: () => message[0] as Map, + ); + kazanData.value = Map.from(match); kazanData['country'] = selectedCountry.value; } else { kazanData.value = {'country': selectedCountry.value}; diff --git a/siro_driver/lib/controller/auth/captin/login_captin_controller.dart b/siro_driver/lib/controller/auth/captin/login_captin_controller.dart index d53051e0..a1e6b8ff 100755 --- a/siro_driver/lib/controller/auth/captin/login_captin_controller.dart +++ b/siro_driver/lib/controller/auth/captin/login_captin_controller.dart @@ -102,6 +102,13 @@ class LoginDriverController extends GetxController { // } isPhoneVerified() async { + // If the phone is already verified locally and we have a driver ID, skip the API check + // This prevents asking for OTP again if the user restarts the app during registration. + if (box.read(BoxName.phoneVerified) == '1' && box.read(BoxName.driverID) != null) { + Get.offAll(() => RegistrationView()); + return; + } + var res = await CRUD().post( link: AppLink.isPhoneVerified, payload: {'phone_number': box.read(BoxName.phoneDriver)}); diff --git a/siro_driver/lib/controller/auth/syria/registration_controller.dart b/siro_driver/lib/controller/auth/syria/registration_controller.dart index 92a9e010..edbffd36 100644 --- a/siro_driver/lib/controller/auth/syria/registration_controller.dart +++ b/siro_driver/lib/controller/auth/syria/registration_controller.dart @@ -371,9 +371,15 @@ class RegistrationController extends GetxController { final _jwt = box.read(BoxName.jwt); final String _token = _jwt != null ? r(_jwt).split(AppInformation.addd)[0] : ''; + + String timestamp = DateTime.now().millisecondsSinceEpoch.toString(); + String nonce = timestamp; + final headers = { 'Authorization': 'Bearer $_token', - 'X-HMAC-Auth': '${box.read(BoxName.hmac)}', + 'X-Device-FP': box.read(BoxName.deviceFingerprint)?.toString() ?? '', + 'X-Timestamp': timestamp, + 'X-Nonce': nonce, }; request.headers.addAll(headers); @@ -472,7 +478,7 @@ class RegistrationController extends GetxController { final req = http.MultipartRequest('POST', syrianUploadUri); req.headers.addAll({ 'Authorization': authHeader, - 'X-HMAC-Auth': hmacHeader, + 'X-Device-FP': box.read(BoxName.deviceFingerprint)?.toString() ?? '', }); req.fields['driver_id'] = driverId; @@ -603,11 +609,14 @@ class RegistrationController extends GetxController { _addField(fields, 'expiry_date', driverLicenseExpiryController.text); _addField(fields, 'password', 'generated_password_or_token'); _addField(fields, 'status', 'yet'); - _addField(fields, 'email', 'Not specified'); + + String generatedEmail = 'driver_${box.read(BoxName.driverID) ?? DateTime.now().millisecondsSinceEpoch}@siromove.com'; + _addField(fields, 'email', generatedEmail); _addField(fields, 'gender', 'Male'); // يفضل ربطها بـ Dropdown أيضاً + _addField(fields, 'country', box.read(BoxName.countryCode)?.toString() ?? 'Jordan'); // --- Car Data --- - _addField(fields, 'vin', 'yet'); + _addField(fields, 'vin', carVinController.text.isNotEmpty ? carVinController.text : 'yet'); _addField(fields, 'car_plate', carPlateController.text); _addField(fields, 'make', carMakeController.text); _addField(fields, 'model', carModelController.text); @@ -615,8 +624,9 @@ class RegistrationController extends GetxController { _addField( fields, 'expiration_date', - driverLicenseExpiryController - .text); // تأكد من أن هذا تاريخ انتهاء السيارة وليس الرخصة + carRegistrationExpiryController.text.isNotEmpty + ? carRegistrationExpiryController.text + : driverLicenseExpiryController.text); _addField( fields, 'color', @@ -668,14 +678,20 @@ class RegistrationController extends GetxController { _addField(fields, 'id_front', idFrontUrl); _addField(fields, 'id_back', idBackUrl); _addField(fields, 'driver_license', driverLicenseUrl); - if (isSyria) - _addField(fields, 'driver_license_back', driverLicenseBackUrl); + // Always add the key to avoid PHP undefined index error + fields['driver_license_back'] = driverLicenseBackUrl ?? ''; _addField(fields, 'profile_picture', profilePicUrl); _addField(fields, 'criminal_record', criminalRecordUrl); _addField(fields, 'car_license_front', carFrontUrl); _addField(fields, 'car_license_back', carBackUrl); req.fields.addAll(fields); + + Log.print('--- 🚀 Registration Request Payload ---'); + req.fields.forEach((key, value) { + Log.print('[$key]: $value'); + }); + Log.print('---------------------------------------'); // 3) الإرسال final streamed = diff --git a/siro_driver/lib/main.dart b/siro_driver/lib/main.dart index c668013e..96529a89 100755 --- a/siro_driver/lib/main.dart +++ b/siro_driver/lib/main.dart @@ -400,7 +400,8 @@ class _MyAppState extends State with WidgetsBindingObserver { if (savedTrip != null && savedTrip.isNotEmpty) { if (Get.currentRoute == '/') { - print('⏳ App is still on Splash screen. Postponing notification trip navigation to HomeCaptainController.'); + print( + '⏳ App is still on Splash screen. Postponing notification trip navigation to HomeCaptainController.'); return; } await storage.delete(key: 'pending_driver_list'); @@ -425,7 +426,8 @@ class _MyAppState extends State with WidgetsBindingObserver { // ============================================================================== Future _processAcceptOrder(List data) async { if (_isProcessingAccept) { - print("⏳ _processAcceptOrder: Already accepting order, skipping duplicate request."); + print( + "⏳ _processAcceptOrder: Already accepting order, skipping duplicate request."); return; } _isProcessingAccept = true; diff --git a/siro_driver/lib/views/auth/syria/registration_view.dart b/siro_driver/lib/views/auth/syria/registration_view.dart index 9c698ec4..569cac86 100644 --- a/siro_driver/lib/views/auth/syria/registration_view.dart +++ b/siro_driver/lib/views/auth/syria/registration_view.dart @@ -450,36 +450,83 @@ class RegistrationView extends StatelessWidget { child: SizedBox( height: 150, width: double.infinity, - child: (img != null && img.isNotEmpty) - ? Image.network( - img, - fit: BoxFit.cover, - errorBuilder: (context, error, stackTrace) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.broken_image, size: 40, color: Colors.red), - const SizedBox(height: 8), - Text('Image not available', - style: TextStyle(color: Colors.red[700])), - ], - ), - ); - }, - ) - : Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.camera_alt_outlined, - size: 40, color: Colors.grey[600]), - const SizedBox(height: 8), - Text(title, style: TextStyle(color: Colors.grey[700])), - Text('Tap to upload'.tr, - style: - const TextStyle(color: Colors.grey, fontSize: 12)), - ], + child: Stack( + children: [ + // Card template background + Container( + width: double.infinity, + height: double.infinity, + decoration: BoxDecoration( + color: Colors.grey[100], + borderRadius: BorderRadius.circular(4), + border: Border.all( + color: Colors.grey[300]!, + width: 1.5, + strokeAlign: BorderSide.strokeAlignInside, + ), ), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.credit_card, size: 48, color: Colors.grey[300]), + const SizedBox(height: 8), + Text( + title, + style: TextStyle( + color: Colors.grey[400], + fontSize: 13, + fontWeight: FontWeight.w500, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ), + // Uploaded image with 50% opacity + if (img != null && img.isNotEmpty) + Positioned.fill( + child: Opacity( + opacity: 0.5, + child: ClipRRect( + borderRadius: BorderRadius.circular(4), + child: Image.network( + img, + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.broken_image, size: 40, color: Colors.red), + const SizedBox(height: 8), + Text('Image not available', + style: TextStyle(color: Colors.red[700])), + ], + ), + ); + }, + ), + ), + ), + ), + // Empty state with camera icon + if (img == null || img.isEmpty) + Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.camera_alt_outlined, + size: 40, color: Colors.grey[600]), + const SizedBox(height: 8), + Text('Tap to upload'.tr, + style: const TextStyle(color: Colors.grey, fontSize: 12)), + ], + ), + ), + ], + ), ), ), );