Ausschliesslich Zeilenenden. Nachgewiesen mit "git diff --cached --ignore-cr-at-eol": Der Diff ist leer, es hat sich kein Zeichen Inhalt geaendert. Deshalb ein eigener Commit: 7448 geaenderte Zeilen in einem Commit mit echten Aenderungen zu verstecken, macht die Historie an dieser Stelle unlesbar. So laesst er sich beim Durchsehen ueberspringen. Refs #26
164 lines
5.8 KiB
TypeScript
164 lines
5.8 KiB
TypeScript
import Link from 'next/link'
|
||
import {
|
||
Archive,
|
||
CalendarClock,
|
||
FolderArchive,
|
||
Paperclip,
|
||
ScrollText,
|
||
} from 'lucide-react'
|
||
import { SeitenKopf } from '@/components/seiten-kopf'
|
||
import { Rechtshinweis } from '@/components/rechtshinweis'
|
||
import { Badge } from '@/components/ui/badge'
|
||
import { Card, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||
import { BerichtsListe } from '@/components/berichte/berichts-liste'
|
||
import { berichtskontext, berichtsZeilenLaden } from '@/components/berichte/kontext'
|
||
import { HinweisKarten } from '@/components/hinweise/HinweisKarten'
|
||
import { db, nichtGeloescht } from '@/lib/db'
|
||
import { formatDatum, relativeTage, tageBis } from '@/lib/utils'
|
||
|
||
export const metadata = { title: 'Berichte' }
|
||
|
||
/** Fristen, hinter denen ein Bericht steht - danach sucht die Übersicht. */
|
||
const BERICHTSFRISTEN = [
|
||
'anfangsbericht',
|
||
'jahresbericht',
|
||
'vermoegensverzeichnis',
|
||
'vermoegensuebersicht',
|
||
'rechnungslegung',
|
||
]
|
||
|
||
const WEGE = [
|
||
{
|
||
href: '/berichte/jahresbericht',
|
||
titel: 'Jahresbericht',
|
||
beschreibung:
|
||
'Textentwurf aus Kontaktprotokollen, Gesundheitsereignissen und Vorgängen – zum Überarbeiten, nicht zum blinden Abgeben.',
|
||
icon: ScrollText,
|
||
},
|
||
{
|
||
href: '/berichte/belegmappe',
|
||
titel: 'Belegmappe',
|
||
beschreibung:
|
||
'Alle Belege eines Zeitraums oder eines Vorgangs als ein PDF mit Deckblatt und Verzeichnis.',
|
||
icon: FolderArchive,
|
||
},
|
||
{
|
||
href: '/berichte/unterlagenpaket',
|
||
titel: 'Unterlagen für den Träger',
|
||
beschreibung:
|
||
'Die nachgeforderten Unterlagen als ein PDF mit Anschreiben, laufender Nummer und Inhaltsverzeichnis.',
|
||
icon: Paperclip,
|
||
},
|
||
{
|
||
href: '/berichte/export',
|
||
titel: 'Vollexport',
|
||
beschreibung:
|
||
'Alles, was gespeichert ist, als ZIP – damit du auch ohne diese Anwendung weiterarbeiten kannst.',
|
||
icon: Archive,
|
||
},
|
||
]
|
||
|
||
/**
|
||
* Die Berichtsuebersicht beantwortet zwei Fragen:
|
||
* "Was ist demnaechst faellig?" und "Was habe ich wann abgegeben?".
|
||
*
|
||
* Die erste Frage kommt aus den Fristen - dort stehen die gesetzlichen
|
||
* Pflichten mit Datum. Die zweite aus den protokollierten Berichten.
|
||
*/
|
||
export default async function BerichteSeite() {
|
||
const { betreuteId, darfBerichteSchreiben } = await berichtskontext('lesen')
|
||
|
||
const [fristen, zeilen] = await Promise.all([
|
||
db.frist.findMany({
|
||
where: {
|
||
betreuteId,
|
||
status: 'OFFEN',
|
||
...nichtGeloescht,
|
||
OR: BERICHTSFRISTEN.map((schluessel) => ({
|
||
systemSchluessel: { startsWith: schluessel },
|
||
})),
|
||
},
|
||
orderBy: { datum: 'asc' },
|
||
take: 10,
|
||
}),
|
||
berichtsZeilenLaden(betreuteId, darfBerichteSchreiben),
|
||
])
|
||
|
||
return (
|
||
<div className="space-y-8">
|
||
<SeitenKopf
|
||
titel="Berichte"
|
||
pfad={[{ titel: 'Berichte' }]}
|
||
beschreibung="Was das Betreuungsgericht und der Sozialhilfeträger von dir sehen wollen – und was du ihnen wann vorgelegt hast."
|
||
/>
|
||
|
||
<section className="space-y-3" aria-label="Demnächst fällig">
|
||
<h2 className="text-base font-semibold">Demnächst fällig</h2>
|
||
{fristen.length === 0 ? (
|
||
<p className="text-sm text-muted-foreground">
|
||
Zurzeit steht keine Berichtsfrist offen. Prüfe unter{' '}
|
||
<Link href="/fristen" className="underline underline-offset-4">
|
||
Fristen
|
||
</Link>
|
||
, ob die Pflichtfristen aus dem Bestellungsdatum schon abgeleitet sind.
|
||
</p>
|
||
) : (
|
||
<ul className="divide-y rounded-md border">
|
||
{fristen.map((frist) => {
|
||
const tage = tageBis(frist.datum)
|
||
const variante =
|
||
tage < 0 ? 'rot' : tage <= 7 ? 'orange' : tage <= 31 ? 'gelb' : 'gruen'
|
||
return (
|
||
<li key={frist.id} className="flex flex-wrap items-center gap-3 p-3">
|
||
<CalendarClock className="size-5 shrink-0 text-muted-foreground" aria-hidden="true" />
|
||
<span className="min-w-0 flex-1">
|
||
<span className="block font-medium">{frist.titel}</span>
|
||
<span className="text-sm text-muted-foreground">
|
||
{formatDatum(frist.datum)}
|
||
{frist.rechtsgrundlage ? ` · ${frist.rechtsgrundlage}` : ''}
|
||
</span>
|
||
</span>
|
||
{frist.ausschlussfrist && <Badge variant="rot">Ausschlussfrist</Badge>}
|
||
<Badge variant={variante}>
|
||
{tage < 0 ? `überfällig, ${relativeTage(tage)}` : relativeTage(tage)}
|
||
</Badge>
|
||
</li>
|
||
)
|
||
})}
|
||
</ul>
|
||
)}
|
||
</section>
|
||
|
||
<section className="grid gap-4 md:grid-cols-2" aria-label="Was möchtest du erzeugen?">
|
||
{WEGE.map((weg) => {
|
||
const Icon = weg.icon
|
||
return (
|
||
<Card key={weg.href}>
|
||
<CardHeader className="flex flex-row items-start gap-3 space-y-0">
|
||
<Icon className="mt-0.5 size-5 shrink-0 text-primary" aria-hidden="true" />
|
||
<div className="min-w-0">
|
||
<CardTitle className="text-lg">
|
||
<Link href={weg.href} className="underline-offset-4 hover:underline">
|
||
{weg.titel}
|
||
</Link>
|
||
</CardTitle>
|
||
<CardDescription className="mt-1">{weg.beschreibung}</CardDescription>
|
||
</div>
|
||
</CardHeader>
|
||
</Card>
|
||
)
|
||
})}
|
||
</section>
|
||
|
||
<section className="space-y-3" aria-label="Erzeugte Berichte">
|
||
<h2 className="text-base font-semibold">Was ich abgegeben habe</h2>
|
||
<BerichtsListe zeilen={zeilen} darfSchreiben={darfBerichteSchreiben} />
|
||
</section>
|
||
|
||
<HinweisKarten kontext={['BERICHTE']} />
|
||
|
||
<Rechtshinweis rechtsgrundlage="§ 1863 BGB" />
|
||
</div>
|
||
)
|
||
}
|