'use client'; import { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { useEffectiveDriverId } from '@/lib/currentDriver'; import { getSendNotificationUseCase, getRaceRepository, getLeagueRepository } from '@/lib/di-container'; import type { NotificationUrgency } from '@gridpilot/notifications/application'; import { Bell, AlertTriangle, Vote, Shield, ChevronDown, ChevronUp, Wrench, X, MessageSquare, AlertCircle, BellRing, User, Building2, LogOut, LogIn, } from 'lucide-react'; type DemoNotificationType = 'protest_filed' | 'defense_requested' | 'vote_required'; type DemoUrgency = 'silent' | 'toast' | 'modal'; interface NotificationOption { type: DemoNotificationType; label: string; description: string; icon: typeof Bell; color: string; } interface UrgencyOption { urgency: DemoUrgency; label: string; description: string; icon: typeof Bell; } const notificationOptions: NotificationOption[] = [ { type: 'protest_filed', label: 'Protest Against You', description: 'A protest was filed against you', icon: AlertTriangle, color: 'text-red-400', }, { type: 'defense_requested', label: 'Defense Requested', description: 'A steward requests your defense', icon: Shield, color: 'text-warning-amber', }, { type: 'vote_required', label: 'Vote Required', description: 'You need to vote on a protest', icon: Vote, color: 'text-primary-blue', }, ]; const urgencyOptions: UrgencyOption[] = [ { urgency: 'silent', label: 'Silent', description: 'Only shows in notification center', icon: Bell, }, { urgency: 'toast', label: 'Toast', description: 'Shows a temporary popup', icon: BellRing, }, { urgency: 'modal', label: 'Modal', description: 'Shows blocking modal (must respond)', icon: AlertCircle, }, ]; type LoginMode = 'none' | 'driver' | 'sponsor'; export default function DevToolbar() { const router = useRouter(); const [isExpanded, setIsExpanded] = useState(false); const [isMinimized, setIsMinimized] = useState(false); const [selectedType, setSelectedType] = useState('protest_filed'); const [selectedUrgency, setSelectedUrgency] = useState('toast'); const [sending, setSending] = useState(false); const [lastSent, setLastSent] = useState(null); const [loginMode, setLoginMode] = useState('none'); const [loggingIn, setLoggingIn] = useState(false); const currentDriverId = useEffectiveDriverId(); // Sync login mode with actual cookie state on mount useEffect(() => { if (typeof document !== 'undefined') { const cookies = document.cookie.split(';'); const demoModeCookie = cookies.find(c => c.trim().startsWith('gridpilot_demo_mode=')); if (demoModeCookie) { const value = demoModeCookie.split('=')[1]?.trim(); if (value === 'sponsor') { setLoginMode('sponsor'); } else if (value === 'driver') { setLoginMode('driver'); } else { setLoginMode('none'); } } else { // Default to driver mode if no cookie (for demo purposes) setLoginMode('driver'); } } }, []); const handleLoginAsDriver = async () => { setLoggingIn(true); try { // Demo: Set cookie to indicate driver mode document.cookie = 'gridpilot_demo_mode=driver; path=/; max-age=86400'; setLoginMode('driver'); // Refresh to update all components that depend on demo mode window.location.reload(); } finally { setLoggingIn(false); } }; const handleLoginAsSponsor = async () => { setLoggingIn(true); try { // Demo: Set cookie to indicate sponsor mode document.cookie = 'gridpilot_demo_mode=sponsor; path=/; max-age=86400'; setLoginMode('sponsor'); // Navigate to sponsor dashboard window.location.href = '/sponsor/dashboard'; } finally { setLoggingIn(false); } }; const handleLogout = async () => { setLoggingIn(true); try { // Demo: Clear demo mode cookie document.cookie = 'gridpilot_demo_mode=; path=/; max-age=0'; setLoginMode('none'); // Refresh to update all components window.location.href = '/'; } finally { setLoggingIn(false); } }; // Only show in development if (process.env.NODE_ENV === 'production') { return null; } const handleSendNotification = async () => { setSending(true); try { const sendNotification = getSendNotificationUseCase(); const raceRepository = getRaceRepository(); const leagueRepository = getLeagueRepository(); const [allRaces, allLeagues] = await Promise.all([ raceRepository.findAll(), leagueRepository.findAll(), ]); const completedRaces = allRaces.filter((race: any) => race.status === 'completed'); const scheduledRaces = allRaces.filter((race: any) => race.status === 'scheduled'); const primaryRace = completedRaces[0] ?? allRaces[0]; const secondaryRace = scheduledRaces[0] ?? allRaces[1] ?? primaryRace; const primaryLeague = allLeagues[0]; let title: string; let body: string; let notificationType: 'protest_filed' | 'protest_defense_requested' | 'protest_vote_required'; let actionUrl: string; switch (selectedType) { case 'protest_filed': { const raceId = primaryRace?.id; title = '🚨 Protest Filed Against You'; body = 'A protest has been filed against you for unsafe rejoining during a recent race. Please review the incident details.'; notificationType = 'protest_filed'; actionUrl = raceId ? `/races/${raceId}/stewarding` : '/races'; break; } case 'defense_requested': { const raceId = secondaryRace?.id ?? primaryRace?.id; title = '⚖️ Defense Requested'; body = 'A steward has requested your defense regarding a recent incident. Please provide your side of the story within 48 hours.'; notificationType = 'protest_defense_requested'; actionUrl = raceId ? `/races/${raceId}/stewarding` : '/races'; break; } case 'vote_required': { const leagueId = primaryLeague?.id; title = '🗳️ Your Vote Required'; body = 'As a league steward, you are required to vote on an open protest. Please review the case and cast your vote.'; notificationType = 'protest_vote_required'; actionUrl = leagueId ? `/leagues/${leagueId}/stewarding` : '/leagues'; break; } } const actions = selectedUrgency === 'modal' ? [ { label: 'View Protest', type: 'primary' as const, href: actionUrl, actionId: 'view' }, { label: 'Dismiss', type: 'secondary' as const, actionId: 'dismiss' }, ] : undefined; await sendNotification.execute({ recipientId: currentDriverId, type: notificationType, title, body, actionUrl, urgency: selectedUrgency as NotificationUrgency, requiresResponse: selectedUrgency === 'modal', actions, data: { protestId: `demo-protest-${Date.now()}`, raceId: primaryRace?.id, leagueId: primaryLeague?.id, deadline: selectedUrgency === 'modal' ? new Date(Date.now() + 48 * 60 * 60 * 1000) : undefined, }, }); setLastSent(`${selectedType}-${selectedUrgency}`); setTimeout(() => setLastSent(null), 3000); } catch (error) { console.error('Failed to send demo notification:', error); } finally { setSending(false); } }; if (isMinimized) { return ( ); } return (
{/* Header */}
Dev Toolbar DEMO
{/* Content */} {isExpanded && (
{/* Notification Type Section */}
Notification Type
{notificationOptions.map((option) => { const Icon = option.icon; const isSelected = selectedType === option.type; return ( ); })}
{/* Urgency Section */}
Urgency Level
{urgencyOptions.map((option) => { const Icon = option.icon; const isSelected = selectedUrgency === option.urgency; return ( ); })}

{urgencyOptions.find(o => o.urgency === selectedUrgency)?.description}

{/* Send Button */} {/* Info */}

Silent: Notification center only
Toast: Temporary popup (auto-dismisses)
Modal: Blocking popup (requires action)

{/* Login Section */}
Demo Login
{loginMode !== 'none' && ( )}

Switch between driver and sponsor views for demo purposes.

)} {/* Collapsed state hint */} {!isExpanded && (
Click ↑ to expand dev tools
)}
); }