Setup wizard for Settings
This commit is contained in:
parent
5d9007f517
commit
8880af2880
11 changed files with 622 additions and 60 deletions
48
src/components/CheckProgressBar.vue
Normal file
48
src/components/CheckProgressBar.vue
Normal file
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<div class="w-full flex flex-row items-center">
|
||||
<div class="contents" v-for="(i, index) in total" :key="index">
|
||||
<SuccessCheckmark v-if="index <= successfull && index != step" class="h-8!" />
|
||||
<div
|
||||
v-else-if="index <= step"
|
||||
class="flex items-center justify-center h-8 w-8 border-4 border-success rounded-full"
|
||||
>
|
||||
<div class="h-2 w-2 border-4 border-success bg-success rounded-full"></div>
|
||||
</div>
|
||||
<div v-else class="h-8 w-8 border-4 border-gray-400 rounded-full"></div>
|
||||
<div v-if="i != total" class="grow border-2" :class="index < step ? ' border-success' : 'border-gray-400'"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import SuccessCheckmark from "./SuccessCheckmark.vue";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
props: {
|
||||
step: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
validator(value: number) {
|
||||
return value >= 0;
|
||||
},
|
||||
},
|
||||
successfull: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
validator(value: number) {
|
||||
return value >= 0;
|
||||
},
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
validator(value: number) {
|
||||
return value >= 1;
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -1,10 +1,11 @@
|
|||
<template>
|
||||
<div class="flex flex-col text-gray-400 text-sm mt-4 items-center">
|
||||
<div class="flex flex-row gap-2 justify-center">
|
||||
<p v-if="appCustom_login_message">{{ appCustom_login_message }}</p>
|
||||
<div class="flex flex-row gap-2 justify-center mb-3">
|
||||
<a v-if="clubWebsite" :href="clubWebsite" target="_blank">Webseite</a>
|
||||
<a v-if="clubImprint" :href="clubImprint" target="_blank">Datenschutz</a>
|
||||
<a v-if="clubPrivacy" :href="clubPrivacy" target="_blank">Impressum</a>
|
||||
</div>
|
||||
<p v-if="appCustom_login_message">{{ appCustom_login_message }}</p>
|
||||
<p>
|
||||
<a href="https://ff-admin.de/admin" target="_blank">FF Admin</a>
|
||||
entwickelt von
|
||||
|
|
70
src/components/setup/Account.vue
Normal file
70
src/components/setup/Account.vue
Normal file
|
@ -0,0 +1,70 @@
|
|||
<template>
|
||||
<form class="flex flex-col gap-2" @submit.prevent="setup">
|
||||
<p class="text-center">Admin Account</p>
|
||||
<div class="-space-y-px">
|
||||
<div>
|
||||
<input id="username" name="username" type="text" required placeholder="Benutzer" class="rounded-b-none!" />
|
||||
</div>
|
||||
<div>
|
||||
<input id="mail" name="mail" type="email" required placeholder="Mailadresse" class="rounded-none!" />
|
||||
</div>
|
||||
<div>
|
||||
<input id="firstname" name="firstname" type="text" required placeholder="Vorname" class="rounded-none!" />
|
||||
</div>
|
||||
<div>
|
||||
<input id="lastname" name="lastname" type="text" required placeholder="Nachname" class="rounded-t-none!" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
<button type="submit" primary :disabled="setupStatus == 'loading' || setupStatus == 'success'">
|
||||
Admin-Account anlegen
|
||||
</button>
|
||||
<Spinner v-if="setupStatus == 'loading'" class="my-auto" />
|
||||
<SuccessCheckmark v-else-if="setupStatus == 'success'" />
|
||||
<FailureXMark v-else-if="setupStatus == 'failed'" />
|
||||
</div>
|
||||
<p v-if="setupMessage" class="text-center">{{ setupMessage }}</p>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import Spinner from "@/components/Spinner.vue";
|
||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||
import FailureXMark from "@/components/FailureXMark.vue";
|
||||
import { mapActions } from "pinia";
|
||||
import { useSetupStore } from "../../stores/setup";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
setupStatus: undefined as undefined | "loading" | "success" | "failed",
|
||||
setupMessage: "" as string,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useSetupStore, ["createAdmin"]),
|
||||
setup(e: any) {
|
||||
let formData = e.target.elements;
|
||||
this.setupStatus = "loading";
|
||||
this.setupMessage = "";
|
||||
this.createAdmin({
|
||||
username: formData.username.value,
|
||||
mail: formData.mail.value,
|
||||
firstname: formData.firstname.value,
|
||||
lastname: formData.lastname.value,
|
||||
})
|
||||
.then((result) => {
|
||||
// this.setupStatus = "success";
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setupStatus = "failed";
|
||||
this.setupMessage = err.response.data;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
66
src/components/setup/App.vue
Normal file
66
src/components/setup/App.vue
Normal file
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<form class="flex flex-col gap-2" @submit.prevent="setup">
|
||||
<p class="text-center">App Konfiguration</p>
|
||||
<div class="-space-y-px">
|
||||
<div>
|
||||
<input id="login_message" name="login_message" type="text" placeholder="Nachricht unter Login (optional)" />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row items-center gap-2 pt-1">
|
||||
<input type="checkbox" id="show_cal_link" checked />
|
||||
<label for="show_cal_link">Link zum Kalender anzeigen (optional)</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-primary cursor-pointer ml-auto" @click="skip('app')">überspringen</p>
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
<button type="submit" primary :disabled="setupStatus == 'loading' || setupStatus == 'success'">
|
||||
Anwendungsdaten speichern
|
||||
</button>
|
||||
<Spinner v-if="setupStatus == 'loading'" class="my-auto" />
|
||||
<SuccessCheckmark v-else-if="setupStatus == 'success'" />
|
||||
<FailureXMark v-else-if="setupStatus == 'failed'" />
|
||||
</div>
|
||||
<p v-if="setupMessage" class="text-center">{{ setupMessage }}</p>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import Spinner from "@/components/Spinner.vue";
|
||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||
import FailureXMark from "@/components/FailureXMark.vue";
|
||||
import { mapActions } from "pinia";
|
||||
import { useSetupStore } from "../../stores/setup";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
setupStatus: undefined as undefined | "loading" | "success" | "failed",
|
||||
setupMessage: "" as string,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useSetupStore, ["setApp", "skip"]),
|
||||
setup(e: any) {
|
||||
let formData = e.target.elements;
|
||||
this.setupStatus = "loading";
|
||||
this.setupMessage = "";
|
||||
this.setApp({
|
||||
login_message: formData.login_message.value,
|
||||
show_cal_link: formData.show_cal_link.checked,
|
||||
})
|
||||
.then((result) => {
|
||||
// this.setupStatus = "success";
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setupStatus = "failed";
|
||||
this.setupMessage = err.response.data;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
99
src/components/setup/Club.vue
Normal file
99
src/components/setup/Club.vue
Normal file
|
@ -0,0 +1,99 @@
|
|||
<template>
|
||||
<form class="flex flex-col gap-2" @submit.prevent="setup">
|
||||
<p class="text-center">Feuerwehr-/Vereinsdaten</p>
|
||||
<div class="-space-y-px">
|
||||
<div>
|
||||
<input
|
||||
id="name"
|
||||
name="name"
|
||||
type="text"
|
||||
placeholder="Feuerwehr-/Vereinsname (optional)"
|
||||
class="rounded-b-none!"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input
|
||||
id="imprint"
|
||||
name="imprint"
|
||||
type="url"
|
||||
placeholder="Link zum Impressum (optional)"
|
||||
class="rounded-none!"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input
|
||||
id="privacy"
|
||||
name="privacy"
|
||||
type="url"
|
||||
placeholder="Link zur Datenschutzerklärung (optional)"
|
||||
class="rounded-none!"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input
|
||||
id="website"
|
||||
name="website"
|
||||
type="url"
|
||||
placeholder="Link zur Webseite (optional)"
|
||||
class="rounded-t-none!"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-primary cursor-pointer ml-auto" @click="skip('club')">überspringen</p>
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
<button type="submit" primary :disabled="setupStatus == 'loading' || setupStatus == 'success'">
|
||||
Vereinsdaten speichern
|
||||
</button>
|
||||
<Spinner v-if="setupStatus == 'loading'" class="my-auto" />
|
||||
<SuccessCheckmark v-else-if="setupStatus == 'success'" />
|
||||
<FailureXMark v-else-if="setupStatus == 'failed'" />
|
||||
</div>
|
||||
<p v-if="setupMessage" class="text-center">{{ setupMessage }}</p>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import Spinner from "@/components/Spinner.vue";
|
||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||
import FailureXMark from "@/components/FailureXMark.vue";
|
||||
import { mapActions } from "pinia";
|
||||
import { useSetupStore } from "../../stores/setup";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
setupStatus: undefined as undefined | "loading" | "success" | "failed",
|
||||
setupMessage: "" as string,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useSetupStore, ["setClub", "skip"]),
|
||||
setup(e: any) {
|
||||
let formData = e.target.elements;
|
||||
this.setupStatus = "loading";
|
||||
this.setupMessage = "";
|
||||
this.setClub({
|
||||
name: formData.name.value,
|
||||
imprint: formData.imprint.value,
|
||||
privacy: formData.privacy.value,
|
||||
website: formData.website.value,
|
||||
})
|
||||
.then((result) => {
|
||||
// this.setupStatus = "success";
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setupStatus = "failed";
|
||||
this.setupMessage = err.response.data;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
3
src/components/setup/Finished.vue
Normal file
3
src/components/setup/Finished.vue
Normal file
|
@ -0,0 +1,3 @@
|
|||
<template>
|
||||
<p class="text-center">Sie haben einen Verifizierungslink per Mail erhalten.</p>
|
||||
</template>
|
87
src/components/setup/Images.vue
Normal file
87
src/components/setup/Images.vue
Normal file
|
@ -0,0 +1,87 @@
|
|||
<template>
|
||||
<form class="flex flex-col gap-2" @submit.prevent="setup">
|
||||
<p class="text-center">Feuerwehr-/Vereins-Auftritt</p>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-col gap-2">
|
||||
<p>quadratisches Icon für App (optional)</p>
|
||||
<img ref="icon_img" class="hidden w-full h-20 object-contain" />
|
||||
<input class="hidden!" type="file" ref="icon" accept="image/*" @change="previewImage('icon')" />
|
||||
<button type="button" primary-outline @click="($refs.icon as HTMLInputElement).click()">Icon auswählen</button>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<p>Logo (optional)</p>
|
||||
<img ref="logo_img" class="hidden w-full h-20 object-contain" />
|
||||
<input class="hidden!" type="file" ref="logo" accept="image/*" @change="previewImage('logo')" />
|
||||
<button type="button" primary-outline @click="($refs.logo as HTMLInputElement).click()">Logo auswählen</button>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<p class="text-primary cursor-pointer ml-auto" @click="skip('appImages')">überspringen</p>
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
<button type="submit" primary :disabled="setupStatus == 'loading' || setupStatus == 'success'">
|
||||
Bilder speichern
|
||||
</button>
|
||||
<Spinner v-if="setupStatus == 'loading'" class="my-auto" />
|
||||
<SuccessCheckmark v-else-if="setupStatus == 'success'" />
|
||||
<FailureXMark v-else-if="setupStatus == 'failed'" />
|
||||
</div>
|
||||
<p v-if="setupMessage" class="text-center">{{ setupMessage }}</p>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import Spinner from "@/components/Spinner.vue";
|
||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||
import FailureXMark from "@/components/FailureXMark.vue";
|
||||
import { mapActions } from "pinia";
|
||||
import { useSetupStore } from "../../stores/setup";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
setupStatus: undefined as undefined | "loading" | "success" | "failed",
|
||||
setupMessage: "" as string,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useSetupStore, ["setClubImages", "skip"]),
|
||||
previewImage(inputname: "icon" | "logo") {
|
||||
let input = this.$refs[inputname] as HTMLInputElement;
|
||||
let previewElement = this.$refs[inputname + "_img"] as HTMLImageElement;
|
||||
if (input.files && input.files[0]) {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function (e) {
|
||||
previewElement.src = e.target?.result as string;
|
||||
previewElement.style.display = "block";
|
||||
};
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
} else {
|
||||
previewElement.src = "";
|
||||
previewElement.style.display = "none";
|
||||
}
|
||||
},
|
||||
setup(e: any) {
|
||||
this.setupStatus = "loading";
|
||||
this.setupMessage = "";
|
||||
this.setClubImages({
|
||||
icon: (this.$refs.icon as HTMLInputElement).files?.[0],
|
||||
logo: (this.$refs.logo as HTMLInputElement).files?.[0],
|
||||
})
|
||||
.then((result) => {
|
||||
// this.setupStatus = "success";
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setupStatus = "failed";
|
||||
this.setupMessage = err.response.data;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
95
src/components/setup/Mail.vue
Normal file
95
src/components/setup/Mail.vue
Normal file
|
@ -0,0 +1,95 @@
|
|||
<template>
|
||||
<form class="flex flex-col gap-2" @submit.prevent="setup">
|
||||
<p class="text-center">Mailversand</p>
|
||||
<div class="-space-y-px">
|
||||
<div class="mb-2">
|
||||
<input id="mail" name="mail" type="email" placeholder="Mailadresse" required autocomplete="email" />
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
id="user"
|
||||
name="user"
|
||||
type="text"
|
||||
placeholder="Benutzername (kann auch Mail sein)"
|
||||
required
|
||||
autocomplete="username"
|
||||
class="rounded-b-none!"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
id="password"
|
||||
name="password"
|
||||
type="password"
|
||||
placeholder="Passwort"
|
||||
required
|
||||
autocomplete="new-password"
|
||||
class="rounded-none!"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<input id="host" name="host" type="text" placeholder="Server-Host" required class="rounded-none!" />
|
||||
</div>
|
||||
<div>
|
||||
<input id="port" name="port" type="number" placeholder="Port (25, 465, 587)" required class="rounded-t-none!" />
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-2 pt-1">
|
||||
<input type="checkbox" id="secure" />
|
||||
<label for="secure">SSL-Verbindung (setzen bei Port 465)</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
<button type="submit" primary :disabled="setupStatus == 'loading' || setupStatus == 'success'">
|
||||
Mailversand speichern
|
||||
</button>
|
||||
<Spinner v-if="setupStatus == 'loading'" class="my-auto" />
|
||||
<SuccessCheckmark v-else-if="setupStatus == 'success'" />
|
||||
<FailureXMark v-else-if="setupStatus == 'failed'" />
|
||||
</div>
|
||||
<p v-if="setupMessage" class="text-center">{{ setupMessage }}</p>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import Spinner from "@/components/Spinner.vue";
|
||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||
import FailureXMark from "@/components/FailureXMark.vue";
|
||||
import { mapActions } from "pinia";
|
||||
import { useSetupStore } from "../../stores/setup";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
setupStatus: undefined as undefined | "loading" | "success" | "failed",
|
||||
setupMessage: "" as string,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useSetupStore, ["setMailConfig", "skip"]),
|
||||
setup(e: any) {
|
||||
let formData = e.target.elements;
|
||||
this.setupStatus = "loading";
|
||||
this.setupMessage = "";
|
||||
this.setMailConfig({
|
||||
host: formData.host.value,
|
||||
port: formData.port.value,
|
||||
secure: formData.secure.checked,
|
||||
mail: formData.mail.value,
|
||||
username: formData.user.value,
|
||||
password: formData.password.value,
|
||||
})
|
||||
.then((result) => {
|
||||
// this.setupStatus = "success";
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setupStatus = "failed";
|
||||
this.setupMessage = err.response.data;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
|
@ -18,7 +18,7 @@
|
|||
--error: #9a0d55;
|
||||
--warning: #bb6210;
|
||||
--info: #388994;
|
||||
--success: #73ad0f;
|
||||
--success: #7ac142;
|
||||
}
|
||||
.dark {
|
||||
--primary: #ff0d00;
|
||||
|
@ -27,7 +27,7 @@
|
|||
--error: #9a0d55;
|
||||
--warning: #bb6210;
|
||||
--info: #4ccbda;
|
||||
--success: #73ad0f;
|
||||
--success: #7ac142;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
130
src/stores/setup.ts
Normal file
130
src/stores/setup.ts
Normal file
|
@ -0,0 +1,130 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { http } from "../serverCom";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import { useConfigurationStore } from "./configuration";
|
||||
|
||||
export const useSetupStore = defineStore("setup", {
|
||||
state: () => {
|
||||
return {
|
||||
dictionary: ["club", "clubImages", "app", "mail", "account", "finished"],
|
||||
step: 0 as number,
|
||||
successfull: 0 as number,
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
stepIndex: (state) => (dict: string) => state.dictionary.findIndex((d) => d == dict),
|
||||
},
|
||||
actions: {
|
||||
skip(dict: string) {
|
||||
let myIndex = this.stepIndex(dict);
|
||||
this.step += 1;
|
||||
if (this.successfull <= myIndex) {
|
||||
this.successfull = myIndex + 1;
|
||||
}
|
||||
},
|
||||
async setClub(data: {
|
||||
name?: string;
|
||||
imprint?: string;
|
||||
privacy?: string;
|
||||
website?: string;
|
||||
}): Promise<AxiosResponse<any, any>> {
|
||||
let configStore = useConfigurationStore();
|
||||
|
||||
let myIndex = this.stepIndex("club");
|
||||
const res = await http.post(`/setup/club`, {
|
||||
name: data.name,
|
||||
imprint: data.imprint,
|
||||
privacy: data.privacy,
|
||||
website: data.website,
|
||||
});
|
||||
configStore.configure();
|
||||
|
||||
this.step += 1;
|
||||
if (this.successfull <= myIndex) {
|
||||
this.successfull = myIndex;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
async setClubImages(data: { icon?: File; logo?: File }): Promise<AxiosResponse<any, any>> {
|
||||
let configStore = useConfigurationStore();
|
||||
|
||||
let myIndex = this.stepIndex("clubImages");
|
||||
const formData = new FormData();
|
||||
|
||||
if (data.icon) {
|
||||
formData.append("icon", data.icon);
|
||||
}
|
||||
|
||||
if (data.logo) {
|
||||
formData.append("logo", data.logo);
|
||||
}
|
||||
|
||||
const res = await http.post(`/setup/club/images`, formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
configStore.configure();
|
||||
|
||||
this.step += 1;
|
||||
if (this.successfull <= myIndex) {
|
||||
this.successfull = myIndex;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
async setApp(data: { login_message: string; show_cal_link: boolean }): Promise<AxiosResponse<any, any>> {
|
||||
let myIndex = this.stepIndex("app");
|
||||
const res = await http.post(`/setup/app`, {
|
||||
custom_login_message: data.login_message,
|
||||
show_link_to_calendar: data.show_cal_link,
|
||||
});
|
||||
this.step += 1;
|
||||
if (this.successfull <= myIndex) {
|
||||
this.successfull = myIndex;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
async setMailConfig(data: {
|
||||
host: string;
|
||||
port: number;
|
||||
secure: boolean;
|
||||
mail: string;
|
||||
username: string;
|
||||
password: string;
|
||||
}): Promise<AxiosResponse<any, any>> {
|
||||
let myIndex = this.stepIndex("mail");
|
||||
const res = await http.post(`/setup/mail`, {
|
||||
host: data.host,
|
||||
port: data.port,
|
||||
secure: data.secure,
|
||||
mail: data.mail,
|
||||
username: data.username,
|
||||
password: data.password,
|
||||
});
|
||||
this.step += 1;
|
||||
if (this.successfull <= myIndex) {
|
||||
this.successfull = myIndex;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
async createAdmin(credentials: {
|
||||
username: string;
|
||||
mail: string;
|
||||
firstname: string;
|
||||
lastname: string;
|
||||
}): Promise<AxiosResponse<any, any>> {
|
||||
let myIndex = this.stepIndex("account");
|
||||
const res = await http.post(`/setup/me`, {
|
||||
username: credentials.username,
|
||||
mail: credentials.mail,
|
||||
firstname: credentials.firstname,
|
||||
lastname: credentials.lastname,
|
||||
});
|
||||
this.step += 1;
|
||||
if (this.successfull < myIndex) {
|
||||
this.successfull = myIndex;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
},
|
||||
});
|
|
@ -5,33 +5,15 @@
|
|||
<AppLogo />
|
||||
<h2 class="text-center text-4xl font-extrabold text-gray-900">Einrichtung</h2>
|
||||
</div>
|
||||
<CheckProgressBar :total="dictionary.length" :step="step" :successfull="successfull" />
|
||||
|
||||
<form class="flex flex-col gap-2" @submit.prevent="setup">
|
||||
<div class="-space-y-px">
|
||||
<div>
|
||||
<input id="username" name="username" type="text" required placeholder="Benutzer" class="rounded-b-none!" />
|
||||
</div>
|
||||
<div>
|
||||
<input id="mail" name="mail" type="email" required placeholder="Mailadresse" class="rounded-none!" />
|
||||
</div>
|
||||
<div>
|
||||
<input id="firstname" name="firstname" type="text" required placeholder="Vorname" class="rounded-none!" />
|
||||
</div>
|
||||
<div>
|
||||
<input id="lastname" name="lastname" type="text" required placeholder="Nachname" class="rounded-t-none!" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
<button type="submit" primary :disabled="setupStatus == 'loading' || setupStatus == 'success'">
|
||||
Admin-Account anlegen
|
||||
</button>
|
||||
<Spinner v-if="setupStatus == 'loading'" class="my-auto" />
|
||||
<SuccessCheckmark v-else-if="setupStatus == 'success'" />
|
||||
<FailureXMark v-else-if="setupStatus == 'failed'" />
|
||||
</div>
|
||||
<p v-if="setupMessage" class="text-center">{{ setupMessage }}</p>
|
||||
</form>
|
||||
<Club v-if="step == stepIndex('club')" />
|
||||
<Images v-else-if="step == stepIndex('clubImages')" />
|
||||
<App v-else-if="step == stepIndex('app')" />
|
||||
<Mail v-else-if="step == stepIndex('mail')" />
|
||||
<Account v-else-if="step == stepIndex('account')" />
|
||||
<Finished v-else-if="step == stepIndex('finished')" />
|
||||
<p v-else class="text-center">UI-Fehler - versuchen Sie einen Reload der Seite</p>
|
||||
|
||||
<FormBottomBar />
|
||||
</div>
|
||||
|
@ -40,42 +22,23 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import Spinner from "@/components/Spinner.vue";
|
||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||
import FailureXMark from "@/components/FailureXMark.vue";
|
||||
import FormBottomBar from "@/components/FormBottomBar.vue";
|
||||
import AppLogo from "@/components/AppLogo.vue";
|
||||
import App from "@/components/setup/App.vue";
|
||||
import Account from "@/components/setup/Account.vue";
|
||||
import CheckProgressBar from "@/components/CheckProgressBar.vue";
|
||||
import { mapState } from "pinia";
|
||||
import { useSetupStore } from "@/stores/setup";
|
||||
import Club from "@/components/setup/Club.vue";
|
||||
import Images from "@/components/setup/Images.vue";
|
||||
import Finished from "@/components/setup/Finished.vue";
|
||||
import Mail from "../../components/setup/Mail.vue";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
data() {
|
||||
return {
|
||||
setupStatus: undefined as undefined | "loading" | "success" | "failed",
|
||||
setupMessage: "" as string,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
setup(e: any) {
|
||||
let formData = e.target.elements;
|
||||
this.setupStatus = "loading";
|
||||
this.setupMessage = "";
|
||||
this.$http
|
||||
.post(`/setup/me`, {
|
||||
username: formData.username.value,
|
||||
mail: formData.mail.value,
|
||||
firstname: formData.firstname.value,
|
||||
lastname: formData.lastname.value,
|
||||
})
|
||||
.then((result) => {
|
||||
this.setupStatus = "success";
|
||||
this.setupMessage = "Sie haben einen Verifizierungslink per Mail erhalten.";
|
||||
})
|
||||
.catch((err) => {
|
||||
this.setupStatus = "failed";
|
||||
this.setupMessage = err.response.data;
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
...mapState(useSetupStore, ["step", "stepIndex", "successfull", "dictionary"]),
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
Loading…
Add table
Reference in a new issue