Merge branch 'milestone/ff-admin-unit' into unit/#70-build-ui-demo
# Conflicts: # package-lock.json # package.json # src/router/club/newsletterGuard.ts # src/router/club/protocolGuard.ts # src/router/index.ts # src/types/permissionTypes.ts # src/views/admin/club/newsletter/NewsletterRecipients.vue
This commit is contained in:
commit
bdc139f37f
107 changed files with 4984 additions and 1742 deletions
|
@ -4,52 +4,56 @@
|
|||
<p v-else-if="loading == 'failed'" @click="fetchNewsletterRecipients" class="cursor-pointer">
|
||||
↺ laden fehlgeschlagen
|
||||
</p>
|
||||
<div class="flex flex-col gap-2 h-1/2">
|
||||
|
||||
<div v-if="!showMemberSelect" class="flex flex-row gap-2 items-center">
|
||||
<select v-model="recipientsByQueryId">
|
||||
<option value="def">Optional</option>
|
||||
<option v-for="query in queries" :key="query.id" :value="query.id">{{ query.title }}</option>
|
||||
</select>
|
||||
<p>Empfänger durch gespeicherte Abfrage</p>
|
||||
<div class="flex flex-col gap-2 grow overflow-y-auto">
|
||||
<div
|
||||
v-for="member in queried"
|
||||
:key="member.id"
|
||||
class="flex flex-row h-fit w-full border border-primary rounded-md bg-primary p-2 text-white justify-between items-center"
|
||||
>
|
||||
<div>
|
||||
<p>{{ member.lastname }}, {{ member.firstname }} {{ member.nameaffix ? `- ${member.nameaffix}` : "" }}</p>
|
||||
<p>Newsletter senden an Typ: {{ member.sendNewsletter?.type.type }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div title="Empfänger manuell hinzufügen" @click="showMemberSelect = true">
|
||||
<UserPlusIcon class="w-7 h-7 cursor-pointer" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 h-1/2">
|
||||
<div v-else class="flex flex-row gap-2 items-center">
|
||||
<MemberSearchSelectMultiple
|
||||
title="weitere Empfänger suchen"
|
||||
showTitleAsPlaceholder
|
||||
v-model="recipients"
|
||||
:disabled="!can('create', 'club', 'newsletter')"
|
||||
/>
|
||||
|
||||
<p>Ausgewählte Empfänger</p>
|
||||
<div class="flex flex-col gap-2 grow overflow-y-auto">
|
||||
<div
|
||||
v-for="member in selected"
|
||||
:key="member.id"
|
||||
class="flex flex-row h-fit w-full border border-primary rounded-md bg-primary p-2 text-white justify-between items-center"
|
||||
>
|
||||
<div>
|
||||
<p>{{ member.lastname }}, {{ member.firstname }} {{ member.nameaffix ? `- ${member.nameaffix}` : "" }}</p>
|
||||
<p>Newsletter senden an Typ: {{ member.sendNewsletter?.type.type }}</p>
|
||||
</div>
|
||||
|
||||
<TrashIcon
|
||||
v-if="can('create', 'club', 'newsletter')"
|
||||
class="w-5 h-5 p-1 box-content cursor-pointer"
|
||||
@click="removeSelected(member.id)"
|
||||
/>
|
||||
</div>
|
||||
<div title="Empfänger über Query hinzufügen" @click="showMemberSelect = false">
|
||||
<ArchiveBoxIcon class="w-7 h-7 cursor-pointer" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="!showMemberSelect">Empfänger durch gespeicherte Abfrage</p>
|
||||
<p v-else>Ausgewählte Empfänger</p>
|
||||
|
||||
<div class="flex flex-col gap-2 grow overflow-y-auto">
|
||||
<div
|
||||
v-for="member in showRecipientsByMode"
|
||||
:key="member.id"
|
||||
class="flex flex-row gap-2 h-fit w-full border border-primary rounded-md bg-primary p-2 text-white items-center"
|
||||
>
|
||||
<ExclamationTriangleIcon v-if="member.sendNewsletter == null" class="w-7 h-7" />
|
||||
|
||||
<div class="grow">
|
||||
<p>{{ member.lastname }}, {{ member.firstname }} {{ member.nameaffix ? `- ${member.nameaffix}` : "" }}</p>
|
||||
<p>Newsletter senden an Typ: {{ member.sendNewsletter?.type.type ?? "---" }}</p>
|
||||
</div>
|
||||
|
||||
<TrashIcon
|
||||
v-if="can('create', 'club', 'newsletter') && showMemberSelect"
|
||||
class="w-5 h-5 p-1 box-content cursor-pointer"
|
||||
@click="removeSelected(member.id)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="countOfNoConfig != 0" class="flex flex-row items-center gap-2 pt-3">
|
||||
<ExclamationTriangleIcon class="text-red-500 w-5 h-5" />
|
||||
<p>{{ countOfNoConfig }} Mitglieder der Auswahl haben keinen Newsletter-Versand konfiguriert!</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -67,7 +71,7 @@ import {
|
|||
TransitionRoot,
|
||||
} from "@headlessui/vue";
|
||||
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
|
||||
import { TrashIcon } from "@heroicons/vue/24/outline";
|
||||
import { ArchiveBoxIcon, ExclamationTriangleIcon, TrashIcon, UserPlusIcon } from "@heroicons/vue/24/outline";
|
||||
import { useMemberStore } from "@/stores/admin/club/member/member";
|
||||
import type { MemberViewModel } from "@/viewmodels/admin/club/member/member.models";
|
||||
import { useNewsletterStore } from "@/stores/admin/club/newsletter/newsletter";
|
||||
|
@ -77,6 +81,8 @@ import { useQueryStoreStore } from "@/stores/admin/configuration/queryStore";
|
|||
import { useQueryBuilderStore } from "@/stores/admin/club/queryBuilder";
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
import MemberSearchSelectMultiple from "@/components/search/MemberSearchSelectMultiple.vue";
|
||||
import MemberSearchSelect from "@/components/search/MemberSearchSelect.vue";
|
||||
import type { FieldType } from "@/types/dynamicQueries";
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -84,22 +90,17 @@ export default defineComponent({
|
|||
props: {
|
||||
newsletterId: String,
|
||||
},
|
||||
watch: {
|
||||
recipientsByQuery() {
|
||||
this.loadQuery();
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
query: "" as String,
|
||||
queryResult: [] as Array<{ id: FieldType; [key: string]: FieldType }>,
|
||||
members: [] as Array<MemberViewModel>,
|
||||
showMemberSelect: false as boolean,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapWritableState(useNewsletterRecipientsStore, ["recipients", "loading"]),
|
||||
...mapWritableState(useNewsletterStore, ["activeNewsletterObj"]),
|
||||
...mapState(useQueryStoreStore, ["queries"]),
|
||||
...mapState(useQueryBuilderStore, ["data"]),
|
||||
...mapState(useAbilityStore, ["can"]),
|
||||
selected(): Array<MemberViewModel> {
|
||||
return this.members
|
||||
|
@ -114,10 +115,10 @@ export default defineComponent({
|
|||
},
|
||||
queried(): Array<MemberViewModel> {
|
||||
if (this.recipientsByQueryId == "def") return [];
|
||||
let keys = Object.keys(this.data?.[0] ?? {});
|
||||
let keys = Object.keys(this.queryResult?.[0] ?? {});
|
||||
let memberKey = keys.find((k) => k.includes("member_id"));
|
||||
return this.members.filter((m) =>
|
||||
this.data
|
||||
this.queryResult
|
||||
.map((t) => ({
|
||||
id: t.id,
|
||||
...(memberKey ? { memberId: t[memberKey] } : {}),
|
||||
|
@ -125,6 +126,17 @@ export default defineComponent({
|
|||
.some((d) => (d.memberId ?? d.id) == m.id)
|
||||
);
|
||||
},
|
||||
showRecipientsByMode() {
|
||||
return (this.showMemberSelect ? this.selected : this.queried).sort((a, b) => {
|
||||
const aHasConfig = a.sendNewsletter != null;
|
||||
const bHasConfig = b.sendNewsletter != null;
|
||||
if (aHasConfig === bHasConfig) return 0;
|
||||
return aHasConfig ? -1 : 1;
|
||||
});
|
||||
},
|
||||
countOfNoConfig() {
|
||||
return this.showRecipientsByMode.filter((member) => member.sendNewsletter == null).length;
|
||||
},
|
||||
recipientsByQueryId: {
|
||||
get() {
|
||||
return this.activeNewsletterObj?.recipientsByQueryId ?? "def";
|
||||
|
@ -133,17 +145,12 @@ export default defineComponent({
|
|||
if (this.activeNewsletterObj == undefined) return;
|
||||
if (val == "def") {
|
||||
this.activeNewsletterObj.recipientsByQueryId = null;
|
||||
this.activeNewsletterObj.recipientsByQuery = null;
|
||||
} else if (this.queries.find((q) => q.id == val)) {
|
||||
this.activeNewsletterObj.recipientsByQueryId = val;
|
||||
this.activeNewsletterObj.recipientsByQuery = cloneDeep(this.queries.find((q) => q.id == val));
|
||||
this.sendQuery(0, 0, this.recipientsByQuery?.query, true);
|
||||
this.loadQuery();
|
||||
}
|
||||
},
|
||||
},
|
||||
recipientsByQuery() {
|
||||
return this.activeNewsletterObj?.recipientsByQuery;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// this.fetchNewsletterRecipients();
|
||||
|
@ -155,7 +162,7 @@ export default defineComponent({
|
|||
...mapActions(useMemberStore, ["getAllMembers"]),
|
||||
...mapActions(useNewsletterRecipientsStore, ["fetchNewsletterRecipients"]),
|
||||
...mapActions(useQueryStoreStore, ["fetchQueries"]),
|
||||
...mapActions(useQueryBuilderStore, ["sendQuery"]),
|
||||
...mapActions(useQueryBuilderStore, ["sendQueryByStoreId"]),
|
||||
removeSelected(id: string) {
|
||||
let index = this.recipients.findIndex((s) => s == id);
|
||||
if (index != -1) {
|
||||
|
@ -170,8 +177,12 @@ export default defineComponent({
|
|||
.catch(() => {});
|
||||
},
|
||||
loadQuery() {
|
||||
if (this.recipientsByQuery) {
|
||||
this.sendQuery(0, 0, this.recipientsByQuery.query, true);
|
||||
if (this.recipientsByQueryId != "def") {
|
||||
this.sendQueryByStoreId(this.recipientsByQueryId, 0, 0, true)
|
||||
.then((result) => {
|
||||
this.queryResult = result.data.rows;
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue