/** * UserPortal.tsx * * Part of the AMAN User module. */ import { useState, useEffect, useMemo, useRef } from "react"; import { useTranslation } from "react-i18next"; import { ChevronRight } from "lucide-react"; import { useAuth } from "../../context/AuthContext"; import { useToast } from "../../context/ToastContext"; import { useNavigate, useLocation } from "react-router-dom"; import { getUserReports, getGlobalStats, getAllReports, type LeakReport, } from "../../services/reports"; import LoadingSpinner from "../../components/shared/LoadingSpinner"; import { logError } from "../../utils/logger"; import ReportList from "../../components/shared/ReportList"; import RoyalCitation from "./components/RoyalCitation/RoyalCitation"; import UserHero from "./components/UserHero/UserHero"; import ReportWizard from "./components/ReportWizard/ReportWizard"; import { Button } from "../../components/ui/Button"; import "./UserPortal.css"; /** * UserPortal Component * * Main entry point for users to report water leaks and track community reports. */ export default function UserPortal() { const { t } = useTranslation(["user", "common"]); const { user } = useAuth(); const { showToast } = useToast(); const navigate = useNavigate(); const locationState = useLocation(); // --- Data & Statistics State --- const [reports, setReports] = useState([]); // Global public reports const [userReports, setUserReports] = useState([]); // Current user's reports const [stats, setStats] = useState({ total: 0, pendingAudit: 0, inProgress: 0, resolved: 0, }); const [statsLoading, setStatsLoading] = useState(true); const [reportsLoading, setReportsLoading] = useState(true); const mountedRef = useRef(true); useEffect(() => { mountedRef.current = true; // Non-blocking parallel data fetches fetchStats(); fetchReports(); // Handle location passed from manager map const state = locationState.state as { lat?: number; lng?: number; fromManager?: boolean; }; if (state?.lat && state?.lng) { requestAnimationFrame(() => { const element = document.getElementById("report-form"); if (element) { element.scrollIntoView({ behavior: "smooth" }); } }); navigate(locationState.pathname, { replace: true, state: {} }); } return () => { mountedRef.current = false; }; }, [user, locationState.key]); async function fetchStats() { setStatsLoading(true); try { const data = await getGlobalStats(); setStats(data); } catch (error) { logError("UserPortal:fetchStats", error); showToast( t("error_fetching_stats", "Failed to load statistics."), "error", ); } finally { if (mountedRef.current) setStatsLoading(false); } } async function fetchReports() { setReportsLoading(true); try { const globalData = await getAllReports(6); setReports(globalData); if (user && !user.isAnonymous) { const userData = await getUserReports(user.uid); setUserReports(userData); } else { setUserReports([]); } } catch (error) { logError("UserPortal:fetchReports", error); showToast( t("error_fetching_reports", "Failed to load reports."), "error", ); } finally { if (mountedRef.current) setReportsLoading(false); } } // Memoize slices to prevent unnecessary re-renders of ReportList const topGlobalReports = useMemo(() => reports.slice(0, 5), [reports]); return (
{ const element = document.getElementById("report-form"); if (element) { element.scrollIntoView({ behavior: "smooth" }); } }} /> { fetchReports(); fetchStats(); }} /> {/* ── Recent Reports ────────────────────────────── */}
navigate("/reports")} >

{t("public_reports")}

{reportsLoading && reports.length === 0 ? (
) : ( navigate(`/report/${report.id}`)} viewMode="list" footerMode="social" emptyMessage={t("common:no_data")} /> )} {reports.length > 5 && (
)}
); }