feat: Add AGB PDF attachment to booking confirmation emails

- Extend email system to support file attachments
- Add sendEmailWithAGB() function that automatically attaches AGB.pdf
- Implement AGB PDF caching for better performance
- Update booking confirmation email template with AGB notice
- Add visual highlight box in HTML email with AGB information
- Update email subject to indicate AGB attachment
- Include AGB reference in both HTML and text versions
- Ensure legal compliance by automatically sending terms with confirmations

Changes:
- email.ts: Add attachment support and AGB PDF integration
- email-templates.ts: Add AGB notice to confirmation emails
- bookings.ts: Use sendEmailWithAGB for confirmed bookings
- German localization for admin treatments component
This commit is contained in:
2025-09-30 11:18:23 +02:00
parent bb04e5a118
commit a1935aae02
4 changed files with 77 additions and 27 deletions

View File

@@ -6,11 +6,39 @@ type SendEmailParams = {
from?: string;
cc?: string | string[];
bcc?: string | string[];
attachments?: Array<{
filename: string;
content: string; // base64 encoded
type?: string;
}>;
};
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { dirname, resolve } from "node:path";
const RESEND_API_KEY = process.env.RESEND_API_KEY;
const DEFAULT_FROM = process.env.EMAIL_FROM || "Stargirlnails <no-reply@stargirlnails.de>";
// Cache for AGB PDF to avoid reading it multiple times
let cachedAGBPDF: string | null = null;
async function getAGBPDFBase64(): Promise<string | null> {
if (cachedAGBPDF) return cachedAGBPDF;
try {
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const agbPath = resolve(__dirname, "../../../AGB.pdf");
const buf = await readFile(agbPath);
cachedAGBPDF = buf.toString('base64');
return cachedAGBPDF;
} catch (error) {
console.warn("Could not read AGB.pdf:", error);
return null;
}
}
export async function sendEmail(params: SendEmailParams): Promise<{ success: boolean }> {
if (!RESEND_API_KEY) {
// In development or if not configured, skip sending but don't fail the flow
@@ -32,6 +60,7 @@ export async function sendEmail(params: SendEmailParams): Promise<{ success: boo
html: params.html,
cc: params.cc ? (Array.isArray(params.cc) ? params.cc : [params.cc]) : undefined,
bcc: params.bcc ? (Array.isArray(params.bcc) ? params.bcc : [params.bcc]) : undefined,
attachments: params.attachments,
}),
});
@@ -43,4 +72,21 @@ export async function sendEmail(params: SendEmailParams): Promise<{ success: boo
return { success: true };
}
export async function sendEmailWithAGB(params: SendEmailParams): Promise<{ success: boolean }> {
const agbBase64 = await getAGBPDFBase64();
if (agbBase64) {
params.attachments = [
...(params.attachments || []),
{
filename: "AGB_Stargirlnails_Kiel.pdf",
content: agbBase64,
type: "application/pdf"
}
];
}
return sendEmail(params);
}