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, ShieldCheck
} from 'lucide-react';
import { SpotlightCard } from '../components/SpotlightCard';
import { config } from '../config/env';
// New Widget Imports
import { RoofConditionChart } from '../components/dashboard/RoofConditionChart';
import { TopSalesLeaderboard } from '../components/dashboard/TopSalesLeaderboard';
import { RevenueByNeighborhood } from '../components/dashboard/RevenueByNeighborhood';
import { GoldenLeadsScatter } from '../components/dashboard/GoldenLeadsScatter';
import { ActionCenterWidget } from '../components/dashboard/ActionCenterWidget';
import { WeatherRiskGauge } from '../components/dashboard/WeatherRiskGauge';
import AnimatedNumber from '../components/AnimatedNumber';
import Loader from '../components/Loader';
const Dashboard = () => {
const { properties, meetings } = useMockStore();
const { user } = useAuth();
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
// Simulate initial data fetch
const timer = setTimeout(() => setIsLoading(false), 800);
return () => clearTimeout(timer);
}, []);
// --- Weather State (Lifted) ---
const [weather, setWeather] = useState(null);
const [forecast, setForecast] = useState([]);
const [weatherLoading, setWeatherLoading] = useState(true);
const [weatherError, setWeatherError] = useState(null);
const [lastUpdated, setLastUpdated] = useState(null);
const fetchWeather = async () => {
const API_KEY = config.weatherApiKey;
const CITY = "Plano,US";
try {
setWeatherLoading(true);
if (config.isDemoMode(API_KEY)) {
await new Promise(resolve => setTimeout(resolve, 800));
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 }
};
const mockForecast = Array.from({ length: 5 }).map((_, i) => ({
dt: Math.floor(Date.now() / 1000) + (i * 10800),
main: { temp: 75 + (i % 2 === 0 ? 2 : -2) },
weather: [{ id: 800 + (i * 10) }]
}));
setWeather(mockCurrent);
setForecast(mockForecast);
setLastUpdated(new Date());
setWeatherLoading(false);
setWeatherError(null);
return;
}
const currentRes = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${CITY}&units=imperial&appid=${API_KEY}`);
if (!currentRes.ok) throw new Error(currentRes.statusText);
const currentData = await currentRes.json();
const forecastRes = await fetch(`https://api.openweathermap.org/data/2.5/forecast?q=${CITY}&units=imperial&appid=${API_KEY}`);
if (!forecastRes.ok) throw new Error(forecastRes.statusText);
const forecastData = await forecastRes.json();
setWeather(currentData);
setForecast(forecastData.list?.slice(0, 5) || []);
setLastUpdated(new Date());
setWeatherLoading(false);
setWeatherError(null);
} catch (err) {
console.error("Weather fetch failed", err);
setWeatherError(err.message);
setWeatherLoading(false);
}
};
useEffect(() => {
fetchWeather();
const interval = setInterval(fetchWeather, 600000);
return () => clearInterval(interval);
}, []);
// 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');
const allMyMeetings = meetings.filter(m => m.agentId === user?.id || m.agentId === 'e1');
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
if (isLoading) return
Welcome back, here's what's happening with your territory. {'Ѕ'}{'а'}{'t'}{'у'}{'а'}{'m'} {'R'}{'а'}{'ѕ'}{'t'}{'о'}{'g'}{'і'}
{lead.propertyData.propertyType} • ${lead.propertyData.currentEstimatedMarketValue.toLocaleString()}
No upcoming meetings.
) : ( upcomingMeetings.map(meeting => (No past meetings.
) : ( pastMeetings.slice(0, 5).map(meeting => ({meeting.customerName}
{title}
{error}
{(error.includes('401') || error.includes('Invalid API key')) && (
Please configure your VITE_OPENWEATHER_API_KEY in the .env file.
Updated: {lastUpdated?.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}