import { useState, useEffect } from 'react' import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom' import { useAuth } from '@/hooks/useAuth' import Sidebar from '@/components/Sidebar' import LoginPage from '@/pages/LoginPage' import DashboardPage from '@/pages/DashboardPage' import TasksPage from '@/pages/TasksPage' import TaskDetailPage from '@/pages/TaskDetailPage' import ProjectsPage from '@/pages/ProjectsPage' import ProjectDetailPage from '@/pages/ProjectDetailPage' import MilestonesPage from '@/pages/MilestonesPage' import MilestoneDetailPage from '@/pages/MilestoneDetailPage' import NotificationsPage from '@/pages/NotificationsPage' import RoleEditorPage from '@/pages/RoleEditorPage' import MonitorPage from '@/pages/MonitorPage' import ProposalsPage from '@/pages/ProposalsPage' import ProposalDetailPage from '@/pages/ProposalDetailPage' import UsersPage from '@/pages/UsersPage' import CalendarPage from '@/pages/CalendarPage' import SupportDetailPage from '@/pages/SupportDetailPage' import MeetingDetailPage from '@/pages/MeetingDetailPage' import OidcCallbackPage from '@/pages/OidcCallbackPage' import OidcSettingsPage from '@/pages/OidcSettingsPage' import axios from 'axios' // Backend URL is baked in at build time via VITE_HF_BACKEND_BASE_URL (the // docker-compose hf-frontend service passes it as a build ARG). Falling // back to a same-origin call only makes sense in dev with the Vite proxy. // localStorage override is kept as an escape hatch for one-off pointing // (e.g. dev pointing the prod build at a local backend). const getApiBase = (): string => { const ls = localStorage.getItem('HF_BACKEND_BASE_URL') if (ls) return ls const baked = import.meta.env.VITE_HF_BACKEND_BASE_URL return baked || '' } type AppState = 'checking' | 'no-admin' | 'ready' export default function App() { const [appState, setAppState] = useState('checking') const [errorMessage, setErrorMessage] = useState('') const { user, loading, login, loginWithToken, logout } = useAuth() useEffect(() => { checkInitialized() }, []) const checkInitialized = async () => { try { const res = await axios.get(`${getApiBase()}/config/status`, { timeout: 5000 }) const cfg = res.data || {} if (cfg.initialized === true) { setAppState('ready') return } setAppState('no-admin') } catch (err) { const msg = err instanceof Error ? err.message : String(err) setErrorMessage(`Backend unreachable at ${getApiBase() || ''} — ${msg}`) setAppState('no-admin') } } if (appState === 'checking') { return
Checking deployment status…
} if (appState === 'no-admin') { return (

⚓ HarborForge

{errorMessage ? ( <>

Cannot reach the backend.

{errorMessage}

Set VITE_HF_BACKEND_BASE_URL at build time (e.g. https://hf-api.example.com) in the frontend container's compose entry.

) : ( <>

No admin user found. Bootstrap the deployment by running, on the host:

{`docker exec hf-backend hf-cli admin create-user \\
  --email you@example.com \\
  --password '...' \\
  # ...or in OIDC_ONLY mode:
  --oidc-issuer https://login.example.com/realms/your-realm \\
  --oidc-subject `}
              
)}
) } if (loading) return
Loading...
if (!user) { return (
} /> } /> } /> } /> } /> } />
) } return (
} /> } /> } /> } /> } /> } /> } /> } /> } /> } /> {/* Legacy routes for backward compatibility */} } /> } /> } /> } /> } /> } /> } /> } /> {user?.is_admin && } />} } /> } />
) }