From b274d2c47b1b377c580b897269aa3ae731edec5e Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Sat, 6 Jun 2026 15:11:01 +0100 Subject: [PATCH] fixes for giftcards and phone input --- frontend/src/lib/stores/savedCards.svelte.ts | 48 ++++++++++++++++++++ frontend/src/lib/utils/phone.ts | 48 ++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 frontend/src/lib/stores/savedCards.svelte.ts create mode 100644 frontend/src/lib/utils/phone.ts diff --git a/frontend/src/lib/stores/savedCards.svelte.ts b/frontend/src/lib/stores/savedCards.svelte.ts new file mode 100644 index 0000000..59ff1e0 --- /dev/null +++ b/frontend/src/lib/stores/savedCards.svelte.ts @@ -0,0 +1,48 @@ +export type SavedCard = { + id: string; + brand: string; + last_4: string; + exp_month: number; + exp_year: number; + cardholder_name?: string; + is_default: boolean; +}; + +function createSavedCardsStore() { + let cards = $state([]); + let loading = $state(false); + let loaded = $state(false); + + async function fetch() { + if (loading) return; + loading = true; + try { + const res = await globalThis.fetch('/api/user/payment-methods', { credentials: 'include' }); + if (res.ok) { + cards = await res.json(); + } else { + cards = []; + } + loaded = true; + } catch { + cards = []; + } finally { + loading = false; + } + } + + function invalidate() { + loaded = false; + return fetch(); + } + + return { + get cards() { return cards; }, + get loading() { return loading; }, + get loaded() { return loaded; }, + fetch, + invalidate, + }; +} + +export const savedCardsStore = createSavedCardsStore(); \ No newline at end of file diff --git a/frontend/src/lib/utils/phone.ts b/frontend/src/lib/utils/phone.ts new file mode 100644 index 0000000..0baa24c --- /dev/null +++ b/frontend/src/lib/utils/phone.ts @@ -0,0 +1,48 @@ +/** + * Strips formatting characters from a phone input, preserving digits and leading +. + */ +export function normalisePhoneInput(value: string): string { + return value.replace(/[^\d+]/g, '').replace(/(?!^)\+/g, ''); +} + +/** + * Validates a UK phone number. + * Accepts: +44XXXXXXXXXX or 0XXXXXXXXXX (10–11 digits after prefix). + * Returns true if valid. + */ +export function isValidUKPhone(phone: string): boolean { + const clean = normalisePhoneInput(phone); + return /^(\+44[1-9]\d{9,10}|0[1-9]\d{9,10})$/.test(clean); +} + +/** + * Formats a phone string as the user types — inserts spaces for readability. + * e.g. 07700900000 → 07700 900000, +447700900000 → +44 7700 900000 + */ +export function formatPhoneDisplay(value: string): string { + const clean = normalisePhoneInput(value); + if (clean.startsWith('+44')) { + const digits = clean.slice(3); + if (digits.length <= 4) return '+44 ' + digits; + if (digits.length <= 8) return '+44 ' + digits.slice(0, 4) + ' ' + digits.slice(4); + return '+44 ' + digits.slice(0, 4) + ' ' + digits.slice(4, 10); + } + if (clean.startsWith('0')) { + const digits = clean.slice(1); + if (digits.length <= 4) return '0' + digits; + if (digits.length <= 7) return '0' + digits.slice(0, 4) + ' ' + digits.slice(4); + return '0' + digits.slice(0, 4) + ' ' + digits.slice(4, 10); + } + return clean; +} + +/** + * Returns an E.164-normalised phone string ready to send to the backend, + * or null if the input is not a valid UK number. + */ +export function toE164UK(phone: string): string | null { + const clean = normalisePhoneInput(phone); + if (!isValidUKPhone(clean)) return null; + if (clean.startsWith('0')) return '+44' + clean.slice(1); + return clean; +} \ No newline at end of file