Notifications + Plausibilitätsprüfung
This commit is contained in:
@@ -2,9 +2,16 @@
|
||||
import { Verbrauchsausweis } from "src/lib/Ausweis/Verbrauchsausweis";
|
||||
import { Gebaeude } from "src/lib/Gebaeude";
|
||||
import HelpLabel from "~/components/HelpLabel.svelte";
|
||||
import { auditHeizungGebaeudeBaujahr } from "../Verbrauchsausweis/audits/HeizungGebaeudeBaujahr";
|
||||
import { addNotification, deleteNotification } from "../Notifications/shared";
|
||||
import TagInput from "../TagInput.svelte";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
export let gebaeude: Gebaeude;
|
||||
|
||||
// TODO: Das ist scheise
|
||||
let tags = writable([]);
|
||||
|
||||
$: ausweis = gebaeude.ausweis || new Verbrauchsausweis();
|
||||
</script>
|
||||
|
||||
@@ -71,11 +78,27 @@
|
||||
/>z.B. 1994-2001.
|
||||
</HelpLabel>
|
||||
<div>
|
||||
<input
|
||||
<TagInput
|
||||
name="IGheizung"
|
||||
type="number"
|
||||
onlyUnique={true}
|
||||
onFocusIn={() => {
|
||||
addNotification({
|
||||
message: "Info",
|
||||
subtext: "Wussten sie, dass sie mehrere Jahre angeben können in denen z.B. Renovierungen an ihrer Heizung durchgeführt wurden. Drücken sie dafür einfach <kbd>Enter</kbd> oder <kbd>Space</kbd> nach jedem Jahr.",
|
||||
dismissable: true,
|
||||
uid: "HEIZUNG_BAUJAHR",
|
||||
timeout: 0,
|
||||
type: "info"
|
||||
});
|
||||
}}
|
||||
onFocusOut={() => {
|
||||
deleteNotification("HEIZUNG_BAUJAHR")
|
||||
}}
|
||||
className="{auditHeizungGebaeudeBaujahr(gebaeude) ? "linked" : ""}"
|
||||
required
|
||||
bind:value={ausweis.baujahr_anlage}
|
||||
autocomplete="off"
|
||||
bind:tags
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -92,12 +115,27 @@
|
||||
-saniert- angeben.
|
||||
</HelpLabel>
|
||||
<div>
|
||||
<input
|
||||
<TagInput
|
||||
name="IGbaujahr"
|
||||
type="number"
|
||||
onlyUnique={true}
|
||||
onFocusIn={() => {
|
||||
addNotification({
|
||||
message: "Info",
|
||||
subtext: "Wussten sie, dass sie mehrere Jahre angeben können in denen z.B. Renovierungen an ihrem Gebäude durchgeführt wurden. Drücken sie dafür einfach <kbd>Enter</kbd> oder <kbd>Space</kbd> nach jedem Jahr.",
|
||||
dismissable: true,
|
||||
uid: "GEBAEUDE_BAUJAHR",
|
||||
timeout: 0,
|
||||
type: "info"
|
||||
});
|
||||
}}
|
||||
onFocusOut={() => {
|
||||
deleteNotification("GEBAEUDE_BAUJAHR")
|
||||
}}
|
||||
className="{auditHeizungGebaeudeBaujahr(gebaeude) ? "linked" : ""}"
|
||||
required
|
||||
autocomplete="off"
|
||||
bind:value={gebaeude.baujahr}
|
||||
bind:tags
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
import Label from "../Label.svelte";
|
||||
import fuelList from "./fuelList";
|
||||
import { Verbrauchsausweis } from "src/lib/Ausweis/Verbrauchsausweis";
|
||||
import { VerbrauchsausweisGewerbe } from "src/lib/Ausweis/VerbrauchsausweisGewerbe";
|
||||
import { Bedarfsausweis } from "src/lib/Ausweis/Bedarfsausweis";
|
||||
import { Gebaeude } from "src/lib/Gebaeude";
|
||||
import { auditVerbrauchAbweichung } from "../Verbrauchsausweis/audits/VerbrauchAbweichung";
|
||||
|
||||
let availableYears = [
|
||||
2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
||||
2018, 2019,
|
||||
];
|
||||
let availableMonths = [
|
||||
"Januar",
|
||||
@@ -25,7 +25,7 @@
|
||||
"Dezember",
|
||||
];
|
||||
|
||||
export let ausweis: Verbrauchsausweis |VerbrauchsausweisGewerbe | Bedarfsausweis;
|
||||
export let gebaeude: Gebaeude;
|
||||
|
||||
const fuelMap: Record<string, string[]> = {};
|
||||
for (const fuel of fuelList) {
|
||||
@@ -37,11 +37,15 @@
|
||||
let month: string = "01";
|
||||
let year: string = "2018";
|
||||
|
||||
$: ausweis = gebaeude.ausweis || new Verbrauchsausweis();
|
||||
|
||||
$: {
|
||||
if (month && year) {
|
||||
ausweis.energieverbrauch_zeitraum = moment(`${month}.01.${year}`);
|
||||
ausweis.kennwerte.zeitraum = moment(`${month}.01.${year}`);
|
||||
}
|
||||
}
|
||||
|
||||
$: abweichung = auditVerbrauchAbweichung(gebaeude);
|
||||
</script>
|
||||
|
||||
<div class="w-full flex flex-col gap-4">
|
||||
@@ -56,7 +60,7 @@
|
||||
<input
|
||||
type="checkbox"
|
||||
class="IGzus1verbrauch1"
|
||||
bind:checked={ausweis.zusaetzliche_heizquelle}
|
||||
bind:checked={ausweis.kennwerte.zusaetzliche_heizquelle}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -88,7 +92,7 @@
|
||||
<b>Koks:</b> Stark kohlenstoffhaltiger Brennstoff.<br /><br />
|
||||
</HelpLabel>
|
||||
<div>
|
||||
<select name="energietraeger_1" required bind:value={ausweis.energietraeger_1}>
|
||||
<select name="energietraeger_1" required bind:value={ausweis.kennwerte.energietraeger_1}>
|
||||
<option>Bitte auswählen</option>
|
||||
{#each Object.keys(fuelMap) as fuel}
|
||||
<option value={fuel}>{fuel}</option>
|
||||
@@ -107,10 +111,10 @@
|
||||
<select
|
||||
name="energietraeger_einheit_heizquelle_1"
|
||||
required
|
||||
bind:value={ausweis.energietraeger_einheit_heizquelle_1}
|
||||
bind:value={ausweis.kennwerte.einheit_1}
|
||||
>
|
||||
<option>Bitte auswählen</option>
|
||||
{#each (fuelMap.hasOwnProperty(ausweis.energietraeger_1) ? fuelMap[ausweis.energietraeger_1] : []) as unit}
|
||||
{#each (fuelMap.hasOwnProperty(ausweis.kennwerte.energietraeger_1) ? fuelMap[ausweis.kennwerte.energietraeger_1] : []) as unit}
|
||||
<option value={unit}>{unit}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -122,8 +126,8 @@
|
||||
<div>
|
||||
<select
|
||||
name="energietraeger_2"
|
||||
bind:value={ausweis.energietraeger_2}
|
||||
disabled={!ausweis.zusaetzliche_heizquelle}
|
||||
bind:value={ausweis.kennwerte.energietraeger_2}
|
||||
disabled={!ausweis.kennwerte.zusaetzliche_heizquelle}
|
||||
required
|
||||
>
|
||||
<option> Bitte auswählen</option>
|
||||
@@ -139,12 +143,12 @@
|
||||
<div>
|
||||
<select
|
||||
name="energietraeger_einheit_heizquelle_2"
|
||||
disabled={!ausweis.zusaetzliche_heizquelle}
|
||||
bind:value={ausweis.energietraeger_einheit_heizquelle_2}
|
||||
disabled={!ausweis.kennwerte.zusaetzliche_heizquelle}
|
||||
bind:value={ausweis.kennwerte.einheit_2}
|
||||
required
|
||||
>
|
||||
<option>Bitte auswählen</option>
|
||||
{#each (fuelMap.hasOwnProperty(ausweis.energietraeger_2) ? fuelMap[ausweis.energietraeger_2] : []) as unit}
|
||||
{#each (fuelMap.hasOwnProperty(ausweis.kennwerte.energietraeger_2) ? fuelMap[ausweis.kennwerte.energietraeger_2] : []) as unit}
|
||||
<option value={unit}>{unit}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -184,7 +188,7 @@
|
||||
<span>von</span>
|
||||
<input
|
||||
class="klima"
|
||||
value={moment(ausweis.energieverbrauch_zeitraum)
|
||||
value={moment(ausweis.kennwerte.zeitraum)
|
||||
.add("1", "year")
|
||||
.format("MM.Y")}
|
||||
readonly
|
||||
@@ -194,7 +198,7 @@
|
||||
<span>von</span>
|
||||
<input
|
||||
class="klima"
|
||||
value={moment(ausweis.energieverbrauch_zeitraum)
|
||||
value={moment(ausweis.kennwerte.zeitraum)
|
||||
.add("2", "years")
|
||||
.format("MM.Y")}
|
||||
readonly
|
||||
@@ -206,7 +210,7 @@
|
||||
<span>bis</span>
|
||||
<input
|
||||
class=""
|
||||
value={moment(ausweis.energieverbrauch_zeitraum)
|
||||
value={moment(ausweis.kennwerte.zeitraum)
|
||||
.add("1", "year")
|
||||
.format("MM.Y")}
|
||||
readonly
|
||||
@@ -216,7 +220,7 @@
|
||||
<span>bis</span>
|
||||
<input
|
||||
class=""
|
||||
value={moment(ausweis.energieverbrauch_zeitraum)
|
||||
value={moment(ausweis.kennwerte.zeitraum)
|
||||
.add("2", "years")
|
||||
.format("MM.Y")}
|
||||
readonly
|
||||
@@ -226,7 +230,7 @@
|
||||
<span>bis</span>
|
||||
<input
|
||||
class=""
|
||||
value={moment(ausweis.energieverbrauch_zeitraum)
|
||||
value={moment(ausweis.kennwerte.zeitraum)
|
||||
.add("3", "years")
|
||||
.format("MM.Y")}
|
||||
readonly
|
||||
@@ -239,7 +243,8 @@
|
||||
<input
|
||||
name="energieverbrauch_1_heizquelle_1"
|
||||
type="number"
|
||||
bind:value={ausweis.energieverbrauch_1_heizquelle_1}
|
||||
class:linked={abweichung.indexOf(1) > -1}
|
||||
bind:value={ausweis.kennwerte.verbrauch_1}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
@@ -248,7 +253,8 @@
|
||||
<input
|
||||
name="energieverbrauch_2_heizquelle_1"
|
||||
type="number"
|
||||
bind:value={ausweis.energieverbrauch_2_heizquelle_1}
|
||||
class:linked={abweichung.indexOf(2) > -1}
|
||||
bind:value={ausweis.kennwerte.verbrauch_2}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
@@ -257,7 +263,8 @@
|
||||
<input
|
||||
name="energieverbrauch_3_heizquelle_1"
|
||||
type="number"
|
||||
bind:value={ausweis.energieverbrauch_3_heizquelle_1}
|
||||
class:linked={abweichung.indexOf(3) > -1}
|
||||
bind:value={ausweis.kennwerte.verbrauch_3}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
@@ -268,8 +275,9 @@
|
||||
<input
|
||||
name="energieverbrauch_1_heizquelle_2"
|
||||
type="number"
|
||||
bind:value={ausweis.energieverbrauch_1_heizquelle_2}
|
||||
disabled={!ausweis.zusaetzliche_heizquelle}
|
||||
bind:value={ausweis.kennwerte.verbrauch_4}
|
||||
class:linked={abweichung.indexOf(4) > -1}
|
||||
disabled={!ausweis.kennwerte.zusaetzliche_heizquelle}
|
||||
/>
|
||||
</div>
|
||||
<div class="column">
|
||||
@@ -277,8 +285,9 @@
|
||||
<input
|
||||
name="energieverbrauch_2_heizquelle_2"
|
||||
type="number"
|
||||
bind:value={ausweis.energieverbrauch_2_heizquelle_2}
|
||||
disabled={!ausweis.zusaetzliche_heizquelle}
|
||||
bind:value={ausweis.kennwerte.verbrauch_5}
|
||||
class:linked={abweichung.indexOf(5) > -1}
|
||||
disabled={!ausweis.kennwerte.zusaetzliche_heizquelle}
|
||||
/>
|
||||
</div>
|
||||
<div class="column">
|
||||
@@ -286,8 +295,9 @@
|
||||
<input
|
||||
name="energieverbrauch_3_heizquelle_2"
|
||||
type="number"
|
||||
bind:value={ausweis.energieverbrauch_3_heizquelle_2}
|
||||
disabled={!ausweis.zusaetzliche_heizquelle}
|
||||
bind:value={ausweis.kennwerte.verbrauch_6}
|
||||
class:linked={abweichung.indexOf(6) > -1}
|
||||
disabled={!ausweis.kennwerte.zusaetzliche_heizquelle}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,8 +18,8 @@ const loggedIn = isLoggedIn(Astro);
|
||||
alt="IBCornelsen - Logo"
|
||||
onclick="window.location.href = '/'"
|
||||
/>
|
||||
<h2 class="MajorHeading">Energieausweis online erstellen</h2>
|
||||
<h2 class="MajorHeading smaller">Energieausweise nach aktueller GEG</h2>
|
||||
<h2 class="text-secondary font-semibold text-2xl absolute top-8 right-0">Energieausweis online erstellen</h2>
|
||||
<h2 class="text-primary font-semibold text-xl absolute top-16 right-0">Energieausweise nach aktueller GEG</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script lang="ts">
|
||||
import cookie from "cookiejs";
|
||||
import { addNotification } from "./Notifications/shared";
|
||||
|
||||
let email: string;
|
||||
let password: string;
|
||||
let hasError: boolean;
|
||||
|
||||
async function login() {
|
||||
const response = await fetch("/api/login", {
|
||||
@@ -23,8 +23,14 @@
|
||||
localStorage.setItem("expires", json.data.expires);
|
||||
window.location.href = "/user";
|
||||
} else {
|
||||
hasError = true;
|
||||
setTimeout(() => (hasError = false), 3000);
|
||||
|
||||
addNotification({
|
||||
message: "Ups...",
|
||||
subtext: "Das hat leider nicht geklappt, haben sie ihr Passwort und ihre Email Adresse richtig eingegeben?",
|
||||
type: "error",
|
||||
timeout: 6000,
|
||||
dismissable: true
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -52,13 +58,7 @@
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button on:click={login}>Einloggen</button>
|
||||
{#if hasError}
|
||||
<p>
|
||||
Das hat leider nicht geklappt, haben sie ihr Passwort und den
|
||||
Nutzernamen richtig eingegeben?
|
||||
</p>
|
||||
{/if}
|
||||
<button class="button" on:click={login}>Einloggen</button>
|
||||
<div class="flex-row justify-between" style="margin-top: 10px">
|
||||
<a href="/signup">Registrieren</a>
|
||||
<a href="/user/passwort_vergessen">Passwort Vergessen?</a>
|
||||
|
||||
10
src/components/Notifications/Notification.svelte
Normal file
10
src/components/Notifications/Notification.svelte
Normal file
@@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
import RawNotification from "./RawNotification.svelte";
|
||||
import { Notification } from "./shared";
|
||||
|
||||
export let notification: Notification & { uid: string };
|
||||
</script>
|
||||
|
||||
<RawNotification {notification}>
|
||||
<p class="text-gray-600 text-lg">{@html notification.subtext}</p>
|
||||
</RawNotification>
|
||||
12
src/components/Notifications/NotificationWrapper.svelte
Normal file
12
src/components/Notifications/NotificationWrapper.svelte
Normal file
@@ -0,0 +1,12 @@
|
||||
<script lang="ts">
|
||||
import Notification from "./Notification.svelte";
|
||||
import RawNotificationWrapper from "./RawNotificationWrapper.svelte";
|
||||
|
||||
import { notifications } from "./shared";
|
||||
</script>
|
||||
|
||||
<RawNotificationWrapper>
|
||||
{#each Object.entries($notifications) as [uid, notification] (uid)}
|
||||
<Notification notification={{...notification, uid }}></Notification>
|
||||
{/each}
|
||||
</RawNotificationWrapper>
|
||||
44
src/components/Notifications/RawNotification.svelte
Normal file
44
src/components/Notifications/RawNotification.svelte
Normal file
@@ -0,0 +1,44 @@
|
||||
<script lang="ts">
|
||||
import { Notification, deleteNotification } from "./shared";
|
||||
import { fly } from "svelte/transition";
|
||||
|
||||
export let notification: Partial<Notification> & { uid: string };
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="border rounded-lg bg-white shadow-md flex flex-row border-l-8" in:fly={{x: 200, duration: 200}} out:fly={{x: 200, duration: 200}}
|
||||
class:border-l-red-400={notification.type == "error"}
|
||||
class:border-l-blue-400={notification.type == "info"}
|
||||
class:border-l-green-400={notification.type == "success"}
|
||||
class:border-l-yellow-400={notification.type == "warning"}
|
||||
>
|
||||
<div class="flex flex-col px-4 py-2">
|
||||
<h2 class="text-xl font-semibold">{@html notification.message}</h2>
|
||||
<p class="text-gray-600 text-lg"><slot></slot></p>
|
||||
</div>
|
||||
{#if notification.dismissable}
|
||||
<button
|
||||
class="border-l px-4 py-2 hover:bg-gray-100"
|
||||
on:click={() => {
|
||||
deleteNotification(notification.uid);
|
||||
if (notification.onUserDismiss) {
|
||||
notification.onUserDismiss()
|
||||
}
|
||||
}}>X</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:global(a) {
|
||||
@apply text-blue-700;
|
||||
}
|
||||
|
||||
:global(a:hover) {
|
||||
@apply underline;
|
||||
}
|
||||
|
||||
:global(kbd) {
|
||||
@apply rounded-lg shadow-md border bg-gray-50 px-1.5 py-1 text-sm;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="fixed right-8 bottom-8 max-w-[400px] flex flex-col gap-4 z-50">
|
||||
<slot></slot>
|
||||
</div>
|
||||
80
src/components/Notifications/shared.ts
Normal file
80
src/components/Notifications/shared.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { Writable, writable } from "svelte/store";
|
||||
import { v4 as uuid } from "uuid";
|
||||
|
||||
export const notifications: Writable<Record<string, Notification>> = writable({});
|
||||
|
||||
const defaults = {
|
||||
message: "",
|
||||
dismissable: false,
|
||||
timeout: 4000,
|
||||
subtext: "",
|
||||
type: "error",
|
||||
onUserDismiss: () => {}
|
||||
};
|
||||
|
||||
export interface Notification {
|
||||
message: string;
|
||||
dismissable: boolean;
|
||||
timeout: number;
|
||||
subtext: string;
|
||||
type: "error" | "success" | "info" | "warning";
|
||||
onUserDismiss: () => any;
|
||||
uid?: string;
|
||||
}
|
||||
|
||||
export function updateNotification(uid: string, updater: Partial<Notification>) {
|
||||
notifications.update((value) => {
|
||||
value[uid] = { ...defaults, ...value[uid], ...updater } as Notification;
|
||||
return value;
|
||||
})
|
||||
}
|
||||
|
||||
export function addNotification(notification: Partial<Notification>): string {
|
||||
let uid = uuid();
|
||||
|
||||
if (notification.uid) {
|
||||
uid = notification.uid;
|
||||
}
|
||||
|
||||
const object: Notification = { ...defaults, ...notification } as Notification;
|
||||
|
||||
notifications.update((value) => {
|
||||
value[uid] = object;
|
||||
return value;
|
||||
})
|
||||
|
||||
if (object.timeout) {
|
||||
setTimeout(() => {
|
||||
deleteNotification(uid);
|
||||
}, object.timeout);
|
||||
}
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
export function deleteNotification(uid: string) {
|
||||
notifications.update((value) => {
|
||||
delete value[uid];
|
||||
return value;
|
||||
})
|
||||
}
|
||||
|
||||
export function showLinkedElement(query: string) {
|
||||
const element = document.querySelector(query);
|
||||
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
element.classList.add("linked");
|
||||
}
|
||||
|
||||
export function hideLinkedElement(query: string) {
|
||||
const element = document.querySelector(query);
|
||||
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
element.classList.remove("linked");
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
<script lang="ts">
|
||||
let password: string;
|
||||
import { addNotification } from "./Notifications/shared";
|
||||
|
||||
let passwort: string;
|
||||
let email: string;
|
||||
let hasError: boolean;
|
||||
|
||||
async function login() {
|
||||
const response = await fetch("/api/user", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
password, email
|
||||
passwort, email
|
||||
})
|
||||
})
|
||||
|
||||
@@ -16,19 +17,22 @@
|
||||
if (json.success == true) {
|
||||
window.location.href = "/login";
|
||||
} else {
|
||||
hasError = true;
|
||||
addNotification({
|
||||
message: "Ups...",
|
||||
subtext: "Da ist wohl etwas schiefgelaufen... Diese Email Adresse ist bereits in Benutzung, haben sie vielleicht bereits ein Konto bei uns?",
|
||||
type: "error",
|
||||
timeout: 0,
|
||||
dismissable: true
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div style="width:50%;margin: 0 auto">
|
||||
<h1>Registrieren:</h1>
|
||||
<div class="login_page">
|
||||
{#if hasError}
|
||||
<p>Leider ist diese Email bereits vergeben.</p>
|
||||
{/if}
|
||||
<div class="block_4" style="margin-top: 25px;">
|
||||
<h4 class="heading_3">Email</h4>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div>
|
||||
<h4>Email</h4>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Email"
|
||||
@@ -37,26 +41,23 @@
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="block_4">
|
||||
<h4 class="heading_3">Passwort</h4>
|
||||
<div>
|
||||
<h4>Passwort</h4>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="********"
|
||||
class="formInput"
|
||||
bind:value={password}
|
||||
bind:value={passwort}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-2 flex flex-row justify-between">
|
||||
<button on:click={login}
|
||||
<button class="button" on:click={login}
|
||||
>Registrieren</button
|
||||
>
|
||||
<a class="button"
|
||||
<div class="flex-row justify-between" style="margin-top: 10px">
|
||||
<a
|
||||
href="/login">Einloggen</a
|
||||
>
|
||||
</div>
|
||||
<div class="flex-row justify-between" style="margin-top: 10px">
|
||||
<a href="/">Home</a>
|
||||
<a href="/user/passwort_vergessen">Passwort Vergessen?</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="left-sidebar">
|
||||
<div class="flex flex-col gap-6">
|
||||
<nav>
|
||||
<div class="nav-card">
|
||||
<div class="card-menu-option dropdown">
|
||||
@@ -159,13 +159,25 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.nav-card {
|
||||
@apply rounded-lg w-full flex flex-col shadow-md border;
|
||||
}
|
||||
|
||||
.infoCard {
|
||||
@apply bg-white rounded-none;
|
||||
@apply bg-white rounded-lg border p-4 shadow-md;
|
||||
}
|
||||
|
||||
.dropdown-content > .card-menu-option,
|
||||
.dropdown-content > a {
|
||||
@apply block w-[350px] bg-gray-100 border text-lg px-4 py-2;
|
||||
@apply block w-[350px] bg-gray-50 border text-lg px-4 py-2;
|
||||
}
|
||||
|
||||
.dropdown-content > a:first-child {
|
||||
@apply rounded-tr-lg rounded-tl-lg;
|
||||
}
|
||||
|
||||
.dropdown-content > a:last-child {
|
||||
@apply rounded-br-lg rounded-bl-lg;
|
||||
}
|
||||
|
||||
.dropdown-content > .card-menu-option:hover,
|
||||
@@ -175,7 +187,7 @@
|
||||
}
|
||||
|
||||
.dropdown-content {
|
||||
@apply absolute bg-white left-full top-[-1px] shadow-md z-10 hidden;
|
||||
@apply absolute bg-white left-full top-[-1px] shadow-md z-10 hidden rounded-lg;
|
||||
}
|
||||
|
||||
.dropdown:hover > .dropdown-content {
|
||||
@@ -231,15 +243,11 @@
|
||||
}
|
||||
|
||||
.nav-card .card-menu-option:first-child {
|
||||
border-top: 0px solid #fff;
|
||||
border-top-left-radius: 0px;
|
||||
border-top-right-radius: 0px;
|
||||
@apply rounded-tr-lg rounded-tl-lg;
|
||||
}
|
||||
|
||||
.nav-card .card-menu-option:last-child {
|
||||
border-bottom: 0px solid #fff;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
@apply rounded-br-lg rounded-bl-lg;
|
||||
}
|
||||
|
||||
.nav-card .card-menu-option a {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="right-sidebar">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="infoCard">
|
||||
<h2 style="font-weight: bold; font-size: 1.2em; color: #3A4AB5;">
|
||||
Rufen Sie uns an<br /> Wir sind gerne für Sie da
|
||||
@@ -128,6 +128,6 @@
|
||||
|
||||
<style>
|
||||
.infoCard {
|
||||
@apply bg-white rounded-none;
|
||||
@apply bg-white rounded-lg border p-4 shadow-md;
|
||||
}
|
||||
</style>
|
||||
89
src/components/TagInput.svelte
Normal file
89
src/components/TagInput.svelte
Normal file
@@ -0,0 +1,89 @@
|
||||
<script lang="ts">
|
||||
import { Writable, writable } from "svelte/store";
|
||||
|
||||
let tag = "";
|
||||
|
||||
export let tags: Writable<string[]> = writable([]);
|
||||
export let addKeys: number[] = [13];
|
||||
export let maxTags: number;
|
||||
export let onlyUnique: boolean = false;
|
||||
export let removeKeys: number[] = [8];
|
||||
export let placeholder: string = "";
|
||||
export let allowPaste: boolean = true;
|
||||
export let allowDrop: boolean = false;
|
||||
export let splitWith: string = ",";
|
||||
export let name: string = "";
|
||||
export let id: string = "";
|
||||
export let allowBlur: boolean = true;
|
||||
export let disable: boolean = false;
|
||||
export let minChars: number = 0;
|
||||
export let labelText;
|
||||
export let labelShow;
|
||||
export let readonly: boolean = false;
|
||||
export let onTagClick: Function;
|
||||
export let onFocusIn: () => any;
|
||||
export let onFocusOut: () => any;
|
||||
export let className: string;
|
||||
|
||||
function addTag(tag: string) {
|
||||
if (onlyUnique && $tags.indexOf(tag) > -1) {
|
||||
tag = "";
|
||||
return;
|
||||
}
|
||||
|
||||
tags.update(value => {
|
||||
return [...value, tag];
|
||||
})
|
||||
}
|
||||
|
||||
function removeTag(i: number) {
|
||||
tags.update(value => {
|
||||
value.splice(i, 1)
|
||||
return value;
|
||||
})
|
||||
}
|
||||
|
||||
function onKeydown(e: KeyboardEvent) {
|
||||
if (addKeys.indexOf(e.keyCode) > -1) {
|
||||
e.preventDefault();
|
||||
addTag(tag);
|
||||
tag = "";
|
||||
} else if (removeKeys.indexOf(e.keyCode) > -1 && tag.length == 0) {
|
||||
e.preventDefault();
|
||||
removeTag($tags.length - 1);
|
||||
tag = ""
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="flex flex-row gap-1 input"
|
||||
style="padding: 0 !important;"
|
||||
>
|
||||
{#if $tags.length > 0}
|
||||
{#each $tags as tag, i}
|
||||
<button class="rounded-lg bg-white px-1.5 border flex flex-row items-center justify-between gap-2" on:click={onTagClick(tag)}>
|
||||
{tag}
|
||||
{#if !disable && !readonly}
|
||||
<span
|
||||
class="svelte-tags-input-tag-remove"
|
||||
on:pointerdown={() => removeTag(i)}
|
||||
>
|
||||
×</span
|
||||
>
|
||||
{/if}
|
||||
</button>
|
||||
{/each}
|
||||
{/if}
|
||||
<input
|
||||
type="text"
|
||||
bind:value={tag}
|
||||
on:keydown={onKeydown}
|
||||
on:focusin={onFocusIn}
|
||||
on:focusout={onFocusOut}
|
||||
class="border-none h-full w-full {className}"
|
||||
disabled={disable || readonly}
|
||||
autocomplete="off"
|
||||
{...$$restProps}
|
||||
/>
|
||||
</div>
|
||||
@@ -11,44 +11,57 @@
|
||||
import moment from "moment";
|
||||
import BilderZusatzsysteme from "../Ausweis/BilderZusatzsysteme.svelte";
|
||||
import { Gebaeude } from "src/lib/Gebaeude";
|
||||
import { hideLinkedElement, notifications } from "../Notifications/shared";
|
||||
import { gebaeude } from "./shared";
|
||||
import RawNotificationWrapper from "../Notifications/RawNotificationWrapper.svelte";
|
||||
import RawNotification from "../Notifications/RawNotification.svelte";
|
||||
import { auditHeizungGebaeudeBaujahr } from "./audits/HeizungGebaeudeBaujahr";
|
||||
import { AuditType, hidden } from "./audits/hidden";
|
||||
import { auditBedarfsausweisBenoetigt } from "./audits/BedarfsausweisBenoetigt";
|
||||
import { auditVerbrauchAbweichung } from "./audits/VerbrauchAbweichung";
|
||||
|
||||
export let gebaeude: Gebaeude;
|
||||
|
||||
export let uid: string = "";
|
||||
|
||||
$: ausweis = gebaeude.ausweis || new Verbrauchsausweis();
|
||||
gebaeude.set(new Gebaeude());
|
||||
$gebaeude.ausweis = new Verbrauchsausweis();
|
||||
$gebaeude.ausweis.gebaeude = $gebaeude;
|
||||
if (uid) {
|
||||
(async () => {
|
||||
const result = await fetch(`/api/verbrauchsausweis?uid=${uid}`, {
|
||||
method: "GET"
|
||||
});
|
||||
|
||||
let needsRequirementCertificate: boolean = false;
|
||||
const json = await result.json();
|
||||
|
||||
$: needsRequirementCertificate =
|
||||
(gebaeude.baujahr < 1978 &&
|
||||
gebaeude.einheiten <= 4 &&
|
||||
gebaeude.saniert == false &&
|
||||
(ausweis.ausstellgrund == "Vermietung" ||
|
||||
ausweis.ausstellgrund == "Sonstiges")) ||
|
||||
ausweis.ausstellgrund == "Neubau" ||
|
||||
ausweis.ausstellgrund == "Modernisierung" ||
|
||||
ausweis.ausstellgrund == "Verkauf";
|
||||
if (json.success) {
|
||||
gebaeude.set(new Gebaeude(json.data.gebaeude));
|
||||
$gebaeude.ausweis = new Verbrauchsausweis(json.data.ausweis);
|
||||
$gebaeude.ausweis.gebaeude = $gebaeude;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$: ausweis = $gebaeude.ausweis || new Verbrauchsausweis();
|
||||
|
||||
function automatischAusfüllen() {
|
||||
gebaeude.baujahr = 1962;
|
||||
ausweis.baujahr_anlage = 1974;
|
||||
gebaeude.saniert = true;
|
||||
gebaeude.einheiten = 1;
|
||||
$gebaeude.baujahr = 1962;
|
||||
ausweis.baujahr_anlage = 1952;
|
||||
$gebaeude.saniert = true;
|
||||
$gebaeude.einheiten = 1;
|
||||
ausweis.ausstellgrund = "Vermietung";
|
||||
ausweis.kennwerte.verbrauch_1 = 15000;
|
||||
ausweis.kennwerte.verbrauch_2 = 14000;
|
||||
ausweis.kennwerte.verbrauch_3 = 16000;
|
||||
gebaeude.wohnflaeche = 152;
|
||||
gebaeude.keller_beheizt = true;
|
||||
$gebaeude.wohnflaeche = 152;
|
||||
$gebaeude.keller_beheizt = true;
|
||||
ausweis.kennwerte.energietraeger_1 = "Erdgas H";
|
||||
ausweis.kennwerte.einheit_1 = "kWh";
|
||||
ausweis.kennwerte.anteil_warmwasser_1 = 18;
|
||||
ausweis.kennwerte.zeitraum = moment("12.01.2019");
|
||||
gebaeude.plz = "21039";
|
||||
gebaeude.ort = "Hamburg";
|
||||
gebaeude.strasse = "Curslacker Deich 170";
|
||||
gebaeude.gebaeudeteil = "Gesamtgebäude";
|
||||
//ausweis.upload();
|
||||
$gebaeude.plz = "21039";
|
||||
$gebaeude.ort = "Hamburg";
|
||||
$gebaeude.strasse = "Curslacker Deich 170";
|
||||
$gebaeude.gebaeudeteil = "Gesamtgebäude";
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -81,29 +94,7 @@
|
||||
|
||||
<Label>A - Prüfung der Ausweisart</Label>
|
||||
|
||||
<Ausweisart bind:gebaeude />
|
||||
|
||||
<div
|
||||
class="flex flex-col p-4"
|
||||
class:hidden={!needsRequirementCertificate}
|
||||
>
|
||||
<div class="form-group col-md-9">
|
||||
<HelpLabel
|
||||
title="Sie benötigen einen Bedarfsausweis. Bitte führen Sie hier Ihre Eingabe für den Bedarfsausweis fort und klicken auf den Button:"
|
||||
>
|
||||
Der Bedarfsausweis ist die etwas umfangreichere Berechnung.
|
||||
Sie benötigen z.B. Länge, Breite und Geschoßhöhe des
|
||||
Gebäudes. Auch müssen genauere Angaben zur Anlagentechnik
|
||||
gemacht werden.
|
||||
</HelpLabel>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-3">
|
||||
<a class="button" href="/bedarfsausweis"
|
||||
>Bedarfsausweis erstellen</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<Ausweisart bind:gebaeude={$gebaeude} />
|
||||
|
||||
<hr />
|
||||
|
||||
@@ -128,7 +119,7 @@
|
||||
required
|
||||
data-msg-minlength="min. 5 Zeichen"
|
||||
data-msg-maxlength="max. 40 Zeichen"
|
||||
bind:value={gebaeude.strasse}
|
||||
bind:value={$gebaeude.strasse}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -136,8 +127,8 @@
|
||||
<!-- PLZ -->
|
||||
<div class="form-group col-md-4 PLZ">
|
||||
<ZipSearch
|
||||
bind:zip={gebaeude.plz}
|
||||
bind:city={gebaeude.ort}
|
||||
bind:zip={$gebaeude.plz}
|
||||
bind:city={$gebaeude.ort}
|
||||
name="zip"
|
||||
/>
|
||||
</div>
|
||||
@@ -151,7 +142,7 @@
|
||||
<input
|
||||
name="IGort"
|
||||
readonly={true}
|
||||
bind:value={gebaeude.ort}
|
||||
bind:value={$gebaeude.ort}
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
@@ -173,7 +164,7 @@
|
||||
autocomplete="off"
|
||||
data-rule-minlength="2"
|
||||
data-msg-minlength="min. 2 Zeichen"
|
||||
bind:value={gebaeude.wohnflaeche}
|
||||
bind:value={$gebaeude.wohnflaeche}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -185,7 +176,7 @@
|
||||
<select
|
||||
name="IGkeller"
|
||||
required
|
||||
bind:value={gebaeude.keller_beheizt}
|
||||
bind:value={$gebaeude.keller_beheizt}
|
||||
>
|
||||
<option>Bitte auswählen</option>
|
||||
<option value={false}>nicht vorhanden</option>
|
||||
@@ -214,7 +205,7 @@
|
||||
<Label>C - Eingabe von 3 zusammenhängenden Verbrauchsjahren</Label>
|
||||
|
||||
<div class="GRB">
|
||||
<Verbrauch bind:ausweis />
|
||||
<Verbrauch bind:gebaeude={$gebaeude} />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
@@ -287,7 +278,7 @@
|
||||
><input
|
||||
type="checkbox"
|
||||
name="IGversorgungssysteme1"
|
||||
bind:checked={gebaeude.energiequelle_2_nutzung[0]}
|
||||
bind:checked={$gebaeude.energiequelle_2_nutzung[0]}
|
||||
value="Heizung"
|
||||
/>Heizung</label
|
||||
>
|
||||
@@ -295,7 +286,7 @@
|
||||
><input
|
||||
type="checkbox"
|
||||
name="IGversorgungssysteme2"
|
||||
bind:checked={gebaeude.energiequelle_2_nutzung[1]}
|
||||
bind:checked={$gebaeude.energiequelle_2_nutzung[1]}
|
||||
value="Warmwasser"
|
||||
/>Warmwasser</label
|
||||
>
|
||||
@@ -303,7 +294,7 @@
|
||||
><input
|
||||
type="checkbox"
|
||||
name="IGversorgungssysteme3"
|
||||
bind:checked={gebaeude.energiequelle_2_nutzung[2]}
|
||||
bind:checked={$gebaeude.energiequelle_2_nutzung[2]}
|
||||
value="Lüftung"
|
||||
/>Lüftung</label
|
||||
>
|
||||
@@ -311,7 +302,7 @@
|
||||
><input
|
||||
type="checkbox"
|
||||
name="IGversorgungssysteme4"
|
||||
bind:checked={gebaeude.energiequelle_2_nutzung[3]}
|
||||
bind:checked={$gebaeude.energiequelle_2_nutzung[3]}
|
||||
value="Kühlung"
|
||||
/>Kühlung</label
|
||||
>
|
||||
@@ -450,7 +441,7 @@
|
||||
>F - Bitte prüfen Sie hier die Angaben zum Sanierungszustand des
|
||||
Gebäudes</Label
|
||||
>
|
||||
<BilderZusatzsysteme {gebaeude} />
|
||||
<BilderZusatzsysteme gebaeude={$gebaeude} />
|
||||
<hr />
|
||||
<div class="flex flex-row justify-between">
|
||||
<Hilfe />
|
||||
@@ -458,3 +449,63 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<RawNotificationWrapper>
|
||||
|
||||
{#each Object.entries($notifications) as [uid, notification] (uid)}
|
||||
<RawNotification notification={{...notification, uid }}>
|
||||
{@html notification.subtext}
|
||||
</RawNotification>
|
||||
{/each}
|
||||
|
||||
{#if auditBedarfsausweisBenoetigt($gebaeude)}
|
||||
<RawNotification notification={{
|
||||
message: "Bedarfsausweis benötigt!",
|
||||
timeout: 0,
|
||||
uid: "BEDARFSAUSWEIS",
|
||||
dismissable: false,
|
||||
type: "info"
|
||||
}}>
|
||||
Sie benötigen einen Bedarfsausweis. <a href='/bedarfsausweis'>Bitte führen Sie hier Ihre Eingabe für den Bedarfsausweis fort</a>.
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
{#if auditHeizungGebaeudeBaujahr($gebaeude)}
|
||||
<RawNotification notification={{
|
||||
message: "Plausibilitätsprüfung",
|
||||
timeout: 0,
|
||||
uid: "HEIZUNG_VOR_GEBAEUDE",
|
||||
dismissable: true,
|
||||
onUserDismiss: () => {
|
||||
hidden.add(AuditType.HEIZUNG_GEBAEUDE_BAUJAHR)
|
||||
$gebaeude = $gebaeude;
|
||||
},
|
||||
type: "warning"
|
||||
}}>
|
||||
Sie haben angegeben, dass ihre Heizung vor ihrem Gebäude konstruiert wurde. Sind sie sich sicher, dass das stimmt?
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
{#if auditVerbrauchAbweichung($gebaeude).length > 0}
|
||||
<RawNotification notification={{
|
||||
message: "Plausibilitätsprüfung",
|
||||
timeout: 0,
|
||||
uid: "VERBRAUCH_ABWEICHUNG",
|
||||
dismissable: true,
|
||||
onUserDismiss: () => {
|
||||
hidden.add(AuditType.VERBRAUCH_ABWEICHUNG)
|
||||
$gebaeude = $gebaeude;
|
||||
},
|
||||
type: "warning"
|
||||
}}>
|
||||
Die Abweichung der Verbräuche zwischen Zeitraum {auditVerbrauchAbweichung($gebaeude)[0]} und {auditVerbrauchAbweichung($gebaeude)[1]} beträgt mehr als 25% und sie haben keinen Leerstand angegeben. Sind sie sich sicher, dass das stimmt?
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
</RawNotificationWrapper>
|
||||
|
||||
<style>
|
||||
:global(.linked) {
|
||||
@apply border-2 border-red-400;
|
||||
}
|
||||
</style>
|
||||
41
src/components/Verbrauchsausweis/audits.ts
Normal file
41
src/components/Verbrauchsausweis/audits.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
export function lookupAudit(audit: keyof typeof audits): boolean {
|
||||
if (!audits.hasOwnProperty(audit)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const valid = audits[audit].validator(hidden);
|
||||
|
||||
if (valid && !hidden.has(audit)) {
|
||||
audits[audit].trueAction(hidden);
|
||||
} else {
|
||||
audits[audit].falseAction(hidden);
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
type Action = (x: typeof hidden) => void;
|
||||
|
||||
export function addAudit(
|
||||
name: string,
|
||||
validator: (x: typeof hidden) => boolean,
|
||||
trueAction: Action,
|
||||
falseAction: Action
|
||||
) {
|
||||
audits[name] = {
|
||||
validator,
|
||||
trueAction,
|
||||
falseAction,
|
||||
};
|
||||
}
|
||||
|
||||
export const audits: Record<
|
||||
string,
|
||||
{
|
||||
validator: (x: typeof hidden) => boolean;
|
||||
trueAction: Action;
|
||||
falseAction: Action;
|
||||
}
|
||||
> = {};
|
||||
|
||||
export const hidden: Set<keyof typeof audits> = new Set();
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Gebaeude } from "src/lib/Gebaeude";
|
||||
|
||||
export function auditBedarfsausweisBenoetigt(gebaeude: Gebaeude): boolean {
|
||||
let ausweis = gebaeude.ausweis;
|
||||
if (!ausweis) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((gebaeude.baujahr < 1978 &&
|
||||
gebaeude.einheiten <= 4 &&
|
||||
gebaeude.saniert == false &&
|
||||
(ausweis.ausstellgrund == "Vermietung" ||
|
||||
ausweis.ausstellgrund == "Sonstiges")) ||
|
||||
ausweis.ausstellgrund == "Neubau" ||
|
||||
ausweis.ausstellgrund == "Modernisierung" ||
|
||||
ausweis.ausstellgrund == "Verkauf");
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Gebaeude } from "src/lib/Gebaeude";
|
||||
import { AuditType, hidden } from "../audits/hidden";
|
||||
|
||||
export function auditHeizungGebaeudeBaujahr(gebaeude: Gebaeude): boolean {
|
||||
let ausweis = gebaeude.ausweis;
|
||||
if (!ausweis) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ausweis.baujahr_anlage > 1500 &&
|
||||
gebaeude.baujahr > 1500 &&
|
||||
ausweis.baujahr_anlage < gebaeude.baujahr
|
||||
&& !hidden.has(AuditType.HEIZUNG_GEBAEUDE_BAUJAHR)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Gebaeude } from "src/lib/Gebaeude";
|
||||
import { AuditType, hidden } from "./hidden";
|
||||
|
||||
export function auditVerbrauchAbweichung(gebaeude: Gebaeude): number[] {
|
||||
let ausweis = gebaeude.ausweis;
|
||||
if (!ausweis || gebaeude.leerstand > 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (hidden.has(AuditType.VERBRAUCH_ABWEICHUNG)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (getAbweichung(ausweis.kennwerte.verbrauch_1, ausweis.kennwerte.verbrauch_2) > 0.25) {
|
||||
return [1, 2];
|
||||
}
|
||||
|
||||
if (getAbweichung(ausweis.kennwerte.verbrauch_2, ausweis.kennwerte.verbrauch_3) > 0.25) {
|
||||
return [2, 3];
|
||||
}
|
||||
|
||||
if (getAbweichung(ausweis.kennwerte.verbrauch_4, ausweis.kennwerte.verbrauch_5) > 0.25) {
|
||||
return [4, 5];
|
||||
}
|
||||
|
||||
if (getAbweichung(ausweis.kennwerte.verbrauch_5, ausweis.kennwerte.verbrauch_6) > 0.25) {
|
||||
return [5, 6];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function getAbweichung(x: number, y: number): number {
|
||||
console.log(x, y, Math.abs((x - y) / ((x + y) / 2)));
|
||||
|
||||
return Math.abs((x - y) / ((x + y) / 2));
|
||||
}
|
||||
6
src/components/Verbrauchsausweis/audits/hidden.ts
Normal file
6
src/components/Verbrauchsausweis/audits/hidden.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const hidden = new Set<AuditType>()
|
||||
|
||||
export enum AuditType {
|
||||
HEIZUNG_GEBAEUDE_BAUJAHR,
|
||||
VERBRAUCH_ABWEICHUNG
|
||||
}
|
||||
4
src/components/Verbrauchsausweis/shared.ts
Normal file
4
src/components/Verbrauchsausweis/shared.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Gebaeude } from "src/lib/Gebaeude";
|
||||
import { Writable, writable } from "svelte/store";
|
||||
|
||||
export const gebaeude: Writable<Gebaeude> = writable();
|
||||
@@ -3,7 +3,7 @@ import "../style/global.scss"
|
||||
import Footer from '../components/Footer.astro';
|
||||
import Header from '../components/Header.astro';
|
||||
import SidebarLeft from '../components/SidebarLeft.astro';
|
||||
import SidebarRight from '../components/SidebarRight.astro';
|
||||
import NotificationWrapper from "~/components/Notifications/NotificationWrapper.svelte";
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
@@ -110,8 +110,8 @@ const schema = JSON.stringify({
|
||||
@apply text-xl font-medium mt-6 mb-4;
|
||||
}
|
||||
|
||||
input, select, textarea {
|
||||
@apply py-1.5 px-2.5 rounded-lg w-full outline-none text-base text-slate-800 border;
|
||||
input, select, textarea, .input {
|
||||
@apply py-1.5 px-2.5 rounded-lg w-full outline-none text-base text-slate-800 border bg-white;
|
||||
}
|
||||
|
||||
input:disabled, input:read-only, select:disabled {
|
||||
|
||||
@@ -4,6 +4,7 @@ import Footer from '../components/Footer.astro';
|
||||
import Header from '../components/Header.astro';
|
||||
import SidebarLeft from '../components/SidebarLeft.astro';
|
||||
import SidebarRight from '../components/SidebarRight.astro';
|
||||
import NotificationWrapper from "~/components/Notifications/NotificationWrapper.svelte";
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
@@ -94,6 +95,7 @@ const schema = JSON.stringify({
|
||||
<SidebarRight></SidebarRight>
|
||||
</main>
|
||||
<Footer />
|
||||
<NotificationWrapper client:load></NotificationWrapper>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -102,7 +104,7 @@ const schema = JSON.stringify({
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
button, .button {
|
||||
.button {
|
||||
@apply px-8 py-2 bg-secondary rounded-lg text-white font-medium hover:shadow-lg transition-all hover:underline active:bg-blue-900 text-center cursor-pointer;
|
||||
color: #fff !important;
|
||||
}
|
||||
@@ -112,7 +114,11 @@ const schema = JSON.stringify({
|
||||
}
|
||||
|
||||
input {
|
||||
@apply py-1 px-2 w-full rounded-lg outline-none text-lg text-slate-800 border;
|
||||
@apply py-1.5 px-4 w-full rounded-lg outline-none text-lg text-slate-700 border bg-gray-50 transition-colors;
|
||||
}
|
||||
|
||||
input:hover, input:focus {
|
||||
@apply bg-gray-100;
|
||||
}
|
||||
|
||||
label {
|
||||
|
||||
@@ -10,7 +10,7 @@ export class Verbrauchsausweis {
|
||||
public warmwasser_enthalten: boolean = true;
|
||||
public id?: number;
|
||||
public uid?: string;
|
||||
public baujahr_anlage: number = 0;
|
||||
public baujahr_anlage: number[] = [];
|
||||
|
||||
public get energetische_nutzfläche(): number {
|
||||
return (
|
||||
@@ -24,7 +24,12 @@ export class Verbrauchsausweis {
|
||||
public kennwerte: Energiekennwerte = new Energiekennwerte();
|
||||
public gebaeude: Gebaeude = new Gebaeude();
|
||||
|
||||
public constructor() {}
|
||||
public constructor(initializer?: Verbrauchsausweis) {
|
||||
if (initializer) {
|
||||
this.ausweisart = initializer.ausweisart;
|
||||
this.kennwerte = initializer.kennwerte;
|
||||
}
|
||||
}
|
||||
|
||||
public static fromBase64(base64: string): Verbrauchsausweis | null {
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
import { Ausweis } from "./Ausweis/Ausweis";
|
||||
import { Verbrauchsausweis } from "./Ausweis/Verbrauchsausweis";
|
||||
import { Dachgeschoss, Lueftungskonzept } from "./Ausweis/types";
|
||||
import { BitChecker } from "./BitChecker";
|
||||
|
||||
@@ -23,7 +24,7 @@ export class Gebaeude {
|
||||
public energiequelle_2_nutzung: boolean[] = BitChecker(0);
|
||||
public daemmung: boolean[] = BitChecker(0);
|
||||
|
||||
public ausweis?: Ausweis;
|
||||
public ausweis: Ausweis;
|
||||
|
||||
public uid?: string;
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export class User {
|
||||
return null;
|
||||
}
|
||||
|
||||
const user = await db<UserType>("users").select("*").where("uid", uid).first();
|
||||
const user = await db<UserType>("benutzer").select("*").where("uid", uid).first();
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
@@ -29,7 +29,7 @@ export class User {
|
||||
return null;
|
||||
}
|
||||
|
||||
const user = await db<UserType>("users").select("*").where("email", email).first();
|
||||
const user = await db<UserType>("benutzer").select("*").where("email", email).first();
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
@@ -48,7 +48,7 @@ export class User {
|
||||
return null;
|
||||
}
|
||||
|
||||
const user = await db<UserType>("users").select("*").where("id", id).first();
|
||||
const user = await db<UserType>("benutzer").select("*").where("id", id).first();
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
@@ -63,11 +63,11 @@ export class User {
|
||||
}
|
||||
|
||||
const uid = uuid();
|
||||
const hashedPassword = hashPassword(user.password);
|
||||
const hashedPassword = hashPassword(user.passwort);
|
||||
|
||||
const result = await db<UserType>("users").insert({
|
||||
const result = await db<UserType>("benutzer").insert({
|
||||
email: user.email,
|
||||
password: hashedPassword,
|
||||
passwort: hashedPassword,
|
||||
uid: uid
|
||||
}, ["id"])
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ export const UserTypeValidator = z.object({
|
||||
id: z.number(),
|
||||
uid: z.string().length(36),
|
||||
email: z.string().max(255),
|
||||
password: z.string().min(6),
|
||||
passwort: z.string().min(6),
|
||||
})
|
||||
|
||||
export const UserRegisterValidator = z.object({
|
||||
email: z.string().max(255),
|
||||
password: z.string().min(6),
|
||||
passwort: z.string().min(6),
|
||||
})
|
||||
|
||||
export type UserType = z.infer<typeof UserTypeValidator>
|
||||
130
src/lib/client/Ausweis/Verbrauchsausweis.ts
Normal file
130
src/lib/client/Ausweis/Verbrauchsausweis.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { Ausstellgrund, Ausweisart } from "src/lib/Ausweis/types";
|
||||
import { Energiekennwerte } from "src/lib/Energiekennwerte";
|
||||
import { Gebaeude } from "src/lib/Gebaeude";
|
||||
import { getKlimafaktorenClient } from "src/lib/Klimafaktoren";
|
||||
import { getHeizwertfaktorClient } from "src/lib/server/Heizwertfaktor";
|
||||
|
||||
|
||||
export default class Verbrauchsausweis {
|
||||
public ausweisart: Ausweisart = "VA";
|
||||
public ausstellgrund: Ausstellgrund = "Vermietung";
|
||||
public warmwasser_enthalten: boolean = true;
|
||||
public uid?: string;
|
||||
public baujahr_anlage: number[] = [];
|
||||
|
||||
public get energetische_nutzfläche(): number {
|
||||
return (
|
||||
this.gebaeude.wohnflaeche *
|
||||
(this.gebaeude.keller_beheizt ? 1.35 : 1.2)
|
||||
);
|
||||
}
|
||||
|
||||
public regnummer?: string;
|
||||
|
||||
public kennwerte: Energiekennwerte = new Energiekennwerte();
|
||||
public gebaeude: Gebaeude = new Gebaeude();
|
||||
|
||||
public constructor(initializer?: Verbrauchsausweis) {
|
||||
if (initializer) {
|
||||
this.ausweisart = initializer.ausweisart;
|
||||
this.kennwerte = initializer.kennwerte;
|
||||
}
|
||||
}
|
||||
|
||||
public get primaer_energie_verbrauch(): Promise<number> {
|
||||
return (async () => {
|
||||
const Endenergieverbrauch = await this.end_energie_verbrauch;
|
||||
|
||||
const brennstoff_1 = getHeizwertfaktorClient(
|
||||
this.kennwerte.energietraeger_1,
|
||||
this.kennwerte.einheit_1
|
||||
);
|
||||
|
||||
return Endenergieverbrauch * brennstoff_1.primärenergiefaktor;
|
||||
})();
|
||||
}
|
||||
|
||||
public get end_energie_verbrauch(): Promise<number> {
|
||||
return (async () => {
|
||||
const date = this.kennwerte.zeitraum;
|
||||
const klimafaktoren = await getKlimafaktorenClient(
|
||||
date,
|
||||
this.gebaeude.plz
|
||||
);
|
||||
|
||||
// Endenergieverbrauch
|
||||
// Um den EEV auszurechnen, müssen die Verbräuche zu kWh konvertiert werden.
|
||||
let brennstoff_1 = getHeizwertfaktorClient(
|
||||
this.kennwerte.energietraeger_1,
|
||||
this.kennwerte.einheit_1
|
||||
);
|
||||
let brennstoff_2 = getHeizwertfaktorClient(
|
||||
this.kennwerte.energietraeger_2,
|
||||
this.kennwerte.einheit_2
|
||||
);
|
||||
|
||||
let verbrauch_1_kwh =
|
||||
this.kennwerte.verbrauch_1 * brennstoff_1.umrechnungsfaktor;
|
||||
let verbrauch_2_kwh =
|
||||
this.kennwerte.verbrauch_2 * brennstoff_1.umrechnungsfaktor;
|
||||
let verbrauch_3_kwh =
|
||||
this.kennwerte.verbrauch_3 * brennstoff_1.umrechnungsfaktor;
|
||||
let verbrauch_4_kwh =
|
||||
this.kennwerte.verbrauch_4 * brennstoff_2.umrechnungsfaktor;
|
||||
let verbrauch_5_kwh =
|
||||
this.kennwerte.verbrauch_5 * brennstoff_2.umrechnungsfaktor;
|
||||
let verbrauch_6_kwh =
|
||||
this.kennwerte.verbrauch_6 * brennstoff_2.umrechnungsfaktor;
|
||||
|
||||
let warmwasserZuschlag = 0;
|
||||
let leerstandsZuschlag = 0;
|
||||
let kuehlungsZuschlag = 0;
|
||||
if (this.kennwerte.anteil_warmwasser_1 == 0) {
|
||||
warmwasserZuschlag = 20 * this.energetische_nutzfläche * 3;
|
||||
}
|
||||
|
||||
if (this.gebaeude.leerstand > 0) {
|
||||
let durchschnittsKlimafaktor =
|
||||
klimafaktoren.reduce((a, b) => a + b, 0) / 3;
|
||||
|
||||
leerstandsZuschlag =
|
||||
((verbrauch_1_kwh +
|
||||
verbrauch_2_kwh +
|
||||
verbrauch_3_kwh +
|
||||
verbrauch_4_kwh +
|
||||
verbrauch_5_kwh +
|
||||
verbrauch_6_kwh) *
|
||||
(this.gebaeude.leerstand / 100)) /
|
||||
durchschnittsKlimafaktor;
|
||||
}
|
||||
|
||||
if (this.gebaeude.energiequelle_2_nutzung[3]) {
|
||||
kuehlungsZuschlag = 6 * this.energetische_nutzfläche * 3;
|
||||
}
|
||||
|
||||
let anteil_heizung = 1 - this.kennwerte.anteil_warmwasser_1 / 100;
|
||||
let anteil_warmwasser = this.kennwerte.anteil_warmwasser_1 / 100;
|
||||
|
||||
let Energieverbrauchskennwert =
|
||||
(anteil_heizung *
|
||||
(verbrauch_1_kwh + verbrauch_4_kwh) *
|
||||
klimafaktoren[0] +
|
||||
anteil_warmwasser * (verbrauch_1_kwh + verbrauch_4_kwh) +
|
||||
anteil_heizung *
|
||||
(verbrauch_2_kwh + verbrauch_5_kwh) *
|
||||
klimafaktoren[1] +
|
||||
anteil_warmwasser * (verbrauch_2_kwh + verbrauch_5_kwh) +
|
||||
anteil_heizung *
|
||||
(verbrauch_3_kwh + verbrauch_6_kwh) *
|
||||
klimafaktoren[2] +
|
||||
anteil_warmwasser * (verbrauch_3_kwh + verbrauch_6_kwh) +
|
||||
warmwasserZuschlag +
|
||||
leerstandsZuschlag +
|
||||
kuehlungsZuschlag) /
|
||||
3 /
|
||||
this.energetische_nutzfläche;
|
||||
|
||||
return Energieverbrauchskennwert;
|
||||
})();
|
||||
}
|
||||
}
|
||||
1
src/lib/client/Ausweis/index.ts
Normal file
1
src/lib/client/Ausweis/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as Verbrauchsausweis } from "./Verbrauchsausweis";
|
||||
36
src/lib/client/Gebaeude/Gebaeude.ts
Normal file
36
src/lib/client/Gebaeude/Gebaeude.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Ausweis } from "src/lib/Ausweis/Ausweis";
|
||||
import { Dachgeschoss, Lueftungskonzept } from "src/lib/Ausweis/types";
|
||||
import { BitChecker } from "src/lib/BitChecker";
|
||||
|
||||
export class Gebaeude {
|
||||
public typ: string = "";
|
||||
public plz: string = "";
|
||||
public ort: string = "";
|
||||
public strasse: string = "";
|
||||
public gebaeudeteil: string = "";
|
||||
public saniert: boolean = false;
|
||||
public baujahr: number = 0;
|
||||
public einheiten: number = 0;
|
||||
public wohnflaeche: number = 0;
|
||||
public keller_beheizt: boolean = false;
|
||||
public dachgeschoss_beheizt: Dachgeschoss = Dachgeschoss.UNBEHEIZT;
|
||||
public lueftungskonzept: Lueftungskonzept = "Fensterlüftung";
|
||||
public wird_gekuehlt: boolean = false;
|
||||
public leerstand: number = 0;
|
||||
public versorgungssysteme: boolean[] = BitChecker(0);
|
||||
public fenster_dach: boolean[] = BitChecker(0);
|
||||
public energiequelle_2_nutzung: boolean[] = BitChecker(0);
|
||||
public daemmung: boolean[] = BitChecker(0);
|
||||
|
||||
public ausweis?: Ausweis;
|
||||
|
||||
public uid?: string;
|
||||
|
||||
public constructor(initializer?: Gebaeude) {
|
||||
if (initializer) {
|
||||
this.typ = initializer.typ;
|
||||
this.plz = initializer.plz;
|
||||
this.ort = initializer.ort;
|
||||
}
|
||||
}
|
||||
}
|
||||
0
src/lib/client/Gebaeude/index.ts
Normal file
0
src/lib/client/Gebaeude/index.ts
Normal file
@@ -1,5 +1,8 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { ActionFailedError, error, success } from "src/lib/APIResponse";
|
||||
import { ActionFailedError, MissingEntityError, error, success } from "src/lib/APIResponse";
|
||||
import { Ausweis } from "src/lib/Ausweis/Ausweis";
|
||||
import { Energiekennwerte } from "src/lib/Energiekennwerte";
|
||||
import { Gebaeude } from "src/lib/Gebaeude";
|
||||
import { db } from "src/lib/shared";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -62,6 +65,10 @@ const AusweisUploadChecker = z.object({
|
||||
ausweis_uid: z.string().optional(),
|
||||
});
|
||||
|
||||
const AusweisDownloadChecker = z.object({
|
||||
uid: z.string()
|
||||
})
|
||||
|
||||
/**
|
||||
* Erstellt einen Verbrauchsausweis anhand der gegebenen Daten und trägt ihn in die Datenbank ein.
|
||||
* @param param0
|
||||
@@ -135,4 +142,40 @@ export const post: APIRoute = async ({ request }) => {
|
||||
kennwerte: kennwerte[0],
|
||||
gebaeude: gebaeude[0],
|
||||
});
|
||||
};
|
||||
|
||||
export const get: APIRoute = async ({ request }) => {
|
||||
const body: z.infer<typeof AusweisDownloadChecker> = await request.json();
|
||||
|
||||
const validation = AusweisDownloadChecker.safeParse(body);
|
||||
|
||||
if (!validation.success) {
|
||||
return error(validation.error.issues);
|
||||
}
|
||||
|
||||
let result = await db<{ gebaeude: Gebaeude, kennwerte: Energiekennwerte, ausweis: Ausweis}>("gebaeude")
|
||||
.select([
|
||||
db.raw("(json_agg(gebaeude)->0) AS gebaeude"),
|
||||
db.raw("(json_agg(energiekennwerte)->0) AS kennwerte"),
|
||||
db.raw("(json_agg(energieausweise)->0) AS ausweis"),
|
||||
])
|
||||
.leftJoin(
|
||||
"energiekennwerte",
|
||||
"energiekennwerte.gebaeude_id",
|
||||
"gebaeude.id"
|
||||
)
|
||||
.leftJoin(
|
||||
"energieausweise",
|
||||
"energieausweise.gebaeude_id",
|
||||
"gebaeude.id"
|
||||
)
|
||||
.where("gebaeude.uid", body.uid)
|
||||
.groupBy("gebaeude.id")
|
||||
.first();
|
||||
|
||||
if (!result) {
|
||||
return MissingEntityError("gebäude");
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
@@ -23,7 +23,7 @@ export const post: APIRoute = async ({ request }) => {
|
||||
}
|
||||
|
||||
// Validate Password
|
||||
if (!validatePassword(user.password, body.password)) {
|
||||
if (!validatePassword(user.passwort, body.password)) {
|
||||
return error(["Invalid email or password."]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { success, MissingPropertyError, MissingEntityError, ActionFailedError, InvalidDataError } from "../../lib/APIResponse";
|
||||
import { success, MissingPropertyError, MissingEntityError, ActionFailedError, InvalidDataError, error } from "../../lib/APIResponse";
|
||||
import { User } from "../../lib/User";
|
||||
import { UserRegisterValidator, UserType, UserTypeValidator } from "../../lib/User/type";
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* Ruft einen Nutzer anhand seiner uid aus der Datenbank ab.
|
||||
@@ -24,7 +25,7 @@ export const get: APIRoute = async ({ request }) => {
|
||||
}
|
||||
|
||||
export const put: APIRoute = async ({ request }) => {
|
||||
const body = await request.json();
|
||||
const body: z.infer<typeof UserRegisterValidator> = await request.json();
|
||||
|
||||
const validate = UserRegisterValidator.safeParse(body);
|
||||
|
||||
@@ -32,6 +33,12 @@ export const put: APIRoute = async ({ request }) => {
|
||||
return InvalidDataError(validate.error);
|
||||
}
|
||||
|
||||
const user = await User.fromEmail(body.email);
|
||||
|
||||
if (user) {
|
||||
return error(["Email address is already being used."]);
|
||||
}
|
||||
|
||||
const result = await User.create(body as UserType);
|
||||
|
||||
if (!result) {
|
||||
|
||||
@@ -1,44 +1,10 @@
|
||||
---
|
||||
import AusweisLayout from "~/layouts/AusweisLayout.astro";
|
||||
import VerbrauchsausweisContent from "~/components/Verbrauchsausweis/VerbrauchsausweisContent.svelte";
|
||||
import { Verbrauchsausweis } from "src/lib/Ausweis/Verbrauchsausweis";
|
||||
import { db } from "src/lib/shared";
|
||||
import { Gebaeude } from "src/lib/Gebaeude";
|
||||
import { Energiekennwerte } from "src/lib/Energiekennwerte";
|
||||
import { Ausweis, getAusweis } from "src/lib/Ausweis/Ausweis";
|
||||
|
||||
let gebaeude = new Gebaeude();
|
||||
if (Astro.cookies.has("ausweis_uid")) {
|
||||
const uid = Astro.cookies.get("ausweis_uid").value;
|
||||
let result = await db<{ gebaeude: Gebaeude, kennwerte: Energiekennwerte, ausweis: Ausweis}>("gebaeude")
|
||||
.select([
|
||||
db.raw("(json_agg(gebaeude)->0) AS gebaeude"),
|
||||
db.raw("(json_agg(energiekennwerte)->0) AS kennwerte"),
|
||||
db.raw("(json_agg(energieausweise)->0) AS ausweis"),
|
||||
])
|
||||
.leftJoin(
|
||||
"energiekennwerte",
|
||||
"energiekennwerte.gebaeude_id",
|
||||
"gebaeude.id"
|
||||
)
|
||||
.leftJoin(
|
||||
"energieausweise",
|
||||
"energieausweise.gebaeude_id",
|
||||
"gebaeude.id"
|
||||
)
|
||||
.where("gebaeude.uid", uid)
|
||||
.groupBy("gebaeude.id")
|
||||
.first();
|
||||
|
||||
if (result) {
|
||||
gebaeude = new Gebaeude(result.gebaeude);
|
||||
gebaeude.ausweis = getAusweis(result.ausweis.ausweisart, result.ausweis);
|
||||
gebaeude.ausweis.gebaeude = gebaeude;
|
||||
gebaeude.ausweis.kennwerte = new Energiekennwerte(result.kennwerte);
|
||||
}
|
||||
}
|
||||
const uid = Astro.cookies.get("ausweis_uid").value;
|
||||
---
|
||||
|
||||
<AusweisLayout title="Verbrauchsausweis erstellen">
|
||||
<VerbrauchsausweisContent client:load gebaeude={gebaeude} />
|
||||
<VerbrauchsausweisContent client:load uid={uid} />
|
||||
</AusweisLayout>
|
||||
|
||||
@@ -3,8 +3,9 @@ header {
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #fff;
|
||||
background-image: url(../images/pattern.png);
|
||||
background-color: #fafafa;
|
||||
overflow-x: hidden;
|
||||
/* background-image: url(../images/pattern.png); */
|
||||
background-repeat: repeat;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
@@ -37,28 +38,7 @@ body {
|
||||
}
|
||||
|
||||
.mainContent {
|
||||
position: relative;
|
||||
-webkit-box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
|
||||
box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
|
||||
background-color: rgb(255, 255, 255);
|
||||
margin-top: 0px;
|
||||
padding: 0% 2%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.only-form-mainContent {
|
||||
|
||||
padding: 20px 10px;
|
||||
width: calc(100% - 4px);
|
||||
}
|
||||
|
||||
.left-sidebar {
|
||||
-ms-grid-row: 1;
|
||||
-ms-grid-column: 1;
|
||||
grid-area: 1/1/1/3;
|
||||
padding-top: 0px;
|
||||
margin-top: 0px;
|
||||
width: 100%;
|
||||
@apply relative w-full rounded-lg border shadow-md px-6 py-8 bg-white;
|
||||
}
|
||||
|
||||
.right-sidebar {
|
||||
@@ -81,16 +61,6 @@ body {
|
||||
margin: 1em 0em;
|
||||
}
|
||||
|
||||
.mainContent h2 {
|
||||
font-weight: normal;
|
||||
font-size: 1rem;
|
||||
position: relative;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
margin: 1em 0em;
|
||||
}
|
||||
|
||||
.mainContent a {
|
||||
color: #3A4AB5;
|
||||
text-decoration: none;
|
||||
@@ -159,23 +129,6 @@ footer a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.MajorHeading {
|
||||
color: rgb(58, 74, 181);
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
right: 0px;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
.MajorHeading.smaller {
|
||||
color: rgb(255, 125, 38);
|
||||
margin-top: 59px;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.nav-head {
|
||||
background-color: #444F94;
|
||||
display: -webkit-box;
|
||||
@@ -588,12 +541,6 @@ textarea {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.right-sidebar img,
|
||||
.left-sidebar img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
@@ -895,17 +842,6 @@ table {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.right-sidebar img,
|
||||
.left-sidebar img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.right-sidebar .large-button,
|
||||
.left-sidebar .large-button {
|
||||
white-space: pre-wrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
block {
|
||||
display: block;
|
||||
@@ -1330,16 +1266,6 @@ content>*:nth-child(3) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* NOTE: Right Sidebar */
|
||||
.infoCard {
|
||||
-webkit-box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
|
||||
box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
border-radius: 1em;
|
||||
padding: 1em;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.large-button {
|
||||
background: #3a4ab5;
|
||||
color: #fff;
|
||||
|
||||
@@ -13,15 +13,6 @@
|
||||
grid-template-rows: auto;
|
||||
}
|
||||
|
||||
.mainContent {
|
||||
display: block;
|
||||
-webkit-box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
|
||||
box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
|
||||
background-color: rgb(255, 255, 255);
|
||||
margin-top: 0px;
|
||||
padding: 20px 1.5%;
|
||||
}
|
||||
|
||||
.stretch-2 {
|
||||
-ms-grid-row: 1;
|
||||
-ms-grid-column: 1;
|
||||
@@ -35,17 +26,6 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.left-sidebar {
|
||||
display: block;
|
||||
max-width: 940px;
|
||||
-ms-grid-row: 1;
|
||||
-ms-grid-column: 1;
|
||||
grid-area: 1/1/1/1;
|
||||
padding-top: 0px;
|
||||
margin-top: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.right-sidebar {
|
||||
display: block;
|
||||
max-width: 940px;
|
||||
|
||||
@@ -20,17 +20,6 @@
|
||||
grid-template-rows: auto;
|
||||
}
|
||||
|
||||
.mainContent {
|
||||
display: block;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
-webkit-box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
|
||||
box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
|
||||
background-color: rgb(255, 255, 255);
|
||||
margin-top: 0px;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.stretch-2 {
|
||||
-ms-grid-row: 1;
|
||||
-ms-grid-column: 2;
|
||||
@@ -56,17 +45,6 @@
|
||||
|
||||
}
|
||||
|
||||
.left-sidebar {
|
||||
display: block;
|
||||
max-width: 940px;
|
||||
-ms-grid-row: 1;
|
||||
-ms-grid-column: 1;
|
||||
grid-area: 1/1/1/1;
|
||||
padding-top: 0px;
|
||||
margin-top: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.right-sidebar {
|
||||
display: block;
|
||||
max-width: 940px;
|
||||
@@ -87,16 +65,6 @@
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.mainContent h2 {
|
||||
font-weight: normal;
|
||||
font-size: 1.6rem;
|
||||
position: relative;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
margin: 1em 0em !important;
|
||||
}
|
||||
|
||||
.mainContent a {
|
||||
color: #3A4AB5;
|
||||
text-decoration: none;
|
||||
@@ -157,23 +125,6 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.MajorHeading {
|
||||
color: rgb(58, 74, 181);
|
||||
font-weight: 500;
|
||||
font-size: 26px;
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
right: 0px;
|
||||
line-height: 1.3em;
|
||||
}
|
||||
|
||||
.MajorHeading.smaller {
|
||||
color: rgb(255, 125, 38);
|
||||
margin-top: 35px;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.nav-head {
|
||||
background-color: rgb(255, 125, 38);
|
||||
display: -webkit-box;
|
||||
@@ -195,7 +146,7 @@
|
||||
|
||||
.headerButton {
|
||||
width: auto;
|
||||
font-size: 18px;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
color: rgb(255, 255, 255);
|
||||
background-color: rgb(255, 125, 38);
|
||||
@@ -244,25 +195,6 @@
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
|
||||
.nav-card {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
-webkit-box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
|
||||
box-shadow: rgb(162, 162, 162) 1px 1px 3px 1px;
|
||||
margin-bottom: 1.5em;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.active {
|
||||
background-color: none;
|
||||
opacity: 1;
|
||||
|
||||
Reference in New Issue
Block a user