You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
8.3 KiB
262 lines
8.3 KiB
/**
|
|
* Error Message Utilities
|
|
*
|
|
* Provides German error messages for form validation and API errors.
|
|
* Uses informal "Du" form as per project requirements.
|
|
*/
|
|
|
|
/**
|
|
* Common validation error messages (German)
|
|
*/
|
|
export const validationMessages = {
|
|
required: 'Dieses Feld ist erforderlich',
|
|
email: 'Bitte gib eine gültige E-Mail-Adresse ein',
|
|
minLength: (min: number) => `Mindestens ${min} Zeichen erforderlich`,
|
|
maxLength: (max: number) => `Maximal ${max} Zeichen erlaubt`,
|
|
min: (min: number) => `Wert muss mindestens ${min} sein`,
|
|
max: (max: number) => `Wert darf maximal ${max} sein`,
|
|
pattern: 'Ungültiges Format',
|
|
url: 'Bitte gib eine gültige URL ein',
|
|
numeric: 'Nur Zahlen erlaubt',
|
|
phoneNumber: 'Bitte gib eine gültige Telefonnummer ein',
|
|
postCode: 'Bitte gib eine gültige Postleitzahl ein',
|
|
dateInvalid: 'Ungültiges Datum',
|
|
dateFuture: 'Datum darf nicht in der Zukunft liegen',
|
|
datePast: 'Datum darf nicht in der Vergangenheit liegen',
|
|
dateOfBirthTooYoung: 'Du musst mindestens 18 Jahre alt sein',
|
|
passwordWeak:
|
|
'Passwort muss mindestens 8 Zeichen, einen Großbuchstaben, einen Kleinbuchstaben und eine Zahl enthalten',
|
|
passwordMismatch: 'Passwörter stimmen nicht überein',
|
|
terms: 'Bitte akzeptiere die AGB',
|
|
privacy: 'Bitte akzeptiere die Datenschutzerklärung',
|
|
}
|
|
|
|
/**
|
|
* Field-specific error messages
|
|
*/
|
|
export const fieldMessages = {
|
|
salutation: {
|
|
required: 'Bitte wähle eine Anrede',
|
|
},
|
|
firstName: {
|
|
required: 'Bitte gib deinen Vornamen ein',
|
|
minLength: 'Vorname muss mindestens 2 Zeichen lang sein',
|
|
},
|
|
lastName: {
|
|
required: 'Bitte gib deinen Nachnamen ein',
|
|
minLength: 'Nachname muss mindestens 2 Zeichen lang sein',
|
|
},
|
|
email: {
|
|
required: 'Bitte gib deine E-Mail-Adresse ein',
|
|
invalid: 'Bitte gib eine gültige E-Mail-Adresse ein',
|
|
},
|
|
password: {
|
|
required: 'Bitte gib ein Passwort ein',
|
|
weak:
|
|
'Passwort muss mindestens 8 Zeichen, einen Großbuchstaben, einen Kleinbuchstaben und eine Zahl enthalten',
|
|
},
|
|
dateOfBirth: {
|
|
required: 'Bitte gib dein Geburtsdatum ein',
|
|
invalid: 'Ungültiges Datum',
|
|
tooYoung: 'Du musst mindestens 18 Jahre alt sein',
|
|
future: 'Geburtsdatum darf nicht in der Zukunft liegen',
|
|
},
|
|
street: {
|
|
required: 'Bitte gib deine Straße und Hausnummer ein',
|
|
minLength: 'Straße muss mindestens 3 Zeichen lang sein',
|
|
},
|
|
postCode: {
|
|
required: 'Bitte gib deine Postleitzahl ein',
|
|
invalid: 'Ungültige Postleitzahl',
|
|
},
|
|
city: {
|
|
required: 'Bitte gib deinen Ort ein',
|
|
minLength: 'Ort muss mindestens 2 Zeichen lang sein',
|
|
},
|
|
countryCode: {
|
|
required: 'Bitte wähle ein Land',
|
|
},
|
|
phone: {
|
|
invalid: 'Bitte gib eine gültige Telefonnummer ein',
|
|
},
|
|
quantity: {
|
|
min: 'Menge muss mindestens 1 sein',
|
|
max: (max: number) => `Maximal ${max} Stück verfügbar`,
|
|
},
|
|
}
|
|
|
|
/**
|
|
* API error messages
|
|
*/
|
|
export const apiErrorMessages = {
|
|
// Authentication errors
|
|
auth: {
|
|
invalidCredentials: 'E-Mail oder Passwort ist falsch',
|
|
emailAlreadyExists: 'Diese E-Mail-Adresse wird bereits verwendet',
|
|
sessionExpired: 'Deine Sitzung ist abgelaufen. Bitte melde dich erneut an',
|
|
unauthorized: 'Du musst angemeldet sein, um diese Aktion durchzuführen',
|
|
forbidden: 'Du hast keine Berechtigung für diese Aktion',
|
|
},
|
|
// Product errors
|
|
products: {
|
|
notFound: 'Produkt nicht gefunden',
|
|
unavailable: 'Produkt ist nicht verfügbar',
|
|
outOfStock: 'Produkt ist nicht mehr auf Lager',
|
|
insufficientStock: 'Nicht genügend auf Lager',
|
|
},
|
|
// Cart errors
|
|
cart: {
|
|
notFound: 'Warenkorb nicht gefunden',
|
|
itemNotFound: 'Artikel nicht im Warenkorb gefunden',
|
|
empty: 'Dein Warenkorb ist leer',
|
|
invalidQuantity: 'Ungültige Menge',
|
|
addFailed: 'Artikel konnte nicht hinzugefügt werden',
|
|
updateFailed: 'Artikel konnte nicht aktualisiert werden',
|
|
removeFailed: 'Artikel konnte nicht entfernt werden',
|
|
},
|
|
// Order errors
|
|
orders: {
|
|
notFound: 'Bestellung nicht gefunden',
|
|
createFailed: 'Bestellung konnte nicht erstellt werden',
|
|
paymentFailed: 'Zahlung fehlgeschlagen',
|
|
invalidAddress: 'Ungültige Lieferadresse',
|
|
submissionFailed: 'Bestellung konnte nicht übermittelt werden',
|
|
},
|
|
// Generic errors
|
|
generic: {
|
|
networkError: 'Netzwerkfehler. Bitte überprüfe deine Internetverbindung',
|
|
serverError: 'Ein Serverfehler ist aufgetreten. Bitte versuche es später erneut',
|
|
validationError: 'Bitte überprüfe deine Eingaben',
|
|
unknownError: 'Ein unbekannter Fehler ist aufgetreten',
|
|
},
|
|
}
|
|
|
|
/**
|
|
* Format API error response to user-friendly message
|
|
*
|
|
* @param error - Error object from API call
|
|
* @returns User-friendly error message in German
|
|
*
|
|
* @example
|
|
* try {
|
|
* await $fetch('/api/cart/items', { method: 'POST', body: { productId, quantity } })
|
|
* } catch (error) {
|
|
* const message = formatApiError(error)
|
|
* toast.error(message)
|
|
* }
|
|
*/
|
|
export function formatApiError(error: unknown): string {
|
|
// Handle FetchError from Nuxt $fetch
|
|
if (error && typeof error === 'object' && 'statusCode' in error) {
|
|
const statusCode = (error as { statusCode: number }).statusCode
|
|
const data = (error as { data?: { message?: string } }).data
|
|
|
|
// Use custom message from API if available
|
|
if (data?.message) {
|
|
return data.message
|
|
}
|
|
|
|
// Map status codes to generic messages
|
|
switch (statusCode) {
|
|
case 400:
|
|
return apiErrorMessages.generic.validationError
|
|
case 401:
|
|
return apiErrorMessages.auth.unauthorized
|
|
case 403:
|
|
return apiErrorMessages.auth.forbidden
|
|
case 404:
|
|
return 'Ressource nicht gefunden'
|
|
case 409:
|
|
return 'Konflikt: Diese Aktion kann nicht durchgeführt werden'
|
|
case 422:
|
|
return apiErrorMessages.generic.validationError
|
|
case 429:
|
|
return 'Zu viele Anfragen. Bitte warte einen Moment'
|
|
case 500:
|
|
return apiErrorMessages.generic.serverError
|
|
case 503:
|
|
return 'Service vorübergehend nicht verfügbar'
|
|
default:
|
|
return apiErrorMessages.generic.unknownError
|
|
}
|
|
}
|
|
|
|
// Handle network errors
|
|
if (error instanceof TypeError && error.message.includes('fetch')) {
|
|
return apiErrorMessages.generic.networkError
|
|
}
|
|
|
|
// Handle Error objects with message
|
|
if (error instanceof Error) {
|
|
return error.message
|
|
}
|
|
|
|
// Fallback for unknown error types
|
|
return apiErrorMessages.generic.unknownError
|
|
}
|
|
|
|
/**
|
|
* Get validation error message for a specific field and error type
|
|
*
|
|
* @param field - Field name
|
|
* @param errorType - Zod error type (e.g., 'required', 'invalid_string', 'too_small')
|
|
* @param params - Additional parameters (e.g., min, max values)
|
|
* @returns User-friendly validation error message
|
|
*
|
|
* @example
|
|
* const message = getValidationMessage('email', 'invalid_string')
|
|
* // => "Bitte gib eine gültige E-Mail-Adresse ein"
|
|
*/
|
|
export function getValidationMessage(
|
|
field: string,
|
|
errorType: string,
|
|
params?: { minimum?: number; maximum?: number }
|
|
): string {
|
|
// Check field-specific messages first
|
|
const fieldKey = field as keyof typeof fieldMessages
|
|
if (fieldKey in fieldMessages) {
|
|
const fieldMessage = fieldMessages[fieldKey]
|
|
|
|
// Map Zod error types to field-specific messages
|
|
if (errorType === 'invalid_type' || errorType === 'required') {
|
|
return fieldMessage.required || validationMessages.required
|
|
}
|
|
|
|
if (errorType === 'invalid_string' || errorType === 'invalid_email') {
|
|
return 'invalid' in fieldMessage
|
|
? fieldMessage.invalid
|
|
: validationMessages.email
|
|
}
|
|
|
|
if (errorType === 'too_small' && 'minLength' in fieldMessage) {
|
|
return fieldMessage.minLength
|
|
}
|
|
|
|
if (errorType === 'too_small' && params?.minimum) {
|
|
return validationMessages.minLength(params.minimum)
|
|
}
|
|
|
|
if (errorType === 'too_big' && params?.maximum) {
|
|
return validationMessages.maxLength(params.maximum)
|
|
}
|
|
}
|
|
|
|
// Fallback to generic messages
|
|
if (errorType === 'invalid_type' || errorType === 'required') {
|
|
return validationMessages.required
|
|
}
|
|
|
|
if (errorType === 'invalid_string' || errorType === 'invalid_email') {
|
|
return validationMessages.email
|
|
}
|
|
|
|
if (errorType === 'too_small' && params?.minimum) {
|
|
return validationMessages.minLength(params.minimum)
|
|
}
|
|
|
|
if (errorType === 'too_big' && params?.maximum) {
|
|
return validationMessages.maxLength(params.maximum)
|
|
}
|
|
|
|
return validationMessages.required
|
|
}
|
|
|