Initial
This commit is contained in:
commit
b43955e0d9
162 changed files with 15425 additions and 0 deletions
107
src/lib/features/auth/RegisterForm.svelte
Normal file
107
src/lib/features/auth/RegisterForm.svelte
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { authStore } from '$auth';
|
||||
import { t } from '$i18n';
|
||||
|
||||
let username = $state('');
|
||||
let email = $state('');
|
||||
let password = $state('');
|
||||
let passwordConfirm = $state('');
|
||||
let error = $state('');
|
||||
let isLoading = $state(false);
|
||||
|
||||
const emailOk = (v: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v);
|
||||
|
||||
function validate(): string {
|
||||
if (!username || !email || !password || !passwordConfirm) return $t('register.fieldsRequired');
|
||||
if (username.trim().length < 3) return $t('register.usernameShort');
|
||||
if (!emailOk(email)) return $t('register.emailInvalid');
|
||||
if (password.length < 8) return $t('register.passwordShort');
|
||||
if (password !== passwordConfirm) return $t('register.passwordMismatch');
|
||||
return '';
|
||||
}
|
||||
|
||||
async function handleSubmit(e: Event) {
|
||||
e.preventDefault();
|
||||
error = '';
|
||||
const msg = validate();
|
||||
if (msg) {
|
||||
error = msg;
|
||||
return;
|
||||
}
|
||||
isLoading = true;
|
||||
try {
|
||||
await authStore.register(username, email, password);
|
||||
goto('/app');
|
||||
} catch (err) {
|
||||
error = (err as Error).message || $t('register.failed');
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body p-4">
|
||||
<h5 class="card-title mb-4">{$t('register.heading')}</h5>
|
||||
|
||||
{#if error}
|
||||
<div class="alert alert-danger py-2" role="alert" data-testid="register-error">{error}</div>
|
||||
{/if}
|
||||
|
||||
<form onsubmit={handleSubmit} novalidate>
|
||||
<div class="form-floating mb-3">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="rg-username"
|
||||
placeholder={$t('register.username')}
|
||||
autocomplete="username"
|
||||
bind:value={username} />
|
||||
<label for="rg-username">{$t('register.username')}</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
id="rg-email"
|
||||
placeholder={$t('register.email')}
|
||||
autocomplete="email"
|
||||
bind:value={email} />
|
||||
<label for="rg-email">{$t('register.email')}</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="rg-password"
|
||||
placeholder={$t('register.password')}
|
||||
autocomplete="new-password"
|
||||
bind:value={password} />
|
||||
<label for="rg-password">{$t('register.password')}</label>
|
||||
</div>
|
||||
<div class="form-floating mb-3">
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="rg-password2"
|
||||
placeholder={$t('register.passwordConfirm')}
|
||||
autocomplete="new-password"
|
||||
bind:value={passwordConfirm} />
|
||||
<label for="rg-password2">{$t('register.passwordConfirm')}</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100" disabled={isLoading}>
|
||||
{#if isLoading}
|
||||
<span class="spinner-border spinner-border-sm me-2" role="status"></span>
|
||||
{$t('register.submitting')}
|
||||
{:else}
|
||||
{$t('register.submit')}
|
||||
{/if}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<p class="text-center text-muted small mt-4 mb-0">
|
||||
{$t('register.haveAccount')} <a href="/login">{$t('register.loginLink')}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue