table('ride') ->where('id', $rideId) ->whereIn('status', ['Applied', 'Arrived', 'Begin']) ->first(); if (!$ride) { return response()->json(['status' => 'failure', 'message' => 'Ride not active'], 404); } $location = DB::connection('tracking')->table('car_locations') ->where('driver_id', $ride->driver_id) ->first(); if (!$location) { return response()->json(['status' => 'failure', 'message' => 'Driver location not available'], 404); } return response()->json([ 'status' => 'success', 'data' => [ 'latitude' => $location->latitude, 'longitude' => $location->longitude, 'heading' => $location->heading, 'speed' => $location->speed, 'updated_at' => $location->updated_at, ], ]); } /** * GET /v2/tracking/public/{rideId}?hash=XXX * Public tracking link for parents/friends — uses HMAC hash instead of auth */ public function publicTrack(Request $request, int $rideId): JsonResponse { $hash = $request->input('hash'); if (!$hash) { return response()->json(['status' => 'failure', 'message' => 'Missing hash'], 400); } // Verify hash: HMAC-SHA256(ride_id, secret_salt) $expectedHash = hash_hmac('sha256', (string) $rideId, config('intaleq.secret_salt_parent')); if (!hash_equals($expectedHash, $hash)) { return response()->json(['status' => 'failure', 'message' => 'Invalid hash'], 403); } $ride = DB::connection('ride')->table('ride') ->where('id', $rideId) ->whereIn('status', ['Applied', 'Arrived', 'Begin']) ->first(); if (!$ride) { return response()->json(['status' => 'failure', 'message' => 'Ride not active'], 404); } $location = DB::connection('tracking')->table('car_locations') ->where('driver_id', $ride->driver_id) ->first(); return response()->json([ 'status' => 'success', 'data' => [ 'latitude' => $location->latitude ?? null, 'longitude' => $location->longitude ?? null, 'heading' => $location->heading ?? null, 'ride_status' => $ride->status, ], ]); } /** GET /v2/tracking/heatmap */ public function heatmap(Request $request): JsonResponse { // Use spatial query for active drivers $drivers = DB::connection('tracking')->table('car_locations') ->select('latitude', 'longitude', 'carType') ->where('status', 'on') ->where('updated_at', '>', now()->subMinutes(10)) ->get(); return response()->json([ 'status' => 'success', 'data' => $drivers, ]); } /** GET /v2/tracking/captain-stats */ public function captainStats(Request $request): JsonResponse { $driverId = $request->input('_jwt_user_id'); $totalRides = DB::connection('ride')->table('ride') ->where('driver_id', $driverId) ->where('status', 'finish') ->count(); $todayRides = DB::connection('ride')->table('ride') ->where('driver_id', $driverId) ->where('status', 'finish') ->whereDate('rideTimeFinish', today()) ->count(); $todayEarnings = DB::connection('ride')->table('ride') ->where('driver_id', $driverId) ->where('status', 'finish') ->whereDate('rideTimeFinish', today()) ->sum('price_for_driver'); $workHours = DB::connection('tracking')->table('driver_daily_summary') ->where('driver_id', $driverId) ->where('date', today()->toDateString()) ->value('total_seconds') ?? 0; return response()->json([ 'status' => 'success', 'data' => [ 'total_rides' => $totalRides, 'today_rides' => $todayRides, 'today_earnings' => round($todayEarnings, 2), 'today_work_seconds' => $workHours, ], ]); } }