v1.4: HTML-E-Mail-Benachrichtigungen im Schulportal-Stil
- server/src/mail.js: baueHtmlMail/buttonHtml (600-px-Karte, Kopfzeile in Hinterstein-Farben #22333b + Amber, Zeilen-Tabelle, Status-Box, Zitat-Box, Aktions-Button 'Zum Mieterportal', Footer), immer mit Plain-Text-Fallback - index.js: Ticket, neue Unterhaltung und Antwort versenden HTML + Text (multipart/alternative ueber die Mail-API) - Vorschauen: preview/08-mail-ticket.png, preview/08-mail-nachricht.png - E2E live verifiziert (Zustellung an axel@hocks.eu, status=sent), Doku
This commit is contained in:
+47
-11
@@ -258,12 +258,25 @@ app.post('/api/tickets', auth, async (req, res, next) => {
|
||||
deutschesDatum()],
|
||||
)
|
||||
const label = mail.einheitLabel(mapUnit(unitRows[0]))
|
||||
mail.benachrichtigeVerwaltung(
|
||||
`Neue Schadensmeldung: ${String(title).trim()} (${label})`,
|
||||
const betreff = `Neue Schadensmeldung: ${String(title).trim()} (${label})`
|
||||
const text =
|
||||
`Im Mieterportal wurde eine neue Schadensmeldung erstellt.\n\n` +
|
||||
`Wohnung: ${label}\nMeldung von: ${mieterName}\nKategorie: ${String(category || 'Sonstiges')}\n\n` +
|
||||
`${String(title).trim()}\n${String(description || '–').trim()}`,
|
||||
)
|
||||
`Wohnung: ${label}\nMeldung von: ${mieterName}\nKategorie: ${String(category || 'Sonstiges')}\n\n` +
|
||||
`${String(title).trim()}\n${String(description || '–').trim()}`
|
||||
const html = mail.baueHtmlMail({
|
||||
titel: 'Neue Schadensmeldung',
|
||||
untertitel: label,
|
||||
einleitung: 'Im Mieterportal wurde eine neue Schadensmeldung erstellt:',
|
||||
zeilen: [
|
||||
['Wohnung', label],
|
||||
['Meldung von', mieterName],
|
||||
['Kategorie', String(category || 'Sonstiges')],
|
||||
],
|
||||
statusBox: { hintergrund: '#f0fdfa', farbe: '#0f766e', text: 'Status: offen – neu eingegangen' },
|
||||
zitat: `${String(title).trim()}\n${String(description || '–').trim()}`,
|
||||
aktionenHtml: mail.buttonHtml('Zum Mieterportal', `${process.env.PORTAL_URL || 'https://mieterportal.hocks.eu'}/schadensmeldungen`),
|
||||
})
|
||||
mail.benachrichtigeVerwaltung(betreff, text, html)
|
||||
res.json({ ticket: mapTicket(rows[0]) })
|
||||
} catch (e) { next(e) }
|
||||
})
|
||||
@@ -308,9 +321,20 @@ app.post('/api/threads', auth, async (req, res, next) => {
|
||||
const betreff = vonRolle === 'tenant'
|
||||
? `Neue Nachricht im Mieterportal: ${String(subject).trim()}`
|
||||
: `Nachricht der Verwaltung: ${String(subject).trim()}`
|
||||
const inhalt = `Neue Unterhaltung von ${autor}:\n\n„${String(text).trim()}“`
|
||||
if (vonRolle === 'tenant') mail.benachrichtigeVerwaltung(betreff, inhalt)
|
||||
else mail.benachrichtigeMieter(unitId, betreff, inhalt)
|
||||
const textVersion = `Neue Unterhaltung von ${autor}:\n\n„${String(text).trim()}“`
|
||||
const html = mail.baueHtmlMail({
|
||||
titel: vonRolle === 'tenant' ? 'Neue Nachricht' : 'Nachricht der Verwaltung',
|
||||
untertitel: String(subject).trim(),
|
||||
einleitung: `Neue Unterhaltung von ${autor}:`,
|
||||
zeilen: [
|
||||
['Wohnung', mail.einheitLabel(mapUnit(unitRows[0]))],
|
||||
['Betreff', String(subject).trim()],
|
||||
],
|
||||
zitat: String(text).trim(),
|
||||
aktionenHtml: mail.buttonHtml('Zum Mieterportal', `${process.env.PORTAL_URL || 'https://mieterportal.hocks.eu'}/nachrichten`),
|
||||
})
|
||||
if (vonRolle === 'tenant') mail.benachrichtigeVerwaltung(betreff, textVersion, html)
|
||||
else mail.benachrichtigeMieter(unitId, betreff, textVersion, html)
|
||||
const { rows } = await pool.query('SELECT * FROM threads WHERE id = $1', [id])
|
||||
const { rows: msgRows } = await pool.query('SELECT * FROM messages WHERE thread_id = $1 ORDER BY at', [id])
|
||||
res.json({ thread: { ...mapThread(rows[0]), messages: msgRows.map(mapMessage) } })
|
||||
@@ -340,9 +364,21 @@ app.post('/api/threads/:id/messages', auth, async (req, res, next) => {
|
||||
const betreff = vonRolle === 'tenant'
|
||||
? `Neue Antwort im Mieterportal: ${th.subject}`
|
||||
: `Antwort der Verwaltung: ${th.subject}`
|
||||
const inhalt = `Neue Nachricht von ${autor} in der Unterhaltung „${th.subject}“:\n\n„${text}“`
|
||||
if (vonRolle === 'tenant') mail.benachrichtigeVerwaltung(betreff, inhalt)
|
||||
else mail.benachrichtigeMieter(th.unit_id, betreff, inhalt)
|
||||
const { rows: einheitRows } = await pool.query('SELECT * FROM units WHERE id = $1', [th.unit_id])
|
||||
const textVersion = `Neue Nachricht von ${autor} in der Unterhaltung „${th.subject}“:\n\n„${text}“`
|
||||
const html = mail.baueHtmlMail({
|
||||
titel: vonRolle === 'tenant' ? 'Neue Antwort' : 'Antwort der Verwaltung',
|
||||
untertitel: th.subject,
|
||||
einleitung: `Neue Nachricht von ${autor}:`,
|
||||
zeilen: [
|
||||
['Wohnung', mail.einheitLabel(mapUnit(einheitRows[0]))],
|
||||
['Unterhaltung', th.subject],
|
||||
],
|
||||
zitat: text,
|
||||
aktionenHtml: mail.buttonHtml('Zum Mieterportal', `${process.env.PORTAL_URL || 'https://mieterportal.hocks.eu'}/nachrichten`),
|
||||
})
|
||||
if (vonRolle === 'tenant') mail.benachrichtigeVerwaltung(betreff, textVersion, html)
|
||||
else mail.benachrichtigeMieter(th.unit_id, betreff, textVersion, html)
|
||||
const { rows: msgRows } = await pool.query('SELECT * FROM messages WHERE thread_id = $1 ORDER BY at', [th.id])
|
||||
const { rows } = await pool.query('SELECT * FROM threads WHERE id = $1', [th.id])
|
||||
res.json({ thread: { ...mapThread(rows[0]), messages: msgRows.map(mapMessage) } })
|
||||
|
||||
Reference in New Issue
Block a user