diff --git a/src/server/lib/email-templates.ts b/src/server/lib/email-templates.ts
index e3edfcb..966b45a 100644
--- a/src/server/lib/email-templates.ts
+++ b/src/server/lib/email-templates.ts
@@ -91,4 +91,36 @@ export async function renderBookingCancelledHTML(params: { name: string; date: s
return renderBrandedEmail("Termin abgesagt", inner);
}
+export async function renderAdminBookingNotificationHTML(params: {
+ name: string;
+ date: string;
+ time: string;
+ treatment: string;
+ phone: string;
+ notes?: string;
+ hasInspirationPhoto: boolean;
+}) {
+ const { name, date, time, treatment, phone, notes, hasInspirationPhoto } = params;
+ const formattedDate = formatDateGerman(date);
+ const inner = `
+
Hallo Admin,
+ eine neue Buchungsanfrage ist eingegangen:
+
+
📅 Buchungsdetails:
+
+ - Name: ${name}
+ - Telefon: ${phone}
+ - Behandlung: ${treatment}
+ - Datum: ${formattedDate}
+ - Uhrzeit: ${time}
+ ${notes ? `- Notizen: ${notes}
` : ''}
+ - Inspiration-Foto: ${hasInspirationPhoto ? '✅ Im Anhang verfügbar' : '❌ Kein Foto hochgeladen'}
+
+
+ Bitte logge dich in das Admin-Panel ein, um die Buchung zu bestätigen oder abzulehnen.
+ Liebe Grüße,
Stargirlnails System
+ `;
+ return renderBrandedEmail("Neue Buchungsanfrage - Admin-Benachrichtigung", inner);
+}
+
diff --git a/src/server/lib/email.ts b/src/server/lib/email.ts
index 14ba5d5..6ba3c5e 100644
--- a/src/server/lib/email.ts
+++ b/src/server/lib/email.ts
@@ -89,4 +89,35 @@ export async function sendEmailWithAGB(params: SendEmailParams): Promise<{ succe
return sendEmail(params);
}
+export async function sendEmailWithInspirationPhoto(
+ params: SendEmailParams,
+ photoData: string,
+ customerName: string
+): Promise<{ success: boolean }> {
+ if (!photoData) {
+ return sendEmail(params);
+ }
+
+ // Extract file extension from base64 data URL
+ const match = photoData.match(/data:image\/([^;]+);base64,(.+)/);
+ if (!match) {
+ console.warn("Invalid photo data format");
+ return sendEmail(params);
+ }
+
+ const [, extension, base64Content] = match;
+ const filename = `inspiration_${customerName.replace(/[^a-zA-Z0-9]/g, '_')}_${Date.now()}.${extension}`;
+
+ params.attachments = [
+ ...(params.attachments || []),
+ {
+ filename,
+ content: base64Content,
+ type: `image/${extension}`
+ }
+ ];
+
+ return sendEmail(params);
+}
+
diff --git a/src/server/rpc/bookings.ts b/src/server/rpc/bookings.ts
index 4a5e019..700795a 100644
--- a/src/server/rpc/bookings.ts
+++ b/src/server/rpc/bookings.ts
@@ -3,8 +3,8 @@ import { z } from "zod";
import { randomUUID } from "crypto";
import { createKV } from "@/server/lib/create-kv";
import { createKV as createAvailabilityKV } from "@/server/lib/create-kv";
-import { sendEmail, sendEmailWithAGB } from "@/server/lib/email";
-import { renderBookingPendingHTML, renderBookingConfirmedHTML, renderBookingCancelledHTML } from "@/server/lib/email-templates";
+import { sendEmail, sendEmailWithAGB, sendEmailWithInspirationPhoto } from "@/server/lib/email";
+import { renderBookingPendingHTML, renderBookingConfirmedHTML, renderBookingCancelledHTML, renderAdminBookingNotificationHTML } from "@/server/lib/email-templates";
// Helper function to convert date from yyyy-mm-dd to dd.mm.yyyy
function formatDateGerman(dateString: string): string {
@@ -41,6 +41,19 @@ type Availability = {
};
const availabilityKV = createAvailabilityKV("availability");
+// Import treatments KV for admin notifications
+import { createKV as createTreatmentsKV } from "@/server/lib/create-kv";
+type Treatment = {
+ id: string;
+ name: string;
+ description: string;
+ price: number;
+ duration: number;
+ category: string;
+ createdAt: string;
+};
+const treatmentsKV = createTreatmentsKV("treatments");
+
const create = os
.input(BookingSchema.omit({ id: true, createdAt: true, status: true }))
.handler(async ({ input }) => {
@@ -84,9 +97,54 @@ const create = os
subject: "Deine Terminanfrage ist eingegangen",
text: `Hallo ${input.customerName},\n\nwir haben deine Anfrage für ${formattedDate} um ${input.appointmentTime} erhalten. Wir bestätigen deinen Termin in Kürze.\n\nLiebe Grüße\nStargirlnails Kiel`,
html,
- cc: process.env.ADMIN_EMAIL ? [process.env.ADMIN_EMAIL] : undefined,
}).catch(() => {});
})();
+
+ // Notify admin: new booking request (with photo if available)
+ void (async () => {
+ if (!process.env.ADMIN_EMAIL) return;
+
+ // Get treatment name from KV
+ const allTreatments = await treatmentsKV.getAllItems();
+ const treatment = allTreatments.find(t => t.id === input.treatmentId);
+ const treatmentName = treatment?.name || "Unbekannte Behandlung";
+
+ const adminHtml = await renderAdminBookingNotificationHTML({
+ name: input.customerName,
+ date: input.appointmentDate,
+ time: input.appointmentTime,
+ treatment: treatmentName,
+ phone: input.customerPhone,
+ notes: input.notes,
+ hasInspirationPhoto: !!input.inspirationPhoto
+ });
+
+ const adminText = `Neue Buchungsanfrage eingegangen:\n\n` +
+ `Name: ${input.customerName}\n` +
+ `Telefon: ${input.customerPhone}\n` +
+ `Behandlung: ${treatmentName}\n` +
+ `Datum: ${formatDateGerman(input.appointmentDate)}\n` +
+ `Uhrzeit: ${input.appointmentTime}\n` +
+ `${input.notes ? `Notizen: ${input.notes}\n` : ''}` +
+ `Inspiration-Foto: ${input.inspirationPhoto ? 'Im Anhang verfügbar' : 'Kein Foto hochgeladen'}\n\n` +
+ `Bitte logge dich in das Admin-Panel ein, um die Buchung zu bearbeiten.`;
+
+ if (input.inspirationPhoto) {
+ await sendEmailWithInspirationPhoto({
+ to: process.env.ADMIN_EMAIL,
+ subject: `Neue Buchungsanfrage - ${input.customerName}`,
+ text: adminText,
+ html: adminHtml,
+ }, input.inspirationPhoto, input.customerName).catch(() => {});
+ } else {
+ await sendEmail({
+ to: process.env.ADMIN_EMAIL,
+ subject: `Neue Buchungsanfrage - ${input.customerName}`,
+ text: adminText,
+ html: adminHtml,
+ }).catch(() => {});
+ }
+ })();
return booking;
});