Dashboard Verbessert

This commit is contained in:
Moritz Utcke
2024-02-25 12:30:30 +07:00
parent 1bfd491f97
commit 23c480dae1
7 changed files with 116 additions and 20 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -46,9 +46,13 @@
</script>
<div class="card lg:card-side bg-base-200 card-bordered border-base-300">
<div class="absolute top-0 left-0 w-full h-full bg-[rgba(0,0,0,0.7)] z-10 rounded-lg select-none">
<!--
TODO: Storniert Feld hinzufügen
{#if ausweis.storniert}
<div class="absolute top-0 left-0 w-full h-full bg-[rgba(0,0,0,0.7)] z-[5] rounded-lg select-none">
<h1 class="absolute -rotate-[25deg] text-7xl tracking-wide uppercase text-red-500 border-4 border-red-500 rounded-lg top-[50%] translate-y-[-50%] left-[50%] translate-x-[-50%]">Storniert</h1>
</div>
{/if} -->
<figure class="lg:w-1/2">
<img
src={(ausweis.gebaeude_aufnahme_allgemein.gebaeude_stammdaten.gebaeude_bilder && ausweis.gebaeude_aufnahme_allgemein.gebaeude_stammdaten.gebaeude_bilder[0]?.url) || "/images/placeholder.jpg"}

View File

@@ -8,8 +8,10 @@
import { addNotification } from "#components/NotificationProvider/shared";
import { notifications } from "#components/NotificationProvider/shared";
import ThemeController from "#components/ThemeController.svelte";
import { BenutzerClient } from "#components/Ausweis/types";
export let lightTheme: boolean;
export let benutzer: BenutzerClient;
const rippleOptions: RippleOptions = {
center: false,
@@ -66,6 +68,7 @@
</li>
</ul>
</details></li>
{#if benutzer.rolle === "ADMIN"}
<li><details>
<summary class="button-tab w-full outline-0 hover:outline-0">
<LockClosed width={22} height={22} />
@@ -88,6 +91,7 @@
</li>
</ul>
</details></li>
{/if}
</div>
<div class="mt-auto flex flex-col gap-4 px-8">
<div class="flex flex-row justify-between items-center">
@@ -114,24 +118,25 @@
</div>
</div>
<div class="divider px-8"></div>
<button
<a
href="/dashboard/einstellungen"
use:ripple={rippleOptions}
class="btn btn-ghost no-animation focus:shadow-none justify-start py-4 h-auto hover:bg-base-200 px-8 rounded-none w-full flex flex-row gap-4"
>
<div class="avatar">
<div class="w-12 rounded-full">
<img
src="https://daisyui.com/images/stock/photo-1534528741775-53994a69daeb.jpg"
src={benutzer.profilbild || "/images/profile-placeholder.png"}
/>
</div>
</div>
<div class="flex flex-col gap-2">
<span class="text-base-content font-semibold"
>Gertrude McKenzie</span
<span class="text-base-content font-semibold text-left"
>{benutzer.vorname} {benutzer.name}</span
>
<span class="text-base-content">uve@rehkenban.bo</span>
<span class="text-base-content">{benutzer.email}</span>
</div>
</button>
</a>
</aside>
<!--<header class="md:hidden flex flex-row justify-between items-center px-8 sticky top-0 z-50 h-20 bg-base-100 border-b border-b-base-300">

View File

@@ -6,7 +6,20 @@ import "../../svelte-dialogs.config"
import "svelte-ripple-action/ripple.css"
import DashboardSidebar from "../components/Dashboard/DashboardSidebar.svelte"
import { NotificationWrapper } from "@ibcornelsen/ui";
import { validateAccessTokenServer } from "src/server/lib/validateAccessToken";
import { prisma } from "@ibcornelsen/database/server";
import { createCaller } from "#lib/caller";
const valid = validateAccessTokenServer(Astro)
if (!valid) {
Astro.redirect("/auth/login", 302)
}
const caller = createCaller(Astro)
const benutzer = await caller.v1.benutzer.self()
export interface Props {
title: string;
@@ -91,7 +104,7 @@ let lightTheme = Astro.cookies.get("theme").value === "light";
</head>
<body class="min-h-screen grid md:grid-cols-[300px_1fr]">
<DashboardSidebar lightTheme={lightTheme} client:load></DashboardSidebar>
<DashboardSidebar lightTheme={lightTheme} benutzer={benutzer} client:load></DashboardSidebar>
<main class="p-8 overflow-auto h-screen bg-base-100">
<slot />
</main>

View File

@@ -7,14 +7,57 @@
} from "radix-svelte-icons";
import { Tabs, Tab, TabList, TabPanel } from "../../components/Tabs";
import { dialogs } from "../../../svelte-dialogs.config";
import { BenutzerClient } from "#components/Ausweis/types";
import { client } from "src/trpc";
import { exclude } from "#lib/exclude";
function profilSpeichern() {
dialogs.confirm({
export let benutzer: BenutzerClient;
let passwort: string | undefined = undefined;
let passwortVerify: string | undefined = undefined;
async function profilSpeichern(e: SubmitEvent) {
e.preventDefault()
if (!passwort) {
passwort = undefined
} else {
if (passwort.length < 8) {
dialogs.alert({
title: "Passwort zu kurz",
text: "Das Passwort muss mindestens 8 Zeichen lang sein.",
})
return
} else if (passwort !== passwortVerify) {
dialogs.alert({
title: "Passwörter stimmen nicht überein",
text: "Die eingegebenen Passwörter stimmen nicht überein.",
})
return
}
}
const response = await dialogs.confirm({
title: "Profil speichern",
text: "Möchtest du deine Änderungen speichern?",
confirmButtonText: "Speichern",
declineButtonText: "Abbrechen",
})
if (!response) return;
const benutzerObjekt = exclude({
...benutzer,
passwort
}, ["rolle"])
// Wir wollen die Rolle nicht mit übertragen.
// Diese wird zwar sowieso rausgeschmissen aber sonst kommen wir nicht durch die Validation durch...
await client.v1.benutzer.update.mutate(benutzerObjekt)
dialogs.success({
title: "Profil gespeichert",
text: "Deine Änderungen wurden erfolgreich gespeichert.",
dismissButtonClass: "btn btn-success"
})
}
</script>
@@ -62,34 +105,51 @@
>
<TabPanel>
<h2 class="text-2xl font-medium">Profil</h2>
<div class="flex flex-col gap-4 my-4 max-w-2xl">
<form class="flex flex-col gap-4 my-4 max-w-2xl" on:submit={profilSpeichern}>
<div class="flex flex-row gap-4">
<div class="flex flex-col">
<span class="whitespace-nowrap">Vorname</span>
<input type="password" class="input text-base-content font-medium" placeholder="Max">
<input type="text" class="input text-base-content font-medium" placeholder="Max" bind:value={benutzer.vorname}>
</div>
<div class="flex flex-col">
<span class="whitespace-nowrap">Nachname</span>
<input type="password" class="input text-base-content font-medium" placeholder="Müller">
<input type="text" class="input text-base-content font-medium" placeholder="Müller" bind:value={benutzer.name}>
</div>
</div>
<div class="flex flex-col">
<span class="whitespace-nowrap">Email Adresse</span>
<input type="text" class="input text-base-content font-medium" placeholder="name@email.com" value="zobhusdi@wo.tk">
<input type="email" class="input text-base-content font-medium" placeholder="name@email.com" bind:value={benutzer.email}>
</div>
<div class="flex flex-col">
<span class="whitespace-nowrap">Telefonnummer</span>
<input type="phone" class="input text-base-content font-medium" placeholder="040 12345678" bind:value={benutzer.telefon}>
</div>
<div class="flex flex-row gap-4">
<div class="flex flex-col">
<span class="whitespace-nowrap">Adresse</span>
<input type="text" class="input text-base-content font-medium" placeholder="Musterstraße 123" bind:value={benutzer.adresse}>
</div>
<div class="flex flex-col">
<span class="whitespace-nowrap">PLZ</span>
<input type="text" class="input text-base-content font-medium" placeholder="12345" bind:value={benutzer.plz}>
</div>
<div class="flex flex-col">
<span class="whitespace-nowrap">Ort</span>
<input type="text" class="input text-base-content font-medium" placeholder="Musterhausen" bind:value={benutzer.ort}>
</div>
</div>
<div class="flex flex-row gap-4">
<div class="flex flex-col">
<span class="whitespace-nowrap">Passwort</span>
<input type="password" class="input text-base-content font-medium" placeholder="*********">
<input type="password" class="input text-base-content font-medium" placeholder="*********" bind:value={passwort}>
</div>
<div class="flex flex-col">
<span class="whitespace-nowrap">Passwort bestätigen</span>
<input type="password" class="input text-base-content font-medium" placeholder="*********">
<input type="password" class="input text-base-content font-medium" placeholder="*********" bind:value={passwortVerify}>
</div>
</div>
</div>
<button class="btn btn-primary" on:click={profilSpeichern}>Speichern</button>
<button class="btn btn-primary" type="submit">Speichern</button>
</form>
</TabPanel>
<TabPanel>
<h1>Panel Two</h1>

View File

@@ -1,10 +1,20 @@
---
import UserLayout from "#layouts/UserLayout.astro";
import { createCaller } from "#lib/caller";
import DashboardEinstellungenModule from "#modules/Dashboard/DashboardEinstellungenModule.svelte";
import { validateAccessTokenServer } from "src/server/lib/validateAccessToken";
const valid = await validateAccessTokenServer(Astro);
if (!valid) {
return Astro.redirect("/auth/login", 302);
}
const caller = createCaller(Astro);
const benutzer = await caller.v1.benutzer.self();
---
<UserLayout title="Einstellungen">
<DashboardEinstellungenModule client:load />
<DashboardEinstellungenModule benutzer={benutzer} client:load />
</UserLayout>

View File

@@ -9,6 +9,10 @@ dialogs.config({
titleClass: "text-base-content text-xl font-medium",
dividerClass: "hidden",
footerClass: "bg-base-100 justify-center gap-4 mt-4",
closeButtonClass: "btn btn-primary",
closeButtonText: "Schließen",
dismissButtonClass: "btn btn-primary",
dismissButtonText: "Schließen",
closeOnBg: true,
closeOnEsc: true
}