diff --git a/frontend/src/lib/components/admin/BookingCreateModal.svelte b/frontend/src/lib/components/admin/BookingCreateModal.svelte index ec11f5a..0d87a92 100644 --- a/frontend/src/lib/components/admin/BookingCreateModal.svelte +++ b/frontend/src/lib/components/admin/BookingCreateModal.svelte @@ -146,6 +146,8 @@ !customServiceErrors.minimum_age_required ); + function toggleCustomForm(show: boolean) { + showCustomCreateForm = show; if (show) { newCustomService = { name: '', @@ -324,6 +326,7 @@ : !!(guestName.trim() && guestPhone.trim() && isValidUKPhone(guestPhone)) ); const canProceedStep2 = $derived(selectedServices.length > 0); + const canProceedStep3 = $derived(true); // Overrides are optional const canProceedStep4 = $derived(!!(selectedDate && selectedTime)); /** Whether the currently selected time slot is out-of-hours */ @@ -484,7 +487,7 @@ (user: { account_role: string }) => !excludedRoles.includes(user.account_role) ); } - } catch (_err) { + } catch (err) { toast.error('Failed to load users'); } finally { loadingUsers = false; @@ -505,7 +508,7 @@ if (response.ok) { services = await response.json(); } - } catch (_err) { + } catch (err) { toast.error('Failed to load services'); } finally { loadingServices = false; @@ -579,7 +582,7 @@ workingHours = { ...workingHours, ...whMap }; availableHours = { ...availableHours, ...ahMap }; } - } catch (_err) { + } catch (err) { toast.error('Failed to load availability'); } finally { _loadingWorkingHours = false; @@ -649,7 +652,7 @@ workingHours = { ...workingHours, ...whMap }; availableHours = { ...availableHours, ...ahMap }; } - } catch (_err) { + } catch (err) { toast.error('Failed to load availability'); } finally { _loadingWorkingHours = false; @@ -739,7 +742,7 @@ toast.error(`Failed to reserve slot: ${errorText}`); return false; } - } catch (_err) { + } catch (err) { toast.error('Failed to reserve slot'); return false; } finally { @@ -1039,7 +1042,7 @@ const errorText = await res.text(); toast.error(`Failed to create booking: ${errorText}`); } - } catch (_err) { + } catch (err) { toast.error('An error occurred while creating booking'); } finally { submitting = false; diff --git a/frontend/src/lib/components/admin/BookingModal.svelte b/frontend/src/lib/components/admin/BookingModal.svelte index f0b15a0..8e0ebfe 100644 --- a/frontend/src/lib/components/admin/BookingModal.svelte +++ b/frontend/src/lib/components/admin/BookingModal.svelte @@ -214,7 +214,7 @@ toast.error('Failed to load booking details: ' + text); } } catch (_err) { - console.error('Error fetching booking details:', err); + console.error(..._err); toast.error('Network error loading booking details'); } } diff --git a/frontend/src/lib/components/admin/WalkInBooking.svelte b/frontend/src/lib/components/admin/WalkInBooking.svelte index 2c7ede3..c178d95 100644 --- a/frontend/src/lib/components/admin/WalkInBooking.svelte +++ b/frontend/src/lib/components/admin/WalkInBooking.svelte @@ -221,7 +221,7 @@ noSlotsToday = true; } catch (_err) { - console.error('Failed to calculate slot availability', err); + console.error('Failed to calculate slot availability', _err); noSlotsToday = true; } finally { loading = false; @@ -279,7 +279,7 @@ return false; } } catch (_err) { - console.error('Reservation error:', err); + console.error('Reservation error:', _err); toast.error('Failed to reserve slot'); return false; } finally { diff --git a/frontend/src/lib/components/admin/WalkInCreateModal.svelte b/frontend/src/lib/components/admin/WalkInCreateModal.svelte index ff545c8..a13fe44 100644 --- a/frontend/src/lib/components/admin/WalkInCreateModal.svelte +++ b/frontend/src/lib/components/admin/WalkInCreateModal.svelte @@ -297,7 +297,7 @@ ); } } catch (_err) { - console.error('Failed to fetch users', err); + console.error('Failed to fetch users', _err); toast.error('Failed to load users'); } finally { loadingUsers = false; @@ -815,7 +815,7 @@ bind:value={guestPhone} bind:error={guestPhoneError} placeholder="07700 900000" - required={false} + _required={false} />

diff --git a/frontend/src/lib/components/booking/BookingFlow.svelte b/frontend/src/lib/components/booking/BookingFlow.svelte index a3701a8..314fd5e 100644 --- a/frontend/src/lib/components/booking/BookingFlow.svelte +++ b/frontend/src/lib/components/booking/BookingFlow.svelte @@ -280,7 +280,7 @@ } } } catch (_err) { - console.error('Failed to fetch discount preview:', err); + console.error('Failed to fetch discount preview:', _err); } } diff --git a/frontend/src/lib/components/layout/NavBar.svelte b/frontend/src/lib/components/layout/NavBar.svelte index 4641463..15f03dc 100644 --- a/frontend/src/lib/components/layout/NavBar.svelte +++ b/frontend/src/lib/components/layout/NavBar.svelte @@ -131,7 +131,8 @@ {#if isLoading} {:else} - + {link.label} {/if} @@ -230,7 +231,7 @@ {:else} {link.label} diff --git a/frontend/src/lib/components/payments/PaymentModal.svelte b/frontend/src/lib/components/payments/PaymentModal.svelte index 4ae051a..b701fea 100644 --- a/frontend/src/lib/components/payments/PaymentModal.svelte +++ b/frontend/src/lib/components/payments/PaymentModal.svelte @@ -299,7 +299,7 @@ startPolling(); } catch (_err) { status = 'error'; - error = err instanceof Error ? err.message : 'Failed to initiate payment'; + error = _err instanceof Error ? _err.message : 'Failed to initiate payment'; toast.error(error ?? 'Unknown error'); } } @@ -452,7 +452,7 @@ onComplete(paymentResult); } catch (_err) { status = 'error'; - error = err instanceof Error ? err.message : 'Failed to process payment'; + error = _err instanceof Error ? _err.message : 'Failed to process payment'; toast.error(error ?? 'Unknown error'); } } @@ -577,7 +577,7 @@ onComplete(paymentResult); } catch (_err) { status = 'error'; - error = err instanceof Error ? err.message : 'Failed to process gift card'; + error = _err instanceof Error ? _err.message : 'Failed to process gift card'; toast.error(error ?? 'Unknown error'); } } @@ -659,7 +659,7 @@ onComplete(paymentResult); } catch (_err) { status = 'error'; - error = err instanceof Error ? err.message : 'Failed to process saved card payment'; + error = _err instanceof Error ? _err.message : 'Failed to process saved card payment'; toast.error(error ?? 'Unknown error'); } } diff --git a/frontend/src/lib/components/payments/UserPaymentModal.svelte b/frontend/src/lib/components/payments/UserPaymentModal.svelte index 2fb8424..e1bad05 100644 --- a/frontend/src/lib/components/payments/UserPaymentModal.svelte +++ b/frontend/src/lib/components/payments/UserPaymentModal.svelte @@ -217,7 +217,11 @@ // state. The backend will split the charge into deposit + non-deposit records // when appropriate, so this choice mainly controls the button label and amount. const defaultType = $derived(defaultPaymentType ?? (depositOutstanding ? 'deposit' : 'full')); - let paymentType = $derived.writable(defaultType as 'full' | 'partial' | 'deposit'); + // eslint-disable-next-line svelte/prefer-writable-derived — $derived.writable not in Svelte 5 stable + let paymentType = $state<'full' | 'partial' | 'deposit'>('full'); + $effect(() => { + paymentType = defaultType as 'full' | 'partial' | 'deposit'; + }); let pollingInterval: ReturnType | null = null; @@ -358,7 +362,7 @@ lockTimer = 300; } } catch (_err) { - console.error('Failed to acquire payment lock:', err); + console.error('Failed to acquire payment lock:', _err); } } @@ -373,7 +377,7 @@ } }); } catch (_err) { - console.error('Failed to release payment lock:', err); + console.error('Failed to release payment lock:', _err); } } @@ -397,7 +401,7 @@ lockAcquired = true; } } catch (_err) { - console.error('Failed to renew payment lock:', err); + console.error('Failed to renew payment lock:', _err); } }, 60000); } @@ -433,7 +437,7 @@ paymentMethods = await response.json(); } } catch (_err) { - console.error('Failed to fetch payment methods:', err); + console.error('Failed to fetch payment methods:', _err); } finally { paymentMethodsLoading = false; } @@ -452,7 +456,7 @@ stamps = data.stamps ?? 0; } } catch (_err) { - console.error('Failed to fetch loyalty data:', err); + console.error('Failed to fetch loyalty data:', _err); } } @@ -507,7 +511,7 @@ } } catch (_err) { status = 'error'; - const msg = err instanceof Error ? err.message : 'Failed to apply loyalty discount'; + const msg = _err instanceof Error ? _err.message : 'Failed to apply loyalty discount'; error = msg; toast.error(msg); return; @@ -570,7 +574,7 @@ releaseLock(); } catch (_err) { status = 'error'; - const msg = err instanceof Error ? err.message : 'Payment declined'; + const msg = _err instanceof Error ? _err.message : 'Payment declined'; error = msg; toast.error(`${msg}. Please try again or use another card.`); releaseLock(); @@ -643,7 +647,7 @@ discountPreview = await resp.json(); } } catch (_err) { - console.error('Failed to fetch discount preview:', err); + console.error('Failed to fetch discount preview:', _err); } }); diff --git a/frontend/src/lib/components/ui/map/MapPopup.svelte b/frontend/src/lib/components/ui/map/MapPopup.svelte index b829614..aab38c0 100644 --- a/frontend/src/lib/components/ui/map/MapPopup.svelte +++ b/frontend/src/lib/components/ui/map/MapPopup.svelte @@ -48,7 +48,7 @@ let wrapperElement: HTMLDivElement | null = $state(null); // Create popup when map is ready - + // eslint-disable-next-line svelte/no-dom-manipulating $effect(() => { const map = mapCtx.getMap(); const loaded = mapCtx.isLoaded(); diff --git a/frontend/src/lib/components/ui/map/MarkerContent.svelte b/frontend/src/lib/components/ui/map/MarkerContent.svelte index 18bdb2c..cb402bf 100644 --- a/frontend/src/lib/components/ui/map/MarkerContent.svelte +++ b/frontend/src/lib/components/ui/map/MarkerContent.svelte @@ -21,7 +21,7 @@ let movedContent: Node[] = []; // Move content to marker element when ready - + // eslint-disable-next-line svelte/no-dom-manipulating $effect(() => { const element = markerCtx.getElement(); const ready = markerCtx.isReady(); diff --git a/frontend/src/lib/components/ui/map/MarkerPopup.svelte b/frontend/src/lib/components/ui/map/MarkerPopup.svelte index 855dc39..3491f36 100644 --- a/frontend/src/lib/components/ui/map/MarkerPopup.svelte +++ b/frontend/src/lib/components/ui/map/MarkerPopup.svelte @@ -42,7 +42,7 @@ let shouldStayOpen = $state(false); // Create popup when marker is ready - + // eslint-disable-next-line svelte/no-dom-manipulating $effect(() => { const marker = markerCtx.getMarker(); const ready = markerCtx.isReady(); diff --git a/frontend/src/lib/components/ui/map/MarkerTooltip.svelte b/frontend/src/lib/components/ui/map/MarkerTooltip.svelte index a841ee0..f64ac32 100644 --- a/frontend/src/lib/components/ui/map/MarkerTooltip.svelte +++ b/frontend/src/lib/components/ui/map/MarkerTooltip.svelte @@ -22,7 +22,7 @@ let wrapperElement: HTMLDivElement | null = $state(null); // Create tooltip popup when marker is ready - + // eslint-disable-next-line svelte/no-dom-manipulating $effect(() => { const marker = markerCtx.getMarker(); const markerElement = markerCtx.getElement(); diff --git a/frontend/src/lib/components/ui/phone-input/PhoneInput.svelte b/frontend/src/lib/components/ui/phone-input/PhoneInput.svelte index cc9ff3a..9dc148f 100644 --- a/frontend/src/lib/components/ui/phone-input/PhoneInput.svelte +++ b/frontend/src/lib/components/ui/phone-input/PhoneInput.svelte @@ -58,7 +58,7 @@ function handleInput(e: Event) { const _target = e.target as HTMLInputElement; - const formatted = formatPhoneDisplay(target.value); + const formatted = formatPhoneDisplay(_target.value); value = formatted; onvaluechange?.(formatted); // Only show live validation after the field has been blurred at least once diff --git a/frontend/src/lib/stores/auth.svelte.ts b/frontend/src/lib/stores/auth.svelte.ts index cc91fb6..066d669 100644 --- a/frontend/src/lib/stores/auth.svelte.ts +++ b/frontend/src/lib/stores/auth.svelte.ts @@ -166,7 +166,7 @@ class AuthStore { } } this.clearAuth(); - + // eslint-disable-next-line svelte/no-navigation-without-resolve goto('/', { invalidateAll: true }); }; diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 56bb060..837d0bc 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -9,7 +9,7 @@ // Redirect admins to /today (their homepage) $effect(() => { if (!authStore.isLoading && authStore.currentUser?.role === 'admin') { - + // eslint-disable-next-line svelte/no-navigation-without-resolve goto('/today', { replaceState: true }); } }); diff --git a/frontend/src/routes/account/+page.svelte b/frontend/src/routes/account/+page.svelte index 7208ca0..13f8e37 100644 --- a/frontend/src/routes/account/+page.svelte +++ b/frontend/src/routes/account/+page.svelte @@ -51,7 +51,7 @@ if (!authStore.isAuthenticated) { pageState = 'unauthorized'; - + // eslint-disable-next-line svelte/no-navigation-without-resolve goto('/login', { replaceState: true }); return; } @@ -801,7 +801,7 @@ let savingName = $state(false); // Name validation (unicode letters, spaces, hyphen, apostrophe, dot) - const nameRegex = /^[\p{L}\p{M}\s-'.]+$/u; + const nameRegex = /^[\p{L}\p{M}\s'.-]+$/u; function startEditFirstName() { firstNameInput = userData?.firstName || ''; @@ -1233,7 +1233,7 @@ if (response.ok) { toast.success('Account deleted successfully', { id: loadingToast }); - + // eslint-disable-next-line svelte/no-navigation-without-resolve authStore.logout(); goto('/'); } else { @@ -2595,7 +2595,7 @@

Data Privacy

- + View and export all personal data we hold about you

- +
@@ -516,7 +516,7 @@ import { SvelteMap } from 'svelte/reactivity';