import React, { useEffect, useState } from 'react'; import { useMockStore } from '../data/mockStore'; import { useAuth } from '../context/AuthContext'; import { Link } from 'react-router-dom'; import { DollarSign, Flame, Calendar, CloudRain, Wind, Droplets, Thermometer, MapPin, Clock, ArrowUpRight, Sun, Cloud, AlertTriangle, Loader2 } from 'lucide-react'; import { SpotlightCard } from '../components/SpotlightCard'; import { config } from '../config/env'; const Dashboard = () => { const { properties, meetings } = useMockStore(); const { user } = useAuth(); // Clock for Plano, TX const [currentTime, setCurrentTime] = useState(new Date()); useEffect(() => { const timer = setInterval(() => setCurrentTime(new Date()), 60000); // Every minute return () => clearInterval(timer); }, []); // Derived Metrics & Split Schedule const hotLeads = properties.filter(p => p.canvassingStatus === 'Hot Lead'); // Filter meetings for current user (or fallback to e1 for dev) const allMyMeetings = meetings.filter(m => m.agentId === user?.id || m.agentId === 'e1'); // Split into Upcoming vs Past const today = new Date(); today.setHours(0, 0, 0, 0); const upcomingMeetings = allMyMeetings .filter(m => new Date(m.date) >= today) .sort((a, b) => new Date(a.date) - new Date(b.date)); const pastMeetings = allMyMeetings .filter(m => new Date(m.date) < today) .sort((a, b) => new Date(b.date) - new Date(a.date)); // Most recent first return (
{/* Ambient Background Glows */}

Dashboard Overview

Welcome back, here's what's happening with your territory.

{/* Real-time Clock Widget */}
{currentTime.toLocaleTimeString('en-US', { timeZone: 'America/Chicago', hour: 'numeric', minute: '2-digit', hour12: false })}
{currentTime.toLocaleDateString('en-US', { timeZone: 'America/Chicago', weekday: 'long', month: 'long', day: 'numeric' })} • Plano, TX
{/* Top Metrics Grid */}
{/* Main Content Grid */}
{/* Left Col: Hot Leads and Schedule */}
{/* Hot Leads Panel */}

Hot Leads

View Map
{hotLeads.length === 0 ? (
No hot leads active. Time to canvas!
) : ( hotLeads.slice(0, 5).map(lead => (
{lead.id}

{lead.propertyData.propertyAddress.split(',')[0]}

{lead.propertyData.propertyType} • ${lead.propertyData.currentEstimatedMarketValue.toLocaleString()}

Hot Lead
)) )}
{/* Split Schedule System */}
{/* Upcoming Meetings */}

Upcoming

{upcomingMeetings.length === 0 ? (

No upcoming meetings.

) : ( upcomingMeetings.map(meeting => ( )) )}
{/* Past / Completed Meetings */}

History

{pastMeetings.length === 0 ? (

No past meetings.

) : ( pastMeetings.slice(0, 5).map(meeting => ( )) )}
{/* Right Col: Weather Widget */}
); }; // --- Sub Components --- const MeetingRow = ({ meeting, type }) => (
{new Date(meeting.date).toLocaleDateString('en-US', { month: 'short' })} {new Date(meeting.date).getDate()}

{meeting.customerName}

{meeting.time}
{meeting.status}
); const MetricCard = ({ title, value, trend, icon: Icon, trendColor, bgGlow }) => (
{trend}

{value}

{title}

{/* Decorative Neomorphic Inner Shadow */}
); const RealWeatherWidget = () => { const [weather, setWeather] = useState(null); const [forecast, setForecast] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [lastUpdated, setLastUpdated] = useState(null); const API_KEY = config.weatherApiKey; const CITY = "Plano,US"; const fetchWeather = async () => { try { setLoading(true); // --- DEMO MODE CHECK --- if (config.isDemoMode(API_KEY)) { // Simulate network delay await new Promise(resolve => setTimeout(resolve, 800)); // MOCK DATA const mockCurrent = { name: "Plano", sys: { country: "US" }, main: { temp: 75, temp_max: 82, temp_min: 68, feels_like: 77, humidity: 45 }, weather: [{ id: 800, description: "Clear Sky (Demo)" }], wind: { speed: 8 } }; // Mock Forecast (Next 15 hours) const mockForecast = Array.from({ length: 5 }).map((_, i) => ({ dt: Math.floor(Date.now() / 1000) + (i * 10800), // +3 hours each main: { temp: 75 + (i % 2 === 0 ? 2 : -2) }, weather: [{ id: 800 + (i * 10) }] // Varying sunny/cloudy codes })); setWeather(mockCurrent); setForecast(mockForecast); setLastUpdated(new Date()); setLoading(false); setError(null); return; // Exit early } // --- REAL API FETCH --- // Fetch Current Weather const currentRes = await fetch( `https://api.openweathermap.org/data/2.5/weather?q=${CITY}&units=imperial&appid=${API_KEY}` ); if (!currentRes.ok) { const errData = await currentRes.json().catch(() => ({ message: currentRes.statusText })); throw new Error(errData.message || `API Error: ${currentRes.status}`); } const currentData = await currentRes.json(); // Fetch 5 Day / 3 Hour Forecast const forecastRes = await fetch( `https://api.openweathermap.org/data/2.5/forecast?q=${CITY}&units=imperial&appid=${API_KEY}` ); if (!forecastRes.ok) { const errData = await forecastRes.json().catch(() => ({ message: forecastRes.statusText })); throw new Error(errData.message || `Forecast Error: ${forecastRes.status}`); } const forecastData = await forecastRes.json(); setWeather(currentData); setForecast(forecastData.list?.slice(0, 5) || []); setLastUpdated(new Date()); setLoading(false); setError(null); } catch (err) { console.error("Weather fetch failed", err); setError(err.message); setLoading(false); } }; useEffect(() => { fetchWeather(); // Refresh every 10 minutes const interval = setInterval(fetchWeather, 600000); return () => clearInterval(interval); }, []); const getWeatherIcon = (code) => { // OWM codes: https://openweathermap.org/weather-conditions if (code === 800) return ; if (code > 800) return ; if (code >= 500 && code < 600) return ; if (code >= 200 && code < 300) return ; return ; }; const getMiniIcon = (code) => { if (code === 800) return ; if (code > 800) return ; if (code >= 500) return ; return ; }; if (loading && !weather) return
Syncing OWM...
; if (error) return (

Weather Unavailable

{error}

{(error.includes('401') || error.includes('Invalid API key')) && (

Please configure your VITE_OPENWEATHER_API_KEY in the .env file.

)}
); if (!weather || !weather.main) return
Weather Unavailable
; return ( // Added text-zinc-900 to ensure text is visible in light mode {/* Dynamic Weather Background Gradient - subtle */}
{weather.name || "Plano"}, {weather.sys?.country}

{Math.round(weather.main.temp)} °F

Updated: {lastUpdated?.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}

{getWeatherIcon(weather.weather[0].id)}

{weather.weather[0].description}

H: {Math.round(weather.main.temp_max)}°F L: {Math.round(weather.main.temp_min)}°F Feels: {Math.round(weather.main.feels_like)}°F
Wind
{Math.round(weather.wind.speed)} mph
Humidity
{weather.main.humidity}%

Forecast (3-Hour Steps)

{forecast.map((item, index) => { const date = new Date(item.dt * 1000); const displayTime = date.toLocaleTimeString('en-US', { hour: 'numeric', hour12: true }); return (
{displayTime}
{getMiniIcon(item.weather[0].id)}
{Math.round(item.main.temp)}°
) })}
); }; export default Dashboard;