98979b58f8
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>
78 lines
2.8 KiB
JavaScript
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;
|