/**
* @license
* SPDX-License-Identifier: Apache-2.0
*/
import { useState, useEffect, lazy, Suspense } from 'react';
import { BrowserRouter as Router, Routes, Route, Link, useLocation } from 'react-router-dom';
import { motion } from 'framer-motion';
import LeafletMapView from './components/LeafletMapView';
import Sidebar from './components/Sidebar';
import { ThinSidebar } from './components/ThinSidebar';
import { Map, Settings, Info, User, ChevronDown, ChevronUp } from 'lucide-react';
const AIAssistant = lazy(() => import('./components/AIAssistant'));
import { OnboardingModal } from './components/OnboardingModal';
import { TripHistory } from './components/TripHistory';
import { IncidentReportModal } from './components/IncidentReportModal';
import { RouteLoadingSkeleton } from './components/SkeletonLoader';
import { requestNotificationPermission, showRouteAlert } from './lib/notifications';
import { useKeyboardShortcuts } from './hooks';
import { getCached, setCache, generateRouteCacheKey } from './lib/routeCache';
import { geocode, getRoute } from './lib/api';
function MapTab({
isSidebarOpen,
routeData, setRouteData,
alternativeRoutes, setAlternativeRoutes,
riskData, setRiskData,
previousRouteData, setPreviousRouteData,
previousRiskData, setPreviousRiskData,
incidentsData, setIncidentsData,
weather, setWeather,
startLoc, setStartLoc,
endLoc, setEndLoc,
startQuery, setStartQuery,
endQuery, setEndQuery,
theme, setTheme,
vehicleType, setVehicleType,
showIncidents, setShowIncidents,
showRoutePlayback, setShowRoutePlayback,
playbackSpeed, setPlaybackSpeed,
mapStyleType, setMapStyleType,
activeLayers, setActiveLayers,
waypoints,
voiceNavEnabled,
onOpenIncidentReport,
onOpenTripHistory,
onToggleVoiceNav
}: any) {
return (
);
}
function SettingsTab({ theme, setTheme, vehicleType, setVehicleType, mapStyleType, setMapStyleType, userProfile, onLogout, onUpdateProfile, highContrast, setHighContrast }: any) {
const [isEditingProfile, setIsEditingProfile] = useState(false);
const [profileName, setProfileName] = useState(userProfile?.name || '');
const [profileEmail, setProfileEmail] = useState(userProfile?.email || '');
const [selectedAvatar, setSelectedAvatar] = useState(userProfile?.photo || '');
const avatarOptions = [
{ id: 'avataaars', label: 'Avatar', url: (name: string) => `https://api.dicebear.com/7.x/avataaars/svg?seed=${encodeURIComponent(name)}` },
{ id: 'male', label: 'Male', url: (name: string) => `https://api.dicebear.com/7.x/personas/svg?seed=${encodeURIComponent(name)}&backgroundColor=b6e3f4` },
{ id: 'female', label: 'Female', url: (name: string) => `https://api.dicebear.com/7.x/personas/svg?seed=${encodeURIComponent(name)}&backgroundColor=ffd5dc` },
{ id: 'children', label: 'Children', url: (name: string) => `https://api.dicebear.com/7.x/croodles/svg?seed=${encodeURIComponent(name)}` },
{ id: 'identicon', label: 'Abstract', url: (name: string) => `https://api.dicebear.com/7.x/identicon/svg?seed=${encodeURIComponent(name)}` },
{ id: 'micah', label: 'Micah', url: (name: string) => `https://api.dicebear.com/7.x/micah/svg?seed=${encodeURIComponent(name)}` },
{ id: 'miniavs', label: 'Mini', url: (name: string) => `https://api.dicebear.com/7.x/miniavs/svg?seed=${encodeURIComponent(name)}` },
{ id: 'pixel-art', label: 'Pixel', url: (name: string) => `https://api.dicebear.com/7.x/pixel-art/svg?seed=${encodeURIComponent(name)}` }
];
useEffect(() => {
setProfileName(userProfile?.name || '');
setProfileEmail(userProfile?.email || '');
setSelectedAvatar(userProfile?.photo || '');
}, [userProfile]);
const handleSaveProfile = () => {
if (profileName.trim()) {
const photo = selectedAvatar || avatarOptions[0].url(profileName);
onUpdateProfile(profileName, profileEmail, photo);
setIsEditingProfile(false);
}
};
const handleDeleteProfile = () => {
if (confirm('Are you sure you want to delete your profile?')) {
onLogout();
}
};
const handleClearAllData = () => {
if (confirm('This will clear all saved locations, recent searches, and your profile. Continue?')) {
localStorage.removeItem('savedLocations');
localStorage.removeItem('recentSearches');
localStorage.removeItem('userProfile');
onLogout();
}
};
const getAvatarUrl = (avatarId: string) => {
const avatar = avatarOptions.find(a => a.id === avatarId);
return avatar ? avatar.url(profileName || 'user') : avatarOptions[0].url(profileName || 'user');
};
return (
{/* Header */}
Settings
Manage your profile and preferences
{/* User Profile Section */}
Manage your personal information
{userProfile ? (
<>
{isEditingProfile ? (
{/* Avatar Selection */}
{avatarOptions.map((avatar) => (
))}
{/* Name Input */}
{
setProfileName(e.target.value);
// Update avatar preview with new name
if (!selectedAvatar || avatarOptions.some(a => selectedAvatar.includes(a.id))) {
const currentAvatar = avatarOptions.find(a => selectedAvatar?.includes(a.id));
if (currentAvatar) {
setSelectedAvatar(currentAvatar.url(e.target.value));
}
}
}}
className="w-full px-4 py-3 bg-zinc-50 dark:bg-zinc-950 border border-zinc-200 dark:border-zinc-800 rounded-lg text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-emerald-500/50"
placeholder="Enter your name"
/>
{/* Email Input */}
setProfileEmail(e.target.value)}
className="w-full px-4 py-3 bg-zinc-50 dark:bg-zinc-950 border border-zinc-200 dark:border-zinc-800 rounded-lg text-zinc-900 dark:text-zinc-100 focus:outline-none focus:ring-2 focus:ring-emerald-500/50"
placeholder="Enter your email"
/>
{/* Preview */}
{profileName || 'Your Name'}
{profileEmail || 'your@email.com'}
Preview
) : (
{userProfile.photo ? (

) : (
{userProfile.name?.charAt(0).toUpperCase()}
)}
{userProfile.name}
{userProfile.email}
Active Profile
)}
>
) : (
)}
{/* Appearance Settings */}
Customize how SafeRoute looks
Theme
Switch between light and dark mode
High Contrast Mode
Increase contrast for better visibility
Voice Navigation
Enable spoken turn-by-turn directions
{/* Preferences */}
Set your default travel preferences
Default Vehicle
Map Style
{[
{ value: 'default', label: 'Default', icon:
},
{ value: 'satellite', label: 'Satellite', icon:
},
{ value: 'navigation', label: 'Navigation', icon:
}
].map((style) => (
))}
{/* Data Management */}
Manage your saved data and history
Saved Locations
Your bookmarked places
{((): number => {
try {
return JSON.parse(localStorage.getItem('savedLocations') || '[]').length;
} catch {
return 0;
}
})()} saved
Recent Searches
Your search history
{((): number => {
try {
return JSON.parse(localStorage.getItem('recentSearches') || '[]').length;
} catch {
return 0;
}
})()} searches
{/* Version Info */}
SafeRoute v1.0.0
Made-with-Ayush
);
}
function AboutTab() {
return (
{/* Hero Section */}
About SafeRoute
An intelligent traffic safety platform that combines real-time routing, weather analysis, and AI-powered risk prediction to help you travel safer.
{/* Problem & Solution */}
The Problem
Road accidents claim over 1.3 million lives annually. Traditional navigation apps lack real-time safety insights, leaving drivers vulnerable to changing road conditions.
Our Solution
SafeRoute analyzes multiple risk factors including weather, traffic, time of day, and historical data to provide intelligent route recommendations.
{/* Key Features */}
Key Features
{[
{
icon: (
),
title: 'Route Risk Analysis',
desc: 'Dynamic color-coded routes showing real-time risk levels for each segment'
},
{
icon: (
),
title: 'Weather Integration',
desc: 'Real-time weather data affecting route risk calculations automatically'
},
{
icon: (
),
title: 'AI Assistant',
desc: 'Intelligent chatbot providing contextual safety advice and recommendations'
},
{
icon: (
),
title: 'Route Playback',
desc: 'Visualize your entire route with animated playback feature'
},
{
icon: (
),
title: 'Multiple Profiles',
desc: 'Save locations, view history, and customize preferences'
},
{
icon: (
),
title: 'Safety Score',
desc: 'Overall route safety rating based on multiple risk factors'
}
].map((feature, idx) => (
{feature.icon}
{feature.title}
{feature.desc}
))}
{/* How It Works */}
How It Works
{[
{ step: '01', title: 'Enter Route', desc: 'Search for your origin and destination' },
{ step: '02', title: 'Set Vehicle', desc: 'Choose driving or cycling mode' },
{ step: '03', title: 'Analyze Risk', desc: 'Our AI calculates safety scores' },
{ step: '04', title: 'Safe Travel', desc: 'Follow the safest route with live updates' }
].map((item, idx) => (
{item.step}
{item.title}
{item.desc}
{idx < 3 && (
)}
))}
{/* Technology Stack */}
Built With
{[
{ name: 'React', icon:
},
{ name: 'Leaflet', icon:
},
{ name: 'OpenStreetMap', icon:
},
{ name: 'Express', icon:
},
{ name: 'Machine Learning', icon:
},
{ name: 'Generative AI', icon:
},
{ name: 'Data Analytics', icon:
},
{ name: 'Predictive Modeling', icon:
},
{ name: 'Real-Time Data', icon:
}
].map((tech) => (
{tech.icon}
{tech.name}
))}
{/* Closing */}
SafeRoute is designed to help you make informed decisions about your travel routes. Always drive safely and follow local traffic regulations.
);
}
export default function App() {
const [routeData, setRouteData] = useState(null);
const [alternativeRoutes, setAlternativeRoutes] = useState([]);
const [riskData, setRiskData] = useState(null);
const [previousRouteData, setPreviousRouteData] = useState(null);
const [previousRiskData, setPreviousRiskData] = useState(null);
const [incidentsData, setIncidentsData] = useState(null);
const [weather, setWeather] = useState(null);
const [startLoc, setStartLoc] = useState<[number, number] | null>(null);
const [endLoc, setEndLoc] = useState<[number, number] | null>(null);
const [startQuery, setStartQuery] = useState('');
const [endQuery, setEndQuery] = useState('');
const [showRoutePlayback, setShowRoutePlayback] = useState(false);
const [playbackSpeed, setPlaybackSpeed] = useState(1);
const [theme, setTheme] = useState<'dark' | 'light'>(() => {
try {
const saved = localStorage.getItem('theme');
return (saved === 'dark' || saved === 'light') ? saved : 'dark';
} catch {
return 'dark';
}
});
const [vehicleType, setVehicleType] = useState<'driving' | 'cycling'>(() => {
try {
const saved = localStorage.getItem('vehicleType');
return (saved === 'driving' || saved === 'cycling') ? saved : 'driving';
} catch {
return 'driving';
}
});
const [showIncidents, setShowIncidents] = useState(false);
const [activeLayers, setActiveLayers] = useState([]);
const [mapStyleType, setMapStyleType] = useState(() => {
try {
return localStorage.getItem('mapStyleType') || 'default';
} catch {
return 'default';
}
});
const [showHeader, setShowHeader] = useState(true);
const [isSidebarOpen, setIsSidebarOpen] = useState(true);
const [userProfile, setUserProfile] = useState(() => {
try {
const saved = localStorage.getItem('userProfile');
return saved ? JSON.parse(saved) : null;
} catch {
return null;
}
});
const [showOnboarding, setShowOnboarding] = useState(() => {
try {
return !localStorage.getItem('onboardingComplete');
} catch {
return true;
}
});
const [showTripHistory, setShowTripHistory] = useState(false);
const [incidentReportLoc, setIncidentReportLoc] = useState<[number, number] | null>(null);
const [voiceNavEnabled, setVoiceNavEnabled] = useState(false);
const [highContrast, setHighContrast] = useState(() => {
try {
return localStorage.getItem('highContrast') === 'true';
} catch {
return false;
}
});
const handleLogin = (profile?: { name: string; email: string; photo?: string }) => {
if (profile) {
const user = {
name: profile.name,
email: profile.email,
photo: profile.photo || `https://api.dicebear.com/7.x/avataaars/svg?seed=${encodeURIComponent(profile.name)}`
};
setUserProfile(user);
localStorage.setItem('userProfile', JSON.stringify(user));
} else {
const mockUser = {
name: 'Guest User',
email: 'guest@example.com',
photo: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Felix'
};
setUserProfile(mockUser);
localStorage.setItem('userProfile', JSON.stringify(mockUser));
}
};
const handleLogout = () => {
setUserProfile(null);
localStorage.removeItem('userProfile');
};
const handleUpdateProfile = (name: string, email: string, photo: string) => {
const user = {
name,
email,
photo
};
setUserProfile(user);
localStorage.setItem('userProfile', JSON.stringify(user));
};
useEffect(() => {
localStorage.setItem('theme', theme);
if (theme === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}, [theme]);
useEffect(() => {
localStorage.setItem('vehicleType', vehicleType);
}, [vehicleType]);
useEffect(() => {
localStorage.setItem('mapStyleType', mapStyleType);
}, [mapStyleType]);
useEffect(() => {
localStorage.setItem('highContrast', String(highContrast));
if (highContrast) {
document.documentElement.classList.add('high-contrast');
} else {
document.documentElement.classList.remove('high-contrast');
}
}, [highContrast]);
const handleOnboardingComplete = () => {
setShowOnboarding(false);
localStorage.setItem('onboardingComplete', 'true');
requestNotificationPermission();
};
useKeyboardShortcuts([
{ key: 'h', ctrl: true, handler: () => setHighContrast(prev => !prev), description: 'Toggle high contrast' },
{ key: 'o', ctrl: true, handler: () => setShowOnboarding(true), description: 'Show onboarding' },
{ key: 't', ctrl: true, handler: () => setShowTripHistory(true), description: 'Trip history' },
]);
return (
{
setEndLoc(loc);
setEndQuery(name);
}}
currentEndLoc={endLoc}
currentEndQuery={endQuery}
/>
setIncidentReportLoc(loc)}
onOpenTripHistory={() => setShowTripHistory(true)}
onToggleVoiceNav={(enabled: boolean) => setVoiceNavEnabled(enabled)}
/>
} />
} />
} />
{showOnboarding && }
{showTripHistory && setShowTripHistory(false)} />}
{incidentReportLoc && (
setIncidentReportLoc(null)}
onSubmit={(report) => {
console.log('Incident reported:', report);
setIncidentReportLoc(null);
}}
/>
)}
);
}