Eine Seite zeigt je Integration, ob sie vorgesehen, eingerichtet oder gestoert ist, wann sie zuletzt geglueckt ist und woran sie klemmt. Der Wartungsplaner steht sichtbar als offene Luecke darin, nicht als Leerstelle. Telegram-Chats werden hier gekoppelt und wieder getrennt, Meldungen je Chat einzeln geschaltet. Aufgaben bekommen einen Schalter zum Spiegeln — einzeln und je Aufgabe, denn wer versehentlich einen ganzen Bereich spiegelt, schickt Kundennamen nach Hause. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
149 lines
4.9 KiB
TypeScript
149 lines
4.9 KiB
TypeScript
import type { Metadata } from 'next'
|
||
import { Benachrichtigungen } from '@/app/(app)/einstellungen/benachrichtigungen'
|
||
import { PasskeyVerwaltung } from '@/app/(app)/einstellungen/passkey-verwaltung'
|
||
import {
|
||
Card,
|
||
CardBeschreibung,
|
||
CardInhalt,
|
||
CardKopf,
|
||
CardTitel,
|
||
} from '@/components/ui/card'
|
||
import { ROLLEN_NAME } from '@/lib/rollen'
|
||
import { alsEinstellung } from '@/server/benachrichtigung/versand'
|
||
import { alsUhrzeit } from '@/lib/zeit'
|
||
import { umgebung } from '@/server/umgebung'
|
||
import { alsDatumUhrzeit } from '@/lib/zeit'
|
||
import { verlangeAnmeldung } from '@/server/berechtigung'
|
||
import { db } from '@/server/db'
|
||
|
||
export const metadata: Metadata = { title: 'Einstellungen' }
|
||
|
||
export default async function EinstellungenSeite() {
|
||
const benutzer = await verlangeAnmeldung('/einstellungen')
|
||
|
||
const einst = umgebung()
|
||
|
||
const [benachrichtigung, telegramChats, pushGeraete] = await Promise.all([
|
||
db.benachrichtigungseinstellung.findUnique({
|
||
where: { benutzerId: benutzer.id },
|
||
select: {
|
||
anlaesse: true,
|
||
perPush: true,
|
||
perMail: true,
|
||
perTelegram: true,
|
||
ueberblickUm: true,
|
||
ruheVon: true,
|
||
ruheBis: true,
|
||
ruheAmWochenende: true,
|
||
zeitblockVorlaufMinuten: true,
|
||
},
|
||
}),
|
||
db.telegramChat.count({ where: { benutzerId: benutzer.id, meldungen: true } }),
|
||
db.pushGeraet.findMany({
|
||
where: { benutzerId: benutzer.id },
|
||
orderBy: { erstelltAm: 'asc' },
|
||
select: {
|
||
id: true,
|
||
bezeichnung: true,
|
||
erstelltAm: true,
|
||
zuletztBenutzt: true,
|
||
},
|
||
}),
|
||
])
|
||
const einstellung = alsEinstellung(benachrichtigung)
|
||
|
||
const passkeys = await db.passkey.findMany({
|
||
where: { benutzerId: benutzer.id },
|
||
orderBy: { erstelltAm: 'asc' },
|
||
select: {
|
||
id: true,
|
||
bezeichnung: true,
|
||
erstelltAm: true,
|
||
zuletztBenutzt: true,
|
||
gesichert: true,
|
||
},
|
||
})
|
||
|
||
return (
|
||
<div className="flex flex-col gap-8">
|
||
<header>
|
||
<h1 className="text-2xl font-semibold tracking-tight">Einstellungen</h1>
|
||
</header>
|
||
|
||
<Card>
|
||
<CardKopf>
|
||
<CardTitel className="text-base">Konto</CardTitel>
|
||
</CardKopf>
|
||
<CardInhalt>
|
||
<dl className="grid gap-2 text-sm sm:grid-cols-[10rem_1fr]">
|
||
<dt className="text-gedaempft-vordergrund">Name</dt>
|
||
<dd>{benutzer.name ?? '—'}</dd>
|
||
<dt className="text-gedaempft-vordergrund">E-Mail</dt>
|
||
<dd>{benutzer.email}</dd>
|
||
<dt className="text-gedaempft-vordergrund">Rolle</dt>
|
||
<dd>{ROLLEN_NAME[benutzer.rolle]}</dd>
|
||
</dl>
|
||
</CardInhalt>
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardKopf>
|
||
<CardTitel className="text-base">Passkeys</CardTitel>
|
||
<CardBeschreibung>
|
||
Mit einem Passkey meldest du dich per Fingerabdruck, Gesicht oder Geräte-PIN
|
||
an – ohne Passwort. Hinterlege am besten zwei, damit du bei Verlust eines
|
||
Geräts nicht ausgesperrt bist.
|
||
</CardBeschreibung>
|
||
</CardKopf>
|
||
<CardInhalt>
|
||
<PasskeyVerwaltung
|
||
passkeys={passkeys.map((p) => ({
|
||
id: p.id,
|
||
bezeichnung: p.bezeichnung,
|
||
erstelltAm: alsDatumUhrzeit(p.erstelltAm),
|
||
zuletztBenutzt: p.zuletztBenutzt ? alsDatumUhrzeit(p.zuletztBenutzt) : null,
|
||
gesichert: p.gesichert,
|
||
}))}
|
||
/>
|
||
</CardInhalt>
|
||
</Card>
|
||
|
||
<Card data-bild="benachrichtigungen">
|
||
<CardKopf>
|
||
<CardTitel className="text-base">Benachrichtigungen</CardTitel>
|
||
<CardBeschreibung>
|
||
Ab Werk meldet der Planer gar nichts. Was du hier einschaltest, kommt — alles
|
||
andere nicht. Eine Anwendung, die zu oft meldet, wird stummgeschaltet und ist
|
||
dann wertlos.
|
||
</CardBeschreibung>
|
||
</CardKopf>
|
||
<CardInhalt>
|
||
<Benachrichtigungen
|
||
pushMoeglich={einst.pushAktiv}
|
||
mailMoeglich={einst.mailAktiv}
|
||
telegramMoeglich={einst.telegramAktiv}
|
||
telegramChats={telegramChats}
|
||
einstellung={{
|
||
anlaesse: [...einstellung.anlaesse],
|
||
perPush: einstellung.perPush,
|
||
perMail: einstellung.perMail,
|
||
perTelegram: einstellung.perTelegram,
|
||
ueberblickUm: alsUhrzeit(einstellung.ueberblickUm),
|
||
ruheVon: alsUhrzeit(einstellung.ruheVon),
|
||
ruheBis: alsUhrzeit(einstellung.ruheBis),
|
||
ruheAmWochenende: einstellung.ruheAmWochenende,
|
||
zeitblockVorlaufMinuten: einstellung.zeitblockVorlaufMinuten,
|
||
}}
|
||
geraete={pushGeraete.map((g) => ({
|
||
id: g.id,
|
||
bezeichnung: g.bezeichnung,
|
||
erstelltAm: alsDatumUhrzeit(g.erstelltAm),
|
||
zuletztBenutzt: g.zuletztBenutzt ? alsDatumUhrzeit(g.zuletztBenutzt) : null,
|
||
}))}
|
||
/>
|
||
</CardInhalt>
|
||
</Card>
|
||
</div>
|
||
)
|
||
}
|