Implement Registration Form validation

Signed-off-by: Sebastian Martinez <sebastinez@me.com>
This commit is contained in:
Sebastian Martinez
2021-08-23 09:25:53 -03:00
parent e39e425ec4
commit 2ceeb04ce6
2 changed files with 64 additions and 15 deletions
+57 -8
View File
@@ -3,11 +3,28 @@
name: string;
value: string | null;
label?: string;
validate?: string;
placeholder?: string;
description: string;
resolve?: boolean;
editable: boolean;
error?: string;
}
const validationTypes: { [index: string]: RegExp } = {
url: /^(https:\/\/|http:\/\/|ipfs:\/\/)\S+/,
// Github
// Username may only contain alphanumeric characters or hyphens.
// Username cannot have multiple consecutive hyphens.
// Username cannot begin or end with a hyphen.
// Maximum is 39 characters.
// Twitter
// Username may only contain alphanumeric characters or underscores.
// Maximum is 15 characters.
// For simplification of the regex pattern we use a combined version of both requirements.
handle: /^[a-zA-Z0-9-_]{1,39}$/,
address: /^0x[a-zA-Z0-9]{40}$/
};
</script>
<script lang="ts">
@@ -22,6 +39,25 @@
export let disabled = false;
export let config: Config;
let formFields = fields;
let hasErrors = false;
const check = (event: Event) => {
const name = (<HTMLInputElement>event.target).name;
const value = (<HTMLInputElement>event.target).value;
formFields = formFields.map(field => {
if (field.name === name && field.validate) {
hasErrors = value.length > 0 ? !validationTypes[field.validate].test(value) : false;
return { ...field,
value: value,
error: hasErrors ? `Must be a valid ${field.validate}` : undefined
};
}
return field;
});
};
const cleanup = (fields: Field[]): { name: string; value: string | null }[] => {
return fields.filter(field => field.editable).map(field => {
return {
@@ -31,8 +67,12 @@
});
};
const dispatch = createEventDispatcher();
const save = () => dispatch('save', cleanup(fields));
const cancel = () => dispatch('cancel');
const save = () => dispatch('save', cleanup(formFields));
const validate = (event: Event) => dispatch('validate', check(event));
const cancel = () => {
formFields = fields;
dispatch('cancel');
};
</script>
<style>
@@ -72,6 +112,9 @@
text-overflow: ellipsis;
border-color: var(--color-secondary) !important;
}
.description.invalid {
color: var(--color-negative) !important;
}
input.field::placeholder {
color: var(--color-secondary);
font-style: italic;
@@ -101,14 +144,14 @@
</style>
<div class="fields">
{#each fields as field}
{#each formFields as field}
<div class="label">
{field.label || capitalize(field.name)}
</div>
<div>
{#if field.editable && editable}
<input name={field.name} class="field" placeholder={field.placeholder}
bind:value={field.value} type="text" {disabled} />
on:keyup={validate} value={field.value} type="text" {disabled} />
{:else}
<span class="field">
{#if field.value}
@@ -126,9 +169,15 @@
{/if}
</span>
{/if}
<div class="description text-small faded">
{@html marked(field.description)}
</div>
{#if field.error}
<div class="description invalid text-small faded">
{field.error}
</div>
{:else}
<div class="description text-small faded">
{@html marked(field.description)}
</div>
{/if}
</div>
{/each}
</div>
@@ -137,7 +186,7 @@
<button on:click={cancel} {disabled} class="small">
Cancel
</button>
<button on:click={save} {disabled} class="small primary">
<button on:click={save} disabled={hasErrors || disabled} class="small primary">
Save
</button>
</div>
+7 -7
View File
@@ -51,10 +51,10 @@
}
fields = [
{ name: "owner", placeholder: "",
{ name: "owner", validate: "address", placeholder: "",
description: "The owner and controller of this name.",
value: r.owner, resolve: true, editable: false },
{ name: "address", placeholder: "Ethereum address, eg. 0x4a9cf21...bc91",
{ name: "address", validate: "address", placeholder: "Ethereum address, eg. 0x4a9cf21...bc91",
description: "The address this name resolves to. " + (
reverseRecord
? `The reverse record for this address is set to **${name}**`
@@ -63,22 +63,22 @@
+ "a reverse record should be set."
),
value: r.address, editable: true },
{ name: "url", label: "URL", placeholder: "https://acme.org",
{ name: "url", label: "URL", validate: "url", placeholder: "https://acme.org",
description: "A homepage or other URL associated with this name.",
value: r.url,editable: true },
{ name: "avatar", placeholder: "https://acme.org/avatar.png",
{ name: "avatar", validate: "url", placeholder: "https://acme.org/avatar.png",
description: "An avatar or square image associated with this name.",
value: r.avatar, editable: true },
{ name: "twitter", placeholder: "Twitter username, eg. 'acme'",
{ name: "twitter", validate: "handle", placeholder: "Twitter username, eg. 'acme'",
description: "The Twitter handle associated with this name.",
value: r.twitter, editable: true },
{ name: "github", label: "GitHub", placeholder: "GitHub username, eg. 'acme'",
{ name: "github", validate: "handle", label: "GitHub", placeholder: "GitHub username, eg. 'acme'",
description: "The GitHub username associated with this name.",
value: r.github, editable: true },
{ name: "seed.id", label: "Seed ID", placeholder: "hynkyn...3nrzc@seed.acme.org:8887",
description: "The ID of a Radicle Link node that hosts entities associated with this name.",
value: r.seedId, editable: true },
{ name: "seed.api", label: "Seed API", placeholder: "https://seed.acme.org:8888",
{ name: "seed.api", label: "Seed API", validate: "url", placeholder: "https://seed.acme.org:8888",
description: "The HTTP address of a node that serves Radicle entities over HTTP.",
value: r.seedApi, editable: true },
];