notatest/web/src/lib/components/AuthForm.svelte

95 lines
2.2 KiB
Svelte

<script lang="ts">
import { cError } from "$lib/client"
import { isPasswordValid } from "$lib/utils"
import { onMount } from "svelte"
export let formName: string
export let handler: (username: string, password: string) => Promise<void>
export let bottomText: string
export let bottomLink: string
let username = ""
let password = ""
let passwordError = ""
let isFormValid = false
// Clear any errors when swapping between login/signup views
onMount(() => cError.set(null))
const validatePassword = () => {
if (formName === "Login") {
// Skip if logging into existing account
passwordError = ""
isFormValid = true
return
}
;[isFormValid, passwordError] = isPasswordValid(password)
}
// Update validation on password change (reactive dependency)
$: {
password
validatePassword()
}
const handleSubmit = async () => {
cError.set(null)
if (formName === "Register" && !isFormValid) {
cError.set(passwordError)
return
}
try {
await handler(username, password)
} catch (err) {
cError.set(err instanceof Error ? err.message : "Authentication failed")
}
}
</script>
<div class="flex min-h-screen items-center justify-center px-4">
<div class="card rounded-4x1 grid w-auto max-w-md justify-items-center space-y-6">
{#if $cError}
<div class="error">
{$cError}
</div>
{/if}
<form class="space-y-5" on:submit|preventDefault={handleSubmit}>
<div class="form-group">
<label for="username" class="form-label"> Username </label>
<input
type="text"
id="username"
bind:value={username}
required
autocomplete="username"
class="w-auto self-center"
/>
</div>
<div class="form-group">
<label for="password" class="form-label"> Password </label>
<input
type="password"
id="password"
bind:value={password}
required
autocomplete={formName === "Login" ? "current-password" : "new-password"}
class="w-full"
/>
</div>
<button type="submit" class="btn-primary w-full rounded-full">
{formName}
</button>
</form>
<p class="text-center text-sm font-medium">
{bottomText}
<a href={bottomLink}> here </a>
</p>
</div>
</div>