Files
accounted/lib/email/consent-notification-templates.ts
T
Jakob WennbergandClaude Sonnet 5 ec27228a8e style: remove em/en dashes repo-wide, add CLAUDE.md rule against them (#890)
Em dashes (—) and en dashes (–) had spread across comments, docs, tests,
and a few UI strings, reading as AI-generated boilerplate rather than
house style. Replaced each with punctuation matching its context: colon
for explanatory clauses, comma for asides, plain hyphen for numeric/legal
ranges (e.g. "21-23§"), "to"/"till" for date ranges, parentheses for
paired-dash asides. messages/en.json and messages/sv.json were fixed by
hand together to keep sv/en in sync.

Left untouched where the dash is the functional subject rather than
decorative punctuation: date-range-parser.ts's separator regex,
charset-repair.ts's CP1252 byte-mapping table (and its test), the SIE
encoding mojibake docs, generic-csv.ts's minus-sign normalizer, the
agent system-prompt files that already instruct against em dashes, and
a golden iXBRL test fixture compared byte-for-byte.

Also fixes two bugs surfaced along the way: an off-by-one in
ApiKeysPanel's scope-label split (a leftover from an earlier partial
pass), and a charset-repair test that had lost the literal en-dash it
exists to verify.

Regenerated the agent atom seed migration (skills:generate) since 27
SKILL.md files changed. Added a CLAUDE.md rule against em/en dashes,
with an explicit carve-out for the functional-dash cases above.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04 15:58:06 +02:00

118 lines
4.5 KiB
TypeScript

import { getBranding } from '@/lib/branding/service'
export interface ConsentExpiryEmailData {
bankName: string
daysUntilExpiry: number
renewalUrl: string
companyName: string
isExpired: boolean
}
/**
* Generate HTML email for consent expiry notification
*/
export function generateConsentExpiryEmailHtml(data: ConsentExpiryEmailData): string {
const { bankName, daysUntilExpiry, renewalUrl, companyName, isExpired } = data
const { appName } = getBranding()
const headerColor = isExpired ? '#dc2626' : '#ea580c'
const title = isExpired
? 'Banksynkronisering har stoppats'
: `Samtycket för ${bankName} löper ut snart`
return `
<!DOCTYPE html>
<html lang="sv">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title}</title>
</head>
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; line-height: 1.6; color: #333; background-color: #f9fafb;">
<div style="max-width: 600px; margin: 0 auto; padding: 40px 20px;">
<div style="background: white; border-radius: 12px; padding: 40px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
<div style="text-align: center; margin-bottom: 30px;">
<div style="display: inline-block; background: ${headerColor}15; color: ${headerColor}; padding: 8px 16px; border-radius: 20px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;">
${isExpired ? 'Åtgärd krävs' : 'Påminnelse'}
</div>
</div>
<h1 style="margin: 0 0 20px 0; font-size: 22px; font-weight: 600; color: #111; text-align: center;">
${title}
</h1>
<div style="margin-bottom: 30px;">
${isExpired ? `
<p style="margin: 0 0 15px 0; color: #dc2626; font-weight: 500;">
PSD2-samtycket för ${bankName} har löpt ut. Automatisk transaktionssynkronisering är stoppad.
</p>
<p style="margin: 0 0 15px 0;">
Förnya anslutningen för att återuppta synkroniseringen.
</p>
` : `
<p style="margin: 0 0 15px 0;">
Samtycket för ${bankName} löper ut om ${daysUntilExpiry} ${daysUntilExpiry === 1 ? 'dag' : 'dagar'}.
</p>
<p style="margin: 0 0 15px 0;">
Förnya anslutningen innan samtycket löper ut för att undvika avbrott i transaktionssynkroniseringen.
</p>
`}
</div>
<div style="text-align: center; margin-bottom: 30px;">
<a href="${renewalUrl}" style="display: inline-block; background: ${headerColor}; color: white; padding: 14px 28px; border-radius: 8px; text-decoration: none; font-weight: 500; font-size: 14px;">
${isExpired ? 'Förnya anslutning' : 'Hantera bankanslutningar'}
</a>
</div>
<div style="padding-top: 20px; border-top: 1px solid #e5e7eb;">
<p style="margin: 0; color: #666; font-size: 14px;">
Med vänliga hälsningar,<br>
<strong>${companyName || appName.toLowerCase()}</strong>
</p>
</div>
</div>
</div>
</body>
</html>
`
}
/**
* Generate plain text email for consent expiry notification
*/
export function generateConsentExpiryEmailText(data: ConsentExpiryEmailData): string {
const { bankName, daysUntilExpiry, renewalUrl, companyName, isExpired } = data
const { appName } = getBranding()
let text = ''
if (isExpired) {
text += `BANKSYNKRONISERING HAR STOPPATS\n`
text += `=`.repeat(40) + `\n\n`
text += `PSD2-samtycket för ${bankName} har löpt ut.\n`
text += `Automatisk transaktionssynkronisering är stoppad.\n\n`
text += `Förnya anslutningen för att återuppta synkroniseringen.\n\n`
} else {
text += `SAMTYCKET FÖR ${bankName.toUpperCase()} LÖPER UT SNART\n`
text += `=`.repeat(40) + `\n\n`
text += `Samtycket för ${bankName} löper ut om ${daysUntilExpiry} ${daysUntilExpiry === 1 ? 'dag' : 'dagar'}.\n\n`
text += `Förnya anslutningen innan samtycket löper ut för att undvika avbrott.\n\n`
}
text += `Hantera bankanslutningar: ${renewalUrl}\n\n`
text += `Med vänliga hälsningar,\n`
text += `${companyName || appName.toLowerCase()}\n`
return text
}
/**
* Generate email subject for consent expiry notification
*/
export function generateConsentExpiryEmailSubject(data: ConsentExpiryEmailData): string {
if (data.isExpired) {
return `Banksynkronisering stoppad - ${data.bankName}`
}
return `Banksamtycke löper ut om ${data.daysUntilExpiry} ${data.daysUntilExpiry === 1 ? 'dag' : 'dagar'} - ${data.bankName}`
}