send or print newsletter preview

This commit is contained in:
Julian Krauser 2024-12-28 18:03:20 +01:00
parent 81b7f533c7
commit 080b6a2b78
8 changed files with 322 additions and 58 deletions

View file

@ -0,0 +1,71 @@
<template>
<div class="flex flex-col gap-2 h-full w-full overflow-y-auto">
<div v-if="activeNewsletterObj != null" class="flex flex-col gap-2 w-full">
<div class="w-full">
<label for="title">Überschrift</label>
<QuillEditor
id="summary"
theme="snow"
placeholder="Überschrift des Newsletters..."
style="height: 150px; max-height: 150px; min-height: 150px"
contentType="html"
:toolbar="toolbarOptions"
v-model:content="activeNewsletterObj.newsletterTitle"
:enable="can('create', 'club', 'newsletter')"
:style="!can('create', 'club', 'newsletter') ? 'opacity: 75%; background: rgb(243 244 246)' : ''"
/>
</div>
<div class="flex flex-col h-1/2">
<label for="summary">Text</label>
<QuillEditor
id="summary"
theme="snow"
placeholder="Text zum Newsletter..."
style="height: 150px; max-height: 150px; min-height: 150px"
contentType="html"
:toolbar="toolbarOptions"
v-model:content="activeNewsletterObj.newsletterText"
:enable="can('create', 'club', 'newsletter')"
:style="!can('create', 'club', 'newsletter') ? 'opacity: 75%; background: rgb(243 244 246)' : ''"
/>
</div>
<div class="flex flex-col h-1/2">
<label for="summary">Signatur</label>
<QuillEditor
id="summary"
theme="snow"
placeholder="Zusammenfassung zum Newsletter..."
style="height: 150px; max-height: 150px; min-height: 150px"
contentType="html"
:toolbar="toolbarOptions"
v-model:content="activeNewsletterObj.newsletterSignatur"
:enable="can('create', 'club', 'newsletter')"
:style="!can('create', 'club', 'newsletter') ? 'opacity: 75%; background: rgb(243 244 246)' : ''"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { defineComponent } from "vue";
import { mapActions, mapState, mapWritableState } from "pinia";
import Spinner from "@/components/Spinner.vue";
import { useNewsletterStore } from "@/stores/admin/newsletter";
import { QuillEditor } from "@vueup/vue-quill";
import "@vueup/vue-quill/dist/vue-quill.snow.css";
import { toolbarOptions } from "@/helpers/quillConfig";
import { useAbilityStore } from "@/stores/ability";
</script>
<script lang="ts">
export default defineComponent({
props: {
newsletterId: String,
},
computed: {
...mapWritableState(useNewsletterStore, ["loadingActive", "activeNewsletterObj"]),
...mapState(useAbilityStore, ["can"]),
},
});
</script>

View file

@ -1,6 +1,10 @@
<template>
<div class="flex flex-col gap-2 h-full w-full overflow-y-auto">
<div v-if="activeNewsletterObj != null" class="flex flex-col gap-2 w-full">
<p class="italic">
Titel und Zusammenfassung werden standardmäßig nicht im Newsletter angezeit, können aber bei Verwendung eines
eigenen Templates verwendet werden.
</p>
<div class="w-full">
<label for="title">Titel</label>
<input

View file

@ -1,49 +1,68 @@
<template>
<!-- <div class="flex flex-col gap-2 h-full w-full overflow-y-auto">
<div class="flex flex-col gap-2 h-full w-full overflow-y-auto">
<Spinner v-if="loading == 'loading'" class="mx-auto" />
<p v-else-if="loading == 'failed'" @click="fetchProtocolPrintout" class="cursor-pointer">
<p v-else-if="loading == 'failed'" @click="fetchNewsletterPrintout" class="cursor-pointer">
&#8634; laden fehlgeschlagen
</p>
<div class="flex flex-col gap-2 h-full overflow-y-auto">
<div
v-for="print in printout"
:key="print.id"
class="flex flex-col h-fit w-full border border-primary rounded-md"
>
<div v-for="print in printout" :key="print" class="flex flex-col h-fit w-full border border-primary rounded-md">
<div class="bg-primary p-2 text-white flex flex-row justify-between items-center">
<p>{{ print.title }}</p>
<p>{{ print }}</p>
<div class="flex flex-row">
<div>
<ViewfinderCircleIcon class="w-5 h-5 p-1 box-content cursor-pointer" @click="openPdfShow(print.id)" />
<ViewfinderCircleIcon class="w-5 h-5 p-1 box-content cursor-pointer" @click="openPdfShow(print)" />
</div>
<div>
<ArrowDownTrayIcon class="w-5 h-5 p-1 box-content cursor-pointer" @click="downloadPdf(print.id)" />
<ArrowDownTrayIcon class="w-5 h-5 p-1 box-content cursor-pointer" @click="downloadPdf(print)" />
</div>
</div>
</div>
<div class="p-2">
<p>Ausdruck Nummer: {{ print.iteration }}</p>
<p>Ausdruck erstellt: {{ print.createdAt }}</p>
</div>
</div>
</div>
<div class="flex flex-row justify-start gap-2">
<div class="flex flex-row flex-wrap justify-start gap-2">
<button
v-if="can('create', 'club', 'newsletter')"
primary
class="!w-fit"
:disabled="printing != undefined"
@click="createProtocolPrintout"
@click="createNewsletterPrintout"
>
Ausdruck erstellen
Newsletter drucken
<Spinner v-if="printing == 'loading'" class="my-auto" />
<SuccessCheckmark v-else-if="printing == 'success'" />
<FailureXMark v-else-if="printing == 'failed'" />
</button>
<button
v-if="can('create', 'club', 'newsletter')"
primary
class="!w-fit"
:disabled="sending != undefined"
@click="createNewsletterSend"
>
Mails versenden
<Spinner v-if="sending == 'loading'" class="my-auto" />
<SuccessCheckmark v-else-if="sending == 'success'" />
<FailureXMark v-else-if="sending == 'failed'" />
</button>
<button v-if="can('create', 'club', 'newsletter')" primary-outline class="!w-fit" @click="openPdfShow()">
Newsletter Vorschau
</button>
<button
v-if="can('create', 'club', 'newsletter')"
primary-outline
class="!w-fit"
:disabled="sendingPreview != undefined"
@click="createNewsletterMailPreview"
>
Mail Vorschau
<Spinner v-if="sendingPreview == 'loading'" class="my-auto" />
<SuccessCheckmark v-else-if="sendingPreview == 'success'" />
<FailureXMark v-else-if="sendingPreview == 'failed'" />
</button>
<Spinner v-if="printing == 'loading'" class="my-auto" />
<SuccessCheckmark v-else-if="printing == 'success'" />
<FailureXMark v-else-if="printing == 'failed'" />
</div>
</div> -->
</div>
</template>
<script setup lang="ts">
@ -52,10 +71,11 @@ import { mapActions, mapState } from "pinia";
import Spinner from "@/components/Spinner.vue";
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
import FailureXMark from "@/components/FailureXMark.vue";
// import { useProtocolPrintoutStore } from "@/stores/admin/newsletterPrintout";
// import { useNewsletterPrintoutStore } from "@/stores/admin/newsletterPrintout";
import { ArrowDownTrayIcon, ViewfinderCircleIcon } from "@heroicons/vue/24/outline";
import { useModalStore } from "@/stores/modal";
import { useAbilityStore } from "@/stores/ability";
import { useNewsletterPrintoutStore } from "../../../../stores/admin/newsletterPrintout";
</script>
<script lang="ts">
@ -63,40 +83,41 @@ export default defineComponent({
props: {
newsletterId: String,
},
// computed: {
// ...mapState(useProtocolPrintoutStore, ["printout", "loading", "printing"]),
// ...mapState(useAbilityStore, ["can"]),
// },
// mounted() {
// this.fetchProtocolPrintout();
// },
// methods: {
// ...mapActions(useModalStore, ["openModal"]),
// ...mapActions(useProtocolPrintoutStore, [
// "fetchProtocolPrintout",
// "createProtocolPrintout",
// "fetchProtocolPrintoutById",
// ]),
// openPdfShow(id: number) {
// this.openModal(
// markRaw(defineAsyncComponent(() => import("@/components/admin/club/newsletter/ProtocolPrintoutViewerModal.vue"))),
// id
// );
// },
// downloadPdf(id: number) {
// let clickedOn = this.printout.find((p) => p.id == id);
// this.fetchProtocolPrintoutById(id)
// .then((response) => {
// const fileURL = window.URL.createObjectURL(new Blob([response.data]));
// const fileLink = document.createElement("a");
// fileLink.href = fileURL;
// fileLink.setAttribute("download", clickedOn?.title ? clickedOn.title + ".pdf" : "Protokoll.pdf");
// document.body.appendChild(fileLink);
// fileLink.click();
// fileLink.remove();
// })
// .catch(() => {});
// },
// },
computed: {
...mapState(useNewsletterPrintoutStore, ["printout", "loading", "printing", "sending", "sendingPreview"]),
...mapState(useAbilityStore, ["can"]),
},
mounted() {
this.fetchNewsletterPrintout();
},
methods: {
...mapActions(useModalStore, ["openModal"]),
...mapActions(useNewsletterPrintoutStore, [
"fetchNewsletterPrintout",
"createNewsletterPrintout",
"fetchNewsletterPrintoutById",
"createNewsletterMailPreview",
"createNewsletterSend",
]),
openPdfShow(filename?: string) {
this.openModal(
markRaw(defineAsyncComponent(() => import("@/components/admin/club/newsletter/NewsletterPreviewModal.vue"))),
filename
);
},
downloadPdf(filename: string) {
this.fetchNewsletterPrintoutById(filename)
.then((response) => {
const fileURL = window.URL.createObjectURL(new Blob([response.data]));
const fileLink = document.createElement("a");
fileLink.href = fileURL;
fileLink.setAttribute("download", filename + ".pdf");
document.body.appendChild(fileLink);
fileLink.click();
fileLink.remove();
})
.catch(() => {});
},
},
});
</script>

View file

@ -53,6 +53,8 @@ import { useNewsletterStore } from "@/stores/admin/newsletter";
import { useModalStore } from "@/stores/modal";
import NewsletterSyncing from "@/components/admin/club/newsletter/NewsletterSyncing.vue";
import { PrinterIcon } from "@heroicons/vue/24/outline";
import { useNewsletterDatesStore } from "../../../../stores/admin/newsletterDates";
import { useNewsletterRecipientsStore } from "../../../../stores/admin/newsletterRecipients";
</script>
<script lang="ts">
@ -72,6 +74,7 @@ export default defineComponent({
return {
tabs: [
{ route: "admin-club-newsletter-overview", title: "Übersicht" },
{ route: "admin-club-newsletter-data", title: "Daten" },
{ route: "admin-club-newsletter-dates", title: "Termine" },
{ route: "admin-club-newsletter-recipients", title: "Empfänger" },
{ route: "admin-club-newsletter-printout", title: "Druck/Versand" },
@ -86,6 +89,8 @@ export default defineComponent({
},
mounted() {
this.fetchNewsletterByActiveId();
this.fetchNewsletterDates();
this.fetchNewsletterRecipients();
},
// this.syncState is undefined, so it will never work
// beforeRouteLeave(to, from, next) {
@ -106,6 +111,8 @@ export default defineComponent({
// },
methods: {
...mapActions(useNewsletterStore, ["fetchNewsletterByActiveId"]),
...mapActions(useNewsletterDatesStore, ["fetchNewsletterDates"]),
...mapActions(useNewsletterRecipientsStore, ["fetchNewsletterRecipients"]),
...mapActions(useModalStore, ["openModal"]),
openInfoModal() {
this.openModal(