From 3edeee1512f6f4544b2c34051c07233e91d3cdfe Mon Sep 17 00:00:00 2001 From: Riyadh Date: Wed, 20 May 2026 11:16:31 +0000 Subject: [PATCH] Remove HTML from meeting notification subjects Strip HTML tags from meeting subjects using a helper function in `executive-meeting-scheduler.ts` to ensure plain text display in push notifications. --- .../src/lib/executive-meeting-scheduler.ts | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/artifacts/api-server/src/lib/executive-meeting-scheduler.ts b/artifacts/api-server/src/lib/executive-meeting-scheduler.ts index 8a45d09c..7a6b0410 100644 --- a/artifacts/api-server/src/lib/executive-meeting-scheduler.ts +++ b/artifacts/api-server/src/lib/executive-meeting-scheduler.ts @@ -20,6 +20,29 @@ function pad2(n: number): string { return String(n).padStart(2, "0"); } +/** + * Reduce a rich-text snippet (Tiptap HTML) to plain text safe for a + * push-notification body. Meeting titles are stored as rich text so the + * scheduler can't just shove them into the payload — iOS shows the raw + * `

` markup verbatim on the lock + * screen otherwise. + */ +function stripHtmlToPlainText(input: string | null | undefined): string { + if (!input) return ""; + // Drop tags, collapse whitespace, decode the handful of named + // entities Tiptap emits. Anything more (full HTML parser) would + // pull a dependency for zero benefit on a 1-line notification. + const noTags = input.replace(/<[^>]*>/g, " "); + const decoded = noTags + .replace(/ /g, " ") + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/"/g, '"') + .replace(/'/g, "'"); + return decoded.replace(/\s+/g, " ").trim(); +} + function dateKey(d: Date): string { return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`; } @@ -125,8 +148,14 @@ async function tickOnce(): Promise { const titleAr = "تذكير اجتماع"; const titleEn = "Meeting reminder"; - const subjectAr = meeting.titleAr || meeting.titleEn || "اجتماع"; - const subjectEn = meeting.titleEn || meeting.titleAr || "Meeting"; + const subjectAr = + stripHtmlToPlainText(meeting.titleAr) || + stripHtmlToPlainText(meeting.titleEn) || + "اجتماع"; + const subjectEn = + stripHtmlToPlainText(meeting.titleEn) || + stripHtmlToPlainText(meeting.titleAr) || + "Meeting"; const bodyAr = `${subjectAr} يبدأ خلال ${deltaMin} دقيقة`; const bodyEn = `${subjectEn} starts in ${deltaMin} min`;