import React, { useState, useEffect } from "react"; import { View, Text, Image, ScrollView, TouchableOpacity } from "react-native"; import ScreenWrapper from "~/components/ui/ScreenWrapper"; import { Icons } from "~/assets/icons"; import TopBar from "~/components/ui/topBar"; import BottomSheet from "~/components/ui/bottomSheet"; import { Button } from "~/components/ui/button"; import Skeleton from "~/components/ui/skeleton"; import { router } from "expo-router"; import { ROUTES } from "~/lib/routes"; import { useAuthWithProfile } from "~/lib/hooks/useAuthWithProfile"; import { doc, FieldValue } from "~/lib/firebase"; type RequestStatus = "pending" | "accepted" | "completed" | "rejected"; type AgentRequest = { id: string; clientName: string; datetimeLabel: string; amount?: string; currency?: string; status: RequestStatus; acceptance: RequestStatus; rawDate: string; time: string; notes?: string; repeatLabel?: string; destinationAccount?: string; }; const MOCK_REQUESTS: AgentRequest[] = []; const getStatusPillClasses = (status: RequestStatus) => { switch (status) { case "pending": return "bg-yellow-100 text-yellow-700"; case "accepted": return "bg-blue-100 text-blue-700"; case "rejected": return "bg-red-100 text-red-700"; case "completed": default: return "bg-green-100 text-green-700"; } }; const isSameDay = (a: Date, b: Date) => { return ( a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate() ); }; const formatAppointmentDatetime = (item: any): string => { const today = new Date(); const tomorrow = new Date(); tomorrow.setDate(today.getDate() + 1); let dateObj: Date | null = null; if (item.nextRunDate) { const d = new Date(item.nextRunDate); if (!isNaN(d.getTime())) { dateObj = d; } } if (!dateObj && item.date) { const d = new Date(item.date); if (!isNaN(d.getTime())) { dateObj = d; } } const timeLabel = item.time || ""; let dayLabel = ""; if (dateObj) { if (isSameDay(dateObj, today)) { dayLabel = "Today"; } else if (isSameDay(dateObj, tomorrow)) { dayLabel = "Tomorrow"; } else { dayLabel = dateObj.toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric", }); } } else if (item.date) { dayLabel = item.date; } if (dayLabel && timeLabel) { return `${dayLabel} ยท ${timeLabel}`; } return dayLabel || timeLabel || ""; }; const buildRepeatLabel = ( repeatType?: string, interval?: number ): string | undefined => { if (!repeatType || repeatType === "none") { return "One-time"; } if (repeatType === "every_x_days" && interval) { return `Every ${interval} days`; } return repeatType; }; export default function EventsScreen() { const [requests, setRequests] = useState(MOCK_REQUESTS); const [selectedRequest, setSelectedRequest] = useState( null ); const [loading, setLoading] = useState(true); const { user } = useAuthWithProfile(); useEffect(() => { const fetchAgentAppointments = async () => { try { if (!user || typeof (user as any).getIdToken !== "function") { setLoading(false); console.log( "[Requests] /api/agents/my-appointments skipping fetch - no auth user or token method" ); return; } setLoading(true); const token = await (user as any).getIdToken(); const response = await fetch( "https://referralapi-fclnigvupq-uc.a.run.app/api/agents/my-appointments", { headers: { Authorization: `Bearer ${token}`, }, } ); console.log("[Requests] raw fetch Response", response); console.log( "[Requests] /api/agents/my-appointments status", response.status ); const text = await response.text(); try { const json = JSON.parse(text); console.log("[Requests] /api/agents/my-appointments json", json); console.log( "[Requests] /api/agents/my-appointments json data ", json?.data ); const payload = json?.data; const items = Array.isArray(payload?.data) ? payload.data : Array.isArray(json?.data) ? json.data : []; if (items.length > 0) { const mapped: AgentRequest[] = items.map((item: any) => { const acceptance: RequestStatus = item.acceptance === "accepted" || item.acceptance === "rejected" ? item.acceptance : "pending"; const status: RequestStatus = acceptance; const datetimeLabel = formatAppointmentDatetime(item); const repeatLabel = buildRepeatLabel( item.repeatType, item.interval ); return { id: String(item.id), clientName: item.fullName || item.email || item.phoneNumber || "Unknown client", datetimeLabel, rawDate: item.date || "", time: item.time || "", amount: typeof item.amount === "number" ? item.amount.toString() : undefined, currency: "ETB", status, acceptance, notes: item.notes, repeatLabel, }; }); setRequests(mapped); } } catch { console.log("[Requests] /api/agents/my-appointments raw", text); } } catch (error) { console.error("[Requests] /api/agents/my-appointments error", error); } finally { setLoading(false); } }; fetchAgentAppointments(); }, [user]); const handleUpdateStatus = async (id: string, next: RequestStatus) => { try { const ref = doc("appointments", id); await ref.update({ acceptance: next, updatedAt: FieldValue.serverTimestamp(), }); console.log( "[Requests] updated appointments acceptance in Firestore", id, next ); // Only update local UI once backend write succeeds setRequests((prev) => prev.map((req) => req.id === id ? { ...req, status: next, acceptance: next } : req ) ); setSelectedRequest((prev) => prev && prev.id === id ? { ...prev, status: next, acceptance: next } : prev ); } catch (error) { console.error( "[Requests] failed to update appointments acceptance", id, error ); } }; const handlePayNow = (req: AgentRequest) => { // UI-only: navigate to the main pay/send screen with no real prefill logic router.push(ROUTES.SEND_OR_REQUEST_MONEY); }; return ( Requests Every "Book Now" request for you appears here. {loading && ( {[1, 2, 3].map((i) => ( ))} )} {!loading && requests.length === 0 && ( No requests right now. )} {!loading && requests.length > 0 && ( {[...requests] // Hide accepted requests completely .filter((req) => req.status !== "accepted") // Keep rejected requests at the bottom .sort((a, b) => { if (a.status === "rejected" && b.status !== "rejected") return 1; if (a.status !== "rejected" && b.status === "rejected") return -1; return 0; }) .map((req) => { const pillClasses = getStatusPillClasses(req.status); return ( {req.clientName} {req.status === "pending" ? "Pending" : req.status === "accepted" ? "Accepted" : req.status === "rejected" ? "Rejected" : "Completed"} {req.datetimeLabel} {req.amount && req.currency && ( {req.currency} {req.amount} )} setSelectedRequest(req)} > View Details ); })} )} setSelectedRequest(null)} maxHeightRatio={0.5} > {selectedRequest && ( Request Details {selectedRequest.clientName} {selectedRequest.datetimeLabel} Date {selectedRequest.datetimeLabel} {selectedRequest.amount && selectedRequest.currency && ( Amount {selectedRequest.currency} {selectedRequest.amount} )} {selectedRequest.destinationAccount && ( Destination account {selectedRequest.destinationAccount} )} Status {selectedRequest.acceptance === "pending" ? "Pending" : selectedRequest.acceptance === "accepted" ? "Accepted" : selectedRequest.acceptance === "rejected" ? "Rejected" : "Completed"} {selectedRequest.notes && ( Notes {selectedRequest.notes} )} {selectedRequest.repeatLabel && ( Repeat {selectedRequest.repeatLabel} )} {selectedRequest.status === "pending" && ( <> handleUpdateStatus(selectedRequest.id, "accepted") } > Mark as Accepted handleUpdateStatus(selectedRequest.id, "rejected") } > Reject Request )} )} ); }