Compare commits

2 Commits
Author SHA1 Message Date
Hamza-Ayed 92eb7fe25d Update: 2026-07-23 20:43:21 2026-07-23 20:43:21 +03:00
Hamza-Ayed 1e785061ec Fix decryptData null type error and live analytics overflow 2026-07-23 20:42:48 +03:00
8 changed files with 84 additions and 44 deletions
+9 -9
View File
@@ -67,15 +67,15 @@ $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
// فك تشفير الحقول الحساسة // فك تشفير الحقول الحساسة
foreach ($result as &$row) { foreach ($result as &$row) {
$row['phone'] = $encryptionHelper->decryptData($row['phone']); $row['phone'] = $encryptionHelper->decryptData($row['phone'] ?? '') ?: ($row['phone'] ?? '');
$row['email'] = $encryptionHelper->decryptData($row['email']); $row['email'] = $encryptionHelper->decryptData($row['email'] ?? '') ?: ($row['email'] ?? '');
$row['gender'] = $encryptionHelper->decryptData($row['gender']); $row['gender'] = $encryptionHelper->decryptData($row['gender'] ?? '') ?: ($row['gender'] ?? 'unknown yet');
$row['birthdate'] = $encryptionHelper->decryptData($row['birthdate']); $row['birthdate'] = $encryptionHelper->decryptData($row['birthdate'] ?? '') ?: ($row['birthdate'] ?? 'unknown yet');
$row['site'] = $encryptionHelper->decryptData($row['site']); $row['site'] = $encryptionHelper->decryptData($row['site'] ?? '') ?: ($row['site'] ?? 'unknown yet');
$row['first_name'] = $encryptionHelper->decryptData($row['first_name']); $row['first_name'] = $encryptionHelper->decryptData($row['first_name'] ?? '') ?: ($row['first_name'] ?? '');
$row['last_name'] = $encryptionHelper->decryptData($row['last_name']); $row['last_name'] = $encryptionHelper->decryptData($row['last_name'] ?? '') ?: ($row['last_name'] ?? '');
$row['employmentType'] = $encryptionHelper->decryptData($row['employmentType']); $row['employmentType'] = $encryptionHelper->decryptData($row['employmentType'] ?? '') ?: ($row['employmentType'] ?? 'unknown yet');
$row['maritalStatus'] = $encryptionHelper->decryptData($row['maritalStatus']); $row['maritalStatus'] = $encryptionHelper->decryptData($row['maritalStatus'] ?? '') ?: ($row['maritalStatus'] ?? 'unknown yet');
} }
$countStmt = $con->query("SELECT COUNT(*) FROM `driver`"); $countStmt = $con->query("SELECT COUNT(*) FROM `driver`");
+2 -1
View File
@@ -44,8 +44,9 @@ class EncryptionHelper
} }
// ─── فك تشفير نص (يدعم CBC والـ GCM المستقبلي) ─────────── // ─── فك تشفير نص (يدعم CBC والـ GCM المستقبلي) ───────────
public function decryptData(string $cipherText): string|false public function decryptData(?string $cipherText): string|false
{ {
if (empty($cipherText)) return '';
// تحقق إن كان مشفر بالنظام الجديد // تحقق إن كان مشفر بالنظام الجديد
if (str_starts_with($cipherText, self::PREFIX_GCM)) { if (str_starts_with($cipherText, self::PREFIX_GCM)) {
$raw = base64_decode(substr($cipherText, strlen(self::PREFIX_GCM)), true); $raw = base64_decode(substr($cipherText, strlen(self::PREFIX_GCM)), true);
+1 -2
View File
@@ -51,8 +51,7 @@ class AppLink {
case 'Egypt': case 'Egypt':
return 'https://location-egypt.siromove.com/siro/ride/location'; return 'https://location-egypt.siromove.com/siro/ride/location';
case 'Jordan': case 'Jordan':
// TODO: Change to new subdomain when fully migrated return 'https://jordan-siro.intaleqapp.com/loction_server/siro/ride/location';
return 'https://location.intaleq.xyz/intaleq/ride/location';
default: default:
return 'https://location.siromove.com/siro/ride/location'; return 'https://location.siromove.com/siro/ride/location';
} }
+25 -7
View File
@@ -1,3 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:jwt_decoder/jwt_decoder.dart'; import 'package:jwt_decoder/jwt_decoder.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -17,10 +19,8 @@ import '../functions/crud.dart';
import '../functions/encrypt_decrypt.dart'; import '../functions/encrypt_decrypt.dart';
class OtpHelper extends GetxController { class OtpHelper extends GetxController {
static final String _sendOtpUrl = static final String _sendOtpUrl = '${AppLink.server}/auth/otp/request.php';
'${AppLink.server}/auth/otp/request.php'; static final String _verifyOtpUrl = '${AppLink.server}/auth/otp/verify.php';
static final String _verifyOtpUrl =
'${AppLink.server}/auth/otp/verify.php';
static final String _checkAdminLogin = static final String _checkAdminLogin =
'${AppLink.server}/Admin/auth/login.php'; '${AppLink.server}/Admin/auth/login.php';
@@ -185,7 +185,13 @@ class OtpHelper extends GetxController {
await box.write(BoxName.phoneVerified, true); await box.write(BoxName.phoneVerified, true);
await box.write('admin_password', password); await box.write('admin_password', password);
FirebaseMessaging.instance.subscribeToTopic('admin_alerts'); if (Platform.isAndroid || Platform.isIOS) {
try {
FirebaseMessaging.instance.subscribeToTopic('admin_alerts');
} catch (e) {
Log.print('FCM Subscribe error: $e');
}
}
mySnackbarSuccess('تم تسجيل الدخول بنجاح'); mySnackbarSuccess('تم تسجيل الدخول بنجاح');
return true; return true;
@@ -241,7 +247,13 @@ class OtpHelper extends GetxController {
String token = r(rawJwt.toString()).split(AppInformation.addd)[0]; String token = r(rawJwt.toString()).split(AppInformation.addd)[0];
if (!JwtDecoder.isExpired(token)) { if (!JwtDecoder.isExpired(token)) {
Log.print('Valid JWT found, skipping login.php (no OTP needed)'); Log.print('Valid JWT found, skipping login.php (no OTP needed)');
FirebaseMessaging.instance.subscribeToTopic('admin_alerts'); if (Platform.isAndroid || Platform.isIOS) {
try {
FirebaseMessaging.instance.subscribeToTopic('admin_alerts');
} catch (e) {
Log.print('FCM Subscribe error: $e');
}
}
Get.offAll(() => const AdminHomePage()); Get.offAll(() => const AdminHomePage());
return; return;
} }
@@ -279,7 +291,13 @@ class OtpHelper extends GetxController {
} else if (response['jwt'] != null) { } else if (response['jwt'] != null) {
box.write(BoxName.jwt, c(response['jwt'])); box.write(BoxName.jwt, c(response['jwt']));
} }
FirebaseMessaging.instance.subscribeToTopic('admin_alerts'); if (Platform.isAndroid || Platform.isIOS) {
try {
FirebaseMessaging.instance.subscribeToTopic('admin_alerts');
} catch (e) {
Log.print('FCM Subscribe error: $e');
}
}
try { try {
if (Get.isRegistered<DashboardController>()) { if (Get.isRegistered<DashboardController>()) {
Get.find<DashboardController>().getDashBoard(); Get.find<DashboardController>().getDashBoard();
@@ -137,6 +137,7 @@ class _StatCard extends StatelessWidget {
border: Border.all(color: AppColor.divider), border: Border.all(color: AppColor.divider),
), ),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
@@ -150,22 +151,30 @@ class _StatCard extends StatelessWidget {
style: const TextStyle( style: const TextStyle(
fontSize: 11, fontSize: 11,
color: AppColor.textMuted, color: AppColor.textMuted,
fontWeight: FontWeight.w600)), fontWeight: FontWeight.w600),
maxLines: 1,
overflow: TextOverflow.ellipsis),
), ),
], ],
), ),
const SizedBox(height: 8), const SizedBox(height: 4),
Text(value, FittedBox(
style: const TextStyle( fit: BoxFit.scaleDown,
fontSize: 24, alignment: Alignment.centerRight,
fontWeight: FontWeight.w700, child: Text(value,
color: AppColor.textPrimary)), style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.w700,
color: AppColor.textPrimary)),
),
if (sub != null) ...[ if (sub != null) ...[
const SizedBox(height: 4), const SizedBox(height: 2),
Text(sub!, Text(sub!,
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 10,
color: subColor ?? AppColor.textSecondary)), color: subColor ?? AppColor.textSecondary),
maxLines: 1,
overflow: TextOverflow.ellipsis),
], ],
], ],
), ),
@@ -154,15 +154,21 @@ class FirebaseMessagesController extends GetxController {
driverToken = myList[14].toString(); driverToken = myList[14].toString();
Get.put(HomeCaptainController(), permanent: true).changeRideId(); Get.put(HomeCaptainController(), permanent: true).changeRideId();
update(); update();
Get.toNamed('/OrderRequestPage', arguments: {
'myListString': myListString, if (Get.currentRoute != '/OrderRequestPage') {
'DriverList': myList, Log.print("🚀 FCM: Navigating to OrderRequestPage...");
'body': body, Get.toNamed('/OrderRequestPage', arguments: {
'is_destination_match': message.data['is_destination_match'] ?? '0', 'myListString': myListString,
// 🆕 "أرباحك أعلى" — يُرسَل فقط عند وجود فرق إيجابي حقيقي 'DriverList': myList,
'driver_earnings_extra': message.data['driver_earnings_extra'], 'body': body,
'driver_earnings_currency': message.data['driver_earnings_currency'], 'is_destination_match': message.data['is_destination_match'] ?? '0',
}); // 🆕 "أرباحك أعلى" — يُرسَل فقط عند وجود فرق إيجابي حقيقي
'driver_earnings_extra': message.data['driver_earnings_extra'],
'driver_earnings_currency': message.data['driver_earnings_currency'],
});
} else {
Log.print("⚠️ [FCM] User is already on OrderRequestPage. Skipping navigation.");
}
} }
break; break;
+12 -5
View File
@@ -232,13 +232,20 @@ Future<void> backgroundMessageHandler(RemoteMessage message) async {
); );
bool isAppInForeground = box.read(BoxName.isAppInForeground) ?? false; bool isAppInForeground = box.read(BoxName.isAppInForeground) ?? false;
String? currentRideStatus = box.read(BoxName.rideStatus);
bool hasActiveRide = (currentRideStatus == 'Begin' ||
currentRideStatus == 'Apply' ||
currentRideStatus == 'Arrived');
if (!isAppInForeground) { if (!hasActiveRide) {
await TripOverlayPlugin.showOverlay(tripData, autoCloseSeconds: 15); if (!isAppInForeground) {
await TripOverlayPlugin.showOverlay(tripData, autoCloseSeconds: 15);
}
// 🔴 الكتابة على القرص مباشرة بدلاً من الرام لضمان انتقالها للتطبيق 🔴
await storage.write(key: 'pending_driver_list', value: myListString);
} else {
print("⛔ [Background FCM] Ignoring new order overlay - driver is in active ride ($currentRideStatus)");
} }
// 🔴 الكتابة على القرص مباشرة بدلاً من الرام لضمان انتقالها للتطبيق 🔴
await storage.write(key: 'pending_driver_list', value: myListString);
} }
} }
} }
+1 -1
View File
@@ -31,7 +31,7 @@ class AppLink {
case 'Egypt': case 'Egypt':
return 'https://location-egypt.siromove.com/siro/ride/location'; return 'https://location-egypt.siromove.com/siro/ride/location';
case 'Jordan': case 'Jordan':
return 'https://location.intaleq.xyz/intaleq/ride/location'; return 'https://jordan-siro.intaleqapp.com/loction_server/siro/ride/location';
default: default:
return 'https://location.siromove.com/siro/ride/location'; return 'https://location.siromove.com/siro/ride/location';
} }