diff --git a/src/client/components/admin-calendar.tsx b/src/client/components/admin-calendar.tsx index 4a88e5d..a5a85ab 100644 --- a/src/client/components/admin-calendar.tsx +++ b/src/client/components/admin-calendar.tsx @@ -73,7 +73,7 @@ export function AdminCalendar() { ); // Propose reschedule mutation - const { mutate: proposeReschedule, isLoading: isProposingReschedule } = useMutation( + const { mutate: proposeReschedule, isPending: isProposingReschedule } = useMutation( queryClient.bookings.proposeReschedule.mutationOptions() ); diff --git a/src/client/components/booking-status-page.tsx b/src/client/components/booking-status-page.tsx index b4ee7f7..d366c1b 100644 --- a/src/client/components/booking-status-page.tsx +++ b/src/client/components/booking-status-page.tsx @@ -71,13 +71,20 @@ export default function BookingStatusPage({ token }: BookingStatusPageProps) { ); // Try fetching reschedule proposal if booking not found or error - useQuery({ + const rescheduleQuery = useQuery({ ...queryClient.cancellation.getRescheduleProposal.queryOptions({ input: { token } }), enabled: !!token && (!!bookingError || !booking), - onSuccess: (data: any) => setRescheduleProposal(data), - onError: () => setRescheduleProposal(null), }); + // Handle reschedule proposal data + useEffect(() => { + if (rescheduleQuery.data) { + setRescheduleProposal(rescheduleQuery.data); + } else if (rescheduleQuery.error) { + setRescheduleProposal(null); + } + }, [rescheduleQuery.data, rescheduleQuery.error]); + // Cancellation mutation const cancelMutation = useMutation({ ...queryClient.cancellation.cancelByToken.mutationOptions(), @@ -387,7 +394,7 @@ export default function BookingStatusPage({ token }: BookingStatusPageProps) { ); } - const statusInfo = getStatusInfo(booking.status); + const statusInfo = getStatusInfo(booking?.status || "pending"); return (
Wir haben deine Terminanfrage erhalten und werden sie in Kürze prüfen. Du erhältst eine E-Mail, sobald dein Termin bestätigt wurde.
)} - {booking.status === "confirmed" && ( + {booking?.status === "confirmed" && (Dein Termin wurde bestätigt! Wir freuen uns auf dich. Du hast eine Bestätigungs-E-Mail mit Kalendereintrag erhalten.
)} - {booking.status === "cancelled" && ( + {booking?.status === "cancelled" && (Dieser Termin wurde storniert. Du kannst jederzeit einen neuen Termin buchen.
)} - {booking.status === "completed" && ( + {booking?.status === "completed" && (Dieser Termin wurde erfolgreich abgeschlossen. Vielen Dank für deinen Besuch!
@@ -465,27 +472,27 @@ export default function BookingStatusPage({ token }: BookingStatusPageProps) {{booking.notes}
@@ -527,7 +534,7 @@ export default function BookingStatusPage({ token }: BookingStatusPageProps) {ℹ️ Stornierungsfrist abgelaufen: Dieser Termin liegt weniger als {parseInt(process.env.MIN_STORNO_TIMESPAN || "24")} Stunden in der Zukunft und kann nicht mehr online storniert werden. Bitte kontaktiere uns direkt. diff --git a/src/server/rpc/bookings.ts b/src/server/rpc/bookings.ts index f3558c1..347b04d 100644 --- a/src/server/rpc/bookings.ts +++ b/src/server/rpc/bookings.ts @@ -612,13 +612,12 @@ const createManual = os cancellationUrl: bookingUrl }); - await sendEmailWithAGBAndCalendar({ - to: input.customerEmail, - subject: "Dein Termin wurde bestätigt - AGB im Anhang", - text: `Hallo ${input.customerName},\n\nwir haben deinen Termin am ${formattedDate} um ${input.appointmentTime} bestätigt.\n\nWichtiger Hinweis: Die Allgemeinen Geschäftsbedingungen (AGB) findest du im Anhang dieser E-Mail. Bitte lies sie vor deinem Termin durch.\n\nTermin-Status ansehen und verwalten: ${bookingUrl}\nFalls du den Termin stornieren möchtest, kannst du das über den obigen Link tun.\n\nRechtliche Informationen: ${generateUrl('/legal')}\nZur Website: ${homepageUrl}\n\nBis bald!\nStargirlnails Kiel`, - html, - bcc: process.env.ADMIN_EMAIL ? [process.env.ADMIN_EMAIL] : undefined, - }, { + await sendEmailWithAGBAndCalendar({ + to: input.customerEmail!, + subject: "Dein Termin wurde bestätigt - AGB im Anhang", + text: `Hallo ${input.customerName},\n\nwir haben deinen Termin am ${formattedDate} um ${input.appointmentTime} bestätigt.\n\nWichtiger Hinweis: Die Allgemeinen Geschäftsbedingungen (AGB) findest du im Anhang dieser E-Mail. Bitte lies sie vor deinem Termin durch.\n\nTermin-Status ansehen und verwalten: ${bookingUrl}\nFalls du den Termin stornieren möchtest, kannst du das über den obigen Link tun.\n\nRechtliche Informationen: ${generateUrl('/legal')}\nZur Website: ${homepageUrl}\n\nBis bald!\nStargirlnails Kiel`, + html, + }, { date: input.appointmentDate, time: input.appointmentTime, durationMinutes: treatment.duration, diff --git a/src/server/rpc/cancellation.ts b/src/server/rpc/cancellation.ts index e1c4f5f..44d2d4d 100644 --- a/src/server/rpc/cancellation.ts +++ b/src/server/rpc/cancellation.ts @@ -343,7 +343,17 @@ export const router = { } // Get booking details for each expired proposal - const expiredDetails = []; + const expiredDetails: Array<{ + customerName: string; + originalDate: string; + originalTime: string; + proposedDate: string; + proposedTime: string; + treatmentName: string; + customerEmail?: string; + customerPhone?: string; + expiredAt: string; + }> = []; for (const proposal of expiredProposals) { const booking = await bookingsKV.getItem(proposal.bookingId); if (booking) { @@ -353,8 +363,8 @@ export const router = { customerName: booking.customerName, originalDate: proposal.originalDate || booking.appointmentDate, originalTime: proposal.originalTime || booking.appointmentTime, - proposedDate: proposal.proposedDate, - proposedTime: proposal.proposedTime, + proposedDate: proposal.proposedDate!, + proposedTime: proposal.proposedTime!, treatmentName: treatment?.name || "Unbekannte Behandlung", customerEmail: booking.customerEmail, customerPhone: booking.customerPhone,