Setzt das Umsetzungsbriefing Runde 4 im bestehenden Frontend um. Informationsarchitektur - «Teamübersicht» heisst «Meine Agenten»; ihr bisheriger Inhalt (Kreisgrafik, Auswertung, Verbindungszusammenfassung) ist entfallen. - Personalverwaltung, Bearbeitungsverlauf und Kanäle & Systeme sind jetzt Reiter derselben Seite (?section=), gestaltet wie die Auswahl im Bearbeitungsverlauf. Es wird nur der gewählte Bereich gerendert. - Die alten Unterseitenpfade leiten um, damit Lesezeichen nicht brechen. Agentenbestand - Reto und Lea vollständig entfernt — aus Navigation, Dossiers, Protokoll, Verbindungen, Vorgängen und Porträtbestand. - Retos Aufgaben liegen bei Bruno: Nachbereitung, WhatsApp-Anruf, Protokoll und Kundennotiz, Ablage im CRM. - Livia ist «Exposé Master»: Lageberichte, Inserate, Angebotsbroschüren. - Sidebar führt Ferdi, Bruno, Livia, Nora, Sina mit Porträt und Funktion. Agentenseiten - Ein gemeinsamer AgentWorkspaceHero auf allen fünf Seiten. - Ferdi: Auswertungskarten, Priorität und Typfarben entfallen; Fälligkeit nur bei fünf Tagen oder weniger rot; Objektlinks nach «Meine Objekte»; neu die Terminplanung im verbundenen Kalender mit typgerechtem PDF-Ausschnitt. - Sina: reduzierte, filter- und sortierbare Objektübersicht; Detailansicht direkt editierbar, leere Pflichtfelder rot umrandet. - Nora: Signale ohne Prozentsätze und Konfidenzstufen, nur belegbare Angaben; Mehrfachauswahl leitet Objekte an Livia weiter. - Livia: aktive und archivierte Leads, Arbeitsbereich gleitet an den oberen Rand; dreistufiger Exposé-Prozess Hochladen → Exposé → Export. - Bruno: neue Seite mit Auftragsliste und Vor-/Nachbereitungs-Drawer; Glocke warnt bei Besichtigung unter 24 Stunden ohne Bericht. Datenschicht - Neu: Kalender, Exposé-Leads, Exposé-Entwürfe, Besichtigungsaufträge — je Domain, Provider, Service und Hook. - IAIService um generateExposeText erweitert; der Entwurf nutzt ausschliesslich erfasste Objektdaten und meldet Lücken, statt sie zu füllen. - Alle Objektverweise zeigen auf reale Einträge aus «Meine Objekte»; neue Detailroute /supply/properties/:propertyId. Offen: Chat, Kalender, CRM und DMS sind Frontend-Simulation ohne Anbindung. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
157 lines
5.2 KiB
TypeScript
157 lines
5.2 KiB
TypeScript
import { WorkspaceType } from '../../domain/enums'
|
|
import { MY_AGENTS_LABEL, ROUTES } from '../../lib/constants'
|
|
import { AGENT_WORKSPACES } from '../../lib/agentWorkspaces'
|
|
import type { LucideIcon } from 'lucide-react'
|
|
import {
|
|
LayoutDashboard,
|
|
Building2,
|
|
CheckSquare,
|
|
Search,
|
|
ClipboardList,
|
|
Settings,
|
|
Users,
|
|
} from 'lucide-react'
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Types
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Eingerückter Subreiter unterhalb eines Hauptreiters.
|
|
*
|
|
* Ohne `agentId` bleibt der Eintrag eine reine Textzeile — Einrückung und
|
|
* schmalerer Schriftgrad machen die Hierarchie deutlich. Mit `agentId` zeigt
|
|
* die Sidebar stattdessen Porträt, Name und Funktion: die fünf digitalen
|
|
* Mitarbeitenden sind Personen, keine Menüpunkte (Runde 4, §2.2). Bewusst kein
|
|
* Autonomiegrad und kein technisches Kurzlabel.
|
|
*/
|
|
export interface NavSubItem {
|
|
path: string
|
|
label: string
|
|
/** Agenten-ID für Porträt und Funktionszeile. */
|
|
agentId?: string
|
|
/** Funktionsbezeichnung unter dem Namen. Nur zusammen mit `agentId`. */
|
|
role?: string
|
|
}
|
|
|
|
export interface NavItem {
|
|
path: string
|
|
label: string
|
|
icon: LucideIcon
|
|
/**
|
|
* Subreiter, die sichtbar bleiben, solange sich der Nutzer innerhalb des
|
|
* Funktionsbereichs befindet (Property On, §3.3).
|
|
*/
|
|
children?: NavSubItem[]
|
|
}
|
|
|
|
export interface WorkspaceConfig {
|
|
label: string
|
|
abbreviation: string
|
|
icon: LucideIcon
|
|
firstPath: string
|
|
navItems: NavItem[]
|
|
chipColor: string
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Workspace configuration
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export const WORKSPACE_CONFIG: Record<WorkspaceType, WorkspaceConfig> = {
|
|
[WorkspaceType.SUPPLY]: {
|
|
label: 'Verwaltung',
|
|
abbreviation: 'VW',
|
|
icon: Building2,
|
|
firstPath: '/supply/dashboard',
|
|
chipColor: '#152642',
|
|
navItems: [
|
|
{ path: '/supply/dashboard', label: 'Übersicht', icon: LayoutDashboard },
|
|
{ path: '/supply/properties', label: 'Meine Objekte', icon: Building2 },
|
|
{
|
|
path: ROUTES.SUPPLY.TEAM,
|
|
label: MY_AGENTS_LABEL,
|
|
icon: Users,
|
|
// Die drei Verwaltungsbereiche sind Reiter der Hauptseite geworden;
|
|
// hier stehen ab Runde 4 die fünf digitalen Mitarbeitenden selbst.
|
|
children: AGENT_WORKSPACES.map(a => ({
|
|
path: a.path,
|
|
label: a.name,
|
|
agentId: a.id,
|
|
role: a.role,
|
|
})),
|
|
},
|
|
],
|
|
},
|
|
/**
|
|
* Die Flächensuche ist in diesem Branch entfernt. Der Eintrag bleibt nur
|
|
* bestehen, weil `WorkspaceType` als Domänen-Enum unangetastet bleibt und
|
|
* dieser Record vollständig sein muss — sichtbar ist er nirgends, denn
|
|
* `WORKSPACE_ORDER` führt ihn nicht mehr und es existiert keine Route.
|
|
*/
|
|
[WorkspaceType.DEMAND]: {
|
|
label: 'Suche',
|
|
abbreviation: 'SU',
|
|
icon: Search,
|
|
firstPath: '/supply/dashboard',
|
|
chipColor: '#1a7a4a',
|
|
navItems: [],
|
|
},
|
|
[WorkspaceType.OPERATIONS]: {
|
|
label: 'Operations',
|
|
abbreviation: 'OP',
|
|
icon: Settings,
|
|
firstPath: '/ops/review-queue',
|
|
chipColor: '#6b21a8',
|
|
navItems: [
|
|
{ path: '/ops/review-queue', label: 'Review Queue', icon: CheckSquare },
|
|
{ path: '/ops/audit', label: 'Audit Log', icon: ClipboardList },
|
|
],
|
|
},
|
|
}
|
|
|
|
// Ordered list for rendering workspace tabs
|
|
export const WORKSPACE_ORDER: WorkspaceType[] = [
|
|
WorkspaceType.SUPPLY,
|
|
]
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Helpers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export function getWorkspaceFromPath(pathname: string): WorkspaceType | null {
|
|
if (pathname.startsWith('/supply')) return WorkspaceType.SUPPLY
|
|
return null
|
|
}
|
|
|
|
export function getPageNameFromPath(pathname: string): string {
|
|
for (const ws of Object.values(WORKSPACE_CONFIG)) {
|
|
for (const item of ws.navItems) {
|
|
if (item.path === pathname) return item.label
|
|
for (const child of item.children ?? []) {
|
|
if (child.path === pathname) return child.label
|
|
}
|
|
}
|
|
}
|
|
// Property On: Deep-Links auf Personalblatt und Verlaufsreiter. Ohne diese Fälle
|
|
// fiele der Titel in den Segment-Fallback und ergäbe «Personalverwaltung» statt
|
|
// des Mitarbeiternamens bzw. «Erledigte auftraege». Die Basispfade der drei
|
|
// Verwaltungsbereiche leiten auf `/supply/team?section=…` um, führen aber bis
|
|
// zum Abschluss der Umleitung noch kurz durch den Seitentitel.
|
|
if (/^\/supply\/team\/personalverwaltung(\/.+)?$/.test(pathname)) return MY_AGENTS_LABEL
|
|
if (/^\/supply\/team\/bearbeitungsverlauf(\/.+)?$/.test(pathname)) return MY_AGENTS_LABEL
|
|
if (/^\/supply\/team\/kanaele-systeme$/.test(pathname)) return MY_AGENTS_LABEL
|
|
if (/^\/supply\/properties\/.+/.test(pathname)) return 'Objekt Detail'
|
|
const segment = pathname.split('/').filter(Boolean).pop() ?? ''
|
|
return segment.charAt(0).toUpperCase() + segment.slice(1).replace(/-/g, ' ')
|
|
}
|
|
|
|
export function getUserInitials(name: string): string {
|
|
return name
|
|
.split(' ')
|
|
.map((n) => n[0])
|
|
.join('')
|
|
.toUpperCase()
|
|
.slice(0, 2)
|
|
}
|