Fix TypeScript errors for Docker build
- Fix optional chaining for booking properties - Fix useMutation isLoading to isPending - Fix email parameter types - Fix expiredDetails array typing
This commit is contained in:
@@ -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()
|
||||
);
|
||||
|
||||
|
@@ -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 (
|
||||
<div className="min-h-screen bg-gradient-to-br from-pink-50 to-purple-50 py-8 px-4">
|
||||
@@ -430,22 +437,22 @@ export default function BookingStatusPage({ token }: BookingStatusPageProps) {
|
||||
<h2 className={`text-xl font-bold ${statusInfo.textColor} mb-2`}>
|
||||
Status: {statusInfo.label}
|
||||
</h2>
|
||||
{booking.status === "pending" && (
|
||||
{booking?.status === "pending" && (
|
||||
<p className={statusInfo.textColor}>
|
||||
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.
|
||||
</p>
|
||||
)}
|
||||
{booking.status === "confirmed" && (
|
||||
{booking?.status === "confirmed" && (
|
||||
<p className={statusInfo.textColor}>
|
||||
Dein Termin wurde bestätigt! Wir freuen uns auf dich. Du hast eine Bestätigungs-E-Mail mit Kalendereintrag erhalten.
|
||||
</p>
|
||||
)}
|
||||
{booking.status === "cancelled" && (
|
||||
{booking?.status === "cancelled" && (
|
||||
<p className={statusInfo.textColor}>
|
||||
Dieser Termin wurde storniert. Du kannst jederzeit einen neuen Termin buchen.
|
||||
</p>
|
||||
)}
|
||||
{booking.status === "completed" && (
|
||||
{booking?.status === "completed" && (
|
||||
<p className={statusInfo.textColor}>
|
||||
Dieser Termin wurde erfolgreich abgeschlossen. Vielen Dank für deinen Besuch!
|
||||
</p>
|
||||
@@ -465,27 +472,27 @@ export default function BookingStatusPage({ token }: BookingStatusPageProps) {
|
||||
<div className="space-y-3">
|
||||
<div className="flex justify-between py-2 border-b border-gray-100">
|
||||
<span className="text-gray-600">Datum:</span>
|
||||
<span className="font-medium text-gray-900">{booking.formattedDate}</span>
|
||||
<span className="font-medium text-gray-900">{booking?.formattedDate}</span>
|
||||
</div>
|
||||
<div className="flex justify-between py-2 border-b border-gray-100">
|
||||
<span className="text-gray-600">Uhrzeit:</span>
|
||||
<span className="font-medium text-gray-900">{booking.appointmentTime} Uhr</span>
|
||||
<span className="font-medium text-gray-900">{booking?.appointmentTime} Uhr</span>
|
||||
</div>
|
||||
<div className="flex justify-between py-2 border-b border-gray-100">
|
||||
<span className="text-gray-600">Behandlung:</span>
|
||||
<span className="font-medium text-gray-900">{booking.treatmentName}</span>
|
||||
<span className="font-medium text-gray-900">{booking?.treatmentName}</span>
|
||||
</div>
|
||||
<div className="flex justify-between py-2 border-b border-gray-100">
|
||||
<span className="text-gray-600">Dauer:</span>
|
||||
<span className="font-medium text-gray-900">{booking.treatmentDuration} Minuten</span>
|
||||
<span className="font-medium text-gray-900">{booking?.treatmentDuration} Minuten</span>
|
||||
</div>
|
||||
{booking.treatmentPrice > 0 && (
|
||||
{booking?.treatmentPrice && booking.treatmentPrice > 0 && (
|
||||
<div className="flex justify-between py-2 border-b border-gray-100">
|
||||
<span className="text-gray-600">Preis:</span>
|
||||
<span className="font-medium text-gray-900">{booking.treatmentPrice.toFixed(2)} €</span>
|
||||
</div>
|
||||
)}
|
||||
{booking.hoursUntilAppointment > 0 && booking.status !== "cancelled" && booking.status !== "completed" && (
|
||||
{booking?.hoursUntilAppointment && booking.hoursUntilAppointment > 0 && booking.status !== "cancelled" && booking.status !== "completed" && (
|
||||
<div className="flex justify-between py-2">
|
||||
<span className="text-gray-600">Verbleibende Zeit:</span>
|
||||
<span className="font-medium text-pink-600">
|
||||
@@ -507,18 +514,18 @@ export default function BookingStatusPage({ token }: BookingStatusPageProps) {
|
||||
<div className="space-y-3">
|
||||
<div className="flex justify-between py-2 border-b border-gray-100">
|
||||
<span className="text-gray-600">Name:</span>
|
||||
<span className="font-medium text-gray-900">{booking.customerName}</span>
|
||||
<span className="font-medium text-gray-900">{booking?.customerName}</span>
|
||||
</div>
|
||||
<div className="flex justify-between py-2 border-b border-gray-100">
|
||||
<span className="text-gray-600">E-Mail:</span>
|
||||
<span className="font-medium text-gray-900">{booking.customerEmail || '—'}</span>
|
||||
<span className="font-medium text-gray-900">{booking?.customerEmail || '—'}</span>
|
||||
</div>
|
||||
<div className="flex justify-between py-2">
|
||||
<span className="text-gray-600">Telefon:</span>
|
||||
<span className="font-medium text-gray-900">{booking.customerPhone || '—'}</span>
|
||||
<span className="font-medium text-gray-900">{booking?.customerPhone || '—'}</span>
|
||||
</div>
|
||||
</div>
|
||||
{booking.notes && (
|
||||
{booking?.notes && (
|
||||
<div className="mt-4 pt-4 border-t border-gray-200">
|
||||
<h3 className="text-sm font-semibold text-gray-700 mb-2">Notizen:</h3>
|
||||
<p className="text-gray-600 text-sm">{booking.notes}</p>
|
||||
@@ -527,7 +534,7 @@ export default function BookingStatusPage({ token }: BookingStatusPageProps) {
|
||||
</div>
|
||||
|
||||
{/* Cancellation Section */}
|
||||
{booking.canCancel && !cancellationResult?.success && (
|
||||
{booking?.canCancel && !cancellationResult?.success && (
|
||||
<div className="bg-white rounded-lg shadow-lg p-6 mb-6">
|
||||
<h2 className="text-lg font-semibold text-gray-900 mb-4 flex items-center">
|
||||
<svg className="w-5 h-5 mr-2 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
@@ -587,7 +594,7 @@ export default function BookingStatusPage({ token }: BookingStatusPageProps) {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!booking.canCancel && booking.status !== "cancelled" && booking.status !== "completed" && (
|
||||
{!booking?.canCancel && booking?.status !== "cancelled" && booking?.status !== "completed" && (
|
||||
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-6">
|
||||
<p className="text-yellow-800 text-sm">
|
||||
<strong>ℹ️ Stornierungsfrist abgelaufen:</strong> 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.
|
||||
|
@@ -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,
|
||||
|
@@ -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,
|
||||
|
Reference in New Issue
Block a user