/** * 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 known error code → look up 'error.' in i18n dictionary first * - 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'); } if (status >= 400 && status < 500) { // Prefer i18n translation keyed on the machine-readable error code if (body && body.code) { var codeKey = 'error.' + body.code; var translated = window.MyAi.t(codeKey); if (translated !== codeKey) return translated; } var msg = body && (body.error || body.Error || body.title); if (msg) return msg; } return 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;