Update: 2026-06-27 04:21:17

This commit is contained in:
Hamza-Ayed
2026-06-27 04:21:17 +03:00
parent b4f063aaac
commit 8993aa0a6b
6 changed files with 122 additions and 43 deletions

View File

@@ -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());
}
?>

View File

@@ -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<String, dynamic>.from(message[0]);
final match = message.cast<Map<String, dynamic>>().firstWhere(
(row) =>
(row['country'] ?? '').toString().toLowerCase() ==
countryParam.toLowerCase(),
orElse: () => message[0] as Map<String, dynamic>,
);
kazanData.value = Map<String, dynamic>.from(match);
kazanData['country'] = selectedCountry.value;
} else {
kazanData.value = {'country': selectedCountry.value};

View File

@@ -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)});

View File

@@ -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 = <String, String>{
'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 =

View File

@@ -400,7 +400,8 @@ class _MyAppState extends State<MyApp> 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<MyApp> with WidgetsBindingObserver {
// ==============================================================================
Future<void> _processAcceptOrder(List<dynamic> data) async {
if (_isProcessingAccept) {
print("⏳ _processAcceptOrder: Already accepting order, skipping duplicate request.");
print(
"⏳ _processAcceptOrder: Already accepting order, skipping duplicate request.");
return;
}
_isProcessingAccept = true;

View File

@@ -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)),
],
),
),
],
),
),
),
);