feat(TrainingCancellation): enhance cancellation functionality and localization support
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 44s
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 44s
- Updated the training cancellation controller to accept training group IDs, improving the cancellation process. - Modified the database schema to include a JSON field for training group IDs in the training cancellations table. - Enhanced the TrainingCancellation model to support the new training group IDs field. - Updated the training cancellation service to normalize and handle training group IDs effectively. - Added localization support for training cancellation features across multiple languages, improving user experience.
This commit is contained in:
@@ -62,6 +62,106 @@
|
||||
"ok": "OK",
|
||||
"saving": "Speichere..."
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Vereinskalender",
|
||||
"title": "Kalender",
|
||||
"description": "Trainingstage, Vereinsturniere und Punktspiele in einer Monatsansicht.",
|
||||
"today": "Heute",
|
||||
"loading": "Kalenderdaten werden geladen...",
|
||||
"noClub": "Bitte zuerst einen Verein auswählen.",
|
||||
"loadError": "Kalenderdaten konnten nicht geladen werden.",
|
||||
"sourceWarning": "{source} konnte nicht geladen werden",
|
||||
"agendaTitle": "Termine im Monat",
|
||||
"agendaEmpty": "Keine Termine in diesem Monat.",
|
||||
"recurringTrainingTime": "Regelmäßige Trainingszeit",
|
||||
"participants": "{count} Teilnehmer",
|
||||
"starts": "{count} Starts",
|
||||
"options": {
|
||||
"title": "Optionen",
|
||||
"subtitle": "Ausfälle & eigene Termine"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Turnier",
|
||||
"officialTournament": "Teilnahme",
|
||||
"match": "Punktspiel",
|
||||
"holiday": "Feiertag",
|
||||
"schoolHoliday": "Ferien",
|
||||
"trainingCancellation": "Ausfall",
|
||||
"customEvent": "Termin"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training fällt aus",
|
||||
"description": "Blendet regelmäßige Trainingszeiten aus.",
|
||||
"date": "Datum",
|
||||
"untilOptional": "Bis optional",
|
||||
"trainingGroups": "Trainingsgruppen",
|
||||
"reasonPlaceholder": "Grund (optional)",
|
||||
"saving": "Speichern...",
|
||||
"submit": "Eintragen",
|
||||
"fallbackTitle": "Training fällt aus",
|
||||
"subtitle": "Trainingsausfall"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Eigene Termine",
|
||||
"description": "Kreistage, Sitzungen, interne Meetings, ...",
|
||||
"titlePlaceholder": "Titel",
|
||||
"categoryPlaceholder": "Kategorie (optional)",
|
||||
"saving": "Speichern...",
|
||||
"submit": "Anlegen",
|
||||
"subtitleFallback": "Eigener Termin"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Trainingsausfall",
|
||||
"message": "„{title}“ als Trainingsausfall markieren?",
|
||||
"useWholeRange": "Für den gesamten Zeitraum ({start} bis {end}) eintragen",
|
||||
"trainingGroups": "Betroffene Trainingsgruppen",
|
||||
"confirm": "Ausfall eintragen",
|
||||
"noGroups": "Es sind keine Trainingsgruppen mit Trainingszeiten vorhanden."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Trainingstage",
|
||||
"trainingTimes": "Trainingszeiten",
|
||||
"trainingCancellations": "Trainingsausfälle",
|
||||
"customEvents": "Eigene Termine",
|
||||
"tournaments": "Turniere",
|
||||
"officialTournaments": "Turnierteilnahmen",
|
||||
"matches": "Punktspiele",
|
||||
"holidays": "Ferien/Feiertage"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Turnier",
|
||||
"officialTournament": "Turnierteilnahme",
|
||||
"match": "Punktspiel"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Offenes Turnier",
|
||||
"club": "Vereinsturnier"
|
||||
},
|
||||
"match": {
|
||||
"home": "Heim",
|
||||
"guest": "Gast"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Feiertag",
|
||||
"schoolHoliday": "Schulferien"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Mo",
|
||||
"tuesday": "Di",
|
||||
"wednesday": "Mi",
|
||||
"thursday": "Do",
|
||||
"friday": "Fr",
|
||||
"saturday": "Sa",
|
||||
"sunday": "So"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Trainingsausfall stornieren",
|
||||
"message": "Trainingsausfall „{title}“ am {date} wirklich stornieren?",
|
||||
"confirm": "Ausfall stornieren"
|
||||
}
|
||||
},
|
||||
"unknown": "Unbekannt",
|
||||
"navigation": {
|
||||
"home": "Startseite",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"period": "Zeitraum",
|
||||
"saving": "Speichere..."
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Vereinskalender",
|
||||
"title": "Kalender",
|
||||
"description": "Trainingstage, Vereinsturniere und Punktspiele in einer Monatsansicht.",
|
||||
"today": "Heute",
|
||||
"loading": "Kalenderdaten werden geladen...",
|
||||
"noClub": "Bitte zuerst einen Verein auswählen.",
|
||||
"loadError": "Kalenderdaten konnten nicht geladen werden.",
|
||||
"sourceWarning": "{source} konnte nicht geladen werden",
|
||||
"agendaTitle": "Termine im Monat",
|
||||
"agendaEmpty": "Keine Termine in diesem Monat.",
|
||||
"recurringTrainingTime": "Regelmäßige Trainingszeit",
|
||||
"participants": "{count} Teilnehmer",
|
||||
"starts": "{count} Starts",
|
||||
"options": {
|
||||
"title": "Optionen",
|
||||
"subtitle": "Ausfälle & eigene Termine"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Turnier",
|
||||
"officialTournament": "Teilnahme",
|
||||
"match": "Punktspiel",
|
||||
"holiday": "Feiertag",
|
||||
"schoolHoliday": "Ferien",
|
||||
"trainingCancellation": "Ausfall",
|
||||
"customEvent": "Termin"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training fällt aus",
|
||||
"description": "Blendet regelmäßige Trainingszeiten aus.",
|
||||
"date": "Datum",
|
||||
"untilOptional": "Bis optional",
|
||||
"trainingGroups": "Trainingsgruppen",
|
||||
"reasonPlaceholder": "Grund (optional)",
|
||||
"saving": "Speichern...",
|
||||
"submit": "Eintragen",
|
||||
"fallbackTitle": "Training fällt aus",
|
||||
"subtitle": "Trainingsausfall"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Eigene Termine",
|
||||
"description": "Kreistage, Sitzungen, interne Meetings, ...",
|
||||
"titlePlaceholder": "Titel",
|
||||
"categoryPlaceholder": "Kategorie (optional)",
|
||||
"saving": "Speichern...",
|
||||
"submit": "Anlegen",
|
||||
"subtitleFallback": "Eigener Termin"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Trainingsausfall",
|
||||
"message": "„{title}“ als Trainingsausfall markieren?",
|
||||
"useWholeRange": "Für den gesamten Zeitraum ({start} bis {end}) eintragen",
|
||||
"trainingGroups": "Betroffene Trainingsgruppen",
|
||||
"confirm": "Ausfall eintragen",
|
||||
"noGroups": "Es sind keine Trainingsgruppen mit Trainingszeiten vorhanden."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Trainingstage",
|
||||
"trainingTimes": "Trainingszeiten",
|
||||
"trainingCancellations": "Trainingsausfälle",
|
||||
"customEvents": "Eigene Termine",
|
||||
"tournaments": "Turniere",
|
||||
"officialTournaments": "Turnierteilnahmen",
|
||||
"matches": "Punktspiele",
|
||||
"holidays": "Ferien/Feiertage"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Turnier",
|
||||
"officialTournament": "Turnierteilnahme",
|
||||
"match": "Punktspiel"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Offenes Turnier",
|
||||
"club": "Vereinsturnier"
|
||||
},
|
||||
"match": {
|
||||
"home": "Heim",
|
||||
"guest": "Gast"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Feiertag",
|
||||
"schoolHoliday": "Schulferien"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Mo",
|
||||
"tuesday": "Di",
|
||||
"wednesday": "Mi",
|
||||
"thursday": "Do",
|
||||
"friday": "Fr",
|
||||
"saturday": "Sa",
|
||||
"sunday": "So"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Trainingsausfall stornieren",
|
||||
"message": "Trainingsausfall „{title}“ am {date} wirklich stornieren?",
|
||||
"confirm": "Ausfall stornieren"
|
||||
}
|
||||
},
|
||||
"unknown": "Unbekannt",
|
||||
"navigation": {
|
||||
"home": "Startseite",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"period": "Zeitraum",
|
||||
"saving": "Speichere..."
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Vereinskalender",
|
||||
"title": "Kalender",
|
||||
"description": "Trainingstage, Vereinsturniere und Punktspiele in einer Monatsansicht.",
|
||||
"today": "Heute",
|
||||
"loading": "Kalenderdaten werden geladen...",
|
||||
"noClub": "Bitte zuerst einen Verein auswählen.",
|
||||
"loadError": "Kalenderdaten konnten nicht geladen werden.",
|
||||
"sourceWarning": "{source} konnte nicht geladen werden",
|
||||
"agendaTitle": "Termine im Monat",
|
||||
"agendaEmpty": "Keine Termine in diesem Monat.",
|
||||
"recurringTrainingTime": "Regelmäßige Trainingszeit",
|
||||
"participants": "{count} Teilnehmer",
|
||||
"starts": "{count} Starts",
|
||||
"options": {
|
||||
"title": "Optionen",
|
||||
"subtitle": "Ausfälle & eigene Termine"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Turnier",
|
||||
"officialTournament": "Teilnahme",
|
||||
"match": "Punktspiel",
|
||||
"holiday": "Feiertag",
|
||||
"schoolHoliday": "Ferien",
|
||||
"trainingCancellation": "Ausfall",
|
||||
"customEvent": "Termin"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training fällt aus",
|
||||
"description": "Blendet regelmäßige Trainingszeiten aus.",
|
||||
"date": "Datum",
|
||||
"untilOptional": "Bis optional",
|
||||
"trainingGroups": "Trainingsgruppen",
|
||||
"reasonPlaceholder": "Grund (optional)",
|
||||
"saving": "Speichern...",
|
||||
"submit": "Eintragen",
|
||||
"fallbackTitle": "Training fällt aus",
|
||||
"subtitle": "Trainingsausfall"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Eigene Termine",
|
||||
"description": "Kreistage, Sitzungen, interne Meetings, ...",
|
||||
"titlePlaceholder": "Titel",
|
||||
"categoryPlaceholder": "Kategorie (optional)",
|
||||
"saving": "Speichern...",
|
||||
"submit": "Anlegen",
|
||||
"subtitleFallback": "Eigener Termin"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Trainingsausfall",
|
||||
"message": "„{title}“ als Trainingsausfall markieren?",
|
||||
"useWholeRange": "Für den gesamten Zeitraum ({start} bis {end}) eintragen",
|
||||
"trainingGroups": "Betroffene Trainingsgruppen",
|
||||
"confirm": "Ausfall eintragen",
|
||||
"noGroups": "Es sind keine Trainingsgruppen mit Trainingszeiten vorhanden."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Trainingstage",
|
||||
"trainingTimes": "Trainingszeiten",
|
||||
"trainingCancellations": "Trainingsausfälle",
|
||||
"customEvents": "Eigene Termine",
|
||||
"tournaments": "Turniere",
|
||||
"officialTournaments": "Turnierteilnahmen",
|
||||
"matches": "Punktspiele",
|
||||
"holidays": "Ferien/Feiertage"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Turnier",
|
||||
"officialTournament": "Turnierteilnahme",
|
||||
"match": "Punktspiel"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Offenes Turnier",
|
||||
"club": "Vereinsturnier"
|
||||
},
|
||||
"match": {
|
||||
"home": "Heim",
|
||||
"guest": "Gast"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Feiertag",
|
||||
"schoolHoliday": "Schulferien"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Mo",
|
||||
"tuesday": "Di",
|
||||
"wednesday": "Mi",
|
||||
"thursday": "Do",
|
||||
"friday": "Fr",
|
||||
"saturday": "Sa",
|
||||
"sunday": "So"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Trainingsausfall stornieren",
|
||||
"message": "Trainingsausfall „{title}“ am {date} wirklich stornieren?",
|
||||
"confirm": "Ausfall stornieren"
|
||||
}
|
||||
},
|
||||
"unknown": "Unbekannt",
|
||||
"navigation": {
|
||||
"home": "Startseite",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"years": "years",
|
||||
"ok": "OK"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Club calendar",
|
||||
"title": "Calendar",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "Today",
|
||||
"loading": "Loading calendar data...",
|
||||
"noClub": "Please select a club first.",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "Events this month",
|
||||
"agendaEmpty": "No events this month.",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Mon",
|
||||
"tuesday": "Tue",
|
||||
"wednesday": "Wed",
|
||||
"thursday": "Thu",
|
||||
"friday": "Fri",
|
||||
"saturday": "Sat",
|
||||
"sunday": "Sun"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Cancel training cancellation",
|
||||
"message": "Really cancel the training cancellation “{title}” on {date}?",
|
||||
"confirm": "Cancel cancellation"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"members": "Members",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"years": "years",
|
||||
"ok": "OK"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Club calendar",
|
||||
"title": "Calendar",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "Today",
|
||||
"loading": "Loading calendar data...",
|
||||
"noClub": "Please select a club first.",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "Events this month",
|
||||
"agendaEmpty": "No events this month.",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Mon",
|
||||
"tuesday": "Tue",
|
||||
"wednesday": "Wed",
|
||||
"thursday": "Thu",
|
||||
"friday": "Fri",
|
||||
"saturday": "Sat",
|
||||
"sunday": "Sun"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Cancel training cancellation",
|
||||
"message": "Really cancel the training cancellation “{title}” on {date}?",
|
||||
"confirm": "Cancel cancellation"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"members": "Members",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"years": "years",
|
||||
"ok": "OK"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Club calendar",
|
||||
"title": "Calendar",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "Today",
|
||||
"loading": "Loading calendar data...",
|
||||
"noClub": "Please select a club first.",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "Events this month",
|
||||
"agendaEmpty": "No events this month.",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Mon",
|
||||
"tuesday": "Tue",
|
||||
"wednesday": "Wed",
|
||||
"thursday": "Thu",
|
||||
"friday": "Fri",
|
||||
"saturday": "Sat",
|
||||
"sunday": "Sun"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Cancel training cancellation",
|
||||
"message": "Really cancel the training cancellation “{title}” on {date}?",
|
||||
"confirm": "Cancel cancellation"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"members": "Members",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"ok": "OK",
|
||||
"period": "Periodo"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Calendario del club",
|
||||
"title": "Calendario",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "Hoy",
|
||||
"loading": "Cargando datos del calendario...",
|
||||
"noClub": "Seleccione primero un club.",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "Eventos del mes",
|
||||
"agendaEmpty": "No hay eventos este mes.",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Lun",
|
||||
"tuesday": "Mar",
|
||||
"wednesday": "Mié",
|
||||
"thursday": "Jue",
|
||||
"friday": "Vie",
|
||||
"saturday": "Sáb",
|
||||
"sunday": "Dom"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Cancelar ausencia de entrenamiento",
|
||||
"message": "¿Cancelar realmente la ausencia “{title}” el {date}?",
|
||||
"confirm": "Cancelar ausencia"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Inicio",
|
||||
"members": "Miembros",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"ok": "OK",
|
||||
"period": "Panahon"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Kalendaryo ng club",
|
||||
"title": "Kalendaryo",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "Ngayon",
|
||||
"loading": "Nilo-load ang datos ng kalendaryo...",
|
||||
"noClub": "Pumili muna ng club.",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "Mga event ngayong buwan",
|
||||
"agendaEmpty": "Walang event ngayong buwan.",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Lun",
|
||||
"tuesday": "Mar",
|
||||
"wednesday": "Miy",
|
||||
"thursday": "Huw",
|
||||
"friday": "Biy",
|
||||
"saturday": "Sab",
|
||||
"sunday": "Lin"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Bawiin ang pagkansela ng training",
|
||||
"message": "Bawiin talaga ang pagkansela ng training “{title}” sa {date}?",
|
||||
"confirm": "Bawiin ang pagkansela"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"members": "Mga miyembro",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"ok": "OK",
|
||||
"period": "Période"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Calendrier du club",
|
||||
"title": "Calendrier",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "Aujourd’hui",
|
||||
"loading": "Chargement des données du calendrier...",
|
||||
"noClub": "Veuillez d’abord sélectionner un club.",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "Événements du mois",
|
||||
"agendaEmpty": "Aucun événement ce mois-ci.",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Lun",
|
||||
"tuesday": "Mar",
|
||||
"wednesday": "Mer",
|
||||
"thursday": "Jeu",
|
||||
"friday": "Ven",
|
||||
"saturday": "Sam",
|
||||
"sunday": "Dim"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Annuler l’annulation de l’entraînement",
|
||||
"message": "Vraiment annuler l’annulation « {title} » le {date} ?",
|
||||
"confirm": "Annuler l’annulation"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Accueil",
|
||||
"members": "Membres",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"ok": "OK",
|
||||
"period": "Periodo"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Calendario del club",
|
||||
"title": "Calendario",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "Oggi",
|
||||
"loading": "Caricamento dati calendario...",
|
||||
"noClub": "Seleziona prima un club.",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "Eventi del mese",
|
||||
"agendaEmpty": "Nessun evento questo mese.",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Lun",
|
||||
"tuesday": "Mar",
|
||||
"wednesday": "Mer",
|
||||
"thursday": "Gio",
|
||||
"friday": "Ven",
|
||||
"saturday": "Sab",
|
||||
"sunday": "Dom"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Annulla cancellazione allenamento",
|
||||
"message": "Annullare davvero la cancellazione “{title}” del {date}?",
|
||||
"confirm": "Annulla cancellazione"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"members": "Membri",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"ok": "OK",
|
||||
"period": "期間"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "クラブカレンダー",
|
||||
"title": "カレンダー",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "今日",
|
||||
"loading": "カレンダーデータを読み込んでいます...",
|
||||
"noClub": "最初にクラブを選択してください。",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "今月の予定",
|
||||
"agendaEmpty": "今月の予定はありません。",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "月",
|
||||
"tuesday": "火",
|
||||
"wednesday": "水",
|
||||
"thursday": "木",
|
||||
"friday": "金",
|
||||
"saturday": "土",
|
||||
"sunday": "日"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "練習中止を取り消す",
|
||||
"message": "{date} の「{title}」の練習中止を本当に取り消しますか?",
|
||||
"confirm": "中止を取り消す"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "ホーム",
|
||||
"members": "メンバー",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"ok": "OK",
|
||||
"period": "Okres"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Kalendarz klubu",
|
||||
"title": "Kalendarz",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "Dzisiaj",
|
||||
"loading": "Ładowanie danych kalendarza...",
|
||||
"noClub": "Najpierw wybierz klub.",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "Wydarzenia w tym miesiącu",
|
||||
"agendaEmpty": "Brak wydarzeń w tym miesiącu.",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Pon",
|
||||
"tuesday": "Wt",
|
||||
"wednesday": "Śr",
|
||||
"thursday": "Czw",
|
||||
"friday": "Pt",
|
||||
"saturday": "Sob",
|
||||
"sunday": "Nd"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Cofnij odwołanie treningu",
|
||||
"message": "Na pewno cofnąć odwołanie „{title}” w dniu {date}?",
|
||||
"confirm": "Cofnij odwołanie"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Strona główna",
|
||||
"members": "Członkowie",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"ok": "ตกลง",
|
||||
"period": "ช่วงเวลา"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "ปฏิทินสโมสร",
|
||||
"title": "ปฏิทิน",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "วันนี้",
|
||||
"loading": "กำลังโหลดข้อมูลปฏิทิน...",
|
||||
"noClub": "โปรดเลือกสโมสรก่อน",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "กิจกรรมในเดือนนี้",
|
||||
"agendaEmpty": "ไม่มีกิจกรรมในเดือนนี้",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "จ.",
|
||||
"tuesday": "อ.",
|
||||
"wednesday": "พ.",
|
||||
"thursday": "พฤ.",
|
||||
"friday": "ศ.",
|
||||
"saturday": "ส.",
|
||||
"sunday": "อา."
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "ยกเลิกการงดซ้อม",
|
||||
"message": "ต้องการยกเลิกการงดซ้อม “{title}” วันที่ {date} หรือไม่?",
|
||||
"confirm": "ยกเลิกการงดซ้อม"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "หน้าแรก",
|
||||
"members": "สมาชิก",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"ok": "OK",
|
||||
"period": "Panahon"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "Kalendaryo ng club",
|
||||
"title": "Kalendaryo",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "Ngayon",
|
||||
"loading": "Nilo-load ang datos ng kalendaryo...",
|
||||
"noClub": "Pumili muna ng club.",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "Mga event ngayong buwan",
|
||||
"agendaEmpty": "Walang event ngayong buwan.",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "Lun",
|
||||
"tuesday": "Mar",
|
||||
"wednesday": "Miy",
|
||||
"thursday": "Huw",
|
||||
"friday": "Biy",
|
||||
"saturday": "Sab",
|
||||
"sunday": "Lin"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "Bawiin ang pagkansela ng training",
|
||||
"message": "Bawiin talaga ang pagkansela ng training “{title}” sa {date}?",
|
||||
"confirm": "Bawiin ang pagkansela"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "Home",
|
||||
"members": "Mga miyembro",
|
||||
|
||||
@@ -62,6 +62,106 @@
|
||||
"ok": "确定",
|
||||
"period": "期间"
|
||||
},
|
||||
"calendar": {
|
||||
"eyebrow": "俱乐部日历",
|
||||
"title": "日历",
|
||||
"description": "Training days, club tournaments and league matches in a monthly view.",
|
||||
"today": "今天",
|
||||
"loading": "正在加载日历数据...",
|
||||
"noClub": "请先选择俱乐部。",
|
||||
"loadError": "Calendar data could not be loaded.",
|
||||
"sourceWarning": "{source} could not be loaded",
|
||||
"agendaTitle": "本月活动",
|
||||
"agendaEmpty": "本月没有活动。",
|
||||
"recurringTrainingTime": "Regular training time",
|
||||
"participants": "{count} participants",
|
||||
"starts": "{count} starts",
|
||||
"options": {
|
||||
"title": "Options",
|
||||
"subtitle": "Cancellations & own events"
|
||||
},
|
||||
"legend": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Participation",
|
||||
"match": "League match",
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays",
|
||||
"trainingCancellation": "Cancelled",
|
||||
"customEvent": "Event"
|
||||
},
|
||||
"cancellation": {
|
||||
"title": "Training cancelled",
|
||||
"description": "Hides regular training times.",
|
||||
"date": "Date",
|
||||
"untilOptional": "Until optional",
|
||||
"trainingGroups": "Training groups",
|
||||
"reasonPlaceholder": "Reason (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Add",
|
||||
"fallbackTitle": "Training cancelled",
|
||||
"subtitle": "Training cancellation"
|
||||
},
|
||||
"customEvent": {
|
||||
"title": "Own events",
|
||||
"description": "District meetings, sessions, internal meetings, ...",
|
||||
"titlePlaceholder": "Title",
|
||||
"categoryPlaceholder": "Category (optional)",
|
||||
"saving": "Saving...",
|
||||
"submit": "Create",
|
||||
"subtitleFallback": "Own event"
|
||||
},
|
||||
"quickCancellation": {
|
||||
"title": "Training cancellation",
|
||||
"message": "Mark “{title}” as training cancellation?",
|
||||
"useWholeRange": "Apply to the full period ({start} to {end})",
|
||||
"trainingGroups": "Affected training groups",
|
||||
"confirm": "Add cancellation",
|
||||
"noGroups": "No training groups with training times are available."
|
||||
},
|
||||
"sources": {
|
||||
"trainingDays": "Training days",
|
||||
"trainingTimes": "Training times",
|
||||
"trainingCancellations": "Training cancellations",
|
||||
"customEvents": "Own events",
|
||||
"tournaments": "Tournaments",
|
||||
"officialTournaments": "Tournament participations",
|
||||
"matches": "League matches",
|
||||
"holidays": "Holidays/school holidays"
|
||||
},
|
||||
"eventTitles": {
|
||||
"training": "Training",
|
||||
"tournament": "Tournament",
|
||||
"officialTournament": "Tournament participation",
|
||||
"match": "League match"
|
||||
},
|
||||
"tournament": {
|
||||
"open": "Open tournament",
|
||||
"club": "Club tournament"
|
||||
},
|
||||
"match": {
|
||||
"home": "Home",
|
||||
"guest": "Away"
|
||||
},
|
||||
"holidayTypes": {
|
||||
"holiday": "Holiday",
|
||||
"schoolHoliday": "School holidays"
|
||||
},
|
||||
"weekdays": {
|
||||
"monday": "周一",
|
||||
"tuesday": "周二",
|
||||
"wednesday": "周三",
|
||||
"thursday": "周四",
|
||||
"friday": "周五",
|
||||
"saturday": "周六",
|
||||
"sunday": "周日"
|
||||
},
|
||||
"cancelCancellation": {
|
||||
"title": "取消训练停课",
|
||||
"message": "确定要取消 {date} 的“{title}”训练停课吗?",
|
||||
"confirm": "取消停课"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"home": "首页",
|
||||
"members": "成员",
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<div class="calendar-page">
|
||||
<header class="calendar-header">
|
||||
<div>
|
||||
<span class="calendar-eyebrow">Vereinskalender</span>
|
||||
<h2>Kalender</h2>
|
||||
<p>Trainingstage, Vereinsturniere und Punktspiele in einer Monatsansicht.</p>
|
||||
<span class="calendar-eyebrow">{{ $t('calendar.eyebrow') }}</span>
|
||||
<h2>{{ $t('calendar.title') }}</h2>
|
||||
<p>{{ $t('calendar.description') }}</p>
|
||||
</div>
|
||||
<div class="calendar-actions">
|
||||
<button type="button" class="calendar-nav-button" @click="goToPreviousMonth">‹</button>
|
||||
<button type="button" class="calendar-today-button" @click="goToToday">Heute</button>
|
||||
<button type="button" class="calendar-today-button" @click="goToToday">{{ $t('calendar.today') }}</button>
|
||||
<button type="button" class="calendar-nav-button" @click="goToNextMonth">›</button>
|
||||
</div>
|
||||
</header>
|
||||
@@ -31,27 +31,39 @@
|
||||
|
||||
<details v-if="currentClub" class="calendar-options" :open="optionsOpen">
|
||||
<summary class="calendar-options-summary" @click.prevent="optionsOpen = !optionsOpen">
|
||||
<span>Optionen</span>
|
||||
<small>Ausfälle & eigene Termine</small>
|
||||
<span>{{ $t('calendar.options.title') }}</span>
|
||||
<small>{{ $t('calendar.options.subtitle') }}</small>
|
||||
</summary>
|
||||
<div class="calendar-options-body">
|
||||
<section class="training-cancellation-panel">
|
||||
<div>
|
||||
<h3>Training fällt aus</h3>
|
||||
<p>Blendet regelmäßige Trainingszeiten aus.</p>
|
||||
<h3>{{ $t('calendar.cancellation.title') }}</h3>
|
||||
<p>{{ $t('calendar.cancellation.description') }}</p>
|
||||
</div>
|
||||
<form class="training-cancellation-form" @submit.prevent="saveTrainingCancellation">
|
||||
<label>
|
||||
<span>Datum</span>
|
||||
<span>{{ $t('calendar.cancellation.date') }}</span>
|
||||
<input v-model="cancellationForm.startDate" type="date" required />
|
||||
</label>
|
||||
<label>
|
||||
<span>Bis optional</span>
|
||||
<span>{{ $t('calendar.cancellation.untilOptional') }}</span>
|
||||
<input v-model="cancellationForm.endDate" type="date" />
|
||||
</label>
|
||||
<input v-model="cancellationForm.reason" type="text" placeholder="Grund (optional)" />
|
||||
<label>
|
||||
<span>{{ $t('calendar.cancellation.trainingGroups') }}</span>
|
||||
<select v-model="cancellationForm.trainingGroupIds" multiple>
|
||||
<option
|
||||
v-for="group in trainingGroupsWithTimes"
|
||||
:key="`cancel-group-${group.id}`"
|
||||
:value="String(group.id)"
|
||||
>
|
||||
{{ group.name }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<input v-model="cancellationForm.reason" type="text" :placeholder="$t('calendar.cancellation.reasonPlaceholder')" />
|
||||
<button type="submit" :disabled="cancellationSaving">
|
||||
{{ cancellationSaving ? 'Speichern...' : 'Eintragen' }}
|
||||
{{ cancellationSaving ? $t('calendar.cancellation.saving') : $t('calendar.cancellation.submit') }}
|
||||
</button>
|
||||
</form>
|
||||
<div v-if="visibleTrainingCancellations.length" class="training-cancellation-list">
|
||||
@@ -60,28 +72,28 @@
|
||||
:key="`cancel-${cancellation.cancellationId}`"
|
||||
type="button"
|
||||
class="training-cancellation-item"
|
||||
@click="deleteTrainingCancellation(cancellation)"
|
||||
title="Löschen"
|
||||
@click="openTrainingCancellationDeleteDialog(cancellation)"
|
||||
:title="$t('common.delete')"
|
||||
>
|
||||
<strong>{{ formatShortDate(cancellation.date) }}</strong>
|
||||
<span>{{ cancellation.title }}</span>
|
||||
<small>Löschen</small>
|
||||
<small>{{ $t('common.delete') }}</small>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="custom-event-panel">
|
||||
<div>
|
||||
<h3>Eigene Termine</h3>
|
||||
<p>Kreistage, Sitzungen, interne Meetings, ...</p>
|
||||
<h3>{{ $t('calendar.customEvent.title') }}</h3>
|
||||
<p>{{ $t('calendar.customEvent.description') }}</p>
|
||||
</div>
|
||||
<form class="custom-event-form" @submit.prevent="saveCustomEvent">
|
||||
<input v-model="customEventForm.title" type="text" placeholder="Titel" required />
|
||||
<input v-model="customEventForm.title" type="text" :placeholder="$t('calendar.customEvent.titlePlaceholder')" required />
|
||||
<input v-model="customEventForm.startDate" type="date" required />
|
||||
<input v-model="customEventForm.endDate" type="date" />
|
||||
<input v-model="customEventForm.category" type="text" placeholder="Kategorie (optional)" />
|
||||
<input v-model="customEventForm.category" type="text" :placeholder="$t('calendar.customEvent.categoryPlaceholder')" />
|
||||
<button type="submit" :disabled="customEventSaving">
|
||||
{{ customEventSaving ? 'Speichern...' : 'Anlegen' }}
|
||||
{{ customEventSaving ? $t('calendar.customEvent.saving') : $t('calendar.customEvent.submit') }}
|
||||
</button>
|
||||
</form>
|
||||
<div v-if="visibleCustomEvents.length" class="custom-event-list">
|
||||
@@ -91,11 +103,11 @@
|
||||
type="button"
|
||||
class="custom-event-item"
|
||||
@click="deleteCustomEvent(event)"
|
||||
title="Löschen"
|
||||
:title="$t('common.delete')"
|
||||
>
|
||||
<strong>{{ formatEventDate(event) }}</strong>
|
||||
<span>{{ event.title }}</span>
|
||||
<small>Löschen</small>
|
||||
<small>{{ $t('common.delete') }}</small>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
@@ -105,12 +117,12 @@
|
||||
<section v-if="sourceWarnings.length" class="calendar-state calendar-state-warning">
|
||||
{{ sourceWarnings.join(' · ') }}
|
||||
</section>
|
||||
<section v-if="loading" class="calendar-state">Kalenderdaten werden geladen...</section>
|
||||
<section v-if="loading" class="calendar-state">{{ $t('calendar.loading') }}</section>
|
||||
<section v-else-if="error" class="calendar-state calendar-state-error">{{ error }}</section>
|
||||
|
||||
<section v-if="!currentClub" class="calendar-state">Bitte zuerst einen Verein auswählen.</section>
|
||||
<section v-if="!currentClub" class="calendar-state">{{ $t('calendar.noClub') }}</section>
|
||||
|
||||
<section v-else class="calendar-grid" aria-label="Kalender">
|
||||
<section v-else class="calendar-grid" :aria-label="$t('calendar.title')">
|
||||
<div v-for="day in weekdays" :key="day" class="calendar-weekday">{{ day }}</div>
|
||||
<article
|
||||
v-for="day in calendarDays"
|
||||
@@ -137,8 +149,8 @@
|
||||
</section>
|
||||
|
||||
<section class="calendar-agenda">
|
||||
<h3>Termine im Monat</h3>
|
||||
<p v-if="visibleEvents.length === 0" class="agenda-empty">Keine Termine in diesem Monat.</p>
|
||||
<h3>{{ $t('calendar.agendaTitle') }}</h3>
|
||||
<p v-if="visibleEvents.length === 0" class="agenda-empty">{{ $t('calendar.agendaEmpty') }}</p>
|
||||
<button
|
||||
v-for="event in visibleEvents"
|
||||
:key="`agenda-${event.id}`"
|
||||
@@ -156,32 +168,98 @@
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<ConfirmDialog
|
||||
v-model="confirmDialog.isOpen"
|
||||
:title="confirmDialog.title"
|
||||
:message="confirmDialog.message"
|
||||
:details="confirmDialog.details"
|
||||
:type="confirmDialog.type"
|
||||
:confirm-text="confirmDialog.confirmText"
|
||||
:cancel-text="confirmDialog.cancelText"
|
||||
:show-cancel="confirmDialog.showCancel"
|
||||
@confirm="handleConfirmResult(true)"
|
||||
@cancel="handleConfirmResult(false)"
|
||||
/>
|
||||
<BaseDialog
|
||||
v-model="quickCancellationDialog.isOpen"
|
||||
:title="$t('calendar.quickCancellation.title')"
|
||||
size="small"
|
||||
:close-on-overlay="false"
|
||||
@close="closeQuickCancellationDialog"
|
||||
>
|
||||
<div class="quick-cancellation-dialog">
|
||||
<p>
|
||||
{{ $t('calendar.quickCancellation.message', { title: quickCancellationDialog.eventTitle }) }}
|
||||
</p>
|
||||
<label v-if="quickCancellationDialog.isRange" class="quick-cancellation-checkbox">
|
||||
<input v-model="quickCancellationDialog.useRange" type="checkbox" />
|
||||
<span>
|
||||
{{ $t('calendar.quickCancellation.useWholeRange', {
|
||||
start: quickCancellationDialog.startDate,
|
||||
end: quickCancellationDialog.endDate
|
||||
}) }}
|
||||
</span>
|
||||
</label>
|
||||
<label class="quick-cancellation-groups">
|
||||
<span>{{ $t('calendar.quickCancellation.trainingGroups') }}</span>
|
||||
<select v-model="quickCancellationDialog.trainingGroupIds" multiple>
|
||||
<option
|
||||
v-for="group in trainingGroupsWithTimes"
|
||||
:key="`quick-cancel-group-${group.id}`"
|
||||
:value="String(group.id)"
|
||||
>
|
||||
{{ group.name }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<p v-if="!trainingGroupsWithTimes.length" class="quick-cancellation-hint">
|
||||
{{ $t('calendar.quickCancellation.noGroups') }}
|
||||
</p>
|
||||
</div>
|
||||
<template #footer>
|
||||
<button type="button" class="dialog-secondary-button" @click="closeQuickCancellationDialog">
|
||||
{{ $t('common.cancel') }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="dialog-primary-button"
|
||||
:disabled="quickCancellationDialog.trainingGroupIds.length === 0"
|
||||
@click="confirmQuickCancellation"
|
||||
>
|
||||
{{ $t('calendar.quickCancellation.confirm') }}
|
||||
</button>
|
||||
</template>
|
||||
</BaseDialog>
|
||||
|
||||
<BaseDialog
|
||||
v-model="cancellationDeleteDialog.isOpen"
|
||||
:title="$t('calendar.cancelCancellation.title')"
|
||||
size="small"
|
||||
:close-on-overlay="false"
|
||||
@close="closeTrainingCancellationDeleteDialog"
|
||||
>
|
||||
<div class="quick-cancellation-dialog">
|
||||
<p>
|
||||
{{ $t('calendar.cancelCancellation.message', {
|
||||
title: cancellationDeleteDialog.title,
|
||||
date: cancellationDeleteDialog.dateLabel
|
||||
}) }}
|
||||
</p>
|
||||
<p v-if="cancellationDeleteDialog.subtitle" class="quick-cancellation-hint">
|
||||
{{ cancellationDeleteDialog.subtitle }}
|
||||
</p>
|
||||
</div>
|
||||
<template #footer>
|
||||
<button type="button" class="dialog-secondary-button" @click="closeTrainingCancellationDeleteDialog">
|
||||
{{ $t('common.cancel') }}
|
||||
</button>
|
||||
<button type="button" class="dialog-danger-button" @click="confirmTrainingCancellationDelete">
|
||||
{{ $t('calendar.cancelCancellation.confirm') }}
|
||||
</button>
|
||||
</template>
|
||||
</BaseDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import apiClient from '../apiClient';
|
||||
import ConfirmDialog from '../components/ConfirmDialog.vue';
|
||||
import BaseDialog from '../components/BaseDialog.vue';
|
||||
|
||||
const WEEKDAYS = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
|
||||
const WEEKDAY_KEYS = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
|
||||
|
||||
export default {
|
||||
name: 'CalendarView',
|
||||
components: {
|
||||
ConfirmDialog,
|
||||
BaseDialog,
|
||||
},
|
||||
data() {
|
||||
const today = new Date();
|
||||
@@ -205,7 +283,8 @@ export default {
|
||||
cancellationForm: {
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
reason: ''
|
||||
reason: '',
|
||||
trainingGroupIds: []
|
||||
},
|
||||
customEventSaving: false,
|
||||
customEventForm: {
|
||||
@@ -215,39 +294,47 @@ export default {
|
||||
category: ''
|
||||
},
|
||||
optionsOpen: false,
|
||||
confirmDialog: {
|
||||
quickCancellationDialog: {
|
||||
isOpen: false,
|
||||
eventTitle: '',
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
isRange: false,
|
||||
useRange: false,
|
||||
reason: '',
|
||||
trainingGroupIds: [],
|
||||
},
|
||||
cancellationDeleteDialog: {
|
||||
isOpen: false,
|
||||
cancellation: null,
|
||||
title: '',
|
||||
message: '',
|
||||
details: '',
|
||||
type: 'info',
|
||||
confirmText: '',
|
||||
cancelText: '',
|
||||
showCancel: true,
|
||||
resolveCallback: null,
|
||||
subtitle: '',
|
||||
dateLabel: '',
|
||||
},
|
||||
plannedTrainingByDateKey: {},
|
||||
plannedTrainingGroupIdsByDateKey: {},
|
||||
trainingGroups: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['currentClub', 'currentClubName']),
|
||||
weekdays() {
|
||||
return WEEKDAYS;
|
||||
return WEEKDAY_KEYS.map(key => this.$t(`calendar.weekdays.${key}`));
|
||||
},
|
||||
eventTypes() {
|
||||
return [
|
||||
{ key: 'training', label: 'Training' },
|
||||
{ key: 'tournament', label: 'Turnier' },
|
||||
{ key: 'officialTournament', label: 'Teilnahme' },
|
||||
{ key: 'match', label: 'Punktspiel' },
|
||||
{ key: 'holiday', label: 'Feiertag' },
|
||||
{ key: 'schoolHoliday', label: 'Ferien' },
|
||||
{ key: 'trainingCancellation', label: 'Ausfall' },
|
||||
{ key: 'customEvent', label: 'Termin' }
|
||||
{ key: 'training', label: this.$t('calendar.legend.training') },
|
||||
{ key: 'tournament', label: this.$t('calendar.legend.tournament') },
|
||||
{ key: 'officialTournament', label: this.$t('calendar.legend.officialTournament') },
|
||||
{ key: 'match', label: this.$t('calendar.legend.match') },
|
||||
{ key: 'holiday', label: this.$t('calendar.legend.holiday') },
|
||||
{ key: 'schoolHoliday', label: this.$t('calendar.legend.schoolHoliday') },
|
||||
{ key: 'trainingCancellation', label: this.$t('calendar.legend.trainingCancellation') },
|
||||
{ key: 'customEvent', label: this.$t('calendar.legend.customEvent') }
|
||||
];
|
||||
},
|
||||
monthLabel() {
|
||||
return this.cursor.toLocaleDateString('de-DE', { month: 'long', year: 'numeric' });
|
||||
return this.cursor.toLocaleDateString(this.$i18n?.locale || 'de-DE', { month: 'long', year: 'numeric' });
|
||||
},
|
||||
displayedYear() {
|
||||
return this.cursor.getFullYear();
|
||||
@@ -288,7 +375,10 @@ export default {
|
||||
.sort((a, b) => a.startsAt - b.startsAt);
|
||||
},
|
||||
sourceWarnings() {
|
||||
return this.sourceErrors.map(source => `${source} konnte nicht geladen werden`);
|
||||
return this.sourceErrors.map(source => this.$t('calendar.sourceWarning', { source }));
|
||||
},
|
||||
trainingGroupsWithTimes() {
|
||||
return this.trainingGroups.filter(group => Array.isArray(group.trainingTimes) && group.trainingTimes.length > 0);
|
||||
},
|
||||
calendarDays() {
|
||||
const year = this.cursor.getFullYear();
|
||||
@@ -328,28 +418,6 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async showConfirm(title, message, details = '', type = 'info', options = {}) {
|
||||
return new Promise((resolve) => {
|
||||
this.confirmDialog = {
|
||||
isOpen: true,
|
||||
title,
|
||||
message,
|
||||
details,
|
||||
type,
|
||||
confirmText: options.confirmText || '',
|
||||
cancelText: options.cancelText || '',
|
||||
showCancel: options.showCancel !== undefined ? !!options.showCancel : true,
|
||||
resolveCallback: resolve,
|
||||
};
|
||||
});
|
||||
},
|
||||
handleConfirmResult(confirmed) {
|
||||
if (this.confirmDialog.resolveCallback) {
|
||||
this.confirmDialog.resolveCallback(confirmed);
|
||||
}
|
||||
this.confirmDialog.isOpen = false;
|
||||
this.confirmDialog.resolveCallback = null;
|
||||
},
|
||||
isOurTeam(teamName) {
|
||||
if (!teamName || !this.currentClubName) return false;
|
||||
return String(teamName).startsWith(this.currentClubName);
|
||||
@@ -365,35 +433,40 @@ export default {
|
||||
this.sourceErrors = [];
|
||||
|
||||
const sources = await Promise.allSettled([
|
||||
this.loadSource('Trainingstage', () => this.loadTrainingEvents()),
|
||||
this.loadSource('Trainingszeiten', () => this.loadRecurringTrainingEvents()),
|
||||
this.loadSource('Trainingsausfälle', () => this.loadTrainingCancellationEvents()),
|
||||
this.loadSource('Eigene Termine', () => this.loadCustomEvents()),
|
||||
this.loadSource('Turniere', () => this.loadTournamentEvents()),
|
||||
this.loadSource('Turnierteilnahmen', () => this.loadOfficialTournamentEvents()),
|
||||
this.loadSource('Punktspiele', () => this.loadMatchEvents()),
|
||||
this.loadSource('Ferien/Feiertage', () => this.loadHolidayEvents())
|
||||
this.loadSource(this.$t('calendar.sources.trainingDays'), () => this.loadTrainingEvents()),
|
||||
this.loadSource(this.$t('calendar.sources.trainingTimes'), () => this.loadRecurringTrainingEvents()),
|
||||
this.loadSource(this.$t('calendar.sources.trainingCancellations'), () => this.loadTrainingCancellationEvents()),
|
||||
this.loadSource(this.$t('calendar.sources.customEvents'), () => this.loadCustomEvents()),
|
||||
this.loadSource(this.$t('calendar.sources.tournaments'), () => this.loadTournamentEvents()),
|
||||
this.loadSource(this.$t('calendar.sources.officialTournaments'), () => this.loadOfficialTournamentEvents()),
|
||||
this.loadSource(this.$t('calendar.sources.matches'), () => this.loadMatchEvents()),
|
||||
this.loadSource(this.$t('calendar.sources.holidays'), () => this.loadHolidayEvents())
|
||||
]);
|
||||
|
||||
const loadedEvents = sources
|
||||
.filter(result => result.status === 'fulfilled')
|
||||
.flatMap(result => result.value.events)
|
||||
.filter(event => event.date && !Number.isNaN(event.date.getTime()));
|
||||
const calendarEvents = this.enrichTrainingCancellationSubtitles(loadedEvents);
|
||||
|
||||
this.plannedTrainingByDateKey = loadedEvents
|
||||
this.plannedTrainingByDateKey = calendarEvents
|
||||
.filter(event => event.type === 'training')
|
||||
.reduce((map, event) => {
|
||||
map[this.toDateKey(event.date)] = true;
|
||||
return map;
|
||||
}, {});
|
||||
this.plannedTrainingGroupIdsByDateKey = calendarEvents
|
||||
.filter(event => event.type === 'training' && event.trainingGroupId)
|
||||
.reduce((map, event) => {
|
||||
const dateKey = this.toDateKey(event.date);
|
||||
if (!map[dateKey]) map[dateKey] = {};
|
||||
map[dateKey][String(event.trainingGroupId)] = true;
|
||||
return map;
|
||||
}, {});
|
||||
|
||||
const cancellationDates = new Set(
|
||||
loadedEvents
|
||||
.filter(event => event.type === 'trainingCancellation')
|
||||
.flatMap(event => this.getDateKeysForRange(event.date, event.endDate || event.date))
|
||||
);
|
||||
const afterCancellations = loadedEvents.filter(event => (
|
||||
!event.isRecurringTraining || !cancellationDates.has(this.toDateKey(event.date))
|
||||
const cancellationEvents = calendarEvents.filter(event => event.type === 'trainingCancellation');
|
||||
const afterCancellations = calendarEvents.filter(event => (
|
||||
!event.isRecurringTraining || !this.isRecurringTrainingCancelled(event, cancellationEvents)
|
||||
));
|
||||
this.events = this.mergeRecurringTrainingSlots(afterCancellations);
|
||||
this.sourceErrors = sources
|
||||
@@ -402,7 +475,7 @@ export default {
|
||||
.filter(Boolean);
|
||||
|
||||
if (sources.every(result => result.status === 'rejected')) {
|
||||
this.error = 'Kalenderdaten konnten nicht geladen werden.';
|
||||
this.error = this.$t('calendar.loadError');
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
@@ -452,14 +525,15 @@ export default {
|
||||
const titleJoined = specific.length ? specific.join(' · ') : (rawTitles.join(' · ') || base.title);
|
||||
const safeIdKey = slotKey.replace(/\|/g, '-');
|
||||
const hasRecurring = sorted.some((x) => x.isRecurringTraining);
|
||||
const recurringSubtitle = this.$t('calendar.recurringTrainingTime');
|
||||
const otherSubtitles = [...new Set(
|
||||
sorted.map((x) => String(x.subtitle || '').trim()).filter((s) => s && s !== 'Regelmäßige Trainingszeit')
|
||||
sorted.map((x) => String(x.subtitle || '').trim()).filter((s) => s && s !== recurringSubtitle)
|
||||
)];
|
||||
let subtitleJoined = '';
|
||||
if (hasRecurring) {
|
||||
subtitleJoined = otherSubtitles.length
|
||||
? `Regelmäßige Trainingszeit · ${otherSubtitles.join(' · ')}`
|
||||
: 'Regelmäßige Trainingszeit';
|
||||
? `${recurringSubtitle} · ${otherSubtitles.join(' · ')}`
|
||||
: recurringSubtitle;
|
||||
} else {
|
||||
subtitleJoined = otherSubtitles.join(' · ') || String(base.subtitle || '').trim() || '';
|
||||
}
|
||||
@@ -483,9 +557,16 @@ export default {
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
enrichTrainingCancellationSubtitles(events) {
|
||||
return events.map(event => (
|
||||
event.type === 'trainingCancellation'
|
||||
? { ...event, subtitle: this.formatCancellationSubtitle(event.trainingGroupIds) }
|
||||
: event
|
||||
));
|
||||
},
|
||||
async loadTrainingEvents() {
|
||||
const response = await apiClient.get(`/diary/${this.currentClub}`);
|
||||
this.ensureSuccess(response, 'Trainingstage');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.trainingDays'));
|
||||
return (response.data || []).map(entry => {
|
||||
const date = this.parseDate(entry.date);
|
||||
return {
|
||||
@@ -494,7 +575,7 @@ export default {
|
||||
date,
|
||||
startsAt: this.combineDateTime(date, entry.trainingStart),
|
||||
time: this.formatTimeRange(entry.trainingStart, entry.trainingEnd),
|
||||
title: 'Training',
|
||||
title: this.$t('calendar.eventTitles.training'),
|
||||
subtitle: entry.diaryTags?.map(tag => tag.name).join(', ') || '',
|
||||
route: '/diary'
|
||||
};
|
||||
@@ -502,8 +583,9 @@ export default {
|
||||
},
|
||||
async loadRecurringTrainingEvents() {
|
||||
const response = await apiClient.get(`/training-times/${this.currentClub}`);
|
||||
this.ensureSuccess(response, 'Trainingszeiten');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.trainingTimes'));
|
||||
const groups = Array.isArray(response.data) ? response.data : [];
|
||||
this.trainingGroups = groups.filter(group => Array.isArray(group.trainingTimes) && group.trainingTimes.length > 0);
|
||||
return groups.flatMap(group => this.mapGroupTrainingTimesToEvents(group));
|
||||
},
|
||||
mapGroupTrainingTimesToEvents(group) {
|
||||
@@ -530,10 +612,11 @@ export default {
|
||||
date: eventDate,
|
||||
startsAt: this.combineDateTime(eventDate, time.startTime),
|
||||
time: this.formatTimeRange(time.startTime, time.endTime),
|
||||
title: group?.name || 'Training',
|
||||
subtitle: 'Regelmäßige Trainingszeit',
|
||||
title: group?.name || this.$t('calendar.eventTitles.training'),
|
||||
subtitle: this.$t('calendar.recurringTrainingTime'),
|
||||
route: '/diary',
|
||||
isRecurringTraining: true
|
||||
isRecurringTraining: true,
|
||||
trainingGroupId: group?.id
|
||||
});
|
||||
date.setDate(date.getDate() + 7);
|
||||
}
|
||||
@@ -544,10 +627,11 @@ export default {
|
||||
const response = await apiClient.get(`/training-cancellations/${this.currentClub}`, {
|
||||
params: { year: this.displayedYear }
|
||||
});
|
||||
this.ensureSuccess(response, 'Trainingsausfälle');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.trainingCancellations'));
|
||||
return (response.data || []).map(cancellation => {
|
||||
const date = this.parseDate(cancellation.startDate || cancellation.date);
|
||||
const endDate = this.parseDate(cancellation.endDate || cancellation.startDate || cancellation.date);
|
||||
const trainingGroupIds = this.normalizeTrainingGroupIds(cancellation.trainingGroupIds);
|
||||
return {
|
||||
id: `training-cancellation-${cancellation.id}`,
|
||||
cancellationId: cancellation.id,
|
||||
@@ -556,8 +640,9 @@ export default {
|
||||
endDate,
|
||||
startsAt: this.combineDateTime(date),
|
||||
time: '',
|
||||
title: cancellation.reason || 'Training fällt aus',
|
||||
subtitle: 'Trainingsausfall'
|
||||
title: cancellation.reason || this.$t('calendar.cancellation.fallbackTitle'),
|
||||
subtitle: this.formatCancellationSubtitle(trainingGroupIds),
|
||||
trainingGroupIds
|
||||
};
|
||||
});
|
||||
},
|
||||
@@ -568,10 +653,11 @@ export default {
|
||||
const response = await apiClient.post(`/training-cancellations/${this.currentClub}`, {
|
||||
startDate: this.cancellationForm.startDate,
|
||||
endDate: this.cancellationForm.endDate || this.cancellationForm.startDate,
|
||||
reason: this.cancellationForm.reason
|
||||
reason: this.cancellationForm.reason,
|
||||
trainingGroupIds: this.normalizeTrainingGroupIds(this.cancellationForm.trainingGroupIds)
|
||||
});
|
||||
this.ensureSuccess(response, 'Trainingsausfälle');
|
||||
this.cancellationForm = { startDate: '', endDate: '', reason: '' };
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.trainingCancellations'));
|
||||
this.cancellationForm = { startDate: '', endDate: '', reason: '', trainingGroupIds: [] };
|
||||
await this.loadCalendarEvents();
|
||||
} finally {
|
||||
this.cancellationSaving = false;
|
||||
@@ -590,14 +676,39 @@ export default {
|
||||
async deleteTrainingCancellation(cancellation) {
|
||||
if (!this.currentClub || !cancellation?.cancellationId) return;
|
||||
const response = await apiClient.delete(`/training-cancellations/${this.currentClub}/${cancellation.cancellationId}`);
|
||||
this.ensureSuccess(response, 'Trainingsausfälle');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.trainingCancellations'));
|
||||
await this.loadCalendarEvents();
|
||||
},
|
||||
openTrainingCancellationDeleteDialog(cancellation) {
|
||||
if (!cancellation?.cancellationId) return;
|
||||
this.cancellationDeleteDialog = {
|
||||
isOpen: true,
|
||||
cancellation,
|
||||
title: cancellation.title || this.$t('calendar.cancellation.fallbackTitle'),
|
||||
subtitle: cancellation.subtitle || '',
|
||||
dateLabel: this.formatEventDate(cancellation),
|
||||
};
|
||||
},
|
||||
closeTrainingCancellationDeleteDialog() {
|
||||
this.cancellationDeleteDialog = {
|
||||
isOpen: false,
|
||||
cancellation: null,
|
||||
title: '',
|
||||
subtitle: '',
|
||||
dateLabel: '',
|
||||
};
|
||||
},
|
||||
async confirmTrainingCancellationDelete() {
|
||||
const cancellation = this.cancellationDeleteDialog.cancellation;
|
||||
if (!cancellation) return;
|
||||
await this.deleteTrainingCancellation(cancellation);
|
||||
this.closeTrainingCancellationDeleteDialog();
|
||||
},
|
||||
async loadCustomEvents() {
|
||||
const response = await apiClient.get(`/calendar-events/${this.currentClub}`, {
|
||||
params: { year: this.displayedYear },
|
||||
});
|
||||
this.ensureSuccess(response, 'Eigene Termine');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.customEvents'));
|
||||
return (response.data || []).map(event => {
|
||||
const date = this.parseDate(event.startDate);
|
||||
const endDate = this.parseDate(event.endDate || event.startDate);
|
||||
@@ -610,7 +721,7 @@ export default {
|
||||
startsAt: this.combineDateTime(date),
|
||||
time: '',
|
||||
title: event.title,
|
||||
subtitle: event.category || 'Eigener Termin',
|
||||
subtitle: event.category || this.$t('calendar.customEvent.subtitleFallback'),
|
||||
};
|
||||
});
|
||||
},
|
||||
@@ -624,7 +735,7 @@ export default {
|
||||
endDate: this.customEventForm.endDate || this.customEventForm.startDate,
|
||||
category: this.customEventForm.category || null,
|
||||
});
|
||||
this.ensureSuccess(response, 'Eigene Termine');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.customEvents'));
|
||||
this.customEventForm = { title: '', startDate: '', endDate: '', category: '' };
|
||||
await this.loadCalendarEvents();
|
||||
} finally {
|
||||
@@ -634,12 +745,12 @@ export default {
|
||||
async deleteCustomEvent(event) {
|
||||
if (!this.currentClub || !event?.customEventId) return;
|
||||
const response = await apiClient.delete(`/calendar-events/${this.currentClub}/${event.customEventId}`);
|
||||
this.ensureSuccess(response, 'Eigene Termine');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.customEvents'));
|
||||
await this.loadCalendarEvents();
|
||||
},
|
||||
async loadTournamentEvents() {
|
||||
const response = await apiClient.get(`/tournament/${this.currentClub}`);
|
||||
this.ensureSuccess(response, 'Turniere');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.tournaments'));
|
||||
return (response.data || []).map(tournament => {
|
||||
const date = this.parseDate(tournament.date);
|
||||
return {
|
||||
@@ -648,21 +759,21 @@ export default {
|
||||
date,
|
||||
startsAt: this.combineDateTime(date),
|
||||
time: '',
|
||||
title: tournament.name || tournament.tournamentName || 'Turnier',
|
||||
subtitle: tournament.allowsExternal ? 'Offenes Turnier' : 'Vereinsturnier',
|
||||
title: tournament.name || tournament.tournamentName || this.$t('calendar.eventTitles.tournament'),
|
||||
subtitle: tournament.allowsExternal ? this.$t('calendar.tournament.open') : this.$t('calendar.tournament.club'),
|
||||
route: '/tournaments'
|
||||
};
|
||||
});
|
||||
},
|
||||
async loadMatchEvents() {
|
||||
const response = await apiClient.get(`/matches/leagues/${this.currentClub}/matches`);
|
||||
this.ensureSuccess(response, 'Punktspiele');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.matches'));
|
||||
return (response.data || [])
|
||||
.filter(match => this.isOurTeam(match.homeTeam?.name) || this.isOurTeam(match.guestTeam?.name))
|
||||
.map(match => {
|
||||
const date = this.parseDate(match.date);
|
||||
const home = match.homeTeam?.name || 'Heim';
|
||||
const guest = match.guestTeam?.name || 'Gast';
|
||||
const home = match.homeTeam?.name || this.$t('calendar.match.home');
|
||||
const guest = match.guestTeam?.name || this.$t('calendar.match.guest');
|
||||
return {
|
||||
id: `match-${match.id}`,
|
||||
type: 'match',
|
||||
@@ -670,14 +781,14 @@ export default {
|
||||
startsAt: this.combineDateTime(date, match.time),
|
||||
time: this.formatTime(match.time),
|
||||
title: `${home} - ${guest}`,
|
||||
subtitle: match.leagueDetails?.name || match.league?.name || 'Punktspiel',
|
||||
subtitle: match.leagueDetails?.name || match.league?.name || this.$t('calendar.eventTitles.match'),
|
||||
route: '/schedule'
|
||||
};
|
||||
});
|
||||
},
|
||||
async loadOfficialTournamentEvents() {
|
||||
const response = await apiClient.get(`/official-tournaments/${this.currentClub}/participations/summary`);
|
||||
this.ensureSuccess(response, 'Turnierteilnahmen');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.officialTournaments'));
|
||||
return (response.data || [])
|
||||
.filter(tournament => Array.isArray(tournament.entries) && tournament.entries.length > 0)
|
||||
.map(tournament => {
|
||||
@@ -693,8 +804,10 @@ export default {
|
||||
endDate: endDate || date,
|
||||
startsAt: this.combineDateTime(date),
|
||||
time: '',
|
||||
title: tournament.tournamentName || tournament.title || 'Turnierteilnahme',
|
||||
subtitle: participantCount > 0 ? `${participantCount} Teilnehmer` : `${entries.length} Starts`,
|
||||
title: tournament.tournamentName || tournament.title || this.$t('calendar.eventTitles.officialTournament'),
|
||||
subtitle: participantCount > 0
|
||||
? this.$t('calendar.participants', { count: participantCount })
|
||||
: this.$t('calendar.starts', { count: entries.length }),
|
||||
route: '/tournament-participations'
|
||||
};
|
||||
})
|
||||
@@ -704,12 +817,12 @@ export default {
|
||||
const response = await apiClient.get(`/calendar/club/${this.currentClub}/holidays`, {
|
||||
params: { year: this.displayedYear }
|
||||
});
|
||||
this.ensureSuccess(response, 'Ferien/Feiertage');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.holidays'));
|
||||
const holidays = response.data?.holidays || [];
|
||||
const schoolHolidays = response.data?.schoolHolidays || [];
|
||||
return [
|
||||
...holidays.map(entry => this.mapCalendarDayEvent(entry, 'holiday', 'Feiertag')),
|
||||
...schoolHolidays.map(entry => this.mapCalendarDayEvent(entry, 'schoolHoliday', 'Schulferien'))
|
||||
...holidays.map(entry => this.mapCalendarDayEvent(entry, 'holiday', this.$t('calendar.holidayTypes.holiday'))),
|
||||
...schoolHolidays.map(entry => this.mapCalendarDayEvent(entry, 'schoolHoliday', this.$t('calendar.holidayTypes.schoolHoliday')))
|
||||
].filter(Boolean);
|
||||
},
|
||||
mapCalendarDayEvent(entry, type, fallbackTitle) {
|
||||
@@ -774,7 +887,52 @@ export default {
|
||||
},
|
||||
shouldShowEventOnDate(event, dateKey) {
|
||||
if (event.type !== 'trainingCancellation') return true;
|
||||
return Boolean(this.plannedTrainingByDateKey[dateKey]);
|
||||
const trainingGroupIds = this.normalizeTrainingGroupIds(event.trainingGroupIds);
|
||||
if (!trainingGroupIds.length) return Boolean(this.plannedTrainingByDateKey[dateKey]);
|
||||
const plannedGroupIds = this.plannedTrainingGroupIdsByDateKey[dateKey] || {};
|
||||
return trainingGroupIds.some(groupId => Boolean(plannedGroupIds[String(groupId)]));
|
||||
},
|
||||
isRecurringTrainingCancelled(event, cancellationEvents) {
|
||||
return cancellationEvents.some(cancellation => (
|
||||
this.isEventOnDate(cancellation, event.date)
|
||||
&& this.matchesCancellationGroup(cancellation, event.trainingGroupId)
|
||||
));
|
||||
},
|
||||
matchesCancellationGroup(cancellation, trainingGroupId) {
|
||||
const trainingGroupIds = this.normalizeTrainingGroupIds(cancellation.trainingGroupIds);
|
||||
return trainingGroupIds.length === 0 || trainingGroupIds.includes(Number.parseInt(trainingGroupId, 10));
|
||||
},
|
||||
normalizeTrainingGroupIds(trainingGroupIds) {
|
||||
const values = this.parseTrainingGroupIdsValue(trainingGroupIds);
|
||||
return [...new Set(
|
||||
values
|
||||
.map(groupId => Number.parseInt(groupId, 10))
|
||||
.filter(groupId => Number.isInteger(groupId) && groupId > 0)
|
||||
)];
|
||||
},
|
||||
parseTrainingGroupIdsValue(trainingGroupIds) {
|
||||
if (Array.isArray(trainingGroupIds)) return trainingGroupIds;
|
||||
if (trainingGroupIds === null || trainingGroupIds === undefined || trainingGroupIds === '') return [];
|
||||
if (typeof trainingGroupIds === 'string') {
|
||||
try {
|
||||
const parsed = JSON.parse(trainingGroupIds);
|
||||
if (Array.isArray(parsed)) return parsed;
|
||||
if (parsed !== null && parsed !== undefined) return [parsed];
|
||||
} catch (error) {
|
||||
return trainingGroupIds.split(',');
|
||||
}
|
||||
}
|
||||
return [];
|
||||
},
|
||||
formatCancellationSubtitle(trainingGroupIds) {
|
||||
const normalizedIds = this.normalizeTrainingGroupIds(trainingGroupIds);
|
||||
if (!normalizedIds.length) return this.$t('calendar.cancellation.subtitle');
|
||||
const names = normalizedIds
|
||||
.map(groupId => this.trainingGroupsWithTimes.find(group => Number(group.id) === groupId)?.name)
|
||||
.filter(Boolean);
|
||||
return names.length
|
||||
? `${this.$t('calendar.cancellation.subtitle')} · ${names.join(', ')}`
|
||||
: this.$t('calendar.cancellation.subtitle');
|
||||
},
|
||||
startOfDay(date) {
|
||||
const result = new Date(date);
|
||||
@@ -798,7 +956,7 @@ export default {
|
||||
return startTime || endTime || '';
|
||||
},
|
||||
formatShortDate(date) {
|
||||
return date.toLocaleDateString('de-DE', { weekday: 'short', day: '2-digit', month: '2-digit' });
|
||||
return date.toLocaleDateString(this.$i18n?.locale || 'de-DE', { weekday: 'short', day: '2-digit', month: '2-digit' });
|
||||
},
|
||||
formatEventDate(event) {
|
||||
if (!event.endDate || this.toDateKey(event.date) === this.toDateKey(event.endDate)) {
|
||||
@@ -821,47 +979,56 @@ export default {
|
||||
this.offerTrainingCancellationForHoliday(event);
|
||||
return;
|
||||
}
|
||||
if (event?.type === 'trainingCancellation') {
|
||||
this.openTrainingCancellationDeleteDialog(event);
|
||||
return;
|
||||
}
|
||||
if (event.route) {
|
||||
this.$router.push(event.route);
|
||||
}
|
||||
},
|
||||
async offerTrainingCancellationForHoliday(event) {
|
||||
offerTrainingCancellationForHoliday(event) {
|
||||
if (!this.currentClub) return;
|
||||
const startDateKey = this.toDateKey(event.date);
|
||||
const endDateKey = this.toDateKey(event.endDate || event.date);
|
||||
const isRange = startDateKey !== endDateKey;
|
||||
|
||||
const shouldCreate = await this.showConfirm(
|
||||
'Trainingsausfall',
|
||||
'Training als Ausfall markieren?',
|
||||
'',
|
||||
'warning',
|
||||
{ confirmText: 'Ja', cancelText: 'Nein' }
|
||||
);
|
||||
if (!shouldCreate) return;
|
||||
|
||||
let useRange = false;
|
||||
if (isRange) {
|
||||
useRange = await this.showConfirm(
|
||||
'Zeitraum',
|
||||
`Gilt der Ausfall für den gesamten Zeitraum (${startDateKey} bis ${endDateKey})?`,
|
||||
'',
|
||||
'info',
|
||||
{ confirmText: 'Zeitraum', cancelText: 'Nur Tag' }
|
||||
);
|
||||
}
|
||||
|
||||
const reason = `${event.title}${event.subtitle ? ` (${event.subtitle})` : ''}`.trim();
|
||||
await this.createTrainingCancellation(startDateKey, useRange ? endDateKey : startDateKey, reason);
|
||||
|
||||
this.quickCancellationDialog = {
|
||||
isOpen: true,
|
||||
eventTitle: event.title,
|
||||
startDate: startDateKey,
|
||||
endDate: endDateKey,
|
||||
isRange,
|
||||
useRange: isRange,
|
||||
reason,
|
||||
trainingGroupIds: this.trainingGroupsWithTimes.map(group => String(group.id)),
|
||||
};
|
||||
},
|
||||
closeQuickCancellationDialog() {
|
||||
this.quickCancellationDialog.isOpen = false;
|
||||
},
|
||||
async confirmQuickCancellation() {
|
||||
const dialog = this.quickCancellationDialog;
|
||||
if (!this.currentClub || !dialog.startDate || dialog.trainingGroupIds.length === 0) return;
|
||||
const endDate = dialog.isRange && dialog.useRange ? dialog.endDate : dialog.startDate;
|
||||
await this.createTrainingCancellation(
|
||||
dialog.startDate,
|
||||
endDate,
|
||||
dialog.reason,
|
||||
dialog.trainingGroupIds
|
||||
);
|
||||
this.closeQuickCancellationDialog();
|
||||
await this.loadCalendarEvents();
|
||||
},
|
||||
async createTrainingCancellation(startDate, endDate, reason) {
|
||||
async createTrainingCancellation(startDate, endDate, reason, trainingGroupIds = []) {
|
||||
const response = await apiClient.post(`/training-cancellations/${this.currentClub}`, {
|
||||
startDate,
|
||||
endDate,
|
||||
reason
|
||||
reason,
|
||||
trainingGroupIds: this.normalizeTrainingGroupIds(trainingGroupIds)
|
||||
});
|
||||
this.ensureSuccess(response, 'Trainingsausfälle');
|
||||
this.ensureSuccess(response, this.$t('calendar.sources.trainingCancellations'));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1104,7 +1271,7 @@ export default {
|
||||
|
||||
.training-cancellation-form {
|
||||
display: grid;
|
||||
grid-template-columns: 10rem 10rem minmax(12rem, 1fr) auto;
|
||||
grid-template-columns: 10rem 10rem 12rem minmax(12rem, 1fr) auto;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -1121,6 +1288,7 @@ export default {
|
||||
}
|
||||
|
||||
.training-cancellation-form input,
|
||||
.training-cancellation-form select,
|
||||
.training-cancellation-form button {
|
||||
border: 1px solid #cfdad4;
|
||||
border-radius: 8px;
|
||||
@@ -1128,6 +1296,11 @@ export default {
|
||||
padding: 0 0.75rem;
|
||||
}
|
||||
|
||||
.training-cancellation-form select {
|
||||
min-height: 4.8rem;
|
||||
padding: 0.35rem 0.5rem;
|
||||
}
|
||||
|
||||
.training-cancellation-form button {
|
||||
background: #2f7a5f;
|
||||
color: #fff;
|
||||
@@ -1318,6 +1491,82 @@ export default {
|
||||
color: #607169;
|
||||
}
|
||||
|
||||
.quick-cancellation-dialog {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.85rem;
|
||||
}
|
||||
|
||||
.quick-cancellation-dialog p {
|
||||
margin: 0;
|
||||
color: #40524b;
|
||||
}
|
||||
|
||||
.quick-cancellation-checkbox,
|
||||
.quick-cancellation-groups {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.quick-cancellation-checkbox {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.quick-cancellation-groups {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.quick-cancellation-groups span {
|
||||
color: #40524b;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.quick-cancellation-groups select {
|
||||
min-height: 8rem;
|
||||
border: 1px solid #cfdad4;
|
||||
border-radius: 8px;
|
||||
padding: 0.45rem;
|
||||
}
|
||||
|
||||
.quick-cancellation-hint {
|
||||
color: #8a4b11;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.dialog-primary-button,
|
||||
.dialog-danger-button,
|
||||
.dialog-secondary-button {
|
||||
min-height: 2.35rem;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-weight: 800;
|
||||
padding: 0 0.85rem;
|
||||
}
|
||||
|
||||
.dialog-primary-button {
|
||||
border: 1px solid #2f7a5f;
|
||||
background: #2f7a5f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.dialog-danger-button {
|
||||
border: 1px solid #b91c1c;
|
||||
background: #dc2626;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.dialog-primary-button:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.dialog-secondary-button {
|
||||
border: 1px solid #cfdad4;
|
||||
background: #f8fbf9;
|
||||
color: #173d31;
|
||||
}
|
||||
|
||||
.agenda-time {
|
||||
color: #40524b;
|
||||
font-weight: 800;
|
||||
|
||||
Reference in New Issue
Block a user