1e8758796e
- Frontend: update extractApiError to check body.code first via i18n 'error.<code>' keys; add en/ro translations for cv_file_missing, captcha_verification_failed, request_cancelled - email-data migration: seed 6 fallback template keys (match N/A, subject label, unknown IP, job search results empty states for keywords/providers/location) - EmailApiEmailSender: replace "N/A", "Job", "Unknown" literals with template lookups - CvSearchEmailSender: replace "none detected", "none", "-" literals with template lookups - cv-matcher-data migration: seed parse-error.summary and parse-error.recommendation in AiPrompts - CvMatcherService: look up localized parse-error messages from AiPrompts before calling ParseResult Closes #53 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
88 lines
3.1 KiB
JavaScript
88 lines
3.1 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 known error code → look up 'error.<code>' 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;
|