Commit 628e5bf2 authored by abergavenny's avatar abergavenny
Browse files

Version 1.0.0

parent b463e8cc
<script setup>
defineEmits(['onTabSelect'])
const props = defineProps(['active', 'tabs'])
</script>
<template>
<div class="tabs">
<div class="tab" :class="{ tab__active: tab.value === props.active }" v-for="tab in props.tabs" :key="tab.key"
@click="$emit('onTabSelect', tab.value)">
<span>{{ tab.name }}</span>
</div>
</div>
</template>
<style scoped>
.tabs {
overflow-x: auto;
padding: var(--spacing);
display: flex;
gap: var(--spacing-s);
}
@media (min-width: 48em) {
.tabs {
flex-direction: row;
}
}
.tab {
padding: 0 var(--spacing);
display: flex;
border-radius: var(--radius);
cursor: pointer;
}
.tab__active {
background-color: hsl(var(--clr-primary));
display: flex;
color: var(--clr-white);
}
.tab:hover:not(.tab__active) {
background-color: hsl(var(--clr-background));
transition: background-color ease-in 250ms;
}
</style>
\ No newline at end of file
<script setup>
import { useRouter } from 'vue-router'
import SectionTitle from '@/components/SectionTitle.vue'
import { useSessionStore } from '@/stores/session'
const emit = defineEmits(['onCloseModal'])
const router = useRouter()
const session = useSessionStore()
async function acceptTerms() {
try {
const response = await session.updateSharing(session.self.id, { sharingAllowed: true })
if (response.success) {
emit('onCloseModal')
await session.fetchSelf()
}
} catch (error) {
console.error('ERROR:', error.name)
}
}
function rejectTerms() {
router.push({ name: 'landing' })
}
</script>
<template>
<div class="tos-request">
<div class="tos-request__content">
<SectionTitle value="Nutzungsbedingungen" />
<div>
<!-- DEVINFO - ToS: Hier den Text für die Nutzungsbedingungen (Eigentümer, falls abweichend) eintragen -->
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna
sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna. Nunc viverra
imperdiet enim. Fusce est. Vivamus a tellus.
<!-- END - ToS -->
</div>
</div>
<div class="tos-request__action">
<button class="button primary" type="button" @click="acceptTerms()">Akzeptieren</button>
<button class="button primary" type="button" @click="rejectTerms()">Nicht akzeptieren</button>
</div>
</div>
</template>
<style scoped>
.tos-request {
overflow: hidden;
flex: 1;
display: flex;
flex-direction: column;
gap: var(--spacing);
}
.tos-request__content {
overflow: hidden;
padding: var(--spacing);
flex: 1;
display: flex;
flex-direction: column;
gap: var(--spacing);
}
.tos-request__content>div:last-of-type {
overflow-y: auto;
}
.tos-request__action {
padding: var(--spacing);
display: flex;
flex-direction: column;
gap: var(--spacing);
}
</style>
\ No newline at end of file
<script setup>
import SectionTitle from '@/components/SectionTitle.vue'
import { useApartmentStore } from '@/stores/apartments'
defineEmits(['onChangePassword'])
const apartments = useApartmentStore()
</script>
<template>
<div class="user-box basic">
<div class="user-box__content">
<SectionTitle value="Benutzername für die Wohneinheit" />
<span>{{ apartments.owner.username }}</span>
</div>
<div class="user-box__content">
<button class="button primary" type="button" @click="$emit('onChangePassword')">
<span>Passwort ändern</span>
</button>
</div>
</div>
</template>
<style scoped>
.user-box {
padding: var(--spacing);
display: flex;
flex-direction: column;
gap: var(--spacing);
align-items: center;
border-radius: var(--radius);
}
@media (min-width: 48em) {
.user-box {
display: flex;
flex-direction: row;
justify-content: space-between;
}
}
.user-box__content {
width: 100%;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
}
</style>
\ No newline at end of file
<script setup>
import { MESSAGES } from '@/data/messages'
</script>
<template>
<div class="waiting-for-data">
<span>{{ MESSAGES['WAITING_FOR_DATA'] }}</span>
</div>
</template>
<style scoped>
.waiting-for-data {
display: flex;
}
.waiting-for-data>span {
font-size: var(--text-s);
}
</style>
\ No newline at end of file
<script setup>
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import MessageBox from '@/components/MessageBox.vue'
import InputGroup from '@/components/InputGroup.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import InputWrapper from '@/components/InputWrapper.vue'
import { MESSAGES } from '@/data/messages'
import { resetAlert } from '@/helpers'
import { useApartmentStore } from '@/stores/apartments'
import { useBuildingStore } from '@/stores/buildings'
import { useUserStore } from '@/stores/users'
const LINK = import.meta.env.VITE_APP_LINK
defineEmits(['closeModal'])
let timeout = null
const copyAllowed = ref(false)
const message = ref(null)
const messageType = ref(null)
const showCopyDialog = ref(false)
const apartments = useApartmentStore()
const buildings = useBuildingStore()
const users = useUserStore()
// Initial values
const state = reactive({
apartmentName: null,
password: null,
username: null
})
const rules = computed(() => {
return {
apartmentName: { required },
password: { required },
username: { required }
}
})
const v$ = useVuelidate(rules, state)
async function copyCredentials() {
if ('clipboard' in navigator) {
try {
await navigator.clipboard.writeText(`Benutzername: ${buildings.current?.prefix}_${state.username} Passwort: ${state.password} - Anmeldung unter ${LINK}`)
} catch (error) {
console.error('ERROR:', error.name)
}
}
}
function buildUrl() {
const subject = '3% Plus - Zugang eingerichtet'
const sender = 'Ihr Verwalter'
// DEVINFO Hier kann der E-Mail-Text zur Benachrichtigung (Zugang erstellt) des Eigentümers angepasst werden
const message = `
Sehr geehrte Frau/Sehr geehrter Herr, %0D%0A%0D%0A
anbei erhalten Sie die Logindaten für das Tool zur Erfassung des energetischen Gebäudezustands, in welchem ich das Gebäude (angegebene Adresse des Gebäudes) bereits angelegt habe: %0D%0A%0D%0A
Benutzername: ${buildings.current?.prefix}_${state.username}%0D%0A
Passwort: ${state.password} %0D%0A%0D%0A
Bitte loggen Sie sich mit diesen Angaben unter folgendem Link ein: ${LINK} %0D%0A%0D%0A
Mit freundlichen Grüßen%0D%0A
${sender}%0D%0A%0D%0A%0D%0A
Wenn diese E-Mail nicht an Sie gerichtet ist, dann löschen Sie diese Nachricht bitte oder informieren den Absender über die falsche Zustellung.
`
return `mailto:?subject=${subject}&body=${message}`
}
async function onSubmit() {
try {
clearTimeout(timeout)
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
timeout = resetAlert(message)
return
}
const response = await apartments.createApartment({
buildingId: buildings.active,
...state
})
if (response.success) {
message.value = MESSAGES[response.message]
messageType.value = 'success'
showCopyDialog.value = true
await buildings.fetchBuildings()
await apartments.fetchApartments()
await users.fetchUsers()
} else {
message.value = MESSAGES[response.message]
messageType.value = 'danger'
}
timeout = resetAlert(message)
} catch (error) {
console.error('ERROR:', error.name)
}
}
onMounted(() => {
if ('clipboard' in navigator) {
copyAllowed.value = true
}
})
onUnmounted(() => {
clearTimeout(timeout)
})
</script>
<template>
<div class="form">
<form @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Wohneinheit" />
<InputGroup>
<label for="apartment-name">Bezeichnung</label>
<input id="apartment-name" type="text" v-model="state.apartmentName" :disabled="showCopyDialog" />
</InputGroup>
<SectionTitle value="Zugangsdaten" />
<MessageBox msg="Legen Sie die Zugangsdaten für die entsprechende Wohneinheit an." type="basic" />
<InputGroup>
<label for="apartment-user">Benutzername</label>
<InputWrapper :row="true">
<div class="aparment-setup-form__static primary">
<span>{{ buildings.current?.prefix }}</span>
</div>
<input id="apartment-user" type="text" v-model="state.username" :disabled="showCopyDialog" />
</InputWrapper>
<MessageBox msg="Die Gebäudekennung wird dem Nutzernamen angefügt." type="basic" />
</InputGroup>
<InputGroup>
<label for="apartment-pass">Passwort</label>
<input id="apartment-pass" type="text" v-model="state.password" :disabled="showCopyDialog" />
</InputGroup>
</div>
<div class="form-section" v-if="showCopyDialog">
<div class="aparment-setup-form__copy basic">
<div>
<span>Sie können die Benutzerinformation in die Zwischenablage kopieren, um diese Informationen dann per
Email zu übermitteln.</span>
</div>
<div class="aparment-setup-form__wrapper">
<button class="button primary" type="button" @click="copyCredentials" :disabled="!copyAllowed">
<span>In Zwischenablage kopieren</span>
</button>
<div>
<a class="aparment-setup-form__button primary" :href="buildUrl()">Per Email senden</a>
</div>
</div>
</div>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" v-if="!showCopyDialog" type="submit" :disabled="message">
<span>Erstellen</span>
</button>
<button class="button primary" v-else type="button" @click="$emit('closeModal')" :disabled="message">
<span>Schließen</span>
</button>
</div>
</form>
</div>
</template>
<style scoped>
.aparment-setup-form__copy {
padding: var(--spacing);
display: flex;
flex-direction: column;
gap: var(--spacing);
justify-content: space-between;
border-radius: var(--radius);
}
@media (min-width: 48em) {
.aparment-setup-form__copy {
flex-direction: row;
}
}
.aparment-setup-form__wrapper {
display: flex;
flex-direction: column;
gap: var(--spacing);
}
.aparment-setup-form__button {
padding: var(--spacing);
height: var(--element-size);
display: flex;
justify-content: center;
align-items: center;
border-radius: var(--radius);
cursor: pointer;
white-space: nowrap;
}
.aparment-setup-form__button:hover {
background-color: hsl(var(--clr-primary-shade));
color: var(--clr-white);
transition: var(--t-background-color);
}
.aparment-setup-form__static {
padding-inline: var(--spacing);
display: flex;
justify-content: center;
align-items: center;
border-radius: var(--radius);
}
</style>
\ No newline at end of file
<script setup>
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import CheckboxWrapper from '@/components/CheckboxWrapper.vue'
import InputGroup from '@/components/InputGroup.vue'
import InputWrapper from '@/components/InputWrapper.vue'
import MessageBox from '@/components/MessageBox.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { MESSAGES } from '@/data/messages'
import { resetAlert } from '@/helpers'
import { HEATING_TYPE_OPTIONS } from '@/data/options'
import { useApartmentStore } from '@/stores/apartments'
let timeout = null
const message = ref(null)
const messageType = ref(null)
const apartments = useApartmentStore()
// Initial values
const state = reactive({
apartmentComment: null,
area: null,
ceilingHeight: null,
centralHeating: null,
heatDemand: null,
heatingType: null,
largeHeatingElements: null,
mediumHeatingElements: null,
panelHeating: null,
powerDemand: null,
smallHeatingElements: null,
workingHeatingInstallations: null
})
const rules = computed(() => {
return {
apartmentComment: {},
area: {},
ceilingHeight: {},
centralHeating: {},
heatDemand: {},
heatingType: {},
largeHeatingElements: {},
mediumHeatingElements: {},
panelHeating: {},
powerDemand: {},
smallHeatingElements: {},
workingHeatingInstallations: {}
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
clearTimeout(timeout)
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
timeout = resetAlert(message)
return
}
const response = await apartments.updateApartmentHeating(apartments.active, state)
if (response.success) {
message.value = MESSAGES[response.message]
messageType.value = 'success'
await apartments.fetchApartments()
} else {
message.value = MESSAGES[response.message]
messageType.value = 'success'
}
timeout = resetAlert(message)
} catch (error) {
console.error('ERROR:', error.name)
}
}
onMounted(() => {
if (apartments.current) {
state.apartmentComment = apartments.current?.data.apartmentComment
state.area = apartments.current?.data.area
state.ceilingHeight = apartments.current?.data.ceilingHeight
state.centralHeating = apartments.current?.data.centralHeating
state.heatDemand = apartments.current?.data.heatDemand
state.heatingElementCondition = apartments.current?.data.heatingElementCondition
state.largeHeatingElements = apartments.current?.data.largeHeatingElements
state.mediumHeatingElements = apartments.current?.data.mediumHeatingElements
state.panelHeating = apartments.current?.data.panelHeating
state.powerDemand = apartments.current?.data.powerDemand
state.smallHeatingElements = apartments.current?.data.smallHeatingElements
}
})
onUnmounted(() => {
clearTimeout(timeout)
})
</script>
<template>
<div class="form">
<form @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Basisinformationen" />
<InputGroup :row="true">
<InputWrapper>
<InputGroup>
<label for="heating-area">Fläche (m²)</label>
<input class="number" id="heating-area" type="number" v-model="state.area" />
</InputGroup>
<InputGroup>
<label for="heating-ceiling">Raumhöhe (m)</label>
<input class="number" id="heating-ceiling" type="number" :step="0.1" v-model="state.ceilingHeight" />
</InputGroup>
</InputWrapper>
</InputGroup>
<SectionTitle value="Heizkörper" />
<InputGroup :row="true">
<InputWrapper>
<InputGroup>
<label for="heating-small">klein (bis 0.5 m²)</label>
<input class="number" id="heating-small" type="number" v-model="state.smallHeatingElements" />
</InputGroup>
<InputGroup>
<label for="heating-medium">normal (0.5 m² - 1.5 m²)</label>
<input class="number" id="heating-medium" type="number" v-model="state.mediumHeatingElements" />
</InputGroup>
<InputGroup>
<label for="heating-large">groß (ab 1.5 m²)</label>
<input class="number" id="heating-large" type="number" v-model="state.largeHeatingElements" />
</InputGroup>
</InputWrapper>
</InputGroup>
<InputGroup :row="true">
<InputGroup>
<label for="heating-working">Anzahl funktionierender Heizkörper</label>
<input class="number" id="heating-working" type="number" v-model="state.workingHeatingInstallations" />
</InputGroup>
<InputGroup :row="true">
<InputGroup>
<label for="heating-panel">Flächenheinzung (m²)</label>
<input class="number" id="heating-panel" type="number" v-model="state.panelHeating" />
<MessageBox msg="Eine Flächenheizung ist z.B. eine Fußbodenheizung oder Wandheizung." type="basic" />
</InputGroup>
</InputGroup>
</InputGroup>
<SectionTitle value="Heizkörper" />
<InputGroup>
<label for="heating-central">Zentralheizung</label>
<CheckboxWrapper value="Wird eine Zentralheizung genutzt?">
<input id="heating-central" type="checkbox" v-model="state.centralHeating" />
</CheckboxWrapper>
</InputGroup>
<InputGroup>
<label for="window-frame">Heizenergie</label>
<select id="window-frame" v-model="state.heatingType" :disabled="state.centralHeating">
<option disabled>Bitte wählen</option>
<option v-for="option in HEATING_TYPE_OPTIONS" :value="option.value" :key="option.value">
{{ option.name }}
</option>
</select>
</InputGroup>
<InputGroup>
<label for="heating-demand">Wärmebedarf Vorjahr (optional)</label>
<input class="number" id="heating-demand" type="number" v-model="state.heatDemand"
:disabled="state.centralHeating" />
</InputGroup>
<InputGroup>
<label for="heating-energy">Strombedarf Vorjahr (kWh)</label>
<input class="number" id="heating-energy" type="number" v-model="state.powerDemand" />
</InputGroup>
<InputGroup>
<label for="heating-comment">Zusätzliche Kommentare</label>
<MessageBox msg="Tragen Sie weitere Informationen zur Heizung ein." type="basic" />
<textarea id="heating-comment" :rows="5" v-model="state.apartmentComment" />
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" type="submit" :disabled="message">
<span>Speichern</span>
</button>
</div>
</form>
</div>
</template>
\ No newline at end of file
<script setup>
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import CheckboxWrapper from '@/components/CheckboxWrapper.vue'
import InputGroup from '@/components/InputGroup.vue'
import MessageBox from '@/components/MessageBox.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { MESSAGES } from '@/data/messages'
import { INSULATING_MATERIAL_OPTIONS } from '@/data/options'
import { resetAlert } from '@/helpers'
import { useBuildingStore } from '@/stores/buildings'
let timeout = null
const message = ref(null)
const messageType = ref(null)
const buildings = useBuildingStore()
// Initial values
const state = reactive({
basementInsulatingMaterial: null,
basementInsulatingMaterialThickness: 0,
basementRefurbishmentComment: '',
heatedBasement: false,
insulatedBasementCeiling: false,
insulatedBasementFloor: false
})
const rules = computed(() => {
return {
basementInsulatingMaterial: { required },
basementInsulatingMaterialThickness: { required },
basementRefurbishmentComment: {},
heatedBasement: {},
insulatedBasementCeiling: {},
insulatedBasementFloor: {}
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
clearTimeout(timeout)
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
timeout = resetAlert(message)
return
}
const response = await buildings.updateBuildingBasement(buildings.active, state)
if (response.success) {
message.value = MESSAGES[response.message]
messageType.value = 'success'
await buildings.fetchBuildings()
} else {
message.value = MESSAGES[response.message]
messageType.value = 'danger'
}
timeout = resetAlert(message)
} catch (error) {
console.error('ERROR:', error.name)
}
}
onMounted(() => {
if (buildings.current) {
state.basementInsulatingMaterial = buildings.current.data.basementInsulatingMaterial
state.basementInsulatingMaterialThickness = buildings.current.data.basementInsulatingMaterialThickness
state.basementRefurbishmentComment = buildings.current.data.basementRefurbishmentComment
state.heatedBasement = buildings.current.data.heatedBasement
state.insulatedBasementCeiling = buildings.current.data.insulatedBasementCeiling
state.insulatedBasementFloor = buildings.current.data.insulatedBasementFloor
}
})
onUnmounted(() => {
clearTimeout(timeout)
})
</script>
<template>
<div class="form">
<form @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Kellerdämmung" />
<InputGroup :row="true">
<InputGroup>
<label for="basement-material">Material</label>
<select id="basement-material" v-model="state.basementInsulatingMaterial">
<option disabled>Bitte wählen</option>
<option v-for="option in INSULATING_MATERIAL_OPTIONS" :value="option.value" :key="option.value">
{{ option.name }}
</option>
</select>
</InputGroup>
<InputGroup>
<label for="basement-thickness">Dicke Dämmstoff (cm)</label>
<input class="number" id="basement-thickness" type="number"
v-model="state.basementInsulatingMaterialThickness" />
</InputGroup>
</InputGroup>
<InputGroup :row="true">
<InputGroup>
<label for="basement-ceiling">Kellerdecke</label>
<CheckboxWrapper value="gedämmt">
<input id="basement-ceiling" type="checkbox" v-model="state.insulatedBasementCeiling" />
</CheckboxWrapper>
</InputGroup>
<InputGroup>
<label for="basement-floor">Kellerboden</label>
<CheckboxWrapper value="gedämmt">
<input id="basement-floor" type="checkbox" v-model="state.insulatedBasementFloor" />
</CheckboxWrapper>
</InputGroup>
<InputGroup>
<label for="basement-heated">Keller beheizt</label>
<CheckboxWrapper value="beheizt">
<input id="basement-heated" type="checkbox" v-model="state.heatedBasement" />
</CheckboxWrapper>
</InputGroup>
</InputGroup>
<InputGroup>
<label for="basement-comment">Zusätzliche Kommentare</label>
<MessageBox msg="Tragen Sie weitere Informationen zum Keller ein." type="basic" />
<textarea id="basement-comment" :rows="5" v-model="state.basementRefurbishmentComment" />
<MessageBox v-if="state.heatedBasement && !state.insulatedBasementFloor"
msg="Hinweis für die Bewertung: Der Kellerboden sollte gedämmt sein." type="success" />
<MessageBox v-if="!state.heatedBasement && !state.insulatedBasementCeiling"
msg="Hinweis für die Bewertung: Die Kellerdecke sollte gedämmt sein." type="success" />
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" type="submit" :disabled="message">
<span>Speichern</span>
</button>
</div>
</form>
</div>
</template>
\ No newline at end of file
<script setup>
import { computed, onUnmounted, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import InputGroup from '@/components/InputGroup.vue'
import MessageBox from '@/components/MessageBox.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { MESSAGES } from '@/data/messages'
import { resetAlert } from '@/helpers'
import { useBuildingStore } from '@/stores/buildings'
let timeout = null
const emit = defineEmits(['closeModal'])
const message = ref(null)
const messageType = ref(null)
const buildings = useBuildingStore()
// Initial values
const state = reactive({
buildingPrefix: null,
buildingName: null,
buildingStreetName: null,
buildingStreetNumber: null,
buildingZipcode: null,
buildingCity: null
})
const rules = computed(() => {
return {
buildingPrefix: { required },
buildingName: { required },
buildingStreetName: {},
buildingStreetNumber: {},
buildingZipcode: {},
buildingCity: {}
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
clearTimeout(timeout)
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
timeout = resetAlert(message)
return
}
const { buildingPrefix, buildingName, buildingStreetName, buildingStreetNumber, buildingZipcode, buildingCity } = state
const response = await buildings.createBuilding({
buildingPrefix,
buildingName,
buildingAddress: [buildingStreetName, buildingStreetNumber, buildingZipcode, buildingCity].join('::')
})
if (response.success) {
message.value = MESSAGES[response.message]
messageType.value = 'success'
await buildings.fetchBuildings()
emit('closeModal')
} else {
message.value = MESSAGES[response.message]
messageType.value = 'danger'
}
timeout = resetAlert(message)
} catch (error) {
console.error('ERROR:', error.name)
}
}
onUnmounted(() => {
clearTimeout(timeout)
})
</script>
<template>
<div class="form">
<form @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Stammdaten" />
<MessageBox
msg="Sie müssen eine Kennung wählen. Nehmen Sie zum Beispiel die ersten Buchstaben der Adresse oder wählen Sie eine beliebige Kombination. 4 bis 5 Zeichen sind empfohlen. Bitte beachten Sie, dass diese Kennung nicht mehr geändert werden kann."
type="basic" />
<InputGroup :row="true">
<InputGroup>
<label for="bf-prefix">Kennung</label>
<input id="bf-prefix" type="text" v-model="state.buildingPrefix" />
</InputGroup>
<InputGroup :stretch="true">
<label for="bf-name">Gebäudebezeichnung</label>
<input id="bf-name" type="text" v-model="state.buildingName" />
</InputGroup>
</InputGroup>
<InputGroup :row="true">
<InputGroup :stretch="true">
<label for="bf-street-name">Straße</label>
<input id="bf-street-name" type="text" v-model="state.buildingStreetName" />
</InputGroup>
<InputGroup>
<label for="bf-street-number">Hausnummer</label>
<input id="bf-street-number" type="text" v-model="state.buildingStreetNumber" />
</InputGroup>
</InputGroup>
<InputGroup :row="true">
<InputGroup>
<label for="bf-zipcode">Postleitzahl</label>
<input id="bf-zipcode" type="text" v-model="state.buildingZipcode" />
</InputGroup>
<InputGroup :stretch="true">
<label for="bf-city">Stadt</label>
<input id="bf-city" type="text" v-model="state.buildingCity" />
</InputGroup>
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" type="submit" :disabled="message">
<span>Speichern</span>
</button>
</div>
</form>
</div>
</template>
\ No newline at end of file
<script setup>
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import MessageBox from '@/components/MessageBox.vue'
import InputGroup from '@/components/InputGroup.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { MESSAGES } from '@/data/messages'
import { resetAlert } from '@/helpers'
import { useApartmentStore } from '@/stores/apartments'
import { useBuildingStore } from '@/stores/buildings'
import { useUserStore } from '@/stores/users'
const LINK = import.meta.env.VITE_APP_LINK
defineEmits(['closeModal'])
let timeout = null
const copyAllowed = ref(false)
const message = ref(null)
const messageType = ref(null)
const showCopyDialog = ref(false)
const apartments = useApartmentStore()
const buildings = useBuildingStore()
const users = useUserStore()
// Initial values
const state = reactive({
newPassword: null
})
const rules = computed(() => {
return {
newPassword: { required }
}
})
const v$ = useVuelidate(rules, state)
async function copyCredentials() {
if ('clipboard' in navigator) {
try {
await navigator.clipboard.writeText(`Benutzername: ${buildings.current?.prefix}_${state.username} Passwort: ${state.newPassword} - Anmeldung unter ${LINK}`)
} catch (error) {
console.error('ERROR:', error.name)
}
}
}
function buildUrl() {
const subject = '3% Plus - Neues Passwort erstellt'
const sender = 'Ihr Verwalter'
// DEVINFO Hier kann der E-Mail-Text zur Benachrichtigung (Passwort ändern) des Eigentümers angepasst werden
const message = `
Sehr geehrte Frau/Sehr geehrter Herr, %0D%0A%0D%0A
anbei erhalten Sie ein neues Passwort für das Tool zur Erfassung des energetischen Gebäudezustands: %0D%0A%0D%0A
Passwort: ${state.newPassword} %0D%0A%0D%0A
Bitte loggen Sie sich mit diesen Angaben unter folgendem Link ein: ${LINK} %0D%0A%0D%0A
Mit freundlichen Grüßen%0D%0A
${sender}%0D%0A%0D%0A%0D%0A
Wenn diese E-Mail nicht an Sie gerichtet ist, dann löschen Sie diese Nachricht bitte oder informieren den Absender über die falsche Zustellung.
`
return `mailto:?subject=${subject}&body=${message}`
}
async function onSubmit() {
try {
clearTimeout(timeout)
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
timeout = resetAlert(message)
return
}
const response = await users.updateUserPassword(apartments.owner._id, state)
if (response.success) {
message.value = MESSAGES[response.message]
messageType.value = 'success'
showCopyDialog.value = true
} else {
message.value = MESSAGES[response.message]
messageType.value = 'danger'
}
timeout = resetAlert(message)
} catch (error) {
console.error('ERROR:', error)
}
}
onMounted(() => {
if ('clipboard' in navigator) {
copyAllowed.value = true
}
})
onUnmounted(() => {
clearTimeout(timeout)
})
</script>
<template>
<div class="form">
<form @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Zugangsdaten" />
<MessageBox msg="Vergeben Sie ein neues Passwort für den zugewiesenen Eigentümer." type="basic" />
<InputGroup>
<label for="apartment-pass">Neues Passwort</label>
<input id="apartment-pass" type="text" v-model="state.newPassword" :disabled="showCopyDialog" />
</InputGroup>
</div>
<div class="form-section" v-if="showCopyDialog">
<div class="change-password__copy basic">
<div>
<span>Sie können die Benutzerinformation in die Zwischenablage kopieren, um diese Informationen dann per
Email zu übermitteln.</span>
</div>
<div class="change-password__wrapper">
<button class="button primary" type="button" @click="copyCredentials" :disabled="!copyAllowed">
<span>In Zwischenablage kopieren</span>
</button>
<div>
<a class="change-password__button primary" :href="buildUrl()">Per Email senden</a>
</div>
</div>
</div>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" v-if="!showCopyDialog" type="submit" :disabled="message">
<span>Speichern</span>
</button>
<button class="button primary" v-else type="button" @click="$emit('closeModal')" :disabled="message">
<span>Schließen</span>
</button>
</div>
</form>
</div>
</template>
<style scoped>
.change-password__copy {
padding: var(--spacing);
display: flex;
flex-direction: column;
gap: var(--spacing);
justify-content: space-between;
border-radius: var(--radius);
}
@media (min-width: 48em) {
.change-password__copy {
flex-direction: row;
}
}
.change-password__wrapper {
display: flex;
flex-direction: column;
gap: var(--spacing);
}
.change-password__button {
padding: var(--spacing);
height: var(--element-size);
display: flex;
justify-content: center;
align-items: center;
border-radius: var(--radius);
cursor: pointer;
white-space: nowrap;
}
.change-password__button:hover {
background-color: hsl(var(--clr-primary-shade));
color: var(--clr-white);
transition: var(--t-background-color);
}
.change-password__static {
padding-inline: var(--spacing);
display: flex;
justify-content: center;
align-items: center;
border-radius: var(--radius);
}
</style>
\ No newline at end of file
<script setup>
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import InputGroup from '@/components/InputGroup.vue'
import InputWrapper from '@/components/InputWrapper.vue'
import CheckboxWrapper from '@/components/CheckboxWrapper.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import MessageBox from '@/components/MessageBox.vue'
import { MESSAGES } from '@/data/messages'
import { resetAlert } from '@/helpers'
import { useBuildingStore } from '@/stores/buildings'
let timeout = null
const message = ref(null)
const messageType = ref(null)
const buildings = useBuildingStore()
// Initial values
const state = reactive({
characteristicsComment: null,
energyPerformanceCertificate: null,
listedBuilding: null,
livingSpace: null,
numberOfFloors: null,
yearOfConstruction: null
})
const rules = computed(() => {
return {
characteristicsComment: {},
energyPerformanceCertificate: {},
listedBuilding: {},
livingSpace: {},
numberOfFloors: {},
yearOfConstruction: {}
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
clearTimeout(timeout)
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
timeout = resetAlert(message)
return
}
const response = await buildings.updateBuildingCharacteristics(buildings.active, state)
if (response.success) {
message.value = MESSAGES[response.message]
messageType.value = 'success'
await buildings.fetchBuildings()
} else {
message.value = MESSAGES[response.message]
messageType.value = 'danger'
}
timeout = resetAlert(message)
} catch (error) {
console.error('ERROR:', error.name)
}
}
onMounted(() => {
if (buildings.current) {
state.characteristicsComment = buildings.current.data.characteristicsComment
state.energyPerformanceCertificate = buildings.current.data.energyPerformanceCertificate
state.listedBuilding = buildings.current.data.listedBuilding
state.livingSpace = buildings.current.data.livingSpace
state.numberOfFloors = buildings.current.data.numberOfFloors
state.yearOfConstruction = buildings.current.data.yearOfConstruction
}
})
onUnmounted(() => {
clearTimeout(timeout)
})
</script>
<template>
<div class="form">
<form @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Gebäudedetails" />
<InputGroup>
<label for="characteristic-yoc">Baujahr</label>
<input class="number" id="characteristic-yoc" type="number" v-model="state.yearOfConstruction" />
</InputGroup>
<InputGroup>
<label for="characteristic-listed">Ist das Gebäude denkmalgeschützt?</label>
<CheckboxWrapper value="Denkmalschutz liegt vor">
<input id="characteristic-listed" type="checkbox" v-model="state.listedBuilding" />
</CheckboxWrapper>
</InputGroup>
<InputGroup :row="true">
<InputGroup>
<label for="characteristic-floors">Stockwerke</label>
<InputWrapper>
<input class="number" id="characteristic-floors" type="number" v-model="state.numberOfFloors" />
<MessageBox msg="Geben Sie die Anzahl der Vollgeschosse ein" type="basic" />
</InputWrapper>
</InputGroup>
<InputGroup>
<label for="characteristic-area">Wohnfläche (m²) gesamt</label>
<input class="number" id="characteristic-area" type="number" v-model="state.livingSpace" />
</InputGroup>
</InputGroup>
<SectionTitle value="Energieeffizienz" />
<InputGroup>
<label for="characteristics-cert">Energieeffizienz (kWh/m²)</label>
<InputWrapper>
<input class="number" id="characteristics-cert" type="number"
v-model="state.energyPerformanceCertificate" />
<MessageBox msg="Sie können den Wert aus dem Energieausweis entnehmen." type="basic" />
</InputWrapper>
</InputGroup>
<InputGroup>
<label for="characteristic-comment">Zusätzliche Kommentare</label>
<MessageBox msg="Tragen Sie weitere Informationen zum Gebäude ein." type="basic" />
<textarea id="characteristic-comment" :rows="5" v-model="state.characteristicsComment" />
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" type="submit" :disabled="message">
<span>Speichern</span>
</button>
</div>
</form>
</div>
</template>
\ No newline at end of file
<script setup>
import { computed, onMounted, onUnmounted, onUpdated, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import CheckboxWrapper from '@/components/CheckboxWrapper.vue'
import InputGroup from '@/components/InputGroup.vue'
import InputWrapper from '@/components/InputWrapper.vue'
import MessageBox from '@/components/MessageBox.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { MESSAGES } from '@/data/messages'
import { resetAlert } from '@/helpers'
import { BUILDING_MATERIAL_OPTIONS, INSULATING_MATERIAL_OPTIONS } from '@/data/options'
import { useBuildingStore } from '@/stores/buildings'
let timeout = null
const message = ref(null)
const messageType = ref(null)
const buildings = useBuildingStore()
// Initial values
const state = reactive({
buildingStructure: null,
buildingStructureThickness: null,
facadeEast: true,
facadeInsulatingMaterial: null,
facadeInsulatingMaterialThickness: null,
facadeNorth: true,
facadeRefurbishmentComment: '',
facadeSouth: true,
facadeWest: true
})
const rules = computed(() => {
return {
buildingStructure: {},
buildingStructureThickness: {},
facadeEast: {},
facadeInsulatingMaterial: {},
facadeInsulatingMaterialThickness: {},
facadeNorth: {},
facadeRefurbishmentComment: {},
facadeSouth: {},
facadeWest: {}
}
})
const v$ = useVuelidate(rules, state)
function resetInsulatedSides() {
if (!state.facadeInsulatingMaterial) {
state.facadeEast = false
state.facadeNorth = false
state.facadeSouth = false
state.facadeWest = false
} else {
state.facadeEast = true
state.facadeNorth = true
state.facadeSouth = true
state.facadeWest = true
}
}
async function onSubmit() {
try {
clearTimeout(timeout)
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
timeout = resetAlert(message)
return
}
const { facadeInsulatingMaterial, facadeInsulatingMaterialThickness } = state
const requestData = {
...state,
facadeInsulatingMaterialThickness: facadeInsulatingMaterial ? facadeInsulatingMaterialThickness : null
}
const response = await buildings.updateBuildingFacade(buildings.active, requestData)
if (response.success) {
message.value = MESSAGES[response.message]
messageType.value = 'success'
await buildings.fetchBuildings()
} else {
message.value = MESSAGES[response.message]
messageType.value = 'danger'
}
timeout = resetAlert(message)
} catch (error) {
console.error('ERROR:', error)
}
}
onMounted(() => {
if (buildings.current) {
state.buildingStructure = buildings.current.data.buildingStructure
state.buildingStructureThickness = buildings.current.data.buildingStructureThickness
state.facadeEast = buildings.current.data.facadeEast || true
state.facadeInsulatingMaterial = buildings.current.data.facadeInsulatingMaterial
state.facadeInsulatingMaterialThickness = buildings.current.data.facadeInsulatingMaterialThickness
state.facadeNorth = buildings.current.data.facadeNorth || true
state.facadeRefurbishmentComment = buildings.current.data.facadeRefurbishmentComment
state.facadeSouth = buildings.current.data.facadeSouth || true
state.facadeWest = buildings.current.data.facadeWest || true
}
})
onUnmounted(() => {
clearTimeout(timeout)
})
</script>
<template>
<div class="form">
<form @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Fassadendämmung" />
<InputGroup :row="true">
<InputGroup>
<label for="facade-material">Material</label>
<select id="facade-material" v-model="state.facadeInsulatingMaterial" @change="resetInsulatedSides">
<option disabled>Bitte wählen</option>
<option v-for="option in INSULATING_MATERIAL_OPTIONS" :value="option.value" :key="option.value">
{{ option.name }}
</option>
</select>
</InputGroup>
<InputGroup>
<label for="facade-thickness">Dicke Dämmstoff (cm)</label>
<input class="number" id="facade-thickness" type="number" v-model="state.facadeInsulatingMaterialThickness"
:disabled="state.facadeInsulatingMaterial === null" />
</InputGroup>
</InputGroup>
<SectionTitle value="Baustruktur" />
<InputGroup :row="true">
<InputGroup>
<label for="facade-wall">Material</label>
<select id="facade-wall" v-model="state.buildingStructure">
<option disabled>Bitte wählen</option>
<option v-for="option in BUILDING_MATERIAL_OPTIONS" :value="option.value" :key="option.value">
{{ option.name }}
</option>
</select>
</InputGroup>
<InputGroup>
<label for="facade-wall-thickness">Dicke Fassade (cm)</label>
<InputWrapper>
<input class="number" id="facade-wall-thickness" type="number"
v-model="state.buildingStructureThickness" />
<MessageBox msg="Geben Sie die Gesamtdicke der Außenwand ein." type="basic" />
</InputWrapper>
</InputGroup>
</InputGroup>
<SectionTitle value="Seitendämmung" />
<MessageBox msg="Geben Sie bitte an, welche Seiten gedämmt sind." type="basic" />
<InputGroup :row="true">
<InputGroup>
<label for="facade-north">Nord</label>
<CheckboxWrapper value="gedämmt">
<input id="facade-north" type="checkbox" v-model="state.facadeNorth" />
</CheckboxWrapper>
</InputGroup>
<InputGroup>
<label for="facade-west">West</label>
<CheckboxWrapper value="gedämmt">
<input id="facade-west" type="checkbox" v-model="state.facadeWest" />
</CheckboxWrapper>
</InputGroup>
<InputGroup>
<label for="facade-south">Süd</label>
<CheckboxWrapper value="gedämmt">
<input id="facade-south" type="checkbox" v-model="state.facadeSouth" />
</CheckboxWrapper>
</InputGroup>
<InputGroup>
<label for="facade-east">Ost</label>
<CheckboxWrapper value="gedämmt">
<input id="facade-east" type="checkbox" v-model="state.facadeEast" />
</CheckboxWrapper>
</InputGroup>
</InputGroup>
<InputGroup>
<label for="facade-comment">Zusätzliche Kommentare</label>
<MessageBox msg="Tragen Sie weitere Informationen zu den eingebauten Dämmstoffen ein." type="basic" />
<textarea id="facade-comment" :rows="5" v-model="state.facadeRefurbishmentComment" />
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" type="submit" :disabled="message">
<span>Speichern</span>
</button>
</div>
</form>
</div>
</template>
\ No newline at end of file
<script setup>
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import CheckboxWrapper from '@/components/CheckboxWrapper.vue'
import InputGroup from '@/components/InputGroup.vue'
import InputWrapper from '@/components/InputWrapper.vue'
import MessageBox from '@/components/MessageBox.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { MESSAGES } from '@/data/messages'
import { HEATING_INSTALLATION_OPTIONS } from '@/data/options'
import { convertHeatConsumption, resetAlert } from '@/helpers'
import { useBuildingStore } from '@/stores/buildings'
let timeout = null
const message = ref(null)
const messageType = ref(null)
const buildings = useBuildingStore()
// Initial values
const state = reactive({
heatingConsumption: null,
heatingInstallation: null,
heatingInstallationComment: null,
photovoltaic: false,
photovoltaicArea: null,
photovoltaicYield: null,
pipeSystem: false,
selfContainedCentralHeating: false,
solarHeat: false,
solarHeatArea: null
})
const rules = computed(() => {
return {
heatingConsumption: {},
heatingInstallation: {},
heatingInstallationComment: {},
photovoltaic: {},
photovoltaicArea: {},
photovoltaicYield: {},
pipeSystem: {},
selfContainedCentralHeating: {},
solarHeat: {},
solarHeatArea: {}
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
clearTimeout(timeout)
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
timeout = resetAlert(message)
return
}
const {
heatingConsumption,
heatingInstallation,
heatingInstallationComment,
pipeSystem,
photovoltaic,
photovoltaicArea,
photovoltaicYield,
selfContainedCentralHeating,
solarHeat,
solarHeatArea,
} = state
const response = await buildings.updateBuildingHeating(buildings.active, {
heatingConsumption: !selfContainedCentralHeating ? heatingConsumption : 0,
heatingInstallation: !selfContainedCentralHeating ? heatingInstallation : null,
heatingInstallationComment,
pipeSystem,
photovoltaic,
photovoltaicArea,
photovoltaicYield,
selfContainedCentralHeating,
solarHeat,
solarHeatArea,
})
if (response.success) {
message.value = MESSAGES[response.message]
messageType.value = 'success'
await buildings.fetchBuildings()
} else {
message.value = MESSAGES[response.message]
messageType.value = 'danger'
}
timeout = resetAlert(message)
} catch (error) {
console.error('ERROR:', error.name)
}
}
onMounted(() => {
if (buildings.current) {
state.heatingConsumption = buildings.current.data.heatingConsumption
state.heatingInstallation = buildings.current.data.heatingInstallation
state.heatingInstallationComment = buildings.current.data.heatingInstallationComment
state.pipeSystem = buildings.current.data.pipeSystem
state.photovoltaic = buildings.current.data.photovoltaic
state.photovoltaicArea = buildings.current.data.photovoltaicArea
state.photovoltaicYield = buildings.current.data.photovoltaicYield
state.selfContainedCentralHeating = buildings.current.data.selfContainedCentralHeating
state.solarHeat = buildings.current.data.solarHeat
state.solarHeatArea = buildings.current.data.solarHeatArea
}
})
onUnmounted(() => {
clearTimeout(timeout)
})
</script>
<template>
<div class="form">
<form @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Heizungssyteme" />
<InputGroup :row="true">
<InputGroup :stretch="true">
<label for="heating-type">Heizsystem</label>
<select id="heating-type" v-model="state.heatingInstallation" :disabled="state.selfContainedCentralHeating">
<option disabled>Bitte wählen</option>
<option v-for="option in HEATING_INSTALLATION_OPTIONS" :value="option.value" :key="option.value">
{{ option.name }}
</option>
</select>
</InputGroup>
<InputGroup>
<label for="heating-system">Etagenheizung</label>
<CheckboxWrapper value="Etagenheizung wird genutzt">
<input id="heating-system" type="checkbox" v-model="state.selfContainedCentralHeating" />
</CheckboxWrapper>
</InputGroup>
</InputGroup>
<InputGroup>
<label for="heating-pipes">1-Rohrsystem</label>
<CheckboxWrapper
value="Wählen Sie 1-Rohrsystem, wenn die Wohneinheit nicht mit einem modernen 2-Rohrsystem ausgestattet ist.">
<input id="heating-pipes" type="checkbox" v-model="state.pipeSystem" />
</CheckboxWrapper>
</InputGroup>
<InputGroup>
<label for="heating-usage">Wärmebedarf Gebäude Vorjahr (kWh/m³/l/kg)</label>
<InputWrapper>
<input class="number" id="heating-usage" type="number" v-model="state.heatingConsumption"
:disabled="state.selfContainedCentralHeating" />
<MessageBox :msg="`= ${convertHeatConsumption(state.heatingConsumption, state.heatingInstallation)} kWh`"
type="basic" />
</InputWrapper>
</InputGroup>
<InputGroup :row="true">
<InputGroup>
<label for="heating-solar">Ist Solarthermie vorhanden?</label>
<CheckboxWrapper value="vorhanden">
<input id="heating-solar" type="checkbox" v-model="state.solarHeat" />
</CheckboxWrapper>
</InputGroup>
<InputGroup>
<label for="heating-solar-area">Fläche (m²)</label>
<input class="number" id="heating-solar-area" type="number" v-model="state.solarHeatArea"
:disabled="!state.solarHeat" />
</InputGroup>
</InputGroup>
<InputGroup :row="true">
<InputGroup>
<label for="heating-pv">Ist Photovoltaik vorhanden?</label>
<CheckboxWrapper value="vorhanden">
<input id="heating-pv" type="checkbox" v-model="state.photovoltaic" />
</CheckboxWrapper>
</InputGroup>
<InputGroup>
<label for="heating-pv-yield">Ertrag Vorjahr (kWh)</label>
<input class="number" id="heating-pv-yield" type="number" v-model="state.photovoltaicYield"
:disabled="!state.photovoltaic" />
</InputGroup>
<InputGroup>
<label for="heating-pv-area">Größe (m²)</label>
<input class="number" id="heating-pv-area" type="number" v-model="state.photovoltaicArea"
:disabled="!state.photovoltaic" />
</InputGroup>
</InputGroup>
<InputGroup>
<label for="heating-comment">Zusätzliche Kommentare</label>
<MessageBox msg="Tragen Sie weitere Informationen zum Heizsystem ein." type="basic" />
<textarea id="heating-comment" :rows="5" v-model="state.heatingInstallationComment" />
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" type="submit" :disabled="message">
<span>Speichern</span>
</button>
</div>
</form>
</div>
</template>
\ No newline at end of file
<script setup>
import { computed, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import { useRouter } from 'vue-router'
import MessageBox from '@/components/MessageBox.vue'
import InputGroup from '@/components/InputGroup.vue'
import { MESSAGES } from '@/data/messages'
import { getTokenPayload, ResponseStatus } from '@/helpers'
import { auth as api } from '@/services/api'
import { useSessionStore } from '@/stores/session'
const props = defineProps(['msg'])
const message = ref(null)
const waiting = ref(false)
const router = useRouter()
const session = useSessionStore()
// Initial values
const state = reactive({
emailOrUsername: null,
password: null
})
const rules = computed(() => {
return {
emailOrUsername: { required },
password: { required }
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
return
}
waiting.value = true
const response = await api.login(state)
if (response?.status === ResponseStatus.Success) {
if (response.data?.token) {
const payload = getTokenPayload(response.data?.token)
session.setUser({ role: payload.role, userId: payload.userId }, true)
waiting.value = false
if (payload.role === 'administrator') {
router.push({
name: 'buildings'
})
} else if (payload.role === 'user') {
router.push({
name: 'apartments'
})
}
return
}
}
message.value = MESSAGES[response.code]
waiting.value = false
} catch (error) {
console.error('ERROR:', error.name)
}
}
</script>
<template>
<div class="form form-bg shadow">
<form @submit.prevent="onSubmit">
<div class="form-content">
<InputGroup>
<label for="login-username">E-Mail oder Benutzername</label>
<input id="login-username" type="text" v-model="state.emailOrUsername" />
</InputGroup>
<InputGroup>
<label for="login-password">Passwort</label>
<input id="login-password" type="password" v-model="state.password" />
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message || props.msg" :msg="message || props.msg" :type="props.msg ? 'warning' : 'danger'" />
<button class="button primary" type="submit" :disabled="waiting">Anmelden</button>
</div>
</form>
<div class="section center">
<router-link class="link" to="/reset-password">Password vergessen?</router-link>
</div>
</div>
</template>
\ No newline at end of file
<script setup>
import { computed, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import InputGroup from '@/components/InputGroup.vue'
import MessageBox from '@/components/MessageBox.vue'
import { MESSAGES } from '@/data/messages'
import { ResponseStatus } from '@/helpers'
import { auth as api } from '@/services/api'
const emit = defineEmits(['onSuccess'])
const props = defineProps(['gmlId'])
const message = ref(null)
const tosAccepted = ref(false)
// Initial values
const state = reactive({
email: null,
gmlId: props.gmlId || null,
password: null
})
const rules = computed(() => {
return {
email: { required },
gmlId: {},
password: { required }
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
return
}
const response = await api.register(state)
if (response.status === ResponseStatus.Success) {
emit('onSuccess', response.data?.confirmRequired)
} else {
message.value = MESSAGES[response.code]
}
} catch (error) {
console.error('ERROR:', error.name)
}
}
</script>
<template>
<div class="form form-bg shadow">
<form @submit.prevent="onSubmit">
<div class="form-content">
<InputGroup>
<label for="register-user">E-Mail</label>
<input id="register-user" type="email" v-model="state.email" />
</InputGroup>
<InputGroup>
<label for="register-password">Passwort</label>
<MessageBox msg="Wählen Sie min. 8 Zeichen." type="basic" autocomplete="email" />
<input id="register-password" type="password" v-model="state.password" autocomplete="new-password" />
</InputGroup>
<InputGroup>
<label for="register-gmlid">GML Id (optional)</label>
<MessageBox msg="Wenn Sie die GML Id nicht zur Verfügung haben, können Sie diese auch später eintragen."
type="basic" />
<input id="register-gmlid" type="text" v-model="state.gmlId" autocomplete="off" />
</InputGroup>
</div>
<div class="form-section">
<div class="registration-form__terms">
<input type="checkbox" v-model="tosAccepted" />
<span>
Wenn Sie ein Konto erstellen, stimmen Sie den <router-link class="link" to="/terms">Nutzungsbedingungen
</router-link> zu. Weitere Informationen über die Datenschutzpraktiken finden Sie in der <router-link
class="link" to="/privacy">Datenschutzerklärung</router-link>.
</span>
</div>
<MessageBox v-if="message" :msg="message" type="danger" />
<button class="button primary" type="submit" :disabled="!tosAccepted">Konto erstellen</button>
</div>
</form>
</div>
</template>
<style scoped>
.registration-form {
background-color: hsl(var(--clr-content));
padding: var(--spacing);
display: flex;
flex-direction: column;
gap: var(--spacing);
border-radius: var(--radius);
}
.registration-form__terms {
background-color: hsl(var(--clr-background));
padding: var(--spacing-s);
display: flex;
gap: var(--spacing-s);
align-items: center;
border-radius: var(--radius);
}
.registration-form__terms>span {
font-size: var(--text-s);
}
</style>
\ No newline at end of file
<script setup>
import { computed, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import InputGroup from '@/components/InputGroup.vue'
import MessageBox from '@/components/MessageBox.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { MESSAGES } from '@/data/messages'
import { ResponseStatus } from '@/helpers'
import { auth as api } from '@/services/api'
const found = ref(false)
const message = ref(null)
const messageType = ref(null)
// Initial values
const state = reactive({
email: null,
})
const rules = computed(() => {
return {
email: { required }
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
return
}
const response = await api.resetPassword(state)
if (response.status === ResponseStatus.Success) {
found.value = true
} else {
message.value = MESSAGES['NOT_FOUND']
messageType.value = 'danger'
}
} catch (error) {
console.error('ERROR:', error.name)
}
}
</script>
<template>
<div class="form form-bg shadow">
<form v-if="!found" @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Passwort vergessen?" />
<MessageBox
msg="Bitte geben Sie Ihre E-Mail-Adresse ein mit der Sie Ihr Konto erstellt haben. Sie erhalten eine Bestätigungsmail und werden aufgefordert ein neues Passwort einzugeben."
type="basic" />
<InputGroup>
<label for="reset-email">E-Mail</label>
<input id="reset-email" type="email" v-model="state.email" />
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" type="submit">Abschicken</button>
<a class="button primary" href="/" alt="login">Zum Login</a>
</div>
</form>
<div v-else class="reset-form__confirmation">
<SectionTitle value="Bestätigungsmail verschickt" />
<MessageBox
msg="Bitte überprüfen Sie Ihr E-Mail-Postfach. Sie erhalten eine Bestätigungsmail und werden aufgefordert ein neues Passwort einzugeben."
type="success" />
<a class="button primary" href="/" alt="login">Zum Login</a>
</div>
</div>
</template>
<style scoped>
.reset-form__confirmation {
padding: var(--spacing);
display: flex;
flex-direction: column;
gap: var(--spacing);
}
</style>
\ No newline at end of file
<script setup>
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import CheckboxWrapper from '@/components/CheckboxWrapper.vue'
import InputGroup from '@/components/InputGroup.vue'
import MessageBox from '@/components/MessageBox.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { MESSAGES } from '@/data/messages'
import { ROOF_CLOUDING_OPTIONS, INSULATING_MATERIAL_OPTIONS } from '@/data/options'
import { resetAlert } from '@/helpers'
import { useBuildingStore } from '@/stores/buildings'
let timeout = null
const message = ref(null)
const messageType = ref(null)
const buildings = useBuildingStore()
// Initial values
const state = reactive({
clouding: null,
flatRoof: null,
heatedAttic: null,
roofArea: null,
roofInsulatingMaterial: null,
roofInsulatingMaterialThickness: null,
roofRefurbishmentComment: null
})
const rules = computed(() => {
return {
clouding: {},
flatRoof: {},
heatedAttic: {},
roofArea: {},
roofInsulatingMaterial: { required },
roofInsulatingMaterialThickness: { required },
roofRefurbishmentComment: {}
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
clearTimeout(timeout)
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
timeout = resetAlert(message)
return
}
const response = await buildings.updateBuildingRoof(buildings.active, state)
if (response.success) {
message.value = MESSAGES[response.message]
messageType.value = 'success'
await buildings.fetchBuildings()
} else {
message.value = MESSAGES[response.message]
messageType.value = 'danger'
}
timeout = resetAlert(message)
} catch (error) {
console.error('ERROR:', error.name)
}
}
onMounted(() => {
if (buildings.current) {
state.clouding = buildings.current?.data.clouding
state.flatRoof = buildings.current?.data.flatRoof
state.heatedAttic = buildings.current?.data.heatedAttic
state.roofArea = buildings.current?.data.roofArea
state.roofInsulatingMaterial = buildings.current?.data.roofInsulatingMaterial
state.roofInsulatingMaterialThickness = buildings.current?.data.roofInsulatingMaterialThickness
state.roofRefurbishmentComment = buildings.current?.data.roofRefurbishmentComment
}
})
onUnmounted(() => {
clearTimeout(timeout)
})
</script>
<template>
<div class="form">
<form @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Dachtyp" />
<InputGroup>
<label for="roof-type">Flachdach</label>
<CheckboxWrapper value="Bitte geben Sie an, ob das Gebäude ein Flachdach hat.">
<input id="roof-type" type="checkbox" v-model="state.flatRoof" />
</CheckboxWrapper>
</InputGroup>
<SectionTitle value="Dämmstoff" />
<InputGroup :row="true">
<InputGroup>
<label for="roof-material">Material</label>
<select id="roof-material" v-model="state.roofInsulatingMaterial">
<option disabled>Bitte wählen</option>
<option v-for="option in INSULATING_MATERIAL_OPTIONS" :value="option.value" :key="option.value">
{{ option.name }}
</option>
</select>
</InputGroup>
<InputGroup>
<label for="roof-material-thickness">Dicke Dämmung (cm)</label>
<input class="number" id="roof-material-thickness" type="number"
v-model="state.roofInsulatingMaterialThickness" :disabled="!state.roofInsulatingMaterial" />
</InputGroup>
</InputGroup>
<SectionTitle value="Dachfläche" />
<InputGroup :row="true">
<InputGroup>
<label for="roof-clouding">Verschattung</label>
<select id="roof-clouding" v-model="state.clouding" :disabled="state.flatRoof">
<option disabled>Bitte wählen</option>
<option v-for="option in ROOF_CLOUDING_OPTIONS" :value="option.value" :key="option.value">
{{ option.name }}
</option>
</select>
</InputGroup>
<InputGroup>
<label for="roof-area">Dachfläche (m²)</label>
<input class="number" id="roof-area" type="number" v-model="state.roofArea" />
</InputGroup>
<InputGroup>
<label for="roof-heated">Dachboden beheizt</label>
<CheckboxWrapper value="beheizt">
<input id="roof-heated" type="checkbox" v-model="state.heatedAttic" />
</CheckboxWrapper>
</InputGroup>
</InputGroup>
<InputGroup>
<label for="roof-comment">Zusätzliche Kommentare</label>
<MessageBox msg="Tragen Sie weitere Informationen zum Dach und der verwendeten Dämmung an." type="basic" />
<textarea id="roof-comment" :rows="5" v-model="state.roofRefurbishmentComment" />
<MessageBox
msg="Hinweis für die Bewertung: Wenn der Dachboden beheizt ist, sollte das Dach gedämmt sein, falls nicht die oberste Geschossdecke."
type="success" />
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" type="submit" :disabled="message">
<span>Speichern</span>
</button>
</div>
</form>
</div>
</template>
\ No newline at end of file
<script setup>
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import InputGroup from '@/components/InputGroup.vue'
import InputWrapper from '@/components/InputWrapper.vue'
import MessageBox from '@/components/MessageBox.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { MESSAGES } from '@/data/messages'
import { randomPrefix, resetAlert } from '@/helpers'
import { useBuildingStore } from '@/stores/buildings'
let timeout = null
const emit = defineEmits(['closeModal', 'setupCompleted'])
const message = ref(null)
const messageType = ref(null)
const buildings = useBuildingStore()
const state = reactive({
buildingCity: '',
buildingGmlId: null,
buildingName: '',
buildingPrefix: null,
buildingStreetName: '',
buildingStreetNumber: '',
buildingZipcode: ''
})
const rules = computed(() => {
return {
buildingCity: {},
buildingGmlId: {},
buildingName: { required },
buildingPrefix: { required },
buildingStreetName: {},
buildingStreetNumber: {},
buildingZipcode: {}
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
clearTimeout(timeout)
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
timeout = resetAlert(message)
return
}
const { buildingCity, buildingGmlId, buildingName, buildingPrefix, buildingStreetName, buildingStreetNumber, buildingZipcode } = state
const response = await buildings.updateBuilding(buildings.firstBuilding._id, {
buildingPrefix,
buildingName,
buildingAddress: [buildingStreetName, buildingStreetNumber, buildingZipcode, buildingCity].join('::'),
buildingGmlId
})
if (response.success) {
await buildings.fetchBuildings()
buildings.setActiveBuilding(buildings.firstBuilding._id)
emit('closeModal')
emit('setupCompleted')
} else {
message.value = MESSAGES[response.message]
messageType.value = 'danger'
}
timeout = resetAlert(message)
} catch (error) {
console.error('ERROR:', error.name)
}
}
onMounted(() => {
state.buildingPrefix = randomPrefix()
})
onUnmounted(() => {
clearTimeout(timeout)
})
</script>
<template>
<div class="initial-setup">
<form @submit.prevent="onSubmit" class="initial-setup__form">
<div class="form-content">
<SectionTitle value="Stammdaten" />
<InputGroup :row="true">
<InputGroup>
<label for="setup-user">Kennung</label>
<input id="setup-user" type="text" v-model="state.buildingPrefix" />
</InputGroup>
<InputGroup :stretch="true">
<label for="setup-user">Gebäudebezeichnung</label>
<input id="setup-user" type="text" v-model="state.buildingName" />
</InputGroup>
</InputGroup>
<MessageBox
msg="Sie müssen eine Kennung wählen. Nehmen Sie zum Beispiel die ersten Buchstaben der Adresse oder wählen Sie eine beliebige Kombination. 4 bis 5 Zeichen sind empfohlen. Bitte beachten Sie, dass diese Kennung nicht mehr geändert werden kann."
type="basic" />
<InputGroup :row="true">
<InputGroup :stretch="true">
<label for="setup-user">Straße</label>
<input id="setup-user" type="text" v-model="state.buildingStreetName" />
</InputGroup>
<InputGroup>
<label for="setup-user">Hausnummer</label>
<input id="setup-user" type="text" v-model="state.buildingStreetNumber" />
</InputGroup>
</InputGroup>
<InputGroup :row="true">
<InputGroup>
<label for="setup-user">Postleitzahl</label>
<input id="setup-user" type="text" v-model="state.buildingZipcode" />
</InputGroup>
<InputGroup :stretch="true">
<label for="setup-user">Stadt</label>
<input id="setup-user" type="text" v-model="state.buildingCity" />
</InputGroup>
</InputGroup>
<SectionTitle value="Optional" />
<InputGroup>
<label for="setup-user">GML Id</label>
<InputWrapper>
<input id="setup-user" type="text" v-model="state.buildingGmlId" />
<MessageBox msg="Sie können die GML Id aus dem Crowdsourcing Tool (CS-T) beziehen." type="basic" />
</InputWrapper>
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" type="submit" :disabled="message">
<span>Speichern</span>
</button>
</div>
</form>
</div>
</template>
<style scoped>
.initial-setup {
overflow-y: auto;
flex: 1;
display: flex;
flex-direction: column;
}
.initial-setup__form {
flex: 1;
display: flex;
flex-direction: column;
}
</style>
\ No newline at end of file
<script setup>
import { computed, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import InputGroup from '@/components/InputGroup.vue'
import MessageBox from '@/components/MessageBox.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { MESSAGES } from '@/data/messages'
import { ResponseStatus } from '@/helpers'
import { auth as api } from '@/services/api'
const props = defineProps(['token'])
const found = ref(false)
const message = ref(null)
const messageType = ref(null)
const router = useRouter()
// Initial values
const state = reactive({
password: null,
passwordRepeat: null
})
const rules = computed(() => {
return {
password: { required },
passwordRepeat: { required }
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
return
}
const response = await api.updatePassword(props.token, state)
if (response.status === ResponseStatus.Success) {
router.push({ name: 'landing' })
} else {
message.value = 'Wrong E-Mail'
messageType.value = 'danger'
}
} catch (error) {
console.error('ERROR:', error)
}
}
</script>
<template>
<div class="form form-bg shadow">
<form v-if="!found" @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Passwort aktualisieren" />
<InputGroup>
<label for="update-password">Neues Passwort</label>
<input id="update-password" type="password" v-model="state.password" />
</InputGroup>
<InputGroup>
<label for="update-password-repeat">Neues Passwort wiederholen</label>
<input id="update-password-repeat" type="password" v-model="state.passwordRepeat" />
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" type="submit">Aktualisieren</button>
</div>
</form>
</div>
</template>
<style scoped>
</style>
<script setup>
import { computed, onMounted, onUnmounted, reactive, ref } from 'vue'
import useVuelidate from '@vuelidate/core'
import { required } from '@vuelidate/validators'
import InputGroup from '@/components/InputGroup.vue'
import InputWrapper from '@/components/InputWrapper.vue'
import MessageBox from '@/components/MessageBox.vue'
import SectionTitle from '@/components/SectionTitle.vue'
import { MESSAGES } from '@/data/messages'
import { resetAlert } from '@/helpers'
import { WINDOW_CONDITION_OPTIONS, WINDOW_FRAME_OPTIONS, WINDOW_GLAZING_OPTIONS } from '@/data/options'
import { useApartmentStore } from '@/stores/apartments'
let timeout = null
const message = ref(null)
const messageType = ref(null)
const apartments = useApartmentStore()
// Initial values
const state = reactive({
averageWindowAge: null,
averageWindowCondition: null,
largeWindows: null,
mediumWindows: null,
roofWindows: null,
smallWindows: null,
windowComment: null,
windowFrame: null,
windowGlazing: null
})
const rules = computed(() => {
return {
averageWindowAge: { required },
averageWindowCondition: { required },
largeWindows: {},
mediumWindows: {},
roofWindows: {},
smallWindows: {},
windowComment: {},
windowFrame: {},
windowGlazing: { required }
}
})
const v$ = useVuelidate(rules, state)
async function onSubmit() {
try {
clearTimeout(timeout)
message.value = null
const isValid = await v$.value.$validate()
if (!isValid) {
message.value = MESSAGES['INVALID_INPUT']
messageType.value = 'warning'
timeout = resetAlert(message)
return
}
const response = await apartments.updateApartmentWindows(apartments.active, state)
if (response.success) {
message.value = MESSAGES[response.message]
messageType.value = 'success'
await apartments.fetchApartments()
} else {
message.value = MESSAGES[response.message]
messageType.value = 'danger'
}
timeout = resetAlert(message)
} catch (error) {
console.error('ERROR:', error.name)
}
}
onMounted(() => {
if (apartments.current) {
state.averageWindowAge = apartments.current.data.averageWindowAge
state.averageWindowCondition = apartments.current.data.averageWindowCondition
state.largeWindows = apartments.current.data.largeWindows
state.mediumWindows = apartments.current.data.mediumWindows
state.roofWindows = apartments.current.data.roofWindows
state.smallWindows = apartments.current.data.smallWindows
state.windowComment = apartments.current.data.windowComment
state.windowFrame = apartments.current.data.windowFrame
state.windowGlazing = apartments.current.data.windowGlazing
}
})
onUnmounted(() => {
clearTimeout(timeout)
})
</script>
<template>
<div class="form">
<form @submit.prevent="onSubmit">
<div class="form-content">
<SectionTitle value="Art der Fenster" />
<InputGroup :row="true">
<InputWrapper>
<InputGroup>
<label for="window-small">Klein (bis 1 m²)</label>
<input class="number" id="window-small" type="number" v-model="state.smallWindows" />
</InputGroup>
</InputWrapper>
</InputGroup>
<InputGroup :row="true">
<InputWrapper>
<InputGroup>
<label for="window-medium">Normal (1-2 m²)</label>
<input class="number" id="window-medium" type="number" v-model="state.mediumWindows" />
</InputGroup>
</InputWrapper>
</InputGroup>
<InputGroup :row="true">
<InputWrapper>
<InputGroup>
<label for="window-large">Groß (ab 2 m²)</label>
<input class="number" id="window-large" type="number" v-model="state.largeWindows" />
</InputGroup>
</InputWrapper>
</InputGroup>
<InputGroup :row="true">
<InputWrapper>
<InputGroup>
<label for="window-roof">Dach (1-2 m²)</label>
<input class="number" id="window-roof" type="number" v-model="state.roofWindows" />
</InputGroup>
</InputWrapper>
</InputGroup>
<InputGroup :row="true">
<InputGroup>
<label for="window-frame">Rahmenart</label>
<select id="window-frame" v-model="state.windowFrame">
<option disabled>Bitte wählen</option>
<option v-for="option in WINDOW_FRAME_OPTIONS" :value="option.value" :key="option.value">
{{ option.name }}
</option>
</select>
</InputGroup>
<InputGroup>
<label for="window-glazing">Verglasung</label>
<select id="window-glazing" v-model="state.windowGlazing">
<option disabled>Bitte wählen</option>
<option v-for="option in WINDOW_GLAZING_OPTIONS" :value="option.value" :key="option.value">
{{ option.name }}
</option>
</select>
</InputGroup>
</InputGroup>
<InputGroup :row="true">
<InputGroup>
<label for="window-condition">Zustand</label>
<select id="window-condition" v-model="state.averageWindowCondition">
<option disabled>Bitte wählen</option>
<option v-for="option in WINDOW_CONDITION_OPTIONS" :value="option.value" :key="option.value">
{{ option.name }}
</option>
</select>
</InputGroup>
<InputGroup>
<label for="window-age">Durchschnittliches Fensteralter</label>
<input class="number" id="window-age" type="number" v-model="state.averageWindowAge" />
</InputGroup>
</InputGroup>
<InputGroup>
<label for="window-comment">Zusätzliche Kommentare</label>
<MessageBox msg="Tragen Sie weitere Informationen zu den Fenstern ein." type="basic" />
<textarea id="window-comment" :rows="5" v-model="state.windowComment" />
</InputGroup>
</div>
<div class="form-section">
<MessageBox v-if="message" :msg="message" :type="messageType" />
<button class="button primary" type="submit" :disabled="message">
<span>Speichern</span>
</button>
</div>
</form>
</div>
</template>
\ No newline at end of file
export const MESSAGES = {
'CONFIRMATION_COMPLETED': 'Sie können sich jetzt einloggen.',
'CONFIRMATION_REQUIRED': 'Bitte verifizieren Sie Ihre E-Mail.',
'EMAIL_ALREADY_IN_USE': 'E-Mail wird bereits verwendet.',
'EMAIL_OR_PASSWORD_WRONG': 'E-Mail/Benutzername oder Passwort falsch.',
'ITEM_CREATED': 'Erstellung erfolgreich.',
'INVALID_INPUT': 'Überprüfen Sie alle Eingabefelder.',
'LOADING_DATA': 'Daten werden geladen ...',
'NO_DATA_AVAILABLE': 'Keine Daten verfügbar',
'NO_INTERNET_CONNECTION': 'Bitte Ihre Internetverbindung überprüfen.',
'PREFIX_UNAVAILABLE': 'Kennung bereits vergeben.',
'REGISTRATION_SUCCESSFUL': 'Sie können sich jetzt einloggen.',
'TOKEN_INVALID': 'Das Token ist nicht mehr gültig.',
'UPDATE_SUCCESSFUL': 'Daten erfolgreich aktualisiert.',
'VALIDATION_ERROR': 'Daten konnten nicht gespeichert werden.',
'WAITING_FOR_DATA': 'Es werden mehr Daten benötigt.',
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment