Refactor: Verbessere CalDAV und Bookings für Multi-Treatment-Support
- CalDAV SUMMARY zeigt jetzt alle Treatment-Namen als Liste statt Anzahl - Treatments-Array im Booking-Type optional für Rückwärtskompatibilität - Neue addMinutesToTime Helper-Funktion für saubere DTEND-Berechnung - getTreatmentNames filtert leere Namen und liefert sicheren Fallback
This commit is contained in:
@@ -5,7 +5,7 @@ import { assertOwner } from "../lib/auth.js";
|
||||
// Types für Buchungen (vereinfacht für CalDAV)
|
||||
type Booking = {
|
||||
id: string;
|
||||
treatmentId: string;
|
||||
treatments?: Array<{id: string, name: string, duration: number, price: number}>;
|
||||
customerName: string;
|
||||
customerEmail?: string;
|
||||
customerPhone?: string;
|
||||
@@ -13,6 +13,8 @@ type Booking = {
|
||||
appointmentTime: string; // HH:MM
|
||||
status: "pending" | "confirmed" | "cancelled" | "completed";
|
||||
notes?: string;
|
||||
// Deprecated fields for backward compatibility
|
||||
treatmentId?: string;
|
||||
bookedDurationMinutes?: number;
|
||||
createdAt: string;
|
||||
};
|
||||
@@ -44,6 +46,14 @@ function formatDateTime(dateStr: string, timeStr: string): string {
|
||||
return date.toISOString().replace(/[-:]/g, '').replace(/\.\d{3}/, '');
|
||||
}
|
||||
|
||||
function addMinutesToTime(timeStr: string, minutesToAdd: number): string {
|
||||
const [hours, minutes] = timeStr.split(':').map(Number);
|
||||
const totalMinutes = hours * 60 + minutes + minutesToAdd;
|
||||
const newHours = Math.floor(totalMinutes / 60);
|
||||
const newMinutes = totalMinutes % 60;
|
||||
return `${String(newHours).padStart(2, '0')}:${String(newMinutes).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
function generateICSContent(bookings: Booking[], treatments: Treatment[]): string {
|
||||
const now = new Date().toISOString().replace(/[-:]/g, '').replace(/\.\d{3}/, '');
|
||||
|
||||
@@ -63,14 +73,41 @@ X-WR-TIMEZONE:Europe/Berlin
|
||||
);
|
||||
|
||||
for (const booking of activeBookings) {
|
||||
const treatment = treatments.find(t => t.id === booking.treatmentId);
|
||||
const treatmentName = treatment?.name || 'Unbekannte Behandlung';
|
||||
const duration = booking.bookedDurationMinutes || treatment?.duration || 60;
|
||||
// Handle new treatments array structure
|
||||
let treatmentNames: string;
|
||||
let duration: number;
|
||||
let treatmentDetails: string;
|
||||
let totalPrice = 0;
|
||||
|
||||
if (booking.treatments && Array.isArray(booking.treatments) && booking.treatments.length > 0) {
|
||||
// Use new treatments array
|
||||
treatmentNames = booking.treatments.map(t => t.name).join(', ');
|
||||
|
||||
duration = booking.treatments.reduce((sum, t) => sum + (t.duration || 0), 0);
|
||||
totalPrice = booking.treatments.reduce((sum, t) => sum + (t.price || 0), 0);
|
||||
|
||||
// Build detailed treatment list for description
|
||||
treatmentDetails = booking.treatments
|
||||
.map(t => `- ${t.name} (${t.duration} Min., ${t.price}€)`)
|
||||
.join('\\n');
|
||||
|
||||
if (booking.treatments.length > 1) {
|
||||
treatmentDetails += `\\n\\nGesamt: ${duration} Min., ${totalPrice.toFixed(2)}€`;
|
||||
}
|
||||
} else {
|
||||
// Fallback to deprecated treatmentId for backward compatibility
|
||||
const treatment = booking.treatmentId ? treatments.find(t => t.id === booking.treatmentId) : null;
|
||||
treatmentNames = treatment?.name || 'Unbekannte Behandlung';
|
||||
duration = booking.bookedDurationMinutes || treatment?.duration || 60;
|
||||
treatmentDetails = `Behandlung: ${treatmentNames}`;
|
||||
if (treatment?.price) {
|
||||
treatmentDetails += ` (${duration} Min., ${treatment.price}€)`;
|
||||
}
|
||||
}
|
||||
|
||||
const startTime = formatDateTime(booking.appointmentDate, booking.appointmentTime);
|
||||
const endTime = formatDateTime(booking.appointmentDate,
|
||||
`${String(Math.floor((parseInt(booking.appointmentTime.split(':')[0]) * 60 + parseInt(booking.appointmentTime.split(':')[1]) + duration) / 60)).padStart(2, '0')}:${String((parseInt(booking.appointmentTime.split(':')[0]) * 60 + parseInt(booking.appointmentTime.split(':')[1]) + duration) % 60).padStart(2, '0')}`
|
||||
);
|
||||
const endTimeStr = addMinutesToTime(booking.appointmentTime, duration);
|
||||
const endTime = formatDateTime(booking.appointmentDate, endTimeStr);
|
||||
|
||||
// UID für jeden Termin (eindeutig)
|
||||
const uid = `booking-${booking.id}@stargirlnails.de`;
|
||||
@@ -83,8 +120,8 @@ UID:${uid}
|
||||
DTSTAMP:${now}
|
||||
DTSTART:${startTime}
|
||||
DTEND:${endTime}
|
||||
SUMMARY:${treatmentName} - ${booking.customerName}
|
||||
DESCRIPTION:Behandlung: ${treatmentName}\\nKunde: ${booking.customerName}${booking.customerPhone ? `\\nTelefon: ${booking.customerPhone}` : ''}${booking.notes ? `\\nNotizen: ${booking.notes}` : ''}
|
||||
SUMMARY:${treatmentNames} - ${booking.customerName}
|
||||
DESCRIPTION:${treatmentDetails}\\n\\nKunde: ${booking.customerName}${booking.customerPhone ? `\\nTelefon: ${booking.customerPhone}` : ''}${booking.notes ? `\\nNotizen: ${booking.notes}` : ''}
|
||||
STATUS:${status}
|
||||
TRANSP:OPAQUE
|
||||
END:VEVENT
|
||||
|
Reference in New Issue
Block a user