import { MaterialCommunityIcons } from "@expo/vector-icons"; import { router } from "expo-router"; import { useCallback, useEffect, useState } from "react"; import { Text, TouchableOpacity, View } from "react-native"; import { RatingSheet } from "@/components/rating-sheet"; import { fetchAPI } from "@/lib/fetch"; import { useT } from "@/lib/i18n"; // Home-screen banner for unfinished business. Two things can be unfinished // after the rider leaves the tracking screen: // // * a ride still in flight — before this, killing the app mid-ride stranded // the rider with no route back to their driver, since home only lists // completed history; // * a finished ride they never rated — the prompt is easy to miss when the // app is backgrounded the moment the door closes. // // Both are recoverable from one poll, so they share one banner. const POLL_MS = 15000; type ActiveRide = { ride_id: number; status: string; service: string; destination_address: string; driver_name: string | null; }; type PendingRating = { ride_id: number; destination_address: string; driver_name: string | null; driver_avatar: string | null; }; const STATUS_KEY: Record = { requested: "bookRide.status.requested", accepted: "bookRide.status.accepted", arrived: "bookRide.status.arrived", en_route: "bookRide.status.enRoute", }; export const ActiveRideBanner = () => { const t = useT(); const [active, setActive] = useState(null); const [pending, setPending] = useState(null); const [ratingOpen, setRatingOpen] = useState(false); const [dismissed, setDismissed] = useState([]); const load = useCallback(async () => { try { const res = await fetchAPI("/(api)/ride/active"); setActive(res.data?.active ?? null); setPending(res.data?.pending_rating ?? null); } catch (err) { // A signed-out or offline home screen simply shows no banner. console.log("[ACTIVE_RIDE_BANNER]: ", err); } }, []); useEffect(() => { void load(); const timer = setInterval(() => void load(), POLL_MS); return () => clearInterval(timer); }, [load]); if (active) { return ( router.push({ pathname: "/(root)/book-ride", params: { id: String(active.ride_id) }, }) } className="bg-primary-500 rounded-2xl p-4 mb-4 flex-row items-center" > {STATUS_KEY[active.status] ? t(STATUS_KEY[active.status]) : active.status} {active.driver_name ? t("home.activeRideWithDriver", { name: active.driver_name }) : active.destination_address} ); } if (pending && !dismissed.includes(pending.ride_id)) { return ( <> {t("home.rateLastRide")} {pending.destination_address} setRatingOpen(true)} className="bg-primary-500 rounded-full px-4 py-2 ml-3" > {t("home.rate")} { setRatingOpen(false); setDismissed((prev) => [...prev, pending.ride_id]); void load(); }} onSkip={() => { setRatingOpen(false); setDismissed((prev) => [...prev, pending.ride_id]); }} /> ); } return null; };