Compare commits

..

No commits in common. "059b0fa9f20078744f6995d66c8140e324fa6558" and "2176c6c3cf39f54298f0eabb92f683b4dfdb659c" have entirely different histories.

23 changed files with 66 additions and 1934 deletions

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 KiB

After

Width:  |  Height:  |  Size: 641 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 MiB

After

Width:  |  Height:  |  Size: 10 MiB

View file

@ -2,7 +2,7 @@
<header class="flex flex-row h-16 min-h-16 justify-between p-3 md:px-5 bg-white shadow-sm"> <header class="flex flex-row h-16 min-h-16 justify-between p-3 md:px-5 bg-white shadow-sm">
<RouterLink to="/" class="flex flex-row gap-2 align-bottom w-fit h-full"> <RouterLink to="/" class="flex flex-row gap-2 align-bottom w-fit h-full">
<img src="/Logo.png" alt="LOGO" class="h-full w-auto" /> <img src="/Logo.png" alt="LOGO" class="h-full w-auto" />
<h1 v-if="false" class="font-bold text-3xl w-fit whitespace-nowrap">FF Admin</h1> <h1 v-if="false" class="font-bold text-3xl w-fit whitespace-nowrap">Mitgliederverwaltung</h1>
</RouterLink> </RouterLink>
<div class="flex flex-row gap-2 items-center"> <div class="flex flex-row gap-2 items-center">
<div v-if="authCheck" class="hidden md:flex flex-row gap-2 h-full align-middle"> <div v-if="authCheck" class="hidden md:flex flex-row gap-2 h-full align-middle">

View file

@ -136,7 +136,7 @@ export default defineComponent({
preferred: formData.preferred.checked, preferred: formData.preferred.checked,
mobile: formData.mobile?.value, mobile: formData.mobile?.value,
email: formData.email?.value, email: formData.email?.value,
postalCode: formData.postalCode?.value, postalCode: formData.postalCode.value,
city: formData.city?.value, city: formData.city?.value,
street: formData.street?.value, street: formData.street?.value,
streetNumber: formData.streetNumber?.value, streetNumber: formData.streetNumber?.value,

View file

@ -80,13 +80,15 @@ export default defineComponent({
this.createInvite(createInvite) this.createInvite(createInvite)
.then((result) => { .then((result) => {
this.status = { status: "success" }; this.status = { status: "success" };
setTimeout(() => {
this.closeModal();
}, 2000);
}) })
.catch((err) => { .catch((err) => {
this.status = { status: "failed", reason: err.response.data }; this.status = { status: "failed", reason: err.response.data };
}) })
.finally(() => {
setTimeout(() => {
this.closeModal();
}, 2000);
});
}, },
}, },
}); });

View file

@ -3,7 +3,7 @@
<div class="bg-primary p-2 text-white flex flex-row justify-between items-center"> <div class="bg-primary p-2 text-white flex flex-row justify-between items-center">
<p> <p>
{{ user.firstname }} {{ user.lastname }} <small v-if="user.permissions_total.admin">(Admin)</small {{ user.firstname }} {{ user.lastname }} <small v-if="user.permissions_total.admin">(Admin)</small
><small v-if="user.isOwner"> (Owner)</small> ><small v-if="isOwner"> (Owner)</small>
</p> </p>
<div class="flex flex-row"> <div class="flex flex-row">
<RouterLink <RouterLink
@ -65,7 +65,7 @@ export default defineComponent({
user: { type: Object as PropType<UserViewModel>, default: {} }, user: { type: Object as PropType<UserViewModel>, default: {} },
}, },
computed: { computed: {
...mapState(useAbilityStore, ["can"]), ...mapState(useAbilityStore, ["can", "isOwner"]),
}, },
methods: { methods: {
...mapActions(useModalStore, ["openModal"]), ...mapActions(useModalStore, ["openModal"]),

View file

@ -3,7 +3,7 @@
<div class="max-w-md w-full space-y-8 pb-20"> <div class="max-w-md w-full space-y-8 pb-20">
<div class="flex flex-col items-center gap-4"> <div class="flex flex-col items-center gap-4">
<img src="/Logo.png" alt="LOGO" class="h-36" /> <img src="/Logo.png" alt="LOGO" class="h-36" />
<h2 class="text-center text-4xl font-extrabold text-gray-900">FF Admin</h2> <h2 class="text-center text-4xl font-extrabold text-gray-900">Mitgliederverwaltung</h2>
</div> </div>
<form class="flex flex-col gap-2" @submit.prevent="login"> <form class="flex flex-col gap-2" @submit.prevent="login">

View file

@ -10,7 +10,16 @@
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<img :src="image" alt="totp" class="w-56 h-56 self-center" /> <img :src="image" alt="totp" class="w-56 h-56 self-center" />
<TextCopy :copyText="otp" /> <div class="flex relative">
<input type="text" :value="otp" />
<ClipboardIcon
class="w-5 h-5 p-2 box-content absolute right-1 top-1/2 -translate-y-1/2 bg-white cursor-pointer"
@click="copyToClipboard"
/>
<div v-if="copySuccess" class="absolute w-5 h-5 right-3 top-[10px]">
<SuccessCheckmark />
</div>
</div>
</div> </div>
<form class="flex flex-col gap-2" @submit.prevent="verify"> <form class="flex flex-col gap-2" @submit.prevent="verify">
<div class="-space-y-px"> <div class="-space-y-px">
@ -35,13 +44,13 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineComponent } from "vue"; import { defineComponent, markRaw, defineAsyncComponent } from "vue";
import { mapActions, mapState } from "pinia"; import { mapActions, mapState } from "pinia";
import MainTemplate from "@/templates/Main.vue"; import MainTemplate from "@/templates/Main.vue";
import Spinner from "@/components/Spinner.vue"; import Spinner from "@/components/Spinner.vue";
import SuccessCheckmark from "@/components/SuccessCheckmark.vue"; import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
import FailureXMark from "@/components/FailureXMark.vue"; import FailureXMark from "@/components/FailureXMark.vue";
import TextCopy from "@/components/TextCopy.vue"; import { ClipboardIcon } from "@heroicons/vue/24/outline";
</script> </script>
<script lang="ts"> <script lang="ts">
@ -53,6 +62,8 @@ export default defineComponent({
otp: undefined as undefined | string, otp: undefined as undefined | string,
verifyStatus: undefined as undefined | "loading" | "success" | "failed", verifyStatus: undefined as undefined | "loading" | "success" | "failed",
verifyError: "" as string, verifyError: "" as string,
copySuccess: false,
timeoutCopy: undefined as any,
}; };
}, },
mounted() { mounted() {
@ -89,6 +100,13 @@ export default defineComponent({
}, 2000); }, 2000);
}); });
}, },
copyToClipboard() {
navigator.clipboard.writeText(this.otp ?? "");
this.copySuccess = true;
this.timeoutCopy = setTimeout(() => {
this.copySuccess = false;
}, 2000);
},
}, },
}); });
</script> </script>

View file

@ -1,7 +1,7 @@
<template> <template>
<SidebarLayout> <SidebarLayout>
<template #sidebar> <template #sidebar>
<SidebarTemplate mainTitle="Mein Account" topTitle="FF Admin" :showTopList="isOwner"> <SidebarTemplate mainTitle="Mein Account" topTitle="Mitgliederverwaltung" :showTopList="isOwner">
<template v-if="isOwner" #topList> <template v-if="isOwner" #topList>
<RoutingLink <RoutingLink
title="Administration" title="Administration"

View file

@ -6,7 +6,7 @@
</div> </div>
</template> </template>
<template #diffMain> <template #diffMain>
<div class="flex flex-col gap-4 h-full pl-7"> <div class="flex flex-col gap-4 grow pl-7">
<div class="flex flex-col gap-2 grow overflow-y-scroll pr-7"> <div class="flex flex-col gap-2 grow overflow-y-scroll pr-7">
<AwardListItem v-for="award in awards" :key="award.id" :award="award" /> <AwardListItem v-for="award in awards" :key="award.id" :award="award" />
</div> </div>

View file

@ -6,7 +6,7 @@
</div> </div>
</template> </template>
<template #diffMain> <template #diffMain>
<div class="flex flex-col gap-4 h-full pl-7"> <div class="flex flex-col gap-4 grow pl-7">
<div class="flex flex-col gap-2 grow overflow-y-scroll pr-7"> <div class="flex flex-col gap-2 grow overflow-y-scroll pr-7">
<CalendarTypeListItem <CalendarTypeListItem
v-for="calendarType in calendarTypes" v-for="calendarType in calendarTypes"

View file

@ -6,7 +6,7 @@
</div> </div>
</template> </template>
<template #diffMain> <template #diffMain>
<div class="flex flex-col gap-4 h-full pl-7"> <div class="flex flex-col gap-4 grow pl-7">
<div class="flex flex-col gap-2 grow overflow-y-scroll pr-7"> <div class="flex flex-col gap-2 grow overflow-y-scroll pr-7">
<CommunicationTypeListItem <CommunicationTypeListItem
v-for="communicationType in communicationTypes" v-for="communicationType in communicationTypes"

View file

@ -6,7 +6,7 @@
</div> </div>
</template> </template>
<template #diffMain> <template #diffMain>
<div class="flex flex-col gap-4 h-full pl-7"> <div class="flex flex-col gap-4 grow pl-7">
<div class="flex flex-col gap-2 grow overflow-y-scroll pr-7"> <div class="flex flex-col gap-2 grow overflow-y-scroll pr-7">
<ExecutivePositionListItem <ExecutivePositionListItem
v-for="executivePosition in executivePositions" v-for="executivePosition in executivePositions"

View file

@ -6,7 +6,7 @@
</div> </div>
</template> </template>
<template #diffMain> <template #diffMain>
<div class="flex flex-col gap-4 h-full pl-7"> <div class="flex flex-col gap-4 grow pl-7">
<div class="flex flex-col gap-2 grow overflow-y-scroll pr-7"> <div class="flex flex-col gap-2 grow overflow-y-scroll pr-7">
<MembershipStatusListItem v-for="status in membershipStatus" :key="status.id" :membershipStatus="status" /> <MembershipStatusListItem v-for="status in membershipStatus" :key="status.id" :membershipStatus="status" />
</div> </div>

View file

@ -6,7 +6,7 @@
</div> </div>
</template> </template>
<template #diffMain> <template #diffMain>
<div class="flex flex-col gap-4 h-full pl-7"> <div class="flex flex-col gap-4 grow pl-7">
<div class="flex flex-col gap-2 grow overflow-y-scroll pr-7"> <div class="flex flex-col gap-2 grow overflow-y-scroll pr-7">
<QualificationListItem <QualificationListItem
v-for="qualification in qualifications" v-for="qualification in qualifications"

View file

@ -6,7 +6,7 @@
</div> </div>
</template> </template>
<template #diffMain> <template #diffMain>
<div class="flex flex-col gap-4 h-full pl-7"> <div class="flex flex-col gap-4 grow pl-7">
<div class="flex flex-col gap-2 grow overflow-y-scroll pr-7"> <div class="flex flex-col gap-2 grow overflow-y-scroll pr-7">
<QueryStoreListItem v-for="query in queries" :key="query.id" :queryItem="query" /> <QueryStoreListItem v-for="query in queries" :key="query.id" :queryItem="query" />
</div> </div>

View file

@ -9,7 +9,7 @@
</div> </div>
</template> </template>
<template #diffMain> <template #diffMain>
<div class="flex flex-col gap-4 h-full pl-7"> <div class="flex flex-col gap-4 grow pl-7">
<div class="flex flex-col gap-2 grow overflow-y-scroll pr-7"> <div class="flex flex-col gap-2 grow overflow-y-scroll pr-7">
<TemplateListItem v-for="template in templates" :key="template.id" :template="template" /> <TemplateListItem v-for="template in templates" :key="template.id" :template="template" />
</div> </div>

View file

@ -6,7 +6,7 @@
</div> </div>
</template> </template>
<template #diffMain> <template #diffMain>
<div class="flex flex-col gap-4 h-full pl-7"> <div class="flex flex-col gap-4 grow pl-7">
<div class="flex flex-col gap-2 grow overflow-y-scroll pr-7"> <div class="flex flex-col gap-2 grow overflow-y-scroll pr-7">
<RoleListItem v-for="role in roles" :key="role.id" :role="role" /> <RoleListItem v-for="role in roles" :key="role.id" :role="role" />
</div> </div>

View file

@ -6,7 +6,7 @@
</div> </div>
</template> </template>
<template #diffMain> <template #diffMain>
<div class="flex flex-col gap-4 h-full pl-7"> <div class="flex flex-col gap-4 grow pl-7">
<div class="flex flex-col gap-2 grow overflow-y-scroll pr-7"> <div class="flex flex-col gap-2 grow overflow-y-scroll pr-7">
<UserListItem v-for="user in users" :key="user.id" :user="user" /> <UserListItem v-for="user in users" :key="user.id" :user="user" />
</div> </div>

View file

@ -47,6 +47,8 @@ import { defineComponent } from "vue";
import Spinner from "@/components/Spinner.vue"; import Spinner from "@/components/Spinner.vue";
import SuccessCheckmark from "@/components/SuccessCheckmark.vue"; import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
import FailureXMark from "@/components/FailureXMark.vue"; import FailureXMark from "@/components/FailureXMark.vue";
import { RouterLink } from "vue-router";
import { ClipboardIcon } from "@heroicons/vue/24/outline";
import FormBottomBar from "@/components/FormBottomBar.vue"; import FormBottomBar from "@/components/FormBottomBar.vue";
import TextCopy from "@/components/TextCopy.vue"; import TextCopy from "@/components/TextCopy.vue";
</script> </script>

View file

@ -47,6 +47,7 @@ import Spinner from "@/components/Spinner.vue";
import SuccessCheckmark from "@/components/SuccessCheckmark.vue"; import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
import FailureXMark from "@/components/FailureXMark.vue"; import FailureXMark from "@/components/FailureXMark.vue";
import { RouterLink } from "vue-router"; import { RouterLink } from "vue-router";
import { ClipboardIcon } from "@heroicons/vue/24/outline";
import FormBottomBar from "@/components/FormBottomBar.vue"; import FormBottomBar from "@/components/FormBottomBar.vue";
import TextCopy from "@/components/TextCopy.vue"; import TextCopy from "@/components/TextCopy.vue";
</script> </script>

View file

@ -17,7 +17,16 @@
<form v-else class="flex flex-col gap-2" @submit.prevent="setup"> <form v-else class="flex flex-col gap-2" @submit.prevent="setup">
<img :src="image" alt="totp" class="w-56 h-56 self-center" /> <img :src="image" alt="totp" class="w-56 h-56 self-center" />
<TextCopy :copyText="otp" /> <div class="flex relative">
<input type="text" :value="otp" />
<ClipboardIcon
class="w-5 h-5 p-2 box-content absolute right-1 top-1/2 -translate-y-1/2 bg-white cursor-pointer"
@click="copyToClipboard"
/>
<div v-if="copySuccess" class="absolute w-5 h-5 right-3 top-[10px]">
<SuccessCheckmark />
</div>
</div>
<div class="-space-y-px"> <div class="-space-y-px">
<div> <div>
@ -48,8 +57,8 @@ import Spinner from "@/components/Spinner.vue";
import SuccessCheckmark from "@/components/SuccessCheckmark.vue"; import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
import FailureXMark from "@/components/FailureXMark.vue"; import FailureXMark from "@/components/FailureXMark.vue";
import { RouterLink } from "vue-router"; import { RouterLink } from "vue-router";
import { ClipboardIcon } from "@heroicons/vue/24/outline";
import FormBottomBar from "@/components/FormBottomBar.vue"; import FormBottomBar from "@/components/FormBottomBar.vue";
import TextCopy from "@/components/TextCopy.vue";
</script> </script>
<script lang="ts"> <script lang="ts">
@ -65,6 +74,8 @@ export default defineComponent({
otp: undefined as undefined | string, otp: undefined as undefined | string,
setupStatus: undefined as undefined | "loading" | "success" | "failed", setupStatus: undefined as undefined | "loading" | "success" | "failed",
setupError: "" as string, setupError: "" as string,
copySuccess: false,
timputCopy: undefined as any,
}; };
}, },
mounted() { mounted() {
@ -110,6 +121,13 @@ export default defineComponent({
this.setupError = err.response.data; this.setupError = err.response.data;
}); });
}, },
copyToClipboard() {
navigator.clipboard.writeText(this.otp ?? "");
this.copySuccess = true;
this.timputCopy = setTimeout(() => {
this.copySuccess = false;
}, 2000);
},
}, },
}); });
</script> </script>