From ade49d9c2fec2f8d2bc91ecd7d0dc100c35101ad Mon Sep 17 00:00:00 2001 From: Laura Gorzitze Date: Mon, 6 Jan 2025 11:49:30 +0100 Subject: [PATCH] #183 Fix user form validation When creating a user, the save button is now only enabled when all required fields are filled out. Additionally, programmatically all fields have the required attribute and visually an asterisk was added to indicate users that the field is required. --- .../main/ui/src/components/users/UserForm.tsx | 47 +++++++++++++++---- app/src/main/ui/src/i18n/de.json | 14 +++--- app/src/main/ui/src/i18n/en.json | 14 +++--- yarn.lock | 8 ++-- 4 files changed, 55 insertions(+), 28 deletions(-) diff --git a/app/src/main/ui/src/components/users/UserForm.tsx b/app/src/main/ui/src/components/users/UserForm.tsx index 7e52bf3c..b855629b 100644 --- a/app/src/main/ui/src/components/users/UserForm.tsx +++ b/app/src/main/ui/src/components/users/UserForm.tsx @@ -1,18 +1,19 @@ import {deprecated_Form as Form, Details} from "@cloudogu/ces-theme-tailwind"; +import type {NotifyFunction, UseFormHandlerFunctions} from "@cloudogu/deprecated-ces-theme-tailwind"; import {Button, H2, ListWithSearchbar} from "@cloudogu/deprecated-ces-theme-tailwind"; import {TrashIcon} from "@heroicons/react/24/outline"; +import {ChangeEvent, useState} from "react"; import {twMerge} from "tailwind-merge"; import {t} from "../../helpers/i18nHelpers"; import {useConfirmation} from "../../hooks/useConfirmation"; import {Prompt} from "../../hooks/usePrompt"; import useUserFormHandler from "../../hooks/useUserFormHandler"; +import type {Group} from "../../services/Groups"; import {GroupsService} from "../../services/Groups"; import {ConfirmationDialog} from "../ConfirmationDialog"; import {useApplicationContext} from "../contexts/ApplicationContext"; import HelpLink from "../helpLink"; -import type {Group} from "../../services/Groups"; import type {User} from "../../services/Users"; -import type {NotifyFunction, UseFormHandlerFunctions} from "@cloudogu/deprecated-ces-theme-tailwind"; const MAX_SEARCH_RESULTS = 10; @@ -31,9 +32,17 @@ export interface UserFormProps { export default function UserForm(props: UserFormProps) { const {handler, notification, notify} = useUserFormHandler(props.initialUser, (values: T) => props.onSubmit(values, notify, handler)); const {open, setOpen: toggleModal, targetName: groupName, setTargetName: setGroupName} = useConfirmation(); + const [formDisabled, setFormDisabled] = useState(true); const {admin} = useApplicationContext().casUser; + const originalChangeFunction = handler.handleChange; + + handler.handleChange = (e:ChangeEvent) => { + originalChangeFunction(e); + hasEmptyRequiredFields(); + }; + const addGroup = (groupName: string): void => { if (handler.values.memberOf.indexOf(groupName) < 0) { const newGroups = [...handler.values.memberOf, groupName]; @@ -83,6 +92,24 @@ export default function UserForm(props: UserFormProps) { /> ); + const hasEmptyRequiredFields = (): void => { + const form = document.forms.item(0); + console.log("Check for null values"); + if (form) { + const inputs: NodeListOf = form.querySelectorAll("input:required"); + for (const input of inputs) { + if (!input.value) { + setFormDisabled(true); + return; + } + } + setFormDisabled(false); + return; + } + setFormDisabled(true); + return; + }; + return ( <> (props: UserFormProps) { {t("users.externalUserWarning")} )} - + {t("editUser.labels.username")} - + {t("editUser.labels.givenName")} - + {t("editUser.labels.surname")} - + {t("editUser.labels.displayName")} - + {t("editUser.labels.email")} {!props.initialUser.external && <> - + {t("editUser.labels.password")} - + {t("editUser.labels.confirmPassword")} @@ -156,7 +183,7 @@ export default function UserForm(props: UserFormProps) { )}
- {props.additionalButtons as JSX.Element} diff --git a/app/src/main/ui/src/i18n/de.json b/app/src/main/ui/src/i18n/de.json index 4133fd45..4e4af75f 100644 --- a/app/src/main/ui/src/i18n/de.json +++ b/app/src/main/ui/src/i18n/de.json @@ -21,15 +21,15 @@ "editUser.errors.username.maxlength": "Darf höchstens 128 zeichen enthalten", "editUser.errors.username.minlength": "Muss mindestens 2 Zeichen enthalten", "editUser.errors.username.required": "Nutzername muss ausgefüllt sein.", - "editUser.labels.confirmPassword": "Passwort bestätigen", - "editUser.labels.displayName": "Anzeigename", - "editUser.labels.email": "E-Mail", + "editUser.labels.confirmPassword": "Passwort bestätigen*", + "editUser.labels.displayName": "Anzeigename*", + "editUser.labels.email": "E-Mail*", "editUser.labels.external": "Externer Account", - "editUser.labels.givenName": "Vorname", + "editUser.labels.givenName": "Vorname*", "editUser.labels.mustChangePassword": "Nutzer muss sein Passwort beim nächsten Login ändern", - "editUser.labels.password": "Passwort", - "editUser.labels.surname": "Nachname", - "editUser.labels.username": "Nutzername", + "editUser.labels.password": "Passwort*", + "editUser.labels.surname": "Nachname*", + "editUser.labels.username": "Nutzername*", "editUser.notification.error": "Die Account Informationen konnten nicht gespeichert werden. Bitte versuchen Sie es später erneut.", "editUser.notification.success": "Die Account Informationen wurden erfolgreich gespeichert.", "general.applicationName": "User Management", diff --git a/app/src/main/ui/src/i18n/en.json b/app/src/main/ui/src/i18n/en.json index 2081704a..4feea53b 100644 --- a/app/src/main/ui/src/i18n/en.json +++ b/app/src/main/ui/src/i18n/en.json @@ -21,15 +21,15 @@ "editUser.errors.username.maxlength": "May contain a maximum of 128 characters", "editUser.errors.username.minlength": "Must contain at least 2 characters", "editUser.errors.username.required": "Username is required.", - "editUser.labels.confirmPassword": "Confirm Password", - "editUser.labels.displayName": "Display Name", - "editUser.labels.email": "E-Mail", + "editUser.labels.confirmPassword": "Confirm Password*", + "editUser.labels.displayName": "Display Name*", + "editUser.labels.email": "E-Mail*", "editUser.labels.external": "External account", - "editUser.labels.givenName": "Given Name", + "editUser.labels.givenName": "Given Name*", "editUser.labels.mustChangePassword": "The user must change the password at the next login", - "editUser.labels.password": "Password", - "editUser.labels.surname": "Surname", - "editUser.labels.username": "Username", + "editUser.labels.password": "Password*", + "editUser.labels.surname": "Surname*", + "editUser.labels.username": "Username*", "editUser.notification.error": "Account information could not be saved. Please try again later.", "editUser.notification.success": "Account information saved successfully.", "general.applicationName": "User Management", diff --git a/yarn.lock b/yarn.lock index b54b7b97..a192a973 100644 --- a/yarn.lock +++ b/yarn.lock @@ -107,7 +107,7 @@ asn1@~0.2.3: dependencies: safer-buffer "~2.1.0" -assert-plus@^1.0.0, assert-plus@1.0.0: +assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== @@ -401,7 +401,7 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enquirer@^2.3.6, "enquirer@>= 2.3.0 < 3": +enquirer@^2.3.6: version "2.4.1" resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz" integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== @@ -469,7 +469,7 @@ extract-zip@2.0.1: optionalDependencies: "@types/yauzl" "^2.9.1" -extsprintf@^1.2.0, extsprintf@1.3.0: +extsprintf@1.3.0, extsprintf@^1.2.0: version "1.3.0" resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== @@ -784,7 +784,7 @@ minimist@^1.2.8: resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -ms@^2.1.1, ms@2.1.2: +ms@2.1.2, ms@^2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==