128 lines
5.7 KiB
PHP
128 lines
5.7 KiB
PHP
<?php
|
||
// ============================================================
|
||
// pending_rating.php — آخر رحلة منتهية لم تُقيَّم بعد
|
||
//
|
||
// لماذا نقطة مستقلة:
|
||
// شاشة التقييم لا تُفتح اليوم إلا عبر needsReview في
|
||
// getRideStatusFromStartApp.php، وذاك محصور بنافذة ساعة واحدة — وهي
|
||
// نافذة مقصودة لاستئناف رحلة **قائمة** لا للتقييم. النتيجة أن من يغلق
|
||
// التطبيق فور نزوله (وهو السلوك الغالب) لا يُطلب منه تقييم أبداً.
|
||
//
|
||
// توسيع تلك النافذة كان سيجعل التطبيق يفتح شاشة رحلة على رحلة انتهت.
|
||
// لذلك: نقطة منفصلة تسأل سؤالاً واحداً — «هل عليّ تقييم متأخر؟» — بلا
|
||
// أي علاقة بحالة الرحلة الجارية.
|
||
//
|
||
// ── قاعدتان لا واحدة ──
|
||
// الرحلات في قاعدة ride والتقييمات في primary، وهما منفصلتان فيزيائياً
|
||
// فلا انضمام ممكن. استعلامان: آخر الرحلات المنتهية من ride، ثم أيّها
|
||
// مقيَّم في primary. الحد الصغير يبقي التكلفة ضئيلة.
|
||
// ============================================================
|
||
|
||
require_once __DIR__ . '/../../connect.php';
|
||
|
||
try {
|
||
$con_ride = Database::get('ride');
|
||
} catch (Exception $e) {
|
||
error_log("[pending_rating] Ride DB unavailable: " . $e->getMessage());
|
||
jsonError("Service unavailable", 503);
|
||
}
|
||
|
||
// من يسأل: راكب يقيّم سائقه، أو سائق يقيّم راكبه.
|
||
$role_ = filterRequest("role") === 'driver' ? 'driver' : 'passenger';
|
||
|
||
// الهوية من الـJWT لا من الطلب — وإلا قرأ أي أحد رحلات غيره.
|
||
$userId = $user_id ?? '';
|
||
if (empty($userId)) {
|
||
jsonError("Unauthorized", 401);
|
||
}
|
||
|
||
// نافذة معقولة: تقييم رحلة نسيها صاحبها بلا قيمة، ويزعجه.
|
||
const PENDING_RATING_WINDOW_DAYS = 7;
|
||
|
||
// عدد الرحلات التي نفحصها. آخر رحلة غير مقيّمة عملياً ضمن آخر قليل،
|
||
// فلا داعي لمسح تاريخ المستخدم كله.
|
||
const PENDING_RATING_SCAN_LIMIT = 10;
|
||
|
||
try {
|
||
// ── ١) آخر الرحلات المنتهية من قاعدة الرحلات ──────────────
|
||
$col = $role_ === 'driver' ? 'driver_id' : 'passenger_id';
|
||
|
||
$stmt = $con_ride->prepare("
|
||
SELECT id, driver_id, passenger_id, price, carType,
|
||
start_location, end_location, rideTimeFinish
|
||
FROM ride
|
||
WHERE `$col` = ?
|
||
AND status = 'Finished'
|
||
AND rideTimeFinish >= NOW() - INTERVAL " . PENDING_RATING_WINDOW_DAYS . " DAY
|
||
ORDER BY rideTimeFinish DESC
|
||
LIMIT " . PENDING_RATING_SCAN_LIMIT
|
||
);
|
||
$stmt->execute([$userId]);
|
||
$rides = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||
|
||
if (empty($rides)) {
|
||
jsonSuccess(['pending' => false], "No pending rating");
|
||
}
|
||
|
||
// ── ٢) أيّها مقيَّم؟ استعلام واحد لكلها ───────────────────
|
||
$ids = array_column($rides, 'id');
|
||
$ph = implode(',', array_fill(0, count($ids), '?'));
|
||
|
||
// الراكب يقيّم السائق في ratingDriver (العمود ride_id)،
|
||
// والسائق يقيّم الراكب في ratingPassenger (العمود rideId).
|
||
$ratedSql = $role_ === 'driver'
|
||
? "SELECT rideId AS rid FROM ratingPassenger WHERE rideId IN ($ph)"
|
||
: "SELECT ride_id AS rid FROM ratingDriver WHERE ride_id IN ($ph)";
|
||
|
||
$stmtRated = $con->prepare($ratedSql);
|
||
$stmtRated->execute($ids);
|
||
$rated = array_flip($stmtRated->fetchAll(PDO::FETCH_COLUMN));
|
||
|
||
// ── ٣) أول رحلة غير مقيّمة (الأحدث أولاً) ─────────────────
|
||
$target = null;
|
||
foreach ($rides as $r) {
|
||
if (!isset($rated[$r['id']]) && !isset($rated[(string) $r['id']])) {
|
||
$target = $r;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (!$target) {
|
||
jsonSuccess(['pending' => false], "No pending rating");
|
||
}
|
||
|
||
// ── ٤) اسم الطرف الآخر ────────────────────────────────────
|
||
// من primary: جداول driver/passengers تعيش هناك، والاسم مشفَّر.
|
||
$otherId = $role_ === 'driver' ? $target['passenger_id'] : $target['driver_id'];
|
||
$otherName = '';
|
||
|
||
try {
|
||
$table = $role_ === 'driver' ? 'passengers' : 'driver';
|
||
$stmtName = $con->prepare("SELECT first_name FROM `$table` WHERE id = ? LIMIT 1");
|
||
$stmtName->execute([$otherId]);
|
||
$raw = $stmtName->fetchColumn();
|
||
|
||
if ($raw && !empty($encryptionHelper)) {
|
||
$dec = $encryptionHelper->decryptData($raw);
|
||
$otherName = ($dec !== false && $dec !== '') ? $dec : '';
|
||
}
|
||
} catch (Throwable $e) {
|
||
// الاسم تحسين لا شرط — الشاشة تعمل بدونه.
|
||
error_log("[pending_rating] تعذّر جلب اسم الطرف الآخر: " . $e->getMessage());
|
||
}
|
||
|
||
jsonSuccess([
|
||
'pending' => true,
|
||
'rideId' => (string) $target['id'],
|
||
'targetId' => (string) $otherId,
|
||
'targetName' => $otherName,
|
||
'price' => $target['price'],
|
||
'carType' => $target['carType'],
|
||
'finishedAt' => $target['rideTimeFinish'],
|
||
], "Pending rating found");
|
||
|
||
} catch (PDOException $e) {
|
||
error_log("[pending_rating] " . $e->getMessage());
|
||
jsonError("DB Error", 500);
|
||
}
|