Login Popup zu Kundendaten bewegt
This commit is contained in:
BIN
persistent/images/img-694ca166-c339-44df-9240-0bb642291459.webp
Normal file
BIN
persistent/images/img-694ca166-c339-44df-9240-0bb642291459.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
BIN
persistent/images/img-85f8a7cd-7351-408f-8576-6d7b9d0ac82b.webp
Normal file
BIN
persistent/images/img-85f8a7cd-7351-408f-8576-6d7b9d0ac82b.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
persistent/images/img-a4e04cf7-9443-4462-9582-3c18b33ef711.webp
Normal file
BIN
persistent/images/img-a4e04cf7-9443-4462-9582-3c18b33ef711.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
persistent/images/img-a50b7f82-0add-4e3a-bb42-3f9b2e49936a.webp
Normal file
BIN
persistent/images/img-a50b7f82-0add-4e3a-bb42-3f9b2e49936a.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
BIN
persistent/images/img-af39ffd3-389b-43a4-9afb-5e82020dc5b0.webp
Normal file
BIN
persistent/images/img-af39ffd3-389b-43a4-9afb-5e82020dc5b0.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
BIN
persistent/images/img-e7269e2e-de35-491a-b24e-76bde9d88ac0.webp
Normal file
BIN
persistent/images/img-e7269e2e-de35-491a-b24e-76bde9d88ac0.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
@@ -1,17 +1,18 @@
|
||||
import { createCallerFactory } from "astro-typesafe-api/server";
|
||||
|
||||
export const createCaller = createCallerFactory({
|
||||
"bild": await import("../src/pages/api/bild.ts"),
|
||||
"klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"),
|
||||
"postleitzahlen": await import("../src/pages/api/postleitzahlen.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/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"),
|
||||
"admin/ausstellen": await import("../src/pages/api/admin/ausstellen.ts"),
|
||||
"admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"),
|
||||
"admin/erinnern": await import("../src/pages/api/admin/erinnern.ts"),
|
||||
"admin/nicht-ausstellen": await import("../src/pages/api/admin/nicht-ausstellen.ts"),
|
||||
"admin/post-ausstellen": await import("../src/pages/api/admin/post-ausstellen.ts"),
|
||||
"admin/registriernummer": await import("../src/pages/api/admin/registriernummer.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/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"),
|
||||
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
|
||||
"bedarfsausweis-wohnen/[uid]": await import("../src/pages/api/bedarfsausweis-wohnen/[uid].ts"),
|
||||
"bedarfsausweis-wohnen": await import("../src/pages/api/bedarfsausweis-wohnen/index.ts"),
|
||||
@@ -26,9 +27,9 @@ export const createCaller = createCallerFactory({
|
||||
"user/self": await import("../src/pages/api/user/self.ts"),
|
||||
"verbrauchsausweis-gewerbe/[uid]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[uid].ts"),
|
||||
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
|
||||
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),
|
||||
"verbrauchsausweis-wohnen/[uid]": await import("../src/pages/api/verbrauchsausweis-wohnen/[uid].ts"),
|
||||
"verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"),
|
||||
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),
|
||||
"aufnahme/[uid]/bilder": await import("../src/pages/api/aufnahme/[uid]/bilder.ts"),
|
||||
"aufnahme/[uid]": await import("../src/pages/api/aufnahme/[uid]/index.ts"),
|
||||
"objekt/[uid]": await import("../src/pages/api/objekt/[uid]/index.ts"),
|
||||
|
||||
@@ -3,14 +3,14 @@ import { api } from "astro-typesafe-api/client"
|
||||
import { exclude } from "#lib/exclude.js";
|
||||
import Cookies from "js-cookie";
|
||||
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
|
||||
import { AufnahmeClient, BedarfsausweisWohnenClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient, } from "#components/Ausweis/types.js";
|
||||
import { AufnahmeClient, BedarfsausweisWohnenClient, BildClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient, } from "#components/Ausweis/types.js";
|
||||
import { Enums } from "@ibcornelsen/database/client";
|
||||
|
||||
export async function ausweisSpeichern(
|
||||
ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient,
|
||||
objekt: ObjektClient,
|
||||
aufnahme: AufnahmeClient,
|
||||
bilder: (UploadedGebaeudeBild & { base64?: string })[],
|
||||
bilder: BildClient[],
|
||||
ausweisart: Enums.Ausweisart
|
||||
) {
|
||||
if (objekt.uid) {
|
||||
@@ -99,26 +99,15 @@ export async function ausweisSpeichern(
|
||||
ausweis.uid = uid;
|
||||
}
|
||||
|
||||
for (const bild of bilder) {
|
||||
if (bild.uid) {
|
||||
continue;
|
||||
await api.aufnahme._uid.bilder.PUT.fetch(bilder.map(bild => bild.uid), {
|
||||
params: {
|
||||
uid: aufnahme.uid
|
||||
},
|
||||
headers: {
|
||||
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
|
||||
}
|
||||
|
||||
const response = await api.aufnahme._uid.bilder.PUT.fetch({
|
||||
data: bild.data,
|
||||
kategorie: bild.kategorie
|
||||
}, {
|
||||
params: {
|
||||
uid: aufnahme.uid
|
||||
},
|
||||
headers: {
|
||||
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
|
||||
}
|
||||
})
|
||||
|
||||
bild.uid = response.uid
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return {
|
||||
uid_ausweis: ausweis.uid,
|
||||
uid_aufnahme: aufnahme.uid,
|
||||
|
||||
@@ -38,6 +38,7 @@ export async function validateAccessTokenClient() {
|
||||
const { accessToken: newAccessToken, accessTokenExpiry, refreshToken: newRefreshToken, refreshTokenExpiry } = await api.auth["access-token"].GET.fetch({
|
||||
refreshToken
|
||||
})
|
||||
|
||||
|
||||
Cookies.set(API_ACCESS_TOKEN_COOKIE_NAME, newAccessToken, {
|
||||
domain: `.${window.location.hostname}`,
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<script lang="ts">
|
||||
import Hilfe from "#components/Ausweis/Hilfe.svelte";
|
||||
export let spaeterWeitermachen;
|
||||
export let automatischAusfüllen;
|
||||
</script>
|
||||
|
||||
@@ -18,13 +16,6 @@ sm:grid-cols-[1fr_min-content_min-content_min-content] sm:justify-self-end sm:mt
|
||||
>Automatisch Ausfüllen
|
||||
</button>
|
||||
|
||||
<Hilfe />
|
||||
|
||||
<button class="button" type="button" on:click={spaeterWeitermachen}
|
||||
>Später Weitermachen
|
||||
</button>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<script lang="ts">
|
||||
import Hilfe from "#components/Ausweis/Hilfe.svelte";
|
||||
import { ausweisSpeichern } from "#client/lib/ausweisSpeichern.js";
|
||||
import { validateAccessTokenClient } from "#client/lib/validateAccessToken.js";
|
||||
import { AufnahmeClient, BedarfsausweisWohnenClient, BenutzerClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
|
||||
import Overlay from "#components/Overlay.svelte";
|
||||
import EmbeddedAuthFlowModule from "#modules/EmbeddedAuthFlowModule.svelte";
|
||||
|
||||
import { Enums } from "@ibcornelsen/database/client";
|
||||
import { AusweisTyp, Enums } from "@ibcornelsen/database/client";
|
||||
import { openWindowWithPost } from "#lib/helpers/window.js";
|
||||
import { PRICES } from "#lib/constants.js";
|
||||
|
||||
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient;
|
||||
export let bilder: UploadedGebaeudeBild[];
|
||||
@@ -15,25 +16,17 @@
|
||||
export let aufnahme: AufnahmeClient;
|
||||
export let ausweisart: Enums.Ausweisart
|
||||
|
||||
let ausweistyp: AusweisTyp = Enums.AusweisTyp.Standard;
|
||||
|
||||
async function ausweisAbschicken() {
|
||||
loginAction = ausweisAbschicken
|
||||
if (!await validateAccessTokenClient()) {
|
||||
loginOverlayHidden = false;
|
||||
return
|
||||
}
|
||||
|
||||
loginOverlayHidden = true
|
||||
|
||||
const result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, ausweisart);
|
||||
|
||||
if (result !== null) {
|
||||
window.history.pushState(
|
||||
{},
|
||||
"",
|
||||
`${location.pathname}?uid=${ausweis.uid}`
|
||||
);
|
||||
window.location.href = `/kundendaten?uid=${ausweis.uid}`;
|
||||
}
|
||||
openWindowWithPost("/kundendaten", {
|
||||
ausweis,
|
||||
objekt,
|
||||
aufnahme,
|
||||
bilder,
|
||||
ausweisart,
|
||||
ausweistyp
|
||||
}, "")
|
||||
}
|
||||
|
||||
let loginAction: () => any = ausweisAbschicken;
|
||||
@@ -61,6 +54,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function hilfeBestellen() {
|
||||
openWindowWithPost("/kundendaten", {
|
||||
ausweis,
|
||||
objekt,
|
||||
aufnahme,
|
||||
bilder,
|
||||
ausweisart,
|
||||
ausweistyp
|
||||
}, "")
|
||||
}
|
||||
|
||||
let showHelp: boolean = false;
|
||||
let loginOverlayHidden = true;
|
||||
</script>
|
||||
|
||||
@@ -69,7 +74,86 @@ sm:grid-cols-[1fr_min-content_min-content_min-content] sm:justify-self-end sm:mt
|
||||
|
||||
<div></div>
|
||||
|
||||
<Hilfe />
|
||||
<div>
|
||||
<button class="button" type="button" on:click={() => (showHelp = !showHelp)}
|
||||
>Hilfe anfordern</button
|
||||
>
|
||||
</div>
|
||||
|
||||
{#if showHelp}
|
||||
<div class="col-start-1 row-start-2 col-span-4 mt-4">
|
||||
<div
|
||||
class="bereich-box grid relative
|
||||
grid-cols-1 gap-x-4 gap-y-4
|
||||
|
||||
"
|
||||
>
|
||||
<div class="pr-12">
|
||||
Gerne helfen wir Ihnen wenn Sie nicht weiterkommen oder Fragen
|
||||
haben. Kurze Fragen zum Formular oder der Ausweisart werden
|
||||
kostenfrei telefonisch unter <a href="tel:+4940209339850"
|
||||
>040/209339850</a
|
||||
> beantwortet (bis 5min). Sollten Sie Unterstützung bei der Erstellung
|
||||
benötgen oder lieber die Arbeit von unserem Ingenieurbüro erledigen
|
||||
lassen, bieten wir Ihnen folgende Hilfen an. Bitte treffen Sie Ihre
|
||||
Auswahl und klicken auf weiter:
|
||||
</div>
|
||||
|
||||
<hr class="m-0" />
|
||||
|
||||
<div class="grid grid-cols-[30px_490px_200px_1fr] items-center">
|
||||
<input
|
||||
type="radio"
|
||||
class=" accent-secondary w-[20px] h-[20px]"
|
||||
id="Produkttb1"
|
||||
value={Enums.AusweisTyp.Beratung}
|
||||
name="Produkt"
|
||||
bind:group={ausweistyp}
|
||||
/>
|
||||
|
||||
<div class="justify-self-stretch">
|
||||
Verbrauchsausweis online inkl. ausführlicher telefonischer
|
||||
Beratung
|
||||
</div>
|
||||
|
||||
<div class="text-right">
|
||||
<b>{PRICES[ausweisart][Enums.AusweisTyp.Beratung]} €</b> inkl. MwSt.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-[30px_490px_200px_1fr] items-center">
|
||||
<input
|
||||
type="radio"
|
||||
class=" accent-secondary w-[20px] h-[20px]"
|
||||
id="Produktof1"
|
||||
value={Enums.AusweisTyp.Offline}
|
||||
name="Produkt"
|
||||
bind:group={ausweistyp}
|
||||
/>
|
||||
|
||||
<div>
|
||||
Verbrauchsausweis offline (Sie schicken uns 3
|
||||
Verbrauchsabrechnungen zu)
|
||||
</div>
|
||||
|
||||
<div class="text-right">
|
||||
<b>{PRICES[ausweisart][Enums.AusweisTyp.Offline]} €</b> inkl. MwSt.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="m-0" />
|
||||
|
||||
<button class="button" on:click={hilfeBestellen}>jetzt Hilfe bestellen</button>
|
||||
|
||||
<button
|
||||
class="button absolute top-2 right-2 w-[30px] h-[30px] text-sm p-0"
|
||||
type="button"
|
||||
on:click={() => (showHelp = !showHelp)}>X</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
<button class="button" type="button" on:click={spaeterWeitermachen}
|
||||
>Später Weitermachen
|
||||
@@ -78,7 +162,7 @@ sm:grid-cols-[1fr_min-content_min-content_min-content] sm:justify-self-end sm:mt
|
||||
<div>
|
||||
<Overlay bind:hidden={loginOverlayHidden}>
|
||||
<div class="bg-white w-full max-w-screen-sm py-8">
|
||||
<EmbeddedAuthFlowModule onLogin={loginAction}></EmbeddedAuthFlowModule>
|
||||
<EmbeddedAuthFlowModule onLogin={loginAction} email={""}></EmbeddedAuthFlowModule>
|
||||
</div>
|
||||
</Overlay>
|
||||
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { PRICES } from "#lib/constants.js";
|
||||
|
||||
let showHelp: boolean = false;
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<button class="button" type="button" on:click={() => (showHelp = !showHelp)}
|
||||
>Hilfe anfordern</button
|
||||
>
|
||||
</div>
|
||||
|
||||
{#if showHelp}
|
||||
<div class="col-start-1 row-start-2 col-span-4 mt-4">
|
||||
<div
|
||||
class="bereich-box grid relative
|
||||
grid-cols-1 gap-x-4 gap-y-4
|
||||
|
||||
"
|
||||
>
|
||||
<div class="pr-12">
|
||||
Gerne helfen wir Ihnen wenn Sie nicht weiterkommen oder Fragen
|
||||
haben. Kurze Fragen zum Formular oder der Ausweisart werden
|
||||
kostenfrei telefonisch unter <a href="tel:+4940209339850"
|
||||
>040/209339850</a
|
||||
> beantwortet (bis 5min). Sollten Sie Unterstützung bei der Erstellung
|
||||
benötgen oder lieber die Arbeit von unserem Ingenieurbüro erledigen
|
||||
lassen, bieten wir Ihnen folgende Hilfen an. Bitte treffen Sie Ihre
|
||||
Auswahl und klicken auf weiter:
|
||||
</div>
|
||||
|
||||
<hr class="m-0" />
|
||||
|
||||
<div class="grid grid-cols-[30px_490px_200px_1fr] items-center">
|
||||
<input
|
||||
type="radio"
|
||||
class=" accent-secondary w-[20px] h-[20px]"
|
||||
id="Produkttb1"
|
||||
value="ptb"
|
||||
name="Produkt"
|
||||
/>
|
||||
|
||||
<div class="justify-self-stretch">
|
||||
Verbrauchsausweis online inkl. ausführlicher telefonischer
|
||||
Beratung
|
||||
</div>
|
||||
|
||||
<div class="text-right">
|
||||
<b>{PRICES.VerbrauchsausweisWohnen[1]} €</b> inkl. MwSt.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-[30px_490px_200px_1fr] items-center">
|
||||
<input
|
||||
type="radio"
|
||||
class=" accent-secondary w-[20px] h-[20px]"
|
||||
id="Produktof1"
|
||||
value="pof"
|
||||
name="Produkt"
|
||||
/>
|
||||
|
||||
<div>
|
||||
Verbrauchsausweis offline (Sie schicken uns 3
|
||||
Verbrauchsabrechnungen zu)
|
||||
</div>
|
||||
|
||||
<div class="text-right">
|
||||
<b>{PRICES.VerbrauchsausweisWohnen[2]} €</b> inkl. MwSt.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="m-0" />
|
||||
|
||||
<button class="button">jetzt Hilfe bestellen</button>
|
||||
|
||||
<button
|
||||
class="button absolute top-2 right-2 w-[30px] h-[30px] text-sm p-0"
|
||||
type="button"
|
||||
on:click={() => (showHelp = !showHelp)}>X</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -1,140 +1,142 @@
|
||||
<script lang="ts">
|
||||
|
||||
import HelpLabel from "#components/labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#components/labels/InputLabel.svelte";
|
||||
import ZipSearch from "#components/PlzSuche.svelte";
|
||||
import ZipSearch from "#components/PlzSuche.svelte";
|
||||
import { BenutzerClient, RechnungClient } from "./types.js";
|
||||
|
||||
export let user: BenutzerClient;
|
||||
export let rechnung: Partial<RechnungClient>;
|
||||
|
||||
|
||||
|
||||
|
||||
$: {
|
||||
if (!rechnung.abweichende_versand_adresse) {
|
||||
rechnung.versand_empfaenger = rechnung.empfaenger
|
||||
rechnung.versand_ort = rechnung.ort
|
||||
rechnung.versand_plz = rechnung.plz
|
||||
rechnung.versand_strasse = rechnung.strasse
|
||||
rechnung.versand_zusatzzeile = rechnung.zusatzzeile
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div id="rechnungsadresse" class="bereich-box grid
|
||||
<div
|
||||
id="rechnungsadresse"
|
||||
class="bereich-box grid
|
||||
grid-cols-1 gap-x-4 gap-y-8
|
||||
sm:grid-cols-2 sm:gap-x-6 sm:gap-y-8
|
||||
xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
|
||||
">
|
||||
"
|
||||
>
|
||||
<!-- Empfänger * -->
|
||||
|
||||
<!-- Empfänger * -->
|
||||
<div class="input-standard order-1 md:order-1 xl:order-1">
|
||||
<Inputlabel title="Rechnungs-Empfänger *"></Inputlabel>
|
||||
|
||||
<div class="input-standard order-1 md:order-1 xl:order-1">
|
||||
<Inputlabel title="Rechnungs-Empfänger *"></Inputlabel>
|
||||
|
||||
<input
|
||||
name="rechnung_empfaenger"
|
||||
type="text"
|
||||
bind:value={rechnung.empfaenger}
|
||||
required
|
||||
data-rule-maxlength="100"
|
||||
data-msg-maxlength="max. 100 Zeichen"
|
||||
/>
|
||||
<input
|
||||
name="rechnung_empfaenger"
|
||||
type="text"
|
||||
bind:value={rechnung.empfaenger}
|
||||
required
|
||||
data-rule-maxlength="100"
|
||||
data-msg-maxlength="max. 100 Zeichen"
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie den Empfänger ein, auf den die Rechnung ausgestellt wird.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Straße, Hausnummer * -->
|
||||
|
||||
<div class="input-standard order21 md:order-2 xl:order-2">
|
||||
<Inputlabel title="Straße, Hausnummer *"></Inputlabel>
|
||||
|
||||
<input
|
||||
name="rechnung_strasse"
|
||||
bind:value={rechnung.strasse}
|
||||
type="text"
|
||||
required
|
||||
data-rule-maxlength="40"
|
||||
data-msg-maxlength="max. 40 Zeichen"
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie die Strasse und Hausnummer, so wie Sie auf der Rechnung erscheinen soll, ein.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PLZ / ORT -->
|
||||
|
||||
<div class="grid grid-cols-[2fr_4fr] gap-x-4 order-3 md:order-3 xl:order-3">
|
||||
|
||||
<div class="input-noHelp">
|
||||
<Inputlabel title="PLZ *"></Inputlabel>
|
||||
<ZipSearch
|
||||
name="rechnung_plz"
|
||||
bind:zip={rechnung.plz}
|
||||
bind:city={rechnung.ort}
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="input-standard">
|
||||
<Inputlabel title="Ort *"></Inputlabel>
|
||||
|
||||
<input
|
||||
name="rechnung_ort"
|
||||
readonly
|
||||
type="text"
|
||||
required
|
||||
value={rechnung.ort}
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie die PLZ des Ortes, so wie Sie auf der Rechnung erscheinen soll, ein.
|
||||
</HelpLabel>
|
||||
<HelpLabel>
|
||||
Bitte geben Sie den Empfänger ein, auf den die Rechnung
|
||||
ausgestellt wird.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- Straße, Hausnummer * -->
|
||||
|
||||
<!-- Zusatzzeile -->
|
||||
<div class="input-standard order21 md:order-2 xl:order-2">
|
||||
<Inputlabel title="Straße, Hausnummer *"></Inputlabel>
|
||||
|
||||
<div class="input-standard order-4 md:order-4 xl:order-4">
|
||||
<Inputlabel title="Zusatzzeile"></Inputlabel>
|
||||
|
||||
<input
|
||||
name="rechnung_zusatzzeile"
|
||||
bind:value={rechnung.zusatzzeile}
|
||||
type="text"
|
||||
data-rule-maxlength="80"
|
||||
data-msg-maxlength="max. 80 Zeichen"
|
||||
/>
|
||||
<input
|
||||
name="rechnung_strasse"
|
||||
bind:value={rechnung.strasse}
|
||||
type="text"
|
||||
required
|
||||
data-rule-maxlength="40"
|
||||
data-msg-maxlength="max. 40 Zeichen"
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie die Strasse und Hausnummer, so wie Sie auf der
|
||||
Rechnung erscheinen soll, ein.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PLZ / ORT -->
|
||||
|
||||
<div class="grid grid-cols-[2fr_4fr] gap-x-4 order-3 md:order-3 xl:order-3">
|
||||
<div class="input-noHelp">
|
||||
<Inputlabel title="PLZ *"></Inputlabel>
|
||||
<ZipSearch
|
||||
name="rechnung_plz"
|
||||
bind:zip={rechnung.plz}
|
||||
bind:city={rechnung.ort}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="input-standard">
|
||||
<Inputlabel title="Ort *"></Inputlabel>
|
||||
|
||||
<input
|
||||
name="rechnung_ort"
|
||||
readonly
|
||||
type="text"
|
||||
required
|
||||
value={rechnung.ort}
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie, falls erforderlich, zusätzliche nformationen ein.
|
||||
Bitte geben Sie die PLZ des Ortes, so wie Sie auf der
|
||||
Rechnung erscheinen soll, ein.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- E-mail -->
|
||||
<!-- Zusatzzeile -->
|
||||
|
||||
<div class="input-standard order-5 md:order-5 xl:order-5">
|
||||
<Inputlabel title="E-mail *"></Inputlabel>
|
||||
<div class="input-standard order-4 md:order-4 xl:order-4">
|
||||
<Inputlabel title="Zusatzzeile"></Inputlabel>
|
||||
|
||||
<input
|
||||
name="rechnung_email"
|
||||
bind:value={rechnung.email}
|
||||
type="email"
|
||||
/>
|
||||
<input
|
||||
name="rechnung_zusatzzeile"
|
||||
bind:value={rechnung.zusatzzeile}
|
||||
type="text"
|
||||
data-rule-maxlength="80"
|
||||
data-msg-maxlength="max. 80 Zeichen"
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie die E-Mail Adresse des Rechnungsempfängers ein.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
<HelpLabel>
|
||||
Bitte geben Sie, falls erforderlich, zusätzliche nformationen
|
||||
ein.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Telefon
|
||||
<!-- E-mail -->
|
||||
|
||||
<div class="input-standard order-5 md:order-5 xl:order-5">
|
||||
<Inputlabel title="E-mail *"></Inputlabel>
|
||||
|
||||
<input name="rechnung_email" bind:value={rechnung.email} type="email" />
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie die E-Mail Adresse des Rechnungsempfängers ein.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Telefon
|
||||
|
||||
<div class="input-standard order-6 md:order-6 xl:order-6">
|
||||
<Inputlabel title="Telefon *"></Inputlabel>
|
||||
@@ -153,147 +155,147 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div class="col-span-3 order-7 md:order-7 xl:order-7">
|
||||
<div class="col-span-3 order-7 md:order-7 xl:order-7">
|
||||
<div
|
||||
class="grid grid-cols-[25px_max-content] items-center justify-items-start"
|
||||
>
|
||||
<input
|
||||
id="abweichende_versand_adresse"
|
||||
class="w-[15px] h-[15px]"
|
||||
type="checkbox"
|
||||
name="abweichende_versand_adresse"
|
||||
bind:checked={rechnung.abweichende_versand_adresse}
|
||||
/>
|
||||
|
||||
<div class="grid grid-cols-[25px_max-content] items-center justify-items-start">
|
||||
<label for="abweichende_versand_adresse" class="cursor-pointer"
|
||||
>abweichende Versandadresse</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input
|
||||
id="abweichende_versand_adresse"
|
||||
class="w-[15px] h-[15px]"
|
||||
type="checkbox"
|
||||
name="abweichende_versand_adresse"
|
||||
bind:checked={rechnung.abweichende_versand_adresse}
|
||||
/>
|
||||
{#if rechnung.abweichende_versand_adresse}
|
||||
<!-- Versand Empfänger * -->
|
||||
|
||||
<label for="abweichende_versand_adresse" class="cursor-pointer"
|
||||
>abweichende Versandadresse</label>
|
||||
<div class="input-standard order-8 md:order-8 xl:order-8">
|
||||
<Inputlabel title="Versand-Empfänger *"></Inputlabel>
|
||||
|
||||
</div>
|
||||
<input
|
||||
name="versand_empfaenger"
|
||||
type="text"
|
||||
readonly={!rechnung.abweichende_versand_adresse}
|
||||
bind:value={rechnung.versand_empfaenger}
|
||||
required
|
||||
data-rule-maxlength="100"
|
||||
data-msg-maxlength="max. 100 Zeichen"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
{#if rechnung.abweichende_versand_adresse}
|
||||
|
||||
<!-- Versand Empfänger * -->
|
||||
|
||||
<div class="input-standard order-8 md:order-8 xl:order-8">
|
||||
<Inputlabel title="Versand-Empfänger *"></Inputlabel>
|
||||
|
||||
<input
|
||||
name="versand_empfaenger"
|
||||
type="text"
|
||||
readonly={!rechnung.abweichende_versand_adresse}
|
||||
bind:value={rechnung.versand_empfaenger}
|
||||
required
|
||||
data-rule-maxlength="100"
|
||||
data-msg-maxlength="max. 100 Zeichen"
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie den Namen des Versand-Empfängers ein.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Versand Straße, Hausnummer * -->
|
||||
|
||||
<div class="input-standard order-9 md:order-9 xl:order-9">
|
||||
<Inputlabel title="Straße, Hausnummer *"></Inputlabel>
|
||||
|
||||
<input
|
||||
name="versand_strasse"
|
||||
type="text"
|
||||
readonly={!rechnung.abweichende_versand_adresse}
|
||||
bind:value={rechnung.versand_strasse}
|
||||
required
|
||||
data-rule-maxlength="40"
|
||||
data-msg-maxlength="max. 40 Zeichen"
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie die Versand-Empfänger Strasse und Hausnummer ein, an die die Rechnung versandt wird.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- PLZ / ORT -->
|
||||
|
||||
<div class="grid grid-cols-[2fr_4fr] gap-x-4 order-10 md:order-10 xl:order-10">
|
||||
|
||||
<div class="input-noHelp">
|
||||
<Inputlabel title="PLZ *"></Inputlabel>
|
||||
<ZipSearch
|
||||
name="versand_plz"
|
||||
readonly={!rechnung.abweichende_versand_adresse}
|
||||
bind:zip={rechnung.versand_plz}
|
||||
bind:city={rechnung.versand_ort}
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="input-standard">
|
||||
<Inputlabel title="Ort *"></Inputlabel>
|
||||
|
||||
<input
|
||||
name="versand_ort"
|
||||
type="text"
|
||||
readonly
|
||||
required
|
||||
bind:value={rechnung.versand_ort}
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie die Versand-Empfänger PLZ des Ortes ein, an den die Rechnung versandt wird.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- Versand Straße, Hausnummer * -->
|
||||
|
||||
<!-- Zusatzzeile -->
|
||||
<div class="input-standard order-9 md:order-9 xl:order-9">
|
||||
<Inputlabel title="Straße, Hausnummer *"></Inputlabel>
|
||||
|
||||
<div class="input-standard order-11 md:order-11 xl:order-11">
|
||||
<Inputlabel title="Zusatzzeile"></Inputlabel>
|
||||
<input
|
||||
name="versand_strasse"
|
||||
type="text"
|
||||
readonly={!rechnung.abweichende_versand_adresse}
|
||||
bind:value={rechnung.versand_strasse}
|
||||
required
|
||||
data-rule-maxlength="40"
|
||||
data-msg-maxlength="max. 40 Zeichen"
|
||||
/>
|
||||
|
||||
<input
|
||||
name="versand_zusatzzeile"
|
||||
type="text"
|
||||
readonly={!rechnung.abweichende_versand_adresse}
|
||||
bind:value={rechnung.versand_zusatzzeile}
|
||||
data-rule-maxlength="80"
|
||||
data-msg-maxlength="max. 80 Zeichen"
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie, falls erforderlich, zusätzliche nformationen ein.
|
||||
Bitte geben Sie die Versand-Empfänger Strasse und Hausnummer
|
||||
ein, an die die Rechnung versandt wird.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- E-mail -->
|
||||
<!-- PLZ / ORT -->
|
||||
|
||||
<div class="input-standard order-12 md:order-12 xl:order-12">
|
||||
<Inputlabel title="E-mail *"></Inputlabel>
|
||||
<div
|
||||
class="grid grid-cols-[2fr_4fr] gap-x-4 order-10 md:order-10 xl:order-10"
|
||||
>
|
||||
<div class="input-noHelp">
|
||||
<Inputlabel title="PLZ *"></Inputlabel>
|
||||
<ZipSearch
|
||||
name="versand_plz"
|
||||
readonly={!rechnung.abweichende_versand_adresse}
|
||||
bind:zip={rechnung.versand_plz}
|
||||
bind:city={rechnung.versand_ort}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<input
|
||||
name="rechnung_email"
|
||||
bind:value={rechnung.email}
|
||||
type="email"
|
||||
/>
|
||||
<div class="input-standard">
|
||||
<Inputlabel title="Ort *"></Inputlabel>
|
||||
|
||||
<div class="help-label">
|
||||
<input
|
||||
name="versand_ort"
|
||||
type="text"
|
||||
readonly
|
||||
required
|
||||
bind:value={rechnung.versand_ort}
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie die Versand-Empfänger PLZ des Ortes ein,
|
||||
an den die Rechnung versandt wird.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Zusatzzeile -->
|
||||
|
||||
<div class="input-standard order-11 md:order-11 xl:order-11">
|
||||
<Inputlabel title="Zusatzzeile"></Inputlabel>
|
||||
|
||||
<input
|
||||
name="versand_zusatzzeile"
|
||||
type="text"
|
||||
readonly={!rechnung.abweichende_versand_adresse}
|
||||
bind:value={rechnung.versand_zusatzzeile}
|
||||
data-rule-maxlength="80"
|
||||
data-msg-maxlength="max. 80 Zeichen"
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie die E-Mail Adresse des Versand-Empfängers ein.
|
||||
Bitte geben Sie, falls erforderlich, zusätzliche
|
||||
nformationen ein.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Telefon
|
||||
<!-- E-mail -->
|
||||
|
||||
<div class="input-standard order-12 md:order-12 xl:order-12">
|
||||
<Inputlabel title="E-mail *"></Inputlabel>
|
||||
|
||||
<input
|
||||
name="rechnung_email"
|
||||
bind:value={rechnung.email}
|
||||
type="email"
|
||||
/>
|
||||
|
||||
<div class="help-label">
|
||||
<HelpLabel>
|
||||
Bitte geben Sie die E-Mail Adresse des Versand-Empfängers
|
||||
ein.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Telefon
|
||||
|
||||
<div class="input-standard order-[13] md:order-[13] xl:order-[13]">
|
||||
<Inputlabel title="Telefon *"></Inputlabel>
|
||||
@@ -311,7 +313,5 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
{/if }
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -153,8 +153,8 @@ export function getAusweisartFromUUID(uid: string): Enums.Ausweisart | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
export type UnterlageClient = Omit<Unterlage, "id" | "objekt_id">
|
||||
export type BildClient = Omit<Bild, "id" | "objekt_id">
|
||||
export type UnterlageClient = Omit<Unterlage, "id" | "aufnahme_id">
|
||||
export type BildClient = Omit<Bild, "id" | "aufnahme_id">
|
||||
|
||||
export type ObjektKomplettClient = ObjektClient & {
|
||||
aufnahmen: AufnahmeKomplettClient[]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<script lang="ts">
|
||||
import UploadImages from "./UploadImages.svelte";
|
||||
import type { Enums } from "@ibcornelsen/database/client";
|
||||
import { BedarfsausweisWohnenClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./Ausweis/types.js";
|
||||
import { BedarfsausweisWohnenClient, BildClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./Ausweis/types.js";
|
||||
import { RotateCounterClockwise, Trash, Upload } from "radix-svelte-icons";
|
||||
|
||||
export let images: UploadedGebaeudeBild[] = [];
|
||||
export let images: BildClient[] = [];
|
||||
export let max: number = Infinity;
|
||||
export let min: number = 1;
|
||||
export let name: string = "";
|
||||
@@ -42,7 +42,7 @@
|
||||
{#if image.kategorie == kategorie}
|
||||
<div class="relative group">
|
||||
<img
|
||||
src={image.data ? image.data : `/bilder/${image.uid}.webp`}
|
||||
src="/bilder/{image.uid}.webp"
|
||||
alt={kategorie}
|
||||
class="h-full max-h-96 w-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all"
|
||||
/>
|
||||
|
||||
@@ -9,13 +9,15 @@
|
||||
// Array of base64 encoded images read into the input.
|
||||
import {
|
||||
BedarfsausweisWohnenClient,
|
||||
BildClient,
|
||||
ObjektClient,
|
||||
UploadedGebaeudeBild,
|
||||
VerbrauchsausweisGewerbeClient,
|
||||
VerbrauchsausweisWohnenClient,
|
||||
} from "./Ausweis/types.js";
|
||||
import { api } from "astro-typesafe-api/client";
|
||||
|
||||
export let images: UploadedGebaeudeBild[] = [];
|
||||
export let images: BildClient[] = [];
|
||||
export let ausweis:
|
||||
| VerbrauchsausweisWohnenClient
|
||||
| VerbrauchsausweisGewerbeClient
|
||||
@@ -78,7 +80,12 @@
|
||||
// Get the scaled-down data from the canvas in the desired output format and quality
|
||||
const dataURL = canvas.toDataURL("image/jpeg", 0.8);
|
||||
|
||||
images.push({ data: dataURL as string, kategorie });
|
||||
const { uid } = await api.bild.PUT.fetch({
|
||||
data: dataURL,
|
||||
kategorie
|
||||
})
|
||||
|
||||
images.push({ uid, kategorie });
|
||||
images = images;
|
||||
|
||||
if (i == Math.min(files.length, max) - 1) {
|
||||
|
||||
@@ -148,7 +148,7 @@ export async function endEnergieVerbrauchVerbrauchsausweis_2016(
|
||||
energieVerbrauchHeizung_2 * durchschnittsKlimafaktor;
|
||||
|
||||
let kuehlungsZuschlag = 0;
|
||||
if (ausweis.wird_gekuehlt) {
|
||||
if (aufnahme.kuehlung) {
|
||||
kuehlungsZuschlag = 6 * 3 * energetischeNutzflaeche;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,41 +21,35 @@ export enum VALID_UUID_PREFIXES {
|
||||
"gnw" = "GEG Nachweis Wohnen"
|
||||
}
|
||||
|
||||
export enum AusweisTyp {
|
||||
Standard,
|
||||
Beratung,
|
||||
Offline
|
||||
}
|
||||
|
||||
/**
|
||||
* Ein Objekt welches alle definierten Preise für unsere Basisprodukte enthält.
|
||||
*/
|
||||
export const PRICES: Record<Enums.Ausweisart, Record<AusweisTyp, number>> = {
|
||||
export const PRICES: Record<Enums.Ausweisart, Record<Enums.AusweisTyp, number>> = {
|
||||
// per E-Mail , inkl.Beratung, offline
|
||||
BedarfsausweisWohnen: {
|
||||
[AusweisTyp.Standard]: 95,
|
||||
[AusweisTyp.Beratung]: 125,
|
||||
[AusweisTyp.Offline]: 295
|
||||
[Enums.AusweisTyp.Standard]: 95,
|
||||
[Enums.AusweisTyp.Beratung]: 125,
|
||||
[Enums.AusweisTyp.Offline]: 295
|
||||
},
|
||||
VerbrauchsausweisWohnen: {
|
||||
[AusweisTyp.Standard]: 65,
|
||||
[AusweisTyp.Beratung]: 95,
|
||||
[AusweisTyp.Offline]: 180
|
||||
[Enums.AusweisTyp.Standard]: 65,
|
||||
[Enums.AusweisTyp.Beratung]: 95,
|
||||
[Enums.AusweisTyp.Offline]: 180
|
||||
},
|
||||
VerbrauchsausweisGewerbe: {
|
||||
[AusweisTyp.Standard]: 95,
|
||||
[AusweisTyp.Beratung]: 125,
|
||||
[AusweisTyp.Offline]: 360
|
||||
[Enums.AusweisTyp.Standard]: 95,
|
||||
[Enums.AusweisTyp.Beratung]: 125,
|
||||
[Enums.AusweisTyp.Offline]: 360
|
||||
},
|
||||
BedarfsausweisGewerbe: {
|
||||
[AusweisTyp.Standard]: 500,
|
||||
[AusweisTyp.Beratung]: 700,
|
||||
[AusweisTyp.Offline]: 1000
|
||||
[Enums.AusweisTyp.Standard]: 500,
|
||||
[Enums.AusweisTyp.Beratung]: 700,
|
||||
[Enums.AusweisTyp.Offline]: 1000
|
||||
},
|
||||
GEGNachweisWohnen: {
|
||||
[AusweisTyp.Standard]: 500,
|
||||
[AusweisTyp.Beratung]: 700,
|
||||
[AusweisTyp.Offline]: 1000
|
||||
[Enums.AusweisTyp.Standard]: 500,
|
||||
[Enums.AusweisTyp.Beratung]: 700,
|
||||
[Enums.AusweisTyp.Offline]: 1000
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
export function openWindowWithPost(url: string, data: Record<string, any>) {
|
||||
var form = document.createElement("form");
|
||||
form.target = "_blank";
|
||||
form.method = "POST";
|
||||
form.action = url;
|
||||
form.style.display = "none";
|
||||
export function openWindowWithPost(url: string, data: Record<string, any>, target = "_blank") {
|
||||
const form = document.createElement("form");
|
||||
form.target = target;
|
||||
form.method = "POST";
|
||||
form.action = url;
|
||||
form.style.display = "none";
|
||||
|
||||
for (var key in data) {
|
||||
var input = document.createElement("input");
|
||||
input.type = "hidden";
|
||||
input.name = key;
|
||||
input.value = data[key];
|
||||
form.appendChild(input);
|
||||
}
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
document.body.removeChild(form);
|
||||
}
|
||||
const createInput = (name: string, value: any) => {
|
||||
const input = document.createElement("input");
|
||||
input.type = "hidden";
|
||||
input.name = name;
|
||||
input.value = JSON.stringify(value);
|
||||
return input;
|
||||
};
|
||||
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
form.appendChild(createInput(key, value));
|
||||
});
|
||||
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
document.body.removeChild(form);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { PDFDocument, rgb, StandardFonts, TextAlignment } from "pdf-lib";
|
||||
import { checkbox, flex, text } from "./elements/index.js";
|
||||
import { xml2pdf } from "./elements/xml2pdf.js";
|
||||
import moment from "moment";
|
||||
import { Heizungsstatus } from "@ibcornelsen/database/server";
|
||||
import { BilderKategorie, Heizungsstatus } from "@ibcornelsen/database/server";
|
||||
import { fileURLToPath } from "url";
|
||||
import { copyPage } from "./utils/copyPage.js";
|
||||
|
||||
@@ -297,33 +297,40 @@ export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: Verbrauchsau
|
||||
|
||||
const images: string[][] = []
|
||||
|
||||
for (const bild of bilder) {
|
||||
let badge: string[];
|
||||
let image: string = "";
|
||||
let individualHeight = (pages[2].getHeight() - 370) / 4;
|
||||
|
||||
if (bild.uid) {
|
||||
image = `<img src="${fileURLToPath(new URL(`../../../../persistent/images/${bilder[0].uid}.webp`, import.meta.url))}" width="${(pages[2].getHeight() - 120) / 3.1}" />`
|
||||
} else if (bild.data) {
|
||||
image = `<img data="${bild.data}" width="${(pages[2].getWidth() - 120) / 3.1}" height="180" />`
|
||||
}
|
||||
const sortedImages = bilder.reduce((acc, c) => {
|
||||
let img: string;
|
||||
|
||||
if (images.length > 0) {
|
||||
let badge = images[images.length - 1]
|
||||
if (badge.length == 3) {
|
||||
badge = [image]
|
||||
images.push(badge)
|
||||
} else {
|
||||
badge.push(image)
|
||||
}
|
||||
if (c.uid) {
|
||||
img = `<img src="${fileURLToPath(new URL(`../../../../persistent/images/${bilder[0].uid}.webp`, import.meta.url))}" width="${(pages[2].getHeight() - 120) / 4.1}" height="${individualHeight}" />`
|
||||
} else {
|
||||
badge = [image]
|
||||
images.push(badge)
|
||||
img = `<img data="${c.data}" width="${(pages[2].getWidth() - 120) / 4.1}" height="${individualHeight}" />`
|
||||
}
|
||||
|
||||
if (c.kategorie in acc) {
|
||||
acc[c.kategorie].push(img)
|
||||
} else {
|
||||
acc[c.kategorie] = [img];
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, {} as Record<BilderKategorie, string[]>)
|
||||
|
||||
let text = ""
|
||||
|
||||
for (const [kategorie, images] of Object.entries(sortedImages)) {
|
||||
text += `<flex direction="column" gap="4" width="${pages[2].getWidth() - 120}" height="${individualHeight}" marginTop="25">
|
||||
<text font="bold" size="14">${kategorie}</text>
|
||||
<flex direction="row" justify="space-between" width="${pages[2].getWidth() - 120}" height="${individualHeight}">
|
||||
${images.join("")}
|
||||
</flex>
|
||||
</flex>`
|
||||
}
|
||||
|
||||
const layoutPage3 = xml2pdf(`<layout height="${pages[2].getHeight()}" width="${pages[2].getWidth()}" marginTop="150" marginLeft="60" marginRight="60">
|
||||
${images.map(badge => `<flex direction="row" justify="space-between" width="${pages[2].getWidth() - 120}" height="180" marginTop="15">${badge.join("")}</flex>`).join("")}
|
||||
</layout>`, { "default": font })
|
||||
${text}
|
||||
</layout>`, { "default": font, bold })
|
||||
|
||||
layout.draw(pages[0], 0, pages[0].getHeight())
|
||||
layoutPage2.draw(pages[1], 0, pages[1].getHeight())
|
||||
|
||||
@@ -132,7 +132,7 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
|
||||
}
|
||||
|
||||
// Kühlung
|
||||
if (ausweis.wird_gekuehlt) {
|
||||
if (aufnahme.kuehlung) {
|
||||
addCheckMark(pages[0], 213, height - 362.5)
|
||||
} else {
|
||||
addCheckMark(pages[0], 355, height - 373.5)
|
||||
|
||||
@@ -147,6 +147,35 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
|
||||
height: 50
|
||||
})
|
||||
|
||||
const erneuerbareEnergienVerwendung = []
|
||||
|
||||
if (ausweis.alternative_heizung) {
|
||||
erneuerbareEnergienVerwendung.push("Heizung")
|
||||
}
|
||||
|
||||
if (ausweis.alternative_kuehlung) {
|
||||
erneuerbareEnergienVerwendung.push("Kühlung")
|
||||
}
|
||||
|
||||
if (ausweis.alternative_lueftung) {
|
||||
erneuerbareEnergienVerwendung.push("Lüftung")
|
||||
}
|
||||
|
||||
if (ausweis.alternative_warmwasser) {
|
||||
erneuerbareEnergienVerwendung.push("Warmwasser")
|
||||
}
|
||||
|
||||
pages[0].drawText(erneuerbareEnergienVerwendung.join(", "), {
|
||||
x: 358,
|
||||
y: height - 337,
|
||||
size: 8
|
||||
})
|
||||
|
||||
// Kühlung
|
||||
if (aufnahme.kuehlung) {
|
||||
addCheckMark(pages[0], 354, height - 376.5)
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------- Seite 2 -------------------------------- */
|
||||
|
||||
@@ -444,7 +473,7 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
|
||||
Math.round(berechnungen?.kuehlungsZuschlag || 0).toString(),
|
||||
"0",
|
||||
"0",
|
||||
"1.8"
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
import EmbeddedRegisterModule from "./EmbeddedRegisterModule.svelte"
|
||||
|
||||
export let onLogin: (response: Awaited<ReturnType<typeof loginClient>>) => any;
|
||||
export let email: string = "";
|
||||
export let password: string = "";
|
||||
|
||||
let route: "login" | "signup" = "login"
|
||||
|
||||
@@ -12,16 +14,16 @@
|
||||
}
|
||||
|
||||
const loginData = {
|
||||
email: "",
|
||||
email,
|
||||
passwort: "",
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if route == "login"}
|
||||
<EmbeddedLoginModule onLogin={onLogin} data={loginData} {navigate} />
|
||||
<EmbeddedLoginModule onLogin={onLogin} bind:email bind:password {navigate} />
|
||||
{:else}
|
||||
<EmbeddedRegisterModule onRegister={(response) => {
|
||||
loginData.email = response.email
|
||||
<EmbeddedRegisterModule bind:email bind:password onRegister={(response) => {
|
||||
email = response.email
|
||||
navigate("login")
|
||||
}} {navigate} />
|
||||
{/if}
|
||||
@@ -3,13 +3,14 @@
|
||||
import { loginClient } from "#lib/login.js";
|
||||
|
||||
export let navigate: (target: string) => void;
|
||||
export let data: { email: string; passwort: string };
|
||||
|
||||
export let email: string;
|
||||
export let password: string;
|
||||
|
||||
export let onLogin: (response: Awaited<ReturnType<typeof loginClient>>) => any;
|
||||
|
||||
async function login(e: SubmitEvent) {
|
||||
e.preventDefault()
|
||||
const response = await loginClient(data.email, data.passwort)
|
||||
const response = await loginClient(email, password)
|
||||
|
||||
if (response === null) {
|
||||
addNotification({
|
||||
@@ -35,7 +36,7 @@
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
name="email"
|
||||
bind:value={data.email}
|
||||
bind:value={email}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
@@ -46,7 +47,7 @@
|
||||
type="password"
|
||||
placeholder="********"
|
||||
name="passwort"
|
||||
bind:value={data.passwort}
|
||||
bind:value={password}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
export let navigate: (target: string) => void;
|
||||
export let onRegister: (response: { email: string, name: string, vorname: string }) => void;
|
||||
let passwort: string;
|
||||
let email: string;
|
||||
export let password: string;
|
||||
export let email: string;
|
||||
let vorname: string;
|
||||
let name: string;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
try {
|
||||
const response = await api.user.PUT.fetch({
|
||||
email,
|
||||
passwort,
|
||||
passwort: password,
|
||||
vorname,
|
||||
name,
|
||||
});
|
||||
@@ -82,7 +82,7 @@
|
||||
placeholder="********"
|
||||
name="passwort"
|
||||
class="px-2.5 py-1.5 rounded-lg border bg-gray-50"
|
||||
bind:value={passwort}
|
||||
bind:value={password}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
import LoginDialog from "#components/LoginDialog.svelte";
|
||||
import {
|
||||
API_ACCESS_TOKEN_COOKIE_NAME,
|
||||
AusweisTyp,
|
||||
PRICES,
|
||||
} from "#lib/constants.js";
|
||||
import Cookies from "js-cookie";
|
||||
import {
|
||||
AufnahmeClient,
|
||||
BenutzerClient,
|
||||
BildClient,
|
||||
getAusweisartFromUUID,
|
||||
ObjektClient,
|
||||
RechnungClient,
|
||||
@@ -25,14 +25,20 @@
|
||||
import { validateAccessTokenClient } from "src/client/lib/validateAccessToken.js";
|
||||
import { api } from "astro-typesafe-api/client";
|
||||
import PaymentOption from "#components/PaymentOption.svelte";
|
||||
import Overlay from "#components/Overlay.svelte";
|
||||
import EmbeddedAuthFlowModule from "./EmbeddedAuthFlowModule.svelte";
|
||||
import { ausweisSpeichern } from "#client/lib/ausweisSpeichern.js";
|
||||
import { addNotification } from "#components/Notifications/shared.js";
|
||||
import NotificationWrapper from "#components/Notifications/NotificationWrapper.svelte";
|
||||
|
||||
export let user: BenutzerClient;
|
||||
export let user: Partial<BenutzerClient>;
|
||||
export let ausweis: VerbrauchsausweisWohnenClient;
|
||||
export let aufnahme: AufnahmeClient;
|
||||
export let objekt: ObjektClient;
|
||||
export let bilder: BildClient[];
|
||||
export let ausweisart: Enums.Ausweisart;
|
||||
export let aktiveBezahlmethode: Bezahlmethoden = Enums.Bezahlmethoden.paypal;
|
||||
export let ausweis_typ: AusweisTyp = AusweisTyp.Standard;
|
||||
export let ausweistyp: Enums.AusweisTyp = Enums.AusweisTyp.Standard;
|
||||
|
||||
let rechnung: Partial<RechnungClient> = {
|
||||
email: user.email,
|
||||
@@ -81,7 +87,7 @@
|
||||
|
||||
let prices = PRICES[ausweisart];
|
||||
|
||||
let basePrice: number = prices[0];
|
||||
let basePrice: number = prices[ausweistyp];
|
||||
|
||||
$: price =
|
||||
basePrice +
|
||||
@@ -135,9 +141,35 @@
|
||||
}
|
||||
|
||||
async function bestellen() {
|
||||
const ausweisart = getAusweisartFromUUID(
|
||||
ausweis.uid
|
||||
) as Enums.Ausweisart;
|
||||
if (!form.checkValidity()) {
|
||||
addNotification({
|
||||
dismissable: true,
|
||||
message: "Fehlende Daten.",
|
||||
subtext: "Nicht alle notwendigen Felder sind ausgefüllt, bitte füllen sie diese aus bevor sie es erneut versuchen.."
|
||||
})
|
||||
|
||||
form.reportValidity();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await validateAccessTokenClient()) {
|
||||
loginAction = bestellen
|
||||
rechnung = rechnung
|
||||
loginOverlayHidden = false;
|
||||
return
|
||||
}
|
||||
|
||||
loginOverlayHidden = true
|
||||
|
||||
const result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, ausweisart)
|
||||
|
||||
if (result === null) {
|
||||
addNotification({
|
||||
dismissable: true,
|
||||
message: "Ups... Das hat nicht geklappt.",
|
||||
subtext: "Der Ausweis konnte nicht gespeichert werden, bitte versuchen sie es erneut oder kontaktieren sie unseren Support."
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
const { uid, checkout_url } = await api.rechnung.PUT.fetch(
|
||||
@@ -158,7 +190,7 @@
|
||||
versand_ort: rechnung.versand_ort,
|
||||
telefon: rechnung.telefon,
|
||||
ausweis_uid: ausweis.uid,
|
||||
ausweis_typ,
|
||||
ausweistyp,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
@@ -209,6 +241,10 @@
|
||||
ausweisart === Enums.Ausweisart.GEGNachweisWohnen ||
|
||||
ausweisart === Enums.Ausweisart.GEGNachweisBedarfsausweis ||
|
||||
ausweisart === Enums.Ausweisart.GEGNachweisGewerbe;
|
||||
|
||||
let loginOverlayHidden = true;
|
||||
let loginAction = () => {};
|
||||
let form: HTMLFormElement;
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -239,7 +275,7 @@
|
||||
<h1 class="text-secondary text-3xl m-0">Energiesausweis erstellen</h1>
|
||||
<h2 class="text-primary text-xl">
|
||||
{ausweisart}
|
||||
{prices[0]} €
|
||||
{prices[ausweistyp]} €
|
||||
</h2>
|
||||
{#if gegAnfrage}
|
||||
<Progressbar
|
||||
@@ -252,7 +288,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="formInput-2">
|
||||
<form id="formInput-2" bind:this={form}>
|
||||
<div id="formular-box" class="formular-boxen ring-0">
|
||||
<Bereich
|
||||
bereich="1"
|
||||
@@ -262,7 +298,7 @@
|
||||
>
|
||||
|
||||
<Bereich bereich="2" title="Rechnungsadresse">
|
||||
<Rechnungsadresse bind:user bind:rechnung /></Bereich
|
||||
<Rechnungsadresse bind:rechnung /></Bereich
|
||||
>
|
||||
|
||||
{#if !gegAnfrage}
|
||||
@@ -376,11 +412,12 @@ grid-cols-5 justify-around justify-items-center items-center"
|
||||
|
||||
<div></div>
|
||||
|
||||
<button class="button">Speichern</button>
|
||||
<button class="button" type="button">Speichern</button>
|
||||
|
||||
{#if gegAnfrage}
|
||||
<button
|
||||
class="button cursor-pointer"
|
||||
type="button"
|
||||
data-cy="bestellen"
|
||||
on:click={anfordern}>Angebot anfordern</button
|
||||
>
|
||||
@@ -388,12 +425,22 @@ grid-cols-5 justify-around justify-items-center items-center"
|
||||
<button
|
||||
class="button cursor-pointer"
|
||||
data-cy="bestellen"
|
||||
type="button"
|
||||
on:click={bestellen}>Kostenpflichtig bestellen</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Overlay bind:hidden={loginOverlayHidden}>
|
||||
<div class="bg-white w-full max-w-screen-sm py-8">
|
||||
<EmbeddedAuthFlowModule onLogin={loginAction} email={rechnung.email}></EmbeddedAuthFlowModule>
|
||||
</div>
|
||||
</Overlay>
|
||||
|
||||
</form>
|
||||
|
||||
<NotificationWrapper></NotificationWrapper>
|
||||
|
||||
<!--
|
||||
<div class="bereich-box pr-12 mt-6">
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
<form id="formInput-1" data-cy="ausweis" name="ausweis">
|
||||
<div id="formular-box" class="formular-boxen ring-0">
|
||||
|
||||
<ButtonSpaeterHilfe {automatischAusfüllen} {spaeterWeitermachen} />
|
||||
<ButtonSpaeterHilfe {automatischAusfüllen} />
|
||||
|
||||
<!-- A Prüfung der Ausweisart -->
|
||||
|
||||
@@ -201,7 +201,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<ButtonWeiterHilfe {spaeterWeitermachen}
|
||||
<ButtonWeiterHilfe
|
||||
bind:ausweis
|
||||
bind:bilder
|
||||
bind:user
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
AufnahmeClient,
|
||||
} from "#components/Ausweis/types.js";
|
||||
import { Enums } from "@ibcornelsen/database/client";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
// TODO: Vom Server sollte ein volles Objekt kommen, dass alle Subobjekte enthält, weil es sonst zu Problemen führen kann
|
||||
// wenn aufnahme oder objekt nicht existiert...
|
||||
@@ -82,30 +81,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function spaeterWeitermachen() {
|
||||
// TODO FIX
|
||||
// const result = await ausweisSpeichern(
|
||||
// ausweis,
|
||||
// objekt,
|
||||
// aufnahme,
|
||||
// bilder
|
||||
// );
|
||||
|
||||
// if (result !== null) {
|
||||
// // Falls der Nutzer zurück navigiert, sollte er wieder auf seinen Vorgang kommen.
|
||||
// // Sonst müsste er alles neu eingeben...
|
||||
// ausweis.uid = result.uid_ausweis;
|
||||
// objekt.uid = result.uid_objekt;
|
||||
// aufnahme.uid = result.uid_aufnahme;
|
||||
// window.history.pushState(
|
||||
// {},
|
||||
// "",
|
||||
// `${location.pathname}?uid=${result.uid_ausweis}`
|
||||
// );
|
||||
// speichernOverlayHidden = false;
|
||||
// }
|
||||
}
|
||||
|
||||
function automatischAusfüllen() {
|
||||
aufnahme.baujahr_gebaeude = [1962];
|
||||
aufnahme.baujahr_heizung = [1952];
|
||||
@@ -139,30 +114,6 @@
|
||||
ausweis = ausweis;
|
||||
}
|
||||
|
||||
async function ausweisAbschicken(e: SubmitEvent) {
|
||||
// if (e && e.preventDefault) e.preventDefault();
|
||||
// const result = await ausweisSpeichern(
|
||||
// ausweis,
|
||||
// objekt,
|
||||
// aufnahme,
|
||||
// bilder
|
||||
// );
|
||||
|
||||
// if (result !== null) {
|
||||
// // Falls der Nutzer zurück navigiert, sollte er wieder auf seinen Vorgang kommen.
|
||||
// // Sonst müsste er alles neu eingeben...
|
||||
// ausweis.uid = result.uid_ausweis;
|
||||
// objekt.uid = result.uid_objekt;
|
||||
// aufnahme.uid = result.uid_aufnahme;
|
||||
// window.history.pushState(
|
||||
// {},
|
||||
// "",
|
||||
// `${location.pathname}?uid=${result.uid_ausweis}`
|
||||
// );
|
||||
// // window.location.href = `/kundendaten?uid=${result.uid_ausweis}`;
|
||||
// }
|
||||
}
|
||||
|
||||
let waitOverlayHidden = true;
|
||||
let speichernOverlayHidden = true;
|
||||
|
||||
@@ -225,7 +176,7 @@ const ausweisart: Enums.Ausweisart = "VerbrauchsausweisWohnen"
|
||||
<div id="progress-box" class="w-full box relative px-4 py-3 text-center order-2 self-stretch">
|
||||
|
||||
<h1 class="text-secondary text-3xl m-0">Energieausweis erstellen</h1>
|
||||
<h2 class="text-primary text-xl">{ausweisart} {PRICES.VerbrauchsausweisWohnen[0]} €</h2>
|
||||
<h2 class="text-primary text-xl">{ausweisart} {PRICES[ausweisart][Enums.AusweisTyp.Standard]} €</h2>
|
||||
<Progressbar active={0}/>
|
||||
</div>
|
||||
|
||||
@@ -233,10 +184,10 @@ const ausweisart: Enums.Ausweisart = "VerbrauchsausweisWohnen"
|
||||
|
||||
|
||||
|
||||
<form id="formInput-1" on:submit={ausweisAbschicken} name="ausweis" data-test="ausweis">
|
||||
<div id="formInput-1" data-test="ausweis">
|
||||
<div id="formular-box" class="formular-boxen ring-0">
|
||||
|
||||
<ButtonSpaeterHilfe {automatischAusfüllen} {spaeterWeitermachen} />
|
||||
<ButtonSpaeterHilfe {automatischAusfüllen} />
|
||||
|
||||
<!-- A Prüfung der Ausweisart -->
|
||||
|
||||
@@ -346,7 +297,7 @@ const ausweisart: Enums.Ausweisart = "VerbrauchsausweisWohnen"
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<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)}
|
||||
|
||||
@@ -5,86 +5,49 @@ import { z } from "zod";
|
||||
import isBase64 from "is-base64";
|
||||
import { fileURLToPath } from "url";
|
||||
import { writeFileSync } from "fs";
|
||||
import { UUidWithPrefix } from "#components/Ausweis/types.js";
|
||||
|
||||
export const PUT = defineApiRoute({
|
||||
input: BildSchema.pick({
|
||||
kategorie: true,
|
||||
}).merge(z.object({
|
||||
data: z.string()
|
||||
})),
|
||||
output: z.object({
|
||||
uid: z.string({ description: "Die UID des Bildes." })
|
||||
}),
|
||||
input: z.array(UUidWithPrefix),
|
||||
output: z.void(),
|
||||
middleware: authorizationMiddleware,
|
||||
async fetch(input, ctx, user) {
|
||||
const data = input.data;
|
||||
|
||||
if (!isBase64(data, { mimeRequired: true })) {
|
||||
throw new APIError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Das Bild ist nicht base64.",
|
||||
});
|
||||
}
|
||||
|
||||
let aufnahme = await prisma.aufnahme.findUnique({
|
||||
const aufnahme = await prisma.aufnahme.findUnique({
|
||||
where: {
|
||||
uid: ctx.params.uid,
|
||||
benutzer_id: user.id
|
||||
},
|
||||
});
|
||||
uid: ctx.params.uid
|
||||
}
|
||||
})
|
||||
|
||||
if (!aufnahme) {
|
||||
throw new APIError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Objekt nicht gefunden oder gehört einem anderen Benutzer.",
|
||||
});
|
||||
}
|
||||
|
||||
const dataWithoutPrefix = data.replace(
|
||||
/^data:image\/\w+;base64,/,
|
||||
""
|
||||
);
|
||||
const buffer = Buffer.from(dataWithoutPrefix, "base64");
|
||||
|
||||
const bild = await prisma.bild.create({
|
||||
data: {
|
||||
kategorie: input.kategorie,
|
||||
aufnahme: {
|
||||
connect: {
|
||||
id: aufnahme.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
select: {
|
||||
uid: true,
|
||||
},
|
||||
});
|
||||
|
||||
const filePath = fileURLToPath(new URL(`../../../../../persistent/images/${bild.uid}.webp`, import.meta.url));
|
||||
|
||||
try {
|
||||
// Wir optimieren das Bild und konvertieren es in WebP
|
||||
// TODO: Sharp scheint nicht zu funktionieren, wir müssen das nochmal testen
|
||||
// const optimizedBuffer = await sharp(buffer).webp({ quality: 80 }).toArray();
|
||||
|
||||
writeFileSync(filePath, buffer)
|
||||
} catch(e) {
|
||||
// Bild wurde nicht gespeichert, wir löschen den Eintrag wieder
|
||||
await prisma.bild.delete({
|
||||
where: {
|
||||
uid: bild.uid
|
||||
}
|
||||
message: "Aufnahme existiert nicht oder gehört einem anderen Benutzer."
|
||||
})
|
||||
// Und geben einen Fehler zurück
|
||||
throw new APIError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message: "Bild konnte nicht gespeichert werden.",
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
uid: bild.uid
|
||||
};
|
||||
prisma.$transaction(async tx => {
|
||||
for (const uid of input) {
|
||||
const img = await tx.bild.update({
|
||||
where: {
|
||||
uid,
|
||||
aufnahme_id: null
|
||||
},
|
||||
data: {
|
||||
aufnahme_id: aufnahme.id
|
||||
},
|
||||
select: {
|
||||
uid: true
|
||||
}
|
||||
})
|
||||
|
||||
if (!img) {
|
||||
throw new APIError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Bild existiert nicht oder gehört bereits zu einer anderen Aufnahme."
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
@@ -115,8 +78,8 @@ export const GET = defineApiRoute({
|
||||
|
||||
if (!aufnahme) {
|
||||
throw new APIError({
|
||||
code: "FORBIDDEN",
|
||||
message: "Objekt existiert nicht oder gehört einem anderen Benutzer."
|
||||
code: "NOT_FOUND",
|
||||
message: "Aufnahme existiert nicht oder gehört einem anderen Benutzer."
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ export const GET = defineApiRoute({
|
||||
const refreshToken = encodeToken({
|
||||
uid: user.uid,
|
||||
typ: TokenType.Refresh,
|
||||
exp: refreshTokenExpiry.unix(),
|
||||
exp: refreshTokenExpiry.valueOf(),
|
||||
});
|
||||
|
||||
// Und erstellen einen neuen
|
||||
@@ -107,7 +107,7 @@ export const GET = defineApiRoute({
|
||||
},
|
||||
});
|
||||
|
||||
const accessTokenExpiry = moment().add(2, "days").unix();
|
||||
const accessTokenExpiry = moment().add(2, "days").valueOf();
|
||||
const accessToken = encodeToken({
|
||||
uid: user.uid,
|
||||
typ: TokenType.Access,
|
||||
@@ -118,7 +118,7 @@ export const GET = defineApiRoute({
|
||||
accessToken,
|
||||
accessTokenExpiry: accessTokenExpiry,
|
||||
refreshToken,
|
||||
refreshTokenExpiry: refreshTokenExpiry.unix(),
|
||||
refreshTokenExpiry: refreshTokenExpiry.valueOf(),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
106
src/pages/api/bild.ts
Normal file
106
src/pages/api/bild.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { authorizationMiddleware, maybeAuthorizationMiddleware } from "#lib/middleware/authorization.js";
|
||||
import { BildSchema } from "@ibcornelsen/database/client";
|
||||
import { prisma } from "@ibcornelsen/database/server";
|
||||
import { defineApiRoute, APIError } from "astro-typesafe-api/server";
|
||||
import { z } from "astro:content";
|
||||
import { fileURLToPath } from "url";
|
||||
import isBase64 from "is-base64";
|
||||
import { writeFileSync } from "fs"
|
||||
import { UUidWithPrefix } from "#components/Ausweis/types.js";
|
||||
|
||||
export const PUT = defineApiRoute({
|
||||
input: BildSchema.pick({
|
||||
kategorie: true,
|
||||
}).merge(z.object({
|
||||
data: z.string()
|
||||
})),
|
||||
output: z.object({
|
||||
uid: z.string({ description: "Die UID des Bildes." })
|
||||
}),
|
||||
async fetch(input) {
|
||||
const data = input.data;
|
||||
|
||||
if (!isBase64(data, { mimeRequired: true })) {
|
||||
throw new APIError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Das Bild ist nicht base64.",
|
||||
});
|
||||
}
|
||||
|
||||
const dataWithoutPrefix = data.replace(
|
||||
/^data:image\/\w+;base64,/,
|
||||
""
|
||||
);
|
||||
const buffer = Buffer.from(dataWithoutPrefix, "base64");
|
||||
|
||||
const bild = await prisma.bild.create({
|
||||
data: {
|
||||
kategorie: input.kategorie
|
||||
},
|
||||
select: {
|
||||
uid: true,
|
||||
},
|
||||
});
|
||||
|
||||
const filePath = fileURLToPath(new URL(`../../../persistent/images/${bild.uid}.webp`, import.meta.url));
|
||||
|
||||
try {
|
||||
// Wir optimieren das Bild und konvertieren es in WebP
|
||||
// TODO: Sharp scheint nicht zu funktionieren, wir müssen das nochmal testen
|
||||
// const optimizedBuffer = await sharp(buffer).webp({ quality: 80 }).toArray();
|
||||
|
||||
writeFileSync(filePath, buffer)
|
||||
} catch(e) {
|
||||
// Bild wurde nicht gespeichert, wir löschen den Eintrag wieder
|
||||
await prisma.bild.delete({
|
||||
where: {
|
||||
uid: bild.uid
|
||||
}
|
||||
})
|
||||
// Und geben einen Fehler zurück
|
||||
throw new APIError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message: "Bild konnte nicht gespeichert werden.",
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
uid: bild.uid
|
||||
};
|
||||
},
|
||||
})
|
||||
|
||||
export const DELETE = defineApiRoute({
|
||||
input: z.object({
|
||||
uid: UUidWithPrefix
|
||||
}),
|
||||
middleware: maybeAuthorizationMiddleware,
|
||||
async fetch(input, context, user) {
|
||||
try {
|
||||
if (user) {
|
||||
await prisma.bild.delete({
|
||||
where: {
|
||||
uid: input.uid,
|
||||
aufnahme: {
|
||||
benutzer: {
|
||||
id: user.id
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
await prisma.bild.delete({
|
||||
where: {
|
||||
uid: input.uid,
|
||||
aufnahme_id: null
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch(e) {
|
||||
throw new APIError({
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
message: "Bild konnte nicht gelöscht werden."
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
} from "#lib/middleware/authorization.js";
|
||||
import { UUidWithPrefix } from "#components/Ausweis/types.js";
|
||||
import { getPrismaAusweisAdapter } from "#lib/server/ausweis.js";
|
||||
import { AusweisTyp, PRICES, SERVICES } from "#lib/constants.js";
|
||||
import { PRICES, SERVICES } from "#lib/constants.js";
|
||||
|
||||
export const PUT = defineApiRoute({
|
||||
meta: {
|
||||
@@ -23,7 +23,7 @@ export const PUT = defineApiRoute({
|
||||
.object({
|
||||
ausweisart: z.nativeEnum(Enums.Ausweisart),
|
||||
ausweis_uid: UUidWithPrefix,
|
||||
ausweis_typ: z.nativeEnum(AusweisTyp)
|
||||
ausweistyp: z.nativeEnum(Enums.AusweisTyp)
|
||||
})
|
||||
.merge(
|
||||
RechnungSchema.omit({
|
||||
@@ -49,8 +49,8 @@ export const PUT = defineApiRoute({
|
||||
// Wir erstellen eine Mollie Payment Referenz und eine neue Rechnung in unserer Datenbank, daraufhin geben
|
||||
// wir eine Checkout URL zurück auf die der Nutzer weitergeleitet werden kann.
|
||||
|
||||
const { ausweis_uid, ausweisart, bezahlmethode, services, ausweis_typ } = input;
|
||||
let betrag = PRICES[ausweisart][ausweis_typ]
|
||||
const { ausweis_uid, ausweisart, bezahlmethode, services, ausweistyp } = input;
|
||||
let betrag = PRICES[ausweisart][ausweistyp]
|
||||
|
||||
const servicePriceList = SERVICES[ausweisart]
|
||||
for (const service of input.services) {
|
||||
@@ -94,6 +94,8 @@ export const PUT = defineApiRoute({
|
||||
bezahlmethode: bezahlmethode,
|
||||
status: Enums.Rechnungsstatus.open,
|
||||
aufnahme_id: ausweis.aufnahme_id,
|
||||
services,
|
||||
ausweistyp
|
||||
},
|
||||
select: {
|
||||
uid: true,
|
||||
|
||||
@@ -16,7 +16,9 @@ export const PUT = defineApiRoute({
|
||||
tags: ["Verbrauchsausweis Wohnen"],
|
||||
},
|
||||
input: z.object({
|
||||
ausweis: VerbrauchsausweisWohnenSchema.omit({
|
||||
ausweis: VerbrauchsausweisWohnenSchema.merge(z.object({
|
||||
startdatum: z.coerce.date()
|
||||
})).omit({
|
||||
id: true,
|
||||
benutzer_id: true,
|
||||
uid: true,
|
||||
|
||||
@@ -1,29 +1,11 @@
|
||||
|
||||
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
|
||||
import { validateAccessTokenServer } from "#server/lib/validateAccessToken.js";
|
||||
import { prisma } from "@ibcornelsen/database/server";
|
||||
import { APIRoute } from "astro";
|
||||
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
|
||||
import * as fs from "fs";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
export const GET: APIRoute = async (Astro) => {
|
||||
const { uid } = Astro.params
|
||||
const token = Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value;
|
||||
|
||||
if (!token) {
|
||||
return new Response(null, {
|
||||
status: 400
|
||||
})
|
||||
}
|
||||
|
||||
const valid = validateAccessTokenServer(Astro);
|
||||
|
||||
if (!valid) {
|
||||
return new Response(null, {
|
||||
status: 401
|
||||
})
|
||||
}
|
||||
|
||||
const image = await prisma.bild.findUnique({
|
||||
where: {
|
||||
@@ -38,6 +20,13 @@ export const GET: APIRoute = async (Astro) => {
|
||||
}
|
||||
|
||||
const path = fileURLToPath(new URL(`../../../persistent/images/${image.uid}.webp`, import.meta.url))
|
||||
|
||||
if (!fs.existsSync(path)) {
|
||||
return new Response(null, {
|
||||
status: 404
|
||||
})
|
||||
}
|
||||
|
||||
const buffer = fs.readFileSync(path)
|
||||
|
||||
return new Response(buffer, {
|
||||
|
||||
@@ -3,98 +3,37 @@
|
||||
import KundendatenModule from "#modules/KundendatenModule.svelte";
|
||||
import AusweisLayout from "#layouts/AusweisLayoutPruefung.astro";
|
||||
import { Enums } from "@ibcornelsen/database/client";
|
||||
import { createCaller } from "../astro-typesafe-api-caller";
|
||||
import { API_ACCESS_TOKEN_COOKIE_NAME, API_REFRESH_TOKEN_COOKIE_NAME } from "#lib/constants";
|
||||
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
|
||||
import { BedarfsausweisWohnenClient, getAusweisartFromUUID, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
|
||||
import { getCurrentUser } from "#lib/server/user";
|
||||
|
||||
// Man sollte nur auf diese Seite kommen, wenn ein Ausweis bereits vorliegt und in der Datenbank abgespeichert wurde.
|
||||
const uid = Astro.url.searchParams.get("uid");
|
||||
const valid = await validateAccessTokenServer(Astro)
|
||||
|
||||
if (!uid || !valid) {
|
||||
return Astro.redirect("/404");
|
||||
}
|
||||
const user = await getCurrentUser(Astro) || {}
|
||||
|
||||
const params = new URLSearchParams(await Astro.request.text());
|
||||
|
||||
const caller = createCaller(Astro)
|
||||
|
||||
const ausweisart = getAusweisartFromUUID(uid);
|
||||
|
||||
let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient;
|
||||
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
|
||||
ausweis = await caller["verbrauchsausweis-wohnen"]._uid.GET.fetch(undefined, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
|
||||
},
|
||||
params: {
|
||||
uid
|
||||
}
|
||||
})
|
||||
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
|
||||
ausweis = await caller["verbrauchsausweis-gewerbe"]._uid.GET.fetch(undefined, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
|
||||
},
|
||||
params: {
|
||||
uid
|
||||
}
|
||||
})
|
||||
} else if (ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) {
|
||||
ausweis = await caller["bedarfsausweis-wohnen"]._uid.GET.fetch(undefined, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
|
||||
},
|
||||
params: {
|
||||
uid
|
||||
}
|
||||
})
|
||||
} else if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) {
|
||||
ausweis = await caller["geg-nachweis-wohnen"]._uid.GET.fetch(undefined, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
|
||||
},
|
||||
params: {
|
||||
uid
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if (!params.has("ausweis") || !params.has("aufnahme") || !params.has("objekt") || !params.has("bilder") || !params.has("ausweisart")) {
|
||||
return Astro.redirect("/404")
|
||||
}
|
||||
|
||||
const aufnahme = await caller.aufnahme._uid.GET.fetch(undefined, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
|
||||
},
|
||||
params: {
|
||||
uid: ausweis.uid_aufnahme
|
||||
let ausweis, aufnahme, objekt, ausweisart, bilder, ausweistyp;
|
||||
try {
|
||||
ausweis = JSON.parse(params.get("ausweis") || "")
|
||||
aufnahme = JSON.parse(params.get("aufnahme") || "")
|
||||
objekt = JSON.parse(params.get("objekt") || "")
|
||||
ausweisart = JSON.parse(params.get("ausweisart") || "") as Enums.Ausweisart;
|
||||
bilder = JSON.parse(params.get("bilder") || "");
|
||||
ausweistyp = JSON.parse(params.get("ausweistyp") || "") as Enums.AusweisTyp;
|
||||
|
||||
if (!ausweisart || !Object.keys(Enums.Ausweisart).includes(ausweisart) || !ausweistyp || !Object.keys(Enums.AusweisTyp).includes(ausweistyp)) {
|
||||
throw new Error()
|
||||
}
|
||||
})
|
||||
|
||||
const objekt = await caller.objekt._uid.GET.fetch(undefined, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
|
||||
},
|
||||
params: {
|
||||
uid: aufnahme.uid_objekt
|
||||
}
|
||||
})
|
||||
|
||||
const user = await caller.user.self.GET.fetch(undefined, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
|
||||
}
|
||||
});
|
||||
|
||||
aufnahme.ausweisart = "VerbrauchsausweisWohnen"
|
||||
|
||||
|
||||
if (!ausweis || !user) {
|
||||
return Astro.redirect("/404");
|
||||
} catch(e){
|
||||
return Astro.redirect("/404")
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
<AusweisLayout title="Kundendaten Aufnehmen - IBCornelsen">
|
||||
<KundendatenModule {user} {ausweis} {objekt} {aufnahme} {ausweisart} bezahlmethode={Enums.Bezahlmethoden.paypal} client:load></KundendatenModule>
|
||||
<KundendatenModule {user} {ausweis} {objekt} {aufnahme} {bilder} {ausweisart} {ausweistyp} aktiveBezahlmethode={Enums.Bezahlmethoden.paypal} client:load></KundendatenModule>
|
||||
</AusweisLayout>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user