This commit is contained in:
2025-12-31 19:55:43 +01:00
parent 8260bf7baf
commit 167e82a52b
66 changed files with 5124 additions and 228 deletions

View File

@@ -102,7 +102,7 @@ const urgencyOptions: UrgencyOption[] = [
},
];
type LoginMode = 'none' | 'driver' | 'sponsor';
type LoginMode = 'none' | 'driver' | 'sponsor' | 'league-owner' | 'league-steward' | 'league-admin' | 'system-owner' | 'super-admin';
export default function DevToolbar() {
const router = useRouter();
@@ -118,48 +118,92 @@ export default function DevToolbar() {
const currentDriverId = useEffectiveDriverId();
// Sync login mode with actual cookie state on mount
// Sync login mode with actual session state on mount
useEffect(() => {
if (typeof document !== 'undefined') {
// Check for actual session cookie first
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');
}
const sessionCookie = cookies.find(c => c.trim().startsWith('gp_session='));
if (sessionCookie) {
// User has a session cookie, check if it's valid by calling the API
fetch('/api/auth/session', {
method: 'GET',
credentials: 'include'
})
.then(res => {
if (res.ok) {
return res.json();
}
throw new Error('No valid session');
})
.then(session => {
if (session && session.user) {
// Determine login mode based on user email patterns
const email = session.user.email?.toLowerCase() || '';
const displayName = session.user.displayName?.toLowerCase() || '';
let mode: LoginMode = 'none';
if (email.includes('sponsor') || displayName.includes('sponsor')) {
mode = 'sponsor';
} else if (email.includes('league-owner') || displayName.includes('owner')) {
mode = 'league-owner';
} else if (email.includes('league-steward') || displayName.includes('steward')) {
mode = 'league-steward';
} else if (email.includes('league-admin') || displayName.includes('admin')) {
mode = 'league-admin';
} else if (email.includes('system-owner') || displayName.includes('system owner')) {
mode = 'system-owner';
} else if (email.includes('super-admin') || displayName.includes('super admin')) {
mode = 'super-admin';
} else if (email.includes('driver') || displayName.includes('demo')) {
mode = 'driver';
}
setLoginMode(mode);
} else {
setLoginMode('none');
}
})
.catch(() => {
// Session invalid or expired
setLoginMode('none');
});
} else {
// Default to driver mode if no cookie (for demo purposes)
setLoginMode('driver');
// No session cookie means not logged in
setLoginMode('none');
}
}
}, []);
const handleLoginAsDriver = async () => {
const handleDemoLogin = async (role: LoginMode) => {
if (role === 'none') return;
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);
}
};
// Use the demo login API
const response = await fetch('/api/auth/demo-login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ role }),
});
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';
if (!response.ok) {
throw new Error('Demo login failed');
}
setLoginMode(role);
// Navigate based on role
if (role === 'sponsor') {
window.location.href = '/sponsor/dashboard';
} else {
// For driver and league roles, go to dashboard
window.location.href = '/dashboard';
}
} catch (error) {
console.error('Demo login failed:', error);
alert('Demo login failed. Please check the console for details.');
} finally {
setLoggingIn(false);
}
@@ -168,11 +212,15 @@ export default function DevToolbar() {
const handleLogout = async () => {
setLoggingIn(true);
try {
// Demo: Clear demo mode cookie
document.cookie = 'gridpilot_demo_mode=; path=/; max-age=0';
// Call logout API
await fetch('/api/auth/logout', { method: 'POST' });
setLoginMode('none');
// Refresh to update all components
window.location.href = '/';
} catch (error) {
console.error('Logout failed:', error);
alert('Logout failed. Please check the console for details.');
} finally {
setLoggingIn(false);
}
@@ -561,8 +609,9 @@ export default function DevToolbar() {
</div>
<div className="space-y-2">
{/* Driver Login */}
<button
onClick={handleLoginAsDriver}
onClick={() => handleDemoLogin('driver')}
disabled={loggingIn || loginMode === 'driver'}
className={`
w-full flex items-center gap-2 px-3 py-2 rounded-lg border text-sm font-medium transition-all
@@ -574,11 +623,63 @@ export default function DevToolbar() {
`}
>
<User className="w-4 h-4" />
{loginMode === 'driver' ? 'Logged in as Driver' : 'Login as Driver'}
{loginMode === 'driver' ? ' Driver' : 'Login as Driver'}
</button>
{/* League Owner Login */}
<button
onClick={handleLoginAsSponsor}
onClick={() => handleDemoLogin('league-owner')}
disabled={loggingIn || loginMode === 'league-owner'}
className={`
w-full flex items-center gap-2 px-3 py-2 rounded-lg border text-sm font-medium transition-all
${loginMode === 'league-owner'
? 'bg-purple-500/20 border-purple-500/50 text-purple-400'
: 'bg-iron-gray/30 border-charcoal-outline text-gray-300 hover:bg-iron-gray/50'
}
disabled:opacity-50 disabled:cursor-not-allowed
`}
>
<span className="text-xs">👑</span>
{loginMode === 'league-owner' ? '✓ League Owner' : 'Login as League Owner'}
</button>
{/* League Steward Login */}
<button
onClick={() => handleDemoLogin('league-steward')}
disabled={loggingIn || loginMode === 'league-steward'}
className={`
w-full flex items-center gap-2 px-3 py-2 rounded-lg border text-sm font-medium transition-all
${loginMode === 'league-steward'
? 'bg-amber-500/20 border-amber-500/50 text-amber-400'
: 'bg-iron-gray/30 border-charcoal-outline text-gray-300 hover:bg-iron-gray/50'
}
disabled:opacity-50 disabled:cursor-not-allowed
`}
>
<Shield className="w-4 h-4" />
{loginMode === 'league-steward' ? '✓ Steward' : 'Login as Steward'}
</button>
{/* League Admin Login */}
<button
onClick={() => handleDemoLogin('league-admin')}
disabled={loggingIn || loginMode === 'league-admin'}
className={`
w-full flex items-center gap-2 px-3 py-2 rounded-lg border text-sm font-medium transition-all
${loginMode === 'league-admin'
? 'bg-red-500/20 border-red-500/50 text-red-400'
: 'bg-iron-gray/30 border-charcoal-outline text-gray-300 hover:bg-iron-gray/50'
}
disabled:opacity-50 disabled:cursor-not-allowed
`}
>
<span className="text-xs"></span>
{loginMode === 'league-admin' ? '✓ Admin' : 'Login as Admin'}
</button>
{/* Sponsor Login */}
<button
onClick={() => handleDemoLogin('sponsor')}
disabled={loggingIn || loginMode === 'sponsor'}
className={`
w-full flex items-center gap-2 px-3 py-2 rounded-lg border text-sm font-medium transition-all
@@ -590,7 +691,41 @@ export default function DevToolbar() {
`}
>
<Building2 className="w-4 h-4" />
{loginMode === 'sponsor' ? 'Logged in as Sponsor' : 'Login as Sponsor'}
{loginMode === 'sponsor' ? ' Sponsor' : 'Login as Sponsor'}
</button>
{/* System Owner Login */}
<button
onClick={() => handleDemoLogin('system-owner')}
disabled={loggingIn || loginMode === 'system-owner'}
className={`
w-full flex items-center gap-2 px-3 py-2 rounded-lg border text-sm font-medium transition-all
${loginMode === 'system-owner'
? 'bg-indigo-500/20 border-indigo-500/50 text-indigo-400'
: 'bg-iron-gray/30 border-charcoal-outline text-gray-300 hover:bg-iron-gray/50'
}
disabled:opacity-50 disabled:cursor-not-allowed
`}
>
<span className="text-xs">👑</span>
{loginMode === 'system-owner' ? '✓ System Owner' : 'Login as System Owner'}
</button>
{/* Super Admin Login */}
<button
onClick={() => handleDemoLogin('super-admin')}
disabled={loggingIn || loginMode === 'super-admin'}
className={`
w-full flex items-center gap-2 px-3 py-2 rounded-lg border text-sm font-medium transition-all
${loginMode === 'super-admin'
? 'bg-pink-500/20 border-pink-500/50 text-pink-400'
: 'bg-iron-gray/30 border-charcoal-outline text-gray-300 hover:bg-iron-gray/50'
}
disabled:opacity-50 disabled:cursor-not-allowed
`}
>
<span className="text-xs"></span>
{loginMode === 'super-admin' ? '✓ Super Admin' : 'Login as Super Admin'}
</button>
{loginMode !== 'none' && (
@@ -606,7 +741,7 @@ export default function DevToolbar() {
</div>
<p className="text-[10px] text-gray-600 mt-2">
Switch between driver and sponsor views for demo purposes.
Test different user roles for demo purposes. Dashboard works for all roles.
</p>
</div>
</div>