This commit is contained in:
Moritz Utcke
2025-03-05 13:11:39 -03:00
parent d7f57a4d04
commit 9b33755cdd
18 changed files with 261 additions and 114 deletions

View File

@@ -5,6 +5,7 @@ export const createCaller = createCallerFactory({
"klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"), "klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"),
"postleitzahlen": await import("../src/pages/api/postleitzahlen.ts"), "postleitzahlen": await import("../src/pages/api/postleitzahlen.ts"),
"unterlage": await import("../src/pages/api/unterlage.ts"), "unterlage": await import("../src/pages/api/unterlage.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"admin/ausstellen": await import("../src/pages/api/admin/ausstellen.ts"), "admin/ausstellen": await import("../src/pages/api/admin/ausstellen.ts"),
"admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"), "admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"),
"admin/erinnern": await import("../src/pages/api/admin/erinnern.ts"), "admin/erinnern": await import("../src/pages/api/admin/erinnern.ts"),
@@ -12,7 +13,6 @@ export const createCaller = createCallerFactory({
"admin/post-ausstellen": await import("../src/pages/api/admin/post-ausstellen.ts"), "admin/post-ausstellen": await import("../src/pages/api/admin/post-ausstellen.ts"),
"admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"), "admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"),
"admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"), "admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"), "ausweise": await import("../src/pages/api/ausweise/index.ts"),
"auth/access-token": await import("../src/pages/api/auth/access-token.ts"), "auth/access-token": await import("../src/pages/api/auth/access-token.ts"),
"auth/forgot-password": await import("../src/pages/api/auth/forgot-password.ts"), "auth/forgot-password": await import("../src/pages/api/auth/forgot-password.ts"),
@@ -30,11 +30,11 @@ export const createCaller = createCallerFactory({
"ticket": await import("../src/pages/api/ticket/index.ts"), "ticket": await import("../src/pages/api/ticket/index.ts"),
"user": await import("../src/pages/api/user/index.ts"), "user": await import("../src/pages/api/user/index.ts"),
"user/self": await import("../src/pages/api/user/self.ts"), "user/self": await import("../src/pages/api/user/self.ts"),
"verbrauchsausweis-gewerbe/[uid]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[uid].ts"), "webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
"verbrauchsausweis-wohnen/[uid]": await import("../src/pages/api/verbrauchsausweis-wohnen/[uid].ts"), "verbrauchsausweis-wohnen/[uid]": await import("../src/pages/api/verbrauchsausweis-wohnen/[uid].ts"),
"verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"), "verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"),
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"), "verbrauchsausweis-gewerbe/[uid]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[uid].ts"),
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
"aufnahme/[uid]/bilder": await import("../src/pages/api/aufnahme/[uid]/bilder.ts"), "aufnahme/[uid]/bilder": await import("../src/pages/api/aufnahme/[uid]/bilder.ts"),
"aufnahme/[uid]": await import("../src/pages/api/aufnahme/[uid]/index.ts"), "aufnahme/[uid]": await import("../src/pages/api/aufnahme/[uid]/index.ts"),
"aufnahme/[uid]/unterlagen": await import("../src/pages/api/aufnahme/[uid]/unterlagen.ts"), "aufnahme/[uid]/unterlagen": await import("../src/pages/api/aufnahme/[uid]/unterlagen.ts"),

View File

@@ -17,12 +17,18 @@
export let objekt: ObjektClient; export let objekt: ObjektClient;
export let aufnahme: AufnahmeClient; export let aufnahme: AufnahmeClient;
export let ausweisart: Enums.Ausweisart export let ausweisart: Enums.Ausweisart
export let form: HTMLFormElement;
export let showWeiter: boolean = true; export let showWeiter: boolean = true;
export let ausweistyp: AusweisTyp = Enums.AusweisTyp.Standard; export let ausweistyp: AusweisTyp = Enums.AusweisTyp.Standard;
async function ausweisAbschicken() { async function ausweisAbschicken() {
if (!form.checkValidity()) {
form.reportValidity()
return
}
openWindowWithPost("/kundendaten", { openWindowWithPost("/kundendaten", {
ausweis, ausweis,
objekt, objekt,

View File

@@ -12,7 +12,7 @@ import {
VerbrauchsausweisGewerbe, VerbrauchsausweisGewerbe,
VerbrauchsausweisWohnen, VerbrauchsausweisWohnen,
GEGNachweisWohnen, GEGNachweisWohnen,
} from "#lib/client/prisma"; } from "#lib/client/prisma.js";
import { z, ZodSchema } from "zod"; import { z, ZodSchema } from "zod";
export type OmitKeys<T, K extends keyof T> = Omit<T, K>; export type OmitKeys<T, K extends keyof T> = Omit<T, K>;
@@ -101,7 +101,7 @@ export type TicketClient = OmitKeys<Tickets, "bearbeiter_id" | "benutzer_id" | "
export type BenutzerClient = OmitKeys<Benutzer, "id" | "passwort">; export type BenutzerClient = OmitKeys<Benutzer, "id" | "passwort">;
export type RechnungClient = OmitKeys<Rechnung, "aufnahme_id" | "benutzer_id" | "id"> export type RechnungClient = OmitKeys<Rechnung, "id">
export function ZodOverlap<T, S = z.ZodType<T, z.ZodTypeDef, T>>(arg: S): S { export function ZodOverlap<T, S = z.ZodType<T, z.ZodTypeDef, T>>(arg: S): S {
return arg; return arg;

View File

@@ -1,14 +1,12 @@
<script lang="ts"> <script lang="ts">
import { ripple } from "svelte-ripple-action"; import { ripple } from "svelte-ripple-action";
import type { RippleOptions } from "svelte-ripple-action/dist/constants.js"; import type { RippleOptions } from "svelte-ripple-action/dist/constants.js";
import { Home, Reader, EnvelopeClosed, Cube, Bell, Gear, LockClosed, HamburgerMenu, CaretDown } from "radix-svelte-icons" import { Reader, Bell, Gear, LockClosed, CaretDown } from "radix-svelte-icons"
import NotificationProvider from "#components/NotificationProvider/NotificationProvider.svelte"; import NotificationProvider from "#components/NotificationProvider/NotificationProvider.svelte";
import DashboardNotification from "./DashboardNotification.svelte"; import DashboardNotification from "./DashboardNotification.svelte";
import { notifications } from "#components/NotificationProvider/shared.js"; import { notifications } from "#components/NotificationProvider/shared.js";
import ThemeController from "#components/ThemeController.svelte"; import ThemeController from "#components/ThemeController.svelte";
import { BenutzerClient } from "#components/Ausweis/types.js"; import { BenutzerClient } from "#components/Ausweis/types.js";
import Cross1 from "radix-svelte-icons/src/lib/icons/Cross1.svelte";
import { flex } from "#lib/pdf/elements/index.js";
export let lightTheme: boolean; export let lightTheme: boolean;
export let benutzer: BenutzerClient; export let benutzer: BenutzerClient;
@@ -21,7 +19,7 @@
let headerOpen = false; let headerOpen = false;
</script> </script>
<aside class:hidden={!headerOpen} class="fixed left-0 top-16 w-full h-[calc(100%-4rem)] flex z-30 md:relative md:h-auto md:w-auto md:top-0 md:flex bg-base-200 border-r border-r-base-300 flex-col py-4"> <aside class:hidden={!headerOpen} class="fixed left-0 top-16 w-full h-[calc(100%-4rem)] flex md:relative md:h-auto md:w-auto md:top-0 md:flex bg-base-200 border-r border-r-base-300 flex-col py-4">
<div class="flex flex-row items-center px-4"> <div class="flex flex-row items-center px-4">

View File

@@ -47,7 +47,7 @@
<div use:clickOutside={() => { <div use:clickOutside={() => {
hideZipDropdown = true; hideZipDropdown = true;
}}> }} class="relative">
<input <input
name={name} name={name}
@@ -55,6 +55,7 @@
type="text" type="text"
required required
readonly={readonly} readonly={readonly}
{...$$restProps}
bind:value={zip} bind:value={zip}
on:input={fetchZipCodeInformation} on:input={fetchZipCodeInformation}
on:focus={() => { on:focus={() => {

View File

@@ -1,23 +1,23 @@
export * from "./anteilshaber" export * from "./anteilshaber.js"
export * from "./apirequests" export * from "./apirequests.js"
export * from "./aufnahme" export * from "./aufnahme.js"
export * from "./bedarfsausweisgewerbe" export * from "./bedarfsausweisgewerbe.js"
export * from "./bedarfsausweiswohnen" export * from "./bedarfsausweiswohnen.js"
export * from "./benutzer" export * from "./benutzer.js"
export * from "./bild" export * from "./bild.js"
export * from "./event" export * from "./event.js"
export * from "./gegeinpreisung" export * from "./gegeinpreisung.js"
export * from "./gegnachweisgewerbe" export * from "./gegnachweisgewerbe.js"
export * from "./gegnachweiswohnen" export * from "./gegnachweiswohnen.js"
export * from "./klimafaktoren" export * from "./klimafaktoren.js"
export * from "./objekt" export * from "./objekt.js"
export * from "./postleitzahlen" export * from "./postleitzahlen.js"
export * from "./rechnung" export * from "./rechnung.js"
export * from "./refreshtokens" export * from "./refreshtokens.js"
export * from "./tickets" export * from "./tickets.js"
export * from "./unterlage" export * from "./unterlage.js"
export * from "./verbrauchsausweisgewerbe" export * from "./verbrauchsausweisgewerbe.js"
export * from "./verbrauchsausweiswohnen" export * from "./verbrauchsausweiswohnen.js"
export * from "./documenttemplates" export * from "./documenttemplates.js"
export * from "./documenttypes" export * from "./documenttypes.js"
export * from "./tokens" export * from "./tokens.js"

View File

@@ -1,7 +1,7 @@
--- ---
// import "svelte-ripple-action/ripple.css"; // import "svelte-ripple-action/ripple.css";
import "../style/global.css"; import "../style/global.css";
import "../../svelte-dialogs.config"; import "../../svelte-dialogs.config.js";
import DashboardSidebar from "../components/Dashboard/DashboardSidebar.svelte"; import DashboardSidebar from "../components/Dashboard/DashboardSidebar.svelte";
import { validateAccessTokenServer } from "#server/lib/validateAccessToken"; import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
import { BenutzerClient } from "#components/Ausweis/types"; import { BenutzerClient } from "#components/Ausweis/types";

View File

@@ -2,7 +2,7 @@
import { AufnahmeKomplettClient, BenutzerClient } from "#components/Ausweis/types.js"; import { AufnahmeKomplettClient, BenutzerClient } from "#components/Ausweis/types.js";
import Carousel from "#components/Carousel.svelte"; import Carousel from "#components/Carousel.svelte";
import DashboardAusweis from "#components/Dashboard/DashboardAusweis.svelte"; import DashboardAusweis from "#components/Dashboard/DashboardAusweis.svelte";
import { Objekt } from "#lib/client/prisma"; import { Objekt } from "#lib/client/prisma.js";
import { ChevronLeft, ChevronRight } from "radix-svelte-icons"; import { ChevronLeft, ChevronRight } from "radix-svelte-icons";
export let user: BenutzerClient; export let user: BenutzerClient;

View File

@@ -5,21 +5,20 @@
Cube, Cube,
Person, Person,
} from "radix-svelte-icons"; } from "radix-svelte-icons";
import { Tabs, Tab, TabList, TabPanel } from "../../components/Tabs"; import { Tabs, Tab, TabList, TabPanel } from "../../components/Tabs/index.js";
import { dialogs } from "../../../svelte-dialogs.config"; import { dialogs } from "../../../svelte-dialogs.config.js";
import { BenutzerClient } from "#components/Ausweis/types"; import { BenutzerClient } from "#components/Ausweis/types.js";
// import { client } from "src/trpc"; import { exclude } from "#lib/exclude.js";
import { exclude } from "#lib/exclude"; import { api } from "astro-typesafe-api/client";
import Cookies from "js-cookie";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
export let benutzer: BenutzerClient; export let benutzer: BenutzerClient;
let passwort: string | undefined = undefined; let passwort: string = "";
let passwortVerify: string | undefined = undefined; let passwortVerify: string = "";
async function profilSpeichern(e: SubmitEvent) { async function profilSpeichern(e: SubmitEvent) {
e.preventDefault() e.preventDefault()
if (!passwort) {
passwort = undefined
} else {
if (passwort.length < 8) { if (passwort.length < 8) {
dialogs.alert({ dialogs.alert({
title: "Passwort zu kurz", title: "Passwort zu kurz",
@@ -33,7 +32,6 @@
}) })
return return
} }
}
const response = await dialogs.confirm({ const response = await dialogs.confirm({
title: "Profil speichern", title: "Profil speichern",
@@ -51,7 +49,11 @@
// Wir wollen die Rolle nicht mit übertragen. // Wir wollen die Rolle nicht mit übertragen.
// Diese wird zwar sowieso rausgeschmissen aber sonst kommen wir nicht durch die Validation durch... // Diese wird zwar sowieso rausgeschmissen aber sonst kommen wir nicht durch die Validation durch...
await client.v1.benutzer.update.mutate(benutzerObjekt) await api.user.POST.fetch(benutzerObjekt, {
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
dialogs.success({ dialogs.success({
title: "Profil gespeichert", title: "Profil gespeichert",
@@ -175,7 +177,7 @@
} }
:global(.tab) { :global(.tab) {
@apply rounded-none px-8 justify-start outline-0 gap-4 items-center text-base font-normal text-base-content; @apply flex flex-row py-4 rounded-none px-8 justify-start outline-0 gap-4 items-center text-base font-normal text-base-content;
} }
:global(.tab:hover) { :global(.tab:hover) {

View File

@@ -1,24 +1,121 @@
<script lang="ts"> <script lang="ts">
import { BenutzerClient, ObjektKomplettClient } from "#components/Ausweis/types.js"; import "../../style/formular.css";
import DashboardAusweis from "#components/Dashboard/DashboardAusweis.svelte"; import {
BenutzerClient,
ObjektClient,
ObjektKomplettClient,
} from "#components/Ausweis/types.js";
import DashboardObjekt from "#components/Dashboard/DashboardObjekt.svelte"; import DashboardObjekt from "#components/Dashboard/DashboardObjekt.svelte";
import Overlay from "#components/Overlay.svelte";
import PlzSuche from "#components/PlzSuche.svelte";
import TagInput from "#components/TagInput.svelte";
import { api } from "astro-typesafe-api/client";
import NotificationProvider from "#components/NotificationProvider/NotificationProvider.svelte";
import NotificationWrapper from "#components/Notifications/NotificationWrapper.svelte";
import { addNotification } from "#components/Notifications/shared.js";
import Cookies from "js-cookie";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
export let user: BenutzerClient; export let user: BenutzerClient;
export let objekte: ObjektKomplettClient[]; export let objekte: ObjektKomplettClient[];
let objektOverlayHidden = true;
let objekt: Omit<ObjektClient, "uid"> = {
adresse: "",
erstellungsdatum: new Date(),
latitude: 0,
longitude: 0,
ort: "",
plz: ""
};
async function objektErstellen() {
if (!objekt.adresse || !objekt.ort || !objekt.plz) {
addNotification({
message: "Daten unvollständig.",
subtext: "Ihre eingegebenen Daten sind unvollständig, bitte vervollständigen sie diese und versuchen sie es erneut..",
timeout: 3000,
dismissable: true,
type: "error"
})
return;
}
const result = await api.objekt.PUT.fetch({
adresse: objekt.adresse,
erstellungsdatum: new Date(),
latitude: 0,
longitude: 0,
ort: objekt.ort,
plz: objekt.plz
}, {
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
if (!result) {
addNotification({
message: "Etwas ist schiefgelaufen.",
subtext: "Das Objekt konnte nicht erstellt werden.",
timeout: 3000,
dismissable: true,
type: "error"
})
return;
}
objektOverlayHidden = true;
objekte.push({
...objekt,
aufnahmen: [],
uid: result.uid
})
objekt = {
adresse: "",
erstellungsdatum: new Date(),
latitude: 0,
longitude: 0,
ort: "",
plz: ""
}
objekte = objekte
}
</script> </script>
<h1>Gebäudeübersicht</h1> <h1>Gebäudeübersicht</h1>
<hr> <hr />
<div class="relative mb-6"> <div class="relative mb-6">
<button class="button flex flex-row rounded-lg gap-2 bg-secondary text-white text-center"> <button class="button" on:click={() => {
Gebäude anlegen + objektOverlayHidden = false
</button> }}> Gebäude anlegen + </button>
</div> </div>
<div class="columns columns-1 md:columns-2 lg:columns-3 gap-4"> <div class="columns columns-1 md:columns-2 lg:columns-3 gap-4">
{#each objekte as objekt} {#each objekte as objekt}
<DashboardObjekt {objekt}></DashboardObjekt> <DashboardObjekt {objekt}></DashboardObjekt>
{/each} {/each}
</div> </div>
<Overlay bind:hidden={objektOverlayHidden}>
<div class="bg-white w-full max-w-screen-sm px-4 py-6 flex flex-col gap-4">
<h2 class="p-0 m-0">Gebäude erstellen</h2>
<input type="text" placeholder="Adresse" bind:value={objekt.adresse}>
<div class="flex flex-row gap-4 justify-between">
<PlzSuche bind:city={objekt.ort} bind:zip={objekt.plz} name="" placeholder="PLZ"></PlzSuche>
<input type="text" bind:value={objekt.ort} placeholder="Ort">
</div>
<button class="button mt-4" on:click={objektErstellen}>Gebäude Erstellen</button>
</div>
</Overlay>
<NotificationWrapper></NotificationWrapper>

View File

@@ -116,29 +116,6 @@
`/angebot-anfragen/bedarfsausweis-gewerbe-anfragen?uid=${ausweis.uid}`, `/angebot-anfragen/bedarfsausweis-gewerbe-anfragen?uid=${ausweis.uid}`,
}[ausweisart]; }[ausweisart];
async function speichern(e: SubmitEvent) {
e.preventDefault();
// Um einen Ausweis zu speichern müssen wir eingeloggt sein, andernfalls wird die API den call ablehnen.
// Wir prüfen also ob wir eingeloggt sind und leiten den Nutzer ggf. auf die Login Seite weiter.
if (!(await validateAccessTokenClient())) {
// TOOD: Auf Dialog umstellen.
const loggedIn = await dialogs.modal(LoginDialog);
if (!loggedIn) {
return false;
}
}
// Falls der Ausweis noch keine benutzer_id hat müssen wir ihn claimen, damit er dem jetzigen Nutzer zugewiesen wird...
// await client.v1.verbrauchsausweisWohnen.claim.mutate({
// uid: ausweis.uid,
// });
localStorage.clear();
window.location.href = `/kaufabschluss?uid=${ausweis.uid}`;
}
async function anfordern() { async function anfordern() {
if (!form.checkValidity()) { if (!form.checkValidity()) {
addNotification({ addNotification({
@@ -210,6 +187,34 @@
} }
} }
async function speichern() {
loginAction = speichern;
if (!await validateAccessTokenClient()) {
loginOverlayHidden = false;
return
}
loginOverlayHidden = true
let result: Awaited<ReturnType<typeof ausweisSpeichern>> | null = null;
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe || ausweisart === Enums.Ausweisart.GEGNachweisBedarfsausweis) {
result = await nachweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart)
} else {
result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, ausweisart)
}
if (result !== null) {
window.history.pushState(
{},
"",
`${location.pathname}?uid=${ausweis.uid}`
);
localStorage.clear()
window.location.href = `/speichern-erfolgreich?uid=${ausweis.uid}`
}
}
async function bestellen() { async function bestellen() {
if (!form.checkValidity()) { if (!form.checkValidity()) {
addNotification({ addNotification({
@@ -498,7 +503,7 @@ sm:grid-cols-[min-content_min-content_min-content] sm:justify-self-end sm:mt-8"
<button class="order-2 button" type="button">Speichern</button> <button class="order-2 button" type="button" on:click={speichern}>Speichern</button>
{#if gegAnfrage} {#if gegAnfrage}
<button <button

View File

@@ -146,6 +146,8 @@
const ausweisart = Enums.Ausweisart.VerbrauchsausweisWohnen const ausweisart = Enums.Ausweisart.VerbrauchsausweisWohnen
const anliegen = "Energieausweis erstellen"; const anliegen = "Energieausweis erstellen";
let form: HTMLFormElement;
</script> </script>
<Overlay bind:hidden={speichernOverlayHidden}> <Overlay bind:hidden={speichernOverlayHidden}>
@@ -179,7 +181,7 @@ const anliegen = "Energieausweis erstellen";
<div id="formInput-1" data-test="ausweis"> <form id="formInput-1" data-test="ausweis" bind:this={form}>
<div id="formular-box" class="formular-boxen ring-0"> <div id="formular-box" class="formular-boxen ring-0">
<ButtonWeiterHilfe <ButtonWeiterHilfe
@@ -190,6 +192,7 @@ const anliegen = "Energieausweis erstellen";
bind:aufnahme bind:aufnahme
ausweisart={Enums.Ausweisart.VerbrauchsausweisWohnen} ausweisart={Enums.Ausweisart.VerbrauchsausweisWohnen}
showWeiter={false} showWeiter={false}
{form}
> >
</ButtonWeiterHilfe> </ButtonWeiterHilfe>
@@ -295,6 +298,7 @@ const anliegen = "Energieausweis erstellen";
bind:user bind:user
bind:objekt bind:objekt
bind:aufnahme bind:aufnahme
bind:form
ausweisart={Enums.Ausweisart.VerbrauchsausweisWohnen} ausweisart={Enums.Ausweisart.VerbrauchsausweisWohnen}
{ausweistyp} {ausweistyp}
> >
@@ -303,7 +307,7 @@ const anliegen = "Energieausweis erstellen";
</div> </form>
<RawNotificationWrapper class="fixed left-8 bottom-8 max-w-[400px] flex flex-col gap-4 z-50"> <RawNotificationWrapper class="fixed left-8 bottom-8 max-w-[400px] flex flex-col gap-4 z-50">
{#each Object.entries($notifications) as [uid, notification] (uid)} {#each Object.entries($notifications) as [uid, notification] (uid)}

View File

@@ -1,7 +1,8 @@
import { UUidWithPrefix } from "#components/Ausweis/types.js"; import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { authorizationMiddleware } from "#lib/middleware/authorization.js"; import { authorizationMiddleware } from "#lib/middleware/authorization.js";
import { ObjektSchema, prisma } from "#lib/server/prisma"; import { prisma } from "#lib/server/prisma.js";
import { defineApiRoute } from "astro-typesafe-api/server"; import { defineApiRoute } from "astro-typesafe-api/server";
import { ObjektSchema } from "src/generated/zod/index.js";
import { z } from "zod"; import { z } from "zod";
export const PUT = defineApiRoute({ export const PUT = defineApiRoute({

View File

@@ -1,9 +1,44 @@
import { UUidWithPrefix } from "#components/Ausweis/types.js"; import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
import { hashPassword } from "#lib/password.js"; import { hashPassword } from "#lib/password.js";
import { prisma } from "#lib/server/prisma"; import { BenutzerSchema, prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server"; import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "zod"; import { z } from "zod";
export const POST = defineApiRoute({
input: BenutzerSchema.omit({
id: true,
lex_office_id: true,
uid: true,
rolle: true
}),
middleware: authorizationMiddleware,
async fetch(input, context, user) {
if (user.email !== input.email) {
// TODO: Email wurde geändert, neue Bestätigunsmail schicken.
}
await prisma.benutzer.update({
where: {
id: user.id
},
data: {
adresse: input.adresse,
anrede: input.anrede,
email: input.email,
firma: input.firma,
name: input.name,
vorname: input.vorname,
ort: input.ort,
passwort: hashPassword(input.passwort),
plz: input.plz,
profilbild: input.profilbild,
telefon: input.telefon,
}
})
},
})
export const PUT = defineApiRoute({ export const PUT = defineApiRoute({
input: z.object({ input: z.object({
email: z.string().email(), email: z.string().email(),

View File

@@ -1,9 +1,7 @@
--- ---
import { createCaller } from "../../../astro-typesafe-api-caller.js"; import { createCaller } from "../../../astro-typesafe-api-caller.js";
import { validateAccessTokenServer } from "#server/lib/validateAccessToken"; import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
import DashboardModule from "#modules/Dashboard/DashboardModule.svelte";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js"; import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import Layout from "#layouts/Layout.astro";
import { prisma } from "#lib/server/prisma"; import { prisma } from "#lib/server/prisma";
import UserLayout from "#layouts/DashboardLayout.astro"; import UserLayout from "#layouts/DashboardLayout.astro";
import DashboardAufnahmeModule from "#modules/Dashboard/DashboardAufnahmeModule.svelte"; import DashboardAufnahmeModule from "#modules/Dashboard/DashboardAufnahmeModule.svelte";

View File

@@ -4,7 +4,7 @@ import { getCurrentUser } from "#lib/server/user";
import DashboardEinstellungenModule from "#modules/Dashboard/DashboardEinstellungenModule.svelte"; import DashboardEinstellungenModule from "#modules/Dashboard/DashboardEinstellungenModule.svelte";
import { validateAccessTokenServer } from "#server/lib/validateAccessToken"; import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
const user = getCurrentUser(Astro) const user = await getCurrentUser(Astro)
if (!user) { if (!user) {
return Astro.redirect("/auth/login", 302); return Astro.redirect("/auth/login", 302);

View File

@@ -46,5 +46,5 @@ const objekte = await prisma.objekt.findMany({
--- ---
<DashboardLayout title="Dashboard" {user}> <DashboardLayout title="Dashboard" {user}>
<DashboardModule {user} {objekte} /> <DashboardModule {user} {objekte} client:load />
</DashboardLayout> </DashboardLayout>

View File

@@ -2,16 +2,16 @@ import { dialogs } from "svelte-dialogs";
dialogs.config({ dialogs.config({
global: { global: {
confirmButtonClass: "btn btn-primary", confirmButtonClass: "button",
declineButtonClass: "btn btn-bordered", declineButtonClass: "button",
dialogClass: "modal-box", dialogClass: "bg-white px-6 py-4 rounded-lg",
headerClass: "bg-base-100 text-center", headerClass: "text-center",
titleClass: "text-base-content text-xl font-medium", titleClass: "text-base-content text-xl font-medium",
dividerClass: "hidden", dividerClass: "hidden",
footerClass: "bg-base-100 justify-center gap-4 mt-4", footerClass: "justify-center gap-4 mt-4",
closeButtonClass: "btn btn-primary", closeButtonClass: "button",
closeButtonText: "Schließen", closeButtonText: "Schließen",
dismissButtonClass: "btn btn-primary", dismissButtonClass: "button",
dismissButtonText: "Schließen", dismissButtonText: "Schließen",
closeOnBg: true, closeOnBg: true,
closeOnEsc: true closeOnEsc: true