221 lines
6.6 KiB
Svelte
221 lines
6.6 KiB
Svelte
<script lang="ts">
|
|
import { clientFormatPhoneNumber } from '$lib/utils';
|
|
import type { PageProps } from './$types';
|
|
|
|
let { data, form }: PageProps = $props();
|
|
|
|
let initialPhone = $derived(clientFormatPhoneNumber(data.user.profile?.phoneNumber ?? ''));
|
|
let phoneNumber = $state('');
|
|
let phoneInitialized = $state(false);
|
|
|
|
$effect(() => {
|
|
if (!phoneInitialized) {
|
|
phoneNumber = initialPhone;
|
|
phoneInitialized = true;
|
|
}
|
|
});
|
|
|
|
let showAddressForm = $state(false);
|
|
|
|
function handlePhoneInput(event: Event) {
|
|
const input = event.target as HTMLInputElement;
|
|
phoneNumber = clientFormatPhoneNumber(input.value);
|
|
}
|
|
</script>
|
|
|
|
<div class="flex h-full min-h-0 flex-col gap-8 p-6">
|
|
<h1 class="text-2xl font-semibold text-gray-900">Account</h1>
|
|
|
|
<!-- Email (read-only) -->
|
|
<div>
|
|
<p class="text-sm font-medium text-gray-700">Email</p>
|
|
<p class="mt-1 text-gray-900">{data.user.email}</p>
|
|
</div>
|
|
|
|
<!-- Profile Form -->
|
|
<section>
|
|
<h2 class="mb-4 text-lg font-medium text-gray-900">Profile</h2>
|
|
|
|
{#if form?.action === 'updateProfile' && form?.success}
|
|
<div class="mb-4 rounded-lg border border-green-200 bg-green-50 p-3 text-green-700">
|
|
Profile updated successfully.
|
|
</div>
|
|
{/if}
|
|
{#if form?.action === 'updateProfile' && form?.error}
|
|
<div class="mb-4 rounded-lg border border-red-200 bg-red-50 p-3 text-red-700">
|
|
{form.error}
|
|
</div>
|
|
{/if}
|
|
|
|
<form method="POST" action="?/updateProfile" class="flex max-w-lg flex-col gap-4">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<label for="firstName" class="block text-sm font-medium text-gray-700">
|
|
First Name
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="firstName"
|
|
name="firstName"
|
|
value={data.user.profile?.firstName ?? ''}
|
|
required
|
|
class="mt-1 w-full rounded-lg border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label for="lastName" class="block text-sm font-medium text-gray-700">
|
|
Last Name
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="lastName"
|
|
name="lastName"
|
|
value={data.user.profile?.lastName ?? ''}
|
|
required
|
|
class="mt-1 w-full rounded-lg border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label for="phoneNumber" class="block text-sm font-medium text-gray-700">
|
|
Phone Number
|
|
</label>
|
|
<input
|
|
type="tel"
|
|
id="phoneNumber"
|
|
name="phoneNumber"
|
|
bind:value={phoneNumber}
|
|
oninput={handlePhoneInput}
|
|
required
|
|
class="mt-1 w-full max-w-xs rounded-lg border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<button
|
|
type="submit"
|
|
class="rounded-lg bg-blue-600 px-4 py-2 font-medium text-white transition-colors hover:bg-blue-700"
|
|
>
|
|
Save Profile
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</section>
|
|
|
|
<!-- Addresses -->
|
|
<section>
|
|
<div class="mb-4 flex items-center justify-between">
|
|
<h2 class="text-lg font-medium text-gray-900">Addresses</h2>
|
|
<button
|
|
type="button"
|
|
class="rounded-lg bg-green-600 px-3 py-1.5 text-sm font-medium text-white transition-colors hover:bg-green-700"
|
|
onclick={() => (showAddressForm = !showAddressForm)}
|
|
>
|
|
{showAddressForm ? 'Cancel' : 'Add Address'}
|
|
</button>
|
|
</div>
|
|
|
|
{#if form?.action === 'addAddress' && form?.success}
|
|
<div class="mb-4 rounded-lg border border-green-200 bg-green-50 p-3 text-green-700">
|
|
Address added successfully.
|
|
</div>
|
|
{/if}
|
|
{#if form?.action === 'addAddress' && form?.error}
|
|
<div class="mb-4 rounded-lg border border-red-200 bg-red-50 p-3 text-red-700">
|
|
{form.error}
|
|
</div>
|
|
{/if}
|
|
|
|
{#if showAddressForm}
|
|
<form
|
|
method="POST"
|
|
action="?/addAddress"
|
|
class="mb-6 max-w-lg rounded-lg border border-gray-200 bg-gray-50 p-4"
|
|
>
|
|
<div class="flex flex-col gap-3">
|
|
<div>
|
|
<label for="street" class="block text-sm font-medium text-gray-700">Street</label>
|
|
<input
|
|
type="text"
|
|
id="street"
|
|
name="street"
|
|
required
|
|
class="mt-1 w-full rounded-lg border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
<div class="grid grid-cols-2 gap-3">
|
|
<div>
|
|
<label for="city" class="block text-sm font-medium text-gray-700">City</label>
|
|
<input
|
|
type="text"
|
|
id="city"
|
|
name="city"
|
|
required
|
|
class="mt-1 w-full rounded-lg border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label for="state" class="block text-sm font-medium text-gray-700">State</label>
|
|
<input
|
|
type="text"
|
|
id="state"
|
|
name="state"
|
|
required
|
|
class="mt-1 w-full rounded-lg border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-2 gap-3">
|
|
<div>
|
|
<label for="postalCode" class="block text-sm font-medium text-gray-700">
|
|
Postal Code
|
|
</label>
|
|
<input
|
|
type="text"
|
|
id="postalCode"
|
|
name="postalCode"
|
|
required
|
|
class="mt-1 w-full rounded-lg border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label for="country" class="block text-sm font-medium text-gray-700">Country</label>
|
|
<input
|
|
type="text"
|
|
id="country"
|
|
name="country"
|
|
required
|
|
value="US"
|
|
class="mt-1 w-full rounded-lg border border-gray-300 px-3 py-2 shadow-sm focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<button
|
|
type="submit"
|
|
class="rounded-lg bg-blue-600 px-4 py-2 font-medium text-white transition-colors hover:bg-blue-700"
|
|
>
|
|
Save Address
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
{/if}
|
|
|
|
{#if data.user.profile?.addresses && data.user.profile.addresses.length > 0}
|
|
<div class="flex flex-col gap-3">
|
|
{#each data.user.profile.addresses as address}
|
|
<div class="rounded-lg border border-gray-200 bg-white p-4">
|
|
<p class="text-sm text-gray-900">{address.street}</p>
|
|
<p class="text-sm text-gray-600">
|
|
{address.city}, {address.state} {address.postalCode}
|
|
</p>
|
|
<p class="text-sm text-gray-600">{address.country}</p>
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
{:else if !showAddressForm}
|
|
<p class="text-sm text-gray-500">No addresses on file.</p>
|
|
{/if}
|
|
</section>
|
|
</div>
|