Der Smoke-Test der fünf betroffenen Seiten hat zwei Fehler aus Runde 8 aufgedeckt, die Typecheck, Lint und Tests nicht sehen konnten. Thomas' Chatkopf blieb stehen, statt in den Titelbalken zu wandern. Seine Seite bot nur 307 Pixel Scrollweg, der Chatkopf misst aber rund 400 — der IntersectionObserver löste deshalb nie aus. Bei den anderen Agenten leistet die lange Liste unter dem Chat den nötigen Weg; hier haben die drei Verwaltungsbereiche ihre eigene Höhe und scrollen innen, also muss die Bedingung ausdrücklich stehen. Die Mindesthöhe des Abschnitts ist jetzt eine Bildschirmhöhe abzüglich des obersten Balkens; `TOP_BAR_PX` kommt dafür aus `AgentWorkspaceHero` statt als zweite Zahl danebenzustehen. Livias Zählzeile schrieb «1 Risiken». Einzahl und Mehrzahl werden nun für alle drei Werte der Zeile unterschieden. Geprüft im Browser gegen den Produktionsbuild: fünf Seiten ohne Laufzeitfehler, Thomas' kompakter Chat erscheint nach dem Scrollen im Balken, Chance- und Risiko-Beispiele sichtbar, alle fünf Vertragstypen bei Ferdi vorhanden, keine Matching-Darstellung auf Livias Seite. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
90 lines
3.5 KiB
TypeScript
90 lines
3.5 KiB
TypeScript
import { useCallback } from 'react'
|
|
import { useSearchParams } from 'react-router'
|
|
import { Box } from '@mui/material'
|
|
import {
|
|
TeamPageHeader,
|
|
AgentWorkspaceHero,
|
|
TOP_BAR_PX,
|
|
AgentWorkspaceTabs,
|
|
PersonnelSection,
|
|
HistorySection,
|
|
ChannelsSection,
|
|
} from '../../components/team'
|
|
import {
|
|
AGENT_SECTIONS,
|
|
AGENT_SECTION_ORDER,
|
|
AGENT_SECTION_PARAM,
|
|
MY_AGENTS_LABEL,
|
|
THOMAS_INTRO,
|
|
} from '../../lib/constants'
|
|
import type { AgentSection } from '../../lib/constants'
|
|
import { AGENT_SUPERVISOR } from '../../lib/agentWorkspaces'
|
|
|
|
function resolveSection(raw: string | null): AgentSection {
|
|
return AGENT_SECTION_ORDER.find(s => s === raw) ?? AGENT_SECTIONS.PERSONNEL
|
|
}
|
|
|
|
/**
|
|
* Hauptseite «Meine Agenten» — der Arbeitsplatz von Thomas (Runde 8, §3).
|
|
*
|
|
* Die Seite beginnt jetzt wie jede andere Agentenseite mit dem Chat-Einstieg:
|
|
* Porträt, Name, Funktion und Eingabefeld. Beim Herunterscrollen wandert er
|
|
* über denselben `IntersectionObserver` wie bei Ferdi, Bruno, Livia, Nora und
|
|
* Sina in den obersten Balken — es ist buchstäblich dieselbe Komponente
|
|
* (`AgentWorkspaceHero`) und dieselbe `AgentChatStickyBar`, keine
|
|
* Thomas-Sonderlösung.
|
|
*
|
|
* Damit der Chatkopf überhaupt wegscrollen kann, scrollt der äussere Bereich
|
|
* als Ganzes. Die drei Abschnitte behalten darunter ihre eigene Höhe und ihren
|
|
* eigenen inneren Scroll — deshalb steht die Mindesthöhe am Wrapper und nicht
|
|
* in den Abschnitten selbst.
|
|
*
|
|
* Es wird immer nur der gewählte Bereich gerendert — drei lange Abschnitte
|
|
* untereinander wären nicht dasselbe in kürzer, sondern etwas anderes. Die
|
|
* Wahl liegt in `?section=`, damit der Browser-Zurück-Knopf sie kennt.
|
|
*/
|
|
export default function MeineAgenten() {
|
|
const [params, setParams] = useSearchParams()
|
|
const section = resolveSection(params.get(AGENT_SECTION_PARAM))
|
|
|
|
// Bereichswechsel verwirft die Parameter des vorigen Bereichs — ein `tab` aus
|
|
// dem Bearbeitungsverlauf hiesse in der Personalverwaltung etwas anderes.
|
|
const handleChange = useCallback(
|
|
(next: AgentSection) => setParams({ [AGENT_SECTION_PARAM]: next }),
|
|
[setParams],
|
|
)
|
|
|
|
return (
|
|
<Box sx={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
|
|
<Box sx={{ flex: 1, overflowY: 'auto', display: 'flex', flexDirection: 'column' }}>
|
|
<AgentWorkspaceHero
|
|
agentId={AGENT_SUPERVISOR.id}
|
|
name={AGENT_SUPERVISOR.name}
|
|
role={AGENT_SUPERVISOR.role}
|
|
/>
|
|
|
|
<TeamPageHeader
|
|
title={MY_AGENTS_LABEL}
|
|
description={THOMAS_INTRO}
|
|
tabs={<AgentWorkspaceTabs value={section} onChange={handleChange} />}
|
|
/>
|
|
|
|
{/*
|
|
Die Mindesthöhe ist kein Gestaltungsmass, sondern die Bedingung dafür,
|
|
dass der Chatkopf überhaupt wegscrollen kann: Er misst rund 400 Pixel,
|
|
und erst wenn der Inhalt darunter mindestens eine Bildschirmhöhe
|
|
einnimmt, entsteht genug Scrollweg, damit er unter den obersten Balken
|
|
rutscht und `AgentChatStickyBar` übernimmt. Bei den anderen Agenten
|
|
leistet das die lange Liste; hier hat der Abschnitt seine eigene Höhe
|
|
und scrollt innen, also muss die Bedingung ausdrücklich stehen.
|
|
*/}
|
|
<Box sx={{ display: 'flex', flexDirection: 'column', minHeight: `calc(100vh - ${TOP_BAR_PX}px)` }}>
|
|
{section === AGENT_SECTIONS.PERSONNEL && <PersonnelSection />}
|
|
{section === AGENT_SECTIONS.HISTORY && <HistorySection />}
|
|
{section === AGENT_SECTIONS.CHANNELS && <ChannelsSection />}
|
|
</Box>
|
|
</Box>
|
|
</Box>
|
|
)
|
|
}
|