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>
This commit is contained in:
256
src/routes/(auth)/signup/+page.svelte
Normal file
256
src/routes/(auth)/signup/+page.svelte
Normal file
@@ -0,0 +1,256 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user