95 lines
2.2 KiB
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>
|