Bugfixes, Kundendaten, Datenbank Anpassung

This commit is contained in:
Moritz Utcke
2024-01-10 15:09:30 +07:00
parent ee5133b3f8
commit b20b857a7d
60 changed files with 737 additions and 1647 deletions

View File

@@ -1,6 +1,6 @@
import { defineConfig } from "astro/config"; import { defineConfig } from "astro/config";
import svelte from "@astrojs/svelte"; import svelte from "@astrojs/svelte";
import astroI18next from "astro-i18next"; // import astroI18next from "astro-i18next";
import tailwind from "@astrojs/tailwind"; import tailwind from "@astrojs/tailwind";
@@ -12,7 +12,7 @@ import mdx from "@astrojs/mdx";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
integrations: [astroI18next(),svelte(), tailwind(), mdx()], integrations: [/*astroI18next(),*/svelte(), tailwind(), mdx()],
outDir: "./dist", outDir: "./dist",
output: "server", output: "server",
adapter: node({ adapter: node({

View File

@@ -1,9 +0,0 @@
POSTGRES_DB=main
POSTGRES_HOST=database
POSTGRES_PORT=5432
POSTGRES_USER=main
POSTGRES_PASSWORD=hHMP8cd^N3SnzGRR
DB_CONTAINER_NAME=database
POSTGRES_DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}"

View File

@@ -1,11 +1,9 @@
version: '3' version: '3'
services: services:
online-energieausweis: ibcornelsen-online-energieausweis:
build: ./ build: ./
container_name: online-energieausweis
command: bun run dev --host command: bun run dev --host
depends_on:
- database
environment: environment:
PORT: 3000 PORT: 3000
NODE_ENV: "development" NODE_ENV: "development"
@@ -14,9 +12,5 @@ services:
- ./:/online-energieausweis - ./:/online-energieausweis
- ./node_modules/@ibcornelsen/ui:/online-energieausweis/node_modules/@ibcornelsen/ui - ./node_modules/@ibcornelsen/ui:/online-energieausweis/node_modules/@ibcornelsen/ui
- ./node_modules/@ibcornelsen/database:/online-energieausweis/node_modules/@ibcornelsen/database - ./node_modules/@ibcornelsen/database:/online-energieausweis/node_modules/@ibcornelsen/database
- ./node_modules/@ibcornelsen/api:/online-energieausweis/node_modules/@ibcornelsen/api
- ./persistent:/persistent - ./persistent:/persistent
database:
network_mode: host
build: ../database
env_file:
- ../database/.env

View File

@@ -28,6 +28,7 @@
"@trpc/server": "^10.45.0", "@trpc/server": "^10.45.0",
"astro": "^2.5.1", "astro": "^2.5.1",
"astro-i18next": "1.0.0-beta.21", "astro-i18next": "1.0.0-beta.21",
"buffer": "^6.0.3",
"bun": "^1.0.2", "bun": "^1.0.2",
"cookiejs": "^2.1.2", "cookiejs": "^2.1.2",
"csvtojson": "^2.0.10", "csvtojson": "^2.0.10",

View File

@@ -1,12 +1,19 @@
<script lang="ts"> <script lang="ts">
import { VerbrauchsausweisWohnen } from "@ibcornelsen/database"; import { GebaeudeStammdaten, VerbrauchsausweisWohnen } from "@ibcornelsen/database";
import { Buffer } from "buffer";
export let ausweis: VerbrauchsausweisWohnen; export let ausweis: VerbrauchsausweisWohnen;
export let gebaeude: GebaeudeStammdaten;
const base64 = btoa(JSON.stringify(ausweis)); let base64: string = "";
$: {
if (ausweis && gebaeude) {
base64 = Buffer.from(JSON.stringify({...ausweis, gebaeude_stammdaten: gebaeude}), "utf-8").toString("base64");
}
}
</script> </script>
<a class="border-2 rounded-lg w-[30%] bg-white text-center hover:shadow-md no-underline p-6 cursor-pointer" target="_blank" href="/pdf/datenblatt?base64={base64}"> <a class="border-2 rounded-lg w-[30%] bg-white text-center hover:shadow-md no-underline p-6 cursor-pointer" target="_blank" href="/pdf/ansichtsausweis?base64={base64}">
<img src="/images/ausweis.webp" alt="Ausweis" /> <img src="/images/ausweis.webp" alt="Ausweis" />
<span class="text-black font-medium text-lg">Ansichtsausweis</span> <span class="text-black font-medium text-lg">Ansichtsausweis</span>
</a> </a>

View File

@@ -4,9 +4,10 @@
import HelpLabel from "#components/HelpLabel.svelte"; import HelpLabel from "#components/HelpLabel.svelte";
export let ausweis: VerbrauchsausweisWohnen; export let ausweis: VerbrauchsausweisWohnen;
export let gebaeude: GebaeudeStammdaten;
import ImageGrid from "../ImageGrid.svelte"; import ImageGrid from "../ImageGrid.svelte";
import { VerbrauchsausweisWohnen } from "@ibcornelsen/database"; import { GebaeudeStammdaten, VerbrauchsausweisWohnen } from "@ibcornelsen/database";
let images: (File & { data: string })[] = []; let images: (File & { data: string })[] = [];
</script> </script>
@@ -33,8 +34,8 @@
<hr class="trenner_form_100" /> <hr class="trenner_form_100" />
<div class="flex flex-row gap-4"> <div class="flex flex-row gap-4">
<AnsichtsausweisButton {ausweis} /> <AnsichtsausweisButton {ausweis} {gebaeude} />
<DatenblattButton {ausweis} /> <DatenblattButton {ausweis} {gebaeude} />
</div> </div>
</div> </div>
</div> </div>

View File

@@ -348,4 +348,4 @@
als PDF anschauen</Label als PDF anschauen</Label
> >
<AusweisPreviewContainer {ausweis} /> <AusweisPreviewContainer {ausweis} {gebaeude} />

View File

@@ -1,9 +1,16 @@
<script lang="ts"> <script lang="ts">
import { VerbrauchsausweisWohnen } from "@ibcornelsen/database"; import { GebaeudeStammdaten, VerbrauchsausweisWohnen } from "@ibcornelsen/database";
import { Buffer } from "buffer";
export let ausweis: VerbrauchsausweisWohnen; export let ausweis: VerbrauchsausweisWohnen;
export let gebaeude: GebaeudeStammdaten;
const base64 = btoa(JSON.stringify(ausweis)); let base64: string = "";
$: {
if (ausweis && gebaeude) {
base64 = Buffer.from(JSON.stringify({...ausweis, gebaeude_stammdaten: gebaeude}), "utf-8").toString("base64");
}
}
</script> </script>
<a class="border-2 rounded-lg w-[30%] bg-white text-center hover:shadow-md no-underline p-6 cursor-pointer" target="_blank" href="/pdf/datenblatt?base64={base64}"> <a class="border-2 rounded-lg w-[30%] bg-white text-center hover:shadow-md no-underline p-6 cursor-pointer" target="_blank" href="/pdf/datenblatt?base64={base64}">

View File

@@ -1,9 +1,9 @@
--- ---
import i18next from "i18next"; // import i18next from "i18next";
import {localizeUrl} from "astro-i18next" // import {localizeUrl} from "astro-i18next"
import { t } from "i18next"; // import { t } from "i18next";
import { isLoggedIn } from "../lib/UI/isLoggedIn"; import { isLoggedIn } from "../lib/UI/isLoggedIn";
import LanguageDropdown from "./LanguageDropdown.svelte"; // import LanguageDropdown from "./LanguageDropdown.svelte";
const loggedIn = isLoggedIn(Astro); const loggedIn = isLoggedIn(Astro);
--- ---
@@ -38,7 +38,7 @@ const loggedIn = isLoggedIn(Astro);
</div> </div>
<div class="nav-head"> <div class="nav-head">
<LanguageDropdown <!--<LanguageDropdown
countries={[ countries={[
{ iso: "de", flag: "de", name: "Deutsch" }, { iso: "de", flag: "de", name: "Deutsch" },
{ iso: "en", flag: "us", name: "English" }, { iso: "en", flag: "us", name: "English" },
@@ -49,7 +49,7 @@ const loggedIn = isLoggedIn(Astro);
})} })}
current={i18next.language} current={i18next.language}
client:load client:load
/> /> -->
<a <a
class="headerButton" class="headerButton"
href="/energieausweis-erstellen/verbrauchsausweis-erstellen.php" href="/energieausweis-erstellen/verbrauchsausweis-erstellen.php"

View File

@@ -0,0 +1,15 @@
<script lang="ts">
import { Bezahlmethoden } from "@ibcornelsen/database";
export let name: string;
export let icon: string;
export let paymentType: Bezahlmethoden;
export let selectedPaymentType: Bezahlmethoden;
</script>
<button class="flex flex-col items-center cursor-pointer" class:bg-gray-100={paymentType == selectedPaymentType} on:click={() => selectedPaymentType = paymentType}>
<img src={icon} alt={name} />
<span aria-label={name}>
{name}
</span>
</button>

View File

@@ -1,7 +1,3 @@
---
import { localizePath } from "astro-i18next"
---
<div class="flex flex-col gap-6"> <div class="flex flex-col gap-6">
<nav> <nav>
<div class="nav-card"> <div class="nav-card">
@@ -10,9 +6,9 @@ import { localizePath } from "astro-i18next"
>Energieausweis erstellen</a >Energieausweis erstellen</a
> >
<div class="dropdown-content"> <div class="dropdown-content">
<a href={localizePath("/verbrauchsausweis")}>Verbrauchsausweis erstellen</a> <a href="/verbrauchsausweis">Verbrauchsausweis erstellen</a>
<a href={localizePath("/bedarfsausweis")}>Bedarfsausweis erstellen</a> <a href="/bedarfsausweis">Bedarfsausweis erstellen</a>
<a href={localizePath("/verbrauchsausweis-gewerbe")} <a href="/verbrauchsausweis-gewerbe"
>Verbrauchsausweis Gewerbe erstellen</a >Verbrauchsausweis Gewerbe erstellen</a
> >
<a href="/bedarfsausweis-gewerbe" <a href="/bedarfsausweis-gewerbe"

View File

@@ -9,10 +9,10 @@
import ZipSearch from "../ZIPSearch.svelte"; import ZipSearch from "../ZIPSearch.svelte";
import { buildingTypes } from "./BuildingTypes"; import { buildingTypes } from "./BuildingTypes";
import BilderZusatzsysteme from "../Ausweis/BilderZusatzsysteme.svelte"; import BilderZusatzsysteme from "../Ausweis/BilderZusatzsysteme.svelte";
import { VerbrauchsausweisGewerbe } from "src/lib/Ausweis/VerbrauchsausweisGewerbe";
import moment from "moment"; import moment from "moment";
import { VerbrauchsausweisGewerbe } from "@ibcornelsen/database";
let ausweis = new VerbrauchsausweisGewerbe(); let ausweis: VerbrauchsausweisGewerbe = {};
let additionalHeating: boolean = false; let additionalHeating: boolean = false;
let heatedWaterIncluded: boolean = false; let heatedWaterIncluded: boolean = false;

View File

@@ -43,8 +43,6 @@ const schema = JSON.stringify({
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<script type="application/ld+json" set:html={schema}></script> <script type="application/ld+json" set:html={schema}></script>
<link rel="icon" type="image/svg+xml" href="/favicon.jpg" /> <link rel="icon" type="image/svg+xml" href="/favicon.jpg" />
<link rel="stylesheet" href="style/main.css" />
<link rel="stylesheet" href="style/bootstrap.min.css" />
<meta <meta
name="description" name="description"

View File

@@ -47,8 +47,6 @@ const schema = JSON.stringify({
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<script type="application/ld+json" set:html={schema}></script> <script type="application/ld+json" set:html={schema}></script>
<link rel="icon" type="image/svg+xml" href="/favicon.jpg" /> <link rel="icon" type="image/svg+xml" href="/favicon.jpg" />
<link rel="stylesheet" href="style/main.css" />
<link rel="stylesheet" href="style/bootstrap.min.css" />
<meta <meta
name="description" name="description"

View File

@@ -1,4 +1,4 @@
import { getKlimafaktoren } from "#lib/getKlimafaktoren"; import { getKlimafaktoren } from "#lib/Klimafaktoren";
import { getHeizwertfaktor } from "#lib/server/Heizwertfaktor"; import { getHeizwertfaktor } from "#lib/server/Heizwertfaktor";
import { GebaeudeStammdaten, VerbrauchsausweisWohnen } from "@ibcornelsen/database"; import { GebaeudeStammdaten, VerbrauchsausweisWohnen } from "@ibcornelsen/database";

View File

@@ -1,12 +0,0 @@
import jwt from "jwt-simple";
type TokenData = { uid: string, exp: number }
export function encodeToken(data: TokenData) {
const token = jwt.encode(data, "yIvbgS$k7Bfc+mpV%TWDZAhje9#uJad4", "HS256");
return token;
}
export function decodeToken(token: string): Partial<TokenData> {
return jwt.decode(token, "yIvbgS$k7Bfc+mpV%TWDZAhje9#uJad4");
}

View File

@@ -1,19 +0,0 @@
import * as crypto from "crypto";
export function hashPassword(password: string): string {
const salt = crypto.randomBytes(16).toString("hex");
const hash = hashWithGivenSalt(password, salt) + salt;
return hash;
}
export function hashWithGivenSalt(password: string, salt: string): string {
const hash = crypto.scryptSync(password, salt, 32).toString("hex");
return hash;
}
export function validatePassword(known: string, unknown: string): boolean {
const salt = known.slice(64);
const originalPasswordHash = known.slice(0, 64);
const currentPasswordHash = hashWithGivenSalt(unknown, salt)
return originalPasswordHash == currentPasswordHash;
}

View File

@@ -2,7 +2,7 @@ import {
endEnergieVerbrauchVerbrauchsausweis_2016, endEnergieVerbrauchVerbrauchsausweis_2016,
energetischeNutzflaecheVerbrauchsausweisWohnen_2016, energetischeNutzflaecheVerbrauchsausweisWohnen_2016,
} from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016"; } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016";
import { getKlimafaktoren } from "#lib/getKlimafaktoren"; import { getKlimafaktoren } from "#lib/Klimafaktoren";
import { getHeizwertfaktor } from "#lib/server/Heizwertfaktor"; import { getHeizwertfaktor } from "#lib/server/Heizwertfaktor";
import { import {
GebaeudeStammdaten, GebaeudeStammdaten,

View File

@@ -1 +0,0 @@
export { validateAuthorizationHeader } from "./validate";

View File

@@ -1,62 +0,0 @@
import { decodeToken } from "src/lib/JsonWebToken";
import { validatePassword } from "src/lib/Password";
import { User } from "src/lib/User";
export async function validateAuthorizationHeader(
request: Request,
validAuthenticationMethods: ("Bearer" | "Basic")[]
): Promise<User | null> {
if (!request.headers.has("authorization")) {
return null;
}
const header = request.headers.get("authorization") as string;
const [authorizationType, value] = header.split(" ");
if (authorizationType == "Basic" && validAuthenticationMethods.indexOf("Basic") > -1) {
// Basic user validation;
try {
const [email, password] = Buffer.from(value, "base64")
.toString()
.split(":");
const user = await User.fromEmail(email);
if (!user) {
return null;
}
if (!validatePassword(user.passwort, password)) {
return null;
}
return user;
} catch (e) {
return null;
}
} else if (authorizationType == "Bearer" && validAuthenticationMethods.indexOf("Bearer") > -1) {
const stringToken = Buffer.from(value, "base64").toString();
try {
const token = decodeToken<{ id: number; uid: string; exp: string }>(
stringToken
);
const id = token.id;
if (!id) {
return null;
}
const user = User.fromPrivateId(id);
if (!user) {
return null;
}
return user;
} catch (e) {
return null;
}
} else {
return null;
}
}

View File

@@ -1,26 +0,0 @@
import { initTRPC } from "@trpc/server";
import { ZodError } from "zod";
import { OpenApiMeta } from "trpc-openapi";
type Context = {
authorization: string | null;
ip: string;
req: Request;
}
export const t = initTRPC.context<Context>().meta<OpenApiMeta>().create({
errorFormatter(opts) {
const { shape, error } = opts;
return {
success: false,
...shape,
data: {
zodError:
error.code === 'BAD_REQUEST' && error.cause instanceof ZodError
? error.cause.flatten()
: null,
},
};
}
});

View File

@@ -1,26 +0,0 @@
import { prisma } from "@ibcornelsen/database";
import { privateProcedure } from "./privateProcedure";
// NOTE: Muss noch mit der Datenbank eingebunden werden.
export const loggedProcedure = privateProcedure.use(async (opts) => {
const start = Date.now();
const result = await opts.next();
const durationMs = Date.now() - start;
await prisma.apiRequests.create({
data: {
ip: opts.ctx.ip,
method: opts.type,
path: opts.path,
responseSize: JSON.stringify(result).length,
responseTime: durationMs,
userAgent: opts.ctx.req.headers["user-agent"] || "",
status: result.ok ? 200 : 500,
user_id: opts.ctx.user.id
}
})
return result;
});

View File

@@ -1,44 +0,0 @@
import { TRPCError } from "@trpc/server";
import { publicProcedure } from "./publicProcedure";
import { decodeToken } from "#lib/JsonWebToken";
import { User } from "#lib/User";
export const privateProcedure = publicProcedure.use(async (opts) => {
const { ctx } = opts;
if (!ctx.authorization) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Für diese Action ist ein Bearer Token verpflichtend." });
}
const [authorizationType, value] = ctx.authorization.split(" ");
if (authorizationType != "Bearer") {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Für diese Action ist ein Bearer Token verpflichtend." });
}
const stringToken = Buffer.from(value, "base64").toString();
try {
const token = decodeToken(
stringToken
);
const uid = token.uid;
if (!uid) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Der gegebene Token ist fehlerhaft." });
}
const user = await User.fromUID(uid);
if (!user) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Der gegebene Token ist fehlerhaft." });
}
return opts.next({
ctx: {
user,
},
});
} catch (e) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Der gegebene Token ist fehlerhaft." });
}
});

View File

@@ -1,3 +0,0 @@
import { t } from "#lib/trpc/context";
export const publicProcedure = t.procedure;

View File

@@ -1,64 +0,0 @@
import { z } from "zod";
import moment from "moment";
import { prisma } from "@ibcornelsen/database";
import { publicProcedure } from "#lib/trpc/middlewares/publicProcedure";
import { encodeToken } from "#lib/JsonWebToken";
import { hashPassword } from "#lib/Password";
import { TRPCError } from "@trpc/server";
export const tRPC_V1_BenutzerErstellenProcedure = publicProcedure
.input(
z.object({
email: z.string().email(),
passwort: z.string().min(8).max(100),
vorname: z.string().min(1).max(100),
name: z.string().min(1).max(100),
})
)
.output(
z.object({
uid: z.string().uuid(),
token: z.string(),
exp: z.number(),
})
)
.query(async (opts) => {
const hashedPassword = hashPassword(opts.input.passwort);
// Vielleicht existiert der Benutzer ja schon?
const existingUser = await prisma.benutzer.findUnique({
where: {
email: opts.input.email
}
})
if (existingUser) {
throw new TRPCError({ code: "CONFLICT", message: "Der Benutzer existiert bereits." });
}
const user = await prisma.benutzer.create({
data: {
email: opts.input.email,
passwort: hashedPassword,
vorname: opts.input.vorname,
name: opts.input.name
},
select: {
id: true,
uid: true
}
})
if (!user) {
throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Der Benutzer konnte nicht erstellt werden." });
}
const expiry = moment().add(2, "days").unix();
const token = encodeToken({ uid: user.uid, exp: expiry })
return {
uid: user.uid,
token: token,
exp: expiry
}
});

View File

@@ -1,31 +0,0 @@
import { z } from "zod";
import { BenutzerSchema, prisma } from "@ibcornelsen/database";
import { TRPCError } from "@trpc/server";
import { loggedProcedure } from "#lib/trpc/middlewares/loggedProcedure";
export const tRPC_V1_BenutzerFromPrivateIdProcedure = loggedProcedure
.input(
z.object({
id: z.number(),
})
)
.output(
BenutzerSchema
)
.query(async (opts) => {
if (opts.ctx.user.id !== opts.input.id) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Sie sind nicht dazu authorisiert die Daten dieses Benutzers einzusehen." });
}
const user = await prisma.benutzer.findUnique({
where: {
id: opts.input.id,
},
});
if (!user) {
throw new TRPCError({ code: "BAD_REQUEST", message: "Der gesuchte Benutzer existiert nicht." });
}
return user;
});

View File

@@ -1,31 +0,0 @@
import { z } from "zod";
import { BenutzerSchema, prisma } from "@ibcornelsen/database";
import { TRPCError } from "@trpc/server";
import { loggedProcedure } from "#lib/trpc/middlewares/loggedProcedure";
export const tRPC_V1_BenutzerFromPublicIdProcedure = loggedProcedure
.input(
z.object({
uid: z.string().uuid(),
})
)
.output(
BenutzerSchema
)
.query(async (opts) => {
if (opts.ctx.user.uid !== opts.input.uid) {
throw new TRPCError({ code: "UNAUTHORIZED", message: "Sie sind nicht dazu authorisiert die Daten dieses Benutzers einzusehen." });
}
const user = await prisma.benutzer.findUnique({
where: {
uid: opts.input.uid,
},
});
if (!user) {
throw new TRPCError({ code: "BAD_REQUEST", message: "Der gesuchte Benutzer existiert nicht." });
}
return user;
});

View File

@@ -1,50 +0,0 @@
import { z } from "zod";
import moment from "moment";
import { prisma } from "@ibcornelsen/database";
import { publicProcedure } from "#lib/trpc/middlewares/publicProcedure";
import { encodeToken } from "#lib/JsonWebToken";
import { hashPassword } from "#lib/Password";
import { TRPCError } from "@trpc/server";
export const tRPC_V1_BenutzerTokenErneuernProcedure = publicProcedure
.input(
z.object({
email: z.string().email(),
passwort: z.string().min(8).max(100),
})
)
.output(
z.object({
uid: z.string().uuid(),
token: z.string(),
exp: z.number(),
})
)
.query(async (opts) => {
const hashedPassword = hashPassword(opts.input.passwort);
// Falls der Nutzer nicht existiert, wird eine Fehlermeldung zurückgegeben.
const user = await prisma.benutzer.findUnique({
where: {
email: opts.input.email
}
})
if (!user) {
throw new TRPCError({ code: "BAD_REQUEST", message: "Der gesuchte Benutzer existiert nicht oder das Password ist falsch." });
}
// Falls das Passwort nicht stimmt, wird eine Fehlermeldung zurückgegeben.
if (user.passwort !== hashedPassword) {
throw new TRPCError({ code: "BAD_REQUEST", message: "Der gesuchte Benutzer existiert nicht oder das Password ist falsch." });
}
const expiry = moment().add(2, "days").unix();
const token = encodeToken({ uid: user.uid, exp: expiry })
return {
uid: user.uid,
token: token,
exp: expiry
}
});

View File

@@ -1,49 +0,0 @@
import { z } from "zod";
import { prisma } from "@ibcornelsen/database";
import { publicProcedure } from "#lib/trpc/middlewares/publicProcedure";
import { decodeToken } from "#lib/JsonWebToken";
export const tRPC_V1_BenutzerTokenValidierenProcedure = publicProcedure
.input(
z.object({
token: z.string(),
})
)
.output(
z.object({
uid: z.string().uuid(),
valid: z.boolean(),
exp: z.number()
})
)
.query(async (opts) => {
const decodedToken = decodeToken(opts.input.token);
if (!decodedToken || !decodedToken.uid || !decodedToken.exp) {
return {
uid: "",
valid: false,
exp: 0,
};
}
const user = await prisma.benutzer.findUnique({
where: {
uid: decodedToken.uid,
},
});
if (!user) {
return {
uid: "",
valid: false,
exp: 0,
};
}
return {
uid: decodedToken.uid,
valid: true,
exp: decodedToken.exp
};
});

View File

@@ -1,45 +0,0 @@
import { t } from "#lib/trpc/context";
import { tRPC_V1_KlimafaktorenProcedure } from "./klimafaktoren";
import { VerbrauchsausweisWohnen2016Erstellen } from "./verbrauchsausweis-wohnen/2016/erstellen";
import { tRPC_V1_BenutzerErstellenProcedure } from "./benutzer/erstellen";
import { tRPC_V1_BenutzerTokenErneuernProcedure } from "./benutzer/tokenErneuern";
import { tRPC_V1_BenutzerTokenValidierenProcedure } from "./benutzer/tokenValidieren";
import { tRPC_V1_BenutzerFromPublicIdProcedure } from "./benutzer/fromPublicId";
import { tRPC_V1_BenutzerFromPrivateIdProcedure } from "./benutzer/fromPrivateId";
const router = t.router;
export const v1Router = router({
verbrauchsausweisWohnen: router({
2016: router({
erstellen: VerbrauchsausweisWohnen2016Erstellen
}),
2023: router({
})
}),
verbrauchsausweisGewerbe: router({
2016: router({
}),
2023: router({
})
}),
bedarfsausweisWohen: router({
2016: router({
}),
2023: router({
})
}),
klimafaktoren: tRPC_V1_KlimafaktorenProcedure,
benutzer: router({
erstellen: tRPC_V1_BenutzerErstellenProcedure,
tokenErneuern: tRPC_V1_BenutzerTokenErneuernProcedure,
tokenValidieren: tRPC_V1_BenutzerTokenValidierenProcedure,
fromPublicId: tRPC_V1_BenutzerFromPublicIdProcedure,
fromPrivateId: tRPC_V1_BenutzerFromPrivateIdProcedure
})
})

View File

@@ -1,78 +0,0 @@
import { z } from "zod";
import moment from "moment";
import { TRPCError } from "@trpc/server";
import { prisma } from "@ibcornelsen/database";
import { publicProcedure } from "#lib/trpc/middlewares/publicProcedure";
export const tRPC_V1_KlimafaktorenProcedure = publicProcedure
.input(
z.object({
plz: z.string().min(4).max(5),
startdatum: z.coerce.date(),
enddatum: z.coerce.date(),
genauigkeit: z.enum(["months", "years"]),
})
)
.output(
z.array(
z.object({
month: z.number(),
year: z.number(),
klimafaktor: z.number(),
})
)
)
.query(async (opts) => {
const start = moment(opts.input.startdatum);
const end = moment(opts.input.enddatum);
if (start.isSameOrAfter(end)) {
throw new TRPCError({
code: "PRECONDITION_FAILED",
message: "Das Startdatum kann nicht vor dem Enddatum liegen.",
});
}
const intervals = [];
let currentDate = start.clone();
while (currentDate.isSameOrBefore(end)) {
let copy = currentDate.clone();
intervals.push(copy);
currentDate.add(1, opts.input.genauigkeit);
}
let klimafaktoren = await prisma.klimafaktoren.findMany({
where: {
plz: opts.input.plz,
month: intervals[0].month(),
OR: intervals.map((date) => {
return {
year: date.year(),
};
}),
},
});
if (!klimafaktoren) {
throw new TRPCError({
code: "NOT_FOUND",
message:
"Die Klimafaktoren konnten nicht geladen werden. Das kann daran liegen, dass sie für diesen Zeitraum oder Ort nicht verfügbar sind.",
});
}
if (klimafaktoren.length !== intervals.length) {
throw new TRPCError({
code: "NOT_FOUND",
message:
"Für diesen Zeitraum konnten nicht alle Klimafaktoren gefunden werden.",
});
}
return klimafaktoren.map((klimafaktor) => ({
month: klimafaktor.month,
year: klimafaktor.year,
klimafaktor: klimafaktor.klimafaktor,
}));
});

View File

@@ -1,143 +0,0 @@
import { z } from "zod";
import { prisma } from "@ibcornelsen/database";
import { publicProcedure } from "#lib/trpc/middlewares/publicProcedure";
export const VerbrauchsausweisWohnen2016Erstellen = publicProcedure
.meta({
openapi: {
method: "POST",
path: "/v1/verbrauchsausweis-wohnen/2016/erstellen",
contentTypes: ["application/json"],
description: "Erstellt einen neuen Verbrauchsausweis für Wohngebäude nach dem Schema der EnEV von 2016.",
tags: ["Verbrauchsausweis Wohnen"],
}
})
.input(z.object({
baujahr_heizung: z.array(z.number()).optional(),
zusaetzliche_heizquelle: z.boolean().optional(),
brennstoff_1: z.string().max(50).optional(),
einheit_1: z.string().max(50).optional(),
brennstoff_2: z.string().max(50).optional(),
einheit_2: z.string().max(50).optional(),
startdatum: z.coerce.date().optional(),
enddatum: z.coerce.date().optional(),
verbrauch_1: z.number().optional(),
verbrauch_2: z.number().optional(),
verbrauch_3: z.number().optional(),
verbrauch_4: z.number().optional(),
verbrauch_5: z.number().optional(),
verbrauch_6: z.number().optional(),
warmwasser_enthalten: z.boolean().optional(),
warmwasser_anteil_bekannt: z.boolean().optional(),
wird_gekuehlt: z.boolean().optional(),
keller_beheizt: z.boolean().optional(),
alternative_heizung: z.boolean().optional(),
alternative_warmwasser: z.boolean().optional(),
alternative_lueftung: z.boolean().optional(),
alternative_kuehlung: z.boolean().optional(),
anteil_warmwasser_1: z.number().optional(),
anteil_warmwasser_2: z.number().optional(),
gebaeude_stammdaten: z.string().uuid().or(z.object({
gebaeudetyp: z.string().max(255).optional(), // Adjust max length as needed
gebaeudeteil: z.string().max(255).optional(), // Adjust max length as needed
baujahr_gebaeude: z.array(z.number()).optional(),
baujahr_heizung: z.array(z.number()).optional(),
baujahr_klima: z.array(z.number()).optional(),
einheiten: z.number().optional(),
flaeche: z.number().optional(),
saniert: z.boolean().optional(),
keller: z.number().optional(),
dachgeschoss: z.number().optional(),
lueftung: z.string().max(50).optional(), // Adjust max length as needed
kuehlung: z.string().max(50).optional(), // Adjust max length as needed
leerstand: z.number().optional(),
plz: z.string().max(5).optional(), // Adjust max length as needed
ort: z.string().max(50).optional(), // Adjust max length as needed
adresse: z.string().max(100).optional(), // Adjust max length as needed
zentralheizung: z.boolean().optional(),
solarsystem_warmwasser: z.boolean().optional(),
warmwasser_rohre_gedaemmt: z.boolean().optional(),
niedertemperatur_kessel: z.boolean().optional(),
brennwert_kessel: z.boolean().optional(),
heizungsrohre_gedaemmt: z.boolean().optional(),
standard_kessel: z.boolean().optional(),
waermepumpe: z.boolean().optional(),
raum_temperatur_regler: z.boolean().optional(),
photovoltaik: z.boolean().optional(),
durchlauf_erhitzer: z.boolean().optional(),
einzelofen: z.boolean().optional(),
zirkulation: z.boolean().optional(),
einfach_verglasung: z.boolean().optional(),
dreifach_verglasung: z.boolean().optional(),
fenster_teilweise_undicht: z.boolean().optional(),
doppel_verglasung: z.boolean().optional(),
fenster_dicht: z.boolean().optional(),
rolllaeden_kaesten_gedaemmt: z.boolean().optional(),
isolier_verglasung: z.boolean().optional(),
tueren_undicht: z.boolean().optional(),
tueren_dicht: z.boolean().optional(),
dachgeschoss_gedaemmt: z.boolean().optional(),
keller_decke_gedaemmt: z.boolean().optional(),
keller_wand_gedaemmt: z.boolean().optional(),
aussenwand_gedaemmt: z.boolean().optional(),
oberste_geschossdecke_gedaemmt: z.boolean().optional(),
aussenwand_min_12cm_gedaemmt: z.boolean().optional(),
dachgeschoss_min_12cm_gedaemmt: z.boolean().optional(),
oberste_geschossdecke_min_12cm_gedaemmt: z.boolean().optional(),
}))
}))
.output(
z.object({
uid: z.string().uuid(),
})
)
.mutation(async (opts) => {
// Es kann sein, dass ein Gebäude bereits existiert. In diesem Fall wird es nicht neu erstellt, sondern nur der Verbrauchsausweis.
// Das können wir ganz einfach überprüfen, indem wir schauen, ob eine UUID für das Gebäude übergeben wurde.
if (typeof opts.input.gebaeude_stammdaten === "string") {
// Gebäude existiert bereits
const gebaeude = await prisma.gebaeudeStammdaten.findUnique({
where: {
uid: opts.input.gebaeude_stammdaten
}
});
if (!gebaeude) {
throw new Error("Das Gebäude mit der übergebenen UUID existiert nicht.");
}
const verbrauchsausweis = await prisma.verbrauchsausweisWohnen.create({
data: {
...opts.input,
gebaeude_stammdaten: {
connect: {
uid: opts.input.gebaeude_stammdaten
}
}
}
});
return { uid: verbrauchsausweis.uid };
} else {
// Gebäude existiert noch nicht
const gebaeude = await prisma.gebaeudeStammdaten.create({
data: opts.input.gebaeude_stammdaten
});
const verbrauchsausweis = await prisma.verbrauchsausweisWohnen.create({
data: {
...opts.input,
gebaeude_stammdaten: {
connect: {
uid: gebaeude.uid
}
}
}
});
return { uid: verbrauchsausweis.uid };
}
});

View File

@@ -1,41 +0,0 @@
import type { APIRoute } from "astro";
import { MissingEntityError, error } from "src/lib/APIResponse";
import { prisma } from "@ibcornelsen/database";
import { xmlVerbrauchsausweisWohnen_2016 } from "#lib/XML/VerbrauchsausweisWohnen/xmlVerbrauchsausweisWohnen_2016";
import uuid from "uuid";
export const get: APIRoute = async ({ url }) => {
const body = url.searchParams;
const uid = body.get("uid");
if (!body.has("uid") || !uid) {
return error(["Missing 'uid' in request body."]);
}
if (!uuid.validate(uid)) {
return error(["'uid' in request body must follow the UUID v4 format."]);
}
const ausweis = await prisma.verbrauchsausweisWohnen.findUnique({
where: {
uid,
},
include: {
gebaeude_stammdaten: true,
},
});
if (!ausweis) {
return MissingEntityError(uid);
}
const xml = await xmlVerbrauchsausweisWohnen_2016(ausweis);
const response = new Response(xml, {
headers: {
"Content-Type": "application/xml",
},
});
return response;
};

View File

@@ -63,16 +63,13 @@
async function ausweisAbschicken() { async function ausweisAbschicken() {
console.log(ausweis);
overlay.ariaHidden = "false"; overlay.ariaHidden = "false";
const response = await client.v1.verbrauchsausweisWohnen[2016].erstellen.mutate({ const response = await client.v1.verbrauchsausweisWohnen[2016].erstellen.mutate({
...ausweis, ...ausweis,
gebaeude_stammdaten: gebaeude gebaeude_stammdaten: gebaeude
}) })
console.log(response.uid); window.location.href = `/kundendaten?uid=${response.uid}`;
} }
let overlay: HTMLDivElement; let overlay: HTMLDivElement;

View File

@@ -1,25 +1,17 @@
<script lang="ts"> <script lang="ts">
import ProgressBar from "#components/Ausweis/Progressbar.svelte"; import ProgressBar from "#components/Ausweis/Progressbar.svelte";
import HelpLabel from "#components/HelpLabel.svelte"; import HelpLabel from "#components/HelpLabel.svelte";
import ZipSearch from "../ZIPSearch.svelte"; import ZipSearch from "../components/ZIPSearch.svelte";
import Label from "../Label.svelte"; import Label from "../components/Label.svelte";
import PriceContainer from "#components/Kaufabschluss/PriceContainer.svelte"; import PriceContainer from "#components/Kaufabschluss/PriceContainer.svelte";
import { Benutzer, Bezahlmethoden, Enums, Rechnungen, VerbrauchsausweisWohnen } from "@ibcornelsen/database";
import PaymentOption from "#components/PaymentOption.svelte";
let deliveryAddress: boolean = false; export let user: Benutzer;
export let ausweis: VerbrauchsausweisWohnen
let rechnung: Rechnungen = {} as Rechnungen;
let mailAddressCity: string = ""; export let selectedPaymentType: Bezahlmethoden = Enums.Bezahlmethoden.PAYPAL;
let mailAddressZipCode: string = "";
let invoiceAddressCity: string = "";
let invoiceAddressZipCode: string = "";
export let paymentType:
| "paypal"
| "kreditkarte"
| "giropay"
| "sofort"
| "rechnung"
| "sepa" = "paypal";
let agbAkzeptiert: boolean; let agbAkzeptiert: boolean;
let datenschutzAkzeptiert: boolean; let datenschutzAkzeptiert: boolean;
@@ -33,24 +25,20 @@
</div> </div>
</div> </div>
<form <div
method="post"
target="_self"
novalidate
class="w-full" class="w-full"
action="/kaufabschluss"
> >
<fieldset class="flex flex-row gap-8"> <div class="flex flex-row gap-8">
<div class="w-3/5"> <div class="w-3/5">
<div class="GRB3"> <div class="GRB3">
<HelpLabel title="Ansprechpartner" /> <HelpLabel title="Ansprechpartner" />
<hr /> <hr />
<div class="grid grid-cols-5 gap-4"> <div class="grid grid-cols-3 gap-4">
<!-- Anrede --> <!-- Anrede -->
<div> <div>
<Label>Anrede *</Label> <Label>Anrede *</Label>
<div> <div>
<select name="Aanrede" class=""> <select name="anrede" bind:value={user.anrede}>
<option>bitte auswählen</option> <option>bitte auswählen</option>
<option value="Herr">Herr</option> <option value="Herr">Herr</option>
<option value="Frau">Frau</option> <option value="Frau">Frau</option>
@@ -61,25 +49,26 @@
<!-- Vorname --> <!-- Vorname -->
<div> <div>
<Label>Vorname *</Label> <Label>Vorname *</Label>
<input name="Avorname" type="text" required /> <input name="vorname" type="text" bind:value={user.vorname} required />
</div> </div>
<!-- Nachname --> <!-- Nachname -->
<div> <div>
<Label>Nachname *</Label> <Label>Nachname *</Label>
<input name="Anachname" type="text" required /> <input name="nachname" type="text" bind:value={user.name} required />
</div> </div>
</div>
<div class="grid grid-cols-2 gap-4">
<!-- Telefon --> <!-- Telefon -->
<div> <div>
<Label>Telefon</Label> <Label>Telefon</Label>
<input name="Atelefon" class="" type="text" /> <input name="telefon" bind:value={user.telefon} type="text" />
</div> </div>
<!-- Email --> <!-- Email -->
<div> <div>
<Label>E-Mail *</Label> <Label>E-Mail *</Label>
<input name="Aemail" type="email" required /> <input name="email" type="email" bind:value={user.email} required />
</div> </div>
</div> </div>
</div> </div>
@@ -91,12 +80,13 @@
<hr /> <hr />
<!-- Empfänger --> <!-- Empfänger -->
<div class="grid grid-cols-5 gap-4"> <div class="grid grid-cols-2 gap-4">
<div> <div>
<Label>Empfänger *</Label> <Label>Empfänger *</Label>
<input <input
name="Rempfaenger" name="Rempfaenger"
type="text" type="text"
bind:value={rechnung.empfaenger}
required required
data-rule-maxlength="100" data-rule-maxlength="100"
data-msg-maxlength="max. 100 Zeichen" data-msg-maxlength="max. 100 Zeichen"
@@ -113,12 +103,14 @@
data-msg-maxlength="max. 80 Zeichen" data-msg-maxlength="max. 80 Zeichen"
/> />
</div> </div>
</div>
<div class="grid grid-cols-3 gap-4">
<!-- Strasse --> <!-- Strasse -->
<div> <div>
<Label>Straße, Hausnummer *</Label> <Label>Straße, Hausnummer *</Label>
<input <input
name="Rstrasse" name="Rstrasse"
bind:value={rechnung.strasse}
type="text" type="text"
required required
data-rule-maxlength="40" data-rule-maxlength="40"
@@ -128,33 +120,34 @@
<!-- PLZ --> <!-- PLZ -->
<ZipSearch <ZipSearch
name="vplz" name="versand_plz"
bind:zip={invoiceAddressZipCode} bind:zip={rechnung.plz}
bind:city={invoiceAddressCity} bind:city={rechnung.ort}
/> />
<!-- Ort --> <!-- Ort -->
<div> <div>
<Label>Ort *</Label> <Label>Ort *</Label>
<input <input
name="Rort" name="rechnung_ort"
readonly readonly
type="text" type="text"
required required
value={invoiceAddressCity} value={rechnung.ort}
/> />
</div> </div>
</div>
<div class="grid grid-cols-2 gap-4">
<!-- Telefon --> <!-- Telefon -->
<div> <div>
<Label>Telefon</Label> <Label>Telefon</Label>
<input name="Rtelefon" class="" type="text" /> <input name="Rtelefon" bind:value={rechnung.telefon} type="text" />
</div> </div>
<!-- Email --> <!-- Email -->
<div> <div>
<Label>E-Mail</Label> <Label>E-Mail</Label>
<input name="Remail" type="email" /> <input name="Remail" bind:value={rechnung.email} type="email" />
</div> </div>
</div> </div>
</div> </div>
@@ -164,24 +157,24 @@
<div class="GRB3"> <div class="GRB3">
<HelpLabel title="Versandadresse" /> <HelpLabel title="Versandadresse" />
<hr /> <hr />
<div class="grid grid-cols-5 gap-4">
<div class="flex flex-row gap-2 items-center"> <div class="flex flex-row gap-2 items-center">
<input <input
class="w-[15px] h-[15px]" class="w-[15px] h-[15px]"
type="checkbox" type="checkbox"
id="deliveryAddress" id="deliveryAddress"
bind:checked={deliveryAddress} bind:checked={rechnung.abweichende_versand_adresse}
/> />
<Label>Abweichende Versandadresse</Label> <Label>Abweichende Versandadresse</Label>
</div> </div>
<div class="grid grid-cols-2 gap-4">
<!-- Empfänger --> <!-- Empfänger -->
<div> <div>
<Label>Empfänger *</Label> <Label>Empfänger *</Label>
<input <input
name="Vempfaenger" name="Vempfaenger"
type="text" type="text"
readonly={!deliveryAddress} readonly={!rechnung.abweichende_versand_adresse}
bind:value={rechnung.versand_empfaenger}
required required
data-rule-maxlength="100" data-rule-maxlength="100"
data-msg-maxlength="max. 100 Zeichen" data-msg-maxlength="max. 100 Zeichen"
@@ -194,19 +187,22 @@
<input <input
name="Vzusatzzeile" name="Vzusatzzeile"
type="text" type="text"
readonly={!deliveryAddress} readonly={!rechnung.abweichende_versand_adresse}
bind:value={rechnung.versand_zusatzzeile}
data-rule-maxlength="80" data-rule-maxlength="80"
data-msg-maxlength="max. 80 Zeichen" data-msg-maxlength="max. 80 Zeichen"
/> />
</div> </div>
</div>
<div class="grid grid-cols-3 gap-4">
<!-- Strasse --> <!-- Strasse -->
<div> <div>
<Label>Straße, Hausnummer *</Label> <Label>Straße, Hausnummer *</Label>
<input <input
name="Vstrasse" name="Vstrasse"
type="text" type="text"
readonly={!deliveryAddress} readonly={!rechnung.abweichende_versand_adresse}
bind:value={rechnung.strasse}
required required
data-rule-maxlength="40" data-rule-maxlength="40"
data-msg-maxlength="max. 40 Zeichen" data-msg-maxlength="max. 40 Zeichen"
@@ -216,9 +212,9 @@
<!-- PLZ --> <!-- PLZ -->
<ZipSearch <ZipSearch
name="rplz" name="rplz"
readonly={!deliveryAddress} readonly={!rechnung.abweichende_versand_adresse}
bind:zip={mailAddressZipCode} bind:zip={rechnung.versand_plz}
bind:city={mailAddressCity} bind:city={rechnung.versand_ort}
/> />
<!-- Ort --> <!-- Ort -->
@@ -229,7 +225,7 @@
type="text" type="text"
readonly readonly
required required
value={mailAddressCity} bind:value={rechnung.versand_ort}
/> />
</div> </div>
</div> </div>
@@ -237,96 +233,28 @@
<hr /> <hr />
<div class="yellow-box"> <div class="GRB3">
<h4>Bitte wählen sie ihre Bezahlmethode aus.</h4> <HelpLabel title="Bezahlmethode" />
<div class="flex flex-row gap-4"> <hr />
<div class="w-1/2"> <div class="flex flex-row justify-between gap-4">
<div> <PaymentOption paymentType={Enums.Bezahlmethoden.PAYPAL} bind:selectedPaymentType name={"PayPal"} icon={"/images/paypal.png"}></PaymentOption>
<div class="payment-option-card"> <PaymentOption paymentType={Enums.Bezahlmethoden.SOFORT} bind:selectedPaymentType name={"Sofort"} icon={"/images/sofort.png"}></PaymentOption>
<img <PaymentOption paymentType={Enums.Bezahlmethoden.GIROPAY} bind:selectedPaymentType name={"Giropay"} icon={"/images/giropay.png"}></PaymentOption>
src="/images/paypal.png" <PaymentOption paymentType={Enums.Bezahlmethoden.KREDITKARTE} bind:selectedPaymentType name={"Kreditkarte"} icon={"/images/mastercard.png"}></PaymentOption>
alt="PayPal" <PaymentOption paymentType={Enums.Bezahlmethoden.RECHNUNG} bind:selectedPaymentType name={"Rechnung"} icon={"/images/rechnung.png"}></PaymentOption>
/>
<div
class="payment-option-label"
aria-label="Zahlen mit PayPal"
>
Zahlen mit PayPal
</div>
</div>
<div class="payment-option-card">
<img
src="/images/giropay.png"
alt="Giropay"
/>
<div
class="payment-option-label"
aria-label="Zahlen mit Giropay"
>
Zahlen mit Giropay
</div>
</div>
<div class="payment-option-card">
<img
src="/images/sofort.png"
alt="Sofort"
/>
<div
class="payment-option-label"
aria-label="Zahlen mit Sofort"
>
Zahlen mit Sofort
</div>
</div>
</div>
<div>
<div class="payment-option-card">
<img
src="/images/mastercard.png"
alt="Mastercard"
/>
<div
class="payment-option-label"
aria-label="Zahlen mit Kreditkarte"
>
Zahlen mit Kreditkarte
</div>
</div>
<div class="payment-option-card">
<img
src="/images/rechnung.png"
alt="Rechnung"
/>
<div
class="payment-option-label"
aria-label="Zahlen mit Rechnung"
>
Zahlen mit Rechnung
</div>
</div>
<div class="payment-option-card">
<img src="/images/sepa.png" alt="SEPA" />
<div
class="payment-option-label"
aria-label="Zahlen mit SEPA über PayPal"
>
SEPA über PayPal
</div>
</div>
</div>
</div> </div>
<div class="w-1/2"> <div class="w-1/2">
<div class="flex-row justify-between"> <div class="flex-row justify-between">
<h5>{paymentType}</h5> <h5>{selectedPaymentType}</h5>
<img <img
src="../../images/{paymentType == src="../../images/{selectedPaymentType ==
'kreditkarte' Enums.Bezahlmethoden.KREDITKARTE
? 'mastercard' ? 'mastercard'
: paymentType}.png" : selectedPaymentType}.png"
class="payment-option-logo" class="payment-option-logo"
/> />
</div> </div>
{#if paymentType == "rechnung"} {#if selectedPaymentType == Enums.Bezahlmethoden.RECHNUNG}
<p> <p>
Sobald sie AGB und Datenschutzerklärung Sobald sie AGB und Datenschutzerklärung
gelesen und akzeptiert haben können sie den gelesen und akzeptiert haben können sie den
@@ -342,7 +270,7 @@
gelesen und akzeptiert haben können sie den gelesen und akzeptiert haben können sie den
Kauf fortsetzen. Durch das Klicken auf Kauf fortsetzen. Durch das Klicken auf
'Kostenpflichtig Bestellen' werden sie zu <strong 'Kostenpflichtig Bestellen' werden sie zu <strong
>{paymentType}</strong >{selectedPaymentType}</strong
> weitergeleitet. > weitergeleitet.
</p> </p>
{/if} {/if}
@@ -379,7 +307,6 @@
> >
</div> </div>
</div> </div>
</div>
<hr /> <hr />
@@ -390,8 +317,8 @@
<div class="w-2/5"> <div class="w-2/5">
<PriceContainer prices={[45, 60, 160]} /> <PriceContainer prices={[45, 60, 160]} />
</div> </div>
</fieldset> </div>
</form> </div>
</div> </div>
<style> <style>

View File

@@ -7,12 +7,20 @@
let passwort: string; let passwort: string;
async function login() { async function login() {
const response = await client.v1.benutzer.tokenErneuern.query({ try {
const response = await client.v1.benutzer.getRefreshToken.query({
email, email,
passwort passwort
}) })
const options = {
if (!response.token || !response.exp) { domain: `.${window.location.hostname}`,
path: "/",
expires: response.exp
}
Cookies.set("accessToken", response.accessToken, options);
Cookies.set("refreshToken", response.refreshToken, options);
window.location.href = "/user";
} catch (e) {
addNotification({ addNotification({
message: "Ups...", message: "Ups...",
subtext: "Das hat leider nicht geklappt, haben sie ihr Passwort und ihre Email Adresse richtig eingegeben?", subtext: "Das hat leider nicht geklappt, haben sie ihr Passwort und ihre Email Adresse richtig eingegeben?",
@@ -20,16 +28,7 @@
timeout: 6000, timeout: 6000,
dismissable: true dismissable: true
}) })
return;
} }
const options = {
domain: `.${window.location.hostname}`,
path: "/",
expires: response.exp
}
Cookies.set("token", response.token, options);
window.location.href = "/user";
} }
</script> </script>

View File

@@ -1,6 +1,5 @@
<script lang="ts"> <script lang="ts">
import { addNotification } from "@ibcornelsen/ui"; import { addNotification } from "@ibcornelsen/ui";
import Cookies from "js-cookie";
import {client} from "src/trpc"; import {client} from "src/trpc";
let passwort: string; let passwort: string;
@@ -9,22 +8,15 @@
let name: string; let name: string;
async function login() { async function login() {
try {
const response = await client.v1.benutzer.erstellen.query({ const response = await client.v1.benutzer.erstellen.query({
email, email,
passwort, passwort,
vorname, vorname,
name name
}) })
if (response.token) {
const options = {
domain: `.${window.location.hostname}`,
path: "/",
expires: response.exp
}
Cookies.set("token", response.token, options);
window.location.href = "/login"; window.location.href = "/login";
} else { } catch (e) {
addNotification({ addNotification({
message: "Ups...", message: "Ups...",
subtext: "Da ist wohl etwas schiefgelaufen... Diese Email Adresse ist bereits in Benutzung, haben sie vielleicht bereits ein Konto bei uns?", subtext: "Da ist wohl etwas schiefgelaufen... Diese Email Adresse ist bereits in Benutzung, haben sie vielleicht bereits ein Konto bei uns?",

View File

@@ -1,42 +0,0 @@
// NOTE: Öffentliche API benötigt OpenApiMeta. Das Package bräuchte momentan noch einen extra Server, deshalb nehmen wir es momentan noch nicht mit rein.
//import { OpenApiMeta } from "trpc-openapi";
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import { APIRoute } from "astro";
import { t } from "../../lib/trpc/context";
import { v1Router } from "#lib/trpc/procedures/v1";
export const appRouter = t.router({
v1: v1Router,
});
export const all: APIRoute = ({ request }) => {
return fetchRequestHandler({
req: request,
endpoint: "/api",
router: appRouter,
createContext: async ({ req }) => {
const ip = req.headers.get("x-forwarded-for");
const authorization = req.headers.get("authorization") || null;
return {
authorization,
ip: ip?.toString() || "",
req: req,
};
},
});
};
export function tRPCCaller(request: Request) {
const { authorization } = {
authorization: request.headers.get("authorization") || "",
};
const createCaller = t.createCallerFactory(appRouter);
return createCaller({
authorization,
req: request,
ip: request.headers.get("x-forwarded-for") || "",
});
}
export type AppRouter = typeof appRouter;

View File

@@ -1,46 +0,0 @@
import type { APIRoute } from "astro";
import {
MissingEntityError,
error,
} from "src/lib/APIResponse";
import * as path from "path";
import * as fs from "fs";
import { prisma } from "@ibcornelsen/database";
export const get: APIRoute = async ({ url }) => {
const body = url.searchParams
const uid = body.get("uid")
if (!body.has("uid") || !uid) {
return error(["Missing 'uid' in request body."])
}
const image = await prisma.gebaeudeBilder.findUnique({
where: {
uid
},
select: {
uid: true,
kategorie: true
}
})
if (!image) {
return MissingEntityError("image")
}
// Check if the image exists on disk
const location = path.join("/persistent/uploads/images", `${image.uid}.jpg`);
if (!fs.existsSync(location)) {
return MissingEntityError("image")
}
const data = fs.readFileSync(location);
return new Response(data, {
headers: {
"Content-Type": "image/jpeg"
}
});
};

View File

@@ -1,131 +0,0 @@
import type { APIRoute } from "astro";
import {
ActionFailedError,
MissingEntityError,
error,
success,
} from "src/lib/APIResponse";
import * as jimp from "jimp";
import { z } from "zod";
import * as path from "path";
import * as fs from "fs";
import { prisma } from "@ibcornelsen/database";
const ImageUploadChecker = z.object({
data: z.string(),
name: z.string(),
gebaeude_uid: z.string().optional(),
kategorie: z.string(),
});
export const get: APIRoute = async ({ url }) => {
const body = url.searchParams
const uid = body.get("uid")
if (!body.has("uid") || !uid) {
return error(["Missing 'uid' in request body."])
}
const image = await prisma.gebaeudeBilder.findUnique({
where: {
uid
},
select: {
uid: true,
kategorie: true
}
})
if (!image) {
return MissingEntityError("image")
}
// Check if the image exists on disk
const location = path.join("/persistent/uploads/images", `${image.uid}.jpg`);
if (!fs.existsSync(location)) {
return MissingEntityError("image")
}
const data = fs.readFileSync(location, { encoding: "base64" });
return success(data);
};
/**
* Speichert ein Bild auf unserem Server ab und gibt die UID des Bildes zurück
* @param param0
* @returns
*/
export const put: APIRoute = async ({ request }) => {
const body: z.infer<typeof ImageUploadChecker> = await request.json();
const validation = ImageUploadChecker.safeParse(body);
if (!validation.success) {
return error(validation.error.issues);
}
const image = Buffer.from(body.data, "base64url");
let jimpResult;
try {
jimpResult = await jimp.read(image);
} catch (e) {
return ActionFailedError();
}
let gebaeude;
if (!body.gebaeude_uid) {
gebaeude = await prisma.gebaeudeStammdaten.create({
data: {},
select: {
uid: true,
id: true
}
})
if (!gebaeude) {
return ActionFailedError();
}
} else {
gebaeude = await prisma.gebaeudeStammdaten.findUnique({
where: {
uid: body.gebaeude_uid
}
})
if (!gebaeude) {
return MissingEntityError("gebaeude");
}
}
const result = await prisma.gebaeudeBilder.create({
data: {
gebaeude_stammdaten_id: gebaeude.id,
kategorie: body.kategorie
},
select: {
uid: true
}
})
if (!result) {
return ActionFailedError();
}
const location = path.join("/persistent/uploads", `${result.uid}.jpg`);
const buffer = await jimpResult.getBufferAsync(jimp.MIME_JPEG)
if (buffer.length > 3_000_000) {
jimpResult.quality(75).write(location);
} else {
jimpResult.write(location);
}
return success({
uid: result.uid,
gebaeude_uid: gebaeude.uid,
});
};

View File

@@ -1,9 +1,9 @@
--- ---
import { changeLanguage } from "i18next";
import AusweisLayout from "#layouts/AusweisLayout.astro"; import AusweisLayout from "#layouts/AusweisLayout.astro";
import BedarfsausweisContent from "#components/Bedarfsausweis/BedarfsausweisContent.svelte"; import BedarfsausweisContent from "#components/Bedarfsausweis/BedarfsausweisContent.svelte";
changeLanguage("de");
--- ---
<AusweisLayout title="Bedarfsausweis erstellen | IBCornelsen"> <AusweisLayout title="Bedarfsausweis erstellen | IBCornelsen">
<BedarfsausweisContent client:load></BedarfsausweisContent> <BedarfsausweisContent client:load></BedarfsausweisContent>

View File

@@ -1,8 +1,8 @@
--- ---
import { changeLanguage } from "i18next";
import Layout from "#layouts/Layout.astro"; import Layout from "#layouts/Layout.astro";
changeLanguage("de");
--- ---
<Layout title="Für Entwickler - IBCornelsen"> <Layout title="Für Entwickler - IBCornelsen">

View File

@@ -1,8 +1,8 @@
--- ---
import { changeLanguage } from "i18next";
import Layout from "#layouts/Layout.astro"; import Layout from "#layouts/Layout.astro";
changeLanguage("de");
--- ---
<Layout title="FAQ - IBCornelsen"></Layout> <Layout title="FAQ - IBCornelsen"></Layout>

View File

@@ -1,11 +1,11 @@
--- ---
import { changeLanguage } from "i18next";
import { BoxWithHeading } from "@ibcornelsen/ui"; import { BoxWithHeading } from "@ibcornelsen/ui";
import Widget from "#components/Widget.svelte"; import Widget from "#components/Widget.svelte";
import Layout from "#layouts/Layout.astro"; import Layout from "#layouts/Layout.astro";
import FeatureCard from "#components/FeatureCard.svelte"; import FeatureCard from "#components/FeatureCard.svelte";
changeLanguage("de");
--- ---
<Layout title="Energieausweis online erstellen - Online Energieausweis"> <Layout title="Energieausweis online erstellen - Online Energieausweis">

View File

@@ -1,11 +0,0 @@
---
import { changeLanguage } from "i18next";
import Kaufabschluss from "#components/Kaufabschluss/Kaufabschluss.svelte";
import AusweisLayout from "#layouts/AusweisLayout.astro";
changeLanguage("de");
---
<AusweisLayout title="Kaufabschluss Verbrauchsausweis - IBCornelsen">
<Kaufabschluss client:load></Kaufabschluss>
</AusweisLayout>

View File

@@ -1,12 +1,40 @@
--- ---
import { changeLanguage } from "i18next";
import Kundendaten from "#components/Ausweis/Kundendaten.svelte";
import AusweisLayout from "#layouts/AusweisLayout.astro";
changeLanguage("de"); import KundendatenModule from "#modules/KundendatenModule.svelte";
import AusweisLayout from "#layouts/AusweisLayout.astro";
import { Benutzer, Enums, prisma } from "@ibcornelsen/database";
const user = await prisma.benutzer.findUnique({
where: {
id: 1,
},
}) as Benutzer;
// Man sollte nur auf diese Seite kommen, wenn ein Ausweis bereits vorliegt und in der Datenbank abgespeichert wurde.
const uid = Astro.url.searchParams.get("uid");
if (!uid) {
return Astro.redirect("/");
}
// NOTE: Muss umgestellt werden, wir brauchen einen Kundendaten Abschluss für jede Ausweisart.
const ausweis = await prisma.verbrauchsausweisWohnen.findUnique({
where: {
uid,
},
});
if (!ausweis) {
return Astro.redirect("/");
}
--- ---
<AusweisLayout title="Kundendaten Aufnehmen - IBCornelsen"> <AusweisLayout title="Kundendaten Aufnehmen - IBCornelsen">
<Kundendaten client:load></Kundendaten> <KundendatenModule user={user} ausweis={ausweis} selectedPaymentType={Enums.Bezahlmethoden.PAYPAL} client:load></KundendatenModule>
</AusweisLayout> </AusweisLayout>

View File

@@ -2,13 +2,6 @@
import moment from "moment"; import moment from "moment";
import LoginModule from "../modules/LoginModule.svelte"; import LoginModule from "../modules/LoginModule.svelte";
import Layout from "../layouts/Layout.astro"; import Layout from "../layouts/Layout.astro";
const token = Astro.cookies.get("token").value;
const expires = Astro.cookies.get("expires").number();
const now = moment().unix();
if (token && now < expires) {
return Astro.redirect(`/user`);
}
--- ---
<Layout title="Login"> <Layout title="Login">

View File

@@ -1,7 +1,7 @@
--- ---
import { changeLanguage } from "i18next";
changeLanguage("de");
Astro.cookies.delete("token"); Astro.cookies.delete("token");
Astro.cookies.delete("expires"); Astro.cookies.delete("expires");

View File

@@ -1,23 +1,42 @@
--- ---
import { changeLanguage } from "i18next";
import moment from "moment"; import moment from "moment";
import { Ausweis } from "src/lib/Ausweis";
import { Verbrauchsausweis } from "src/lib/Ausweis/Verbrauchsausweis";
import Checkbox from "#components/Checkbox.svelte"; import Checkbox from "#components/Checkbox.svelte";
import PDFHeader from "#components/PDF/PDFHeader.svelte"; import PDFHeader from "#components/PDF/PDFHeader.svelte";
import PDFSectionHeader from "#components/PDF/PDFSectionHeader.svelte"; import PDFSectionHeader from "#components/PDF/PDFSectionHeader.svelte";
import PDFLayout from "#layouts/PDFLayout.astro"; import PDFLayout from "#layouts/PDFLayout.astro";
import { VerbrauchsausweisWohnen, GebaeudeStammdaten, prisma } from "@ibcornelsen/database";
changeLanguage("de");
const base64 = Astro.url.searchParams.get("base64"); const base64 = Astro.url.searchParams.get("base64");
if (!base64) { let ausweis: (Partial<VerbrauchsausweisWohnen> & { gebaeude_stammdaten: Partial<GebaeudeStammdaten> }) | null = null;
if (base64) {
const buffer = Buffer.from(base64, "base64");
const json = buffer.toString("utf-8");
ausweis = JSON.parse(json);
} else {
const uidAusweis = Astro.url.searchParams.get("ausweis_uid");
if (!uidAusweis) {
return Astro.redirect("/404"); return Astro.redirect("/404");
}
ausweis = await prisma.verbrauchsausweisWohnen.findUnique({
where: {
uid: uidAusweis,
},
include: {
gebaeude_stammdaten: true,
},
});
} }
const ausweis = Verbrauchsausweis.fromBase64(base64);
if (!ausweis) { if (!ausweis) {
return Astro.redirect("/404"); return Astro.redirect("/404");
} }
const gebaeude = ausweis.gebaeude_stammdaten;
--- ---
<PDFLayout title="Ansichtsausweis"> <PDFLayout title="Ansichtsausweis">
@@ -45,30 +64,30 @@ if (!ausweis) {
<table> <table>
<tr> <tr>
<td>Gebäudetyp</td> <td>Gebäudetyp</td>
<td>{ausweis.objekt_typ}</td> <td>{gebaeude.gebaeudetyp}</td>
</tr> </tr>
<tr> <tr>
<td>Adresse</td> <td>Adresse</td>
<td>{ausweis.objekt_strasse}</td> <td>{gebaeude.adresse}</td>
</tr> </tr>
<tr> <tr>
<td>Gebäudeteil</td> <td>Gebäudeteil</td>
<td>{ausweis.objekt_gebaeudeteil}</td> <td>{gebaeude.gebaeudeteil}</td>
</tr> </tr>
<tr> <tr>
<td>Baujahr Gebäude ³</td> <td>Baujahr Gebäude ³</td>
<td>{ausweis.baujahr_gebaeude}</td> <td>{gebaeude.baujahr_gebaeude}</td>
</tr> </tr>
<tr> <tr>
<td <td
>Baujahr Wärmeerzeuger <sup>3</sup> >Baujahr Wärmeerzeuger <sup>3</sup>
<sup>4</sup></td <sup>4</sup></td
> >
<td>{ausweis.baujahr_anlage}</td> <td>{gebaeude.baujahr_heizung}</td>
</tr> </tr>
<tr> <tr>
<td>Anzahl Wohnungen</td> <td>Anzahl Wohnungen</td>
<td>{ausweis.anzahl_einheiten}</td> <td>{gebaeude.einheiten}</td>
</tr> </tr>
<tr> <tr>
<td>Gebäudenutzfläche (A<sub>N</sub>)</td> <td>Gebäudenutzfläche (A<sub>N</sub>)</td>

View File

@@ -1,79 +1,136 @@
--- ---
import { changeLanguage } from "i18next";
import moment from "moment"; import moment from "moment";
import { Verbrauchsausweis } from "src/lib/Ausweis/Verbrauchsausweis";
import { Dachgeschoss } from "src/lib/Ausweis/types";
import Checkbox from "#components/Checkbox.svelte"; import Checkbox from "#components/Checkbox.svelte";
import DatenblattFooter from "#components/DatenblattFooter.svelte"; import DatenblattFooter from "#components/DatenblattFooter.svelte";
import DatenblattHeader from "#components/DatenblattHeader.svelte"; import DatenblattHeader from "#components/DatenblattHeader.svelte";
import PDFHeader from "#components/PDF/PDFHeader.svelte";
import PDFSectionHeader from "#components/PDF/PDFSectionHeader.svelte";
import PDFLayout from "#layouts/PDFLayout.astro"; import PDFLayout from "#layouts/PDFLayout.astro";
import { GebaeudeStammdaten, VerbrauchsausweisWohnen, prisma } from "@ibcornelsen/database";
changeLanguage("de");
const base64 = Astro.url.searchParams.get("base64"); const base64 = Astro.url.searchParams.get("base64");
if (!base64) { let ausweis: (Partial<VerbrauchsausweisWohnen> & { gebaeude_stammdaten: Partial<GebaeudeStammdaten> }) | null = null;
if (base64) {
const buffer = Buffer.from(base64, "base64");
const json = buffer.toString("utf-8");
ausweis = JSON.parse(json);
} else {
const uidAusweis = Astro.url.searchParams.get("ausweis_uid");
if (!uidAusweis) {
return Astro.redirect("/404"); return Astro.redirect("/404");
}
ausweis = await prisma.verbrauchsausweisWohnen.findUnique({
where: {
uid: uidAusweis,
},
include: {
gebaeude_stammdaten: true,
},
});
} }
const ausweis = Verbrauchsausweis.fromBase64(base64);
if (!ausweis) { if (!ausweis) {
return Astro.redirect("/404"); return Astro.redirect("/404");
} }
const gebaeude = ausweis.gebaeude_stammdaten;
--- ---
<PDFLayout title="Datenblatt"> <PDFLayout title="Datenblatt">
<div class="flex flex-col gap-20"> <div class="flex flex-col gap-20">
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<DatenblattHeader></DatenblattHeader> <DatenblattHeader />
<div class="px-12 py-20 flex flex-col gap-2"> <div class="px-12 py-20 flex flex-col gap-2">
<div class="flex flex-row justify-between items-center"> <div class="flex flex-row justify-between items-center">
<h2>Datenblatt Energieausweis</h2> <h2>Datenblatt Energieausweis</h2>
<h2>Ausweis ID: </h2> <h2>Ausweis ID:</h2>
</div> </div>
<h3>Gebäudedaten:</h3> <h3>Gebäudedaten:</h3>
<p>Adresse: {ausweis.objekt_strasse}, {ausweis.objekt_plz} {ausweis.objekt_ort}</p> <p>
Adresse: {gebaeude.adresse}, {
gebaeude.plz
}
{gebaeude.ort}
</p>
<div class="flex justify-between"> <div class="flex justify-between">
<Checkbox checked={ausweis.ausstellgrund == "Neubau"}>Neubau</Checkbox> <Checkbox checked={ausweis.ausstellgrund == "Neubau"}>
<Checkbox checked={ausweis.ausstellgrund == "Vermietung" || ausweis.ausstellgrund == "Verkauf"}>Vermietung/Verkauf</Checkbox> Neubau
<Checkbox checked={ausweis.ausstellgrund == "Modernisierung"}>Modernisierung</Checkbox> </Checkbox>
<Checkbox checked={ausweis.ausstellgrund == "Sonstiges"}>Sonstiges</Checkbox> <Checkbox
checked={ausweis.ausstellgrund == "Vermietung" ||
ausweis.ausstellgrund == "Verkauf"}
>
Vermietung/Verkauf
</Checkbox>
<Checkbox
checked={ausweis.ausstellgrund == "Modernisierung"}
>
Modernisierung
</Checkbox>
<Checkbox checked={ausweis.ausstellgrund == "Sonstiges"}>
Sonstiges
</Checkbox>
</div> </div>
<div class="flex justify-between gap-4"> <div class="flex justify-between gap-4">
<table> <table>
<tbody><tr> <tbody
><tr>
<td>Baujahr Gebäude:</td> <td>Baujahr Gebäude:</td>
<td>{ausweis.baujahr_gebaeude}</td> <td
>{
gebaeude.baujahr_gebaeude
}</td
>
</tr> </tr>
<tr> <tr>
<td>Baujahr Heizung:</td> <td>Baujahr Heizung:</td>
<td>{ausweis.baujahr_anlage}</td> <td
>{
gebaeude.baujahr_heizung
}</td
>
</tr> </tr>
<tr> <tr>
<td>Wohnfläche:</td> <td>Wohnfläche:</td>
<td>{ausweis.wohnflaeche}</td> <td>{gebaeude.flaeche}</td>
</tr> </tr>
<tr> <tr>
<td>Lüftungskonzept:</td> <td>Lüftungskonzept:</td>
<td>{ausweis.lueftungskonzept}</td> <td>{gebaeude.lueftung}</td>
</tr> </tr>
<tr> <tr>
<td>Gebäudetyp:</td> <td>Gebäudetyp:</td>
<td>{ausweis.objekt_typ}</td> <td
</tr></tbody> >{
gebaeude.gebaeudetyp
}</td
>
</tr></tbody
>
</table> </table>
<table> <table>
<tbody><tr> <tbody
><tr>
<td>Dachgeschoss:</td> <td>Dachgeschoss:</td>
<td>{ausweis.dachgeschoss == Dachgeschoss.BEHEIZT ? "Beheizt" : (ausweis.dachgeschoss == Dachgeschoss.UNBEHEIZT ? "Unbeheizt" : "Nicht Vorhanden")}</td> <td
>{
gebaeude.dachgeschoss
? "Beheizt"
: gebaeude
.dachgeschoss
? "Unbeheizt"
: "Nicht Vorhanden"
}</td
>
</tr> </tr>
<tr> <tr>
<td>Beheizter Keller:</td> <td>Beheizter Keller:</td>
<td>{ausweis.keller_beheizt ? "Ja" : "Nein"}</td> <td>{ausweis.keller_beheizt ? "Ja" : "Nein"}</td
>
</tr> </tr>
<tr> <tr>
<td>Wohnungen:</td> <td>Wohnungen:</td>
<td>{ausweis.anzahl_einheiten}</td> <td>{gebaeude.einheiten}</td>
</tr> </tr>
<tr> <tr>
<td>Anlage zur Kühlung:</td> <td>Anlage zur Kühlung:</td>
@@ -81,40 +138,75 @@ if (!ausweis) {
</tr> </tr>
<tr> <tr>
<td>Leerstand:</td> <td>Leerstand:</td>
<td>{ausweis.leerstand}%</td> <td>{gebaeude.leerstand}%</td
</tr></tbody> >
</tr></tbody
>
</table> </table>
</div> </div>
<div class="flex flex-row gap-8"> <div class="flex flex-row gap-8">
<div class="flex flex-col"> <div class="flex flex-col">
<h2>Heizverbrauch</h2> <h2>Heizverbrauch</h2>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>Von: {moment(ausweis.energieverbrauch_zeitraum).format("MM.YYYY")}</p> <p>
<p>Bis: {moment(ausweis.energieverbrauch_zeitraum).add("1", "year").format("MM.YYYY")}</p> Von: {
moment(ausweis.startdatum).format("MM.YYYY")
}
</p>
<p>
Bis: {
moment(ausweis.startdatum)
.add("1", "year")
.format("MM.YYYY")
}
</p>
</div> </div>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>Von: {moment(ausweis.energieverbrauch_zeitraum).add("1", "year").format("MM.YYYY")}</p> <p>
<p>Bis: {moment(ausweis.energieverbrauch_zeitraum).add("2", "years").format("MM.YYYY")}</p> Von: {
moment(ausweis.startdatum)
.add("1", "year")
.format("MM.YYYY")
}
</p>
<p>
Bis: {
moment(ausweis.startdatum)
.add("2", "years")
.format("MM.YYYY")
}
</p>
</div> </div>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>Von: {moment(ausweis.energieverbrauch_zeitraum).add("2", "years").format("MM.YYYY")}</p> <p>
<p>Bis: {moment(ausweis.energieverbrauch_zeitraum).add("3", "years").format("MM.YYYY")}</p> Von: {
moment(ausweis.startdatum)
.add("2", "years")
.format("MM.YYYY")
}
</p>
<p>
Bis: {
moment(ausweis.startdatum)
.add("3", "years")
.format("MM.YYYY")
}
</p>
</div> </div>
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<h2>{ausweis.energietraeger_1}</h2> <h2>{ausweis.brennstoff_1}</h2>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>{ausweis.energieverbrauch_1_heizquelle_1}</p> <p>{ausweis.verbrauch_1}</p>
<p>{ausweis.energietraeger_einheit_heizquelle_1}</p> <p>{ausweis.einheit_1}</p>
</div> </div>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>{ausweis.energieverbrauch_2_heizquelle_1}</p> <p>{ausweis.verbrauch_2}</p>
<p>{ausweis.energietraeger_einheit_heizquelle_1}</p> <p>{ausweis.einheit_1}</p>
</div> </div>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>{ausweis.energieverbrauch_3_heizquelle_1}</p> <p>{ausweis.verbrauch_3}</p>
<p>{ausweis.energietraeger_einheit_heizquelle_1}</p> <p>{ausweis.einheit_1}</p>
</div> </div>
</div> </div>
</div> </div>
@@ -122,85 +214,266 @@ if (!ausweis) {
<div class="flex flex-col"> <div class="flex flex-col">
<h2>Heizverbrauch (Heizwert)</h2> <h2>Heizverbrauch (Heizwert)</h2>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>Von: {moment(ausweis.energieverbrauch_zeitraum).format("MM.YYYY")}</p> <p>
<p>Bis: {moment(ausweis.energieverbrauch_zeitraum).add("1", "year").format("MM.YYYY")}</p> Von: {
moment(ausweis.startdatum).format("MM.YYYY")
}
</p>
<p>
Bis: {
moment(ausweis.startdatum)
.add("1", "year")
.format("MM.YYYY")
}
</p>
</div> </div>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>Von: {moment(ausweis.energieverbrauch_zeitraum).add("1", "year").format("MM.YYYY")}</p> <p>
<p>Bis: {moment(ausweis.energieverbrauch_zeitraum).add("2", "years").format("MM.YYYY")}</p> Von: {
moment(ausweis.startdatum)
.add("1", "year")
.format("MM.YYYY")
}
</p>
<p>
Bis: {
moment(ausweis.startdatum)
.add("2", "years")
.format("MM.YYYY")
}
</p>
</div> </div>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>Von: {moment(ausweis.energieverbrauch_zeitraum).add("2", "years").format("MM.YYYY")}</p> <p>
<p>Bis: {moment(ausweis.energieverbrauch_zeitraum).add("3", "years").format("MM.YYYY")}</p> Von: {
moment(ausweis.startdatum)
.add("2", "years")
.format("MM.YYYY")
}
</p>
<p>
Bis: {
moment(ausweis.startdatum)
.add("3", "years")
.format("MM.YYYY")
}
</p>
</div> </div>
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<h2>{ausweis.energietraeger_1}</h2> <h2>{ausweis.brennstoff_1}</h2>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>{ausweis.energieverbrauch_1_heizquelle_1}</p> <p>{ausweis.verbrauch_1}</p>
<p>{ausweis.energietraeger_einheit_heizquelle_1}</p> <p>{ausweis.einheit_1}</p>
</div> </div>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>{ausweis.energieverbrauch_2_heizquelle_1}</p> <p>{ausweis.verbrauch_2}</p>
<p>{ausweis.energietraeger_einheit_heizquelle_1}</p> <p>{ausweis.einheit_1}</p>
</div> </div>
<div class="flex flex-row justify-between gap-4"> <div class="flex flex-row justify-between gap-4">
<p>{ausweis.energieverbrauch_3_heizquelle_1}</p> <p>{ausweis.verbrauch_3}</p>
<p>{ausweis.energietraeger_einheit_heizquelle_1}</p> <p>{ausweis.einheit_1}</p>
</div> </div>
</div> </div>
</div> </div>
<p>Warmwasser enthalten: {ausweis.warmwasser_enthalten ? "Ja" : "Nein"}</p> <p>
Warmwasser enthalten: {
ausweis.warmwasser_enthalten ? "Ja" : "Nein"
}
</p>
</div> </div>
<DatenblattFooter></DatenblattFooter> <DatenblattFooter />
</div> </div>
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
<DatenblattHeader></DatenblattHeader> <DatenblattHeader />
<div class="px-12 py-20 flex flex-col gap-2"> <div class="px-12 py-20 flex flex-col gap-2">
<h2>Modernisierungsstand</h2> <h2>Modernisierungsstand</h2>
<h3>Heizungsanlage</h3> <h3>Heizungsanlage</h3>
<div class="grid grid-cols-3"> <div class="grid grid-cols-3">
<Checkbox checked={ausweis.versorgungssysteme[0]}>Zentral/Etage</Checkbox> <Checkbox
<Checkbox checked={ausweis.versorgungssysteme[1]}>Einzelöfen</Checkbox> checked={gebaeude.zentralheizung ||
<Checkbox checked={ausweis.versorgungssysteme[2]}>Durchlauferhitzer</Checkbox> false}
<Checkbox checked={ausweis.versorgungssysteme[3]}>Standardkessel</Checkbox> >
<Checkbox checked={ausweis.versorgungssysteme[4]}>Solarsystem für Warmwasser</Checkbox> Zentral/Etage
<Checkbox checked={ausweis.versorgungssysteme[5]}>Wärmepumpe</Checkbox> </Checkbox>
<Checkbox checked={ausweis.versorgungssysteme[6]}>Niedertemperaturkessel</Checkbox> <Checkbox
<Checkbox checked={ausweis.versorgungssysteme[7]}>Brennwertkessel/Therme</Checkbox> checked={gebaeude.einzelofen ||
<Checkbox checked={ausweis.versorgungssysteme[8]}>Warmwasserrohre gedämmt</Checkbox> false}
<Checkbox checked={ausweis.versorgungssysteme[9]}>Heizungsrohre gedämmt</Checkbox> >
<Checkbox checked={ausweis.versorgungssysteme[10]}>Zirkulation</Checkbox> Einzelöfen
<Checkbox checked={ausweis.versorgungssysteme[11]}>Raumtemperraturregler</Checkbox> </Checkbox>
<Checkbox
checked={gebaeude
.durchlauf_erhitzer || false}
>
Durchlauferhitzer
</Checkbox>
<Checkbox
checked={gebaeude.standard_kessel ||
false}
>
Standardkessel
</Checkbox>
<Checkbox
checked={gebaeude
.solarsystem_warmwasser || false}
>
Solarsystem für Warmwasser
</Checkbox>
<Checkbox
checked={gebaeude.waermepumpe ||
false}
>
Wärmepumpe
</Checkbox>
<Checkbox
checked={gebaeude
.niedertemperatur_kessel || false}
>
Niedertemperaturkessel
</Checkbox>
<Checkbox
checked={gebaeude.brennwert_kessel ||
false}
>
Brennwertkessel/Therme
</Checkbox>
<Checkbox
checked={gebaeude
.warmwasser_rohre_gedaemmt || false}
>
Warmwasserrohre gedämmt
</Checkbox>
<Checkbox
checked={gebaeude
.heizungsrohre_gedaemmt || false}
>
Heizungsrohre gedämmt
</Checkbox>
<Checkbox
checked={gebaeude.zirkulation ||
false}
>
Zirkulation
</Checkbox>
<Checkbox
checked={gebaeude
.raum_temperatur_regler || false}
>
Raumtemperraturregler
</Checkbox>
</div> </div>
<h3>Fenster/Dachfenster/Türen</h3> <h3>Fenster/Dachfenster/Türen</h3>
<div class="grid grid-cols-3"> <div class="grid grid-cols-3">
<Checkbox checked={ausweis.fenster_dach[0]}>Einfachglas</Checkbox> <Checkbox
<Checkbox checked={ausweis.fenster_dach[1]}>Doppelverglasung</Checkbox> checked={gebaeude
<Checkbox checked={ausweis.fenster_dach[2]}>Isolierverglasung</Checkbox> .einfach_verglasung || false}
<Checkbox checked={ausweis.fenster_dach[3]}>Dreifachverglasung</Checkbox> >
<Checkbox checked={ausweis.fenster_dach[4]}>Alle Fenster dicht</Checkbox> Einfachglas
<Checkbox checked={ausweis.fenster_dach[5]}>Fenster teilweise undicht</Checkbox> </Checkbox>
<Checkbox checked={ausweis.fenster_dach[6]}>Alle Türen dicht</Checkbox> <Checkbox
<Checkbox checked={ausweis.fenster_dach[7]}>Türen teilweise undicht</Checkbox> checked={gebaeude
<Checkbox checked={ausweis.fenster_dach[8]}>Rolladenkästen gedämmt</Checkbox> .doppel_verglasung || false}
>
Doppelverglasung
</Checkbox>
<Checkbox
checked={gebaeude
.isolier_verglasung || false}
>
Isolierverglasung
</Checkbox>
<Checkbox
checked={gebaeude
.dreifach_verglasung || false}
>
Dreifachverglasung
</Checkbox>
<Checkbox
checked={gebaeude.fenster_dicht ||
false}
>
Alle Fenster dicht
</Checkbox>
<Checkbox
checked={gebaeude
.fenster_teilweise_undicht || false}
>
Fenster teilweise undicht
</Checkbox>
<Checkbox
checked={gebaeude.tueren_dicht ||
false}
>
Alle Türen dicht
</Checkbox>
<Checkbox
checked={gebaeude.tueren_undicht ||
false}
>
Türen teilweise undicht
</Checkbox>
<Checkbox
checked={gebaeude
.rolllaeden_kaesten_gedaemmt || false}
>
Rolladenkästen gedämmt
</Checkbox>
</div> </div>
<h3>Wärmedämmung</h3> <h3>Wärmedämmung</h3>
<div class="grid grid-cols-2"> <div class="grid grid-cols-2">
<Checkbox checked={ausweis.daemmung[0]}>Außenwand gedämmt</Checkbox> <Checkbox
<Checkbox checked={ausweis.daemmung[1]}>Kelleraußenwand gedämmt</Checkbox> checked={gebaeude
<Checkbox checked={ausweis.daemmung[2]}>Kellerdecke gedämmt</Checkbox> .aussenwand_gedaemmt || false}
<Checkbox checked={ausweis.daemmung[3]}>Dachgeschoss gedämmt</Checkbox> >
<Checkbox checked={ausweis.daemmung[4]}>Oberste Geschossdecke gedämmt</Checkbox> Außenwand gedämmt
<Checkbox checked={ausweis.daemmung[5]}>Oberste Geschossdecke min. 12cm gedämmt</Checkbox> </Checkbox>
<Checkbox
checked={gebaeude
.keller_wand_gedaemmt || false}
>
Kelleraußenwand gedämmt
</Checkbox>
<Checkbox
checked={gebaeude
.keller_decke_gedaemmt || false}
>
Kellerdecke gedämmt
</Checkbox>
<Checkbox
checked={gebaeude
.dachgeschoss_gedaemmt || false}
>
Dachgeschoss gedämmt
</Checkbox>
<Checkbox
checked={gebaeude
.oberste_geschossdecke_gedaemmt || false}
>
Oberste Geschossdecke gedämmt
</Checkbox>
<Checkbox
checked={gebaeude
.oberste_geschossdecke_min_12cm_gedaemmt || false}
>
Oberste Geschossdecke min. 12cm gedämmt
</Checkbox>
</div> </div>
<Checkbox checked={true}>Die Angaben sind richtig und entsprechen dem aktuellen Stand.</Checkbox> <Checkbox checked={true}>
<Checkbox checked={true}>Ich habe die AGB gelesen und akzeptiert.</Checkbox> Die Angaben sind richtig und entsprechen dem aktuellen
<p>Die Angaben auf diesem Datenblatt wurden uns übermittelt und werden zur Berechnung und Stand.
Ausstellung des Ausweises herangezogen.</p> </Checkbox>
<Checkbox checked={true}>
Ich habe die AGB gelesen und akzeptiert.
</Checkbox>
<p>
Die Angaben auf diesem Datenblatt wurden uns übermittelt und
werden zur Berechnung und Ausstellung des Ausweises
herangezogen.
</p>
</div> </div>
<DatenblattFooter></DatenblattFooter> <DatenblattFooter />
</div> </div>
</div> </div>
</PDFLayout> </PDFLayout>

View File

@@ -1,11 +1,8 @@
--- ---
import { changeLanguage } from "i18next";
import moment from "moment"; import moment from "moment";
import RegisterView from "../modules/RegisterModule.svelte"; import RegisterView from "../modules/RegisterModule.svelte";
import Layout from "../layouts/Layout.astro"; import Layout from "../layouts/Layout.astro";
changeLanguage("de");
const token = Astro.cookies.get("token").value; const token = Astro.cookies.get("token").value;
const expires = Astro.cookies.get("expires").number(); const expires = Astro.cookies.get("expires").number();
const now = moment().unix(); const now = moment().unix();

View File

@@ -1,32 +1,10 @@
--- ---
import UserLayout from "#layouts/UserLayout.astro"; import UserLayout from "#layouts/UserLayout.astro";
import { User } from "#lib/User";
import { tRPCCaller } from "../api/[trpc]";
const token = Astro.cookies.get("token").value;
if (!token) {
Astro.cookies.delete("token");
return Astro.redirect(`/login`);
}
const response = await tRPCCaller(Astro.request).v1.benutzer.tokenValidieren({ token });
if (!response.valid) {
Astro.cookies.delete("token");
return Astro.redirect(`/login`);
}
const user = await User.fromUID(response.uid);
if (!user) {
Astro.cookies.delete("token");
return Astro.redirect(`/login`);
}
--- ---
<UserLayout title="Dashboard"> <UserLayout title="Dashboard">
<h1>Willkommen zurück <b>{user.email}</b></h1> <h1>Willkommen zurück</h1>
<h2>Ihre Ausweise</h2> <h2>Ihre Ausweise</h2>
<div class="grid grid-flow-row grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4"> <div class="grid grid-flow-row grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">

View File

@@ -1,9 +1,9 @@
--- ---
import { changeLanguage } from "i18next";
import AusweisLayout from "#layouts/AusweisLayout.astro"; import AusweisLayout from "#layouts/AusweisLayout.astro";
import VerbrauchsausweisGewerbeContent from "#components/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbeContent.svelte"; import VerbrauchsausweisGewerbeContent from "#components/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbeContent.svelte";
changeLanguage("de");
--- ---
<AusweisLayout title="Verbrauchsausweis Gewerbe erstellen | IBCornelsen"> <AusweisLayout title="Verbrauchsausweis Gewerbe erstellen | IBCornelsen">

View File

@@ -1,9 +1,9 @@
--- ---
import { changeLanguage } from "i18next";
import AusweisLayout from "#layouts/AusweisLayout.astro"; import AusweisLayout from "#layouts/AusweisLayout.astro";
import VerbrauchsausweisWohnenModule from "#modules/Ausweise/VerbrauchsausweisWohnenModule.svelte"; import VerbrauchsausweisWohnenModule from "#modules/Ausweise/VerbrauchsausweisWohnenModule.svelte";
changeLanguage("de");
const uid = Astro.cookies.get("ausweis_uid").value; const uid = Astro.cookies.get("ausweis_uid").value;
--- ---

View File

@@ -31,9 +31,6 @@ body {
} }
.stretch-2 { .stretch-2 {
-ms-grid-row: 1;
-ms-grid-column: 1;
-ms-grid-column-span: 4;
grid-area: 1/1/1/4; grid-area: 1/1/1/4;
} }
@@ -43,9 +40,6 @@ body {
.right-sidebar { .right-sidebar {
display: none; display: none;
-ms-grid-row: 1;
-ms-grid-column: 1;
-ms-grid-column-span: 3;
grid-area: 1/1/1/3; grid-area: 1/1/1/3;
padding-top: 0px; padding-top: 0px;
margin-top: 0px; margin-top: 0px;
@@ -62,7 +56,7 @@ body {
} }
.mainContent a { .mainContent a {
color: #3A4AB5; color: #3a4ab5;
text-decoration: none; text-decoration: none;
display: inline; display: inline;
} }
@@ -78,8 +72,6 @@ body {
text-transform: none; text-transform: none;
} }
footer a { footer a {
display: inline; display: inline;
color: #fff; color: #fff;
@@ -87,7 +79,6 @@ footer a {
font-size: 14px; font-size: 14px;
} }
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/*- Branding: -*/ /*- Branding: -*/
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
@@ -130,12 +121,11 @@ footer a {
} }
.nav-head { .nav-head {
background-color: #444F94; background-color: #444f94;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row; -ms-flex-direction: row;
flex-direction: row; flex-direction: row;
-webkit-box-pack: end; -webkit-box-pack: end;
@@ -156,13 +146,12 @@ footer a {
max-height: 100%; max-height: 100%;
padding-bottom: 0px; padding-bottom: 0px;
padding-top: 0px; padding-top: 0px;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;
align-items: center; align-items: center;
background-color: #444F94; background-color: #444f94;
} }
header a { header a {
@@ -186,31 +175,17 @@ header a {
background-color: #ff7d26; background-color: #ff7d26;
} }
.headerButton.active { .headerButton.active {
background-color: rgb(58, 74, 181); background-color: rgb(58, 74, 181);
} }
/*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/
/*- -*/ /*- -*/
.justify-between { .justify-between {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between; justify-content: space-between;
} }
@@ -225,12 +200,12 @@ header a {
hr { hr {
border: none; border: none;
border-bottom: 1px solid #CECECE; border-bottom: 1px solid #cecece;
margin: 1em 0 1em 0; margin: 1em 0 1em 0;
} }
ul hr { ul hr {
margin: .5em 0 !important; margin: 0.5em 0 !important;
} }
.nopad { .nopad {
@@ -263,9 +238,7 @@ ul hr {
padding: 0; padding: 0;
margin: 0 10px 0 0; margin: 0 10px 0 0;
border-radius: 50%; border-radius: 50%;
vertical-align: middle; box-shadow: 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.24);
-webkit-box-shadow: 0 0 2px rgba(0, 0, 0, .12), 0 2px 4px rgba(0, 0, 0, .24);
box-shadow: 0 0 2px rgba(0, 0, 0, .12), 0 2px 4px rgba(0, 0, 0, .24);
} }
.rplg .rplg-social-logo svg { .rplg .rplg-social-logo svg {
@@ -280,10 +253,8 @@ ul hr {
} }
.rplgsw-wrapper { .rplgsw-wrapper {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
overflow: hidden overflow: hidden;
} }
.rplg-box * { .rplg-box * {
@@ -312,8 +283,6 @@ ul hr {
} }
.rplg-row { .rplg-row {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;
@@ -321,8 +290,6 @@ ul hr {
} }
.rplg-trim { .rplg-trim {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;
@@ -338,7 +305,6 @@ ul hr {
vertical-align: middle; vertical-align: middle;
} }
/* /*
Login - Hausbox Login - Hausbox
@@ -347,8 +313,7 @@ Login - Hausbox
.haus_info_box { .haus_info_box {
width: 100%; width: 100%;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;
@@ -384,8 +349,8 @@ Login - Hausbox
.haus-box { .haus-box {
border-radius: 8px; border-radius: 8px;
-webkit-box-shadow: 0 0 .5em #ccc; -webkit-box-shadow: 0 0 0.5em #ccc;
box-shadow: 0 0 .5em #ccc; box-shadow: 0 0 0.5em #ccc;
width: 300px !important; width: 300px !important;
} }
@@ -408,8 +373,7 @@ Login - Hausbox
.image-box { .image-box {
width: auto; width: auto;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
gap: 10px; gap: 10px;
-webkit-box-align: center; -webkit-box-align: center;
@@ -427,8 +391,8 @@ Login - Hausbox
.ampel-img { .ampel-img {
height: 100px; height: 100px;
width: 35px !important; width: 35px !important;
-webkit-box-shadow: 0 0 .5em #ccc; -webkit-box-shadow: 0 0 0.5em #ccc;
box-shadow: 0 0 .5em #ccc; box-shadow: 0 0 0.5em #ccc;
} }
.haus-content { .haus-content {
@@ -451,8 +415,8 @@ Login - Hausbox
.energieausweis-img { .energieausweis-img {
width: 33%; width: 33%;
-webkit-box-shadow: 0 0 .5em #ccc; -webkit-box-shadow: 0 0 0.5em #ccc;
box-shadow: 0 0 .5em #ccc; box-shadow: 0 0 0.5em #ccc;
} }
.energieausweis-img img { .energieausweis-img img {
@@ -468,15 +432,14 @@ Login - Hausbox
cursor: pointer; cursor: pointer;
font-weight: normal; font-weight: normal;
border-radius: 1em; border-radius: 1em;
-webkit-box-shadow: .1em .1em .2em #bbb; -webkit-box-shadow: 0.1em 0.1em 0.2em #bbb;
box-shadow: .1em .1em .2em #bbb; box-shadow: 0.1em 0.1em 0.2em #bbb;
} }
.kbutton:focus { .kbutton:focus {
background-color: #384da3; background-color: #384da3;
} }
/* /*
Input, textarea styling (forms) Input, textarea styling (forms)
@@ -524,7 +487,7 @@ textarea {
width: -webkit-max-content; width: -webkit-max-content;
width: -moz-max-content; width: -moz-max-content;
width: max-content; width: max-content;
padding: .375rem .75rem; padding: 0.375rem 0.75rem;
border-radius: 4px; border-radius: 4px;
border: none; border: none;
font-size: 1rem; font-size: 1rem;
@@ -554,7 +517,7 @@ textarea {
.caption-text { .caption-text {
font-size: 75%; font-size: 75%;
padding-top: 5px; padding-top: 5px;
opacity: .8; opacity: 0.8;
} }
.image-list img { .image-list img {
@@ -570,15 +533,15 @@ textarea {
width: 1.3em; width: 1.3em;
height: auto; height: auto;
background: none; background: none;
left: -.6em; left: -0.6em;
top: .3em; top: 0.3em;
} }
.kost-tbl { .kost-tbl {
width: 100%; width: 100%;
margin: 0 0 2em 0; margin: 0 0 2em 0;
-webkit-box-shadow: .2em .2em .4em #ccc; -webkit-box-shadow: 0.2em 0.2em 0.4em #ccc;
box-shadow: .2em .2em .4em #ccc; box-shadow: 0.2em 0.2em 0.4em #ccc;
} }
.haus_ul1, .haus_ul1,
@@ -592,7 +555,7 @@ textarea {
.haus_ul2 li { .haus_ul2 li {
position: relative; position: relative;
font-size: 1.1em; font-size: 1.1em;
padding: .3em .3em .3em 1.3em; padding: 0.3em 0.3em 0.3em 1.3em;
} }
.haus_ul1 li::before { .haus_ul1 li::before {
@@ -604,8 +567,8 @@ textarea {
width: 1.3em; width: 1.3em;
height: auto; height: auto;
background: none; background: none;
left: -.6em; left: -0.6em;
top: .3em; top: 0.3em;
} }
.kost-tbl thead td { .kost-tbl thead td {
@@ -631,8 +594,6 @@ table {
grid-gap: 20px; grid-gap: 20px;
} }
.start_infobox_img { .start_infobox_img {
float: right; float: right;
width: 23% !important; width: 23% !important;
@@ -653,23 +614,23 @@ table {
.start_infobox_button a:hover { .start_infobox_button a:hover {
background-color: #ff7d26; background-color: #ff7d26;
color: #fff !important; color: #fff !important;
padding: .15em 1em .15em 1em; padding: 0.15em 1em 0.15em 1em;
border-radius: .8em; border-radius: 0.8em;
font-size: 1.3em; font-size: 1.3em;
font-weight: 600; font-weight: 600;
-webkit-box-shadow: .1em .1em .2em #bbb; -webkit-box-shadow: 0.1em 0.1em 0.2em #bbb;
box-shadow: .1em .1em .2em #bbb; box-shadow: 0.1em 0.1em 0.2em #bbb;
} }
.start_infobox_button a { .start_infobox_button a {
background-color: #3a4ab5; background-color: #3a4ab5;
color: #fff !important; color: #fff !important;
padding: .2em 1em .2em 1em; padding: 0.2em 1em 0.2em 1em;
border-radius: .8em; border-radius: 0.8em;
font-size: 1.3em; font-size: 1.3em;
font-weight: 600; font-weight: 600;
-webkit-box-shadow: .1em .1em .2em #bbb; -webkit-box-shadow: 0.1em 0.1em 0.2em #bbb;
box-shadow: .1em .1em .2em #bbb; box-shadow: 0.1em 0.1em 0.2em #bbb;
} }
.start_infobox_button { .start_infobox_button {
@@ -682,8 +643,8 @@ table {
margin: 2em auto; margin: 2em auto;
border: 2px dotted #ff7d26; border: 2px dotted #ff7d26;
border-radius: 1em; border-radius: 1em;
-webkit-box-shadow: 0 0 .5em #ccc; -webkit-box-shadow: 0 0 0.5em #ccc;
box-shadow: 0 0 .5em #ccc; box-shadow: 0 0 0.5em #ccc;
} }
.start_infobox ul li::before { .start_infobox ul li::before {
@@ -694,7 +655,7 @@ table {
height: 7px; height: 7px;
background-color: #ddd; background-color: #ddd;
position: absolute; position: absolute;
border-radius: .1em; border-radius: 0.1em;
} }
.start_infobox .title, .start_infobox .title,
@@ -702,7 +663,7 @@ table {
color: #ff7d26 !important; color: #ff7d26 !important;
margin: 0; margin: 0;
font-size: 1.4em; font-size: 1.4em;
margin-bottom: -.3em; margin-bottom: -0.3em;
position: relative; position: relative;
} }
@@ -728,7 +689,7 @@ table {
.pdf { .pdf {
position: relative; position: relative;
padding: 0 0 .5em 3.5em; padding: 0 0 0.5em 3.5em;
text-align: left !important; text-align: left !important;
} }
@@ -742,9 +703,9 @@ table {
.bedarfsausweis-wohngebaeude-beispiel, .bedarfsausweis-wohngebaeude-beispiel,
.verbrauchsausweis-wohngebaeude-beispiel { .verbrauchsausweis-wohngebaeude-beispiel {
width: 100%; width: 100%;
margin: 0 .5% 2em .5%; margin: 0 0.5% 2em 0.5%;
font-size: 1.1em; font-size: 1.1em;
padding: .5em .5%; padding: 0.5em 0.5%;
float: left; float: left;
text-align: center; text-align: center;
border-top-left-radius: 1em; border-top-left-radius: 1em;
@@ -762,9 +723,9 @@ table {
.buynow-btn { .buynow-btn {
background-color: #4251a3; background-color: #4251a3;
border-radius: 1em; border-radius: 1em;
padding: .2em 1em; padding: 0.2em 1em;
-webkit-box-shadow: .1em .1em .2em #bbb; -webkit-box-shadow: 0.1em 0.1em 0.2em #bbb;
box-shadow: .1em .1em .2em #bbb; box-shadow: 0.1em 0.1em 0.2em #bbb;
white-space: nowrap; white-space: nowrap;
border: 2px solid #fff; border: 2px solid #fff;
color: #fff !important; color: #fff !important;
@@ -774,13 +735,11 @@ table {
.buynow-btn:hover { .buynow-btn:hover {
background-color: #ff7d26; background-color: #ff7d26;
-webkit-box-shadow: .1em .1em .2em #bbb; -webkit-box-shadow: 0.1em 0.1em 0.2em #bbb;
box-shadow: .1em .1em .2em #bbb; box-shadow: 0.1em 0.1em 0.2em #bbb;
white-space: nowrap; white-space: nowrap;
} }
.row * { .row * {
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
@@ -800,9 +759,6 @@ table {
} }
.row { .row {
display: -ms-flexbox;
display: -webkit-box;
display: flex; display: flex;
-ms-flex-wrap: wrap; -ms-flex-wrap: wrap;
flex-wrap: wrap; flex-wrap: wrap;
@@ -811,18 +767,14 @@ table {
} }
.flex-row { .flex-row {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row; -ms-flex-direction: row;
flex-direction: row; flex-direction: row;
} }
.align-center { .align-center {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;
@@ -833,16 +785,11 @@ table {
} }
.flex-column { .flex-column {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column; flex-direction: column;
} }
block { block {
display: block; display: block;
position: relative; position: relative;
@@ -870,14 +817,9 @@ cbutton {
width: -moz-min-content; width: -moz-min-content;
width: min-content; width: min-content;
cursor: pointer; cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
} }
:root { :root {
--theme-primary: #fff; --theme-primary: #fff;
--theme-orange: rgb(255, 125, 38); --theme-orange: rgb(255, 125, 38);
@@ -886,19 +828,17 @@ cbutton {
--std-font: Abel, Roboto, sand-serif; --std-font: Abel, Roboto, sand-serif;
} }
.section_1 > *:nth-child(1) {
.section_1>*:nth-child(1) {
-ms-grid-row: 1; -ms-grid-row: 1;
-ms-grid-column: 1; -ms-grid-column: 1;
} }
.section_1>*:nth-child(2) { .section_1 > *:nth-child(2) {
-ms-grid-row: 1; -ms-grid-row: 1;
-ms-grid-column: 2; -ms-grid-column: 2;
} }
.section_1>*:nth-child(3) { .section_1 > *:nth-child(3) {
-ms-grid-row: 1; -ms-grid-row: 1;
-ms-grid-column: 3; -ms-grid-column: 3;
} }
@@ -936,18 +876,9 @@ cbutton {
} }
.block_4 { .block_4 {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column; flex-direction: column;
-webkit-box-align: start; align-items: flex-start;
-ms-flex-align: start;
align-items: start;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between; justify-content: space-between;
width: inherit; width: inherit;
padding: 0px; padding: 0px;
@@ -955,21 +886,16 @@ cbutton {
} }
.block_5 { .block_5 {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row; flex-direction: row;
width: 100%; width: 100%;
padding: 0px; padding: 0px;
margin: 0px; margin: 0px;
-webkit-box-align: start;
-ms-flex-align: start; align-items: flex-start;
align-items: start;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between; justify-content: space-between;
} }
@@ -1064,26 +990,22 @@ content {
margin: 10px auto; margin: 10px auto;
display: -ms-grid; display: -ms-grid;
display: grid; display: grid;
-webkit-column-gap: 20px;
-moz-column-gap: 20px;
column-gap: 20px; column-gap: 20px;
-ms-grid-columns: 2fr 20px 6fr 20px 2fr;
grid-template-columns: 2fr 6fr 2fr; grid-template-columns: 2fr 6fr 2fr;
-ms-grid-rows: auto;
grid-template-rows: auto; grid-template-rows: auto;
} }
content>*:nth-child(1) { content > *:nth-child(1) {
-ms-grid-row: 1; -ms-grid-row: 1;
-ms-grid-column: 1; -ms-grid-column: 1;
} }
content>*:nth-child(2) { content > *:nth-child(2) {
-ms-grid-row: 1; -ms-grid-row: 1;
-ms-grid-column: 3; -ms-grid-column: 3;
} }
content>*:nth-child(3) { content > *:nth-child(3) {
-ms-grid-row: 1; -ms-grid-row: 1;
-ms-grid-column: 5; -ms-grid-column: 5;
} }
@@ -1093,7 +1015,6 @@ content>*:nth-child(3) {
margin-bottom: 0; margin-bottom: 0;
} }
.rpt_plan img { .rpt_plan img {
width: 50%; width: 50%;
margin: 15px auto; margin: 15px auto;
@@ -1107,20 +1028,17 @@ content>*:nth-child(3) {
text-align: center; text-align: center;
font-weight: bold; font-weight: bold;
line-height: 1.2em; line-height: 1.2em;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
padding: 14px 18px; padding: 14px 18px;
background: #4251a3; background: #4251a3;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column; flex-direction: column;
-webkit-box-pack: center; -webkit-box-pack: center;
-ms-flex-pack: center; -ms-flex-pack: center;
justify-content: center; justify-content: center;
border-top-left-radius: .4em; border-top-left-radius: 0.4em;
border-top-right-radius: .4em; border-top-right-radius: 0.4em;
margin-bottom: 0; margin-bottom: 0;
} }
@@ -1128,10 +1046,10 @@ content>*:nth-child(3) {
padding: 6px 10px; padding: 6px 10px;
text-align: center; text-align: center;
color: #fff; color: #fff;
text-shadow: 1px 2px 7px rgba(0, 0, 0, .6); text-shadow: 1px 2px 7px rgba(0, 0, 0, 0.6);
font-size: 5em; font-size: 5em;
font-weight: bold; font-weight: bold;
padding-bottom: .2em; padding-bottom: 0.2em;
margin-bottom: 0; margin-bottom: 0;
} }
@@ -1206,17 +1124,12 @@ content>*:nth-child(3) {
width: 100%; width: 100%;
min-width: 152px; min-width: 152px;
@apply border shadow-md; @apply border shadow-md;
border-radius: .4em; border-radius: 0.4em;
background: #f5f5f5; background: #f5f5f5;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column; flex-direction: column;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center; align-items: center;
} }
@@ -1229,7 +1142,7 @@ content>*:nth-child(3) {
height: 7px; height: 7px;
background-color: #ddd; background-color: #ddd;
position: absolute; position: absolute;
border-radius: .1em; border-radius: 0.1em;
} }
.widget_nav ul li { .widget_nav ul li {
@@ -1262,12 +1175,11 @@ content>*:nth-child(3) {
.large-button { .large-button {
background: #3a4ab5; background: #3a4ab5;
color: #fff; color: #fff;
padding: .2em 1em .2em 1em; padding: 0.2em 1em 0.2em 1em;
border-radius: .8em; border-radius: 0.8em;
font-size: 1em; font-size: 1em;
font-weight: 600; font-weight: 600;
text-decoration: none; text-decoration: none;
-webkit-box-shadow: 0.1em 0.1em 0.2em #bbb;
box-shadow: 0.1em 0.1em 0.2em #bbb; box-shadow: 0.1em 0.1em 0.2em #bbb;
margin-top: 10px; margin-top: 10px;
white-space: nowrap; white-space: nowrap;
@@ -1305,7 +1217,7 @@ ul li {
} }
ul li::before { ul li::before {
content: ''; content: "";
width: 10px; width: 10px;
height: 10px; height: 10px;
left: 0; left: 0;
@@ -1313,7 +1225,7 @@ ul li::before {
margin-left: 0; margin-left: 0;
background: #ff7d26; background: #ff7d26;
position: absolute; position: absolute;
border-radius: .1em; border-radius: 0.1em;
} }
.img-subtitle { .img-subtitle {
@@ -1323,18 +1235,13 @@ ul li::before {
text-align: center; text-align: center;
} }
footer { footer {
background: rgb(255, 125, 38); background: rgb(255, 125, 38);
height: 40px; height: 40px;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between; justify-content: space-between;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center; align-items: center;
padding: 0 30px; padding: 0 30px;
width: auto; width: auto;
@@ -1344,17 +1251,10 @@ footer {
} }
#pwtester { #pwtester {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
width: 100%; width: 100%;
margin: 10px 0 0 0; margin: 10px 0 0 0;
-webkit-box-pack: space-evenly;
-ms-flex-pack: space-evenly;
justify-content: space-evenly; justify-content: space-evenly;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row; flex-direction: row;
} }
@@ -1363,17 +1263,14 @@ footer {
width: 24%; width: 24%;
height: 4px; height: 4px;
border-radius: 4px; border-radius: 4px;
background: #B7B7B7; background: #b7b7b7;
} }
.objekt_card { .objekt_card {
display: -ms-grid; display: -ms-grid;
display: grid; display: grid;
-ms-grid-columns: 1fr 1fr;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
-ms-grid-rows: 375px 5px 125px;
grid-template-rows: 375px 125px; grid-template-rows: 375px 125px;
-webkit-box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px; box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
background: #fff; background: #fff;
margin: 0 auto; margin: 0 auto;
@@ -1383,30 +1280,27 @@ footer {
grid-row-gap: 5px; grid-row-gap: 5px;
max-width: 1100px; max-width: 1100px;
position: relative; position: relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
margin-bottom: 30px; margin-bottom: 30px;
} }
.objekt_card>*:nth-child(1) { .objekt_card > *:nth-child(1) {
-ms-grid-row: 1; -ms-grid-row: 1;
-ms-grid-column: 1; -ms-grid-column: 1;
} }
.objekt_card>*:nth-child(2) { .objekt_card > *:nth-child(2) {
-ms-grid-row: 1; -ms-grid-row: 1;
-ms-grid-column: 2; -ms-grid-column: 2;
} }
.objekt_card>*:nth-child(3) { .objekt_card > *:nth-child(3) {
-ms-grid-row: 3; -ms-grid-row: 3;
-ms-grid-column: 1; -ms-grid-column: 1;
} }
.objekt_card>*:nth-child(4) { .objekt_card > *:nth-child(4) {
-ms-grid-row: 3; -ms-grid-row: 3;
-ms-grid-column: 2; -ms-grid-column: 2;
} }
@@ -1432,8 +1326,7 @@ body .objekt_card:first-of-type {
.objekt_previewImage { .objekt_previewImage {
-o-object-fit: contain; -o-object-fit: contain;
object-fit: contain; object-fit: contain;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
} }
@@ -1462,22 +1355,14 @@ body .objekt_card:first-of-type {
.objekt_makler { .objekt_makler {
margin: 0 20px 20px 20px; margin: 0 20px 20px 20px;
padding-left: 20px; padding-left: 20px;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center; align-items: center;
border-top: 1px solid rgb(223, 223, 223); border-top: 1px solid rgb(223, 223, 223);
} }
.objekt_images { .objekt_images {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row; flex-direction: row;
border-bottom-left-radius: 5px; border-bottom-left-radius: 5px;
} }
@@ -1494,12 +1379,8 @@ body .objekt_card:first-of-type {
/* NOTE MAKLER SYSTEM */ /* NOTE MAKLER SYSTEM */
.card_container { .card_container {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column; flex-direction: column;
} }
@@ -1513,8 +1394,6 @@ body .objekt_card:first-of-type {
} }
.justify_left { .justify_left {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
} }
@@ -1563,10 +1442,8 @@ body .objekt_card:first-of-type {
height: 100%; height: 100%;
display: -ms-grid; display: -ms-grid;
display: grid; display: grid;
grid-template-areas: "main detail""main info"; grid-template-areas: "main detail" "main info";
-ms-grid-columns: 3.8fr 20px 1.2fr;
grid-template-columns: 3.8fr 1.2fr; grid-template-columns: 3.8fr 1.2fr;
-ms-grid-rows: 250px 20px auto;
grid-template-rows: 250px auto; grid-template-rows: 250px auto;
grid-gap: 20px; grid-gap: 20px;
} }
@@ -1583,7 +1460,6 @@ body .objekt_card:first-of-type {
.text_container { .text_container {
-ms-grid-row: 1; -ms-grid-row: 1;
-ms-grid-row-span: 3;
-ms-grid-column: 1; -ms-grid-column: 1;
grid-area: main; grid-area: main;
background: #fff; background: #fff;
@@ -1606,18 +1482,11 @@ body .objekt_card:first-of-type {
} }
.image_slideshow { .image_slideshow {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row; flex-direction: row;
margin-right: 10px; margin-right: 10px;
gap: 10px; gap: 10px;
overflow: hidden; overflow: hidden;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center; justify-content: center;
--image-width: 1200px; --image-width: 1200px;
--image-margin: 6px; --image-margin: 6px;
@@ -1630,31 +1499,20 @@ body .objekt_card:first-of-type {
.image_slideshow img { .image_slideshow img {
width: 1200px; width: 1200px;
height: 500px; height: 500px;
-o-object-fit: cover;
object-fit: cover; object-fit: cover;
border-radius: 8px; border-radius: 8px;
-webkit-transition: all .4s ease; transition: all 0.4s ease;
-o-transition: all .4s ease;
transition: all .4s ease;
-webkit-box-shadow: 1px 1px 2px 1px rgba(24, 24, 24, 0.178);
box-shadow: 1px 1px 2px 1px rgba(24, 24, 24, 0.178); box-shadow: 1px 1px 2px 1px rgba(24, 24, 24, 0.178);
} }
.image_slideshow .control_wrapper { .image_slideshow .control_wrapper {
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
position: absolute; position: absolute;
width: calc(1200px + 60px); width: calc(1200px + 60px);
height: 500px; height: 500px;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center; align-items: center;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between; justify-content: space-between;
-webkit-transition: all 0.4s ease;
-o-transition: all 0.4s ease;
transition: all 0.4s ease; transition: all 0.4s ease;
} }
@@ -1662,9 +1520,6 @@ body .objekt_card:first-of-type {
position: relative; position: relative;
width: 1200px; width: 1200px;
height: 530px; height: 530px;
/*margin: 0 6px;*/
-webkit-transition: all 0.4s ease;
-o-transition: all 0.4s ease;
transition: all 0.4s ease; transition: all 0.4s ease;
} }
@@ -1679,21 +1534,13 @@ body .objekt_card:first-of-type {
border-radius: 50%; border-radius: 50%;
height: 16px; height: 16px;
width: 16px; width: 16px;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center; align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center; justify-content: center;
color: #000; color: #000;
-webkit-transition: all .3s ease; transition: all 0.3s ease;
-o-transition: all .3s ease;
transition: all .3s ease;
cursor: pointer; cursor: pointer;
-webkit-box-shadow: 1px 1px 2px 1px rgba(24, 24, 24, 0.178);
box-shadow: 1px 1px 2px 1px rgba(24, 24, 24, 0.178); box-shadow: 1px 1px 2px 1px rgba(24, 24, 24, 0.178);
} }
@@ -1711,12 +1558,11 @@ body .objekt_card:first-of-type {
-ms-grid-columns: 2fr 20px 1fr; -ms-grid-columns: 2fr 20px 1fr;
grid-template-columns: 2fr 1fr; grid-template-columns: 2fr 1fr;
grid-gap: 20px; grid-gap: 20px;
-ms-grid-rows: auto;
grid-template-rows: auto; grid-template-rows: auto;
grid-template-areas: "profile_info menu_buttons"". menu_buttons"; grid-template-areas: "profile_info menu_buttons" ". menu_buttons";
} }
.profile_container>div { .profile_container > div {
border-radius: 8px; border-radius: 8px;
width: 100%; width: 100%;
min-height: 100px; min-height: 100px;
@@ -1725,9 +1571,8 @@ body .objekt_card:first-of-type {
.span-2 { .span-2 {
-ms-grid-row: 1; -ms-grid-row: 1;
-ms-grid-row-span: 2;
-ms-grid-column: 1; -ms-grid-column: 1;
grid-area: 1/1/span 2 / 1; grid-area: 1/1 / span 2 / 1;
} }
.slim { .slim {
@@ -1803,7 +1648,6 @@ body .objekt_card:first-of-type {
display: none; display: none;
} }
.login-container { .login-container {
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
} }

View File

@@ -127,11 +127,11 @@
.nav-head { .nav-head {
background-color: rgb(255, 125, 38); background-color: rgb(255, 125, 38);
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-orient: horizontal; -webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row; -ms-flex-direction: row;
flex-direction: row; flex-direction: row;
-webkit-box-pack: end; -webkit-box-pack: end;
@@ -154,8 +154,8 @@
max-height: 100%; max-height: 100%;
padding-bottom: 0px; padding-bottom: 0px;
padding-top: 0px; padding-top: 0px;
display: -webkit-box;
display: -ms-flexbox;
display: flex; display: flex;
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;

View File

@@ -1,14 +1,14 @@
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client'; import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import cookies from 'js-cookie'; import cookies from 'js-cookie';
import type { AppRouter } from 'src/pages/api/[trpc]'; import type { AppRouter } from '@ibcornelsen/api';
export const client = createTRPCProxyClient<AppRouter>({ export const client = createTRPCProxyClient<AppRouter>({
links: [ links: [
httpBatchLink({ httpBatchLink({
url: 'http://localhost:3000/api', url: 'http://localhost:3001/',
headers() { headers() {
return { return {
'Authorization': `Bearer ${cookies.get('uid')}`, 'Authorization': `Bearer ${cookies.get('accessToken')}`,
}; };
}, },
}), }),

10
test.ts
View File

@@ -1,10 +0,0 @@
import { AppRouter } from "src/pages/api/[trpc]"
import { createOpenApiExpressMiddleware } from "trpc-openapi"
import express from 'express';
const app = express();
app.use(createOpenApiExpressMiddleware({ router: AppRouter }));
app.listen(5555);
console.log("Server listening on port 80");