fix(matchService): handle missing match after update with HttpError

- Added error handling in MatchService to throw an HttpError if a match is not found after an update, improving robustness.
- Enhanced sorting logic in DiaryView to ensure case-insensitive comparison for first and last names, with a stable fallback using IDs.
- Refactored currentClub watcher in ScheduleView to use an object syntax for better clarity and immediate execution on initialization.
This commit is contained in:
Torsten Schulz (local)
2026-02-27 12:00:23 +01:00
parent b3bbca3887
commit b2017b7365
3 changed files with 41 additions and 19 deletions

View File

@@ -12,6 +12,7 @@ import Club from '../models/Club.js';
import SeasonService from './seasonService.js';
import { checkAccess } from '../utils/userUtils.js';
import { Op } from 'sequelize';
import HttpError from '../exceptions/HttpError.js';
import { devLog } from '../utils/logger.js';
class MatchService {
@@ -470,6 +471,9 @@ class MatchService {
// Aktualisiertes Match nochmals laden und für WebSocket-Broadcast anreichern (gleiche Struktur wie getMatchesForLeague)
const updated = await Match.findByPk(matchId);
if (!updated) {
throw new HttpError('Match not found after update', 404);
}
const enriched = {
id: updated.id,
date: updated.date,

View File

@@ -2068,12 +2068,34 @@ export default {
},
sortedMembers() {
// Erstelle eine Kopie des Arrays, um Mutation zu vermeiden
// Sortierung: zuerst nach Vorname, dann nach Nachname (beides case-insensitive, deutsch)
// Fallback: ID, damit die Reihenfolge bei komplett gleichen Namen stabil ist
const locale = 'de-DE';
const options = { sensitivity: 'base' };
const safe = (value) => (value ?? '').toString().trim();
return [...this.members].sort((a, b) => {
const firstNameComparison = a.firstName.localeCompare(b.firstName);
if (firstNameComparison === 0) {
return a.lastName.localeCompare(b.lastName);
const firstNameA = safe(a.firstName);
const firstNameB = safe(b.firstName);
const firstNameComparison = firstNameA.localeCompare(firstNameB, locale, options);
if (firstNameComparison !== 0) {
return firstNameComparison;
}
return firstNameComparison;
const lastNameA = safe(a.lastName);
const lastNameB = safe(b.lastName);
const lastNameComparison = lastNameA.localeCompare(lastNameB, locale, options);
if (lastNameComparison !== 0) {
return lastNameComparison;
}
// Stabiler Fallback, falls sowohl Vor- als auch Nachname identisch sind
const idA = Number.isFinite(a.id) ? a.id : parseInt(a.id, 10) || 0;
const idB = Number.isFinite(b.id) ? b.id : parseInt(b.id, 10) || 0;
return idA - idB;
});
},
async showPic(member) {

View File

@@ -325,14 +325,17 @@ export default {
...mapGetters(['isAuthenticated', 'currentClub', 'clubs', 'currentClubName']),
},
watch: {
currentClub(newVal) {
offScheduleMatchUpdated(this.handleScheduleMatchUpdated);
offMatchReportSubmitted(this.handleMatchReportSubmitted);
disconnectSocket();
if (newVal) {
connectSocket(newVal);
onScheduleMatchUpdated(this.handleScheduleMatchUpdated);
onMatchReportSubmitted(this.handleMatchReportSubmitted);
currentClub: {
immediate: true,
handler(newVal) {
offScheduleMatchUpdated(this.handleScheduleMatchUpdated);
offMatchReportSubmitted(this.handleMatchReportSubmitted);
disconnectSocket();
if (newVal) {
connectSocket(newVal);
onScheduleMatchUpdated(this.handleScheduleMatchUpdated);
onMatchReportSubmitted(this.handleMatchReportSubmitted);
}
}
},
},
@@ -1084,13 +1087,6 @@ export default {
// und ruft anschließend onSeasonChange auf, was loadTeams() ausführt
this.loadTeams();
},
mounted() {
if (this.currentClub) {
connectSocket(this.currentClub);
onScheduleMatchUpdated(this.handleScheduleMatchUpdated);
onMatchReportSubmitted(this.handleMatchReportSubmitted);
}
},
beforeUnmount() {
offScheduleMatchUpdated(this.handleScheduleMatchUpdated);
offMatchReportSubmitted(this.handleMatchReportSubmitted);