diff --git a/src/components/Notification.vue b/src/components/Notification.vue index f208413..e320e19 100644 --- a/src/components/Notification.vue +++ b/src/components/Notification.vue @@ -113,10 +113,10 @@ export default defineComponent({ }, methods: { ...mapActions(useNotificationStore, ["revoke"]), - close(id: number) { + close(id: string) { this.revoke(id); }, - hovering(id: number, value: boolean, timeout?: number) { + hovering(id: string, value: boolean, timeout?: number) { if (value) { clearTimeout(this.timeouts[id]); } else { diff --git a/src/router/newsletterGuard.ts b/src/router/newsletterGuard.ts index d96cb8e..5d96cf9 100644 --- a/src/router/newsletterGuard.ts +++ b/src/router/newsletterGuard.ts @@ -9,8 +9,6 @@ export async function setNewsletterId(to: any, from: any, next: any) { useNewsletterDatesStore().$reset(); useNewsletterRecipientsStore().$reset(); - useNewsletterPrintoutStore().unsubscribePdfPrintingProgress(); - useNewsletterPrintoutStore().unsubscribeMailSendingProgress(); useNewsletterPrintoutStore().$reset(); next(); @@ -23,8 +21,6 @@ export async function resetNewsletterStores(to: any, from: any, next: any) { useNewsletterDatesStore().$reset(); useNewsletterRecipientsStore().$reset(); - useNewsletterPrintoutStore().unsubscribePdfPrintingProgress(); - useNewsletterPrintoutStore().unsubscribeMailSendingProgress(); useNewsletterPrintoutStore().$reset(); next(); diff --git a/src/serverCom.ts b/src/serverCom.ts index e5cc8e5..893a376 100644 --- a/src/serverCom.ts +++ b/src/serverCom.ts @@ -62,7 +62,7 @@ http.interceptors.response.use( .then(() => { return http(originalRequest); }) - .catch(); + .catch(() => {}); } const notificationStore = useNotificationStore(); @@ -108,4 +108,25 @@ function newEventSource(path: string) { }); } -export { http, newEventSource, host }; +async function* streamingFetch(path: string, abort?: AbortController) { + await refreshToken() + .then(() => {}) + .catch(() => {}); + + const token = localStorage.getItem("accessToken"); + const response = await fetch(url + "/api" + path, { + signal: abort?.signal, + headers: { + Authorization: `Bearer ${token}`, + }, + }); + + const reader = response.body?.getReader(); + while (true && reader) { + const { done, value } = await reader.read(); + if (done) break; + yield new TextDecoder().decode(value); + } +} + +export { http, newEventSource, streamingFetch, host }; diff --git a/src/stores/admin/club/newsletter/newsletterPrintout.ts b/src/stores/admin/club/newsletter/newsletterPrintout.ts index 0a12ef6..e4a500c 100644 --- a/src/stores/admin/club/newsletter/newsletterPrintout.ts +++ b/src/stores/admin/club/newsletter/newsletterPrintout.ts @@ -1,8 +1,9 @@ import { defineStore } from "pinia"; -import { http, newEventSource } from "@/serverCom"; +import { http, newEventSource, streamingFetch } from "@/serverCom"; import { useNewsletterStore } from "./newsletter"; import type { AxiosResponse } from "axios"; import type { EventSourcePolyfill } from "event-source-polyfill"; +import { useNotificationStore, type NotificationType } from "../../../notification"; export const useNewsletterPrintoutStore = defineStore("newsletterPrintout", { state: () => { @@ -12,10 +13,10 @@ export const useNewsletterPrintoutStore = defineStore("newsletterPrintout", { printing: undefined as undefined | "loading" | "success" | "failed", sending: undefined as undefined | "loading" | "success" | "failed", sendingPreview: undefined as undefined | "loading" | "success" | "failed", - pdfProgessSource: undefined as undefined | EventSourcePolyfill, - mailProgessSource: undefined as undefined | EventSourcePolyfill, pdfSourceMessages: [] as Array, mailSourceMessages: [] as Array, + pdfPrintingAbort: undefined as undefined | AbortController, + mailSendingAbort: undefined as undefined | AbortController, }; }, actions: { @@ -63,6 +64,7 @@ export const useNewsletterPrintoutStore = defineStore("newsletterPrintout", { }); }, createNewsletterPrintout() { + this.subscribePdfPrintingProgress(); this.printing = "loading"; const newsletterId = useNewsletterStore().activeNewsletter; if (newsletterId == null) return; @@ -78,10 +80,12 @@ export const useNewsletterPrintoutStore = defineStore("newsletterPrintout", { .finally(() => { setTimeout(() => { this.printing = undefined; + this.pdfPrintingAbort?.abort(); }, 1500); }); }, createNewsletterSend() { + this.subscribeMailSendingProgress(); this.sending = "loading"; const newsletterId = useNewsletterStore().activeNewsletter; if (newsletterId == null) return; @@ -96,32 +100,47 @@ export const useNewsletterPrintoutStore = defineStore("newsletterPrintout", { .finally(() => { setTimeout(() => { this.sending = undefined; + this.mailSendingAbort?.abort(); }, 1500); }); }, - subscribePdfPrintingProgress() { - // const newsletterId = useNewsletterStore().activeNewsletter; - // if (this.pdfProgessSource != undefined) return; - // this.pdfProgessSource = newEventSource(`/admin/newsletter/${newsletterId}/printoutprogress`); - // this.pdfProgessSource.onmessage = (event) => { - // console.log("pdf", event); - // }; + async subscribePdfPrintingProgress() { + this.pdfSourceMessages = []; + const newsletterId = useNewsletterStore().activeNewsletter; + const notificationStore = useNotificationStore(); + this.pdfPrintingAbort = new AbortController(); + for await (let chunk of streamingFetch( + `/admin/newsletter/${newsletterId}/printoutprogress`, + this.pdfPrintingAbort + )) { + chunk.split("//").forEach((r) => { + if (r.trim() != "") { + let data = JSON.parse(r); + this.pdfSourceMessages.push(data); + let type: NotificationType = "info"; + if (data.factor == "failed") type = "error"; + notificationStore.push(`Druck: ${data.iteration}/${data.total}`, `${data.msg}`, type); + } + }); + this.fetchNewsletterPrintout(); + } }, - subscribeMailSendingProgress() { - // const newsletterId = useNewsletterStore().activeNewsletter; - // if (this.mailProgessSource != undefined) return; - // this.mailProgessSource = newEventSource(`/admin/newsletter/${newsletterId}/sendprogress`); - // this.mailProgessSource.onmessage = (event) => { - // console.log("mail", event); - // }; - }, - unsubscribePdfPrintingProgress() { - this.pdfProgessSource?.close(); - this.pdfProgessSource = undefined; - }, - unsubscribeMailSendingProgress() { - this.mailProgessSource?.close(); - this.mailProgessSource = undefined; + async subscribeMailSendingProgress() { + this.mailSourceMessages = []; + const newsletterId = useNewsletterStore().activeNewsletter; + const notificationStore = useNotificationStore(); + this.mailSendingAbort = new AbortController(); + for await (let chunk of streamingFetch(`/admin/newsletter/${newsletterId}/sendprogress`, this.mailSendingAbort)) { + chunk.split("//").forEach((r) => { + if (r.trim() != "") { + let data = JSON.parse(r); + this.mailSourceMessages.push(data); + let type: NotificationType = "info"; + if (data.factor == "failed") type = "error"; + notificationStore.push(`Mailversand: ${data.iteration}/${data.total}`, `${data.msg}`, type); + } + }); + } }, }, }); diff --git a/src/stores/notification.ts b/src/stores/notification.ts index 249f2c0..49297aa 100644 --- a/src/stores/notification.ts +++ b/src/stores/notification.ts @@ -1,7 +1,7 @@ import { defineStore } from "pinia"; export interface Notification { - id: number; + id: string; title: string; text: string; type: NotificationType; @@ -19,7 +19,7 @@ export const useNotificationStore = defineStore("notification", { }, actions: { push(title: string, text: string, type: NotificationType, timeout: number = 5000) { - let id = Date.now(); + let id = `${Date.now()}_${Math.random()}`; this.notifications.push({ id, title, @@ -34,7 +34,7 @@ export const useNotificationStore = defineStore("notification", { this.revoke(id); }, timeout); }, - revoke(id: number) { + revoke(id: string) { this.notifications.splice( this.notifications.findIndex((n) => n.id === id), 1 diff --git a/src/views/admin/club/newsletter/NewsletterPrintout.vue b/src/views/admin/club/newsletter/NewsletterPrintout.vue index 90c06c0..dfa2ccf 100644 --- a/src/views/admin/club/newsletter/NewsletterPrintout.vue +++ b/src/views/admin/club/newsletter/NewsletterPrintout.vue @@ -89,8 +89,6 @@ export default defineComponent({ }, mounted() { this.fetchNewsletterPrintout(); - this.subscribeMailSendingProgress(); - this.subscribePdfPrintingProgress(); }, methods: { ...mapActions(useModalStore, ["openModal"]), @@ -100,8 +98,6 @@ export default defineComponent({ "fetchNewsletterPrintoutById", "createNewsletterMailPreview", "createNewsletterSend", - "subscribeMailSendingProgress", - "subscribePdfPrintingProgress", ]), openPdfShow(filename?: string) { this.openModal(