Refactor error handling and localization in frontend components
This commit enhances the error handling and user interface of various frontend components by integrating localization support. It updates error messages and titles across multiple views and dialogs to utilize the translation function, ensuring a consistent user experience in different languages. Additionally, it refines the handling of error messages in the MyTischtennis account and member transfer settings, improving clarity and user feedback during operations.
This commit is contained in:
125
backend/constants/ERROR_CODES_USAGE.md
Normal file
125
backend/constants/ERROR_CODES_USAGE.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Fehlercode-System - Verwendungsanleitung
|
||||
|
||||
## Übersicht
|
||||
|
||||
Das Fehlercode-System ersetzt hardcodierte deutsche Fehlermeldungen durch strukturierte Fehlercodes, die im Frontend übersetzt werden.
|
||||
|
||||
## Backend-Verwendung
|
||||
|
||||
### 1. Fehlercode verwenden
|
||||
|
||||
```javascript
|
||||
import HttpError from '../exceptions/HttpError.js';
|
||||
import { ERROR_CODES, createError } from '../constants/errorCodes.js';
|
||||
|
||||
// Einfacher Fehlercode ohne Parameter
|
||||
throw new HttpError(createError(ERROR_CODES.USER_NOT_FOUND), 404);
|
||||
|
||||
// Fehlercode mit Parametern
|
||||
throw new HttpError(
|
||||
createError(ERROR_CODES.MEMBER_NOT_FOUND, { memberId: 123 }),
|
||||
404
|
||||
);
|
||||
|
||||
// Oder direkt:
|
||||
throw new HttpError(
|
||||
{ code: ERROR_CODES.MEMBER_NOT_FOUND, params: { memberId: 123 } },
|
||||
404
|
||||
);
|
||||
```
|
||||
|
||||
### 2. Legacy-Format (wird weiterhin unterstützt)
|
||||
|
||||
```javascript
|
||||
// Alte Variante funktioniert noch:
|
||||
throw new HttpError('Benutzer nicht gefunden', 404);
|
||||
```
|
||||
|
||||
## Frontend-Verwendung
|
||||
|
||||
### 1. Fehlermeldungen automatisch übersetzen
|
||||
|
||||
Die `getSafeErrorMessage`-Funktion erkennt automatisch Fehlercodes:
|
||||
|
||||
```javascript
|
||||
import { getSafeErrorMessage } from '../utils/errorMessages.js';
|
||||
|
||||
// In einer Vue-Komponente (Options API)
|
||||
try {
|
||||
await apiClient.post('/api/endpoint', data);
|
||||
} catch (error) {
|
||||
const message = getSafeErrorMessage(error, this.$t('errors.ERROR_UNKNOWN_ERROR'), this.$t);
|
||||
await this.showInfo(this.$t('messages.error'), message, '', 'error');
|
||||
}
|
||||
|
||||
// In einer Vue-Komponente (Composition API)
|
||||
import { useI18n } from 'vue-i18n';
|
||||
const { t } = useI18n();
|
||||
|
||||
try {
|
||||
await apiClient.post('/api/endpoint', data);
|
||||
} catch (error) {
|
||||
const message = getSafeErrorMessage(error, t('errors.ERROR_UNKNOWN_ERROR'), t);
|
||||
await showInfo(t('messages.error'), message, '', 'error');
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Dialog-Utils mit Übersetzung
|
||||
|
||||
```javascript
|
||||
import { buildInfoConfig, safeErrorMessage } from '../utils/dialogUtils.js';
|
||||
|
||||
// Mit Übersetzungsfunktion
|
||||
this.infoDialog = buildInfoConfig({
|
||||
title: this.$t('messages.error'),
|
||||
message: safeErrorMessage(error, this.$t('errors.ERROR_UNKNOWN_ERROR'), this.$t),
|
||||
type: 'error'
|
||||
}, this.$t);
|
||||
```
|
||||
|
||||
## API-Response-Format
|
||||
|
||||
### Neues Format (mit Fehlercode):
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"code": "ERROR_MEMBER_NOT_FOUND",
|
||||
"params": {
|
||||
"memberId": 123
|
||||
},
|
||||
"error": "ERROR_MEMBER_NOT_FOUND" // Für Rückwärtskompatibilität
|
||||
}
|
||||
```
|
||||
|
||||
### Legacy-Format (wird weiterhin unterstützt):
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "Mitglied nicht gefunden",
|
||||
"error": "Mitglied nicht gefunden"
|
||||
}
|
||||
```
|
||||
|
||||
## Übersetzungen hinzufügen
|
||||
|
||||
1. **Backend**: Fehlercode in `backend/constants/errorCodes.js` definieren
|
||||
2. **Frontend**: Übersetzung in `frontend/src/i18n/locales/de.json` unter `errors` hinzufügen
|
||||
|
||||
Beispiel:
|
||||
```json
|
||||
{
|
||||
"errors": {
|
||||
"ERROR_MEMBER_NOT_FOUND": "Mitglied nicht gefunden.",
|
||||
"ERROR_MEMBER_NOT_FOUND_WITH_ID": "Mitglied mit ID {memberId} nicht gefunden."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Migration bestehender Fehler
|
||||
|
||||
1. Hardcodierte Fehlermeldung identifizieren
|
||||
2. Passenden Fehlercode in `errorCodes.js` finden oder erstellen
|
||||
3. Backend-Code anpassen: `throw new HttpError(createError(ERROR_CODES.XXX), status)`
|
||||
4. Übersetzung in `de.json` hinzufügen
|
||||
5. Frontend-Code muss nicht geändert werden (automatische Erkennung)
|
||||
|
||||
120
backend/constants/errorCodes.js
Normal file
120
backend/constants/errorCodes.js
Normal file
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Fehlercodes für die API
|
||||
* Diese Codes werden an das Frontend gesendet und dort übersetzt
|
||||
*
|
||||
* Format: { code: string, params?: object }
|
||||
*
|
||||
* Beispiel:
|
||||
* - { code: 'ERROR_USER_NOT_FOUND' }
|
||||
* - { code: 'ERROR_MEMBER_NOT_FOUND', params: { memberId: 123 } }
|
||||
* - { code: 'ERROR_VALIDATION_FAILED', params: { field: 'email', value: 'invalid' } }
|
||||
*/
|
||||
|
||||
export const ERROR_CODES = {
|
||||
// Allgemeine Fehler
|
||||
INTERNAL_SERVER_ERROR: 'ERROR_INTERNAL_SERVER_ERROR',
|
||||
UNKNOWN_ERROR: 'ERROR_UNKNOWN_ERROR',
|
||||
VALIDATION_FAILED: 'ERROR_VALIDATION_FAILED',
|
||||
NOT_FOUND: 'ERROR_NOT_FOUND',
|
||||
UNAUTHORIZED: 'ERROR_UNAUTHORIZED',
|
||||
FORBIDDEN: 'ERROR_FORBIDDEN',
|
||||
BAD_REQUEST: 'ERROR_BAD_REQUEST',
|
||||
|
||||
// Authentifizierung
|
||||
USER_NOT_FOUND: 'ERROR_USER_NOT_FOUND',
|
||||
INVALID_PASSWORD: 'ERROR_INVALID_PASSWORD',
|
||||
LOGIN_FAILED: 'ERROR_LOGIN_FAILED',
|
||||
SESSION_EXPIRED: 'ERROR_SESSION_EXPIRED',
|
||||
|
||||
// MyTischtennis
|
||||
MYTISCHTENNIS_USER_NOT_FOUND: 'ERROR_MYTISCHTENNIS_USER_NOT_FOUND',
|
||||
MYTISCHTENNIS_INVALID_PASSWORD: 'ERROR_MYTISCHTENNIS_INVALID_PASSWORD',
|
||||
MYTISCHTENNIS_LOGIN_FAILED: 'ERROR_MYTISCHTENNIS_LOGIN_FAILED',
|
||||
MYTISCHTENNIS_ACCOUNT_NOT_LINKED: 'ERROR_MYTISCHTENNIS_ACCOUNT_NOT_LINKED',
|
||||
MYTISCHTENNIS_PASSWORD_NOT_SAVED: 'ERROR_MYTISCHTENNIS_PASSWORD_NOT_SAVED',
|
||||
MYTISCHTENNIS_SESSION_EXPIRED: 'ERROR_MYTISCHTENNIS_SESSION_EXPIRED',
|
||||
MYTISCHTENNIS_NO_PASSWORD_SAVED: 'ERROR_MYTISCHTENNIS_NO_PASSWORD_SAVED',
|
||||
|
||||
// Mitglieder
|
||||
MEMBER_NOT_FOUND: 'ERROR_MEMBER_NOT_FOUND',
|
||||
MEMBER_ALREADY_EXISTS: 'ERROR_MEMBER_ALREADY_EXISTS',
|
||||
MEMBER_FIRSTNAME_REQUIRED: 'ERROR_MEMBER_FIRSTNAME_REQUIRED',
|
||||
MEMBER_LASTNAME_REQUIRED: 'ERROR_MEMBER_LASTNAME_REQUIRED',
|
||||
|
||||
// Gruppen
|
||||
GROUP_NOT_FOUND: 'ERROR_GROUP_NOT_FOUND',
|
||||
GROUP_NAME_REQUIRED: 'ERROR_GROUP_NAME_REQUIRED',
|
||||
GROUP_ALREADY_EXISTS: 'ERROR_GROUP_ALREADY_EXISTS',
|
||||
GROUP_INVALID_PRESET_TYPE: 'ERROR_GROUP_INVALID_PRESET_TYPE',
|
||||
GROUP_CANNOT_RENAME_PRESET: 'ERROR_GROUP_CANNOT_RENAME_PRESET',
|
||||
|
||||
// Turniere
|
||||
TOURNAMENT_NOT_FOUND: 'ERROR_TOURNAMENT_NOT_FOUND',
|
||||
TOURNAMENT_NO_DATE: 'ERROR_TOURNAMENT_NO_DATE',
|
||||
TOURNAMENT_CLASS_NAME_REQUIRED: 'ERROR_TOURNAMENT_CLASS_NAME_REQUIRED',
|
||||
TOURNAMENT_NO_PARTICIPANTS: 'ERROR_TOURNAMENT_NO_PARTICIPANTS',
|
||||
TOURNAMENT_NO_VALID_PARTICIPANTS: 'ERROR_TOURNAMENT_NO_VALID_PARTICIPANTS',
|
||||
TOURNAMENT_NO_TRAINING_DAY: 'ERROR_TOURNAMENT_NO_TRAINING_DAY',
|
||||
TOURNAMENT_PDF_GENERATION_FAILED: 'ERROR_TOURNAMENT_PDF_GENERATION_FAILED',
|
||||
TOURNAMENT_SELECT_FIRST: 'ERROR_TOURNAMENT_SELECT_FIRST',
|
||||
|
||||
// Trainingstagebuch
|
||||
DIARY_DATE_NOT_FOUND: 'ERROR_DIARY_DATE_NOT_FOUND',
|
||||
DIARY_DATE_UPDATED: 'ERROR_DIARY_DATE_UPDATED',
|
||||
DIARY_NO_PARTICIPANTS: 'ERROR_DIARY_NO_PARTICIPANTS',
|
||||
DIARY_PDF_GENERATION_FAILED: 'ERROR_DIARY_PDF_GENERATION_FAILED',
|
||||
DIARY_IMAGE_LOAD_FAILED: 'ERROR_DIARY_IMAGE_LOAD_FAILED',
|
||||
DIARY_STATS_LOAD_FAILED: 'ERROR_DIARY_STATS_LOAD_FAILED',
|
||||
DIARY_NO_EXERCISE_DATA: 'ERROR_DIARY_NO_EXERCISE_DATA',
|
||||
DIARY_ACTIVITY_PARTICIPANTS_UPDATE_FAILED: 'ERROR_DIARY_ACTIVITY_PARTICIPANTS_UPDATE_FAILED',
|
||||
DIARY_GROUP_ASSIGNMENT_UPDATED: 'SUCCESS_DIARY_GROUP_ASSIGNMENT_UPDATED',
|
||||
DIARY_GROUP_ASSIGNMENT_UPDATE_FAILED: 'ERROR_DIARY_GROUP_ASSIGNMENT_UPDATE_FAILED',
|
||||
DIARY_ASSIGN_ALL_PARTICIPANTS_FAILED: 'ERROR_DIARY_ASSIGN_ALL_PARTICIPANTS_FAILED',
|
||||
DIARY_ASSIGN_GROUP_FAILED: 'ERROR_DIARY_ASSIGN_GROUP_FAILED',
|
||||
DIARY_PARTICIPANT_ASSIGN_FAILED: 'ERROR_DIARY_PARTICIPANT_ASSIGN_FAILED',
|
||||
DIARY_PARTICIPANT_GROUP_ASSIGNMENT_UPDATE_FAILED: 'ERROR_DIARY_PARTICIPANT_GROUP_ASSIGNMENT_UPDATE_FAILED',
|
||||
DIARY_MEMBER_CREATED: 'SUCCESS_DIARY_MEMBER_CREATED',
|
||||
DIARY_MEMBER_CREATE_FAILED: 'ERROR_DIARY_MEMBER_CREATE_FAILED',
|
||||
|
||||
// Team Management
|
||||
TEAM_NOT_LINKED_TO_LEAGUE: 'ERROR_TEAM_NOT_LINKED_TO_LEAGUE',
|
||||
TEAM_LINK_TO_LEAGUE_REQUIRED: 'ERROR_TEAM_LINK_TO_LEAGUE_REQUIRED',
|
||||
TEAM_PDF_LOAD_FAILED: 'ERROR_TEAM_PDF_LOAD_FAILED',
|
||||
TEAM_STATS_LOAD_FAILED: 'ERROR_TEAM_STATS_LOAD_FAILED',
|
||||
|
||||
// Aktivitäten
|
||||
ACTIVITY_IMAGE_DELETE_FAILED: 'ERROR_ACTIVITY_IMAGE_DELETE_FAILED',
|
||||
|
||||
// Offizielle Turniere
|
||||
OFFICIAL_TOURNAMENT_PDF_UPLOAD_SUCCESS: 'SUCCESS_OFFICIAL_TOURNAMENT_PDF_UPLOAD',
|
||||
OFFICIAL_TOURNAMENT_PDF_UPLOAD_FAILED: 'ERROR_OFFICIAL_TOURNAMENT_PDF_UPLOAD',
|
||||
|
||||
// Vereine
|
||||
CLUB_NOT_FOUND: 'ERROR_CLUB_NOT_FOUND',
|
||||
CLUB_ALREADY_EXISTS: 'ERROR_CLUB_ALREADY_EXISTS',
|
||||
CLUB_NAME_REQUIRED: 'ERROR_CLUB_NAME_REQUIRED',
|
||||
CLUB_NAME_TOO_SHORT: 'ERROR_CLUB_NAME_TOO_SHORT',
|
||||
|
||||
// Mitglieder-Übertragung
|
||||
MEMBER_TRANSFER_BULK_FAILED: 'ERROR_MEMBER_TRANSFER_BULK_FAILED',
|
||||
|
||||
// Training
|
||||
TRAINING_STATS_LOAD_FAILED: 'ERROR_TRAINING_STATS_LOAD_FAILED',
|
||||
|
||||
// Logs
|
||||
LOG_NOT_FOUND: 'ERROR_LOG_NOT_FOUND',
|
||||
};
|
||||
|
||||
/**
|
||||
* Erstellt ein Fehler-Objekt mit Code und optionalen Parametern
|
||||
* @param {string} code - Fehlercode aus ERROR_CODES
|
||||
* @param {object} params - Optionale Parameter für die Fehlermeldung
|
||||
* @returns {object} Fehler-Objekt mit code und params
|
||||
*/
|
||||
export function createError(code, params = null) {
|
||||
return {
|
||||
code,
|
||||
...(params && { params })
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user