Hauptnavigation und Startseite (§2) - Hauptseite «Übersicht» samt Route, Menüeintrag, Hook, Service und den nur dort verwendeten Widgets entfernt; /supply/dashboard leitet auf die Startseite um, damit Lesezeichen nicht ins Leere laufen. - «Meine Objekte» heisst im Menü «Startseite»; die frühere Überschrift «Objektverwaltung» heisst jetzt «Meine Objekte». - Die Startseite scrollt als Ganzes. Die Höhe des Meetingraums rechnet gegen die Viewport-Höhe, damit Titel und Balken «Filter & Übersicht» beim Einstieg auf jeder Monitorgrösse sichtbar bleiben (geprüft 1280–1920 px). Agenten-Meetingraum (§3) - Zentralperspektive aus clip-path-Flächen, ohne 3D-Engine und ohne Animationsbibliothek: rechts geschlossene Wand, links und gegenüber boden- bis deckenhohe Glasfronten mit Blick auf Rhein, Basler Münster, Altstadt und Wettsteinbrücke. - Sitzordnung, Zielrouten, Grössen und Plakettenversatz liegen in einer zentralen Konfiguration (meetingRoomSeats.ts). - Neuer Agent Giorgio, Personalverwalter, sitzt vis-à-vis und führt in «Meine Agenten». Er steht bewusst nicht in AGENT_WORKSPACES: er hat keine Arbeitsseite, sondern ist die Adminfläche selbst. - Auf schmalen Schirmen tritt eine vereinfachte Kachelanordnung an die Stelle der Perspektive; ausgeblendet wird kein Agent. Sticky Chat bei allen Agenten (§5, §9–§11) - Scrollt der Chatkopf unter den globalen Balken, übernimmt dort eine kompakte Fassung mit Porträt, Name, Frage und Eingabefeld. - Ein gemeinsamer Zustand (agentChatStore) statt zweier Chat-Instanzen: Eingabetext und Fokus überstehen den Wechsel in beide Richtungen. - Noras Seite scrollte bisher gar nicht — Chatkopf ausserhalb des Scrollbereichs, zwei getrennt scrollende Spalten darunter. Behoben über den Seitenaufbau, nicht über eine Nora-Sonderlösung. Nora: CRM-Kanal und gemeinsame Lead-Liste (§12, §13) - Dritter Kanal «CRM» mit eigenem Domänentyp, Mockdaten, Provider, Service und Hook nach dem bestehenden Schichtenmuster. - Die Reiter «KI-Signale»/«Netzwerk» sind einer gemeinsamen Liste gewichen. Jede Zeile trägt ihre Kanalherkunft als Badge; die Herkunft steht im Datenmodell (LeadChannel) und wird nicht aus der Darstellung geraten. - Der frühere Reiterbalken ist der Filter «Kanaltyp» mit Alle/KI Signal/ Netzwerk/CRM, Standard «Alle», mit Empty State und Rücksetzung. Produkttour und Profilmenü (§8) - Tour auf die neue Struktur umgeschrieben: Startseite, Meetingraum, Agenten, sticky Chat, Leadkanäle. «Übersicht» kommt nicht mehr vor, «Meine Objekte» bezeichnet nur noch den Objektbereich. - Bereich «Demo-Modus» mit «Verwaltung» und «Bürosuche» entfernt. Geprüft: 413 Tests, Typecheck, Build, ESLint, Token-Schwelle (889/925). Im Browser: Navigation, Agentenklicks aller sechs Plätze, Kanalfilter und Detailschubladen, Sticky Chat bei vier Agenten, 1280–1920 px sowie Tablet- und Mobilbreite, keine 404 für Bilder oder Routen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
106 lines
5.0 KiB
TypeScript
106 lines
5.0 KiB
TypeScript
import { lazy, Suspense } from 'react'
|
|
import { Routes, Route, Navigate } from 'react-router'
|
|
import { LoadingPage, AppErrorBoundary } from './components/ui'
|
|
import { AppShell } from './components/layout'
|
|
import { ProtectedRoute } from './components/auth'
|
|
import { WorkspaceType } from './domain/enums'
|
|
import { useSessionStore } from './stores/sessionStore'
|
|
import { AGENT_SECTIONS, AGENT_SECTION_PARAM, ROUTES } from './lib/constants'
|
|
|
|
// Die Flächensuche ist entfernt — es bleibt ein einziger erreichbarer Einstieg.
|
|
// Seit Runde 5 ist das die Startseite; die frühere «Übersicht» existiert nicht mehr.
|
|
const WORKSPACE_HOME: Record<string, string> = {
|
|
[WorkspaceType.SUPPLY]: ROUTES.SUPPLY.PROPERTIES,
|
|
}
|
|
|
|
function RoleRedirect() {
|
|
const currentUser = useSessionStore(s => s.currentUser)
|
|
const first = currentUser?.allowedWorkspaces[0] ?? WorkspaceType.SUPPLY
|
|
return <Navigate to={WORKSPACE_HOME[first] ?? ROUTES.SUPPLY.PROPERTIES} replace />
|
|
}
|
|
|
|
const LoginScreen = lazy(() => import('./pages/auth/LoginScreen'))
|
|
|
|
const Properties = lazy(() => import('./pages/supply/Properties'))
|
|
const MatchCenter = lazy(() => import('./pages/supply/MatchCenter'))
|
|
const FutureAvailability = lazy(() => import('./pages/supply/FutureAvailability'))
|
|
const DataQuality = lazy(() => import('./pages/supply/DataQuality'))
|
|
const ReminderManager = lazy(() => import('./pages/supply/ReminderManager'))
|
|
const MarketIntelligence = lazy(() => import('./pages/supply/MarketIntelligence'))
|
|
const NewListing = lazy(() => import('./pages/supply/NewListing'))
|
|
const MyListings = lazy(() => import('./pages/supply/MyListings'))
|
|
const Besichtigungen = lazy(() => import('./pages/supply/Besichtigungen'))
|
|
|
|
// Property On — «Meine Agenten»
|
|
const MeineAgenten = lazy(() => import('./pages/supply/MeineAgenten'))
|
|
|
|
/** Alter Unterseitenpfad → Reiter der Hauptseite. Hält Lesezeichen am Leben. */
|
|
function TeamSectionRedirect({ section }: { section: string }) {
|
|
return <Navigate to={`${ROUTES.SUPPLY.TEAM}?${AGENT_SECTION_PARAM}=${section}`} replace />
|
|
}
|
|
|
|
function App() {
|
|
return (
|
|
<AppErrorBoundary>
|
|
<Suspense fallback={<LoadingPage />}>
|
|
<Routes>
|
|
{/* Public */}
|
|
<Route path="/auth/login" element={<LoginScreen />} />
|
|
|
|
{/* Protected: auth check only */}
|
|
<Route element={<ProtectedRoute />}>
|
|
<Route element={<AppShell />}>
|
|
<Route path="/" element={<RoleRedirect />} />
|
|
|
|
{/* Supply Workspace */}
|
|
<Route element={<ProtectedRoute workspace={WorkspaceType.SUPPLY} />}>
|
|
{/* Runde 5, §2.1: Die Hauptseite «Übersicht» ist entfernt. Der
|
|
alte Pfad bleibt als Umleitung bestehen, damit Lesezeichen
|
|
und Deep Links auf der Startseite landen statt im Nichts. */}
|
|
<Route
|
|
path={ROUTES.SUPPLY.LEGACY_DASHBOARD}
|
|
element={<Navigate to={ROUTES.SUPPLY.PROPERTIES} replace />}
|
|
/>
|
|
<Route path="/supply/properties" element={<Properties />} />
|
|
{/* Objekt-Detailroute — Ziel aller Objektlinks der Agentenseiten. */}
|
|
<Route path="/supply/properties/:propertyId" element={<Properties />} />
|
|
<Route path="/supply/match-center" element={<MatchCenter />} />
|
|
<Route path="/supply/future-availability" element={<FutureAvailability />} />
|
|
<Route path="/supply/new-listing" element={<NewListing />} />
|
|
|
|
{/* Die fünf Agentenseiten. Vier behalten den Pfad ihres Vorgängers. */}
|
|
<Route path="/supply/reminder-manager" element={<ReminderManager />} />
|
|
<Route path="/supply/besichtigungen" element={<Besichtigungen />} />
|
|
<Route path="/supply/my-listings" element={<MyListings />} />
|
|
<Route path="/supply/market-intelligence" element={<MarketIntelligence />} />
|
|
<Route path="/supply/data-quality" element={<DataQuality />} />
|
|
|
|
{/* Property On — «Meine Agenten». Die drei Verwaltungsbereiche sind
|
|
seit Runde 4 Reiter derselben Seite; die alten Unterseitenpfade
|
|
leiten dorthin um, damit bestehende Lesezeichen nicht brechen. */}
|
|
<Route path="/supply/team" element={<MeineAgenten />} />
|
|
<Route
|
|
path="/supply/team/personalverwaltung/*"
|
|
element={<TeamSectionRedirect section={AGENT_SECTIONS.PERSONNEL} />}
|
|
/>
|
|
<Route
|
|
path="/supply/team/bearbeitungsverlauf/*"
|
|
element={<TeamSectionRedirect section={AGENT_SECTIONS.HISTORY} />}
|
|
/>
|
|
<Route
|
|
path="/supply/team/kanaele-systeme"
|
|
element={<TeamSectionRedirect section={AGENT_SECTIONS.CHANNELS} />}
|
|
/>
|
|
</Route>
|
|
</Route>
|
|
</Route>
|
|
|
|
<Route path="*" element={<Navigate to="/" replace />} />
|
|
</Routes>
|
|
</Suspense>
|
|
</AppErrorBoundary>
|
|
)
|
|
}
|
|
|
|
export default App
|