import React, { useCallback, useEffect, useMemo, useState } from 'react'; import type { Company, Contact, DirectoryUser, View } from './types'; import { companiesApi, contactsApi, dashboardApi, usersApi } from './lib/api'; import { useAuth } from './lib/auth'; import { NavigationProvider, type OpenTarget, type SettingsTab } from './lib/navigation'; import { LoginScreen } from './components/LoginScreen'; import { Sidebar } from './components/Sidebar'; import { Header } from './components/Header'; import { Dashboard } from './components/dashboard/Dashboard'; import { Contacts } from './components/contacts/Contacts'; import { Companies } from './components/companies/Companies'; import { Leads } from './components/leads/Leads'; import { Suspects } from './components/suspects/Suspects'; import { ReminderWatcher } from './components/leads/ReminderWatcher'; import { Tenders } from './components/tenders/Tenders'; import { LiveBoard } from './components/tenders/LiveBoard'; import { Projects } from './components/projects/Projects'; import { History } from './components/history/History'; import { ScannerDashboard } from './components/scanner/ScannerDashboard'; import { ScannerAgents } from './components/scanner/ScannerAgents'; import { Settings } from './components/settings/Settings'; /* * Rahmen der Anwendung: Anmeldung, Seitenleiste, Kopfzeile und der Wechsel * zwischen den Ansichten. * * Zwei Dinge liegen bewusst hier oben: * * Die Listen der Unternehmen und Benutzer werden einmal geladen und * weitergereicht - fast jedes Formular braucht sie als Auswahl. * * `open(type, id)` wechselt die Ansicht und reicht die Kennung dorthin * durch. Damit kann jede @-Erwaehnung und jeder Suchtreffer die passende * Karte oeffnen, ohne dass die Ebenen dazwischen davon wissen. */ export const App: React.FC = () => { const { user, isLoading } = useAuth(); const [view, setView] = useState('Dashboard'); const [collapsed, setCollapsed] = useState(false); const [companies, setCompanies] = useState([]); const [contacts, setContacts] = useState([]); const [users, setUsers] = useState([]); const [counts, setCounts] = useState>({}); const [pending, setPending] = useState<{ type: OpenTarget; id: number } | null>(null); /** Reiter, mit dem die Einstellungen oeffnen sollen (z. B. aus dem Diktat). */ const [settingsTab, setSettingsTab] = useState(null); const loadShared = useCallback(async () => { if (!user) return; try { const [{ companies: rows }, { contacts: people }, { users: directory }, dashboard] = await Promise.all([ companiesApi.list(), contactsApi.list(), usersApi.directory(), dashboardApi.load(), ]); setCompanies(rows); setContacts(people); setUsers(directory); setCounts(dashboard.counts); } catch { /* Ein Fehler hier darf die Anwendung nicht blockieren - die einzelnen Ansichten melden ihre eigenen Ladefehler. */ } }, [user]); useEffect(() => { void loadShared(); }, [loadShared]); const navigation = useMemo( () => ({ setView, open: (type: OpenTarget, id: number) => { const target: Record = { contact: 'Kontakte', company: 'Unternehmen', tender: 'Ausschreibungen', project: 'Laufende Projekte', lead: 'Leads', user: 'Einstellungen', }; const next = target[type]; if (!next) return; setView(next); setPending({ type, id }); }, goToSettings: (tab: SettingsTab) => { setSettingsTab(tab); setView('Einstellungen'); }, }), [] ); if (isLoading) { return (

Wird geladen …

); } if (!user) return ; /** Kennung nur an die Ansicht geben, die gerade sichtbar ist. */ const openIdFor = (type: OpenTarget) => (pending?.type === type ? pending.id : null); const clearPending = () => setPending(null); return (
setCollapsed((value) => !value)} />
{view === 'Dashboard' && } {view === 'Kontakte' && ( )} {view === 'Unternehmen' && ( )} {(view === 'Suspects' || view === 'Suspects · Archiv') && ( )} {(view === 'Leads' || view === 'Leads · Archiviert') && ( )} {(view === 'Ausschreibungen' || view === 'Ausschreibungen · Archiv') && ( )} {view === 'Live!' && } {view === 'Laufende Projekte' && ( )} {view === 'Scanner' && } {view === 'Scanner · Suchagenten' && } {view === 'Historie' && } {view === 'Einstellungen' && ( setSettingsTab(null)} /> )}
{/* Faellige und liegengebliebene Leads melden sich von selbst - unabhaengig davon, welche Ansicht gerade offen ist. */}
); };