fix: resolve stale price display in driver ratings and remove misleading discount UI in rider ratings

This commit is contained in:
Hamza-Ayed
2026-07-09 04:48:19 +03:00
parent 03e9d648a1
commit 2152d34a8e
6 changed files with 76 additions and 62 deletions
@@ -1,6 +1,14 @@
<?php
require_once __DIR__ . '/../../connect.php';
// 🔥 [Fix Broken Access Control] كان يتحقق من صلاحية التوكن فقط — أي مستخدم
// مسجّل دخول كان يقدر يغيّر حالة أي سائق (تفعيل/رفض) أو رقم هاتفه.
if ($role !== 'admin' && $role !== 'super_admin') {
http_response_code(403);
echo json_encode(['error' => 'Unauthorized access. Admin role required.']);
exit;
}
$driver_id = filterRequest("id");
$phone = filterRequest("phone");
$status = filterRequest("status");
@@ -1,6 +1,15 @@
<?php
require_once __DIR__ . '/../../../connect.php';
// 🔥 [Fix Broken Access Control] كان يتحقق من صلاحية التوكن فقط — أي مستخدم
// مسجّل دخول (راكب/سائق آخر) كان يقدر يجلب بيانات أي سائق مفكوكة التشفير
// (هوية وطنية، هاتف، عنوان...) بالإضافة لروابط وثائقه الشخصية.
if ($role !== 'admin' && $role !== 'super_admin') {
http_response_code(403);
echo json_encode(['error' => 'Unauthorized access. Admin role required.']);
exit;
}
$driverId = filterRequest("id");
if (empty($driverId)) {
@@ -1,6 +1,15 @@
<?php
require_once __DIR__ . '/../../../connect.php';
// 🔥 [Fix Broken Access Control] كان يتحقق من صلاحية التوكن فقط بدون التحقق
// من الدور — أي توكن صالح (حتى راكب) كان يقدر يسحب قائمة السائقين المعلّقين
// وبياناتهم الشخصية المفكوكة التشفير.
if ($role !== 'admin' && $role !== 'super_admin') {
http_response_code(403);
echo json_encode(['error' => 'Unauthorized access. Admin role required.']);
exit;
}
$limit = isset($_POST['limit']) ? (int)$_POST['limit'] : (isset($_GET['limit']) ? (int)$_GET['limit'] : 10);
$offset = isset($_POST['offset']) ? (int)$_POST['offset'] : (isset($_GET['offset']) ? (int)$_GET['offset'] : 0);
+23 -1
View File
@@ -58,9 +58,31 @@ try {
$firstName_encrypted = $encryptionHelper->encryptData($firstName);
$lastName_encrypted = $encryptionHelper->encryptData($lastName);
$email_encrypted = $encryptionHelper->encryptData($email);
$password_hashed = password_hash($email, PASSWORD_DEFAULT);
$password_hashed = password_hash($email, PASSWORD_DEFAULT);
$unknown_encrypted = $encryptionHelper->encryptData("unknown yet");
// ======================================================
// Step 4.5: التحقق الفعلي من ملكية رقم الهاتف (🔥 Fix)
// ======================================================
// كانت هذه النقطة تسمح بإنشاء حساب راكب بأي رقم هاتف بدون إثبات
// ملكيته فعلياً — auth/otp/verify.php يُعلّم الصف verified=1 لكن
// register_passenger.php لم يكن يتحقق من ذلك إطلاقاً. الآن نشترط
// وجود صف تحقق ناجح (verified=1) لنفس رقم الهاتف خلال آخر 30 دقيقة
// (مهلة أوسع من صلاحية الرمز نفسه [5 دقائق] لإعطاء وقت كافٍ لإكمال
// نموذج التسجيل بعد التحقق مباشرة).
$step = 4.5;
$verifyCheckStmt = $con->prepare(
"SELECT id FROM phone_verification_passenger
WHERE phone_number = ? AND verified = 1 AND created_at > DATE_SUB(NOW(), INTERVAL 30 MINUTE)
LIMIT 1"
);
$verifyCheckStmt->execute([$phoneNumber_encrypted]);
if ($verifyCheckStmt->rowCount() === 0) {
error_log("$logTag Step 4.5 Error: Phone number not verified via OTP.");
jsonError("Phone number must be verified before registration.");
exit();
}
// ======================================================
// Step 5: إنشاء ID فريد
// ======================================================
@@ -76,9 +76,14 @@ class RatePassenger extends StatelessWidget {
Widget _buildHeroPriceDisplay(BuildContext context) {
final MapDriverController mapController = Get.find<MapDriverController>();
// Parse the string to double to format it correctly
double amount =
double.tryParse(mapController.paymentAmount.toString()) ?? 0.0;
// 🔥 [Fix Stale Price] كان يُعرض mapController.paymentAmount — وهو السعر
// المُقتبَس وقت عرض الرحلة على السائق، ولا يتحدث أبداً بعد ذلك. السعر
// النهائي الصحيح (بعد كل التعديلات من finish_ride_updates.php) موجود
// فعلاً في controller.price لكنه لم يكن يُستخدم هنا. الآن نعتمده أولاً.
final String? finalPriceStr = controller.price;
double amount = (finalPriceStr != null && finalPriceStr.isNotEmpty)
? (double.tryParse(finalPriceStr) ?? 0.0)
: (double.tryParse(mapController.paymentAmount.toString()) ?? 0.0);
String formattedAmount = currencyFormatter.format(amount);
return Container(
+19 -58
View File
@@ -4,6 +4,7 @@ import 'package:flutter_rating_bar/flutter_rating_bar.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
import '../../constant/currency.dart';
import '../../constant/style.dart';
import '../../controller/firebase/firbase_messge.dart';
import '../../controller/payment/payment_controller.dart';
@@ -43,69 +44,29 @@ class RateDriverFromPassenger extends StatelessWidget {
'${'Total price to '.tr}${Get.find<RideLifecycleController>().driverName}',
style: AppStyle.title,
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(
width: 2,
color: AppColor.redColor,
)),
child: Padding(
padding: const EdgeInsets.all(4),
child: Text(
(double.parse(controller.price
.toString()) *
.12 +
double.parse(controller.price
.toString()))
.toStringAsFixed(2),
style: AppStyle.number.copyWith(
color: AppColor.redColor,
textBaseline:
TextBaseline.ideographic,
decoration:
TextDecoration.lineThrough,
decorationColor:
AppColor.redColor),
),
),
// 🔥 [Fix Fake Discount] كان هنا سعر "خصم" مُصطنَع
// بالكامل (السعر الحقيقي × 1.12 + السعر الحقيقي)
// يُعرض بخط مشطوب وكأنه سعر سابق حقيقي — رقم
// مضلِّل تماماً، لا يعكس أي سعر منافس أو عرض
// حقيقي. الآن نعرض السعر الفعلي فقط مع رمز
// العملة الصحيح حسب دولة الرحلة.
Container(
decoration: BoxDecoration(
border: Border.all(
width: 2,
color: AppColor.greenColor,
)),
child: Padding(
padding: const EdgeInsets.all(4),
child: Text(
'${controller.price ?? '0'} ${CurrencyHelper.currency}',
style: AppStyle.number,
),
const SizedBox(
height: 10,
),
Container(
decoration: BoxDecoration(
border: Border.all(
width: 2,
color: AppColor.greenColor,
)),
child: Padding(
padding: const EdgeInsets.all(4),
child: Text(
controller.price.toString(),
style: AppStyle.number,
),
),
),
],
),
),
const SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
'Exclusive offers and discounts always with the Siro app'
.tr,
style: AppStyle.title.copyWith(
color: AppColor.redColor,
),
textAlign: TextAlign.center,
),
),
(Get.find<PaymentController>()
.isWalletChecked ==
true)