Files
monacousa-portal/src/routes/(auth)/signup/+page.svelte
Matt e7338d1a70 Initial production deployment setup
- Production docker-compose with nginx support
- Nginx configuration for portal.monacousa.org
- Deployment script with backup/restore
- Gitea CI/CD workflow
- Fix CountryFlag reactivity for dropdown flags

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 02:19:49 +01:00

257 lines
6.7 KiB
Svelte

<script lang="ts">
import { enhance } from '$app/forms';
import { Button } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import { DatePicker, NationalitySelect } from '$lib/components/ui';
import { FormMessage, LoadingSpinner } from '$lib/components/auth';
import { CalendarDate, today, getLocalTimeZone } from '@internationalized/date';
let { form } = $props();
let loading = $state(false);
let selectedNationalities = $state<string[]>([]);
let dateOfBirth = $state<CalendarDate | undefined>(undefined);
// Calculate max date for 18+ years old
const todayDate = today(getLocalTimeZone());
const maxDateOfBirth = new CalendarDate(
todayDate.year - 18,
todayDate.month,
todayDate.day
);
// Parse form data on error to restore values
$effect(() => {
if (form?.nationality) {
selectedNationalities = form.nationality.split(',').filter(Boolean);
}
if (form?.date_of_birth) {
const [year, month, day] = form.date_of_birth.split('-').map(Number);
dateOfBirth = new CalendarDate(year, month, day);
}
});
</script>
<svelte:head>
<title>Sign Up | Monaco USA</title>
</svelte:head>
<div class="space-y-6">
<div class="text-center">
<h2 class="text-xl font-semibold text-slate-900">Create your account</h2>
<p class="mt-1 text-sm text-slate-500">Join the Monaco USA community</p>
</div>
{#if form?.error}
<FormMessage type="error" message={form.error} />
{/if}
{#if form?.success}
<FormMessage type="success" message={form.success} />
{:else}
<form
method="POST"
use:enhance={() => {
loading = true;
return async ({ update }) => {
loading = false;
await update();
};
}}
class="space-y-4"
>
<!-- Name Row -->
<div class="grid grid-cols-2 gap-4">
<div class="space-y-2">
<Label for="first_name" class="text-sm font-medium text-slate-700">
First name <span class="text-monaco-600">*</span>
</Label>
<Input
id="first_name"
name="first_name"
type="text"
placeholder="John"
required
disabled={loading}
value={form?.first_name || ''}
class="h-11"
autocomplete="given-name"
/>
</div>
<div class="space-y-2">
<Label for="last_name" class="text-sm font-medium text-slate-700">
Last name <span class="text-monaco-600">*</span>
</Label>
<Input
id="last_name"
name="last_name"
type="text"
placeholder="Doe"
required
disabled={loading}
value={form?.last_name || ''}
class="h-11"
autocomplete="family-name"
/>
</div>
</div>
<!-- Email -->
<div class="space-y-2">
<Label for="email" class="text-sm font-medium text-slate-700">
Email address <span class="text-monaco-600">*</span>
</Label>
<Input
id="email"
name="email"
type="email"
placeholder="you@example.com"
required
disabled={loading}
value={form?.email || ''}
class="h-11"
autocomplete="email"
/>
</div>
<!-- Phone -->
<div class="space-y-2">
<Label for="phone" class="text-sm font-medium text-slate-700">
Phone number <span class="text-monaco-600">*</span>
</Label>
<Input
id="phone"
name="phone"
type="tel"
placeholder="+33 6 12 34 56 78"
required
disabled={loading}
value={form?.phone || ''}
class="h-11"
autocomplete="tel"
/>
</div>
<!-- Date of Birth - New DatePicker -->
<div class="space-y-2">
<Label class="text-sm font-medium text-slate-700">
Date of birth <span class="text-monaco-600">*</span>
</Label>
<DatePicker
bind:value={dateOfBirth}
maxValue={maxDateOfBirth}
disabled={loading}
placeholder="Select your birth date"
name="date_of_birth"
/>
<p class="text-xs text-slate-500">You must be at least 18 years old to join.</p>
</div>
<!-- Address -->
<div class="space-y-2">
<Label for="address" class="text-sm font-medium text-slate-700">
Address <span class="text-monaco-600">*</span>
</Label>
<Input
id="address"
name="address"
type="text"
placeholder="123 Avenue Princesse Grace, Monaco"
required
disabled={loading}
value={form?.address || ''}
class="h-11"
autocomplete="street-address"
/>
</div>
<!-- Nationality - New Dropdown Select -->
<div class="space-y-2">
<Label class="text-sm font-medium text-slate-700">
Nationality <span class="text-monaco-600">*</span>
</Label>
<NationalitySelect
bind:value={selectedNationalities}
disabled={loading}
placeholder="Search and select nationalities..."
name="nationality"
/>
{#if selectedNationalities.length === 0}
<p class="text-xs text-slate-500">Select at least one nationality.</p>
{/if}
</div>
<!-- Password -->
<div class="space-y-2">
<Label for="password" class="text-sm font-medium text-slate-700">
Password <span class="text-monaco-600">*</span>
</Label>
<Input
id="password"
name="password"
type="password"
placeholder="Create a strong password"
required
disabled={loading}
minlength={8}
class="h-11"
autocomplete="new-password"
/>
<p class="text-xs text-slate-500">At least 8 characters.</p>
</div>
<!-- Confirm Password -->
<div class="space-y-2">
<Label for="confirm_password" class="text-sm font-medium text-slate-700">
Confirm password <span class="text-monaco-600">*</span>
</Label>
<Input
id="confirm_password"
name="confirm_password"
type="password"
placeholder="Confirm your password"
required
disabled={loading}
minlength={8}
class="h-11"
autocomplete="new-password"
/>
</div>
<!-- Terms Agreement -->
<div class="flex items-start gap-2">
<input
type="checkbox"
id="terms"
name="terms"
required
class="mt-1 h-4 w-4 rounded border-slate-300 text-monaco-600 focus:ring-monaco-500"
/>
<label for="terms" class="text-sm text-slate-600">
I agree to the
<a href="/terms" class="text-monaco-600 hover:underline">Terms of Service</a>
and
<a href="/privacy" class="text-monaco-600 hover:underline">Privacy Policy</a>.
</label>
</div>
<Button type="submit" variant="monaco" size="lg" class="w-full" disabled={loading}>
{#if loading}
<LoadingSpinner size="sm" class="mr-2" />
Creating account...
{:else}
Create account
{/if}
</Button>
</form>
{/if}
<div class="text-center">
<p class="text-sm text-slate-600">
Already have an account?
<a href="/login" class="font-medium text-monaco-600 hover:text-monaco-700"> Sign in </a>
</p>
</div>
</div>