mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-12 16:30:34 +08:00
Implement Registration Form validation
Signed-off-by: Sebastian Martinez <sebastinez@me.com>
This commit is contained in:
+57
-8
@@ -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>
|
||||
|
||||
@@ -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 },
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user