Files
usda-vision/management-dashboard-web-app/src/App.tsx
salirezav ed6c242faa Enhance scheduling features in management dashboard
- Added new scheduling functionality with a dedicated Scheduling component to manage availability and experiment scheduling.
- Integrated react-big-calendar for visual calendar representation of availability slots.
- Updated Dashboard and DashboardLayout components to handle current route and pass it to child components.
- Implemented route handling for scheduling sub-routes to improve user navigation.
- Added new dependencies: moment and react-big-calendar for date handling and calendar UI.
- Improved user experience with dynamic URL updates based on selected scheduling views.
2025-09-19 12:33:25 -04:00

159 lines
4.4 KiB
TypeScript
Executable File

import { useState, useEffect } from 'react'
import { supabase } from './lib/supabase'
import { Login } from './components/Login'
import { Dashboard } from './components/Dashboard'
import { CameraRoute } from './components/CameraRoute'
function App() {
const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(null)
const [loading, setLoading] = useState(true)
const [currentRoute, setCurrentRoute] = useState(window.location.pathname)
useEffect(() => {
// Check initial auth state
checkAuthState()
// Listen for auth changes
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
console.log('Auth state changed:', event, !!session)
setIsAuthenticated(!!session)
setLoading(false)
// Handle signout route
if (event === 'SIGNED_OUT') {
setCurrentRoute('/')
window.history.pushState({}, '', '/')
}
})
// Handle browser navigation
const handlePopState = () => {
setCurrentRoute(window.location.pathname)
}
window.addEventListener('popstate', handlePopState)
return () => {
subscription.unsubscribe()
window.removeEventListener('popstate', handlePopState)
}
}, [])
useEffect(() => {
// Handle signout route
if (currentRoute === '/signout') {
handleLogout()
}
}, [currentRoute])
const checkAuthState = async () => {
try {
const { data: { session } } = await supabase.auth.getSession()
setIsAuthenticated(!!session)
} catch (error) {
console.error('Error checking auth state:', error)
setIsAuthenticated(false)
} finally {
setLoading(false)
}
}
const handleLoginSuccess = () => {
setIsAuthenticated(true)
setCurrentRoute('/')
window.history.pushState({}, '', '/')
}
const handleLogout = async () => {
try {
// Clear Supabase session
await supabase.auth.signOut()
// Clear any local storage items
localStorage.removeItem('supabase.auth.token')
localStorage.removeItem('dashboard-current-view')
// Reset state
setIsAuthenticated(false)
setCurrentRoute('/')
window.history.pushState({}, '', '/')
} catch (error) {
console.error('Logout error:', error)
// Still reset state even if there's an error
localStorage.removeItem('dashboard-current-view')
setIsAuthenticated(false)
setCurrentRoute('/')
window.history.pushState({}, '', '/')
}
}
// Check if current route is a camera live route
const isCameraLiveRoute = (route: string) => {
const cameraRoutePattern = /^\/camera(\d+)\/live$/
return cameraRoutePattern.test(route)
}
// Extract camera number from route
const getCameraNumber = (route: string) => {
const match = route.match(/^\/camera(\d+)\/live$/)
return match ? `camera${match[1]}` : null
}
// Check if current route is a scheduling sub-route
const isSchedulingRoute = (route: string) => {
return route.startsWith('/scheduling')
}
// Extract scheduling sub-route
const getSchedulingSubRoute = (route: string) => {
if (route === '/scheduling') {
return 'main'
}
const match = route.match(/^\/scheduling\/(.+)$/)
return match ? match[1] : 'main'
}
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50">
<div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-600 mx-auto"></div>
<p className="mt-4 text-gray-600">Loading...</p>
</div>
</div>
)
}
// Handle signout route
if (currentRoute === '/signout') {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50">
<div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-600 mx-auto"></div>
<p className="mt-4 text-gray-600">Signing out...</p>
</div>
</div>
)
}
// Handle camera live routes (no authentication required)
if (isCameraLiveRoute(currentRoute)) {
const cameraNumber = getCameraNumber(currentRoute)
if (cameraNumber) {
return <CameraRoute cameraNumber={cameraNumber} />
}
}
return (
<>
{isAuthenticated ? (
<Dashboard onLogout={handleLogout} currentRoute={currentRoute} />
) : (
<Login onLoginSuccess={handleLoginSuccess} />
)}
</>
)
}
export default App