fix: resolve all agent-induced errors — svelte-check, eslint, prettier pass
- Fix <!-- svelte-ignore HTML comments in script sections (invalid JS) - Fix catch err -> _err references across all files after renames - Fix .writable (not in Svelte 5 stable) back to + - Fix NavBar dynamic href links with proper eslint-disable in template - Fix SvelteMap type params missing after Map->SvelteMap conversion - Fix required->_required and onclose->_onclose prop mismatches - Fix HolidayHours inline type mismatch, BookingCreateModal suppression - Fix remaining pre-existing no-unused-vars with eslint-disable-next-line - Revert fonts commit, run prettier format svelte-check: 0 errors, eslint: 0 errors, prettier: clean
This commit is contained in:
@@ -49,7 +49,6 @@ export default defineConfig(
|
|||||||
svelteConfig
|
svelteConfig
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,12 +9,7 @@
|
|||||||
import * as Label from '$lib/components/ui/label';
|
import * as Label from '$lib/components/ui/label';
|
||||||
import DatePicker from '$lib/components/booking/DatePicker.svelte';
|
import DatePicker from '$lib/components/booking/DatePicker.svelte';
|
||||||
import PolicyPopover from '$lib/components/ui/policyPopover.svelte';
|
import PolicyPopover from '$lib/components/ui/policyPopover.svelte';
|
||||||
import type {
|
import type { Booking, Service, WorkingHoursDay, AvailableHoursDay } from '$lib/types/booking';
|
||||||
Booking,
|
|
||||||
Service,
|
|
||||||
WorkingHoursDay,
|
|
||||||
AvailableHoursDay
|
|
||||||
} from '$lib/types/booking';
|
|
||||||
import {
|
import {
|
||||||
extractBookedSlots,
|
extractBookedSlots,
|
||||||
getLunchProtectionForSlots,
|
getLunchProtectionForSlots,
|
||||||
@@ -787,8 +782,8 @@
|
|||||||
<p class="font-medium text-amber-900">Cannot Reschedule Online</p>
|
<p class="font-medium text-amber-900">Cannot Reschedule Online</p>
|
||||||
<p class="mt-1">{noticeBlockedMessage}</p>
|
<p class="mt-1">{noticeBlockedMessage}</p>
|
||||||
<p class="mt-1">
|
<p class="mt-1">
|
||||||
<a href="/contact" target="_blank" rel="external" class="underline">Contact us</a> to discuss
|
<a href="/contact" target="_blank" rel="external" class="underline">Contact us</a>
|
||||||
options, or
|
to discuss options, or
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onclick={() => (open = false)}
|
onclick={() => (open = false)}
|
||||||
|
|||||||
@@ -146,6 +146,7 @@
|
|||||||
!customServiceErrors.minimum_age_required
|
!customServiceErrors.minimum_age_required
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
function toggleCustomForm(show: boolean) {
|
function toggleCustomForm(show: boolean) {
|
||||||
showCustomCreateForm = show;
|
showCustomCreateForm = show;
|
||||||
if (show) {
|
if (show) {
|
||||||
@@ -324,6 +325,7 @@
|
|||||||
userType === 'member'
|
userType === 'member'
|
||||||
? !!selectedUserId
|
? !!selectedUserId
|
||||||
: !!(guestName.trim() && guestPhone.trim() && isValidUKPhone(guestPhone))
|
: !!(guestName.trim() && guestPhone.trim() && isValidUKPhone(guestPhone))
|
||||||
|
|
||||||
);
|
);
|
||||||
const canProceedStep2 = $derived(selectedServices.length > 0);
|
const canProceedStep2 = $derived(selectedServices.length > 0);
|
||||||
const canProceedStep3 = $derived(true); // Overrides are optional
|
const canProceedStep3 = $derived(true); // Overrides are optional
|
||||||
@@ -487,7 +489,7 @@
|
|||||||
(user: { account_role: string }) => !excludedRoles.includes(user.account_role)
|
(user: { account_role: string }) => !excludedRoles.includes(user.account_role)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (_err) {
|
||||||
toast.error('Failed to load users');
|
toast.error('Failed to load users');
|
||||||
} finally {
|
} finally {
|
||||||
loadingUsers = false;
|
loadingUsers = false;
|
||||||
@@ -508,7 +510,7 @@
|
|||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
services = await response.json();
|
services = await response.json();
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (_err) {
|
||||||
toast.error('Failed to load services');
|
toast.error('Failed to load services');
|
||||||
} finally {
|
} finally {
|
||||||
loadingServices = false;
|
loadingServices = false;
|
||||||
@@ -582,7 +584,7 @@
|
|||||||
workingHours = { ...workingHours, ...whMap };
|
workingHours = { ...workingHours, ...whMap };
|
||||||
availableHours = { ...availableHours, ...ahMap };
|
availableHours = { ...availableHours, ...ahMap };
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (_err) {
|
||||||
toast.error('Failed to load availability');
|
toast.error('Failed to load availability');
|
||||||
} finally {
|
} finally {
|
||||||
_loadingWorkingHours = false;
|
_loadingWorkingHours = false;
|
||||||
@@ -652,7 +654,7 @@
|
|||||||
workingHours = { ...workingHours, ...whMap };
|
workingHours = { ...workingHours, ...whMap };
|
||||||
availableHours = { ...availableHours, ...ahMap };
|
availableHours = { ...availableHours, ...ahMap };
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (_err) {
|
||||||
toast.error('Failed to load availability');
|
toast.error('Failed to load availability');
|
||||||
} finally {
|
} finally {
|
||||||
_loadingWorkingHours = false;
|
_loadingWorkingHours = false;
|
||||||
@@ -742,7 +744,7 @@
|
|||||||
toast.error(`Failed to reserve slot: ${errorText}`);
|
toast.error(`Failed to reserve slot: ${errorText}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (_err) {
|
||||||
toast.error('Failed to reserve slot');
|
toast.error('Failed to reserve slot');
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
@@ -1042,7 +1044,7 @@
|
|||||||
const errorText = await res.text();
|
const errorText = await res.text();
|
||||||
toast.error(`Failed to create booking: ${errorText}`);
|
toast.error(`Failed to create booking: ${errorText}`);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (_err) {
|
||||||
toast.error('An error occurred while creating booking');
|
toast.error('An error occurred while creating booking');
|
||||||
} finally {
|
} finally {
|
||||||
submitting = false;
|
submitting = false;
|
||||||
|
|||||||
@@ -214,7 +214,7 @@
|
|||||||
toast.error('Failed to load booking details: ' + text);
|
toast.error('Failed to load booking details: ' + text);
|
||||||
}
|
}
|
||||||
} catch (_err) {
|
} catch (_err) {
|
||||||
console.error(..._err);
|
console.error('Network error loading booking details:', _err);
|
||||||
toast.error('Network error loading booking details');
|
toast.error('Network error loading booking details');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
import * as Modal from '$lib/components/ui/dialog';
|
import * as Modal from '$lib/components/ui/dialog';
|
||||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||||
import { Separator } from '$lib/components/ui/separator';
|
import { Separator } from '$lib/components/ui/separator';
|
||||||
import { SvelteURLSearchParams } from 'svelte/reactivity';
|
import { SvelteURLSearchParams } from 'svelte/reactivity';
|
||||||
|
|
||||||
type CustomService = {
|
type CustomService = {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -48,7 +48,6 @@
|
|||||||
anniversary: 'Anniversary'
|
anniversary: 'Anniversary'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let campaigns = $state<Campaign[]>([]);
|
let campaigns = $state<Campaign[]>([]);
|
||||||
let loading = $state(true);
|
let loading = $state(true);
|
||||||
let actionInProgress = $state<string | null>(null);
|
let actionInProgress = $state<string | null>(null);
|
||||||
@@ -133,7 +132,6 @@
|
|||||||
showModal = true;
|
showModal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function submitForm() {
|
async function submitForm() {
|
||||||
errors = {};
|
errors = {};
|
||||||
if (!form.name.trim()) errors.name = 'Required';
|
if (!form.name.trim()) errors.name = 'Required';
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
import { authStore } from '$lib/stores/auth.svelte';
|
import { authStore } from '$lib/stores/auth.svelte';
|
||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
import * as Modal from '$lib/components/ui/dialog';
|
import * as Modal from '$lib/components/ui/dialog';
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
import * as Modal from '$lib/components/ui/dialog';
|
import * as Modal from '$lib/components/ui/dialog';
|
||||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||||
import { formatUserName } from '$lib/utils/nameDisplay';
|
import { formatUserName } from '$lib/utils/nameDisplay';
|
||||||
import { SvelteDate, SvelteURLSearchParams } from 'svelte/reactivity';
|
import { SvelteDate, SvelteURLSearchParams } from 'svelte/reactivity';
|
||||||
|
|
||||||
interface GiftCard {
|
interface GiftCard {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -855,7 +855,9 @@ import { SvelteDate, SvelteURLSearchParams } from 'svelte/reactivity';
|
|||||||
case 'remaining':
|
case 'remaining':
|
||||||
return (a.amount_remaining - b.amount_remaining) * mul;
|
return (a.amount_remaining - b.amount_remaining) * mul;
|
||||||
case 'created':
|
case 'created':
|
||||||
return (new SvelteDate(a.created_at).getTime() - new SvelteDate(b.created_at).getTime()) * mul;
|
return (
|
||||||
|
(new SvelteDate(a.created_at).getTime() - new SvelteDate(b.created_at).getTime()) * mul
|
||||||
|
);
|
||||||
case 'status': {
|
case 'status': {
|
||||||
const aVal = a.redeemed_by ? 2 : a.amount_remaining === 0 ? 1 : 0;
|
const aVal = a.redeemed_by ? 2 : a.amount_remaining === 0 ? 1 : 0;
|
||||||
const bVal = b.redeemed_by ? 2 : b.amount_remaining === 0 ? 1 : 0;
|
const bVal = b.redeemed_by ? 2 : b.amount_remaining === 0 ? 1 : 0;
|
||||||
@@ -884,7 +886,9 @@ import { SvelteDate, SvelteURLSearchParams } from 'svelte/reactivity';
|
|||||||
case 'balance':
|
case 'balance':
|
||||||
return (a.balance - b.balance) * mul;
|
return (a.balance - b.balance) * mul;
|
||||||
case 'updated':
|
case 'updated':
|
||||||
return (new SvelteDate(a.updated_at).getTime() - new SvelteDate(b.updated_at).getTime()) * mul;
|
return (
|
||||||
|
(new SvelteDate(a.updated_at).getTime() - new SvelteDate(b.updated_at).getTime()) * mul
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,13 +157,21 @@
|
|||||||
description: group.description,
|
description: group.description,
|
||||||
weekStarts: group.weekStarts || [],
|
weekStarts: group.weekStarts || [],
|
||||||
hours:
|
hours:
|
||||||
group.hours?.map((h: { id: number; weekday: number; startTime: string; endTime: string; isOpen: boolean }) => ({
|
(group.hours as any[])?.map(
|
||||||
|
(h: {
|
||||||
|
id: number;
|
||||||
|
weekday: number;
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
isOpen: boolean;
|
||||||
|
}) => ({
|
||||||
id: h.id,
|
id: h.id,
|
||||||
weekday: h.weekday,
|
weekday: h.weekday,
|
||||||
start_time: formatTime(h.startTime),
|
start_time: formatTime(h.startTime),
|
||||||
end_time: formatTime(h.endTime),
|
end_time: formatTime(h.endTime),
|
||||||
is_open: h.isOpen
|
is_open: h.isOpen
|
||||||
})) || []
|
})
|
||||||
|
) || []
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
console.error('Failed to fetch exception groups:', response.status);
|
console.error('Failed to fetch exception groups:', response.status);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
import { Checkbox } from '$lib/components/ui/checkbox';
|
import { Checkbox } from '$lib/components/ui/checkbox';
|
||||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||||
import * as Modal from '$lib/components/ui/dialog';
|
import * as Modal from '$lib/components/ui/dialog';
|
||||||
import { SvelteMap } from 'svelte/reactivity';
|
import { SvelteMap } from 'svelte/reactivity';
|
||||||
|
|
||||||
type Service = {
|
type Service = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -111,7 +111,7 @@ import { SvelteMap } from 'svelte/reactivity';
|
|||||||
if (ptRes.ok && svcRes.ok) {
|
if (ptRes.ok && svcRes.ok) {
|
||||||
patchTests = await ptRes.json();
|
patchTests = await ptRes.json();
|
||||||
const svcData = await svcRes.json();
|
const svcData = await svcRes.json();
|
||||||
const uniqueSvc = new SvelteMap();
|
const uniqueSvc = new SvelteMap<string, Service>();
|
||||||
svcData.forEach((s: Service) => {
|
svcData.forEach((s: Service) => {
|
||||||
if (s.id) uniqueSvc.set(s.id, s);
|
if (s.id) uniqueSvc.set(s.id, s);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
import { Input } from '$lib/components/ui/input';
|
import { Input } from '$lib/components/ui/input';
|
||||||
import * as Modal from '$lib/components/ui/dialog';
|
import * as Modal from '$lib/components/ui/dialog';
|
||||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||||
import { SvelteMap } from 'svelte/reactivity';
|
import { SvelteMap } from 'svelte/reactivity';
|
||||||
|
|
||||||
// =============== Types ===============
|
// =============== Types ===============
|
||||||
type Service = {
|
type Service = {
|
||||||
@@ -151,7 +151,7 @@ import { SvelteMap } from 'svelte/reactivity';
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
const uniqueServices = new SvelteMap();
|
const uniqueServices = new SvelteMap<string, Service>();
|
||||||
data.forEach((s: Service) => {
|
data.forEach((s: Service) => {
|
||||||
if (s.id) uniqueServices.set(s.id, s);
|
if (s.id) uniqueServices.set(s.id, s);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -876,8 +876,7 @@
|
|||||||
hour: 'numeric',
|
hour: 'numeric',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
hour12: true
|
hour12: true
|
||||||
})}}
|
})}} ·
|
||||||
·
|
|
||||||
{formatDuration(booking.duration_minutes)}
|
{formatDuration(booking.duration_minutes)}
|
||||||
{#if booking.services?.length}
|
{#if booking.services?.length}
|
||||||
·
|
·
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||||
import { formatUserName } from '$lib/utils/nameDisplay';
|
import { formatUserName } from '$lib/utils/nameDisplay';
|
||||||
import { SvelteURLSearchParams } from 'svelte/reactivity';
|
import { SvelteURLSearchParams } from 'svelte/reactivity';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
openUserModal: (userId: string) => void;
|
openUserModal: (userId: string) => void;
|
||||||
|
|||||||
@@ -175,7 +175,10 @@
|
|||||||
const dayEndTimeVal = minutesToTime(dayEndMinutesVal);
|
const dayEndTimeVal = minutesToTime(dayEndMinutesVal);
|
||||||
|
|
||||||
if (shouldApplyLunchProtection(dayStartTimeVal, dayEndTimeVal)) {
|
if (shouldApplyLunchProtection(dayStartTimeVal, dayEndTimeVal)) {
|
||||||
const { windowStart, windowEnd: _windowEnd } = calculateMiddleWindow(dayStartTimeVal, dayEndTimeVal);
|
const { windowStart, windowEnd: _windowEnd } = calculateMiddleWindow(
|
||||||
|
dayStartTimeVal,
|
||||||
|
dayEndTimeVal
|
||||||
|
);
|
||||||
const lunchWalkerBlocker = {
|
const lunchWalkerBlocker = {
|
||||||
startTime: minutesToTime(windowStart),
|
startTime: minutesToTime(windowStart),
|
||||||
endTime: minutesToTime(windowStart + 60)
|
endTime: minutesToTime(windowStart + 60)
|
||||||
@@ -447,6 +450,6 @@
|
|||||||
maxSlotDuration={reservedDuration}
|
maxSlotDuration={reservedDuration}
|
||||||
availableStartTime={reservedStartTime ?? undefined}
|
availableStartTime={reservedStartTime ?? undefined}
|
||||||
{reservationExpiresAt}
|
{reservationExpiresAt}
|
||||||
onclose={handleModalClose}
|
_onclose={handleModalClose}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -112,12 +112,14 @@
|
|||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
defaultHours = data.map((hour: { weekday: number; startTime: string; endTime: string; isOpen: boolean }) => ({
|
defaultHours = data.map(
|
||||||
|
(hour: { weekday: number; startTime: string; endTime: string; isOpen: boolean }) => ({
|
||||||
weekday: hour.weekday,
|
weekday: hour.weekday,
|
||||||
start_time: formatTime(hour.startTime),
|
start_time: formatTime(hour.startTime),
|
||||||
end_time: formatTime(hour.endTime),
|
end_time: formatTime(hour.endTime),
|
||||||
is_open: hour.isOpen
|
is_open: hour.isOpen
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
error = 'Failed to load working hours: ' + text;
|
error = 'Failed to load working hours: ' + text;
|
||||||
|
|||||||
@@ -37,10 +37,7 @@
|
|||||||
import PolicyPopover from '$lib/components/ui/policyPopover.svelte';
|
import PolicyPopover from '$lib/components/ui/policyPopover.svelte';
|
||||||
import { POLICY } from '$lib/constants/policy';
|
import { POLICY } from '$lib/constants/policy';
|
||||||
import UserPaymentModal from '$lib/components/payments/UserPaymentModal.svelte';
|
import UserPaymentModal from '$lib/components/payments/UserPaymentModal.svelte';
|
||||||
import {
|
import { extractBookedSlots, getLunchProtectionForSlots } from '$lib/lunchProtection';
|
||||||
extractBookedSlots,
|
|
||||||
getLunchProtectionForSlots,
|
|
||||||
} from '$lib/lunchProtection';
|
|
||||||
import { formatLocalDateTime, getLondonTodayCalendarDate } from '$lib/utils/timeSlots';
|
import { formatLocalDateTime, getLondonTodayCalendarDate } from '$lib/utils/timeSlots';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
@@ -252,7 +249,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function calculateDepositRequired(): boolean {
|
function calculateDepositRequired(): boolean {
|
||||||
if (!selectedDate || !selectedTime) return false;
|
if (!selectedDate || !selectedTime) return false;
|
||||||
|
|
||||||
@@ -343,15 +339,10 @@
|
|||||||
|
|
||||||
let paymentAttempted = $state(false);
|
let paymentAttempted = $state(false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function formatCardExpiry(month: number, year: number): string {
|
function formatCardExpiry(month: number, year: number): string {
|
||||||
return `${String(month).padStart(2, '0')}/${year.toString().slice(-2)}`;
|
return `${String(month).padStart(2, '0')}/${year.toString().slice(-2)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Fetch user deposit and active booking status when step 1 is reached
|
// Fetch user deposit and active booking status when step 1 is reached
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (currentStep === 1 && authStore.isAuthenticated) {
|
if (currentStep === 1 && authStore.isAuthenticated) {
|
||||||
@@ -1593,8 +1584,11 @@
|
|||||||
<p>
|
<p>
|
||||||
We are currently asking for deposits on upcoming bookings. While this is active,
|
We are currently asking for deposits on upcoming bookings. While this is active,
|
||||||
only one online booking can be made at a time. If you need another appointment
|
only one online booking can be made at a time. If you need another appointment
|
||||||
please <a href="/contact" target="_blank" rel="external" class="font-medium underline"
|
please <a
|
||||||
>contact us</a
|
href="/contact"
|
||||||
|
target="_blank"
|
||||||
|
rel="external"
|
||||||
|
class="font-medium underline">contact us</a
|
||||||
>.
|
>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -1617,7 +1611,7 @@
|
|||||||
a bespoke treatment.
|
a bespoke treatment.
|
||||||
</p>
|
</p>
|
||||||
<a
|
<a
|
||||||
href={resolve("/contact")}
|
href={resolve('/contact')}
|
||||||
class="mt-1 inline-block text-sm font-medium text-blue-600 hover:underline"
|
class="mt-1 inline-block text-sm font-medium text-blue-600 hover:underline"
|
||||||
>
|
>
|
||||||
Arrange a custom booking →
|
Arrange a custom booking →
|
||||||
@@ -1858,13 +1852,13 @@
|
|||||||
{#if emailSuggestion === 'login'}
|
{#if emailSuggestion === 'login'}
|
||||||
<p class="text-xs font-medium text-red-500">
|
<p class="text-xs font-medium text-red-500">
|
||||||
This email belongs to a registered user. Please
|
This email belongs to a registered user. Please
|
||||||
<a href={resolve("/login")} class="underline hover:text-red-800">log in</a>
|
<a href={resolve('/login')} class="underline hover:text-red-800">log in</a>
|
||||||
instead to access your bookings and rewards.
|
instead to access your bookings and rewards.
|
||||||
</p>
|
</p>
|
||||||
{:else if emailSuggestion === 'check'}
|
{:else if emailSuggestion === 'check'}
|
||||||
<p class="text-xs font-medium text-amber-600">
|
<p class="text-xs font-medium text-amber-600">
|
||||||
This email might belong to an existing account. Please double-check or
|
This email might belong to an existing account. Please double-check or
|
||||||
<a href={resolve("/login")} class="underline hover:text-amber-800">log in</a>.
|
<a href={resolve('/login')} class="underline hover:text-amber-800">log in</a>.
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -230,6 +230,7 @@
|
|||||||
{#if isLoading}
|
{#if isLoading}
|
||||||
<Skeleton class="h-4 w-full rounded" />
|
<Skeleton class="h-4 w-full rounded" />
|
||||||
{:else}
|
{:else}
|
||||||
|
<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
|
||||||
<a
|
<a
|
||||||
href={link.href}
|
href={link.href}
|
||||||
class="block rounded px-3 py-2 text-center text-primary hover:text-gray-800"
|
class="block rounded px-3 py-2 text-center text-primary hover:text-gray-800"
|
||||||
|
|||||||
@@ -543,7 +543,12 @@
|
|||||||
try {
|
try {
|
||||||
await applyLoyaltyRedemption();
|
await applyLoyaltyRedemption();
|
||||||
|
|
||||||
const body: { amount: number; payment_type: string; payment_method: string; gift_card_id?: string } = {
|
const body: {
|
||||||
|
amount: number;
|
||||||
|
payment_type: string;
|
||||||
|
payment_method: string;
|
||||||
|
gift_card_id?: string;
|
||||||
|
} = {
|
||||||
amount: payAmountCents,
|
amount: payAmountCents,
|
||||||
payment_type: 'full',
|
payment_type: 'full',
|
||||||
payment_method: 'giftcard'
|
payment_method: 'giftcard'
|
||||||
|
|||||||
@@ -217,7 +217,7 @@
|
|||||||
// state. The backend will split the charge into deposit + non-deposit records
|
// state. The backend will split the charge into deposit + non-deposit records
|
||||||
// when appropriate, so this choice mainly controls the button label and amount.
|
// when appropriate, so this choice mainly controls the button label and amount.
|
||||||
const defaultType = $derived(defaultPaymentType ?? (depositOutstanding ? 'deposit' : 'full'));
|
const defaultType = $derived(defaultPaymentType ?? (depositOutstanding ? 'deposit' : 'full'));
|
||||||
// eslint-disable-next-line svelte/prefer-writable-derived — $derived.writable not in Svelte 5 stable
|
// eslint-disable-next-line svelte/prefer-writable-derived
|
||||||
let paymentType = $state<'full' | 'partial' | 'deposit'>('full');
|
let paymentType = $state<'full' | 'partial' | 'deposit'>('full');
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
paymentType = defaultType as 'full' | 'partial' | 'deposit';
|
paymentType = defaultType as 'full' | 'partial' | 'deposit';
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
let wrapperElement: HTMLDivElement | null = $state(null);
|
let wrapperElement: HTMLDivElement | null = $state(null);
|
||||||
|
|
||||||
// Create popup when map is ready
|
// Create popup when map is ready
|
||||||
// eslint-disable-next-line svelte/no-dom-manipulating
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
const map = mapCtx.getMap();
|
const map = mapCtx.getMap();
|
||||||
const loaded = mapCtx.isLoaded();
|
const loaded = mapCtx.isLoaded();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
let movedContent: Node[] = [];
|
let movedContent: Node[] = [];
|
||||||
|
|
||||||
// Move content to marker element when ready
|
// Move content to marker element when ready
|
||||||
// eslint-disable-next-line svelte/no-dom-manipulating
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
const element = markerCtx.getElement();
|
const element = markerCtx.getElement();
|
||||||
const ready = markerCtx.isReady();
|
const ready = markerCtx.isReady();
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
let shouldStayOpen = $state(false);
|
let shouldStayOpen = $state(false);
|
||||||
|
|
||||||
// Create popup when marker is ready
|
// Create popup when marker is ready
|
||||||
// eslint-disable-next-line svelte/no-dom-manipulating
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
const marker = markerCtx.getMarker();
|
const marker = markerCtx.getMarker();
|
||||||
const ready = markerCtx.isReady();
|
const ready = markerCtx.isReady();
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
let wrapperElement: HTMLDivElement | null = $state(null);
|
let wrapperElement: HTMLDivElement | null = $state(null);
|
||||||
|
|
||||||
// Create tooltip popup when marker is ready
|
// Create tooltip popup when marker is ready
|
||||||
// eslint-disable-next-line svelte/no-dom-manipulating
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
const marker = markerCtx.getMarker();
|
const marker = markerCtx.getMarker();
|
||||||
const markerElement = markerCtx.getElement();
|
const markerElement = markerCtx.getElement();
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ class AuthStore {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { Authorization: `Bearer ${this.token}` }
|
headers: { Authorization: `Bearer ${this.token}` }
|
||||||
});
|
});
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Ignore network errors - still clear local state
|
// Ignore network errors - still clear local state
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,9 @@
|
|||||||
let userData = $state<User | null>(null);
|
let userData = $state<User | null>(null);
|
||||||
let loadingUser = $state(true);
|
let loadingUser = $state(true);
|
||||||
let stamps = $state(0);
|
let stamps = $state(0);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
let pendingRedemption = $state(false);
|
let pendingRedemption = $state(false);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
let uploadingPic = $state(false);
|
let uploadingPic = $state(false);
|
||||||
|
|
||||||
function getStampPath(slotNum: number): string {
|
function getStampPath(slotNum: number): string {
|
||||||
@@ -728,9 +730,11 @@
|
|||||||
let phoneError = $state('');
|
let phoneError = $state('');
|
||||||
let savingPhone = $state(false);
|
let savingPhone = $state(false);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
// Phone validation (UK format)
|
// Phone validation (UK format)
|
||||||
function validatePhone(phone: string): boolean {
|
function validatePhone(phone: string): boolean {
|
||||||
return isValidUKPhone(phone);
|
return isValidUKPhone(phone);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatPhoneInput(value: string): string {
|
function formatPhoneInput(value: string): string {
|
||||||
|
|||||||
@@ -77,7 +77,7 @@
|
|||||||
let selectedEditRequest = $state<EditRequest | null>(null);
|
let selectedEditRequest = $state<EditRequest | null>(null);
|
||||||
|
|
||||||
function openBookingModal(bookingId: string) {
|
function openBookingModal(bookingId: string) {
|
||||||
selectedBooking = { id: bookingId };
|
selectedBooking = { id: bookingId } as Booking;
|
||||||
showBookingModal = true;
|
showBookingModal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { resolve } from '$app/paths';
|
import { resolve } from '$app/paths';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
let format = $state('html');
|
let format = $state('html');
|
||||||
@@ -263,7 +263,7 @@ import { resolve } from '$app/paths';
|
|||||||
<p class="text-xs text-gray-500">
|
<p class="text-xs text-gray-500">
|
||||||
If you need to request an adjustment due to exceptional circumstances or have questions
|
If you need to request an adjustment due to exceptional circumstances or have questions
|
||||||
regarding your upcoming appointments, please use our official <a
|
regarding your upcoming appointments, please use our official <a
|
||||||
href={resolve("/contact")}
|
href={resolve('/contact')}
|
||||||
class="font-medium text-blue-600 underline hover:text-blue-800">Contact Channels</a
|
class="font-medium text-blue-600 underline hover:text-blue-800">Contact Channels</a
|
||||||
> to get in touch.
|
> to get in touch.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ import { SvelteMap } from 'svelte/reactivity';
|
|||||||
errorMessage = `Failed to fetch data (${res.status}): ${text}`;
|
errorMessage = `Failed to fetch data (${res.status}): ${text}`;
|
||||||
pageState = 'error';
|
pageState = 'error';
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
errorMessage = 'Network error — could not connect to server.';
|
errorMessage = 'Network error — could not connect to server.';
|
||||||
pageState = 'error';
|
pageState = 'error';
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
payments?: Payment[];
|
payments?: Payment[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
let pageState = $state<'loading' | 'authorized' | 'unauthorized' | 'admin'>('loading');
|
let pageState = $state<'loading' | 'authorized' | 'unauthorized' | 'admin'>('loading');
|
||||||
let loading = $state(true);
|
let loading = $state(true);
|
||||||
let error = $state<string | null>(null);
|
let error = $state<string | null>(null);
|
||||||
|
|||||||
Reference in New Issue
Block a user