newsletter recipients
This commit is contained in:
parent
ec477b7d72
commit
81b7f533c7
6 changed files with 81 additions and 17 deletions
|
@ -11,7 +11,7 @@ export function flattenQueryResult(result: Array<QueryResult>): Array<{ [key: st
|
||||||
|
|
||||||
for (const key in row) {
|
for (const key in row) {
|
||||||
const value = row[key];
|
const value = row[key];
|
||||||
const newKey = prefix ? `${prefix}.${key}` : key;
|
const newKey = prefix ? `${prefix}_${key}` : key;
|
||||||
|
|
||||||
if (Array.isArray(value) && value.every((item) => typeof item === "object" && item !== null)) {
|
if (Array.isArray(value) && value.every((item) => typeof item === "object" && item !== null)) {
|
||||||
console.log(value, newKey);
|
console.log(value, newKey);
|
||||||
|
|
|
@ -2,7 +2,6 @@ import { defineStore } from "pinia";
|
||||||
import { http } from "@/serverCom";
|
import { http } from "@/serverCom";
|
||||||
import type { TableMeta } from "@/viewmodels/admin/query.models";
|
import type { TableMeta } from "@/viewmodels/admin/query.models";
|
||||||
import type { DynamicQueryStructure, FieldType } from "@/types/dynamicQueries";
|
import type { DynamicQueryStructure, FieldType } from "@/types/dynamicQueries";
|
||||||
import { flattenQueryResult } from "@/helpers/queryFormatter";
|
|
||||||
|
|
||||||
export const useQueryBuilderStore = defineStore("queryBuilder", {
|
export const useQueryBuilderStore = defineStore("queryBuilder", {
|
||||||
state: () => {
|
state: () => {
|
||||||
|
@ -31,23 +30,21 @@ export const useQueryBuilderStore = defineStore("queryBuilder", {
|
||||||
this.loading = "failed";
|
this.loading = "failed";
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
sendQuery(offset = 0, count = 25) {
|
sendQuery(offset = 0, count = 25, query?: DynamicQueryStructure | string) {
|
||||||
this.queryError = "";
|
this.queryError = "";
|
||||||
this.data = [];
|
this.data = [];
|
||||||
this.totalLength = 0;
|
this.totalLength = 0;
|
||||||
if (this.query == undefined || this.query == "" || (typeof this.query != "string" && this.query.table == ""))
|
let queryToSend = query ?? this.query;
|
||||||
|
if (queryToSend == undefined || queryToSend == "" || (typeof queryToSend != "string" && queryToSend.table == ""))
|
||||||
return;
|
return;
|
||||||
this.loadingData = "loading";
|
this.loadingData = "loading";
|
||||||
http
|
http
|
||||||
.post(`/admin/querybuilder/query?offset=${offset}&count=${count}`, {
|
.post(`/admin/querybuilder/query?offset=${offset}&count=${count}`, {
|
||||||
query: this.query,
|
query: queryToSend,
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.data.stats == "success") {
|
if (result.data.stats == "success") {
|
||||||
this.data = flattenQueryResult(result.data.rows).map((row) => ({
|
this.data = result.data.rows;
|
||||||
id: row.id ?? "", // Ensure id is present
|
|
||||||
...row,
|
|
||||||
}));
|
|
||||||
this.totalLength = result.data.total;
|
this.totalLength = result.data.total;
|
||||||
this.loadingData = "fetched";
|
this.loadingData = "fetched";
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -8,8 +8,8 @@ export interface NewsletterViewModel {
|
||||||
newsletterText: string;
|
newsletterText: string;
|
||||||
newsletterSignatur: string;
|
newsletterSignatur: string;
|
||||||
isSent: boolean;
|
isSent: boolean;
|
||||||
recipientsByQueryId?: number;
|
recipientsByQueryId?: number | null;
|
||||||
recipientsByQuery?: QueryViewModel;
|
recipientsByQuery?: QueryViewModel | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateNewsletterViewModel {
|
export interface CreateNewsletterViewModel {
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<QuillEditor
|
<QuillEditor
|
||||||
id="summary"
|
id="summary"
|
||||||
theme="snow"
|
theme="snow"
|
||||||
placeholder="Zusammenfassung zur Sitzung..."
|
placeholder="Zusammenfassung zum Newsletter..."
|
||||||
style="height: 250px; max-height: 250px; min-height: 250px"
|
style="height: 250px; max-height: 250px; min-height: 250px"
|
||||||
contentType="html"
|
contentType="html"
|
||||||
:toolbar="toolbarOptions"
|
:toolbar="toolbarOptions"
|
||||||
|
|
|
@ -5,11 +5,27 @@
|
||||||
↺ laden fehlgeschlagen
|
↺ laden fehlgeschlagen
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
-- select members by query
|
<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>
|
||||||
|
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<Combobox v-model="recipients" :disabled="!can('create', 'club', 'newsletter')" multiple>
|
<Combobox v-model="recipients" :disabled="!can('create', 'club', 'newsletter')" multiple>
|
||||||
<ComboboxLabel>Empfänger suchen</ComboboxLabel>
|
<ComboboxLabel>weitere Empfänger suchen</ComboboxLabel>
|
||||||
<div class="relative mt-1">
|
<div class="relative mt-1">
|
||||||
<ComboboxInput
|
<ComboboxInput
|
||||||
class="rounded-md shadow-sm relative block w-full px-3 py-2 border border-gray-300 focus:border-primary placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-0 focus:z-10 sm:text-sm resize-none"
|
class="rounded-md shadow-sm relative block w-full px-3 py-2 border border-gray-300 focus:border-primary placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-0 focus:z-10 sm:text-sm resize-none"
|
||||||
|
@ -64,7 +80,6 @@
|
||||||
</div>
|
</div>
|
||||||
</Combobox>
|
</Combobox>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
|
||||||
<p>Ausgewählte Empfänger</p>
|
<p>Ausgewählte Empfänger</p>
|
||||||
<div class="flex flex-col gap-2 grow overflow-y-auto">
|
<div class="flex flex-col gap-2 grow overflow-y-auto">
|
||||||
<div
|
<div
|
||||||
|
@ -104,8 +119,12 @@ import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
|
||||||
import { TrashIcon } from "@heroicons/vue/24/outline";
|
import { TrashIcon } from "@heroicons/vue/24/outline";
|
||||||
import { useMemberStore } from "@/stores/admin/member";
|
import { useMemberStore } from "@/stores/admin/member";
|
||||||
import type { MemberViewModel } from "@/viewmodels/admin/member.models";
|
import type { MemberViewModel } from "@/viewmodels/admin/member.models";
|
||||||
|
import { useNewsletterStore } from "@/stores/admin/newsletter";
|
||||||
import { useNewsletterRecipientsStore } from "@/stores/admin/newsletterRecipients";
|
import { useNewsletterRecipientsStore } from "@/stores/admin/newsletterRecipients";
|
||||||
import { useAbilityStore } from "@/stores/ability";
|
import { useAbilityStore } from "@/stores/ability";
|
||||||
|
import { useQueryStoreStore } from "@/stores/admin/queryStore";
|
||||||
|
import { useQueryBuilderStore } from "@/stores/admin/queryBuilder";
|
||||||
|
import cloneDeep from "lodash.clonedeep";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -113,6 +132,11 @@ export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
newsletterId: String,
|
newsletterId: String,
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
recipientsByQuery() {
|
||||||
|
this.loadQuery();
|
||||||
|
},
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
query: "" as String,
|
query: "" as String,
|
||||||
|
@ -120,7 +144,10 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapWritableState(useNewsletterRecipientsStore, ["recipients", "loading"]),
|
...mapWritableState(useNewsletterRecipientsStore, ["recipients", "loading"]),
|
||||||
|
...mapWritableState(useNewsletterStore, ["activeNewsletterObj"]),
|
||||||
...mapState(useMemberStore, ["members"]),
|
...mapState(useMemberStore, ["members"]),
|
||||||
|
...mapState(useQueryStoreStore, ["queries"]),
|
||||||
|
...mapState(useQueryBuilderStore, ["data"]),
|
||||||
...mapState(useAbilityStore, ["can"]),
|
...mapState(useAbilityStore, ["can"]),
|
||||||
filtered(): Array<MemberViewModel> {
|
filtered(): Array<MemberViewModel> {
|
||||||
return this.query === ""
|
return this.query === ""
|
||||||
|
@ -144,20 +171,60 @@ export default defineComponent({
|
||||||
selected(): Array<MemberViewModel> {
|
selected(): Array<MemberViewModel> {
|
||||||
return this.members.filter((m) => this.recipients.includes(m.id));
|
return this.members.filter((m) => this.recipients.includes(m.id));
|
||||||
},
|
},
|
||||||
|
queried(): Array<MemberViewModel> {
|
||||||
|
let keys = Object.keys(this.data?.[0] ?? {});
|
||||||
|
let memberKey = keys.find((k) => k.includes("member_id"));
|
||||||
|
return this.members.filter((m) =>
|
||||||
|
this.data
|
||||||
|
.map((t) => ({
|
||||||
|
id: t.id,
|
||||||
|
...(memberKey ? { memberId: t[memberKey] } : {}),
|
||||||
|
}))
|
||||||
|
.some((d) => (d.memberId ?? d.id) == m.id)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
recipientsByQueryId: {
|
||||||
|
get() {
|
||||||
|
return this.activeNewsletterObj?.recipientsByQueryId ?? "def";
|
||||||
|
},
|
||||||
|
set(val: string) {
|
||||||
|
if (this.activeNewsletterObj == undefined) return;
|
||||||
|
if (val == "def") {
|
||||||
|
this.activeNewsletterObj.recipientsByQueryId = null;
|
||||||
|
this.activeNewsletterObj.recipientsByQuery = null;
|
||||||
|
} else if (this.queries.find((q) => q.id == parseInt(val))) {
|
||||||
|
this.activeNewsletterObj.recipientsByQueryId = parseInt(val);
|
||||||
|
this.activeNewsletterObj.recipientsByQuery = cloneDeep(this.queries.find((q) => q.id == parseInt(val)));
|
||||||
|
this.sendQuery(0, 1000, this.recipientsByQuery?.query);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
recipientsByQuery() {
|
||||||
|
return this.activeNewsletterObj?.recipientsByQuery;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetchMembers();
|
this.fetchMembers(0, 1000, true);
|
||||||
this.fetchNewsletterRecipients();
|
this.fetchNewsletterRecipients();
|
||||||
|
this.fetchQueries();
|
||||||
|
this.loadQuery();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions(useMemberStore, ["fetchMembers"]),
|
...mapActions(useMemberStore, ["fetchMembers"]),
|
||||||
...mapActions(useNewsletterRecipientsStore, ["fetchNewsletterRecipients"]),
|
...mapActions(useNewsletterRecipientsStore, ["fetchNewsletterRecipients"]),
|
||||||
|
...mapActions(useQueryStoreStore, ["fetchQueries"]),
|
||||||
|
...mapActions(useQueryBuilderStore, ["sendQuery"]),
|
||||||
removeSelected(id: number) {
|
removeSelected(id: number) {
|
||||||
let index = this.recipients.findIndex((s) => s == id);
|
let index = this.recipients.findIndex((s) => s == id);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
this.recipients.splice(index, 1);
|
this.recipients.splice(index, 1);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
loadQuery() {
|
||||||
|
if (this.recipientsByQuery) {
|
||||||
|
this.sendQuery(0, 1000, this.recipientsByQuery.query);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -141,7 +141,7 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetchMembers();
|
this.fetchMembers(0, 1000, true);
|
||||||
this.fetchProtocolPresence();
|
this.fetchProtocolPresence();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
Loading…
Reference in a new issue