"use client"; import { useState, type FormEvent } from "react"; import Link from "next/link"; import { TextField } from "@nexarch/shl"; import { search, ApiError, type SearchHit } from "../lib/api"; import { splitHighlighted } from "../lib/highlight"; import { HIGHLIGHT_BG_LIGHT, HIGHLIGHT_FG_LIGHT } from "../lib/highlightColors"; function tenantSlug(): string { return process.env.NEXT_PUBLIC_MAIL_TENANT_SLUG ?? ""; } function Snippet({ text }: { text: string }) { if (!text) { return null; } return ( {splitHighlighted(text).map((segment, idx) => segment.matched ? ( {segment.text} ) : ( {segment.text} ) )} ); } function resultHref(hit: SearchHit): string { const params = new URLSearchParams({ subject: hit.subjectSnippet, snippet: hit.bodySnippet, }); return `/mail/${encodeURIComponent(hit.messageId)}?${params.toString()}#fundstelle`; } export default function SearchPage() { const [query, setQuery] = useState(""); const [hits, setHits] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); async function runSearch(e?: FormEvent) { e?.preventDefault(); if (!query.trim()) { setHits(null); setError(null); return; } setLoading(true); setError(null); try { const result = await search(tenantSlug(), query); setHits(result.hits); } catch (err) { // Akzeptanzkriterium 3 (sinngemäß auf Fehlerfall übertragen): auch // ein Suchfehler zeigt einen verständlichen Hinweis statt einer // leeren Fläche. setHits([]); setError(err instanceof ApiError ? err.message : "Suche konnte nicht ausgeführt werden."); } finally { setLoading(false); } } return (

Mail-Suche

setQuery(e.target.value)} placeholder='z. B. "Quartalsbericht" oder Umsatz -Verlust' /> {error && (

{error}

)} {hits !== null && hits.length === 0 && !error && (

Keine Treffer für diese Suchanfrage.

)} {hits !== null && hits.length > 0 && (
    {hits.map((hit) => (
  • ))}
)}
); }