feat(aufgaben): Inbox, Aufgabenliste, Ideen und Projekte
Die Schnellerfassung braucht ein Feld und einen Knopf; wer beim Erfassen erst ein Formular ausfüllen muss, erfasst nichts. Der Fokus bleibt danach im Feld, damit mehrere Sachen hintereinander hineingehen. Die Filter der Aufgabenliste stehen in der Adresse, nicht im Zustand der Komponente — so lässt sich eine gefilterte Liste als Lesezeichen ablegen, und der Zurück-Knopf tut, was er soll. Die Startseite zeigt jetzt, was überfällig, heute oder morgen fällig ist, statt nur die Bereiche aufzuzählen. Für die Auswahlfelder bewusst das native <select>: es bedient sich auf dem Handy mit dem Systemdialog und ist ohne Zusatzcode tastaturbedienbar. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b3ca1c9ce7
commit
a4a889fcb8
+112
-35
@@ -1,4 +1,6 @@
|
||||
import Link from 'next/link'
|
||||
import { AufgabenListe } from '@/components/aufgaben/aufgaben-liste'
|
||||
import { Schnellerfassung } from '@/components/aufgaben/schnellerfassung'
|
||||
import {
|
||||
Card,
|
||||
CardBeschreibung,
|
||||
@@ -8,6 +10,12 @@ import {
|
||||
} from '@/components/ui/card'
|
||||
import { wochenKapazitaet } from '@/lib/bereich'
|
||||
import { alsDatum, alsDauer } from '@/lib/zeit'
|
||||
import {
|
||||
aufgabenLaden,
|
||||
bereicheLaden,
|
||||
projekteZurAuswahlLaden,
|
||||
zaehlstaende,
|
||||
} from '@/server/abfragen/aufgaben'
|
||||
import { verlangeAnmeldung } from '@/server/berechtigung'
|
||||
import { db } from '@/server/db'
|
||||
import { jetzt } from '@/server/zeitgeber'
|
||||
@@ -16,10 +24,23 @@ export default async function StartSeite() {
|
||||
const benutzer = await verlangeAnmeldung('/')
|
||||
const heute = jetzt()
|
||||
|
||||
const bereiche = await db.bereich.findMany({
|
||||
where: { aktiv: true },
|
||||
orderBy: [{ reihenfolge: 'asc' }, { name: 'asc' }],
|
||||
})
|
||||
const [alleOffenen, bereiche, projekte, zahlen, bereichsListe] = await Promise.all([
|
||||
aufgabenLaden({ nurOffen: true }, 200),
|
||||
bereicheLaden(),
|
||||
projekteZurAuswahlLaden(),
|
||||
zaehlstaende(),
|
||||
db.bereich.findMany({
|
||||
where: { aktiv: true },
|
||||
orderBy: [{ reihenfolge: 'asc' }, { name: 'asc' }],
|
||||
}),
|
||||
])
|
||||
|
||||
// Was jetzt zählt: überfällig, heute oder morgen fällig. Ideen bleiben draußen.
|
||||
const dran = alleOffenen.filter(
|
||||
(a) =>
|
||||
a.typ !== 'IDEE' &&
|
||||
(a.ueberfaellig || a.faelligkeit === 'heute' || a.faelligkeit === 'morgen'),
|
||||
)
|
||||
|
||||
const anrede = benutzer.name?.split(' ')[0] ?? benutzer.email
|
||||
|
||||
@@ -30,10 +51,53 @@ export default async function StartSeite() {
|
||||
<p className="text-gedaempft-vordergrund mt-1 text-sm">{alsDatum(heute)}</p>
|
||||
</header>
|
||||
|
||||
<section className="flex flex-col gap-4">
|
||||
<h2 className="text-lg font-medium">Deine Bereiche</h2>
|
||||
<Card>
|
||||
<CardKopf>
|
||||
<CardTitel className="text-base">Schnell erfassen</CardTitel>
|
||||
<CardBeschreibung>
|
||||
Landet in der{' '}
|
||||
<Link href="/inbox" className="text-betont underline underline-offset-4">
|
||||
Inbox
|
||||
</Link>{' '}
|
||||
und wird später einsortiert.
|
||||
</CardBeschreibung>
|
||||
</CardKopf>
|
||||
<CardInhalt>
|
||||
<Schnellerfassung />
|
||||
</CardInhalt>
|
||||
</Card>
|
||||
|
||||
{bereiche.length === 0 ? (
|
||||
<section className="flex flex-col gap-3">
|
||||
<div className="flex flex-wrap items-baseline justify-between gap-2">
|
||||
<h2 className="text-lg font-medium">Jetzt dran</h2>
|
||||
<Link
|
||||
href="/aufgaben"
|
||||
className="text-gedaempft-vordergrund hover:text-vordergrund text-sm"
|
||||
>
|
||||
Alle {zahlen.offen} offenen Aufgaben
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<AufgabenListe
|
||||
aufgaben={dran}
|
||||
bereiche={bereiche}
|
||||
projekte={projekte}
|
||||
leerText="Nichts überfällig, nichts heute fällig. Ein guter Tag."
|
||||
/>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<div className="flex flex-wrap items-baseline justify-between gap-2">
|
||||
<h2 className="text-lg font-medium">Deine Bereiche</h2>
|
||||
<Link
|
||||
href="/bereiche"
|
||||
className="text-gedaempft-vordergrund hover:text-vordergrund text-sm"
|
||||
>
|
||||
Bereiche verwalten
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{bereichsListe.length === 0 ? (
|
||||
<Card>
|
||||
<CardInhalt className="text-gedaempft-vordergrund py-8 text-center text-sm">
|
||||
Noch keine Bereiche angelegt.{' '}
|
||||
@@ -44,38 +108,51 @@ export default async function StartSeite() {
|
||||
</Card>
|
||||
) : (
|
||||
<ul className="grid gap-4 sm:grid-cols-2">
|
||||
{bereiche.map((bereich) => (
|
||||
<li key={bereich.id}>
|
||||
<Card>
|
||||
<CardKopf className="flex-row items-center gap-3">
|
||||
<span
|
||||
aria-hidden
|
||||
className="size-3 shrink-0 rounded-full ring-1 ring-black/10"
|
||||
style={{ backgroundColor: bereich.farbe }}
|
||||
/>
|
||||
<CardTitel className="text-base">{bereich.name}</CardTitel>
|
||||
</CardKopf>
|
||||
<CardInhalt>
|
||||
<p className="text-gedaempft-vordergrund text-sm">
|
||||
{alsDauer(wochenKapazitaet(bereich))} in der Woche eingeplant
|
||||
</p>
|
||||
</CardInhalt>
|
||||
</Card>
|
||||
</li>
|
||||
))}
|
||||
{bereichsListe.map((bereich) => {
|
||||
const offeneHier = alleOffenen.filter(
|
||||
(a) => a.bereich?.id === bereich.id && a.typ !== 'IDEE',
|
||||
)
|
||||
return (
|
||||
<li key={bereich.id}>
|
||||
<Card>
|
||||
<CardKopf className="flex-row items-center gap-3">
|
||||
<span
|
||||
aria-hidden
|
||||
className="size-3 shrink-0 rounded-full ring-1 ring-black/10"
|
||||
style={{ backgroundColor: bereich.farbe }}
|
||||
/>
|
||||
<CardTitel className="text-base">{bereich.name}</CardTitel>
|
||||
</CardKopf>
|
||||
<CardInhalt>
|
||||
<p className="text-gedaempft-vordergrund text-sm">
|
||||
{offeneHier.length === 0
|
||||
? 'Nichts offen'
|
||||
: `${offeneHier.length} offen`}{' '}
|
||||
· {alsDauer(wochenKapazitaet(bereich))} Kapazität je Woche
|
||||
</p>
|
||||
</CardInhalt>
|
||||
</Card>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
)}
|
||||
</section>
|
||||
|
||||
<Card>
|
||||
<CardKopf>
|
||||
<CardTitel className="text-base">Was als Nächstes kommt</CardTitel>
|
||||
<CardBeschreibung>
|
||||
Aufgaben und Ideen folgen mit M2, das Lesen der Kalender mit M3, die
|
||||
Wochenplanung per Ziehen und Ablegen mit M4.
|
||||
</CardBeschreibung>
|
||||
</CardKopf>
|
||||
</Card>
|
||||
{zahlen.ideen > 0 && (
|
||||
<Card>
|
||||
<CardKopf>
|
||||
<CardTitel className="text-base">
|
||||
<Link href="/ideen" className="hover:underline hover:underline-offset-4">
|
||||
{zahlen.ideen} Idee(n) warten
|
||||
</Link>
|
||||
</CardTitel>
|
||||
<CardBeschreibung>
|
||||
Ideen drängen sich nicht in die Aufgabenliste — bis du eine übernimmst.
|
||||
</CardBeschreibung>
|
||||
</CardKopf>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user