Add e-mail based login
This commit is contained in:
@@ -1,22 +1,34 @@
|
||||
<script>
|
||||
<script lang="ts" context="module">
|
||||
export type FormConfig = {
|
||||
fields: FormField[],
|
||||
submit_label: string
|
||||
submit_red?: boolean,
|
||||
on_submit: (values: {[key: string]: string}) => Promise<SubmitResult>,
|
||||
}
|
||||
export type FormField = {
|
||||
type: string,
|
||||
name?: string,
|
||||
label?: string,
|
||||
default_value?: string,
|
||||
description?: string,
|
||||
separator?: boolean,
|
||||
radio_values?: string[], // Options to choose from when type is "radio"
|
||||
pattern?: string, // Used for pattern matching on input fields
|
||||
binding?: any
|
||||
}
|
||||
export type SubmitResult = {
|
||||
success: boolean,
|
||||
message?: string,
|
||||
messages?: string[],
|
||||
error_json?: GenericResponse,
|
||||
}
|
||||
</script>
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import Spinner from "./Spinner.svelte";
|
||||
import type { GenericResponse } from "../lib/PixeldrainAPI.mjs";
|
||||
|
||||
|
||||
export let config = {
|
||||
fields: [
|
||||
{
|
||||
name: "",
|
||||
label: "",
|
||||
type: "",
|
||||
default_value: "",
|
||||
binding: null,
|
||||
}
|
||||
],
|
||||
submit_label: "",
|
||||
submit_red: false,
|
||||
on_submit: async field_values => {},
|
||||
}
|
||||
export let config: FormConfig
|
||||
|
||||
onMount(() => {
|
||||
config.fields.forEach(field => {
|
||||
@@ -28,15 +40,9 @@ onMount(() => {
|
||||
|
||||
let loading = false
|
||||
let submitted = false
|
||||
let submit_result = {
|
||||
success: false,
|
||||
message: "",
|
||||
messages: null,
|
||||
}
|
||||
let submit_result: SubmitResult
|
||||
|
||||
let form_elem
|
||||
|
||||
let submit = async (event) => {
|
||||
const submit = async (event: SubmitEvent) => {
|
||||
loading = true
|
||||
event.preventDefault()
|
||||
|
||||
@@ -51,15 +57,13 @@ let submit = async (event) => {
|
||||
}
|
||||
} else if (field.type === "description") {
|
||||
field_values[field.name] = ""
|
||||
} else if (field.type === "captcha") {
|
||||
field_values[field.name] = form_elem.getElementsByClassName("g-recaptcha-response")[0].value
|
||||
} else {
|
||||
field_values[field.name] = field.binding.value
|
||||
}
|
||||
})
|
||||
|
||||
submit_result = await config.on_submit(field_values)
|
||||
if (submit_result.error_json) {
|
||||
if (submit_result && submit_result.error_json) {
|
||||
submit_result = handle_errors(submit_result.error_json)
|
||||
}
|
||||
submitted = true
|
||||
@@ -67,7 +71,8 @@ let submit = async (event) => {
|
||||
loading = false
|
||||
return false
|
||||
}
|
||||
let field_label = (field) => {
|
||||
|
||||
const field_label = (field: string) => {
|
||||
let label = ""
|
||||
config.fields.forEach(val => {
|
||||
if (val.name === field) {
|
||||
@@ -76,7 +81,8 @@ let field_label = (field) => {
|
||||
})
|
||||
return label
|
||||
}
|
||||
let handle_errors = (response) => {
|
||||
|
||||
const handle_errors = (response: GenericResponse) => {
|
||||
console.log(response)
|
||||
let result = {success: false, message: "", messages: null}
|
||||
|
||||
@@ -86,18 +92,18 @@ let handle_errors = (response) => {
|
||||
response.errors.forEach(err => {
|
||||
if (err.value === "string_out_of_range") {
|
||||
result.messages.push(
|
||||
`${field_label(err.extra.field)} is too long or too short.
|
||||
`${field_label(<string>err.extra.field)} is too long or too short.
|
||||
It should be between ${err.extra.min_len} and
|
||||
${err.extra.max_len} characters. Current length:
|
||||
${err.extra.len}`
|
||||
)
|
||||
} else if (err.value === "field_contains_illegal_character") {
|
||||
result.messages.push(
|
||||
`Character '${err.extra.char}' is not allowed in ${field_label(err.extra.field)}`
|
||||
`Character '${err.extra.char}' is not allowed in ${field_label(<string>err.extra.field)}`
|
||||
)
|
||||
} else if (err.value === "missing_field") {
|
||||
result.messages.push(
|
||||
`${field_label(err.extra.field)} is required`
|
||||
`${field_label(<string>err.extra.field)} is required`
|
||||
)
|
||||
} else {
|
||||
result.messages.push(err.message)
|
||||
@@ -111,8 +117,8 @@ let handle_errors = (response) => {
|
||||
}
|
||||
</script>
|
||||
|
||||
<form method="POST" on:submit={submit} bind:this={form_elem}>
|
||||
{#if submitted}
|
||||
<form method="POST" on:submit={submit}>
|
||||
{#if submitted && submit_result !== undefined}
|
||||
{#if submit_result.messages}
|
||||
<div id="submit_result" class:highlight_green={submit_result.success} class:highlight_red={!submit_result.success}>
|
||||
Something went wrong, please correct these errors before continuing:<br/>
|
||||
@@ -129,7 +135,6 @@ let handle_errors = (response) => {
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
|
||||
<div class="form">
|
||||
{#each config.fields as field}
|
||||
{#if field.type !== "description"}
|
||||
@@ -141,8 +146,10 @@ let handle_errors = (response) => {
|
||||
id="input_{field.name}"
|
||||
name="{field.name}"
|
||||
value="{field.default_value}"
|
||||
pattern={field.pattern}
|
||||
type="text"
|
||||
class="form_input"/>
|
||||
class="form_input"
|
||||
/>
|
||||
{:else if field.type === "text_area"}
|
||||
<textarea bind:this={field.binding}
|
||||
id="input_{field.name}"
|
||||
@@ -155,58 +162,79 @@ let handle_errors = (response) => {
|
||||
id="input_{field.name}"
|
||||
name="{field.name}"
|
||||
value="{field.default_value}"
|
||||
pattern={field.pattern}
|
||||
type="number"
|
||||
class="form_input"/>
|
||||
class="form_input"
|
||||
/>
|
||||
{:else if field.type === "decimal"}
|
||||
<input bind:this={field.binding}
|
||||
id="input_{field.name}"
|
||||
name="{field.name}"
|
||||
value="{field.default_value}"
|
||||
pattern={field.pattern}
|
||||
type="number"
|
||||
step="0.1"
|
||||
class="form_input"/>
|
||||
class="form_input"
|
||||
/>
|
||||
{:else if field.type === "datetime-local"}
|
||||
<input bind:this={field.binding}
|
||||
id="input_{field.name}"
|
||||
name="{field.name}"
|
||||
value="{field.default_value}"
|
||||
pattern={field.pattern}
|
||||
type="datetime-local"
|
||||
class="form_input"/>
|
||||
class="form_input"
|
||||
/>
|
||||
{:else if field.type === "username"}
|
||||
<input bind:this={field.binding}
|
||||
id="input_{field.name}"
|
||||
name="{field.name}"
|
||||
value="{field.default_value}"
|
||||
pattern={field.pattern}
|
||||
type="text"
|
||||
autocomplete="username"
|
||||
class="form_input"/>
|
||||
class="form_input"
|
||||
/>
|
||||
{:else if field.type === "email"}
|
||||
<input bind:this={field.binding}
|
||||
id="input_{field.name}"
|
||||
name="{field.name}"
|
||||
value="{field.default_value}"
|
||||
pattern={field.pattern}
|
||||
type="email"
|
||||
autocomplete="email"
|
||||
class="form_input"/>
|
||||
class="form_input"
|
||||
/>
|
||||
{:else if field.type === "current_password"}
|
||||
<input bind:this={field.binding}
|
||||
id="input_{field.name}"
|
||||
name="{field.name}"
|
||||
value="{field.default_value}"
|
||||
pattern={field.pattern}
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
class="form_input"/>
|
||||
class="form_input"
|
||||
/>
|
||||
{:else if field.type === "new_password"}
|
||||
<input bind:this={field.binding}
|
||||
id="input_{field.name}"
|
||||
name="{field.name}"
|
||||
value="{field.default_value}"
|
||||
pattern={field.pattern}
|
||||
type="password"
|
||||
autocomplete="new-password"
|
||||
class="form_input"/>
|
||||
{:else if field.type === "captcha"}
|
||||
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
||||
<div class="g-recaptcha" data-theme="dark" data-sitekey="{field.captcha_site_key}"></div>
|
||||
class="form_input"
|
||||
/>
|
||||
{:else if field.type === "totp"}
|
||||
<input bind:this={field.binding}
|
||||
id="input_{field.name}"
|
||||
name="{field.name}"
|
||||
value="{field.default_value?field.default_value:""}"
|
||||
type="text"
|
||||
autocomplete="one-time-code"
|
||||
pattern={"[0-9]{6}"}
|
||||
class="form_input"
|
||||
/>
|
||||
{:else if field.type === "radio"}
|
||||
<div>
|
||||
{#each field.radio_values as val}
|
||||
|
||||
Reference in New Issue
Block a user