Files
myAi/web/wwwroot/js/utils/form-helpers.js
T
claude 98979b58f8 refactor: Extract shared JavaScript utilities (Step 1 of 6)
Create reusable utility modules to eliminate duplication across main.js,
cv-matcher.js, and legal.js:

- js/utils/form-helpers.js: showFieldError, clearFieldErrors, isValidEmail,
  extractApiError — shared form validation and error handling
- js/utils/i18n.js: currentLang, t, applyLanguage, updateLegalLinks,
  browserLang — shared translation and language switching
- js/utils/api.js: checkApiLive, getRecaptchaWebKey, getGoogleTagManagerId,
  loadGoogleTagManager — shared API configuration loading
- js/modules/cookie-consent.js: getConsent, setConsent, initConsent,
  setupConsentHandlers — cookie banner and consent management

All utilities exposed on window.MyAi namespace for use by existing pages.
Full JSDoc headers and inline comments for maintainability.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-29 09:05:51 +03:00

78 lines
2.8 KiB
JavaScript

/**
* Form Validation & Error Handling Utilities
*
* Shared helpers for form field validation and error display across all pages.
* Provides reusable patterns for: error messages, field validation, API error extraction.
*/
/**
* Display a field error message and mark its container with is-invalid class.
* Finds the appropriate parent container (label, form group, consent row, etc.)
* and toggles the is-invalid class based on whether msg is provided.
*
* @param {string} errorId - HTML ID of the error message element
* @param {string} [msg] - Error message to display; empty/null to clear
*/
function showFieldError(errorId, msg) {
var $el = $('#' + errorId);
$el.text(msg || '');
var $parent = $el.parent();
var $container = $parent.is('label, .consent-inline') ? $parent : $el.prev();
if (!$container.length || !$container.is('label, .consent-inline, .file-drop, .subscribe-row')) {
$container = $el.closest('form');
}
$container.toggleClass('is-invalid', !!msg);
}
/**
* Clear multiple field errors at once.
* Calls showFieldError(id, '') for each error element ID.
*
* @param {string[]} errorIds - Array of HTML IDs to clear
*/
function clearFieldErrors(errorIds) {
for (var i = 0; i < errorIds.length; i++) {
showFieldError(errorIds[i], '');
}
}
/**
* Validate email format using a simple regex pattern.
* Checks for: non-whitespace + @ + non-whitespace + . + non-whitespace
*
* @param {string} value - Email address to validate
* @returns {boolean} - True if email format is valid
*/
function isValidEmail(value) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(value || '').trim());
}
/**
* Extract user-facing error message from API response.
*
* Rules:
* - 429 (rate limit) → return rateLimitKey translation
* - 4xx with error body → return server's error message (intentional feedback)
* - 5xx or no body → return fallbackKey translation
*
* @param {object|null} body - Parsed JSON response body
* @param {number} status - HTTP status code
* @param {string} fallbackKey - i18n key for 5xx/unknown errors (e.g., 'form.failed')
* @param {string} [rateLimitKey] - Optional i18n key for 429 (defaults to 'form.rateLimited')
* @returns {string} - User-facing error message
*/
function extractApiError(body, status, fallbackKey, rateLimitKey) {
if (status === 429) {
return window.MyAi.t(rateLimitKey || 'form.rateLimited');
}
var msg = body && (body.error || body.Error || body.title);
return (status >= 400 && status < 500 && msg) ? msg : window.MyAi.t(fallbackKey);
}
// Expose helpers on window.MyAi for use by other scripts
window.MyAi = window.MyAi || {};
window.MyAi.showFieldError = showFieldError;
window.MyAi.clearFieldErrors = clearFieldErrors;
window.MyAi.isValidEmail = isValidEmail;
window.MyAi.extractApiError = extractApiError;