From 6f031f105910974ace9220dcf409f4786ceb16a9 Mon Sep 17 00:00:00 2001 From: sua yoo Date: Mon, 15 Jul 2024 11:02:10 -0700 Subject: [PATCH] show correct field when validating --- frontend/src/pages/invite/ui/org-form.ts | 44 ++++++++++++++++++++---- frontend/src/theme.stylesheet.css | 9 ++--- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/frontend/src/pages/invite/ui/org-form.ts b/frontend/src/pages/invite/ui/org-form.ts index cb9821f8..def73be0 100644 --- a/frontend/src/pages/invite/ui/org-form.ts +++ b/frontend/src/pages/invite/ui/org-form.ts @@ -3,7 +3,7 @@ import { Task, TaskStatus } from "@lit/task"; import type { SlInput } from "@shoelace-style/shoelace"; import { serialize } from "@shoelace-style/shoelace/dist/utilities/form.js"; import { html } from "lit"; -import { customElement, property } from "lit/decorators.js"; +import { customElement, property, query } from "lit/decorators.js"; import slugify from "slugify"; import { TailwindElement } from "@/classes/TailwindElement"; @@ -43,6 +43,9 @@ export class OrgForm extends TailwindElement { @property({ type: String }) slug = ""; + @query("#orgForm") + private readonly form?: HTMLFormElement | null; + readonly _api = new APIController(this); readonly _notify = new NotifyController(this); @@ -151,21 +154,34 @@ export class OrgForm extends TailwindElement { } catch (e) { console.debug(e); if (isApiError(e)) { + let error: Error | null = null; + let fieldName = ""; + if (e.details === "duplicate_org_name") { - throw new Error( - msg("This org name is already taken, try another one."), + fieldName = "orgName"; + error = new Error( + msg(str`The org name "${name}" is already taken, try another one.`), ); } else if (e.details === "duplicate_org_slug") { - throw new Error( - msg("This org URL is already taken, try another one."), + fieldName = "orgSlug"; + error = new Error( + msg(str`The org URL "${slug}" is already taken, try another one.`), ); } else if (e.details === "invalid_slug") { - throw new Error( + fieldName = "orgSlug"; + error = new Error( msg( - "This org URL is invalid. Please use alphanumeric characters and dashes (-) only.", + str`The org URL "${slug}" is not a valid URL. Please use alphanumeric characters and dashes (-) only`, ), ); } + + if (error) { + if (fieldName) { + this.highlightErrorField(fieldName, error); + } + throw error; + } } this._notify.toast({ @@ -178,6 +194,20 @@ export class OrgForm extends TailwindElement { } } + private highlightErrorField(fieldName: string, error: Error) { + const input = this.form?.querySelector(`[name="${fieldName}"]`); + + if (input) { + input.setCustomValidity(error.message); + + const onOneInput = () => { + input.setCustomValidity(""); + input.removeEventListener("sl-input", onOneInput); + }; + input.addEventListener("sl-input", onOneInput); + } + } + private async checkFormValidity(formEl: HTMLFormElement) { await this.updateComplete; return !formEl.querySelector("[data-invalid]"); diff --git a/frontend/src/theme.stylesheet.css b/frontend/src/theme.stylesheet.css index b421f37d..5875dd84 100644 --- a/frontend/src/theme.stylesheet.css +++ b/frontend/src/theme.stylesheet.css @@ -166,14 +166,15 @@ box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-color-danger-100); } - [data-user-invalid]:not([disabled])::part(form-control-label):after { - /* Required asterisk color */ - color: var(--sl-color-danger-500); + [data-user-invalid]:not([disabled])::part(form-control-label), + /* Required asterisk color */ + [data-user-invalid]:not([disabled])::part(form-control-label)::after { + color: var(--sl-color-danger-700); } [data-user-invalid]:not([disabled])::part(form-control-help-text), [data-user-invalid]:not([disabled]) .form-help-text { - color: var(--sl-color-danger-500); + color: var(--sl-color-danger-700); } /* TODO tailwind sets border-width: 0, see if this can be fixed in tw */