Build: Update server-dist artifacts for v0.1.4
This commit is contained in:
@@ -3,7 +3,7 @@ import { z } from "zod";
|
||||
import { randomUUID } from "crypto";
|
||||
import { createKV } from "../lib/create-kv.js";
|
||||
import { sendEmail, sendEmailWithAGBAndCalendar, sendEmailWithInspirationPhoto } from "../lib/email.js";
|
||||
import { renderBookingPendingHTML, renderBookingConfirmedHTML, renderBookingCancelledHTML, renderAdminBookingNotificationHTML, renderBookingRescheduleProposalHTML, renderAdminRescheduleAcceptedHTML, renderAdminRescheduleDeclinedHTML } from "../lib/email-templates.js";
|
||||
import { renderBookingPendingHTML, renderBookingConfirmedHTML, renderBookingCancelledHTML, renderAdminBookingNotificationHTML, renderBookingRescheduleProposalHTML, renderAdminRescheduleAcceptedHTML, renderAdminRescheduleDeclinedHTML, renderCustomerMessageHTML } from "../lib/email-templates.js";
|
||||
import { createORPCClient } from "@orpc/client";
|
||||
import { RPCLink } from "@orpc/client/fetch";
|
||||
import { checkBookingRateLimit } from "../lib/rate-limiter.js";
|
||||
@@ -745,4 +745,63 @@ export const router = {
|
||||
}
|
||||
};
|
||||
}),
|
||||
// Admin sendet Nachricht an Kunden
|
||||
sendCustomerMessage: os
|
||||
.input(z.object({
|
||||
sessionId: z.string(),
|
||||
bookingId: z.string(),
|
||||
message: z.string().min(1, "Nachricht darf nicht leer sein").max(5000, "Nachricht ist zu lang (max. 5000 Zeichen)"),
|
||||
}))
|
||||
.handler(async ({ input }) => {
|
||||
await assertOwner(input.sessionId);
|
||||
const booking = await kv.getItem(input.bookingId);
|
||||
if (!booking)
|
||||
throw new Error("Buchung nicht gefunden");
|
||||
// Check if booking has customer email
|
||||
if (!booking.customerEmail) {
|
||||
throw new Error("Diese Buchung hat keine E-Mail-Adresse. Bitte kontaktiere den Kunden telefonisch.");
|
||||
}
|
||||
// Check if booking is in the future
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
const bookingDate = booking.appointmentDate;
|
||||
if (bookingDate < today) {
|
||||
throw new Error("Nachrichten können nur für zukünftige Termine gesendet werden.");
|
||||
}
|
||||
// Get treatment name for context
|
||||
const treatment = await treatmentsKV.getItem(booking.treatmentId);
|
||||
const treatmentName = treatment?.name || "Behandlung";
|
||||
// Prepare email with Reply-To header
|
||||
const ownerName = process.env.OWNER_NAME || "Stargirlnails Kiel";
|
||||
const emailFrom = process.env.EMAIL_FROM || "Stargirlnails <no-reply@stargirlnails.de>";
|
||||
const replyToEmail = process.env.ADMIN_EMAIL;
|
||||
const formattedDate = formatDateGerman(bookingDate);
|
||||
const html = await renderCustomerMessageHTML({
|
||||
customerName: booking.customerName,
|
||||
message: input.message,
|
||||
appointmentDate: bookingDate,
|
||||
appointmentTime: booking.appointmentTime,
|
||||
treatmentName: treatmentName,
|
||||
});
|
||||
const textContent = `Hallo ${booking.customerName},\n\nZu deinem Termin:\nBehandlung: ${treatmentName}\nDatum: ${formattedDate}\nUhrzeit: ${booking.appointmentTime}\n\nNachricht von ${ownerName}:\n${input.message}\n\nBei Fragen oder Anliegen kannst du einfach auf diese E-Mail antworten – wir helfen dir gerne weiter!\n\nLiebe Grüße,\n${ownerName}`;
|
||||
// Send email with BCC to admin for monitoring
|
||||
// Note: Not using explicit 'from' or 'replyTo' to match behavior of other system emails
|
||||
console.log(`Sending customer message to ${booking.customerEmail} for booking ${input.bookingId}`);
|
||||
console.log(`Email config: from=${emailFrom}, replyTo=${replyToEmail}, bcc=${replyToEmail}`);
|
||||
const emailResult = await sendEmail({
|
||||
to: booking.customerEmail,
|
||||
subject: `Nachricht zu deinem Termin am ${formattedDate}`,
|
||||
text: textContent,
|
||||
html: html,
|
||||
bcc: replyToEmail ? [replyToEmail] : undefined,
|
||||
});
|
||||
if (!emailResult.success) {
|
||||
console.error(`Failed to send customer message to ${booking.customerEmail}`);
|
||||
throw new Error("E-Mail konnte nicht versendet werden. Bitte überprüfe die E-Mail-Konfiguration oder versuche es später erneut.");
|
||||
}
|
||||
console.log(`Successfully sent customer message to ${booking.customerEmail}`);
|
||||
return {
|
||||
success: true,
|
||||
message: `Nachricht wurde erfolgreich an ${booking.customerEmail} gesendet.`
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
@@ -7,6 +7,7 @@ import { router as cancellation } from "./cancellation.js";
|
||||
import { router as legal } from "./legal.js";
|
||||
import { router as gallery } from "./gallery.js";
|
||||
import { router as reviews } from "./reviews.js";
|
||||
import { router as social } from "./social.js";
|
||||
export const router = {
|
||||
demo,
|
||||
treatments,
|
||||
@@ -17,4 +18,5 @@ export const router = {
|
||||
legal,
|
||||
gallery,
|
||||
reviews,
|
||||
social,
|
||||
};
|
||||
|
10
server-dist/rpc/social.js
Normal file
10
server-dist/rpc/social.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { os } from "@orpc/server";
|
||||
const getSocialMedia = os.handler(async () => {
|
||||
return {
|
||||
tiktokProfile: process.env.TIKTOK_PROFILE,
|
||||
instagramProfile: process.env.INSTAGRAM_PROFILE,
|
||||
};
|
||||
});
|
||||
export const router = os.router({
|
||||
getSocialMedia,
|
||||
});
|
Reference in New Issue
Block a user