Files
property-match/src/pages/supply/MeineAgenten.tsx
T
Benjamin SutterandClaude Opus 5 f5451f649f fix(agenten): Thomas' Chat klappt wirklich ein, Einzahl bei Livias Zählung
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>
2026-08-23 22:22:01 +02:00

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>
)
}