// Mail-Templates für Supabase Auth-Hook (Send-Email-Hook). // GoTrue posted Hook-Body → wir rendern Subject + SenderName + HTML // pro Mail-Typ × Locale, dann via Brevo Transactional API versendet. // // Vorteil vs Public-HTML-Templates: dynamic Sender-Name + dynamic Subject // (GoTrue's eingebaute Mail-Config ist global statisch). export type EmailActionType = | 'signup' | 'recovery' | 'magiclink' | 'invite' | 'email_change'; export type Locale = 'de' | 'en' | 'fr' | 'ar'; const SUPPORTED_LOCALES: Locale[] = ['de', 'en', 'fr', 'ar']; export function normalizeLocale(input: string | undefined | null): Locale { if (!input) return 'en'; const short = String(input).split('-')[0].toLowerCase(); return (SUPPORTED_LOCALES as readonly string[]).includes(short) ? (short as Locale) : 'en'; } interface Texts { senderName: string; subject: string; title: string; body: string; helpText: string; privacyLabel: string; } const TEXTS: Record> = { signup: { de: { senderName: 'Willkommen bei ReBreak', subject: 'Bestätige deine E-Mail – ReBreak', title: 'Willkommen bei ReBreak', body: 'Gib diesen Code in der App ein, um deine E-Mail-Adresse zu bestätigen:', helpText: 'Falls du dich nicht bei ReBreak registriert hast, kannst du diese E-Mail ignorieren.', privacyLabel: 'Datenschutz', }, en: { senderName: 'Welcome to ReBreak', subject: 'Confirm your email – ReBreak', title: 'Welcome to ReBreak', body: 'Enter this code in the app to confirm your email address:', helpText: "If you didn't sign up for ReBreak, you can safely ignore this email.", privacyLabel: 'Privacy', }, fr: { senderName: 'Bienvenue sur ReBreak', subject: 'Confirme ton e-mail – ReBreak', title: 'Bienvenue sur ReBreak', body: "Saisis ce code dans l'application pour confirmer ton adresse e-mail :", helpText: "Si tu n'as pas créé de compte ReBreak, tu peux ignorer ce message.", privacyLabel: 'Confidentialité', }, ar: { senderName: 'مرحبًا بك في ReBreak', subject: 'تأكيد البريد الإلكتروني – ReBreak', title: 'مرحبًا بك في ReBreak', body: 'أدخل هذا الرمز في التطبيق لتأكيد بريدك الإلكتروني:', helpText: 'إذا لم تقم بإنشاء حساب على ReBreak، يمكنك تجاهل هذه الرسالة.', privacyLabel: 'الخصوصية', }, }, recovery: { de: { senderName: 'ReBreak Passwort-Reset', subject: 'Passwort zurücksetzen – ReBreak', title: 'Passwort zurücksetzen', body: 'Gib diesen Code in der App ein, um ein neues Passwort zu setzen:', helpText: 'Falls du das nicht angefordert hast, kannst du diese E-Mail ignorieren — dein Passwort bleibt unverändert.', privacyLabel: 'Datenschutz', }, en: { senderName: 'ReBreak Password Reset', subject: 'Reset your password – ReBreak', title: 'Reset your password', body: 'Enter this code in the app to set a new password:', helpText: "If you didn't request this, you can ignore this email — your password stays the same.", privacyLabel: 'Privacy', }, fr: { senderName: 'Réinitialisation ReBreak', subject: 'Réinitialise ton mot de passe – ReBreak', title: 'Réinitialise ton mot de passe', body: "Saisis ce code dans l'application pour définir un nouveau mot de passe :", helpText: "Si tu n'as pas demandé cette réinitialisation, ignore ce message — ton mot de passe reste inchangé.", privacyLabel: 'Confidentialité', }, ar: { senderName: 'إعادة تعيين كلمة المرور ReBreak', subject: 'إعادة تعيين كلمة المرور – ReBreak', title: 'إعادة تعيين كلمة المرور', body: 'أدخل هذا الرمز في التطبيق لتعيين كلمة مرور جديدة:', helpText: 'إذا لم تطلب إعادة التعيين، تجاهل هذه الرسالة — لن تتغير كلمة المرور.', privacyLabel: 'الخصوصية', }, }, magiclink: { de: { senderName: 'ReBreak Login', subject: 'Dein Login-Code – ReBreak', title: 'Dein Login-Code', body: 'Gib diesen Code in der App ein, um dich anzumelden:', helpText: 'Falls du keinen Login angefordert hast, kannst du diese E-Mail ignorieren.', privacyLabel: 'Datenschutz', }, en: { senderName: 'ReBreak Sign-In', subject: 'Your sign-in code – ReBreak', title: 'Your sign-in code', body: 'Enter this code in the app to sign in:', helpText: "If you didn't request a sign-in, you can ignore this email.", privacyLabel: 'Privacy', }, fr: { senderName: 'Connexion ReBreak', subject: 'Ton code de connexion – ReBreak', title: 'Ton code de connexion', body: "Saisis ce code dans l'application pour te connecter :", helpText: "Si tu n'as pas demandé à te connecter, ignore ce message.", privacyLabel: 'Confidentialité', }, ar: { senderName: 'تسجيل الدخول ReBreak', subject: 'رمز تسجيل الدخول – ReBreak', title: 'رمز تسجيل الدخول', body: 'أدخل هذا الرمز في التطبيق لتسجيل الدخول:', helpText: 'إذا لم تطلب تسجيل الدخول، يمكنك تجاهل هذه الرسالة.', privacyLabel: 'الخصوصية', }, }, invite: { de: { senderName: 'ReBreak Einladung', subject: 'Du wurdest eingeladen – ReBreak', title: 'Du wurdest zu ReBreak eingeladen', body: 'Verwende diesen Code in der App, um deinen Account zu aktivieren:', helpText: 'Falls du diese Einladung nicht erwartet hast, kannst du diese E-Mail ignorieren.', privacyLabel: 'Datenschutz', }, en: { senderName: 'ReBreak Invite', subject: "You've been invited – ReBreak", title: "You've been invited to ReBreak", body: 'Use this code in the app to activate your account:', helpText: "If you weren't expecting this invite, you can ignore this email.", privacyLabel: 'Privacy', }, fr: { senderName: 'Invitation ReBreak', subject: "Tu as été invité·e – ReBreak", title: 'Tu as été invité·e sur ReBreak', body: "Utilise ce code dans l'application pour activer ton compte :", helpText: "Si tu n'attendais pas cette invitation, tu peux ignorer ce message.", privacyLabel: 'Confidentialité', }, ar: { senderName: 'دعوة ReBreak', subject: 'تمت دعوتك – ReBreak', title: 'تمت دعوتك إلى ReBreak', body: 'استخدم هذا الرمز في التطبيق لتفعيل حسابك:', helpText: 'إذا لم تكن تتوقع هذه الدعوة، يمكنك تجاهل هذه الرسالة.', privacyLabel: 'الخصوصية', }, }, email_change: { de: { senderName: 'ReBreak E-Mail-Änderung', subject: 'E-Mail-Adresse ändern – ReBreak', title: 'E-Mail-Adresse ändern', body: 'Gib diesen Code in der App ein, um die Änderung deiner E-Mail-Adresse zu bestätigen:', helpText: 'Falls du diese Änderung nicht angefordert hast, kannst du diese E-Mail ignorieren — deine alte E-Mail-Adresse bleibt erhalten.', privacyLabel: 'Datenschutz', }, en: { senderName: 'ReBreak Email Change', subject: 'Change your email – ReBreak', title: 'Change your email address', body: 'Enter this code in the app to confirm your new email address:', helpText: "If you didn't request this change, you can ignore this email — your current address stays the same.", privacyLabel: 'Privacy', }, fr: { senderName: "Changement d'e-mail ReBreak", subject: "Modifier ton e-mail – ReBreak", title: 'Modifier ton adresse e-mail', body: "Saisis ce code dans l'application pour confirmer la modification de ton adresse e-mail :", helpText: "Si tu n'as pas demandé ce changement, ignore ce message — ton adresse actuelle reste inchangée.", privacyLabel: 'Confidentialité', }, ar: { senderName: 'تغيير البريد ReBreak', subject: 'تغيير عنوان البريد – ReBreak', title: 'تغيير عنوان البريد الإلكتروني', body: 'أدخل هذا الرمز في التطبيق لتأكيد تغيير عنوان بريدك الإلكتروني:', helpText: 'إذا لم تطلب هذا التغيير، يمكنك تجاهل هذه الرسالة — سيبقى بريدك الحالي دون تغيير.', privacyLabel: 'الخصوصية', }, }, }; const ICON_URL = 'https://api.staging.rebreak.org/email-assets/icon.png'; const MARKETING_URL = 'https://rebreak.org'; const PRIVACY_URL = 'https://rebreak.org/datenschutz'; const FONT_FAMILY = "'Nunito','Nunito Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif"; function htmlEscape(s: string): string { return s .replace(/&/g, '&') .replace(//g, '>'); } export interface RenderedEmail { subject: string; senderName: string; html: string; } export function renderEmail( action: EmailActionType, locale: Locale, token: string, ): RenderedEmail { const t = TEXTS[action][locale]; const isRtl = locale === 'ar'; const dir = isRtl ? 'rtl' : 'ltr'; const textAlign = isRtl ? 'right' : 'left'; const safeToken = htmlEscape(token); const html = ` ReBreak
ReBreak
ReBreak
 

${t.title}

${t.body}

${safeToken}

${t.helpText}

rebreak.org  ·  ${t.privacyLabel}

© ReBreak

`; return { subject: t.subject, senderName: t.senderName, html }; }