From 6df54857079c9ecf4e32e1f05279adc06ff047a5 Mon Sep 17 00:00:00 2001 From: GeNii96 Date: Tue, 2 Jun 2026 11:18:19 +0200 Subject: [PATCH] fix loginpage error message /display onyl once --- OnlyPrompt.Frontend/js/shared.js | 220 +++++++++++++++++-------------- 1 file changed, 120 insertions(+), 100 deletions(-) diff --git a/OnlyPrompt.Frontend/js/shared.js b/OnlyPrompt.Frontend/js/shared.js index 13d0c7b..2bc0115 100644 --- a/OnlyPrompt.Frontend/js/shared.js +++ b/OnlyPrompt.Frontend/js/shared.js @@ -1,95 +1,111 @@ -import './linq.js' -import { Template } from './template.js'; +import "./linq.js"; +import { Template } from "./template.js"; export function formToObject(form) { - const data = new FormData(form); - const object = {}; - data.forEach((value, key) => { - setNestedValue(object, key, value); - }); - return object; + const data = new FormData(form); + const object = {}; + data.forEach((value, key) => { + setNestedValue(object, key, value); + }); + return object; } function setNestedValue(obj, path, value) { - path.split('.').asEnumerable() - .isLast() - .forEach((key, isLast) => { - if (isLast) { - obj[key] = value; - } - else { - if (!obj[key]) { - obj[key] = {}; - } + path + .split(".") + .asEnumerable() + .isLast() + .forEach((key, isLast) => { + if (isLast) { + obj[key] = value; + } else { + if (!obj[key]) { + obj[key] = {}; + } - obj = obj[key]; - } - }); + obj = obj[key]; + } + }); } export async function sendFormAsync(form, url, method) { - url = url || form.action; - method = method || form.method || 'post'; - const data = formToObject(form); - const response = await sendJsonAsync(url, data, method); - if (response.ok && response.redirected) { - window.location.href = response.url; - return null; - } + url = url || form.action; + method = method || form.method || "post"; + const data = formToObject(form); + const response = await sendJsonAsync(url, data, method); + if (response.ok && response.redirected) { + window.location.href = response.url; + return null; + } - const responseText = await response.text(); - if (response.ok == false && handleValidationError(response, responseText, form)) { - return null; - } + const responseText = await response.text(); + if ( + response.ok == false && + handleValidationError(response, responseText, form) + ) { + return null; + } - if (response.ok == false) { - handleGenericFormError(response, responseText, form); - return null; - } else { - return responseText.length == 0 ? null : JSON.parse(responseText); - } + if (response.ok == false) { + handleGenericFormError(response, responseText, form); + return null; + } else { + return responseText.length == 0 ? null : JSON.parse(responseText); + } } -export async function sendJsonAsync(url, data, method = 'post') { - const response = await fetch(url, { - method: method.toUpperCase(), - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(data) - }); +export async function sendJsonAsync(url, data, method = "post") { + const response = await fetch(url, { + method: method.toUpperCase(), + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }); - return response; + return response; } export async function postAndRenderAsync(url, data, template, targetElement) { - const response = await sendJsonAsync(url, data); - if (response.ok) { - const responseText = await response.text(); - targetElement.innerHTML = template.render(responseText.length == 0 ? undefined : JSON.parse(responseText)); - } + const response = await sendJsonAsync(url, data); + if (response.ok) { + const responseText = await response.text(); + targetElement.innerHTML = template.render( + responseText.length == 0 ? undefined : JSON.parse(responseText), + ); + } } -export async function postFormAndRenderAsync(url, form, template, targetElement) { - const object = formToObject(form); - const data = await postFormAsync(url, object, template, targetElement); - if (data) { - targetElement.innerHTML = template.render(data); - } +export async function postFormAndRenderAsync( + url, + form, + template, + targetElement, +) { + const object = formToObject(form); + const data = await postFormAsync(url, object, template, targetElement); + if (data) { + targetElement.innerHTML = template.render(data); + } } const genericFormErrorTemplate = new Template(`
- An error occurred while submitting the form. Please try again later. - {{ $this }} + {{ $this }}
`); function handleGenericFormError(response, responseText, form) { - if (!response.ok) { - const html = genericFormErrorTemplate.render(responseText); - form.insertAdjacentHTML('beforeend', html); - } + if (!response.ok) { + // Remove all existing form-level errors before adding a new one + form.querySelectorAll(":scope > .form-error").forEach((el) => el.remove()); + let message = responseText; + try { + message = JSON.parse(responseText); + } catch (_) {} + const html = genericFormErrorTemplate.render(message); + form.insertAdjacentHTML("beforeend", html); + } } const validationErrorTemplate = new Template(` @@ -116,45 +132,49 @@ const unknownInputErrorTemplate = new Template(` `); function toCamelCase(str) { - str = str.replace(/([-_][a-z])/gi, (match) => { - return match.toUpperCase() - .replace('-', '') - .replace('_', ''); - }); + str = str.replace(/([-_][a-z])/gi, (match) => { + return match.toUpperCase().replace("-", "").replace("_", ""); + }); - str = str[0].toLowerCase() + str.substring(1); - return str; + str = str[0].toLowerCase() + str.substring(1); + return str; } - function handleValidationError(response, responseText, form) { - if (response.status !== 400) return false; - const responseObject = JSON.parse(responseText); - const unknownInputErrors = {}; - if (responseObject.type === 'https://tools.ietf.org/html/rfc9110#section-15.5.1' && responseObject.errors) { - for (const [field, messages] of Object.entries(responseObject.errors)) { - const input = form.querySelector(`[name="${toCamelCase(field)}"]`); - if (input) { - const parent = input.parentElement; - const errorHtml = validationErrorTemplate.render(messages); - let errorContainer = parent.querySelector('.form-error'); // Check if an error container already exists - if (errorContainer) { - errorContainer.outerHTML = errorHtml; // Replace existing error container - } else { - parent.insertAdjacentHTML('beforeend', errorHtml); - } - } else { - unknownInputErrors[field] = messages; - } + if (response.status !== 400) return false; + const responseObject = JSON.parse(responseText); + const unknownInputErrors = {}; + if ( + responseObject.type === + "https://tools.ietf.org/html/rfc9110#section-15.5.1" && + responseObject.errors + ) { + for (const [field, messages] of Object.entries(responseObject.errors)) { + const input = form.querySelector(`[name="${toCamelCase(field)}"]`); + if (input) { + const parent = input.parentElement; + const errorHtml = validationErrorTemplate.render(messages); + let errorContainer = parent.querySelector(".form-error"); // Check if an error container already exists + if (errorContainer) { + errorContainer.outerHTML = errorHtml; // Replace existing error container + } else { + parent.insertAdjacentHTML("beforeend", errorHtml); } - - if (Object.keys(unknownInputErrors).length > 0) { - const html = unknownInputErrorTemplate.render(unknownInputErrors); - form.insertAdjacentHTML('beforeend', html); - } - - return true; + } else { + unknownInputErrors[field] = messages; + } } - return false; -} \ No newline at end of file + if (Object.keys(unknownInputErrors).length > 0) { + form + .querySelectorAll(":scope > .form-error") + .forEach((el) => el.remove()); + const html = unknownInputErrorTemplate.render(unknownInputErrors); + form.insertAdjacentHTML("beforeend", html); + } + + return true; + } + + return false; +}