fix: resolve stale price display in driver ratings and remove misleading discount UI in rider ratings
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user