Cypress und API

This commit is contained in:
Moritz Utcke
2025-01-22 12:20:45 +07:00
parent 5d73f5f7c7
commit 46ef96becd
57 changed files with 1057 additions and 3945 deletions

View File

@@ -1,17 +1,42 @@
import { defineConfig } from "cypress"; import { defineConfig } from "cypress";
import dsv from "@rollup/plugin-dsv"
import { fileURLToPath } from "url";
import vitePreprocessor from "cypress-vite";
export default defineConfig({ export default defineConfig({
e2e: { e2e: {
baseUrl: "http://localhost:3000", baseUrl: "http://localhost:3000",
supportFile: false,
viewportHeight: 900, viewportHeight: 900,
viewportWidth: 1660, viewportWidth: 1660,
supportFile: false,
specPattern: "./src/cypress/e2e/**/*.{ts,js}",
setupNodeEvents(on, config) {
on("file:preprocessor", vitePreprocessor({
optimizeDeps: {
exclude: ["@ibcornelsen/api", "@ibcornelsen/database"]
},
resolve: {
alias: {
"#": fileURLToPath(new URL("./src", import.meta.url)),
"#components": fileURLToPath(new URL("./src/components", import.meta.url)),
"#lib": fileURLToPath(new URL("./src/lib", import.meta.url))
}
},
base: fileURLToPath(new URL("./src", import.meta.url)),
build: {
commonjsOptions: {
transformMixedEsModules: false
}
},
plugins: [dsv()]
}))
},
}, },
component: { component: {
devServer: { devServer: {
framework: "svelte", framework: "svelte",
bundler: "vite", bundler: "vite"
}, },
}, }
}); });

View File

@@ -1,282 +0,0 @@
import fuelList from "#components/Ausweis/brennstoffListe";
import { faker } from "@faker-js/faker";
import { Enums } from "@ibcornelsen/database/client";
import "cypress-file-upload"
describe("Verbrauchsausweis erstellen Schritt 1", () => {
it("erstellt einen neuen Verbrauchsausweis Wohngebäude.", () => {
cy.visit("/energieausweis-erstellen/verbrauchsausweis-wohnen");
cy.wait(1000);
// Wir überprüfen, ob alle Ausstelgründe vorhanden sind, diese sollten genau so viele sein wie in der Datenbank vorhanden sind.
cy.get("input[name='ausstellgrund']")
.should("have.length", Object.values(Enums.Ausstellgrund).length)
.eq(
faker.number.int({
min: 0,
max: Object.values(Enums.Ausstellgrund).length - 1,
})
)
.check();
// Jetzt Füllen wir das Baujahr vom Gebäude aus.
cy.get("input[name='baujahr_gebaeude']")
.should("have.attr", "type", "number")
.type(
faker.number.int({ min: 1900, max: 2021 }).toString() +
"{enter}",
{ delay: 50 }
);
// Jetzt Füllen wir das Baujahr der Heizung aus.
cy.get("input[name='baujahr_heizung']")
.should("have.attr", "type", "number")
.type(
faker.number.int({ min: 1900, max: 2021 }).toString() +
"{enter}",
{ delay: 50 }
);
// Anzahl Einheiten
cy.get("input[name='einheiten']")
.should("have.attr", "type", "number")
.type(faker.number.int({ min: 1, max: 5 }).toString());
// Sanierungsstatus
cy.get("select[name='saniert']").select(
Math.random() > 0.5 ? "true" : "false"
);
// Adresse
cy.get("input[name='adresse']").type(faker.location.streetAddress());
// Postleitzahl
cy.get("input[name='plz']").type(
faker.location.zipCode({
format: "#####",
})
);
// TODO: Ort - Dieser wird aus der Datenbank abgefragt, wir müssen also warten, bis der Dropdown da ist.
// Flaeche
cy.get("input[name='flaeche']")
.should("have.attr", "type", "number")
.type(faker.number.int({ min: 50, max: 1000 }).toString());
// Nutzflaeche
cy.get("input[name='nutzflaeche']")
.should("have.attr", "type", "number")
.type(faker.number.int({ min: 50, max: 1000 }).toString());
// Keller
cy.get("select[name='keller']").find("option:not([disabled])").should("have.length", Object.values(Enums.Heizungsstatus).length).parent().select(faker.number.int({
max: Object.values(Enums.Heizungsstatus).length,
min: 1
}));
// Dachgeschoss
cy.get("select[name='dachgeschoss']").find("option:not([disabled])").should("have.length", Object.values(Enums.Heizungsstatus).length).parent().select(faker.number.int({
max: Object.values(Enums.Heizungsstatus).length,
min: 1
}));
// Brennstoff und Einheit 1
const brennstoffKombo = fuelList[faker.number.int({ min: 0, max: fuelList.length - 1 })];
cy.get("select[name='brennstoff_1']").select(brennstoffKombo[0]);
cy.get("select[name='einheit_1']").select(brennstoffKombo[1]);
// Verbrauchszeitraum
cy.get("select[name='energieverbrauch_zeitraum_monat']").select(faker.number.int({ min: 1, max: 12 }).toString());
cy.get("select[name='energieverbrauch_zeitraum_jahr']").select(faker.number.int({ min: 2018, max: 2019 }).toString());
// Verbrauch
cy.get("input[name='verbrauch_1']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
cy.get("input[name='verbrauch_2']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
cy.get("input[name='verbrauch_3']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
const zusaetzlicheHeizquelle = Math.random() > 0.5;
if (zusaetzlicheHeizquelle) {
cy.get("input[name='zusaetzliche_heizquelle']").check();
// Brennstoff und Einheit 2
const brennstoffKombo2 = fuelList[faker.number.int({ min: 0, max: fuelList.length - 1 })];
cy.get("select[name='brennstoff_2']").select(brennstoffKombo2[0]);
cy.get("select[name='einheit_2']").select(brennstoffKombo2[1]);
// Verbrauch
cy.get("input[name='verbrauch_4']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
cy.get("input[name='verbrauch_5']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
cy.get("input[name='verbrauch_6']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
}
// Warmwasser enthalten und bekannt
const warmwasserEnthalten = Math.random() > 0.5;
const anteilBekannt = Math.random() > 0.5;
if (warmwasserEnthalten) {
cy.get("input[name='warmwasser_enthalten']").check();
if (anteilBekannt) {
// Der Anteil ist bekannt, wir müssen ihn also angeben.
cy.get("input[name='warmwasser_anteil_bekannt']").check();
cy.get("input[name='anteil_warmwasser_1']").type(faker.number.int({ min: 0, max: 50 }).toString());
if (zusaetzlicheHeizquelle) {
// Zusätzliche Heizquelle existiert, also müssen wir auch hier den Anteil angeben.
cy.get("input[name='anteil_warmwasser_2']").type(faker.number.int({ min: 0, max: 50 }).toString());
}
}
}
// Alternative Energieversorgungssysteme
if (Math.random() > 0.5) cy.get("input[name='alternative_heizung']").check();
if (Math.random() > 0.5) cy.get("input[name='alternative_warmwasser']").check();
if (Math.random() > 0.5) cy.get("input[name='alternative_lueftung']").check();
if (Math.random() > 0.5) cy.get("input[name='alternative_kuehlung']").check();
// Gebäudetyp
cy.get("select[name='gebaeudetyp']").then(($dropdown) => {
const options = $dropdown.find('option');
// Select the option at the random index
cy.get("select[name='gebaeudetyp']").select(options.eq(faker.number.int({ min: 1, max: options.length - 1 })).val() as string);
});
// Gebäudeteil
cy.get("select[name='gebaeudeteil']").then(($dropdown) => {
const options = $dropdown.find('option');
// Select the option at the random index
cy.get("select[name='gebaeudeteil']").select(options.eq(faker.number.int({ min: 1, max: options.length - 1 })).val() as string);
});
// Lüftung
cy.get("select[name='lueftung']").then(($dropdown) => {
const options = $dropdown.find('option');
// Select the option at the random index
cy.get("select[name='lueftung']").select(options.eq(faker.number.int({ min: 1, max: options.length - 1 })).val() as string);
});
// Kühlung
cy.get("select[name='kuehlung']").then(($dropdown) => {
const options = $dropdown.find('option');
// Select the option at the random index
cy.get("select[name='kuehlung']").select(options.eq(faker.number.int({ min: 1, max: options.length - 1 })).val() as string);
});
// Leerstand
cy.get("input[name='leerstand']").should("have.attr", "type", "number").type(faker.number.int({ min: 0, max: 30 }).toString());
// Heizungsanlage Daten
if (Math.random() > 0.5) cy.get("input[name='zentralheizung']").check();
if (Math.random() > 0.5) cy.get("input[name='einzelofen']").check();
if (Math.random() > 0.5) cy.get("input[name='durchlauf_erhitzer']").check();
if (Math.random() > 0.5) cy.get("input[name='standard_kessel']").check();
if (Math.random() > 0.5) cy.get("input[name='solarsystem_warmwasser']").check();
if (Math.random() > 0.5) cy.get("input[name='waermepumpe']").check();
if (Math.random() > 0.5) cy.get("input[name='niedertemperatur_kessel']").check();
if (Math.random() > 0.5) cy.get("input[name='brennwert_kessel']").check();
if (Math.random() > 0.5) cy.get("input[name='warmwasser_rohre_gedaemmt']").check();
if (Math.random() > 0.5) cy.get("input[name='heizungsrohre_gedaemmt']").check();
if (Math.random() > 0.5) cy.get("input[name='zirkulation']").check();
if (Math.random() > 0.5) cy.get("input[name='raum_temperatur_regler']").check();
// Heizungsanlage Bilder
cy.get("input[name='heizung_image']").should("have.attr", "type", "file").attachFile("images/heizungsanlage/1.jpeg", { subjectType: "input" });
cy.get("input[name='heizung_image']").should("have.attr", "type", "file").attachFile("images/heizungsanlage/2.jpeg", { subjectType: "input" });
// Fenster Daten
if (Math.random() > 0.5) cy.get("input[name='einfach_verglasung']").check();
if (Math.random() > 0.5) cy.get("input[name='doppel_verglasung']").check();
if (Math.random() > 0.5) cy.get("input[name='isolier_verglasung']").check();
if (Math.random() > 0.5) cy.get("input[name='dreifach_verglasung']").check();
if (Math.random() > 0.5) cy.get("input[name='fenster_dicht']").check();
if (Math.random() > 0.5) cy.get("input[name='fenster_teilweise_undicht']").check();
if (Math.random() > 0.5) cy.get("input[name='tueren_dicht']").check();
if (Math.random() > 0.5) cy.get("input[name='tueren_undicht']").check();
if (Math.random() > 0.5) cy.get("input[name='rolllaeden_kaesten_gedaemmt']").check();
// Fenster Bilder
cy.get("input[name='fenster_image']").should("have.attr", "type", "file").attachFile("images/fenster/1.jpeg", { subjectType: "input" });
cy.get("input[name='fenster_image']").should("have.attr", "type", "file").attachFile("images/fenster/2.jpeg", { subjectType: "input" });
// Wärmedämmung Daten
if (Math.random() > 0.5) cy.get("input[name='aussenwand_gedaemmt']").check();
if (Math.random() > 0.5) cy.get("input[name='keller_wand_gedaemmt']").check();
if (Math.random() > 0.5) cy.get("input[name='keller_decke_gedaemmt']").check();
if (Math.random() > 0.5) cy.get("input[name='dachgeschoss_gedaemmt']").check();
if (Math.random() > 0.5) cy.get("input[name='oberste_geschossdecke_gedaemmt']").check();
if (Math.random() > 0.5) cy.get("input[name='oberste_geschossdecke_min_12cm_gedaemmt']").check();
// Wärmedämmung Bilder
cy.get("input[name='daemmung_image']").should("have.attr", "type", "file").attachFile("images/daemmung/1.jpeg", { subjectType: "input" });
cy.get("input[name='daemmung_image']").should("have.attr", "type", "file").attachFile("images/daemmung/2.jpeg", { subjectType: "input" });
// Gebäude Bild
cy.get("input[name='gebaeude_image']").should("have.attr", "type", "file").attachFile("images/gebaeude/1.jpeg", { subjectType: "input" });
// Jetzt können wir den Verbrauchsausweis erstellen.
cy.get("form[name='ausweis'] button[type='submit']").click({ force: true });
// Wir sind nicht eingeloggt also sollte jetzt ein Login Screen erscheinen.
// Wir klicken auf registrieren und erstellen einen neuen Benutzer, danach loggen wir uns mit diesem ein.
cy.get("button[name='registrieren']").click();
const email = faker.internet.email();
const passwort = "test1234";
const vorname = faker.person.firstName();
const nachname = faker.person.lastName();
cy.get("form[name='signup'] input[name='email']").should("be.visible").should("have.attr", "type", "email").type(email);
cy.get("form[name='signup'] input[name='passwort']").should("be.visible").should("have.attr", "type", "password").type(passwort);
cy.get("form[name='signup'] input[name='vorname']").should("be.visible").should("have.attr", "type", "text").type(vorname);
cy.get("form[name='signup'] input[name='nachname']").should("be.visible").should("have.attr", "type", "text").type(nachname);
cy.get("form[name='signup'] button[type='submit']").click();
// Wir sind jetzt registriert und können uns nun einloggen.
// Die Email sollte automatisch eingetragen sein, da wir uns gerade registriert haben.
cy.get("form[name='login'] input[name='email']").should("be.visible").should("have.attr", "type", "email").should("contain.value", email);
cy.get("form[name='login'] input[name='passwort']").should("be.visible").should("have.attr", "type", "password").type(passwort);
cy.get("form[name='login'] button[type='submit']").click();
// Der Ausweis sollte jetzt schon erstellt worden sein und wir sollten auf die kundendaten seite weitergeleitet worden sein.
cy.url().should("contain", "/kundendaten");
cy.wait(1000)
// Wir füllen jetzt die Kundendaten aus.
cy.get("select[name='anrede']").select(Math.random() > 0.5 ? "Herr" : "Frau");
cy.get("input[name='vorname']").should("contain.value", vorname);
cy.get("input[name='name']").should("contain.value", nachname);
cy.get("input[name='email']").should("contain.value", email);
cy.get("input[name='telefon']").type(faker.phone.number());
cy.get("input[name='rechnung_empfaenger']").type(`${vorname} ${nachname}`);
cy.get("input[name='rechnung_strasse']").type(faker.location.streetAddress());
// TODO: Random Plz generieren, allerdings muss die auch in der Datenbank vorhanden sein...
cy.get("input[name='rechnung_plz']").type("2103");
// Jetzt sollte der PLZ Container erscheinen, dort klicken wir einfach das erste Element an.
cy.get("div[data-test='plz-container']").children().first().click();
cy.get("input[name='rechnung_telefon']").type(faker.phone.number());
cy.get("input[name='rechnung_email']").type(faker.internet.email());
cy.get("button[data-test='paypal']").click();
// Datenschutz und AGB akzeptieren, dann schicken wir das Formular ab.
cy.get("input[name='agb-akzeptieren']").check()
cy.get("input[name='datenschutz-akzeptieren']").check()
cy.get("button[type='submit']").click();
cy.origin('https://www.mollie.com', () => {
// Jetzt sind wir auf der Mollie Seite, dort wählen wir den "paid" status aus
cy.get("input[type='radio'][name='final_state'][value='paid']").check();
// Da wird unser Test fehlschlagen, da die localhost domain von Mollie aus nicht erreichbar ist.
})
});
});

View File

@@ -75,6 +75,7 @@
"bun-types": "^1.1.45", "bun-types": "^1.1.45",
"cypress": "^13.17.0", "cypress": "^13.17.0",
"cypress-file-upload": "^5.0.8", "cypress-file-upload": "^5.0.8",
"cypress-vite": "^1.6.0",
"daisyui": "^4.12.23", "daisyui": "^4.12.23",
"eslint": "~8.15.0", "eslint": "~8.15.0",
"eslint-config-prettier": "8.1.0", "eslint-config-prettier": "8.1.0",

View File

@@ -4,12 +4,13 @@ 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"),
"ticket": await import("../src/pages/api/ticket.ts"), "ticket": await import("../src/pages/api/ticket.ts"),
"bedarfsausweis-wohnen": await import("../src/pages/api/bedarfsausweis-wohnen/index.ts"),
"aufnahme/[uid]": await import("../src/pages/api/aufnahme/[uid].ts"), "aufnahme/[uid]": await import("../src/pages/api/aufnahme/[uid].ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"), "aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"bedarfsausweis-wohnen": await import("../src/pages/api/bedarfsausweis-wohnen/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/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"), "auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"),
"objekt": await import("../src/pages/api/objekt/index.ts"), "objekt": await import("../src/pages/api/objekt/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": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.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"),

View File

@@ -13,8 +13,7 @@ export async function verbrauchsausweisWohnenSpeichern(
ausweis: VerbrauchsausweisWohnenClient, ausweis: VerbrauchsausweisWohnenClient,
objekt: ObjektClient, objekt: ObjektClient,
aufnahme: AufnahmeClient, aufnahme: AufnahmeClient,
images: (UploadedGebaeudeBild & { base64?: string })[], bilder: (UploadedGebaeudeBild & { base64?: string })[]
user: BenutzerClient
) { ) {
if (objekt.uid) { if (objekt.uid) {
await api.objekt._uid.PATCH.fetch({ await api.objekt._uid.PATCH.fetch({
@@ -87,6 +86,26 @@ export async function verbrauchsausweisWohnenSpeichern(
}) })
} }
for (const bild of bilder) {
if (bild.uid) {
continue;
}
const response = await api.objekt._uid.bilder.PUT.fetch({
base64: bild.base64,
kategorie: bild.kategorie
}, {
params: {
uid: objekt.uid
},
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
bild.uid = response.uid
}
return { return {
uid_ausweis: ausweis.uid, uid_ausweis: ausweis.uid,
uid_aufnahme: aufnahme.uid, uid_aufnahme: aufnahme.uid,

View File

@@ -7,6 +7,7 @@ import {
VerbrauchsausweisGewerbe, VerbrauchsausweisGewerbe,
VerbrauchsausweisWohnen, VerbrauchsausweisWohnen,
} from "@ibcornelsen/database/client"; } from "@ibcornelsen/database/client";
import { z, ZodSchema } from "zod";
type OmitKeys<T, K extends keyof T> = Omit<T, K>; type OmitKeys<T, K extends keyof T> = Omit<T, K>;
@@ -78,6 +79,14 @@ export type ObjektClient = OmitKeys<Objekt, "benutzer_id" | "id">;
export type AufnahmeClient = OmitKeys< export type AufnahmeClient = OmitKeys<
Aufnahme, Aufnahme,
"id" | "objekt_id" | "benutzer_id" "id" | "objekt_id" | "benutzer_id"
>; > & {
uid_objekt: string
};
export type BenutzerClient = OmitKeys<Benutzer, "id" | "passwort">; export type BenutzerClient = OmitKeys<Benutzer, "id" | "passwort">;
type ZodOverlapType<T> = z.ZodType<T, z.ZodTypeDef, T>;
export function ZodOverlap<T, S = z.ZodType<T, z.ZodTypeDef, T>>(arg: S): S {
return arg;
}

View File

@@ -1,8 +0,0 @@
---
const currentYear = new Date().getFullYear();
---
<div class="flex flex-row justify-between px-4 items-center bg-primary py-2 mt-auto">
<a class="text-white font-medium text-lg" href="/impressum">Impressum und Datenschutz</a>
<a class="text-white font-medium text-lg" href="/">© {currentYear} IB Cornelsen Hamburg.</a>
</div>

View File

@@ -1,67 +0,0 @@
---
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
import ThemeController from "./ThemeController.svelte";
const valid = await validateAccessTokenServer(Astro)
const lightTheme = Astro.cookies.get("theme")?.value === "light";
---
<header>
<a class="hidden md:block w-full h-48 bg-base-200" href="/">
<img
src="/images/header/header-bg.jpg"
class="w-full h-full object-cover"
alt="Hintergrund - Rollen Architektenpapier"
/>
<img
src="/images/header/logo-big.svg"
class="absolute top-4 right-0 w-[464px]"
alt="IBCornelsen - Logo"
/>
<h2
class="text-secondary font-semibold text-2xl absolute top-8 right-4"
>
Energieausweis online erstellen
</h2>
<h2
class="text-primary font-semibold text-xl absolute top-16 right-4"
>
Energieausweise nach aktueller GEG
</h2>
</a>
<div class="px-4 flex flex-row w-full md:justify-end items-center bg-primary">
<a
class="header-button hidden md:block"
href="/energieausweis-erstellen/verbrauchsausweis-erstellen"
>Energieausweis erstellen</a
>
<a class="header-button hidden md:block" href="/kontakt"
>Kontakt</a
>
<a class="header-button hidden md:block" href="/agb">AGB</a>
{
valid ? (
<a class="header-button" href="/dashboard">
Profil
</a>
) : (
<a class="header-button" href="/auth/login">
Login
</a>
)
}
<ThemeController lightTheme={lightTheme} client:load />
<a class="hamburger_menu"
><img src="/images/hamburger.png" width="22" alt="hamburger" /></a
>
</div>
</header>
<style>
.header-button {
@apply px-4 py-2 text-primary-content font-medium text-lg tracking-normal hover:bg-secondary h-full;
}
</style>

View File

@@ -1,5 +1,5 @@
--- ---
import CardNavigation from "#components/design/sidebars/cards/cardNavigation.svelte"; import NavigationCard from "#components/design/sidebars/cards/NavigationCard.svelte";
import CardPriceiInfo from "#components/design/sidebars/cards/cardPriceiInfo.svelte"; import CardPriceiInfo from "#components/design/sidebars/cards/cardPriceiInfo.svelte";
import CardProduktSidebar from "#components/design/sidebars/cards/CardProduktSidebar.svelte"; import CardProduktSidebar from "#components/design/sidebars/cards/CardProduktSidebar.svelte";
@@ -9,7 +9,7 @@ import { PRICES } from "#lib/constants";
<div class=""> <div class="">
<CardNavigation client:load/> <NavigationCard client:load/>
<CardProduktSidebar art="Verbrauchsausweis Gewerbe" price={PRICES.VerbrauchsausweisGewerbe[0]}></CardProduktSidebar> <CardProduktSidebar art="Verbrauchsausweis Gewerbe" price={PRICES.VerbrauchsausweisGewerbe[0]}></CardProduktSidebar>
<CardPriceiInfo /> <CardPriceiInfo />

View File

@@ -1,5 +1,5 @@
--- ---
import CardContact from "#components/design/sidebars/cards/cardContact.svelte"; import CardContact from "#components/design/sidebars/cards/ContactCard.svelte";
import CardPriceiInfo from "#components/design/sidebars/cards/cardPriceiInfo.svelte"; import CardPriceiInfo from "#components/design/sidebars/cards/cardPriceiInfo.svelte";
import CardProduktSidebar from "#components/design/sidebars/cards/CardProduktSidebar.svelte"; import CardProduktSidebar from "#components/design/sidebars/cards/CardProduktSidebar.svelte";

View File

@@ -1,4 +1,4 @@
<div id ="cardContact" class="box card"> <div class="box card">
<div class="grid grid-cols-[max-content,1fr] gap-x-2 border-b-[1px] pb-2 mb-4"> <div class="grid grid-cols-[max-content,1fr] gap-x-2 border-b-[1px] pb-2 mb-4">

View File

@@ -23,7 +23,6 @@
</script> </script>
<div <div
id="cardLogin"
class="box card" class="box card"
> >
<div class="grid"> <div class="grid">

View File

@@ -0,0 +1,455 @@
<script lang="ts">
let innerWidth: number;
function dropdown() {
if (innerWidth < 1024) {
const check_element = this.lastChild;
const rotate_list = document.querySelectorAll(".dd-symbol-clone");
const rotate_element = this.childNodes[0].children[0];
var first_check = check_element.classList.contains(
"show-dropdown-content"
);
const nodeList = document.querySelectorAll(".dropdown-content");
if (first_check == true) {
check_element.classList.remove("show-dropdown-content");
rotate_element.classList.toggle("rotate-symbol");
} else {
for (let i = 0; i < nodeList.length; i++) {
const element = nodeList[i];
element.classList.remove("show-dropdown-content");
}
for (let i = 0; i < rotate_list.length; i++) {
const element = rotate_list[i];
element.classList.remove("rotate-symbol");
}
check_element.classList.add("show-dropdown-content");
rotate_element.classList.add("rotate-symbol");
}
}
}
function hover() {
if (innerWidth > 1024) {
const check_element = this.firstChild.lastChild;
check_element.style.visibility = "visible";
}
}
function hoverout() {
if (innerWidth > 1024) {
const check_element = this.firstChild.lastChild;
check_element.style.visibility = "hidden";
}
}
function hamburger() {
const nodeList = document.querySelectorAll(".dropdown-content");
for (let i = 0; i < nodeList.length; i++) {
nodeList[i].classList.remove("show-dropdown-content");
}
var element = document.getElementById("cardNavigation");
element.classList.toggle("hidden");
const spans = this.children;
var first_check = spans[0].classList.contains("hamburger-swing-0");
if (first_check == true) {
for (let i = 0; i < spans.length; i++) {
spans[i].classList.remove("hamburger-swing-" + i);
}
const rotate_list = document.querySelectorAll(".dd-symbol");
for (let i = 0; i < rotate_list.length; i++) {
rotate_list[i].classList.remove("rotate-symbol");
}
} else {
for (let i = 0; i < spans.length; i++) {
spans[i].classList.add("hamburger-swing-" + i);
}
}
}
</script>
<svelte:window bind:innerWidth />
<div
class="hamburger_menu py-1 px-2 bg-secondary
xs:px-4
lg:hidden"
>
<div
id="hamburger"
on:click={hamburger}
on:keydown={hamburger}
class="cursor-pointer"
>
<span></span>
<span></span>
<span></span>
</div>
</div>
<nav
id="cardNavigation"
class="cardNavigation box hidden relative ring-0 md:ring-2 ring-primary/50 rounded-tr-none lg:block mb-0 lg:mb-5"
>
<div class="nav-element bg-secondary/5 py-1 pl-2 text-xs font-bold">
Jetzt bestellen
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/welcher-energieausweis/"
>Welcher Energieausweis?</a
>
</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div
class="nav-element dropdown lg:dropdown-right"
on:click={dropdown}
on:keydown={dropdown}
on:mouseover={hover}
on:mouseleave={hoverout}
>
{#if innerWidth > 1023}
<a href={undefined} class="nav-element-child"
>Energieausweis erstellen<span class="dd-symbol-clone"></span
><span class="dd-symbol"></span></a
>
{:else}
<a href={undefined} class="nav-element-child"
>Energieausweis erstellen<span class="dd-symbol-clone"></span
><span class="dd-symbol"></span></a
>
{/if}
<ul class="dropdown-content energieasusweis-erstellen">
{#if innerWidth < 1023}
<li>
<a href="/energieausweis-erstellen"
>Energieausweis erstellen</a
>
</li>
{/if}
<li>
<a
href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/"
>Verbrauchsausweis erstellen</a
>
</li>
<li>
<a href="/energieausweis-erstellen/bedarfsausweis-wohngebaeude/"
>Bedarfsausweis erstellen</a
>
</li>
<li>
<a href="/energieausweis-erstellen/verbrauchsausweis-gewerbe/"
>Verbrauchsausweis Gewerbe erstellen</a
>
</li>
</ul>
</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div
class="nav-element dropdown lg:dropdown-right"
on:click={dropdown}
on:keydown={dropdown}
on:mouseover={hover}
on:mouseleave={hoverout}
>
{#if innerWidth > 1023}
<a href={undefined} class="nav-element-child"
>Angebot anfragen<span class="dd-symbol-clone"></span><span
class="dd-symbol"></span
></a
>
{:else}
<a href={undefined} class="nav-element-child"
>Angebot anfragen<span class="dd-symbol-clone"></span><span
class="dd-symbol"></span
></a
>
{/if}
<ul class="dropdown-content angebot-anfragen">
{#if innerWidth < 1023}
<li>
<a href="/energieausweis-erstellen">Angebot anfragen</a>
</li>
{/if}
<li>
<a
href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/"
>Bedarfsausweis Gewerbe anfragen</a
>
</li>
<li>
<a href="/energieausweis-erstellen/bedarfsausweis-wohngebaeude/"
>GEG Nachweis Wohnen anfragen</a
>
</li>
<li>
<a href="/energieausweis-erstellen/verbrauchsausweis-gewerbe/"
>GEG Nachweis Gewerbe anfragen</a
>
</li>
</ul>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/sanierungsfahrplan"
>Sanierungsfahrplan (iSFP)</a
>
</div>
<div class="nav-element bg-secondary/5 py-1 pl-2 text-xs font-bold">
Produkte & Preise
</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div
class="nav-element dropdown lg:dropdown-right"
on:click={dropdown}
on:keydown={dropdown}
on:mouseover={hover}
on:mouseleave={hoverout}
>
<a href={undefined} class="nav-element-child"
>Verbrauchsausweis<span class="dd-symbol-clone"></span><span
class="dd-symbol"></span
></a
>
<ul class="dropdown-content verbrauchsausweis">
{#if innerWidth < 1023}
<li><a href="index">Verbrauchsausweis</a></li>
{/if}
<li><a href="index">Verbrauchsausweis Wohngebäude</a></li>
<li><a href="index">Verbrauchsausweis online erstellen</a></li>
<li><a href="index">Häufige Fragen zum Verbrauchsausweis</a></li>
<li>
<a href="index">Statistiken zum Verbrauchsausweis Wohngebäude</a
>
</li>
<li><a href="index">Verbrauchsausweis Gewerbe</a></li>
<li>
<a href="index">Verbrauchsausweis Gewerbe online erstellen</a>
</li>
<li>
<a href="index">Häufige Fragen zum Verbrauchsausweis Gewerbe</a>
</li>
<li>
<a href="index">Statistiken zum Verbrauchsausweis Gewerbe</a>
</li>
</ul>
</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div
class="nav-element dropdown lg:dropdown-right"
on:click={dropdown}
on:keydown={dropdown}
on:mouseover={hover}
on:mouseleave={hoverout}
>
<a href={undefined} class="nav-element-child"
>Bedarfsausweis<span class="dd-symbol-clone"></span><span
class="dd-symbol"></span
></a
>
<ul class="dropdown-content bedarfsausweis">
{#if innerWidth < 1023}
<li><a href="index">Bedarfsausweis</a></li>
{/if}
<li><a href="index">Bedarfsausweis Wohngebäude</a></li>
<li><a href="index">Bedarfsausweis online erstellen</a></li>
<li><a href="index">Häufige Fragen zum Bedarfsausweis</a></li>
<li>
<a href="index">Statistiken zum Bedarfsausweis Wohngebäude</a>
</li>
<li><a href="index">Bedarfsausweis Gewerbe</a></li>
<li><a href="index">Bedarfsausweis Gewerbe online erstellen</a></li>
<li>
<a href="index">Häufige Fragen zum Bedarfsausweis Gewerbe</a>
</li>
<li><a href="index">Statistiken zum Bedarfsausweis Gewerbe</a></li>
</ul>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/sanierungsfahrplan"
>Sanierungsfahrplan</a
>
</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div
class="nav-element dropdown lg:dropdown-right"
on:click={dropdown}
on:keydown={dropdown}
on:mouseover={hover}
on:mouseleave={hoverout}
>
<a href={undefined} class="nav-element-child"
>Energieausweis<span class="dd-symbol-clone"></span><span
class="dd-symbol"></span
></a
>
<ul class="dropdown-content energieausweis">
{#if innerWidth < 1023}
<li><a href="index">Energieausweis</a></li>
{/if}
<li><a href="index">Energieausweis Pflicht</a></li>
<li><a href="index">Energieausweis Kosten</a></li>
<li><a href="index">Energieausweis Haus</a></li>
</ul>
</div>
<div class="nav-element">
<a
class="no-dropdown nav-element-child"
href="/energieausweis-aussteller">Energieberater finden</a
>
</div>
<div class="nav-element bg-secondary/5 py-1 pl-2 text-xs font-bold">
FAQ & Hilfe
</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div
class="nav-element dropdown lg:dropdown-right"
on:click={dropdown}
on:keydown={dropdown}
on:mouseover={hover}
on:mouseleave={hoverout}
>
{#if innerWidth > 1023}
<a href="/bestellprozess-energieausweis" class="nav-element-child"
>Bestellprozess Energieausweis<span class="dd-symbol-clone"
></span
><span class="dd-symbol"></span></a
>
{:else}
<a href="/bestellprozess-energieausweis" class="nav-element-child"
>Bestellprozess Energieausweis<span class="dd-symbol-clone"
></span
><span class="dd-symbol"></span></a
>
{/if}
<ul class="dropdown-content bestellprozess-energieausweis">
{#if innerWidth < 1023}
<li>
<a href="/bestellprozess-energieausweis"
>Bestellprozess Energieausweis</a
>
</li>
{/if}
<li>
<a
href="/bestellprozess-energieausweis/merkblatt-verbrauchsausweis-wohnen/"
>Merkblatt Verbrauchsausweis Wohnen</a
>
</li>
<li>
<a href="/energieausweis-erstellen/bedarfsausweis-wohngebaeude/"
>Merkblatt Bedarfsausweis Wohnen</a
>
</li>
<li>
<a href="/energieausweis-erstellen/verbrauchsausweis-gewerbe/"
>Merkblatt Verbrauchsausweis Gewerbe</a
>
</li>
</ul>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/geg/"
>Gebäudeenergiegesetz (GEG)</a
>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/enev-zusammenfassung/"
>EnEV Zusammenfassung - Archiv</a
>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/faq/">FAQ</a>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/glossar/">Glossar</a>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/kundenbewertungen/"
>Kundenbewertungen</a
>
</div>
<div class="nav-element">
<a
class="no-dropdown nav-element-child lg:!rounded-b-lg xl:!rounded-b-xl"
href="/fuer-entwickler/">Für Entwickler</a
>
</div>
</nav>
<style lang="scss">
.dd-symbol::before {
content: "";
font-size: 0.95rem;
position: absolute;
top: 0px;
left: -7px;
animation-name: flim;
animation-duration: 2s;
animation-iteration-count: infinite;
}
.dd-symbol {
visibility: hidden;
}
.dd-symbol::after {
content: "";
font-size: 0.95rem;
position: absolute;
top: 0px;
right: -7px;
animation-name: flim;
animation-duration: 2s;
animation-delay: 1s;
animation-iteration-count: infinite;
}
@keyframes flim {
0% {
opacity: 0;
}
16.66% {
opacity: 0.25;
}
33.32% {
opacity: 0.5;
}
49.98% {
opacity: 0.75;
}
66.64% {
opacity: 0.5;
}
83.33% {
opacity: 0.25;
}
100% {
opacity: 0;
}
}
</style>

View File

@@ -1,286 +0,0 @@
<script>
let innerWidth
function dropdown(){
const innerWidth = window.innerWidth;
if(innerWidth<1024){
const check_element = this.lastChild;
const rotate_list = document.querySelectorAll(".dd-symbol-clone");
const rotate_element = this.childNodes[0].children[0];
var first_check = check_element.classList.contains("show-dropdown-content");
const nodeList = document.querySelectorAll(".dropdown-content");
if(first_check == true){
check_element.classList.remove("show-dropdown-content");
rotate_element.classList.toggle("rotate-symbol");
}else{
for (let i = 0; i < nodeList.length; i++) {
const element = nodeList[i];
element.classList.remove("show-dropdown-content");
}
for (let i = 0; i < rotate_list.length; i++) {
const element = rotate_list[i];
element.classList.remove("rotate-symbol");
}
check_element.classList.add("show-dropdown-content");
rotate_element.classList.add("rotate-symbol");
}
}
}
function hover(){
const innerWidth = window.innerWidth;
if(innerWidth>1024){
const check_element = this.firstChild.lastChild;
check_element.style.visibility = "visible";
}
}
function hoverout(){
const innerWidth = window.innerWidth;
if(innerWidth>1024){
const check_element = this.firstChild.lastChild;
check_element.style.visibility = "hidden";
}
}
function hamburger(){
const nodeList = document.querySelectorAll(".dropdown-content");
for (let i = 0; i < nodeList.length; i++) {
nodeList[i].classList.remove("show-dropdown-content");}
var element = document.getElementById("cardNavigation");
element.classList.toggle("hidden");
const spans = this.children;
var first_check = spans[0].classList.contains("hamburger-swing-0");
if(first_check == true){
for (let i = 0; i < spans.length; i++)
{spans[i].classList.remove("hamburger-swing-"+i);}
const rotate_list = document.querySelectorAll(".dd-symbol");
for (let i = 0; i < rotate_list.length; i++)
{rotate_list[i].classList.remove("rotate-symbol");}
}else{
for (let i = 0; i < spans.length; i++)
{spans[i].classList.add("hamburger-swing-"+i);} }
}
</script>
<svelte:window bind:innerWidth />
<div class="hamburger_menu py-1 px-2 bg-secondary
xs:px-4
lg:hidden">
<div id="hamburger" on:click={hamburger} on:keydown={hamburger} class="cursor-pointer">
<span></span>
<span></span>
<span></span>
</div>
</div>
<nav id="cardNavigation" class="cardNavigation box hidden relative ring-0 md:ring-2 ring-primary/50 rounded-tr-none lg:block mb-0 lg:mb-5">
<div class="nav-element bg-secondary/5 py-1 pl-2 text-xs font-bold">Jetzt bestellen</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/welcher-energieausweis/">Welcher Energieausweis?</a>
</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div class="nav-element dropdown lg:dropdown-right" on:click={dropdown} on:keydown={dropdown} on:mouseover={hover} on:mouseleave={hoverout}>
{#if innerWidth > 1023}
<a href={undefined} class="nav-element-child" >Energieausweis erstellen<span class="dd-symbol-clone"></span><span class="dd-symbol"></span></a>
{:else}
<a href={undefined} class="nav-element-child">Energieausweis erstellen<span class="dd-symbol-clone"></span><span class="dd-symbol"></span></a>
{/if}
<ul class="dropdown-content energieasusweis-erstellen">
{#if innerWidth < 1023}
<li><a href="/energieausweis-erstellen">Energieausweis erstellen</a></li>
{/if}
<li><a href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/">Verbrauchsausweis erstellen</a></li>
<li><a href="/energieausweis-erstellen/bedarfsausweis-wohngebaeude/">Bedarfsausweis erstellen</a></li>
<li><a href="/energieausweis-erstellen/verbrauchsausweis-gewerbe/">Verbrauchsausweis Gewerbe erstellen</a></li>
</ul>
</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div class="nav-element dropdown lg:dropdown-right" on:click={dropdown} on:keydown={dropdown} on:mouseover={hover} on:mouseleave={hoverout}>
{#if innerWidth > 1023}
<a href={undefined} class="nav-element-child" >Angebot anfragen<span class="dd-symbol-clone"></span><span class="dd-symbol"></span></a>
{:else}
<a href={undefined} class="nav-element-child">Angebot anfragen<span class="dd-symbol-clone"></span><span class="dd-symbol"></span></a>
{/if}
<ul class="dropdown-content angebot-anfragen">
{#if innerWidth < 1023}
<li><a href="/energieausweis-erstellen">Angebot anfragen</a></li>
{/if}
<li><a href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/">Bedarfsausweis Gewerbe anfragen</a></li>
<li><a href="/energieausweis-erstellen/bedarfsausweis-wohngebaeude/">GEG Nachweis Wohnen anfragen</a></li>
<li><a href="/energieausweis-erstellen/verbrauchsausweis-gewerbe/">GEG Nachweis Gewerbe anfragen</a></li>
</ul>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/sanierungsfahrplan">Sanierungsfahrplan (iSFP)</a>
</div>
<div class="nav-element bg-secondary/5 py-1 pl-2 text-xs font-bold">Produkte & Preise</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div class="nav-element dropdown lg:dropdown-right" on:click={dropdown} on:keydown={dropdown} on:mouseover={hover} on:mouseleave={hoverout}>
<a href={undefined} class="nav-element-child">Verbrauchsausweis<span class="dd-symbol-clone"></span><span class="dd-symbol"></span></a>
<ul class="dropdown-content verbrauchsausweis">
{#if innerWidth < 1023}
<li><a href="index">Verbrauchsausweis</a></li>
{/if}
<li><a href="index">Verbrauchsausweis Wohngebäude</a></li>
<li><a href="index">Verbrauchsausweis online erstellen</a></li>
<li><a href="index">Häufige Fragen zum Verbrauchsausweis</a></li>
<li><a href="index">Statistiken zum Verbrauchsausweis Wohngebäude</a></li>
<li><a href="index">Verbrauchsausweis Gewerbe</a></li>
<li><a href="index">Verbrauchsausweis Gewerbe online erstellen</a></li>
<li><a href="index">Häufige Fragen zum Verbrauchsausweis Gewerbe</a></li>
<li><a href="index">Statistiken zum Verbrauchsausweis Gewerbe</a></li>
</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div class="nav-element dropdown lg:dropdown-right" on:click={dropdown} on:keydown={dropdown} on:mouseover={hover} on:mouseleave={hoverout}>
<a href={undefined} class="nav-element-child">Bedarfsausweis<span class="dd-symbol-clone"></span><span class="dd-symbol"></span></a>
<ul class="dropdown-content bedarfsausweis">
{#if innerWidth < 1023}
<li><a href="index">Bedarfsausweis</a></li>
{/if}
<li><a href="index">Bedarfsausweis Wohngebäude</a></li>
<li><a href="index">Bedarfsausweis online erstellen</a></li>
<li><a href="index">Häufige Fragen zum Bedarfsausweis</a></li>
<li><a href="index">Statistiken zum Bedarfsausweis Wohngebäude</a></li>
<li><a href="index">Bedarfsausweis Gewerbe</a></li>
<li><a href="index">Bedarfsausweis Gewerbe online erstellen</a></li>
<li><a href="index">Häufige Fragen zum Bedarfsausweis Gewerbe</a></li>
<li><a href="index">Statistiken zum Bedarfsausweis Gewerbe</a></li>
</ul>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/sanierungsfahrplan">Sanierungsfahrplan</a>
</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div class="nav-element dropdown lg:dropdown-right" on:click={dropdown} on:keydown={dropdown} on:mouseover={hover} on:mouseleave={hoverout}>
<a href={undefined} class="nav-element-child">Energieausweis<span class="dd-symbol-clone"></span><span class="dd-symbol"></span></a>
<ul class="dropdown-content energieausweis">
{#if innerWidth < 1023}
<li><a href="index">Energieausweis</a></li>
{/if}
<li><a href="index">Energieausweis Pflicht</a></li>
<li><a href="index">Energieausweis Kosten</a></li>
<li><a href="index">Energieausweis Haus</a></li>
</ul>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/energieausweis-aussteller">Energieberater finden</a>
</div>
<div class="nav-element bg-secondary/5 py-1 pl-2 text-xs font-bold">FAQ & Hilfe</div>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div class="nav-element dropdown lg:dropdown-right" on:click={dropdown} on:keydown={dropdown} on:mouseover={hover} on:mouseleave={hoverout}>
{#if innerWidth > 1023}
<a href="/bestellprozess-energieausweis" class="nav-element-child" >Bestellprozess Energieausweis<span class="dd-symbol-clone"></span><span class="dd-symbol"></span></a>
{:else}
<a href="/bestellprozess-energieausweis" class="nav-element-child">Bestellprozess Energieausweis<span class="dd-symbol-clone"></span><span class="dd-symbol"></span></a>
{/if}
<ul class="dropdown-content bestellprozess-energieausweis">
{#if innerWidth < 1023}
<li><a href="/bestellprozess-energieausweis">Bestellprozess Energieausweis</a></li>
{/if}
<li><a href="/bestellprozess-energieausweis/merkblatt-verbrauchsausweis-wohnen/">Merkblatt Verbrauchsausweis Wohnen</a></li>
<li><a href="/energieausweis-erstellen/bedarfsausweis-wohngebaeude/">Merkblatt Bedarfsausweis Wohnen</a></li>
<li><a href="/energieausweis-erstellen/verbrauchsausweis-gewerbe/">Merkblatt Verbrauchsausweis Gewerbe</a></li>
</ul>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/geg/">Gebäudeenergiegesetz (GEG)</a>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/enev-zusammenfassung/">EnEV Zusammenfassung - Archiv</a>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/faq/">FAQ</a>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/glossar/">Glossar</a>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child" href="/kundenbewertungen/">Kundenbewertungen</a>
</div>
<div class="nav-element">
<a class="no-dropdown nav-element-child lg:!rounded-b-lg xl:!rounded-b-xl"href="/fuer-entwickler/">Für Entwickler</a>
</div>
</nav>
<style lang="scss">
.dd-symbol::before{
content:'';
font-size:0.95rem;
position:absolute;
top:0px;
left:-7px;
animation-name: flim;
animation-duration: 2s;
animation-iteration-count: infinite;
}
.dd-symbol{visibility: hidden;}
.dd-symbol::after{
content:'';
font-size:0.95rem;
position:absolute;
top:0px;
right:-7px;
animation-name: flim;
animation-duration: 2s;
animation-delay: 1s;
animation-iteration-count: infinite;
}
@keyframes flim{
0% {opacity: 0;}
16.66% {opacity: 0.25;}
33.32% {opacity: 0.5;}
49.98% {opacity: 0.75;}
66.64% {opacity: 0.5;}
83.33% {opacity: 0.25;}
100% {opacity: 0;}
}
</style>

View File

@@ -1,253 +0,0 @@
<div class="flex flex-col gap-6">
<nav>
<div class="nav-card">
<div class="card-menu-option dropdown dropdown-right dropdown-hover">
<a href="/energieausweis-erstellen/verbrauchsausweis-wohnen"
>Energieausweis erstellen</a
>
<div class="dropdown-content">
<a href="/energieausweis-erstellen/verbrauchsausweis-wohnen">Verbrauchsausweis erstellen</a>
<a href="/bedarfsausweis">Bedarfsausweis erstellen</a>
<a href="/energieausweis-erstellen/verbrauchsausweis-gewerbe"
>Verbrauchsausweis Gewerbe erstellen</a
>
<a href="/bedarfsausweis-gewerbe"
>Bedarfsausweis Gewerbe anfragen</a
>
</div>
</div>
<a class="card-menu-option" href="/welcher-energieausweis"
>Welcher Energieausweis ?</a
>
<div class="card-menu-option dropdown dropdown-right dropdown-hover">
<a href="/energieausweis-erstellen/verbrauchsausweis-wohnen">Verbrauchsausweis</a>
<div class="dropdown-content">
<a
href="/energieausweis-erstellen/verbrauchsausweis-wohnenverbrauchsausweis-wohngebaeude"
>Verbrauchsausweis Wohngebäude</a
>
<a
href="/energieausweis-erstellen/verbrauchsausweis-erstellen"
>Verbrauchsausweis online erstellen</a
>
<a
href="/energieausweis-erstellen/verbrauchsausweis-wohnenhaeufige-fragen-zum-verbrauchsausweis"
>Häufige Fragen zum Verbrauchsausweis</a
>
<a
href="/energieausweis-erstellen/verbrauchsausweis-wohnenstatistiken-zum-verbrauchsausweis"
>Statistiken zum Verbrauchsausweis Wohngebäude</a
>
<hr class="nav-hr" />
<a href="/energieausweis-erstellen/verbrauchsausweis-wohnenverbrauchsausweis-gewerbe"
>Verbrauchsausweis Gewerbe</a
>
<a
href="/energieausweis-erstellen/verbrauchsausweis-gewerbe-erstellen"
>Verbrauchsausweis Gewerbe online erstellen</a
>
<a
href="/energieausweis-erstellen/verbrauchsausweis-wohnenhaeufige-fragen-zum-verbrauchsausweis-gewerbe"
>Häufige Fragen zum Verbrauchsausweis Gewerbe</a
>
<a
href="/energieausweis-erstellen/verbrauchsausweis-wohnenstatistiken-zum-verbrauchsausweis-gewerbe"
>Statistiken zum Verbrauchsausweis Gewerbe</a
>
</div>
</div>
<div class="card-menu-option dropdown dropdown-right dropdown-hover">
<a href="/bedarfsausweis/">Bedarfsausweis</a>
<div class="dropdown-content">
<a href="/bedarfsausweis/bedarfsausweis-wohngebaeude"
>Bedarfsausweis Wohngebäude</a
>
<a
href="/energieausweis-erstellen/bedarfsausweis-erstellen"
>Bedarfsausweis online erstellen</a
>
<a
href="/bedarfsausweis/haeufige-fragen-zum-bedarfsausweis"
>Häufige Fragen zum Bedarfsausweis</a
>
<a href="/bedarfsausweis/statistiken-zum-bedarfsausweis"
>Statistiken zum Bedarfsausweis Wohngebäude</a
>
<hr class="nav-hr" />
<a href="/bedarfsausweis/bedarfsausweis-gewerbe"
>Bedarfsausweis Gewerbe</a
>
<a
href="/energieausweis-erstellen/bedarfsausweis-gewerbe-anfragen"
>Bedarfsausweis Gewerbe anfragen</a
>
<a
href="/bedarfsausweis/haeufige-fragen-zum-bedarfsausweis-gewerbe"
>Häufige Fragen zum Bedarfsausweis Gewerbe</a
>
</div>
</div>
<div class="card-menu-option dropdown dropdown-right dropdown-hover">
<a href="/">Energieausweis</a>
<div class="dropdown-content">
<a href="/energieausweis-pflicht"
>Energieausweis Pflicht</a
>
<a href="/energieausweis-kosten"
>Energieausweis Kosten</a
>
<a href="/energieausweis-haus">Energieausweis Haus</a>
</div>
</div>
<a class="card-menu-option" href="/enev-zusammenfassung"
>EnEV Zusammenfassung - Archiv</a
>
<a class="card-menu-option" href="/energieausweis-aussteller"
>Energieausweis Aussteller</a
>
<a class="card-menu-option" href="/kundenbewertungen"
>Kundenbewertungen</a
>
<a class="card-menu-option" href="/faq">FAQ</a>
<a class="card-menu-option" href="/developers">Für Entwickler</a>
</div>
</nav>
<div class="infoCard">
<div class="flex-column align-center">
<img
src="/images/right-sidebar/ing-niedersachsen.png"
alt="Mitglied Ingenieurkammer Niedersachen"
style="height: 150px;margin-bottom: 25px; width: auto;"
/>
<img
src="/images/right-sidebar/mitglied-haendlerbund.png"
alt="Mitglied im Händlerbund"
style="width:auto;
"
/>
</div>
</div>
<div class="infoCard">
<div class="heading1">Was wird der Energieausweis kosten?</div>
<hr style="margin-bottom:15px;" />
<ul>
<li>Verbrauchsausweis Wohngebäude<br />45€ inkl. MwSt.<hr /></li>
<li>Bedarfsausweis Wohngebäude<br />75€ inkl. MwSt.<hr /></li>
<li>Verbrauchsausweis Gewerbe<br />65€ inkl. MwSt.<hr /></li>
<li>Bedarfsausweis Gewerbe<br />ab 300€ inkl. MwSt.<hr /></li>
<li>EnEV-Nachweis Wohngebäude<br />ab 400€ inkl. MwSt.<hr /></li>
<li>EnEV-Nachweis Gewerbe<br />ab 450€ inkl. MwSt.</li>
</ul>
<hr />
</div>
<div class="infoCard">
<div class="heading1">Zahlungsoptionen</div>
<hr style="margin-bottom:15px;" />
<p style="text-align:center; font-size: 1.1em;">
Ihre online Zahlungen werden sicher über eine SSL Verschlüsselung
abgewickelt.
</p>
<hr style="margin-bottom:15px;" />
<div class="align-center">
<img
src="/images/left-sidebar/payment.png"
alt="Bezahloptionen - Paypal, Visa, Kreditkarte..."
/>
</div>
</div>
</div>
<style>
.nav-card {
@apply rounded-lg w-full flex flex-col shadow-md border border-base-300;
}
.infoCard {
@apply bg-base-200 border-base-300 rounded-lg border p-4 shadow-md;
}
.dropdown-content > .card-menu-option,
.dropdown-content > a {
@apply block w-[350px] bg-base-200 border text-lg px-4 py-2 border-base-300;
}
.dropdown-content > a:first-child {
@apply rounded-tr-lg rounded-tl-lg;
}
.dropdown-content > a:last-child {
@apply rounded-br-lg rounded-bl-lg;
}
.dropdown-content > .card-menu-option:hover,
.dropdown-content > a:hover {
background-color: #444f94 !important;
color: #fff !important;
}
.dropdown-content {
@apply absolute bg-base-200 left-full top-[-1px] shadow-md z-10 hidden rounded-lg;
}
.dropdown:hover > .dropdown-content {
@apply block;
}
.dropdown::after {
content: "\276F";
position: absolute;
top: 20px;
right: 10px;
font-size: 14px;
font-weight: 300;
transform: translate(0, -50%) rotate(0deg);
transition: transform 0.25s;
}
.dropdown {
position: relative;
}
.dropdown-content:hover {
display: none;
}
.dropdown::after {
content: "\276F";
font-size: 14px;
font-weight: 300;
position: absolute;
right: 10px;
top: 20px;
transform: translate(0, -50%) rotate(0deg);
transition: transform 0.25s;
}
.card-menu-option {
@apply bg-base-200 border-b border-base-300 text-base-content text-lg py-2.5 px-5 select-none no-underline w-auto cursor-pointer;
}
.nav-card .card-menu-option:first-child {
@apply rounded-tr-lg rounded-tl-lg;
}
.nav-card .card-menu-option:last-child {
@apply rounded-br-lg rounded-bl-lg;
}
.nav-card .card-menu-option a {
@apply text-base-content;
text-decoration: none;
}
.nav-card .card-menu-option:hover > a {
color: #fff;
}
.nav-card .card-menu-option:hover {
background-color: #ff7d26;
color: #fff;
text-decoration: none;
}
</style>

View File

@@ -1,144 +0,0 @@
---
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
import SidebarWidgetLogin from "./SidebarWidgetLogin.svelte";
import SidebarWidgetProfile from "./SidebarWidgetProfile.svelte"
const loggedin = await validateAccessTokenServer(Astro)
---
<div class="flex flex-col gap-4">
{ !loggedin ?
<SidebarWidgetLogin client:load></SidebarWidgetLogin> : <SidebarWidgetProfile></SidebarWidgetProfile>}
<div class="infoCard">
<h2 style="font-weight: bold; font-size: 1.2em; color: #3A4AB5;">
Rufen Sie uns an<br /> Wir sind gerne für Sie da
</h2>
<hr style="margin-bottom:15px;" />
<div class="flex-row justify-between">
<div class="flex-column align-left">
<p>Telefonische Beratung unter</p>
<h2 style="font-weight: bold; font-size: 1.2em; color: #3A4AB5;">
<a href="tel:+4940209339850">040 / 209 339 850</a>
</h2>
</div>
<img
src="/images/right-sidebar/telefon-1.png"
style="width:70px; height: 73px;"
alt="Telefon - Rufen sie uns an."
/>
</div>
</div>
<div class="infoCard">
<h2 style="font-weight: bold; font-size: 1.2em; color: #3A4AB5;">
Bitte bewerten Sie uns!
</h2>
<hr style="margin-bottom:15px;" />
<div
class="review-widget_net"
data-uuid="d908c994-f1f2-4ab6-bad1-b2d3538086e7"
data-template="7"
data-filter=""
data-lang="de"
data-theme="light"
>
<a href="https://www.review-widget.net/" target="_blank" rel="noopener"
><img
src="https://grwapi.net/assets/spinner/spin.svg"
title="Google Review Widget"
alt="Review Widget"
/></a>
</div><script async src="https://grwapi.net/widget.min.js"></script>
<hr />
</div>
<div class="infoCard">
<h2 style="font-weight: bold; font-size: 1.2em; color: #3A4AB5;">
Verbrauchsausweis für Wohngebäude
</h2>
<hr style="margin-bottom:15px;" />
<div class="flex-column align-center">
<img
src="/images/right-sidebar/wohnhaus-1.png"
alt="Verbrauchsausweis ab 45€ für Wohngebäude."
/>
<a
href="/energieausweis-erstellen/verbrauchsausweis-erstellen"
class="large-button">Jetzt Verbrauchsausweis erstellen</a
>
</div>
</div>
<div class="infoCard">
<h2 style="font-weight: bold; font-size: 1.2em; color: #3A4AB5;">
Welche Häuser benötigen einen Energieausweis?
</h2>
<hr style="margin-bottom:15px;" />
<ul>
<li>Wohngebäude &gt; 50m² mit dauerhaftem Aufenthalt<hr /></li>
<li>Nichtwohngebäude &gt; 50m² mit dauerhaftem Aufenthalt<hr /></li>
<li>Beheizte Gebäude &gt; 50m²<hr /></li>
<li>Neubauten<hr /></li>
<li>Anbauten &gt; 50 m²<hr /></li>
<li>Sanierung mit Austausch der Heizungsanlage</li>
</ul>
<hr />
</div>
<div class="infoCard">
<h2 style="font-weight: bold; font-size: 1.2em; color: #3A4AB5;">
Bedarfsausweis für Wohngebäude
</h2>
<hr style="margin-bottom:15px;" />
<div class="flex-column align-center">
<img
src="/images/right-sidebar/wohnhaus-ba-1.png"
alt="Bedarfsausweis ab 75€ für Wohngebäude"
/>
<a
href="/energieausweis-erstellen/bedarfsausweis-erstellen"
class="large-button">Jetzt Bedarfsausweis erstellen</a
>
</div>
</div>
<div class="infoCard">
<h2 style="font-weight: bold; font-size: 1.2em; color: #3A4AB5;">
Welcher Energieausweis ist der richtige?
</h2>
<hr style="margin-bottom:15px;" />
<ul>
<li>
Verbrauchsausweis bei Vermietung, Verkauf und Aushang (Baujahr nach 1977
bzw. saniert).<hr />
</li>
<li>
Bedarfsausweis bei Neubau, Sanierung, Erweiterung und
Fördermittelantrag.
</li>
</ul>
<hr />
</div>
<div class="infoCard">
<h2 style="font-weight: bold; font-size: 1.2em; color: #3A4AB5;">
Verbrauchsausweis für Gewerbe
</h2>
<hr style="margin-bottom:15px;" />
<div class="flex-column align-center">
<img
src="/images/right-sidebar/gewerbe-1.png"
alt="Verbrauchsausweis Gewerbe für 65€"
/>
<a
href="/energieausweis-erstellen/verbrauchsausweis-gewerbe-erstellen"
class="large-button">Jetzt Verbrauchsausweis erstellen</a
>
</div>
</div>
</div>
<style>
.infoCard {
@apply bg-base-200 rounded-lg border border-base-300 p-4 shadow-md;
}
</style>

View File

@@ -1,25 +0,0 @@
---
import Login from "#components/design/sidebars/cards/cardlogin_1.svelte";
import Contact from "#components/design/sidebars/cards/cardcontact.svelte";
import Review from "#components/design/sidebars/cards/cardreview.svelte";
import VApromo from "#components/design/sidebars/cards/cardVApromo.svelte";
import VAGpromo from "#components/design/sidebars/cards/cardVAGpromo.svelte";
import BApromo from "#components/design/sidebars/cards/cardBApromo.svelte";
import BAGpromo from "#components/design/sidebars/cards/cardBAGpromo.svelte";
---
<div class="hidden
xl:flex xl:flex-col xl:grow
">
<Login client:load />
<Contact client:load />
<Review client:load />
<VApromo client:load />
<VAGpromo client:load />
<BApromo client:load />
<BAGpromo client:load />
</div>
</div>

View File

@@ -0,0 +1,286 @@
import fuelList from "#components/Ausweis/brennstoffListe.js";
import { faker } from "@faker-js/faker";
import { Enums } from "@ibcornelsen/database/client";
import "cypress-file-upload"
describe("Verbrauchsausweis erstellen Schritt 1", () => {
it("erstellt einen neuen Verbrauchsausweis Wohngebäude.", () => {
cy.visit("/energieausweis-erstellen/verbrauchsausweis-wohngebaeude");
console.log(Enums);
// cy.wait(1000);
// // Wir überprüfen, ob alle Ausstelgründe vorhanden sind, diese sollten genau so viele sein wie in der Datenbank vorhanden sind.
// cy.get("input[name='ausstellgrund']")
// .should("have.length", Object.values(Enums.Ausstellgrund).length)
// .eq(
// faker.number.int({
// min: 0,
// max: Object.values(Enums.Ausstellgrund).length - 1,
// })
// )
// .check();
// // Jetzt Füllen wir das Baujahr vom Gebäude aus.
// cy.get("input[name='baujahr_gebaeude']")
// .should("have.attr", "type", "number")
// .type(
// faker.number.int({ min: 1900, max: 2021 }).toString() +
// "{enter}",
// { delay: 50 }
// );
// // Jetzt Füllen wir das Baujahr der Heizung aus.
// cy.get("input[name='baujahr_heizung']")
// .should("have.attr", "type", "number")
// .type(
// faker.number.int({ min: 1900, max: 2021 }).toString() +
// "{enter}",
// { delay: 50 }
// );
// // Anzahl Einheiten
// cy.get("input[name='einheiten']")
// .should("have.attr", "type", "number")
// .type(faker.number.int({ min: 1, max: 5 }).toString());
// // Sanierungsstatus
// cy.get("select[name='saniert']").select(
// Math.random() > 0.5 ? "true" : "false"
// );
// // Adresse
// cy.get("input[name='adresse']").type(faker.location.streetAddress());
// // Postleitzahl
// cy.get("input[name='plz']").type(
// faker.location.zipCode({
// format: "#####",
// })
// );
// // TODO: Ort - Dieser wird aus der Datenbank abgefragt, wir müssen also warten, bis der Dropdown da ist.
// // Flaeche
// cy.get("input[name='flaeche']")
// .should("have.attr", "type", "number")
// .type(faker.number.int({ min: 50, max: 1000 }).toString());
// // Nutzflaeche
// cy.get("input[name='nutzflaeche']")
// .should("have.attr", "type", "number")
// .type(faker.number.int({ min: 50, max: 1000 }).toString());
// // Keller
// cy.get("select[name='keller']").find("option:not([disabled])").should("have.length", Object.values(Enums.Heizungsstatus).length).parent().select(faker.number.int({
// max: Object.values(Enums.Heizungsstatus).length,
// min: 1
// }));
// // Dachgeschoss
// cy.get("select[name='dachgeschoss']").find("option:not([disabled])").should("have.length", Object.values(Enums.Heizungsstatus).length).parent().select(faker.number.int({
// max: Object.values(Enums.Heizungsstatus).length,
// min: 1
// }));
// // Brennstoff und Einheit 1
// const brennstoffKombo = fuelList[faker.number.int({ min: 0, max: fuelList.length - 1 })];
// cy.get("select[name='brennstoff_1']").select(brennstoffKombo[0]);
// cy.get("select[name='einheit_1']").select(brennstoffKombo[1]);
// // Verbrauchszeitraum
// cy.get("select[name='energieverbrauch_zeitraum_monat']").select(faker.number.int({ min: 1, max: 12 }).toString());
// cy.get("select[name='energieverbrauch_zeitraum_jahr']").select(faker.number.int({ min: 2018, max: 2019 }).toString());
// // Verbrauch
// cy.get("input[name='verbrauch_1']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
// cy.get("input[name='verbrauch_2']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
// cy.get("input[name='verbrauch_3']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
// const zusaetzlicheHeizquelle = Math.random() > 0.5;
// if (zusaetzlicheHeizquelle) {
// cy.get("input[name='zusaetzliche_heizquelle']").check();
// // Brennstoff und Einheit 2
// const brennstoffKombo2 = fuelList[faker.number.int({ min: 0, max: fuelList.length - 1 })];
// cy.get("select[name='brennstoff_2']").select(brennstoffKombo2[0]);
// cy.get("select[name='einheit_2']").select(brennstoffKombo2[1]);
// // Verbrauch
// cy.get("input[name='verbrauch_4']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
// cy.get("input[name='verbrauch_5']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
// cy.get("input[name='verbrauch_6']").type(faker.number.int({ min: 4000, max: 15000 }).toString());
// }
// // Warmwasser enthalten und bekannt
// const warmwasserEnthalten = Math.random() > 0.5;
// const anteilBekannt = Math.random() > 0.5;
// if (warmwasserEnthalten) {
// cy.get("input[name='warmwasser_enthalten']").check();
// if (anteilBekannt) {
// // Der Anteil ist bekannt, wir müssen ihn also angeben.
// cy.get("input[name='warmwasser_anteil_bekannt']").check();
// cy.get("input[name='anteil_warmwasser_1']").type(faker.number.int({ min: 0, max: 50 }).toString());
// if (zusaetzlicheHeizquelle) {
// // Zusätzliche Heizquelle existiert, also müssen wir auch hier den Anteil angeben.
// cy.get("input[name='anteil_warmwasser_2']").type(faker.number.int({ min: 0, max: 50 }).toString());
// }
// }
// }
// // Alternative Energieversorgungssysteme
// if (Math.random() > 0.5) cy.get("input[name='alternative_heizung']").check();
// if (Math.random() > 0.5) cy.get("input[name='alternative_warmwasser']").check();
// if (Math.random() > 0.5) cy.get("input[name='alternative_lueftung']").check();
// if (Math.random() > 0.5) cy.get("input[name='alternative_kuehlung']").check();
// // Gebäudetyp
// cy.get("select[name='gebaeudetyp']").then(($dropdown) => {
// const options = $dropdown.find('option');
// // Select the option at the random index
// cy.get("select[name='gebaeudetyp']").select(options.eq(faker.number.int({ min: 1, max: options.length - 1 })).val() as string);
// });
// // Gebäudeteil
// cy.get("select[name='gebaeudeteil']").then(($dropdown) => {
// const options = $dropdown.find('option');
// // Select the option at the random index
// cy.get("select[name='gebaeudeteil']").select(options.eq(faker.number.int({ min: 1, max: options.length - 1 })).val() as string);
// });
// // Lüftung
// cy.get("select[name='lueftung']").then(($dropdown) => {
// const options = $dropdown.find('option');
// // Select the option at the random index
// cy.get("select[name='lueftung']").select(options.eq(faker.number.int({ min: 1, max: options.length - 1 })).val() as string);
// });
// // Kühlung
// cy.get("select[name='kuehlung']").then(($dropdown) => {
// const options = $dropdown.find('option');
// // Select the option at the random index
// cy.get("select[name='kuehlung']").select(options.eq(faker.number.int({ min: 1, max: options.length - 1 })).val() as string);
// });
// // Leerstand
// cy.get("input[name='leerstand']").should("have.attr", "type", "number").type(faker.number.int({ min: 0, max: 30 }).toString());
// // Heizungsanlage Daten
// if (Math.random() > 0.5) cy.get("input[name='zentralheizung']").check();
// if (Math.random() > 0.5) cy.get("input[name='einzelofen']").check();
// if (Math.random() > 0.5) cy.get("input[name='durchlauf_erhitzer']").check();
// if (Math.random() > 0.5) cy.get("input[name='standard_kessel']").check();
// if (Math.random() > 0.5) cy.get("input[name='solarsystem_warmwasser']").check();
// if (Math.random() > 0.5) cy.get("input[name='waermepumpe']").check();
// if (Math.random() > 0.5) cy.get("input[name='niedertemperatur_kessel']").check();
// if (Math.random() > 0.5) cy.get("input[name='brennwert_kessel']").check();
// if (Math.random() > 0.5) cy.get("input[name='warmwasser_rohre_gedaemmt']").check();
// if (Math.random() > 0.5) cy.get("input[name='heizungsrohre_gedaemmt']").check();
// if (Math.random() > 0.5) cy.get("input[name='zirkulation']").check();
// if (Math.random() > 0.5) cy.get("input[name='raum_temperatur_regler']").check();
// // Heizungsanlage Bilder
// cy.get("input[name='heizung_image']").should("have.attr", "type", "file").attachFile("images/heizungsanlage/1.jpeg", { subjectType: "input" });
// cy.get("input[name='heizung_image']").should("have.attr", "type", "file").attachFile("images/heizungsanlage/2.jpeg", { subjectType: "input" });
// // Fenster Daten
// if (Math.random() > 0.5) cy.get("input[name='einfach_verglasung']").check();
// if (Math.random() > 0.5) cy.get("input[name='doppel_verglasung']").check();
// if (Math.random() > 0.5) cy.get("input[name='isolier_verglasung']").check();
// if (Math.random() > 0.5) cy.get("input[name='dreifach_verglasung']").check();
// if (Math.random() > 0.5) cy.get("input[name='fenster_dicht']").check();
// if (Math.random() > 0.5) cy.get("input[name='fenster_teilweise_undicht']").check();
// if (Math.random() > 0.5) cy.get("input[name='tueren_dicht']").check();
// if (Math.random() > 0.5) cy.get("input[name='tueren_undicht']").check();
// if (Math.random() > 0.5) cy.get("input[name='rolllaeden_kaesten_gedaemmt']").check();
// // Fenster Bilder
// cy.get("input[name='fenster_image']").should("have.attr", "type", "file").attachFile("images/fenster/1.jpeg", { subjectType: "input" });
// cy.get("input[name='fenster_image']").should("have.attr", "type", "file").attachFile("images/fenster/2.jpeg", { subjectType: "input" });
// // Wärmedämmung Daten
// if (Math.random() > 0.5) cy.get("input[name='aussenwand_gedaemmt']").check();
// if (Math.random() > 0.5) cy.get("input[name='keller_wand_gedaemmt']").check();
// if (Math.random() > 0.5) cy.get("input[name='keller_decke_gedaemmt']").check();
// if (Math.random() > 0.5) cy.get("input[name='dachgeschoss_gedaemmt']").check();
// if (Math.random() > 0.5) cy.get("input[name='oberste_geschossdecke_gedaemmt']").check();
// if (Math.random() > 0.5) cy.get("input[name='oberste_geschossdecke_min_12cm_gedaemmt']").check();
// // Wärmedämmung Bilder
// cy.get("input[name='daemmung_image']").should("have.attr", "type", "file").attachFile("images/daemmung/1.jpeg", { subjectType: "input" });
// cy.get("input[name='daemmung_image']").should("have.attr", "type", "file").attachFile("images/daemmung/2.jpeg", { subjectType: "input" });
// // Gebäude Bild
// cy.get("input[name='gebaeude_image']").should("have.attr", "type", "file").attachFile("images/gebaeude/1.jpeg", { subjectType: "input" });
// // Jetzt können wir den Verbrauchsausweis erstellen.
// cy.get("form[name='ausweis'] button[type='submit']").click({ force: true });
// // Wir sind nicht eingeloggt also sollte jetzt ein Login Screen erscheinen.
// // Wir klicken auf registrieren und erstellen einen neuen Benutzer, danach loggen wir uns mit diesem ein.
// cy.get("button[name='registrieren']").click();
// const email = faker.internet.email();
// const passwort = "test1234";
// const vorname = faker.person.firstName();
// const nachname = faker.person.lastName();
// cy.get("form[name='signup'] input[name='email']").should("be.visible").should("have.attr", "type", "email").type(email);
// cy.get("form[name='signup'] input[name='passwort']").should("be.visible").should("have.attr", "type", "password").type(passwort);
// cy.get("form[name='signup'] input[name='vorname']").should("be.visible").should("have.attr", "type", "text").type(vorname);
// cy.get("form[name='signup'] input[name='nachname']").should("be.visible").should("have.attr", "type", "text").type(nachname);
// cy.get("form[name='signup'] button[type='submit']").click();
// // Wir sind jetzt registriert und können uns nun einloggen.
// // Die Email sollte automatisch eingetragen sein, da wir uns gerade registriert haben.
// cy.get("form[name='login'] input[name='email']").should("be.visible").should("have.attr", "type", "email").should("contain.value", email);
// cy.get("form[name='login'] input[name='passwort']").should("be.visible").should("have.attr", "type", "password").type(passwort);
// cy.get("form[name='login'] button[type='submit']").click();
// // Der Ausweis sollte jetzt schon erstellt worden sein und wir sollten auf die kundendaten seite weitergeleitet worden sein.
// cy.url().should("contain", "/kundendaten");
// cy.wait(1000)
// // Wir füllen jetzt die Kundendaten aus.
// cy.get("select[name='anrede']").select(Math.random() > 0.5 ? "Herr" : "Frau");
// cy.get("input[name='vorname']").should("contain.value", vorname);
// cy.get("input[name='name']").should("contain.value", nachname);
// cy.get("input[name='email']").should("contain.value", email);
// cy.get("input[name='telefon']").type(faker.phone.number());
// cy.get("input[name='rechnung_empfaenger']").type(`${vorname} ${nachname}`);
// cy.get("input[name='rechnung_strasse']").type(faker.location.streetAddress());
// // TODO: Random Plz generieren, allerdings muss die auch in der Datenbank vorhanden sein...
// cy.get("input[name='rechnung_plz']").type("2103");
// // Jetzt sollte der PLZ Container erscheinen, dort klicken wir einfach das erste Element an.
// cy.get("div[data-test='plz-container']").children().first().click();
// cy.get("input[name='rechnung_telefon']").type(faker.phone.number());
// cy.get("input[name='rechnung_email']").type(faker.internet.email());
// cy.get("button[data-test='paypal']").click();
// // Datenschutz und AGB akzeptieren, dann schicken wir das Formular ab.
// cy.get("input[name='agb-akzeptieren']").check()
// cy.get("input[name='datenschutz-akzeptieren']").check()
// cy.get("button[type='submit']").click();
// cy.origin('https://www.mollie.com', () => {
// // Jetzt sind wir auf der Mollie Seite, dort wählen wir den "paid" status aus
// cy.get("input[type='radio'][name='final_state'][value='paid']").check();
// // Da wird unser Test fehlschlagen, da die localhost domain von Mollie aus nicht erreichbar ist.
// })
});
});

View File

@@ -1,4 +1,4 @@
import { API_ACCESS_TOKEN_COOKIE_NAME, API_REFRESH_TOKEN_COOKIE_NAME } from "#lib/constants"; import { API_ACCESS_TOKEN_COOKIE_NAME, API_REFRESH_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import {faker} from "@faker-js/faker"; import {faker} from "@faker-js/faker";
describe('Benutzer Authentifizierung', () => { describe('Benutzer Authentifizierung', () => {
@@ -11,6 +11,8 @@ describe('Benutzer Authentifizierung', () => {
it("erstellt einen Nutzer und leitet auf die Login Seite weiter", () => { it("erstellt einen Nutzer und leitet auf die Login Seite weiter", () => {
cy.visit("/auth/signup") cy.visit("/auth/signup")
cy.wait(1000)
cy.get('input[name="email"]').type(email) cy.get('input[name="email"]').type(email)
cy.get('input[name="passwort"]').type(password) cy.get('input[name="passwort"]').type(password)
cy.get('input[name="vorname"]').type(name) cy.get('input[name="vorname"]').type(name)
@@ -24,12 +26,14 @@ describe('Benutzer Authentifizierung', () => {
it("meldet einen Nutzer an und leitet auf die Startseite weiter", () => { it("meldet einen Nutzer an und leitet auf die Startseite weiter", () => {
cy.visit("/auth/login") cy.visit("/auth/login")
cy.wait(1000)
cy.get('input[name="email"]').type(email) cy.get('input[name="email"]').type(email)
cy.get('input[name="passwort"]').type(password) cy.get('input[name="passwort"]').type(password)
cy.get('button[type="submit"]').click() cy.get('button[type="submit"]').click()
cy.url().should("include", "/user") cy.url().should("include", "/dashboard")
// Wir sollten nun einen Access Token und Refresh Token in unseren Cookies sehen. // Wir sollten nun einen Access Token und Refresh Token in unseren Cookies sehen.
cy.getCookie(API_ACCESS_TOKEN_COOKIE_NAME).should("exist") cy.getCookie(API_ACCESS_TOKEN_COOKIE_NAME).should("exist")

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -14,7 +14,7 @@
// *********************************************************** // ***********************************************************
// Import commands.js using ES2015 syntax: // Import commands.js using ES2015 syntax:
import './commands' import './commands.js'
// Alternatively you can use CommonJS syntax: // Alternatively you can use CommonJS syntax:
// require('./commands') // require('./commands')

View File

@@ -4,7 +4,7 @@ import "../style/formular.css";
import "../../svelte-dialogs.config" import "../../svelte-dialogs.config"
import Header from "#components/design/header/AusweisHeader.astro"; import Header from "#components/design/header/AusweisHeader.astro";
import Footer from "#components/design/footer/Footer.astro"; import Footer from "#components/design/footer/Footer.astro";
import SidebarLeft from "#components/design/sidebars/left/SidebarLeft.astro"; import SidebarLeft from "#components/design/sidebars/SidebarLeft.astro";
import { NotificationWrapper } from "@ibcornelsen/ui"; import { NotificationWrapper } from "@ibcornelsen/ui";
export interface Props { export interface Props {

View File

@@ -2,9 +2,9 @@
import "../style/global.css"; import "../style/global.css";
import "../style/formular.css"; import "../style/formular.css";
import "../../svelte-dialogs.config" import "../../svelte-dialogs.config"
import Header from "#header/AusweisHeader.astro"; import Header from "#components/design/header/AusweisHeader.astro";
import Footer from "#footer/Footer.astro"; import Footer from "#components/design/footer/Footer.astro";
import SidebarLeft from "#sidebarLeft/SidebarLeft.astro"; import SidebarLeft from "#components/design/sidebars/SidebarLeft.astro";
import { NotificationWrapper } from "@ibcornelsen/ui"; import { NotificationWrapper } from "@ibcornelsen/ui";
export interface Props { export interface Props {

View File

@@ -3,8 +3,8 @@ import "../style/global.css";
import "../../svelte-dialogs.config" import "../../svelte-dialogs.config"
import Header from "#components/design/header/Header.astro"; import Header from "#components/design/header/Header.astro";
import Footer from "#components/design/footer/Footer.astro"; import Footer from "#components/design/footer/Footer.astro";
import SidebarLeft from "#components/design/sidebars/left/SidebarLeft.astro"; import SidebarLeft from "#components/design/sidebars/SidebarLeft.astro";
import SidebarRight from "#components/design/sidebars/right/SidebarRight.astro"; import SidebarRight from "#components/design/sidebars/SidebarRight.astro";
import { NotificationWrapper } from "@ibcornelsen/ui"; import { NotificationWrapper } from "@ibcornelsen/ui";
export interface Props { export interface Props {

View File

@@ -1,63 +0,0 @@
---
import "../style/global.css";
import "../../svelte-dialogs.config"
import Header from "#components/design/header/Header_1.astro";
import Footer from "#components/design/footer/Footer.astro";
import SidebarLeft from "#components/design/sidebars/left/SidebarLeft.astro";
import SidebarRight from "#components/design/sidebars/right/SidebarRight_1.astro";
import { NotificationWrapper } from "@ibcornelsen/ui";
export interface Props {
title: string;
}
const { title } = Astro.props;
---
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.jpg" />
<meta
name="description"
content="✅ Jetzt Ihren Energieausweis online erstellen. Erhalten Sie Ihren online Energieausweis rechtssicher und nach aktueller GEG (vormals EnEV) vom Diplom Ingenieur geprüft."
/>
<title>
{title || "Energieausweis online erstellen - Online Energieausweis"}
</title>
</head>
<body>
<container class="w-full max-w-[1920px]">
<Header />
<main
class="w-full p-0 grid
sm:grid-cols-[minmax(1fr,1fr)] sm:gap-1 sm:px-0
md:grid-cols-[minmax(1fr,1fr)] md:gap-2 md:px-0
lg:grid-cols-[minmax(250px,250px)1fr] lg:gap-3 lg:p-3
xl:grid-cols-[minmax(350px,350px)1fr] xl:gap-4 xl:p-4
2xl:grid-cols-[minmax(350px,350px)1fr_minmax(350px,350px)] 2xl:gap-5 2xl:p-5
">
<SidebarLeft />
<article class="box grow rounded-tl-none">
<slot />
</article>
<SidebarRight />
</main>
<Footer />
<NotificationWrapper client:load />
</container>
</body>
</html>

View File

@@ -1,154 +0,0 @@
---
import i18next from "i18next";
import "../style/UMBE_global.css";
import "#style/global.css";
import "../../svelte-dialogs.config"
import Footer from "../components/Footer.astro";
import Header from "../components/Header.astro";
import SidebarLeft from "../components/SidebarLeft.astro";
import SidebarRight from "../components/SidebarRight.astro";
import { NotificationWrapper } from "@ibcornelsen/ui";
import TicketPopup from "../components/Tickets/TicketButton.svelte"
export interface Props {
title: string;
}
const { title } = Astro.props;
const schema = JSON.stringify({
"@context": "http://schema.org",
"@type": "Corporation",
name: "IB Cornelsen",
alternateName: "online-energieausweis.org",
url: "https://online-energieausweis.org",
logo: "https://online-energieausweis.org/ib-cornelsen.png",
address: {
"@type": "PostalAddress",
streetAddress: "Katendeich 5A",
addressLocality: "Hamburg",
postalCode: "21035",
addressCountry: "Deutschland",
email: "info@online-energieausweis.org",
},
contactPoint: {
"@type": "ContactPoint",
telephone: "+49-040-209339850",
faxNumber: "+49-040-209339859",
contactType: "customer service",
areaServed: "DE",
availableLanguage: "German",
},
});
---
<!DOCTYPE html>
<html lang={i18next.language}>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<script type="application/ld+json" set:html={schema}></script>
<link rel="icon" type="image/svg+xml" href="/favicon.jpg" />
<meta
name="description"
content="✅ Jetzt Ihren Energieausweis online erstellen. Erhalten Sie Ihren online Energieausweis rechtssicher und nach aktueller GEG (vormals EnEV) vom Diplom Ingenieur geprüft."
/>
<link rel="canonical" href="https://online-energieausweis.org/" />
<meta property="og:locale" content="de_DE" />
<meta property="og:type" content="website" />
<meta
property="og:title"
content="Energieausweis online erstellen - Online Energieausweis"
/>
<meta
property="og:description"
content="✅ Jetzt Ihren Energieausweis online erstellen. Erhalten Sie Ihren online Energieausweis rechtssicher und nach aktueller GEG (vormals EnEV) vom Diplom Ingenieur geprüft."
/>
<meta property="og:url" content="https://online-energieausweis.org/" />
<meta
property="og:site_name"
content="Energieausweis online erstellen"
/>
<meta name="twitter:card" content="summary_large_image" />
<meta
name="twitter:description"
content="✅ Jetzt Ihren Energieausweis online erstellen. Erhalten Sie Ihren online Energieausweis rechtssicher und nach aktueller GEG (vormals EnEV) vom Diplom Ingenieur geprüft."
/>
<meta
name="twitter:title"
content="Energieausweis online erstellen - Online Energieausweis"
/>
<meta
name="twitter:image"
content="https://online-energieausweis.org/images/energieausweis-online-erstellen.jpg"
/>
<title>
{title || "Energieausweis online erstellen - Online Energieausweis"}
</title>
</head>
<body>
<Header />
<main
class="lg:grid gap-6 md:p-6 lg:grid-cols-[2fr,6fr,2fr] max-w-[1920px] w-full bg-base-100"
>
<SidebarLeft />
<article class="w-full max-w-full bg-base-200 border border-base-300">
<slot />
</article>
<div class="hidden lg:block">
<SidebarRight />
<div>
</main>
<Footer />
<NotificationWrapper client:load />
<TicketPopup client:load />
</body>
</html>
<style is:global lang="scss">
:root {
@apply bg-base-100 text-base-content;
}
article {
@apply rounded-lg w-full shadow-md border;
}
.mainContent {
p, h1, h2, h3, h4, h5, h6 {
@apply text-base-content;
}
}
body {
min-height: 100vh;
}
.button {
@apply px-8 py-2 bg-secondary rounded-lg text-white font-medium hover:shadow-lg transition-all hover:underline active:bg-blue-900 text-center cursor-pointer;
color: #fff !important;
}
h3 {
@apply text-xl font-medium mt-6 mb-4;
}
input {
@apply py-1.5 px-4 w-full rounded-lg outline-none text-lg text-slate-700 border bg-gray-50 transition-colors;
}
input:hover,
input:focus {
@apply bg-gray-100;
}
label {
@apply text-base font-semibold;
}
</style>

View File

@@ -1,23 +0,0 @@
---
---
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.jpg" />
<meta
name="description"
content="IB Cornelsen - Widget"
/>
<title>
IB Cornelsen - Widget
</title>
</head>
<body>
<slot />
</body>
</html>

View File

@@ -3,8 +3,8 @@ import "../style/global.css";
import "../../svelte-dialogs.config" import "../../svelte-dialogs.config"
import Header from "#components/design/header/Header.astro"; import Header from "#components/design/header/Header.astro";
import Footer from "#components/design/footer/Footer.astro"; import Footer from "#components/design/footer/Footer.astro";
import SidebarLeft from "#components/design/sidebars/left/SidebarLeft.astro"; import SidebarLeft from "#components/design/sidebars/SidebarLeft.astro";
import SidebarRight from "#components/design/sidebars/right/SidebarRight.astro"; import SidebarRight from "#components/design/sidebars/SidebarRight.astro";
import { NotificationWrapper } from "@ibcornelsen/ui"; import { NotificationWrapper } from "@ibcornelsen/ui";
export interface Props { export interface Props {

131
src/lib/faker.ts Normal file
View File

@@ -0,0 +1,131 @@
import {
AufnahmeClient,
VerbrauchsausweisWohnenClient,
ObjektClient,
} from "#components/Ausweis/types.js";
import { faker } from "@faker-js/faker";
import { Enums } from "@ibcornelsen/database/client";
export function fakeObjekt(seed: number = 42): ObjektClient {
faker.seed(seed);
return {
adresse: faker.location.streetAddress(),
plz: faker.location.zipCode({ format: "#####" }),
ort: faker.location.city(),
uid: faker.string.uuid(),
latitude: faker.location.latitude(),
longitude: faker.location.longitude(),
};
}
export function fakeAufnahme(seed: number = 42, uid_objekt: string = faker.string.uuid()): AufnahmeClient {
faker.seed(seed);
const tuerenDicht = faker.datatype.boolean();
return {
baujahr_gebaeude: [faker.number.int({ min: 1960, max: 2014 })],
baujahr_heizung: [faker.number.int({ min: 1960, max: 2014 })],
baujahr_klima: [faker.number.int({ min: 1985, max: 2014 })],
nutzflaeche: faker.number.int({ min: 50, max: 300 }),
einheiten: faker.number.int({ min: 1, max: 3 }),
saniert: faker.datatype.boolean(),
keller: faker.helpers.enumValue(Enums.Heizungsstatus),
dachgeschoss: faker.helpers.enumValue(Enums.Heizungsstatus),
flaeche: faker.number.int({ min: 50, max: 300 }),
gebaeudetyp: "Einfamilienhaus",
gebaeudeteil: "Gesamtgebäude",
lueftung: "Fensterlueftung",
kuehlung: "Vorhanden",
brennstoff_1: "Erdgas H",
alternative_heizung: faker.datatype.boolean(),
alternative_kuehlung: faker.datatype.boolean(),
alternative_lueftung: faker.datatype.boolean(),
alternative_warmwasser: faker.datatype.boolean(),
aussenwand_gedaemmt: faker.datatype.boolean(),
aussenwand_min_12cm_gedaemmt: faker.datatype.boolean(),
ausweisart: Enums.Ausweisart.VerbrauchsausweisWohnen,
bestellt: faker.datatype.boolean(),
boxpruefung: faker.datatype.boolean(),
brennstoff_2: "Erdgas H",
brennwert_kessel: faker.datatype.boolean(),
dachgeschoss_gedaemmt: faker.datatype.boolean(),
dachgeschoss_min_12cm_gedaemmt: faker.datatype.boolean(),
doppel_verglasung: faker.datatype.boolean(),
dreifach_verglasung: faker.datatype.boolean(),
durchlauf_erhitzer: faker.datatype.boolean(),
einfach_verglasung: faker.datatype.boolean(),
einzelofen: faker.datatype.boolean(),
energieeffizienzklasse: "",
erledigt: faker.datatype.boolean(),
erstellungsdatum: faker.date.past(),
fenster_dicht: faker.datatype.boolean(),
fenster_teilweise_undicht: faker.datatype.boolean(),
heizungsrohre_gedaemmt: faker.datatype.boolean(),
isolier_verglasung: faker.datatype.boolean(),
keller_decke_gedaemmt: faker.datatype.boolean(),
keller_wand_gedaemmt: faker.datatype.boolean(),
leerstand: faker.number.int({ min: 0, max: 20 }),
niedertemperatur_kessel: faker.datatype.boolean(),
oberste_geschossdecke_gedaemmt: faker.datatype.boolean(),
oberste_geschossdecke_min_12cm_gedaemmt: faker.datatype.boolean(),
photovoltaik: faker.datatype.boolean(),
prueftext: faker.lorem.sentence(),
raum_temperatur_regler: faker.datatype.boolean(),
rolllaeden_kaesten_gedaemmt: faker.datatype.boolean(),
solarsystem_warmwasser: faker.datatype.boolean(),
standard_kessel: faker.datatype.boolean(),
storniert: false,
tueren_dicht: tuerenDicht,
tueren_undicht: !tuerenDicht,
waermepumpe: faker.datatype.boolean(),
warmwasser_rohre_gedaemmt: faker.datatype.boolean(),
zentralheizung: faker.datatype.boolean(),
zirkulation: faker.datatype.boolean(),
zurueckgestellt: faker.datatype.boolean(),
uid: faker.string.uuid(),
ausstellungsdatum: faker.date.past(),
uid_objekt
};
}
export function fakeVerbrauchsausweisWohnen(
seed: number = 42,
uid_aufnahme: string = faker.string.uuid(),
uid_objekt: string = faker.string.uuid()
): VerbrauchsausweisWohnenClient {
faker.seed(seed);
const verbrauch_1 = faker.number.int({ min: 5000, max: 20000 });
const verbrauch_4 = faker.number.int({ min: 5000, max: 15000 });
const ausweis: VerbrauchsausweisWohnenClient = {
verbrauch_1: verbrauch_1,
verbrauch_2: verbrauch_1 + faker.number.int({ min: -2000, max: 2000 }),
verbrauch_3: verbrauch_1 + faker.number.int({ min: -2000, max: 2000 }),
einheit_1: "kWh",
warmwasser_enthalten: faker.datatype.boolean(),
uid: faker.string.uuid(),
alternative_heizung: faker.datatype.boolean(),
alternative_kuehlung: faker.datatype.boolean(),
alternative_lueftung: faker.datatype.boolean(),
alternative_warmwasser: faker.datatype.boolean(),
anteil_warmwasser_1: faker.number.int({ min: 0, max: 60 }),
anteil_warmwasser_2: faker.number.int({ min: 0, max: 60 }),
ausstellgrund: faker.helpers.enumValue(Enums.Ausstellgrund),
einheit_2: "kWh",
keller_beheizt: faker.datatype.boolean(),
registriernummer: faker.string.uuid(),
startdatum: faker.date.past({ years: 3 }),
verbrauch_4: verbrauch_4,
verbrauch_5: verbrauch_4 + faker.number.int({ min: -2000, max: 2000 }),
verbrauch_6: verbrauch_4 + faker.number.int({ min: -2000, max: 2000 }),
warmwasser_anteil_bekannt: faker.datatype.boolean(),
wird_gekuehlt: faker.datatype.boolean(),
zusaetzliche_heizquelle: faker.datatype.boolean(),
faktorKeller: faker.number.float({ min: 0, max: 1 }),
uid_aufnahme,
uid_objekt
};
return ausweis;
}

View File

@@ -1,116 +0,0 @@
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { faker } from "@faker-js/faker";
import { Enums } from "@ibcornelsen/database/client";
export function verbrauchsausweisWohnenFaker(seed: number = 42): VerbrauchsausweisWohnenClient {
faker.seed(seed);
const tuerenDicht = faker.datatype.boolean();
const verbrauch_1 = faker.number.int({ min: 5000, max: 20000 });
const verbrauch_4 = faker.number.int({ min: 5000, max: 15000 });
const ausweis: VerbrauchsausweisWohnenClient = {
aufnahme: {
rechnungen: [],
baujahr_gebaeude: [faker.number.int({ min: 1960, max: 2014 })],
baujahr_heizung: [faker.number.int({ min: 1960, max: 2014 })],
baujahr_klima: [faker.number.int({ min: 1985, max: 2014 })],
adresse: faker.location.streetAddress(),
plz: faker.location.zipCode({ format: "#####" }),
ort: faker.location.city(),
nutzflaeche: faker.number.int({ min: 50, max: 300 }),
einheiten: faker.number.int({ min: 1, max: 3 }),
saniert: faker.datatype.boolean(),
keller: faker.helpers.enumValue(Enums.Heizungsstatus),
dachgeschoss: faker.helpers.enumValue(Enums.Heizungsstatus),
flaeche: faker.number.int({ min: 50, max: 300 }),
gebaeudetyp: "Einfamilienhaus",
gebaeudeteil: "Gesamtgebäude",
lueftung: "Fensterlüftung",
kuehlung: "Vorhanden",
objekt: {
adresse: faker.location.streetAddress(),
plz: faker.location.zipCode({ format: "#####" }),
ort: faker.location.city(),
uid: faker.string.uuid(),
gebaeude_bilder: [],
latitude: faker.location.latitude(),
longitude: faker.location.longitude(),
},
brennstoff_1: "Erdgas H",
alternative_heizung: faker.datatype.boolean(),
alternative_kuehlung: faker.datatype.boolean(),
alternative_lueftung: faker.datatype.boolean(),
alternative_warmwasser: faker.datatype.boolean(),
aussenwand_gedaemmt: faker.datatype.boolean(),
aussenwand_min_12cm_gedaemmt: faker.datatype.boolean(),
ausweisart: Enums.Ausweisart.VerbrauchsausweisWohnen,
bestellt: faker.datatype.boolean(),
boxpruefung: faker.datatype.boolean(),
brennstoff_2: "Erdgas H",
brennwert_kessel: faker.datatype.boolean(),
dachgeschoss_gedaemmt: faker.datatype.boolean(),
dachgeschoss_min_12cm_gedaemmt: faker.datatype.boolean(),
doppel_verglasung: faker.datatype.boolean(),
dreifach_verglasung: faker.datatype.boolean(),
durchlauf_erhitzer: faker.datatype.boolean(),
einfach_verglasung: faker.datatype.boolean(),
einzelofen: faker.datatype.boolean(),
energieeffizienzklasse: "",
erledigt: faker.datatype.boolean(),
erstellungsdatum: faker.date.past(),
fenster_dicht: faker.datatype.boolean(),
fenster_teilweise_undicht: faker.datatype.boolean(),
heizungsrohre_gedaemmt: faker.datatype.boolean(),
isolier_verglasung: faker.datatype.boolean(),
keller_decke_gedaemmt: faker.datatype.boolean(),
keller_wand_gedaemmt: faker.datatype.boolean(),
leerstand: faker.number.int({ min: 0, max: 20 }),
niedertemperatur_kessel: faker.datatype.boolean(),
oberste_geschossdecke_gedaemmt: faker.datatype.boolean(),
oberste_geschossdecke_min_12cm_gedaemmt: faker.datatype.boolean(),
photovoltaik: faker.datatype.boolean(),
prueftext: faker.lorem.sentence(),
raum_temperatur_regler: faker.datatype.boolean(),
rolllaeden_kaesten_gedaemmt: faker.datatype.boolean(),
solarsystem_warmwasser: faker.datatype.boolean(),
standard_kessel: faker.datatype.boolean(),
storniert: false,
tueren_dicht: tuerenDicht,
tueren_undicht: !tuerenDicht,
waermepumpe: faker.datatype.boolean(),
warmwasser_rohre_gedaemmt: faker.datatype.boolean(),
zentralheizung: faker.datatype.boolean(),
zirkulation: faker.datatype.boolean(),
zurueckgestellt: faker.datatype.boolean(),
uid: faker.string.uuid(),
events: [],
ausstellungsdatum: faker.date.past()
},
verbrauch_1: verbrauch_1,
verbrauch_2: verbrauch_1 + faker.number.int({ min: -2000, max: 2000 }),
verbrauch_3: verbrauch_1 + faker.number.int({ min: -2000, max: 2000 }),
einheit_1: "kWh",
warmwasser_enthalten: faker.datatype.boolean(),
uid: faker.string.uuid(),
alternative_heizung: faker.datatype.boolean(),
alternative_kuehlung: faker.datatype.boolean(),
alternative_lueftung: faker.datatype.boolean(),
alternative_warmwasser: faker.datatype.boolean(),
anteil_warmwasser_1: faker.number.int({ min: 0, max: 60 }),
anteil_warmwasser_2: faker.number.int({ min: 0, max: 60 }),
ausstellgrund: faker.helpers.enumValue(Enums.Ausstellgrund),
einheit_2: "kWh",
keller_beheizt: faker.datatype.boolean(),
registriernummer: faker.string.uuid(),
startdatum: faker.date.past({ years: 3 }),
verbrauch_4: verbrauch_4,
verbrauch_5: verbrauch_4 + faker.number.int({ min: -2000, max: 2000 }),
verbrauch_6: verbrauch_4 + faker.number.int({ min: -2000, max: 2000 }),
warmwasser_anteil_bekannt: faker.datatype.boolean(),
wird_gekuehlt: faker.datatype.boolean(),
zusaetzliche_heizquelle: faker.datatype.boolean(),
}
return ausweis;
}

View File

@@ -1,37 +0,0 @@
import { z } from "zod";
export function zodGenerateDefaultSchema<Schema extends z.ZodFirstPartySchemaTypes>(schema: Schema): z.TypeOf<Schema> {
switch (schema._def.typeName) {
case z.ZodFirstPartyTypeKind.ZodDefault:
return schema._def.defaultValue();
case z.ZodFirstPartyTypeKind.ZodObject: {
// The switch wasn't able to infer this but the cast should
// be safe.
return Object.fromEntries(
Object.entries(
(schema as z.SomeZodObject).shape
).map(([key, value]) => [key, zodGenerateDefaultSchema(value)])
);
}
case z.ZodFirstPartyTypeKind.ZodString:
return "";
case z.ZodFirstPartyTypeKind.ZodNull:
return null;
case z.ZodFirstPartyTypeKind.ZodNullable:
return null;
case z.ZodFirstPartyTypeKind.ZodUndefined:
return undefined;
case z.ZodFirstPartyTypeKind.ZodNumber:
return 0;
case z.ZodFirstPartyTypeKind.ZodBoolean:
return false;
case z.ZodFirstPartyTypeKind.ZodOptional:
return undefined;
case z.ZodFirstPartyTypeKind.ZodNativeEnum:
return schema._def.values[0];
case z.ZodFirstPartyTypeKind.ZodArray:
return [];
default:
throw new Error(`Unsupported type ${schema._def.typeName}`);
}
}

View File

@@ -1,296 +0,0 @@
<script lang="ts">
import ProgressBar from "#components/Ausweis/Progressbar.svelte";
import type { Bezahlmethoden } from "@ibcornelsen/database/client";
import { Enums } from "@ibcornelsen/database/client";
import { dialogs } from "svelte-dialogs";
import LoginDialog from "#components/LoginDialog.svelte";
import { PRICES } from "#lib/constants.js";
import {
BenutzerClient,
VerbrauchsausweisWohnenClient,
} from "#components/Ausweis/types.js";
import { validateAccessTokenClient } from "src/client/lib/validateAccessToken.js";
import { client } from "src/trpc.js";
export let user: BenutzerClient;
export let ausweis: VerbrauchsausweisWohnenClient;
let services = [
{
name: "Qualitätsdruck per Post (zusätzlich zur PDF Version) für 9€ inkl. MwSt.",
id: Enums.Service.Qualitaetsdruck,
price: 9,
selected: false,
},
{
name: "Aushang (für öffentliche Gebäude gesetzlich vorgeschrieben) für 10€ inkl. MwSt.",
id: Enums.Service.Aushang,
price: 10,
selected: false,
},
{
name: "Same Day Service (Bestellung Werktags vor 12:00 Uhr - Ausstellung bis 18:00 Uhr am gleichen Tag) für 29€ inkl. MwSt.",
id: Enums.Service.SameDay,
price: 29,
selected: false,
},
{
name: "Telefonische Energieeffizienzberatung für 75€ inkl. MwSt.",
id: Enums.Service.Telefonberatung,
price: 75,
selected: false,
},
];
export let selectedPaymentType: Bezahlmethoden =
Enums.Bezahlmethoden.paypal;
let prices: number[] = [];
if (ausweis.aufnahme.ausweisart) {
prices = PRICES[ausweis.aufnahme.ausweisart];
}
let basePrice: number = prices[0];
$: price =
basePrice +
services.reduce(
(acc, service) => (service.selected && acc + service.price) || acc,
0
);
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,
});
window.location.href = `/kaufabschluss?uid=${ausweis.uid}`;
}
</script>
<form on:submit={speichern}>
<div class="grid grid-cols-[1.5fr_2fr] gap-4">
<div
class="rounded-lg border p-4 border-base-300 bg-base-100 flex flex-col gap-4"
>
<div class="flex flex-col gap-2 test-box">
<strong>A - Prüfung der Ausweisart</strong>
<div>
<span>Vermietung, Verkauf oder sonstiges</span>
<span
>Baujahr Heizung nicht kleiner als Baujahr Gebäude</span
><span
>Baujahr nach 1977 oder saniert oder mehr als 4
Wohneinheiten</span
><span>Heizung min. 3 Jahre alt</span><span
>Verbrauchsausweis zulässig</span
>
</div>
</div>
<div class="flex flex-col gap-2 test-box">
<strong
>B - Prüfung der Adresse, Wohnfläche, Keller und Dach</strong
>
<div>
<span>PLZ gültig</span><span>Klimafaktorern</span><span
>Wohnfläche passt zu Wohneinheiten</span
>
</div>
</div>
<div class="flex flex-col gap-2 test-box">
<strong>C - Prüfung der Verbrauchsangaben</strong>
<div>
<span>Verbrauchsmenge schlüssig</span><span
>Verbrauchsabweichung im Rahmen</span
><span>Endenergieverbrauch schlüssig</span>
</div>
</div>
<div class="flex flex-col gap-2 test-box">
<strong
>D - Prüfung Warmwasser und alternative
Energieversorgung</strong
>
<div>
<span>Warmwasseranteil schlüssig</span>
</div>
</div>
<div class="flex flex-col gap-2 test-box">
<strong
>E - Prüfung von Gebäudetyp, Lüftung, Kühlung und
Leerstand</strong
>
<div>
<span>Leerstand nicht größer als 30%</span>
</div>
</div>
<div class="flex flex-col gap-2 test-box">
<strong
>F - Prüfung des Sanierungsstandes und der Gebäudebilder</strong
>
<div>
<span>Mindestens ein Bild pro Abschnitt vorhanden</span
><span>Angaben zum Sanierungsstand vorhanden</span><span
>Bei Baujahr vor 1978 Dach oder Geschossdecke min.
12 cm gedämmt</span
>
</div>
</div>
</div>
<div>
<div
class="rounded-lg border p-4 border-base-300 bg-base-100 flex flex-col"
>
<table>
<tr>
<td><strong>Produkt:</strong></td>
<td><div class="py-2">Verbrauchsausweis</div></td>
</tr>
<tr>
<td><strong>Beschreibung:</strong></td>
<td>
<div class="py-2">
Registrierung beim DiBt<br />
Prüfung durch Diplom Ingenieur<br />
Energieausweis Vorschau als PDF<br />
</div>
</td>
</tr>
<tr>
<td>Netto-Preis</td>
<td
><div class="py-2">
{(price * 0.81).toFixed(2) + "€"}
</div></td
>
</tr>
<tr>
<td>19% gesetzl. MwSt.</td>
<td
><div class="py-2">
{(price * 0.19).toFixed(2) + "€"}
</div></td
>
</tr>
<hr />
<tr>
<td>Preis inkl. MwSt.</td>
<td
><div class="py-2">
<strong>{price + "€"}</strong>
</div>
</td>
</tr>
</table>
</div>
<h3 class="font-semibold mt-8">
Hiermit bestelle ich folgende Version des Energieausweises:
</h3>
<div
class="rounded-lg border p-4 border-base-300 bg-base-100 flex flex-col"
>
<table>
<tr>
<td
>Verbrauchsausweis online für {prices[0]} € inkl.
MwSt. als PDF per E-Mail</td
>
<td
><input
type="radio"
class="radio radio-secondary"
bind:group={basePrice}
value={prices[0]}
name="Preis"
checked
/>
</td>
</tr>
<tr>
<td
>Verbrauchsausweis online inkl. Beratung für {prices[1]}
€ inkl. MwSt. als PDF per E-Mail</td
>
<td
><input
type="radio"
class="radio radio-secondary"
bind:group={basePrice}
value={prices[1]}
name="Preis"
/>
</td>
</tr><tr>
<td
>Verbrauchsausweis offline für {prices[2]} € inkl.
MwSt. als PDF per E-Mail (Sie schicken uns 3 Verbrauchsabrechnungen)</td
>
<td
><input
type="radio"
class="radio radio-secondary"
bind:group={basePrice}
value={prices[2]}
name="Preis"
/></td
>
</tr>
</table>
</div>
<h3 class="font-semibold mt-8">Zusatzleistungen</h3>
<div
class="rounded-lg border p-4 border-base-300 bg-base-100 flex flex-col"
>
<table>
{#each services as service}
<tr>
<td>{service.name}</td>
<td
><input
type="checkbox"
class="checkbox checkbox-secondary"
bind:checked={service.selected}
/>
</td>
</tr>
{/each}
</table>
</div>
</div>
</div>
<div class="flex flex-row justify-between">
<!-- TODO: Zurück implementieren -->
<button class="btn btn-secondary mt-4">Zurück</button>
<div class="flex flex-row gap-4">
<!-- TODO: Speichern implementieren -->
<button class="btn btn-secondary mt-4">Speichern</button>
<button class="btn btn-secondary mt-4">Zum Kaufabschluss</button
>
</div>
</div>
</form>
<style>
.test-box div {
@apply flex flex-col gap-1.5;
}
</style>

View File

@@ -1,8 +1,8 @@
<script lang="ts"> <script lang="ts">
import { addNotification } from "@ibcornelsen/ui"; import { addNotification } from "@ibcornelsen/ui";
import { CrossCircled } from "radix-svelte-icons"; import { CrossCircled } from "radix-svelte-icons";
import {client} from "src/trpc.js";
import { fade } from "svelte/transition"; import { fade } from "svelte/transition";
import { api } from "astro-typesafe-api/client";
let passwort: string; let passwort: string;
let email: string; let email: string;
@@ -14,7 +14,7 @@
async function login(e: SubmitEvent) { async function login(e: SubmitEvent) {
e.preventDefault() e.preventDefault()
try { try {
const response = await client.v1.benutzer.erstellen.mutate({ const { uid } = await api.user.PUT.fetch({
email, email,
passwort, passwort,
vorname, vorname,

View File

@@ -2,7 +2,7 @@
import { validateAccessTokenClient } from "#client/lib/validateAccessToken.js"; import { validateAccessTokenClient } from "#client/lib/validateAccessToken.js";
import { verbrauchsausweisWohnenSpeichern } from "#client/lib/verbrauchsausweisWohnenSpeichern.js"; import { verbrauchsausweisWohnenSpeichern } from "#client/lib/verbrauchsausweisWohnenSpeichern.js";
import { AufnahmeClient, BenutzerClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js"; import { AufnahmeClient, BenutzerClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { addNotification, updateNotification } from "#components/Notifications/index.js"; import { addNotification } from "#components/Notifications/index.js";
import Overlay from "#components/Overlay.svelte"; import Overlay from "#components/Overlay.svelte";
import EmbeddedAuthFlowModule from "#modules/EmbeddedAuthFlowModule.svelte"; import EmbeddedAuthFlowModule from "#modules/EmbeddedAuthFlowModule.svelte";
@@ -14,56 +14,6 @@
export let user: BenutzerClient; export let user: BenutzerClient;
export let aufnahme: AufnahmeClient; export let aufnahme: AufnahmeClient;
async function bilderHochladen() {
// Alle Bilder hochladen
if (images.length === 0) {
return
}
const notification = addNotification({
dismissable: false,
message: "Bilder hochladen.",
subtext: `${images.length} Bilder werden hochgeladen, bitte haben sie Geduld.`,
timeout: 0,
type: "info"
})
for (let i = 0; i < images.length; i++) {
const image = images[i];
if (image.uid) {
// Bild wurde bereits hochgeladen, wir müssen es also nicht nochmal hochladen.
continue
}
try {
const response = await api.objekt._uid.bilder.PUT.fetch({
base64: image.base64,
kategorie: image.kategorie
}, {
params: {
uid: objekt.uid
}
})
image.uid = response.uid
updateNotification(notification, {
dismissable: true,
message: "Bild hochgeladen.",
subtext: `${i + 1}/${images.length} Bildern wurden erfolgreich hochgeladen, bitte haben sie Geduld.`,
timeout: 4000
})
} catch (e) {
updateNotification(notification, {
dismissable: true,
message: "Bild konnte nicht hochgeladen werden.",
subtext: `Bild ${i + 1}/${images.length} konnte nicht hochgeladen werden, wir haben bereits ein Ticket erstellt und melden uns so schnell wie möglich bei ihnen.`,
timeout: 150000,
type: "error"
})
}
}
}
async function ausweisSpeichern() { async function ausweisSpeichern() {
// Um einen Ausweis zu speichern müssen wir eingeloggt sein, andernfalls wird die API den call ablehnen. // 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. // Wir prüfen also ob wir eingeloggt sind und leiten den Nutzer ggf. auf die Login Seite weiter.
@@ -81,11 +31,9 @@
const response = await verbrauchsausweisWohnenSpeichern(ausweis, const response = await verbrauchsausweisWohnenSpeichern(ausweis,
objekt, objekt,
aufnahme, aufnahme,
images, images)
user)
if (response !== null) { if (response !== null) {
await bilderHochladen();
// Falls der Nutzer zurück navigiert, sollte er wieder auf seinen Vorgang kommen. // Falls der Nutzer zurück navigiert, sollte er wieder auf seinen Vorgang kommen.
// Sonst müsste er alles neu eingeben... // Sonst müsste er alles neu eingeben...
ausweis.uid = response.uid_ausweis; ausweis.uid = response.uid_ausweis;
@@ -94,8 +42,6 @@
return true return true
} }
return false;
} catch (e: any) { } catch (e: any) {
await api.ticket.PUT.fetch({ await api.ticket.PUT.fetch({
titel: "Ausweis konnte nicht gespeichert werden", titel: "Ausweis konnte nicht gespeichert werden",

View File

@@ -1,858 +0,0 @@
<script lang="ts">
import PerformanceScore from "#components/Ausweis/PerformanceScore.svelte";
import Progressbar from "#components/Ausweis/Progressbar.svelte";
import Hilfe from "#components/Ausweis/Hilfe.svelte";
import HelpLabel from "#components/HelpLabel.svelte";
import Verbrauch from "#components/Ausweis/Verbrauch.svelte";
import Label from "#components/Label.svelte";
import Ausweisart from "#components/Ausweis/Ausweisart.svelte";
import ZipSearch from "#components/PlzSuche.svelte";
import moment from "moment";
import BilderZusatzsysteme from "#components/Ausweis/BilderZusatzsysteme.svelte";
import { RawNotificationWrapper, RawNotification, notifications } from "#components/Notifications/index.js";
import { auditHeizungGebaeudeBaujahr } from "#components/Verbrauchsausweis/audits/HeizungGebaeudeBaujahr.js";
import { auditHeizungJuengerDreiJahre } from "#components/Verbrauchsausweis/audits/HeizungJuengerDreiJahre.js";
import { auditZeitraumAktuell } from "#components/Verbrauchsausweis/audits/ZeitraumAktuell.js";
import { auditKlimaFaktoren } from "#components/Verbrauchsausweis/audits/KlimaFaktoren.js";
import { auditWohnFlaeche } from "#components/Verbrauchsausweis/audits/WohnFlaeche.js";
import { auditWarmWasser } from "#components/Verbrauchsausweis/audits/WarmWasser.js";
import { auditLeerStand } from "#components/Verbrauchsausweis/audits/LeerStand.js";
import { auditPlzNichtErkannt } from "#components/Verbrauchsausweis/audits/PlzNichtErkannt.js";
import { AuditType, hidden } from "#components/Verbrauchsausweis/audits/hidden.js";
import { auditBedarfsausweisBenoetigt } from "#components/Verbrauchsausweis/audits/BedarfsausweisBenoetigt.js";
import { auditVerbrauchAbweichung } from "#components/Verbrauchsausweis/audits/VerbrauchAbweichung.js";
import { auditEndEnergie } from "#components/Verbrauchsausweis/audits/EndEnergie.js";
import { auditWohnflaecheGroesserGesamtflaeche } from "#components/Verbrauchsausweis/audits/WohnflaecheGroesserGesamtflaeche.js";
import { Enums } from "@ibcornelsen/database/client"
import Overlay from "#components/Overlay.svelte";
import AusweisGespeichertModule from "./AusweisGespeichertModule.svelte";
import { VerbrauchsausweisWohnenClient, BenutzerClient, UploadedGebaeudeBild } from "#components/Ausweis/types.js";
import { verbrauchsausweisWohnenSpeichern } from "src/client/lib/verbrauchsausweisWohnenSpeichern.js";
// 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...
export let ausweis: VerbrauchsausweisWohnenClient;
export let user: BenutzerClient = {} as BenutzerClient;
let aufnahme = ausweis.aufnahme || {};
let gebaeude = ausweis.aufnahme?.objekt || {};
let images: (UploadedGebaeudeBild & { base64?: string })[] = ausweis.aufnahme?.objekt?.gebaeude_bilder || [];
async function spaeterWeitermachen() {
const result = await verbrauchsausweisWohnenSpeichern(ausweis, gebaeude, aufnahme, images, user);
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
gebaeude.uid = result.gebaeude_uid
aufnahme.uid = result.gebaeude_aufnahme_uid
window.history.pushState({}, "", `${location.pathname}?uid=${result.uid}`);
speichernOverlayHidden = false;
}
}
function automatischAusfüllen() {
aufnahme.baujahr_gebaeude = [1962];
aufnahme.baujahr_heizung = [1952];
aufnahme.saniert = true;
aufnahme.einheiten = 1;
ausweis.ausstellgrund = "Vermietung";
ausweis.verbrauch_1 = 15000;
ausweis.verbrauch_2 = 14000;
ausweis.verbrauch_3 = 16000;
aufnahme.flaeche = 152;
aufnahme.nutzflaeche = 172;
ausweis.keller_beheizt = true;
aufnahme.brennstoff_1 = "Erdgas H";
ausweis.einheit_1 = "kWh";
ausweis.anteil_warmwasser_1 = 18;
ausweis.startdatum = moment("01.01.2019").toDate();
aufnahme.plz = "21039";
aufnahme.ort = "Hamburg";
aufnahme.adresse = "Curslacker Deich 170";
aufnahme.gebaeudeteil = "Gesamtgebäude";
gebaeude = gebaeude;
ausweis = ausweis;
}
async function ausweisAbschicken(e: SubmitEvent) {
if (e && e.preventDefault) e.preventDefault();
const result = await verbrauchsausweisWohnenSpeichern(ausweis, gebaeude, aufnahme, images, user);
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
gebaeude.uid = result.gebaeude_uid
aufnahme.uid = result.gebaeude_aufnahme_uid
window.history.pushState({}, "", `${location.pathname}?uid=${result.uid}`);
window.location.href = `/kundendaten?uid=${result.uid}`;
}
}
let waitOverlayHidden = true;
let speichernOverlayHidden = true;
$: {
if (aufnahme.saniert
&& aufnahme.oberste_geschossdecke_gedaemmt === undefined
&& aufnahme.dachgeschoss_gedaemmt === undefined) {
aufnahme.oberste_geschossdecke_gedaemmt = true;
aufnahme.dachgeschoss_gedaemmt = true;
}
}
</script>
<Overlay bind:hidden={speichernOverlayHidden}>
<div class="bg-white w-full max-w-screen-sm py-8 px-8">
<AusweisGespeichertModule uid={ausweis.uid}></AusweisGespeichertModule>
</div>
</Overlay>
<Overlay bind:hidden={waitOverlayHidden}>
<p class="text-white font-semibold text-4xl">
Bitte warten sie, ihr Ausweis wird nun erstellt.
</p>
</Overlay>
<div class="flex flex-row gap-8 items-center mb-8">
<div class="flex flex-col w-full">
<h1>Verbrauchsausweis erstellen - 45€</h1>
<Progressbar progress={0} />
</div>
<PerformanceScore
bind:ausweis
bind:aufnahme={aufnahme}
bind:objekt={gebaeude}
/>
</div>
<form on:submit={ausweisAbschicken} name="ausweis" data-test="ausweis">
<div class="yellow-box">
<div class="flex flex-row justify-between">
<button class="button" type="button" on:click={spaeterWeitermachen}
>Später Weitermachen</button
>
<div class="flex gap-4">
<Hilfe />
<button
on:click={automatischAusfüllen}
type="button"
class="button">Automatisch Ausfüllen</button
>
</div>
</div>
<hr />
<Label>A - Prüfung der Ausweisart</Label>
<Ausweisart
bind:objekt={gebaeude}
bind:aufnahme={aufnahme}
bind:ausweis
/>
<hr />
<Label
>B - Eingabe der Gebäudeadresse - Angaben zu Wohnfläche, Kellerund
Dachgeschoss</Label
>
<div class="GRB">
<!-- Strasse -->
<div class="form-group col-md-4">
<HelpLabel title="Straße, Hausnummer *">
Bitte geben Sie hier die Straße und Hausnummer des Gebäudes
ein.
</HelpLabel>
<div>
<input
name="adresse"
data-test="adresse"
type="text"
autocomplete="off"
required
data-msg-minlength="min. 5 Zeichen"
data-msg-maxlength="max. 40 Zeichen"
bind:value={aufnahme.adresse}
/>
</div>
</div>
<!-- PLZ -->
<div class="form-group col-md-4 PLZ">
<ZipSearch
bind:zip={aufnahme.plz}
bind:city={aufnahme.ort}
name="plz"
/>
</div>
<div class="form-group col-md-4">
<HelpLabel title="Ort *">
Ort des Gebäudes wird automatisch ermittelt.
</HelpLabel>
<div>
<input
name="ort"
data-test="ort"
readonly={true}
bind:value={aufnahme.ort}
type="text"
/>
</div>
</div>
<!-- Wohnfläche -->
<div class="form-group col-md-3">
<HelpLabel title="Wohnfläche m² *">
Bitte geben Sie hier die beheizte Wohnfläche in m² ein.
Dabei handelt es sich um die Wohnfläche abzüglich
vorhandener Flächen die sich außerhalb des Gebäudes
befinden. (Balkone, Terassen,etc.).
</HelpLabel>
<div>
<input
name="flaeche"
data-test="flaeche"
maxlength="4"
type="number"
required
autocomplete="off"
data-rule-minlength="2"
data-msg-minlength="min. 2 Zeichen"
bind:value={aufnahme.flaeche}
/>
</div>
</div>
<!-- Keller -->
<div class="form-group col-md-3">
<Label>Keller *</Label>
<div>
<select
name="keller"
data-test="keller"
required
bind:value={aufnahme.keller}
>
<option disabled>Bitte auswählen</option>
<option value={Enums.Heizungsstatus.NICHT_VORHANDEN}
>nicht vorhanden</option
>
<option value={Enums.Heizungsstatus.UNBEHEIZT}
>unbeheizt</option
>
<option value={Enums.Heizungsstatus.BEHEIZT}
>beheizt</option
>
</select>
</div>
</div>
<!-- Dachgeschoss -->
<div class="form-group col-md-3">
<Label>Dachgeschoss *</Label>
<div>
<select
name="dachgeschoss"
data-test="dachgeschoss"
bind:value={aufnahme.dachgeschoss}
required
>
<option disabled>Bitte auswählen</option>
<option value={Enums.Heizungsstatus.NICHT_VORHANDEN}
>nicht vorhanden</option
>
<option value={Enums.Heizungsstatus.UNBEHEIZT}
>unbeheizt</option
>
<option value={Enums.Heizungsstatus.BEHEIZT}
>beheizt</option
>
</select>
</div>
</div>
<!-- Gesamtfläche -->
<div class="form-group col-md-3">
<HelpLabel title="Gesamtfläche m²">
Bitte geben Sie hier die beheizte Gesamtfläche in m² ein
(wenn bekannt). Dabei handelt es sich um die Wohnfläche +
weiterer Flächen innerhalb des Gebäudes (z.B. Fläche des
beheizten Kellers). Diese Fläche wird dann im Energieausweis
als energetische Nutzfläche (An) ausgewiesen.
</HelpLabel>
<div>
<input
name="nutzflaeche"
data-test="nutzflaeche"
maxlength="4"
type="number"
required
autocomplete="off"
data-rule-minlength="2"
data-msg-minlength="min. 2 Zeichen"
bind:value={aufnahme.nutzflaeche}
/>
</div>
</div>
</div>
<hr />
<Label>C - Eingabe von 3 zusammenhängenden Verbrauchsjahren</Label>
<div class="GRB">
<Verbrauch
bind:gebaeude
bind:aufnahme
bind:ausweis
/>
</div>
<hr />
<Label
>D - Eingabe Warmwasseranteil und Verwendung von alternativen
Energieversorgungssystemen</Label
>
<div class="GRB">
<!-- Anteil WW enthalten -->
<div class="flex flex-col">
<div class="flex flex-row gap-4 items-center">
<input
type="checkbox"
class="checkbox"
name="warmwasser_enthalten"
data-test="warmwasser_enthalten"
bind:checked={ausweis.warmwasser_enthalten}
/>
<Label>Warmwasser im Verbrauch enthalten</Label>
</div>
<div class="flex flex-row gap-4 items-center">
<input
type="checkbox"
class="checkbox"
name="warmwasser_anteil_bekannt"
data-test="warmwasser_anteil_bekannt"
bind:checked={ausweis.warmwasser_anteil_bekannt}
disabled={!ausweis.warmwasser_enthalten}
/>
<Label>Anteil bekannt</Label>
</div>
</div>
<!-- Warmwasser Antel -->
<div class="form-group col-md-2">
<HelpLabel title="% Anteil Warmwasser">
Wenn bekannt geben Sie den Anteil der Warmwasser-Versorgung
hier ein. Standardmäßig wird ein Anteil von 18% angenommen.
</HelpLabel>
<input
name="anteil_warmwasser_1"
data-test="anteil_warmwasser_1"
maxlength="2"
type="number"
bind:value={ausweis.anteil_warmwasser_1}
disabled={!ausweis.warmwasser_anteil_bekannt ||
!ausweis.warmwasser_enthalten}
autocomplete="off"
/>
</div>
<div class="form-group col-md-2">
<HelpLabel title="zusätzliche Heizquelle">
Wenn bekannt geben Sie den Anteil der Warmwasser-Versorgung
von der zusätzlichen Heizquelle hier ein. Standardmäßig wird
ein Anteil von 18% angenommen.
</HelpLabel>
<input
name="anteil_warmwasser_2"
data-test="anteil_warmwasser_2"
maxlength="3"
type="number"
autocomplete="off"
bind:value={ausweis.anteil_warmwasser_2}
disabled={!ausweis.zusaetzliche_heizquelle ||
!ausweis.warmwasser_anteil_bekannt ||
!ausweis.warmwasser_enthalten}
/>
</div>
<!-- Alternative Energieversorgungssyteme -->
<div class="form-group col-md-5">
<HelpLabel
title="Alternative Energieversorgungssysteme genutzt für "
>
Bitte setzen Sie den Haken falls nachhaltige CO2-Effiziente
Heizungssysteme vorhanden sind. Das wäre beispielsweise bei
Pelletofen, Wärmepumpe, BHKW, Solarsystem, etc. der Fall.
</HelpLabel>
<div class="flex flex-row gap-4">
<label class="checkbox-inline"
><input
type="checkbox"
name="alternative_heizung"
data-test="alternative_heizung"
bind:checked={ausweis.alternative_heizung}
value="Heizung"
/>Heizung</label
>
<label class="checkbox-inline"
><input
type="checkbox"
name="alternative_warmwasser"
data-test="alternative_warmwasser"
bind:checked={ausweis.alternative_warmwasser}
value="Warmwasser"
/>Warmwasser</label
>
<label class="checkbox-inline"
><input
type="checkbox"
name="alternative_lueftung"
data-test="alternative_lueftung"
bind:checked={ausweis.alternative_lueftung}
value="Lüftung"
/>Lüftung</label
>
<label class="checkbox-inline"
><input
type="checkbox"
name="alternative_kuehlung"
data-test="alternative_kuehlung"
bind:checked={ausweis.alternative_kuehlung}
value="Kühlung"
/>Kühlung</label
>
</div>
</div>
</div>
<hr />
<Label
>E - Eingabe von Gebäudetyp, Gebäudeteil, Lüftung, Kühlung und
Leerstand</Label
>
<div class="GRB">
<!-- Gebäudetyp -->
<div class="form-group col-md-3">
<HelpLabel title="Gebäudetyp *">
Bitte wählen Sie hier den Gebäudetyp aus.
</HelpLabel>
<div>
<select
name="gebaeudetyp"
data-test="gebaeudetyp"
bind:value={aufnahme.gebaeudetyp}
required
>
<option disabled>Bitte auswählen</option>
<option value="Einfamilienhaus">Einfamilienhaus</option>
<option value="Freistehendes Einfamilienhaus"
>Freistehendes Einfamilienhaus</option
>
<option value="Freistehendes Zweifamilienhaus"
>Freistehendes Zweifamilienhaus</option
>
<option value="Doppelhaushälfte"
>Doppelhaushälfte</option
>
<option value="Reihenendhaus">Reihenendhaus</option>
<option value="Reihenmittelhaus"
>Reihenmittelhaus</option
>
<option value="Mehrfamilienhaus"
>Mehrfamilienhaus</option
>
<option value="Wohn- und Geschäftshaus"
>Wohn- und Geschäftshaus</option
>
<option value="Atrium-Bungalow">Atrium-Bungalow</option>
<option value="Winkelbungalow">Winkelbungalow</option>
</select>
</div>
</div>
<!-- Gebäudeteil -->
<div class="form-group col-md-3">
<HelpLabel title="Gebäudeteil *">
Bitte geben Sie hier den Gebäudeteil ein. In den meisten
Fällen handelt es sich um das Gesamtgebäude. Sollte es sich
allerdings um ein Gebäude mit mehr als 10% Gewerbeanteil
handeln, so sollten 2 Ausweise erstellt werden. In diesem
Fall wählen Sie Gebäudeteil 'Wohnen' bzw. Gebäudeteil
'Gewerbe'.
</HelpLabel>
<div>
<select
name="gebaeudeteil"
data-test="gebaeudeteil"
bind:value={aufnahme.gebaeudeteil}
required
>
<option disabled>Bitte auswählen</option>
<option value="Gesamtgebäude">Gesamtgebäude</option>
<option value="Wohnen">Wohnen</option>
</select>
</div>
</div>
<!-- Lüftung -->
<div class="form-group col-md-2">
<HelpLabel title="Lüftung durch *">
Bitte geben Sie hier ein ob über die Fenster natürlich
belüftet wird oder über eine Lüftungsanlage.
</HelpLabel>
<div>
<select
name="lueftung"
data-test="lueftung"
required
bind:value={aufnahme.lueftung}
>
<option disabled>Bitte auswählen</option>
<option value="Fensterlüftung">Fensterlüftung</option>
<option value="Schachtlüftung">Schachtlüftung</option>
<option value="Lüftungsanlage ohne Wärmerückgewinnung"
>Lüftungsanlage ohne Wärmerückgewinnung</option
>
<option value="Lüftungsanlage mit Wärmerückgewinnung"
>Lüftungsanlage mit Wärmerückgewinnung</option
>
</select>
</div>
</div>
<!-- Lüftung -->
<div class="form-group col-md-2">
<HelpLabel title="Anlage Kühlung *">
Bitte geben Sie an ob das Gebäude im Sommer zusätzlich
gekühlt wird.
</HelpLabel>
<div>
<select
name="kuehlung"
data-test="kuehlung"
required
bind:value={aufnahme.kuehlung}
>
<option disabled>Bitte auswählen</option>
<option value="1">vorhanden</option>
<option value="0">nicht vorhanden</option>
</select>
</div>
</div>
<!-- Leerstand -->
<div class="form-group col-md-2">
<HelpLabel title="Leerstand in %">
Bitte geben Sie hier den Leerstand in % des Gesamtzeitraumes
(3 Jahre) ein. Zum Beispiel 4 Monate Leerstand in 36 Monaten
wären dann ca. 11%.
</HelpLabel>
<div>
<input
name="leerstand"
data-test="leerstand"
maxlength="2"
type="number"
bind:value={aufnahme.leerstand}
/>
</div>
</div>
</div>
<hr />
<Label
>F - Bitte prüfen Sie hier die Angaben zum Sanierungszustand des
Gebäudes</Label
>
<BilderZusatzsysteme bind:images bind:gebaeude bind:aufnahme bind:ausweis />
<hr />
<div class="flex flex-row justify-between">
<Hilfe />
<button type="submit" class="button">Weiter</button>
</div>
</div>
</form>
<RawNotificationWrapper>
{#each Object.entries($notifications) as [uid, notification] (uid)}
<RawNotification notification={{ ...notification, uid }}>
{@html notification.subtext}
</RawNotification>
{/each}
{#if auditBedarfsausweisBenoetigt(ausweis, aufnahme)}
<RawNotification
notification={{
message: "Bedarfsausweis benötigt!",
timeout: 0,
uid: "BEDARFSAUSWEIS",
dismissable: false,
type: "info",
}}
>
Sie benötigen einen Bedarfsausweis. <a href="/bedarfsausweis"
>Bitte führen Sie hier Ihre Eingabe für den Bedarfsausweis fort</a
>.
</RawNotification>
{/if}
{#await auditPlzNichtErkannt(objekt) then result}
{#if result}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "PLZ_NICHT_ERKANNT",
dismissable: false,
type: "warning",
}}
>
Die Postleitzahl konnte nicht zugeordnet werden. Bitte prüfen
Sie die Eingabe. Sollte die Postleitzahl korrekt eingegeben
sein, werden wir den Ort händisch zuordnen.
</RawNotification>
{/if}
{/await}
{#if auditHeizungGebaeudeBaujahr(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "HEIZUNG_GEBAEUDE_BAUJAHR",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.HEIZUNG_GEBAEUDE_BAUJAHR);
aufnahme = aufnahme;
},
type: "warning",
}}
>
Sie haben angegeben, dass ihre Heizung vor ihrem Gebäude konstruiert
wurde. Sind sie sich sicher, dass das stimmt?
</RawNotification>
{/if}
{#if auditHeizungJuengerDreiJahre(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "HEIZUNG_JUENGER_DREI_JAHRE",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.HEIZUNG_JUENGER_DREI_JAHRE);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Ihre Heizungsanlage ist jünger als 3 Jahre. Für den
Verbrauchsausweis müssen Sie mindestens 3 Verbrauchsjahre eingeben
die den aktuellen Stand des Gebäudes abbilden. Ein Verbrauchsausweis
ist daher nicht möglich. Bitte klicken Sie
<a href="/bedarfsausweis">hier</a> um zum Eingabeformular für den Bedarfsausweis
zu gelangen.
</RawNotification>
{/if}
{#if auditZeitraumAktuell(ausweis, gebaeude)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "ZEITRAUM_AKTUELL",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.ZEITRAUM_AKTUELL);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Verbrauchszeiträume sind nicht aktuell genug. Das Ende des
letzten Verbrauchszeitraumes darf nicht mehr als 18 Monate
zurückliegen. Ein Verbrauchsausweis ist mit diesen Zeiträumen daher
nicht möglich. Bitte klicken Sie <a href="/bedarfsausweis">hier</a> um
zum Eingabeformular für den Bedarfsausweis zu gelangen.
</RawNotification>
{/if}
{#await auditKlimaFaktoren(ausweis, gebaeude) then result}
{#if result}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "KLIMA_FAKTOREN",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.KLIMA_FAKTOREN);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Verbrauchszeiträume sind zu aktuell und es liegen noch keine
Klimafaktoren dazu vor. Bitte verschieben Sie die
Verbrauchszeiträume 1 Jahr nach hinten. Wenn das nicht möglich
ist, klicken Sie
<a href="/bedarfsausweis">hier</a> um zum Eingabeformular für den
Bedarfsausweis zu gelangen.
</RawNotification>
{/if}
{/await}
{#if auditWohnFlaeche(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "WOHN_FLAECHE",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.WOHN_FLAECHE);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Wohnfläche ist viel zu klein. Bitte überprüfen Sie Ihre Eingabe
nochmal und stellen sicher, daß sich Ihre Angaben auf das gesamte
Gebäude beziehen.
</RawNotification>
{/if}
{#if auditWarmWasser(ausweis)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "WARM_WASSER",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.WARM_WASSER);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Bitte überprüfen Sie nochmal die Höhe des Warmwasseranteils. Dieser
scheint nicht ganz im Rahmen zu liegen.
</RawNotification>
{/if}
{#if auditLeerStand(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "LEER_STAND",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.LEER_STAND);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Bei Leerstand größer als 30% darf kein Verbrauchsausweis ausgestellt
werden. Bitte klicken Sie <a href="/bedarfsausweis">hier</a> um zum Eingabeformular
für den Bedarfsausweis zu gelangen.
</RawNotification>
{/if}
{#if auditVerbrauchAbweichung(ausweis, aufnahme).length > 0}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "VERBRAUCH_ABWEICHUNG",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.VERBRAUCH_ABWEICHUNG);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Abweichung der Verbräuche zwischen Zeitraum {auditVerbrauchAbweichung(
ausweis,
aufnahme,
)[0]} und {auditVerbrauchAbweichung(ausweis, aufnahme)[1]} beträgt mehr
als 30% und sie haben keinen Leerstand angegeben. Sind sie sich sicher,
dass das stimmt?
</RawNotification>
{/if}
{#await auditEndEnergie(ausweis, gebaeude, aufnahme) then result}
{#if result}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "END_ENERGIE",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.END_ENERGIE);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Endenergie liegt außerhalb des normalen Rahmens. Bitte
nochmal überprüfen. Bei Passivhäusern oder ganz alten
unsanierten Gebäuden ist so eine Abweichung durchaus möglich.
</RawNotification>
{/if}
{/await}
{#if auditWohnflaecheGroesserGesamtflaeche(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "WOHNFLAECHE_GROESSER_GESAMTFLAECHE",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.WOHNFLAECHE_GROESSER_GESAMTFLAECHE);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Wohnfläche darf nicht größer als die Nutzfläche sein.
</RawNotification>
{/if}
</RawNotificationWrapper>
<style>
:global(input[type="number"]),
:global(input[type="text"]) {
@apply input input-bordered py-1.5 px-2 h-auto;
}
:global(input[type="number"]:disabled) {
@apply bg-gray-200 border border-gray-300;
}
:global(.linked) {
@apply border-2 border-red-400;
}
</style>

View File

@@ -66,8 +66,7 @@
ausweis, ausweis,
objekt, objekt,
aufnahme, aufnahme,
bilder, bilder
user
); );
if (result !== null) { if (result !== null) {
@@ -124,8 +123,7 @@
ausweis, ausweis,
objekt, objekt,
aufnahme, aufnahme,
bilder, bilder
user
); );
if (result !== null) { if (result !== null) {

View File

@@ -1,736 +0,0 @@
<script lang="ts">
import PerformanceScore from "#components/Ausweis/PerformanceScore.svelte";
import Progressbar from "#components/Ausweis/Progressbar.svelte";
import Hilfe from "#components/Ausweis/Hilfe.svelte";
import HelpLabel from "#components/HelpLabel.svelte";
import Verbrauch from "#components/Ausweis/Verbrauch.svelte";
import Label from "#components/Label.svelte";
import BereichLabel from "#components/labels/BereichLabel.svelte";
import Ausweisart from "#components/Ausweis/Ausweisart.svelte";
import ZipSearch from "#components/PlzSuche.svelte";
import moment from "moment";
import BilderZusatzsysteme from "#components/Ausweis/BilderZusatzsysteme.svelte";
import { RawNotificationWrapper, RawNotification, notifications } from "#components/Notifications/index.js";
import { auditHeizungGebaeudeBaujahr } from "#components/Verbrauchsausweis/audits/HeizungGebaeudeBaujahr.js";
import { auditHeizungJuengerDreiJahre } from "#components/Verbrauchsausweis/audits/HeizungJuengerDreiJahre.js";
import { auditZeitraumAktuell } from "#components/Verbrauchsausweis/audits/ZeitraumAktuell.js";
import { auditKlimaFaktoren } from "#components/Verbrauchsausweis/audits/KlimaFaktoren.js";
import { auditWohnFlaeche } from "#components/Verbrauchsausweis/audits/WohnFlaeche.js";
import { auditWarmWasser } from "#components/Verbrauchsausweis/audits/WarmWasser.js";
import { auditLeerStand } from "#components/Verbrauchsausweis/audits/LeerStand.js";
import { auditPlzNichtErkannt } from "#components/Verbrauchsausweis/audits/PlzNichtErkannt.js";
import { AuditType, hidden } from "#components/Verbrauchsausweis/audits/hidden.js";
import { auditBedarfsausweisBenoetigt } from "#components/Verbrauchsausweis/audits/BedarfsausweisBenoetigt.js";
import { auditVerbrauchAbweichung } from "#components/Verbrauchsausweis/audits/VerbrauchAbweichung.js";
import { auditEndEnergie } from "#components/Verbrauchsausweis/audits/EndEnergie.js";
import { auditWohnflaecheGroesserGesamtflaeche } from "#components/Verbrauchsausweis/audits/WohnflaecheGroesserGesamtflaeche.js";
import { Enums } from "@ibcornelsen/database/client"
import Overlay from "#components/Overlay.svelte";
import AusweisGespeichertModule from "./AusweisGespeichertModule.svelte";
import { VerbrauchsausweisWohnenClient, BenutzerClient, UploadedGebaeudeBild } from "#components/Ausweis/types.js";
import { verbrauchsausweisWohnenSpeichern } from "src/client/lib/verbrauchsausweisWohnenSpeichern.js";
// 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...
export let ausweis: VerbrauchsausweisWohnenClient;
export let user: BenutzerClient = {} as BenutzerClient;
let aufnahme = ausweis.aufnahme || {};
let gebaeude = ausweis.aufnahme?.objekt || {};
let images: (UploadedGebaeudeBild & { base64?: string })[] = ausweis.aufnahme?.objekt?.gebaeude_bilder || [];
async function spaeterWeitermachen() {
const result = await verbrauchsausweisWohnenSpeichern(ausweis, gebaeude, aufnahme, images, user);
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
gebaeude.uid = result.gebaeude_uid
aufnahme.uid = result.gebaeude_aufnahme_uid
window.history.pushState({}, "", `${location.pathname}?uid=${result.uid}`);
speichernOverlayHidden = false;
}
}
function automatischAusfüllen() {
aufnahme.baujahr_gebaeude = [1962];
aufnahme.baujahr_heizung = [1952];
aufnahme.saniert = true;
aufnahme.einheiten = 1;
ausweis.ausstellgrund = "Vermietung";
ausweis.verbrauch_1 = 15000;
ausweis.verbrauch_2 = 14000;
ausweis.verbrauch_3 = 16000;
aufnahme.flaeche = 152;
aufnahme.nutzflaeche = 172;
ausweis.keller_beheizt = true;
aufnahme.brennstoff_1 = "Erdgas H";
ausweis.einheit_1 = "kWh";
ausweis.anteil_warmwasser_1 = 18;
ausweis.startdatum = moment("01.01.2019").toDate();
aufnahme.plz = "21039";
aufnahme.ort = "Hamburg";
aufnahme.adresse = "Curslacker Deich 170";
aufnahme.gebaeudeteil = "Gesamtgebäude";
gebaeude = gebaeude;
ausweis = ausweis;
}
async function ausweisAbschicken(e: SubmitEvent) {
if (e && e.preventDefault) e.preventDefault();
const result = await verbrauchsausweisWohnenSpeichern(ausweis, gebaeude, aufnahme, images, user);
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
gebaeude.uid = result.gebaeude_uid
aufnahme.uid = result.gebaeude_aufnahme_uid
window.history.pushState({}, "", `${location.pathname}?uid=${result.uid}`);
window.location.href = `/kundendaten?uid=${result.uid}`;
}
}
let waitOverlayHidden = true;
let speichernOverlayHidden = true;
$: {
if (aufnahme.saniert
&& aufnahme.oberste_geschossdecke_gedaemmt === undefined
&& aufnahme.dachgeschoss_gedaemmt === undefined) {
aufnahme.oberste_geschossdecke_gedaemmt = true;
aufnahme.dachgeschoss_gedaemmt = true;
}
}
</script>
<Overlay bind:hidden={speichernOverlayHidden}>
<div class="bg-white w-full max-w-screen-sm py-8 px-8">
<AusweisGespeichertModule uid={ausweis.uid}></AusweisGespeichertModule>
</div>
</Overlay>
<Overlay bind:hidden={waitOverlayHidden}>
<p class="text-white font-semibold text-4xl">
Bitte warten sie, ihr Ausweis wird nun erstellt.
</p>
</Overlay>
<!-- <div class="flex flex-row gap-8 items-center mb-8">
<div class="flex flex-col w-full">
<h1>Verbrauchsausweis erstellen - 45€</h1>
<Progressbar progress={0} />
</div>
<PerformanceScore
bind:ausweis
bind:aufnahme
bind:gebaeude
/>
</div>-->
<form on:submit={ausweisAbschicken} name="ausweis" data-test="ausweis">
<div id="formular-box" class="formular-boxen ring-0">
<div class="w-full grid gap-x-4 gap-y-2
grid-cols-1
xs:grid-cols-2
">
<div class="md:justify-self-start"><button class="button" type="button" on:click={spaeterWeitermachen}>Später Weitermachen</button></div>
<div class="md:justify-self-end"><Hilfe /></div>
</div>
<div class="mt-2"><button class="button" on:click={automatischAusfüllen} type="button" >Automatisch Ausfüllen</button></div>
<hr />
<BereichLabel bereich="A">Prüfung der Ausweisart</BereichLabel>
<div class="bereich-box">
<Ausweisart
bind:objekt={gebaeude}
bind:aufnahme={aufnahme}
bind:ausweis
/>
</div>
<BereichLabel bereich="B">Eingabe der Gebäudeadresse -&nbsp;Angaben&nbsp;zu&nbsp;Wohnfläche, Keller&nbsp;und&nbsp;Dachgeschoss</BereichLabel>
<div class="bereich-box">
<div class="w-full grid
grid-cols-bereich-B gap-x-4
xl:grid-cols-bereich-B-xl xl:gap-x-8
2xl:grid-cols-bereich-B-2xl 2xl:gap-x-8
">
<div class="grid grid-cols-1 gap-x-4
md:grid-cols-2 md:gap-x-6 md:mb-6
xl:mb-0
2xl:grid-cols-3 2xl:gap-x-6
">
<!-- Strasse -->
<div class="md:col-span-2 2xl:col-span-1">
<HelpLabel title="* Straße, Hausnummer">
Bitte geben Sie hier die Straße und Hausnummer des Gebäudes
ein.
</HelpLabel>
<div>
<input
name="adresse"
data-test="adresse"
type="text"
autocomplete="off"
required
data-msg-minlength="min. 5 Zeichen"
data-msg-maxlength="max. 40 Zeichen"
bind:value={aufnahme.adresse}
/>
</div>
</div>
<!-- PLZ -->
<div class="PLZ">
<Label>* PLZ</Label>
<ZipSearch
bind:zip={aufnahme.plz}
bind:city={aufnahme.ort}
name="plz"
/>
</div>
<!-- Ort -->
<div class="">
<HelpLabel title="* Ort">
Ort des Gebäudes wird automatisch ermittelt.
</HelpLabel>
<div>
<input
name="ort"
data-test="ort"
readonly={true}
bind:value={aufnahme.ort}
type="text"
/>
</div>
</div>
</div>
<div class="grid grid-cols-1 gap-x-4
md:grid-cols-2 md:gap-x-6
2xl:grid-cols-4 2xl:gap-x-6
">
<!-- Wohnfläche -->
<div class="">
<HelpLabel title="* Wohnfläche m²">
Bitte geben Sie hier die beheizte Wohnfläche in m² ein.
Dabei handelt es sich um die Wohnfläche abzüglich
vorhandener Flächen die sich außerhalb des Gebäudes
befinden. (Balkone, Terassen,etc.).
</HelpLabel>
<div>
<input
name="flaeche"
data-test="flaeche"
maxlength="4"
type="number"
required
autocomplete="off"
data-rule-minlength="2"
data-msg-minlength="min. 2 Zeichen"
bind:value={aufnahme.flaeche}
/>
</div>
</div>
<!-- Gesamtfläche -->
<div class="">
<HelpLabel title="&nbsp;&nbsp;Gesamtfläche m²">
Bitte geben Sie hier die beheizte Gesamtfläche in m² ein
(wenn bekannt). Dabei handelt es sich um die Wohnfläche +
weiterer Flächen innerhalb des Gebäudes (z.B. Fläche des
beheizten Kellers). Diese Fläche wird dann im Energieausweis
als energetische Nutzfläche (An) ausgewiesen.
</HelpLabel>
<div>
<input
name="nutzflaeche"
data-test="nutzflaeche"
maxlength="4"
type="number"
required
autocomplete="off"
data-rule-minlength="2"
data-msg-minlength="min. 2 Zeichen"
bind:value={aufnahme.nutzflaeche}
/>
</div>
</div>
<!-- Keller -->
<div class="">
<Label>* Keller</Label>
<div>
<select
name="keller"
data-test="keller"
required
bind:value={aufnahme.keller}
>
<option disabled>Bitte auswählen</option>
<option value={Enums.Heizungsstatus.NICHT_VORHANDEN}
>nicht vorhanden</option
>
<option value={Enums.Heizungsstatus.UNBEHEIZT}
>unbeheizt</option
>
<option value={Enums.Heizungsstatus.BEHEIZT}
>beheizt</option
>
</select>
</div>
</div>
<!-- Dachgeschoss -->
<div class="">
<Label>* Dachgeschoss</Label>
<div>
<select
name="dachgeschoss"
data-test="dachgeschoss"
bind:value={aufnahme.dachgeschoss}
required
>
<option disabled>Bitte auswählen</option>
<option value={Enums.Heizungsstatus.NICHT_VORHANDEN}
>nicht vorhanden</option
>
<option value={Enums.Heizungsstatus.UNBEHEIZT}
>unbeheizt</option
>
<option value={Enums.Heizungsstatus.BEHEIZT}
>beheizt</option
>
</select>
</div>
</div>
</div>
</div>
</div>
<BereichLabel bereich="C">Eingabe von 3 zusammenhängenden Verbrauchsjahren</BereichLabel>
<div class="bereich-box">
<div class="w-full grid
grid-cols-bereich-C gap-x-4 gap-y-8
xl:grid-cols-bereich-C-xl xl:gap-x-8 xl:gap-y-0
2xl:grid-cols-bereich-C-2xl 2xl:gap-x-8
">
<Verbrauch
bind:gebaeude
bind:aufnahme
bind:ausweis
/>
</div>
</div>
<BereichLabel bereich="d">Eingabe Warmwasseranteil und Verwendung von alternativenEnergieversorgungssystemen</BereichLabel>
<div class="bereich-box">
<!-- Anteil WW enthalten -->
<div class="flex flex-col">
<div class="flex flex-row gap-4 items-center">
<input
type="checkbox"
class="checkbox"
name="warmwasser_enthalten"
data-test="warmwasser_enthalten"
bind:checked={ausweis.warmwasser_enthalten}
/>
<Label>Warmwasser im Verbrauch enthalten</Label>
</div>
<div class="flex flex-row gap-4 items-center">
<input
type="checkbox"
class="checkbox"
name="warmwasser_anteil_bekannt"
data-test="warmwasser_anteil_bekannt"
bind:checked={ausweis.warmwasser_anteil_bekannt}
disabled={!ausweis.warmwasser_enthalten}
/>
<Label>Anteil bekannt</Label>
</div>
</div>
<!-- Warmwasser Antel -->
<div class="form-group col-md-2">
<HelpLabel title="% Anteil Warmwasser">
Wenn bekannt geben Sie den Anteil der Warmwasser-Versorgung
hier ein. Standardmäßig wird ein Anteil von 18% angenommen.
</HelpLabel>
<input
name="anteil_warmwasser_1"
data-test="anteil_warmwasser_1"
maxlength="2"
type="number"
bind:value={ausweis.anteil_warmwasser_1}
disabled={!ausweis.warmwasser_anteil_bekannt ||
!ausweis.warmwasser_enthalten}
autocomplete="off"
/>
</div>
<div class="form-group col-md-2">
<HelpLabel title="zusätzliche Heizquelle">
Wenn bekannt geben Sie den Anteil der Warmwasser-Versorgung
von der zusätzlichen Heizquelle hier ein. Standardmäßig wird
ein Anteil von 18% angenommen.
</HelpLabel>
<input
name="anteil_warmwasser_2"
data-test="anteil_warmwasser_2"
maxlength="3"
type="number"
autocomplete="off"
bind:value={ausweis.anteil_warmwasser_2}
disabled={!ausweis.zusaetzliche_heizquelle ||
!ausweis.warmwasser_anteil_bekannt ||
!ausweis.warmwasser_enthalten}
/>
</div>
<!-- Alternative Energieversorgungssyteme -->
<div class="form-group col-md-5">
<HelpLabel
title="Alternative Energieversorgungssysteme genutzt für "
>
Bitte setzen Sie den Haken falls nachhaltige CO2-Effiziente
Heizungssysteme vorhanden sind. Das wäre beispielsweise bei
Pelletofen, Wärmepumpe, BHKW, Solarsystem, etc. der Fall.
</HelpLabel>
<div class="flex flex-row gap-4">
<label class="checkbox-inline"
><input
type="checkbox"
name="alternative_heizung"
data-test="alternative_heizung"
bind:checked={ausweis.alternative_heizung}
value="Heizung"
/>Heizung</label
>
<label class="checkbox-inline"
><input
type="checkbox"
name="alternative_warmwasser"
data-test="alternative_warmwasser"
bind:checked={ausweis.alternative_warmwasser}
value="Warmwasser"
/>Warmwasser</label
>
<label class="checkbox-inline"
><input
type="checkbox"
name="alternative_lueftung"
data-test="alternative_lueftung"
bind:checked={ausweis.alternative_lueftung}
value="Lüftung"
/>Lüftung</label
>
<label class="checkbox-inline"
><input
type="checkbox"
name="alternative_kuehlung"
data-test="alternative_kuehlung"
bind:checked={ausweis.alternative_kuehlung}
value="Kühlung"
/>Kühlung</label
>
</div>
</div>
</div>
<hr />
</div>
</form>
<RawNotificationWrapper>
{#each Object.entries($notifications) as [uid, notification] (uid)}
<RawNotification notification={{ ...notification, uid }}>
{@html notification.subtext}
</RawNotification>
{/each}
{#if auditBedarfsausweisBenoetigt(ausweis, aufnahme)}
<RawNotification
notification={{
message: "Bedarfsausweis benötigt!",
timeout: 0,
uid: "BEDARFSAUSWEIS",
dismissable: false,
type: "info",
}}
>
Sie benötigen einen Bedarfsausweis. <a href="/bedarfsausweis"
>Bitte führen Sie hier Ihre Eingabe für den Bedarfsausweis fort</a
>.
</RawNotification>
{/if}
{#await auditPlzNichtErkannt(objekt) then result}
{#if result}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "PLZ_NICHT_ERKANNT",
dismissable: false,
type: "warning",
}}
>
Die Postleitzahl konnte nicht zugeordnet werden. Bitte prüfen
Sie die Eingabe. Sollte die Postleitzahl korrekt eingegeben
sein, werden wir den Ort händisch zuordnen.
</RawNotification>
{/if}
{/await}
{#if auditHeizungGebaeudeBaujahr(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "HEIZUNG_GEBAEUDE_BAUJAHR",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.HEIZUNG_GEBAEUDE_BAUJAHR);
aufnahme = aufnahme;
},
type: "warning",
}}
>
Sie haben angegeben, dass ihre Heizung vor ihrem Gebäude konstruiert
wurde. Sind sie sich sicher, dass das stimmt?
</RawNotification>
{/if}
{#if auditHeizungJuengerDreiJahre(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "HEIZUNG_JUENGER_DREI_JAHRE",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.HEIZUNG_JUENGER_DREI_JAHRE);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Ihre Heizungsanlage ist jünger als 3 Jahre. Für den
Verbrauchsausweis müssen Sie mindestens 3 Verbrauchsjahre eingeben
die den aktuellen Stand des Gebäudes abbilden. Ein Verbrauchsausweis
ist daher nicht möglich. Bitte klicken Sie
<a href="/bedarfsausweis">hier</a> um zum Eingabeformular für den Bedarfsausweis
zu gelangen.
</RawNotification>
{/if}
{#if auditZeitraumAktuell(ausweis, gebaeude)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "ZEITRAUM_AKTUELL",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.ZEITRAUM_AKTUELL);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Verbrauchszeiträume sind nicht aktuell genug. Das Ende des
letzten Verbrauchszeitraumes darf nicht mehr als 18 Monate
zurückliegen. Ein Verbrauchsausweis ist mit diesen Zeiträumen daher
nicht möglich. Bitte klicken Sie <a href="/bedarfsausweis">hier</a> um
zum Eingabeformular für den Bedarfsausweis zu gelangen.
</RawNotification>
{/if}
{#await auditKlimaFaktoren(ausweis, gebaeude) then result}
{#if result}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "KLIMA_FAKTOREN",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.KLIMA_FAKTOREN);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Verbrauchszeiträume sind zu aktuell und es liegen noch keine
Klimafaktoren dazu vor. Bitte verschieben Sie die
Verbrauchszeiträume 1 Jahr nach hinten. Wenn das nicht möglich
ist, klicken Sie
<a href="/bedarfsausweis">hier</a> um zum Eingabeformular für den
Bedarfsausweis zu gelangen.
</RawNotification>
{/if}
{/await}
{#if auditWohnFlaeche(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "WOHN_FLAECHE",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.WOHN_FLAECHE);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Wohnfläche ist viel zu klein. Bitte überprüfen Sie Ihre Eingabe
nochmal und stellen sicher, daß sich Ihre Angaben auf das gesamte
Gebäude beziehen.
</RawNotification>
{/if}
{#if auditWarmWasser(ausweis)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "WARM_WASSER",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.WARM_WASSER);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Bitte überprüfen Sie nochmal die Höhe des Warmwasseranteils. Dieser
scheint nicht ganz im Rahmen zu liegen.
</RawNotification>
{/if}
{#if auditLeerStand(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "LEER_STAND",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.LEER_STAND);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Bei Leerstand größer als 30% darf kein Verbrauchsausweis ausgestellt
werden. Bitte klicken Sie <a href="/bedarfsausweis">hier</a> um zum Eingabeformular
für den Bedarfsausweis zu gelangen.
</RawNotification>
{/if}
{#if auditVerbrauchAbweichung(ausweis, aufnahme).length > 0}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "VERBRAUCH_ABWEICHUNG",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.VERBRAUCH_ABWEICHUNG);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Abweichung der Verbräuche zwischen Zeitraum {auditVerbrauchAbweichung(
ausweis,
aufnahme,
)[0]} und {auditVerbrauchAbweichung(ausweis, aufnahme)[1]} beträgt mehr
als 30% und sie haben keinen Leerstand angegeben. Sind sie sich sicher,
dass das stimmt?
</RawNotification>
{/if}
{#await auditEndEnergie(ausweis, gebaeude, aufnahme) then result}
{#if result}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "END_ENERGIE",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.END_ENERGIE);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Endenergie liegt außerhalb des normalen Rahmens. Bitte
nochmal überprüfen. Bei Passivhäusern oder ganz alten
unsanierten Gebäuden ist so eine Abweichung durchaus möglich.
</RawNotification>
{/if}
{/await}
{#if auditWohnflaecheGroesserGesamtflaeche(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "WOHNFLAECHE_GROESSER_GESAMTFLAECHE",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.WOHNFLAECHE_GROESSER_GESAMTFLAECHE);
gebaeude = gebaeude;
},
type: "warning",
}}
>
Die Wohnfläche darf nicht größer als die Nutzfläche sein.
</RawNotification>
{/if}
</RawNotificationWrapper>
<style>
</style>

View File

@@ -1,365 +0,0 @@
---
import { BoxWithHeading } from "@ibcornelsen/ui";
import Widget from "#components/Widget.svelte";
import Layout from "#layouts/Layout.astro";
import FeatureCard from "#components/FeatureCard.svelte";
---
<Layout title="Energieausweis online erstellen - Online Energieausweis">
<h1>Energieausweis online erstellen</h1>
<Widget client:load />
<h2>GEG gilt ab 1. Mai 2021 und löst die EnEV ab</h2>
<BoxWithHeading heading="Folgende Punkte ändern sich:">
<ul>
<li>
Erhöhte Sorgfaltspflicht bei der Erstellung der Energieausweise.
Insbesondere zur Einschätzung der Modernisierungsempfehlungen
werden jetzt Fotos der relevanten Bereiche von Dach, Fenster,
Heizung und Außenwand benötigt.
</li>
<li>
Die Primärenergiefaktoren zur Ermittlung des Gebäudekennwerts
werden jetzt direkt im GEG (§22 Primärenergiefaktoren) geregelt.
Dadurch wird mehr Transparenz und Nachvollziehbarkeit
geschaffen. Auch findet die Verwendung von Biogas aus dem
Erdgasnetz jetzt angemessen Berücksichtigung.
</li>
<li>
Die lokale Erzeugung von Strom über eine PV-Anlage wird besser
berücksichtigt und kann vom Jahres-Primärenergiebedarf abgezogen
werden (bis 45%).
</li>
<li>
Die Angabe der CO2-Emission des Gebäudes im Energieausweis wird
verplichtend eingeführt.
</li>
</ul>
</BoxWithHeading>
<h2>
Energieausweis nach aktueller GEG (vormals EnEV) geprüft vom Diplom
Ingenieur
</h2>
<div class="right-img">
<img
title="Energieausweis online erstellen"
src="images/Bedarfsausweis-Wohngebaeude-Beispiel.jpg"
alt="Energieausweis online erstellen"
/>
</div>Sie möchten Ihren <strong>Energieausweis online erstellen</strong>?
Auf dieser Seite finden Sie alle nötigen Informationen hierzu. Sollten Sie
sich nicht sicher sein <a href="/energieausweis-welcher-energieausweis"
>welchen Energieausweis</a
> Sie benötigen, können Sie sich bei uns umfassend informieren. Wir haben fürs
Sie alle wichtigen Informationen rund um die GEG und zur
<a href="/energieausweis-pflicht">Energieausweis Pflicht</a> zusammengetragen.
Zusätzlich haben wir die entscheidenden Informationen auf übersichtlichen Merkblättern
im PDF Format zum Download zusammengefasst. Sollten Sie noch Fragen zum Thema
Energieausweis online erstellen haben, stehen wir Ihnen gerne telefonisch unter
folgender Nummer: 040/209 339 850 zur Verfügung.
<hr />Mit dem <strong>Energieausweis</strong> werden Wohngebäude und Nichtwohngebäude
nach den Vorgaben der Energieeinsparverordnung <a
href="/enev-zusammenfassung">EnEV</a
>
energetisch bewertet. Das <a href="https://www.dibt.de/" target="blank"
>DIBt</a
>
(Deutsches Institut für Bautechnik) regelt die Grundsätze zur Ausstellung, Berechnung
und der Qualitätssicherung. Der Energieausweis beschreibt die entsprechenden
Energiekennwerte auf einer Farbskala, grün (A+/Effizienzhaus), gelb (D) und rot
(H / unsaniert). Es wird grundsätzlich zwischen zwei Energieausweisarten unterschieden:
<hr />
<div
style="border-left: 5px solid #f5b68c; border-right: 5px solid #f5b68c;"
class="px-4"
>
<p>
Der verbrauchsbasierte Energieausweis wird als <a
title="Verbrauchsausweis"
href="/energieausweis-erstellen/verbrauchsausweis-wohnen"
><strong>Verbrauchsausweis</strong></a
> bezeichnet. Dies ist der „kleine“ Energieausweis und kann bei Vermietung
und Verkauf in den meisten Fällen verwendet werden. Hier gehts direkt
zum Eingabeformular <br />→ <a
title="Energieausweis online erstellen - Verbrauchsausweis"
href="/energieausweis-erstellen/verbrauchsausweis-erstellen"
>Energieausweis online erstellen</a
>
<hr />
</p>
<p>
Der bedarfsbasierte Energieausweis wird als <a
title="Bedarfsausweis"
href="/bedarfsausweis/"><strong>Bedarfsausweis</strong></a
>bezeichnet. Dies ist der „große“ Energieausweis und kann immer
verwendet werden. Bei Neubau und Modernisierung ist er zwingend
vorgeschrieben. Hier gehts direkt zum Eingabeformular <br />→ <a
title="Energieausweis online erstellen - Bedarfsausweis"
href="/energieausweis-erstellen/bedarfsausweis-erstellen"
>Energieausweis online erstellen</a
>
</p>
</div>
<hr />
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
<FeatureCard heading="Verbrauchsausweis Wohngebäude" price={45} href="/energieausweis-erstellen/verbrauchsausweis-wohnen">
<div class="rpt_feature">Unsere Leistungen:</div>
<div class="rpt_feature">Prüfung durch Diplom Ingenieur</div>
<div class="rpt_feature">Energieausweis Vorschau als PDF</div>
<div class="rpt_feature">Ausweisdokument als PDF per E-Mail</div>
<div class="rpt_feature">Registrierung beim DiBt</div>
<div class="rpt_feature">Bearbeitung innhalb 24h</div>
<div class="rpt_feature">rechtssicher nach aktueller EnEV</div>
<div class="rpt_feature">telefonische Beratung</div>
</FeatureCard>
<FeatureCard heading="Bedarfsausweis Wohngebäude" price={75} href="/bedarfsausweis">
<div class="rpt_feature">Unsere Leistungen:</div>
<div class="rpt_feature">Prüfung durch Diplom Ingenieur</div>
<div class="rpt_feature">Energieausweis Vorschau als PDF</div>
<div class="rpt_feature">Ausweisdokument als PDF per E-Mail</div>
<div class="rpt_feature">Registrierung beim DiBt</div>
<div class="rpt_feature">Bearbeitung innhalb 24h</div>
<div class="rpt_feature">rechtssicher nach aktueller EnEV</div>
<div class="rpt_feature">telefonische Beratung</div>
</FeatureCard>
<FeatureCard heading="Verbrauchsausweis Gewerbe" price={65} href="/energieausweis-erstellen/verbrauchsausweis-gewerbe">
<div class="rpt_feature">Unsere Leistungen:</div>
<div class="rpt_feature">Prüfung durch Diplom Ingenieur</div>
<div class="rpt_feature">Energieausweis Vorschau als PDF</div>
<div class="rpt_feature">Ausweisdokument als PDF per E-Mail</div>
<div class="rpt_feature">Registrierung beim DiBt</div>
<div class="rpt_feature">Bearbeitung innhalb 24h</div>
<div class="rpt_feature">rechtssicher nach aktueller EnEV</div>
<div class="rpt_feature">telefonische Beratung</div>
</FeatureCard>
</div>
<hr />
<h2>Unterschied: Verbrauchsausweis und Bedarfsausweis</h2> Grundsätzlich unterscheidet
man beim Energieausweis zwischen Verbrauchsausweis und Bedarfsausweis.<h3>
Was ist ein Verbrauchsausweis?
</h3>
Der Verbrauchsausweis gibt den Energieverbrauch der Gebäudebewohner in den vergangenen
drei Jahren für Heizung und Warmwasserbereitung an. Um den <a
href="/enev-zusammenfassung#§-19-EnEV"
>Energieverbrauchskennwert zu ermitteln</a
>, wird der tatsächliche Energieverbrauch mithilfe eines standortbezogenen
Klimafaktors bereinigt. Der Durchschnittswert wird dann durch die sogenannte
energetische Gebäudenutzfläche (An) geteilt. So führt beispielsweise ein
hoher Verbrauch in einem einzelnen harten Winter nicht zu einer schlechteren
Beurteilung des Gebäudes. Der tatsächliche Energieverbrauch in einem Gebäude
oder einer Wohnung kann aufgrund des Witterungseinflusses vom
Energieverbrauchskennwert abweichen.Das Ergebnis im Verbrauchsausweis ist
stark vom individuellen Nutzungsverhalten der Bewohner abhängig. Wird in
einem energetisch schlechten Gebäude kaum geheizt, so kann der
Energieausweis trotzdem sehr gut ausfallen.<h3>
Was ist ein Bedarfsausweis?
</h3> Der Bedarfsausweis entsteht auf Grundlage einer technischen <a
href="/enev-zusammenfassung#§-18-EnEV"
>Analyse der Bausubstanz und der Heizungsanlage eines Gebäudes</a
> und ist unabhängig vom individuellen Nutzerverhalten. Die Farbverlaufsskala
im Bedarfsausweis weist zwei verschiedene Werte aus, die sehr unterschiedlich
ausfallen können einen Wert für den Endenergiebedarf und einen für den Primärenergiebedarf.
Zusätzlich wird noch ein Kennwert für die energetische Qualität der Gebäudehülle
dargestellt.Der Energiebedarf gibt die nach technischen Regeln berechnete, vom
konkreten Gebäude jährlich benötigte Energiemenge für Heizung, Lüftung und Warmwasserbereitung
an. Dabei werden bei der Berechnung standardisierte Randbedingungen beispielsweise
eine Innentemperatur von 19 Grad im beheizten Bereich des Gebäudes zugrunde
gelegt. Am Endenergiebedarf sollten sich Hausbewohner orientieren, wenn sie ihren
künftigen Energieverbrauch und die Energiekosten abschätzen wollen.Der Primärenergiebedarf
bildet die Gesamtenergieeffizienz eines Gebäudes ab. Er berücksichtigt neben
der Endenergie auch die so genannte „Vorkette“ (Erkundung, Gewinnung, Verteilung,
Umwandlung) der jeweils eingesetzten Energieträger (z.B. Heizöl, Gas, Strom,
erneuerbare Energien).Besonders niedrig fällt der Primärenergiebedarf aus, wenn
erneuerbare Energien (solare Strahlungsenergie, Geothermie, Energie aus Biomasse)
für die Energieversorgung im Gebäude eingesetzt werden. Am Primärenergiebedarf
können Verbraucher erkennen, wie umweltfreundlich ihr Gebäude ist.<h3>
Fazit Verbrauchsausweis / Bedarfsausweis
</h3> Geht es um den tatsächlichen Verbrauch der Energie, der den Aufwand für
Heizung und zentrale Warmwasserbereitung der vergangenen drei Jahre berücksichtigt,
wird der Energieverbrauchskennwert für den Verbrauchsausweis ermittelt. Bei gewerblichen
Objekten wird zusätzlich der Verbrauch für Beleuchtung und Klimatisierung mit
eingerechnet. Anhand der Zeiträume und der Lage des Gebäudes (Postleitzahl) werden
diese Daten ausgewertet und sowohl zeit-, als auch klimabereinigt zur Bewertung
der vorhandenen energetischen Qualität herangezogen.Für das Ausstellen des Bedarfsausweis
wird der rechnerische Energiebedarf unter standardisierten Randbedingungen benötigt.
Daten rund um Bausubstanz, Gebäudehülle und Heizanlage fließen in die Berechnung
mit ein. Bedarfsausweise widerspiegeln die tatsächliche energetische Qualität
eines Gebäudes damit wesentlich besser als die Verbrauchsausweise.
<hr />
<div class="start_infobox" title="Verbrauchsausweis Wohngebäude">
<div class="start_infobox_inside IB_VA_WG">
<img
alt="Energieausweis online erstellen - Verbrauchsausweis"
title="Energieausweis online erstellen - Verbrauchsausweis"
class="start_infobox_img"
src="/images/energieausweis-online-erstellen-verbrauchsausweis.png"
/>
<div class="title">Verbrauchsausweis Wohngebäude</div>
<hr />
<ul>
<li>
3 zusammenhängende Heizenergieverbräuche müssen eingegeben
werden.
</li>
<li>
Wohnfläche, Baujahr Gebäude und Baujahr Heizung müssen
eingegeben werden.
</li>
<li>
<div class="start_infobox_link">
<a
title="Verbrauchsausweis"
href="/energieausweis-erstellen/verbrauchsausweis-wohnenverbrauchsausweis-wohngebaeude"
>Verbrauchsausweis</a
>
bei fast allen Gebäuden möglich. (Baujahr &gt; 1977 - Vermietung/Verkauf)
</div>
</li>
</ul>
<div class="start_infobox_button">
<a
title="Verbrauchsausweis erstellen"
href="/energieausweis-erstellen/verbrauchsausweis-erstellen"
>Jetzt Verbrauchsausweis erstellen</a
>
</div>
</div>
</div>
<div class="start_infobox BA-WG" title="Bedarfssausweis Wohngebäude">
<div class="start_infobox_inside">
<img
alt="Energieausweis online erstellen - Bedarfsausweis"
title="Energieausweis online erstellen - Bedarfsausweis"
class="start_infobox_img"
src="/images/energieausweis-online-erstellen-verbrauchsausweis.png"
/>
<div class="title">Bedarfsausweis Wohngebäude</div>
<hr />
<ul>
<li>
Die verwendete Heizungsanlage (Standardkessel,
Brennwertkessel, etc.) muß eingegeben werden.
</li>
<li>
Grundrissgeometrie sowie Baujahr Heizung und Gebäude müssen
eingegeben werden.
</li>
<li>
<a
title="Bedarfsausweis"
href="/bedarfsausweis/bedarfsausweis-wohngebaeude"
>Bedarfsausweis</a
> bei allen Gebäuden möglich. Die Berechnung ist umfangreicher
und besser vergleichbar.
</li>
</ul>
<div class="start_infobox_button">
<a
title="Bedarfsausweis erstellen"
href="/energieausweis-erstellen/bedarfsausweis-erstellen"
>Jetzt Bedarfsausweis erstellen</a
>
</div>
</div>
</div>
<div class="start_infobox VANW_WG" title="Bedarfsausweis Gewerbe">
<div class="start_infobox_inside">
<img
alt="Energieausweis online erstellen - Bedarfsausweis Gewerbe"
title="Energieausweis online erstellen - Bedarfsausweis Gewerbe"
class="start_infobox_img"
src="/images/energieausweis-online-erstellen-verbrauchsausweis-gewerbe.png"
/>
<div class="title">Bedarfsausweis Gewerbe</div>
<hr />
<ul>
<li>
Aktuelle Grundriss- und Ansichtspläne werden für die
Zonierung benötigt.
</li>
<li>
Baubeschreibung (z.B. aus der Baugenehmigung) mit Angabe der
verwendeten Baustoffe und TGA.
</li>
<li>
Angabe vom Baujahr der Heizung, Gebäude und Klimaanlage.
</li>
<li>
<a
title="Bedarfsausweis Gewerbe"
href="/bedarfsausweis/bedarfsausweis-gewerbe"
>Bedarfsausweis Gewerbe</a
> bei allen Nichtwohngebäuden möglich (kann immmer verwendet
werden).
</li>
</ul>
<div class="start_infobox_button">
<a
href="/energieausweis-erstellen/bedarfsausweis-gewerbe-anfragen"
title="Bedarfsausweis Gewerbe anfragen"
>Jetzt Bedarfsausweis Gewerbe anfragen</a
>
</div>
</div>
</div>
<hr />
<h2>Energieausweis online erstellen</h2> Soll Wohneigentum veräußert oder bauliches
Teileigentum zum Erwerb angeboten werden, muss dem möglichen Käufer oder Leasingnehmer
auf Verlangen unverzüglich ein
<a href="enev-zusammenfassung#§-16a-EnEV">Energieausweis gezeigt werden</a>.
In den meisten Fällen ist hier ein Verbrauchsausweis ausreichend. Auch
Mietern oder Pächtern soll der Energieausweis unmittelbaren Aufschluss über
die energetischen Bedingungen des Gebäudes aufzeigen.Kommt der Anbieter der
offerierten Immobilie diesem Auftrag nach der Energieeinsparverordnung nicht
nach, drohen Bußgelder bis zu 15 000 Euro. Als Ausnahmen gelten Gebäude mit
nicht mehr als 50 m² Fläche sowie Baudenkmäler (<a
href="enev-zusammenfassung#§-16-EnEV">§ 16 Abs. 4 EnEV</a
>).Die Deutsche Energie-Agentur GmbH (<a
href="https://www.dena.de/"
target="blank">dena</a
>) empfiehlt bei Wohngebäuden generell den Bedarfsausweis. Er erlaubt eine
nutzerunabhängige Bewertung des Gebäudes. Zusätzlich können bei der
Erstellung eines Bedarfsausweises die Empfehlungen für Modernisierungen auf
der Basis einer technischen Analyse des Gebäudes ermittelt werden.
<hr />
<h2>Zusammenfassung: Was ist ein Energieausweis?</h2>
<ul id="start_ul_1">
<li>
Der Gesetzgeber hat zwei Arten des Energieausweises bestimmt: Den
Verbrauchsausweis und den Bedarfsausweis.
</li>
<li>
Je nach Gebäudeart, Baujahr, Nutzungsart gilt es verschiedene
Kriterien für den Energieausweis zu beachten.
</li>
<li>
Der Energieausweis ist ein Mittel, das als Starter für
Energiesparmaßnahmen definiert werden kann.
</li>
<li>
Mit Hilfe des Energieausweises kann sich der Marktwert einer
Immobilie erhöhen.
</li>
<li>
Der Energieausweis offenbart bauliche Mängel, die eine
Energieverschwendung mit sich bringen.
</li>
<li>
Im Energieausweis werden Sanierungs- bzw. Modernisierungsvorschläge
dokumentiert.
</li>
<li>
Anhand des Energiepasses lässt sich der energetische Zustand
verschiedener Gebäude miteinander vergleichen.
</li>
</ul>
</Layout>

View File

@@ -1,128 +0,0 @@
---
layout: ../layouts/Layout.astro
title: "Welcher Energieausweis?"
---
import WelcherAusweisWidget from "#components/widgets/WelcherAusweisWidget.svelte";
import TextboxCardTemplate from "#components/design/content/TextboxCardTemplate.svelte";
# Welcher Energieausweis ist der richtige?
## Machen Sie hier den Online Check, welcher Energieausweis der richtige ist:
Falls Sie nicht wissen sollten welchen Energieausweis Sie benötigen, können Sie
hier ganz einfach den Gebäudetyp und die entsprechende Maßnahme angeben und
bekommen als Ergebnis, den für Sie pasenden Energieausweis angezeigt.
<WelcherAusweisWidget client:load/>
## Bei Vermietung und Verkauf Ihres Wohnhauses ist der Verbrauchsausweis Wohngebäude ausreichend
In den meisten Fällen können Sie bei Vermietung oder Verkauf Ihrer Immobilie den
einfacheren Energieausweis erstellen lassen. Dieser Ausweis ist
verbrauchsorientiert und benötigt als Berechnungsgrundlage 3 zusammenhängende
Jahre der Heizenergieabrechnugen des Gebäudes. Wenn Ihnen also diese 3
Abrechnugsjahre vorliegen, und es gab dazwischen keine grundlegenden
Sanierungsmaßnahmen bzw. Heizungsaustausch, dann steht der Dateneingabe nichts
im Wege. Laut GEG (vormals EnEV) gibt es nur eine rechtliche Ausnahme, bei der
es nicht zulässig ist einen Verbrauchsausweis bei Vermietung und Verkauf zu
verwenden. Dies ist dann der Fall, wenn Ihr Gebäude gänzlich unsaniert ist, vor
1978 gebaut wurde und weniger als 5 Wohneinheiten besitzt. In diesem Fall oder
bei unvollständigen Verbrauchsabrechnungen (z.B. bei Leerstand), kann der
Bedarfsausweis Wohngebäude erstellt werden.
---
## Bei Neubau, Modernisierung, Änderung oder Erweiterung Ihres Wohnhauses benötigen Sie den Bedarfsausweis für Wohngebäude
Im der aktuellen GEG ist geregelt, wie bei Änderungen im Baubestand zu verfahren
ist. In §46-51 des GEG ist festgelegt welche Mindestanforderungen bei
Änderungen, Erweiterungen und Ausbau eingehalten werden müssen. Außerdem wird
beschrieben unter welchen Voraussetzungen ein Bedarfsausweis erstellt werden
muß. Dies ist z.B. nicht der Fall wenn nur einzelne Bauteile wie Dach, Außenwand
und Fenster erneuert werden oder die Erweiterung < 50 m² ist. Dann muß nur ein
Bauteilnachweis geführt werden.Bei Austausch der Heizungsanlage muß in jedem
Fall ein Bedarfsausweis erstellt werden. Es kann auch vorkommen, daß bei
Einzelmaßnahmen eine komplette Bedarfsberechnung durchgeführt werden muss wenn
der Bauteilnachweis die EnEV-Anforderungen nicht erfüllt. Bei
genehmigungspflichtigen Neubaumaßnahmen ist es vorgeschrieben vor Baubeginn
einen GEG-Nachweis (früher Wärmeschutznachweis) zu erstellen. Aus der
GEG-Berechnung kann später nach Fertigstellung der Bedarfsausweis erstellt
werden. In § 15-19 des GEG ist geregelt welche Anforderungen für Wohngebäude
eingehalten werden müssen.
---
<TextboxCardTemplate
TitelName="Folgende Dokumente und Informationen werden für den Bedarfsausweis benötigt:"
BulletPoints={[
["Grundriss- und Ansichtspläne sowie Baubeschreibung.", true],
["Die wärmeübertragenden Umfassngsflächen wie Dach, Außenwand, Fenster,Kellerdecke bzw. Boden werden aus den Plänen ermittelt.", true],
["Auch das Gebäudevolumen zur Ermittlung der energetischen Gebäudenutzfläche und die verschiedenen Nutzungszonen werden aus den Plänen erhoben.", false],
["Die verwendete Heizungsanlage mit den Wärmeübergabekomponenten (Heizkörper, Fußbodenheizung, etc) sowie Energieträger und Kessel werden aus der Baubeschreibung oder aus den Angaben des Bauherren herangezogen.", false],
]}
></TextboxCardTemplate>
Sollten Sie den Bedarfsausweis nur für Vermietung und Verkauf benötigen, dann
können Sie den Ausweis bei uns auch online erstellen lassen. Die Eingabedaten
werden dann nach einem vereinfachten Verfahren erhoben.
---
## Bei Vermietung und Verkauf Ihres Gewerbegebäudes benötigen Sie den Verbrauchsausweis Nichtwohngebäude (Gewerbe)
Bei Vermietung oder Verkauf Ihrer Gewerbeimmobilie können Sie den einfacheren
Energieausweis erstellen lassen. Der gewerbliche Verbrauchsausweis benötigt als
Berechnungsgrundlage den Stromverbrauch und den Heizenergieverbrauch des
Gebäudes. Es werden 3 zusammenhängende Jahre der Heizenergieabrechnugen und der
Stromabrechnung des Gebäudes benötigt. Wenn Ihnen also diese 3 Abrechnugsjahre
vorliegen und die Verbräuche lassen sich eindeutig zuordnen, dann steht der
Dateneingabe nichts im Wege.Es dürfen keine grundlegenden Sanierungsmaßnahmen
bzw. Heizungsaustausch während dieses Zeitraums durchgeführt worden sein. Wenn
diese Voraussetzungen nicht vorliegen, oder keine vollständigen
Verbrauchsabrechnungen vorliegen (z.B. bei Leerstand), dann kann alternativ der
Bedarfsausweis Nichtwohngebäude (Gewerbe) erstellt werden.
---
## Bei Neubau, Modernisierung, Änderung oder Erweiterung Ihres Gewerbegebäudes benötigen Sie den Bedarfsausweis für Nichtwohngebäude (Gewerbe)
In §46-51 des GEG ist festgelegt welche Mindestanforderungen bei Änderungen,
Erweiterungen und Ausbau eingehalten werden müssen. Außerdem wird beschrieben
unter welchen Voraussetzungen ein Bedarfsausweis erstellt werden muß. Dies ist
z.B. nicht der Fall wenn nur einzelne Bauteile wie Dach, Außenwand und Fenster
erneuert werden oder die Erweiterung < 50 m² ist. Dann muß nur ein
Bauteilnachweis geführt werden.Bei Austausch der Heizungsanlage muß in jedem
Fall ein Bedarfsausweis erstellt werden. Es kann auch vorkommen, daß bei
Einzelmaßnahmen eine komplette Bedarfsberechnung durchgeführt werden muss wenn
der Bauteilnachweis die EnEV-Anforderungen nicht erfüllt.Bei Neubauten ist es
vorgeschrieben vor Baubeginn einen GEG-Nachweis (früher Wärmeschutznachweis) zu
erstellen. Aus der GEG-Berechnung kann später nach Fertigstellung der
Bedarfsausweis erstellt werden. Im §18-19 des GEG ist geregelt welche
Anforderungen für Nichtwohngebäude eingehalten werden müssen.
---
<TextboxCardTemplate
TitelName="Folgende Dokumente und Informationen werden für den Bedarfsausweis Gewerbe benötigt:"
BulletPoints={[
["Grundriss- und Ansichtspläne sowie Baubeschreibung.", true],
["Die wärmeübertragenden Umfassngsflächen wie Dach, Außenwand, Fenster,Kellerdecke bzw. Boden werden aus den Plänen ermittelt.", true],
["Auch das Gebäudevolumen zur Ermittlung der energetischen Gebäudenutzfläche und die verschiedenen Nutzungszonen werden aus den Plänen erhoben.", false],
["Die verwendete Heizungsanlage mit den Wärmeübergabekomponenten (Heizkörper,Fußbodenheizung, etc) sowie Energieträger und Kessel werden aus der Baubeschreibung oder aus den Angaben des Bauherren herangezogen.", false],
["Anlagentechnik zu Kühlung und Lüftung der entsprechenden Nutzungszonen müssen definiert sein.", true],
["Die verwendete Beleuchtung der verschiedenen Nutzungszonen wird ebenfalls herangezogen", true],
]}
></TextboxCardTemplate>
Sollten Sie den Bedarfsausweis nur für Vermietung und Verkauf benötigen, dann
können Sie den Ausweis bei uns auch online erstellen lassen. Die Eingabedaten
werden dann nach einem vereinfachten Verfahren erhoben.

View File

@@ -1,3 +1,5 @@
import { AufnahmeClient, ZodOverlap } from "#components/Ausweis/types.js";
import { exclude } from "#lib/exclude.js";
import { authorizationMiddleware } from "#lib/middleware/authorization.js"; import { authorizationMiddleware } from "#lib/middleware/authorization.js";
import { AufnahmeSchema, prisma } from "@ibcornelsen/database/server"; import { AufnahmeSchema, prisma } from "@ibcornelsen/database/server";
import { APIError, defineApiRoute } from "astro-typesafe-api/server"; import { APIError, defineApiRoute } from "astro-typesafe-api/server";
@@ -55,6 +57,13 @@ export const GET = defineApiRoute({
} }
} }
}, },
output: ZodOverlap<AufnahmeClient>(AufnahmeSchema.omit({
id: true,
objekt_id: true,
benutzer_id: true
}).merge(z.object({
uid_objekt: z.string().uuid()
}))),
middleware: authorizationMiddleware, middleware: authorizationMiddleware,
async fetch(input, context, user) { async fetch(input, context, user) {
const { uid } = context.params; const { uid } = context.params;
@@ -64,6 +73,13 @@ export const GET = defineApiRoute({
uid, uid,
benutzer_id: user.id benutzer_id: user.id
}, },
include: {
objekt: {
select: {
uid: true
}
}
}
}); });
if (!aufnahme) { if (!aufnahme) {
@@ -73,6 +89,9 @@ export const GET = defineApiRoute({
}) })
} }
return aufnahme return exclude({
uid_objekt: aufnahme.objekt.uid,
...aufnahme
}, ["id", "objekt_id", "benutzer_id", "objekt"])
}, },
}); });

View File

@@ -1,3 +1,5 @@
import { ObjektClient, ZodOverlap } from "#components/Ausweis/types.js";
import { exclude } from "#lib/exclude.js";
import { authorizationMiddleware } from "#lib/middleware/authorization.js"; import { authorizationMiddleware } from "#lib/middleware/authorization.js";
import { ObjektSchema, prisma } from "@ibcornelsen/database/server"; import { ObjektSchema, prisma } from "@ibcornelsen/database/server";
import { APIError, defineApiRoute } from "astro-typesafe-api/server"; import { APIError, defineApiRoute } from "astro-typesafe-api/server";
@@ -57,6 +59,10 @@ export const GET = defineApiRoute({
} }
} }
}, },
output: ZodOverlap<ObjektClient>(ObjektSchema.omit({
benutzer_id: true,
id: true
})),
middleware: authorizationMiddleware, middleware: authorizationMiddleware,
async fetch(input, ctx, user) { async fetch(input, ctx, user) {
const { uid } = ctx.params; const { uid } = ctx.params;
@@ -75,6 +81,6 @@ export const GET = defineApiRoute({
}) })
} }
return objekt return exclude(objekt, ["benutzer_id", "id"])
}, },
}); });

View File

@@ -0,0 +1,41 @@
import { hashPassword } from "#lib/password.js";
import { prisma } from "@ibcornelsen/database/server";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "zod";
export const PUT = defineApiRoute({
input: z.object({
email: z.string().email(),
passwort: z.string().min(6),
vorname: z.string(),
name: z.string()
}),
output: z.object({
uid: z.string().uuid()
}),
async fetch(input) {
const user = await prisma.benutzer.findUnique({
where: {
email: input.email
}
})
if (user) {
throw new APIError({
code: "CONFLICT",
message: "Email Adresse ist bereits vergeben."
})
}
const { uid } = await prisma.benutzer.create({
data: {
email: input.email,
passwort: hashPassword(input.passwort),
vorname: input.vorname,
name: input.name
}
})
return { uid }
},
})

View File

@@ -1,3 +1,4 @@
import { VerbrauchsausweisWohnenClient, ZodOverlap } from "#components/Ausweis/types.js";
import { exclude } from "#lib/exclude.js"; import { exclude } from "#lib/exclude.js";
import { authorizationMiddleware } from "#lib/middleware/authorization.js"; import { authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma, VerbrauchsausweisWohnenSchema } from "@ibcornelsen/database/server"; import { prisma, VerbrauchsausweisWohnenSchema } from "@ibcornelsen/database/server";
@@ -59,15 +60,15 @@ export const GET = defineApiRoute({
} }
} }
}, },
output: VerbrauchsausweisWohnenSchema.merge(z.object({ output: ZodOverlap<VerbrauchsausweisWohnenClient>(VerbrauchsausweisWohnenSchema.merge(z.object({
uid_aufnahme: z.string().uuid(), uid_aufnahme: z.string().uuid(),
uid_objekt: z.string().uuid(), uid_objekt: z.string().uuid(),
uid_benutzer: z.string().uuid().optional() uid_benutzer: z.string().uuid().optional()
})).omit({ })).omit({
id: true, id: true,
aufnahme_id: true, aufnahme_id: true,
benutzer_id: true, benutzer_id: true
}), })),
middleware: authorizationMiddleware, middleware: authorizationMiddleware,
async fetch(input, context, user) { async fetch(input, context, user) {
const { uid } = context.params; const { uid } = context.params;

View File

@@ -4,6 +4,7 @@ import VerbrauchsausweisWohnenModule from "#modules/VerbrauchsausweisWohnen/Verb
import { AufnahmeClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; import { AufnahmeClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { createCaller } from "../../../astro-typesafe-api-caller.js"; import { createCaller } from "../../../astro-typesafe-api-caller.js";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants"; import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants";
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
const uid = Astro.url.searchParams.get("uid"); const uid = Astro.url.searchParams.get("uid");
let ausweis: VerbrauchsausweisWohnenClient = {} as VerbrauchsausweisWohnenClient; let ausweis: VerbrauchsausweisWohnenClient = {} as VerbrauchsausweisWohnenClient;
@@ -11,9 +12,17 @@ let aufnahme: AufnahmeClient = {} as AufnahmeClient;
let objekt: ObjektClient = {} as ObjektClient; let objekt: ObjektClient = {} as ObjektClient;
let bilder: UploadedGebaeudeBild[] = [] let bilder: UploadedGebaeudeBild[] = []
const valid = validateAccessTokenServer(Astro);
const caller = createCaller(Astro); const caller = createCaller(Astro);
if (uid) { if (uid) {
if (!valid) {
return Astro.redirect(
`/auth/login?redirect=${Astro.url.toString()}`
);
}
try { try {
ausweis = await caller["verbrauchsausweis-wohnen"]._uid.GET.fetch(null, { ausweis = await caller["verbrauchsausweis-wohnen"]._uid.GET.fetch(null, {
headers: { headers: {

View File

@@ -1,8 +1,9 @@
import { createCaller } from "#lib/caller.js";
import { API_ACCESS_TOKEN_COOKIE_NAME, API_REFRESH_TOKEN_COOKIE_NAME, API_UID_COOKIE_NAME } from "#lib/constants.js"; import { API_ACCESS_TOKEN_COOKIE_NAME, API_REFRESH_TOKEN_COOKIE_NAME, API_UID_COOKIE_NAME } from "#lib/constants.js";
import type { AstroGlobal } from "astro"; import type { AstroGlobal } from "astro";
import moment from "moment"; import moment from "moment";
import { createCaller } from "../../astro-typesafe-api-caller.js"
import jwt from "jsonwebtoken"
import { TokenData, TokenType } from "#lib/auth/token.js";
export async function validateAccessTokenServer(astro: AstroGlobal) { export async function validateAccessTokenServer(astro: AstroGlobal) {
const accessToken = astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value; const accessToken = astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value;
@@ -17,12 +18,14 @@ export async function validateAccessTokenServer(astro: AstroGlobal) {
} }
if (accessToken) { if (accessToken) {
const { valid } = await createCaller(astro).v1.benutzer.validateAccessToken({accessToken}) const { exp, typ, uid } = jwt.decode(accessToken, {
json: true
}) as TokenData
if (!valid) { if (exp > Date.now() && typ === TokenType.Access) {
astro.cookies.delete(API_ACCESS_TOKEN_COOKIE_NAME); return true;
} else { } else {
return true astro.cookies.delete(API_ACCESS_TOKEN_COOKIE_NAME);
} }
} }
@@ -32,7 +35,7 @@ export async function validateAccessTokenServer(astro: AstroGlobal) {
// Wenn das nicht klappt, dann müssen wir uns neu anmelden. // Wenn das nicht klappt, dann müssen wir uns neu anmelden.
// TODO: Schlägt fehl! Ich habe keine Ahnung warum. Ich habe das Gefühl, dass das an der Astro-Implementierung liegt. Der Refresh Token updated sich nicht richtig.... // TODO: Schlägt fehl! Ich habe keine Ahnung warum. Ich habe das Gefühl, dass das an der Astro-Implementierung liegt. Der Refresh Token updated sich nicht richtig....
try { try {
const { accessToken: newAccessToken, accessTokenExpiry, refreshToken: newRefreshToken, refreshTokenExpiry } = await createCaller(astro).v1.benutzer.getAccessToken({ const { accessToken: newAccessToken, accessTokenExpiry, refreshToken: newRefreshToken, refreshTokenExpiry } = await createCaller(astro).auth["access-token"].GET.fetch({
refreshToken refreshToken
}) })

View File

@@ -1,11 +1,11 @@
import { test, describe, expect } from "bun:test"; import { test, describe, expect } from "bun:test";
import { pdfVerbrauchsausweisWohnen } from "#lib/pdf/pdfVerbrauchsausweisWohnen"; import { pdfVerbrauchsausweisWohnen } from "#lib/pdf/pdfVerbrauchsausweisWohnen.js";
import { verbrauchsausweisWohnenFaker } from "#lib/faker/verbrauchsausweis-wohnen"; import { fakeVerbrauchsausweisWohnen } from "#lib/faker.js";
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
describe('Verbrauchsausweis Wohnen PDF', async () => { describe('Verbrauchsausweis Wohnen PDF', async () => {
const ausweis: VerbrauchsausweisWohnenClient = verbrauchsausweisWohnenFaker(42); const ausweis: VerbrauchsausweisWohnenClient = fakeVerbrauchsausweisWohnen(42);
test("Ausweis Erstellung", async () => { test("Ausweis Erstellung", async () => {
const pdf = await pdfVerbrauchsausweisWohnen(ausweis); const pdf = await pdfVerbrauchsausweisWohnen(ausweis);

View File

@@ -1,6 +1,6 @@
import { test, describe, expect } from "bun:test"; import { test, describe, expect } from "bun:test";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016"; import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
import { importVerbrauchsausweisWohnenAltesSystem, verbrauchsausweisWohnenImportTranslate } from "#lib/altes-system/import"; import { importVerbrauchsausweisWohnenAltesSystem, verbrauchsausweisWohnenImportTranslate } from "#lib/altes-system/import.js";
describe('Energieverbrauch', async () => { describe('Energieverbrauch', async () => {
const request = await importVerbrauchsausweisWohnenAltesSystem(); const request = await importVerbrauchsausweisWohnenAltesSystem();