refactor(startseite): Meetingraum als Fotoszene mit Live-Auslastung
Die gezeichnete Raumkulisse ist ersetzt. Aus Farbflächen konstruierte Wände bleiben neben fotografierten Agentenporträts erkennbar gezeichnet — die Bildwirkung muss aus dem Foto kommen, nicht aus Geometrie. Entfallen sind damit die beiden SVG-Stadtansichten, die CSS-3D-Flächen und die Farbwelt DS_MEETING_ROOM. Neu trägt die Szene die Basler Aussicht aus dem Auftrag als Foto (§5), mit abgestuftem Verlauf für Lesbarkeit und Übergang zur Objektliste. Ein Austausch des Motivs ist ein Einzeiler in `roomBackdrop.ts`. Mehrwert statt Kulisse: Jedes Namensschild zeigt die aktuelle Auslastung seines Agenten — überfällige Fristen, Termine der Woche, offene Exposés, neue Marktchancen, Objekte mit Datenlücken, offene Freigaben. Darüber fasst ein Anriss zusammen, wie viele Bereiche heute Aufmerksamkeit brauchen. Damit beantwortet die Startseite die Frage, mit der sie geöffnet wird, statt sie auf sechs Zahlen zu verteilen. - `agentWorkloadService` hält die fachlichen Festlegungen: Zeitfenster, Dringlichkeitsschwellen und Formulierungen. Der Stichzeitpunkt ist ein Parameter, nicht die Systemuhr — dieselbe Datenlage ergibt dasselbe Ergebnis, und der Dienst ist ohne Renderer prüfbar (10 neue Tests). - `useAgentWorkload` sammelt nur die Bestände ein. - Noras Zahl wird nie «dringend»: sie schlägt vor, sie entscheidet nicht. - Die Schilder bemessen ihre Höchstbreite an der Szenenbreite (`cqw`), nicht am Fenster. Am Fenster gemessen überlappten sie auf schmalen Laptops, weil die Szene um das Seitenmenü schmaler ist. Geprüft: 423 Tests, Typecheck, Build, ESLint, Token-Schwelle (889/925). Im Browser 1280–1920 px: keine Überlappungen, Titel und «Filter & Übersicht» beim Einstieg sichtbar, alle sechs Agentenklicks auf der richtigen Subpage, Tablet-Ansicht mit allen sechs Agenten, keine Konsolenfehler, keine 404. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { useMemo } from 'react'
|
||||
import { useReminders } from './useReminders'
|
||||
import { useVisitAssignments } from './useVisitAssignments'
|
||||
import { useExposeLeads } from './useExposeLeads'
|
||||
import { useUnifiedLeads } from './useUnifiedLeads'
|
||||
import { useProperties } from './useProperties'
|
||||
import { useAgentWorkItems } from './useAgentWorkItems'
|
||||
import { computeAgentWorkload } from '../services/agentWorkloadService'
|
||||
import type { AgentWorkload } from '../domain/agentWorkload'
|
||||
|
||||
/**
|
||||
* Aktuelle Auslastung aller sechs digitalen Mitarbeitenden (Runde 5).
|
||||
*
|
||||
* Der Hook sammelt nur die Bestände ein; was daraus wird, entscheidet
|
||||
* `agentWorkloadService` — Schwellen, Zeitfenster und Formulierungen sind
|
||||
* fachliche Festlegungen und gehören nicht in die Oberflächenschicht
|
||||
* (CLAUDE.md §4.2/§5.2).
|
||||
*/
|
||||
export function useAgentWorkload(): { data: Record<string, AgentWorkload>; isLoading: boolean } {
|
||||
const { data: reminders = [], isLoading: remindersLoading } = useReminders()
|
||||
const { data: visits = [], isLoading: visitsLoading } = useVisitAssignments()
|
||||
const { data: exposeLeads = [], isLoading: exposeLoading } = useExposeLeads()
|
||||
const { data: leads, isLoading: leadsLoading } = useUnifiedLeads()
|
||||
const { data: properties = [], isLoading: propertiesLoading } = useProperties()
|
||||
const { data: workItems = [], isLoading: workItemsLoading } = useAgentWorkItems()
|
||||
|
||||
const data = useMemo(
|
||||
() => computeAgentWorkload({ reminders, visits, exposeLeads, leads, properties, workItems }),
|
||||
[reminders, visits, exposeLeads, leads, properties, workItems],
|
||||
)
|
||||
|
||||
return {
|
||||
data,
|
||||
isLoading:
|
||||
remindersLoading || visitsLoading || exposeLoading ||
|
||||
leadsLoading || propertiesLoading || workItemsLoading,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user