feat(matches): add fixture type handling and notes to manual match creation; update localization for match types
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 56s
All checks were successful
Deploy tt-tagebuch / deploy (push) Successful in 56s
This commit is contained in:
@@ -1482,7 +1482,14 @@
|
||||
"addMatch": "Spiel hinzufügen",
|
||||
"manualMatchDescription": "Manuell gepflegte Spiele erscheinen neben den importierten Click-TT-Terminen.",
|
||||
"fixtureType": "Spieltyp:",
|
||||
"regularMatch": "Reguläres Spiel",
|
||||
"cupMatch": "Pokalspiel",
|
||||
"friendlyMatch": "Freundschaftsspiel",
|
||||
"fixtureTypeDescription": {
|
||||
"league": "Reguläre und Pokalspiele werden im Spielplan gespeichert.",
|
||||
"cup": "Reguläre und Pokalspiele werden im Spielplan gespeichert.",
|
||||
"friendly": "Freundschaftsspiele werden separat verwaltet; die Angaben werden in das passende Formular übernommen."
|
||||
},
|
||||
"ownTeam": "Eigene Mannschaft",
|
||||
"selectTeam": "Mannschaft wählen",
|
||||
"opponent": "Gegner",
|
||||
@@ -1495,7 +1502,10 @@
|
||||
"notes": "Notizen",
|
||||
"saving": "Speichert…",
|
||||
"manualMatchRequired": "Bitte Mannschaft, Gegner, Datum und Uhrzeit ausfüllen.",
|
||||
"manualMatchSaved": "Pokalspiel wurde hinzugefügt.",
|
||||
"manualMatchSaved": {
|
||||
"league": "Reguläres Spiel wurde hinzugefügt.",
|
||||
"cup": "Pokalspiel wurde hinzugefügt."
|
||||
},
|
||||
"manualMatchSaveFailed": "Pokalspiel konnte nicht gespeichert werden.",
|
||||
"galleryLoading": "Galerie wird geladen…",
|
||||
"gallery": "Mitglieder-Galerie",
|
||||
|
||||
@@ -1459,7 +1459,14 @@
|
||||
"addMatch": "Add match",
|
||||
"manualMatchDescription": "Manually maintained matches appear alongside imported Click-TT fixtures.",
|
||||
"fixtureType": "Fixture type:",
|
||||
"regularMatch": "Regular match",
|
||||
"cupMatch": "Cup match",
|
||||
"friendlyMatch": "Friendly match",
|
||||
"fixtureTypeDescription": {
|
||||
"league": "Regular and cup matches are stored in the schedule.",
|
||||
"cup": "Regular and cup matches are stored in the schedule.",
|
||||
"friendly": "Friendly matches are managed separately; the details are transferred to the appropriate form."
|
||||
},
|
||||
"ownTeam": "Own team",
|
||||
"selectTeam": "Select team",
|
||||
"opponent": "Opponent",
|
||||
@@ -1472,7 +1479,10 @@
|
||||
"notes": "Notes",
|
||||
"saving": "Saving…",
|
||||
"manualMatchRequired": "Please fill in the team, opponent, date and time.",
|
||||
"manualMatchSaved": "Cup match added.",
|
||||
"manualMatchSaved": {
|
||||
"league": "Regular match added.",
|
||||
"cup": "Cup match added."
|
||||
},
|
||||
"manualMatchSaveFailed": "Cup match could not be saved.",
|
||||
"galleryLoading": "Loading gallery…",
|
||||
"gallery": "Member gallery",
|
||||
|
||||
@@ -275,7 +275,13 @@
|
||||
<BaseDialog v-model="manualMatchDialog.isOpen" :title="$t('schedule.addMatch')" :max-width="620" @close="closeManualMatchDialog">
|
||||
<form class="manual-match-form" @submit.prevent="saveManualMatch">
|
||||
<p class="manual-match-intro">{{ $t('schedule.manualMatchDescription') }}</p>
|
||||
<div class="manual-match-type">{{ $t('schedule.fixtureType') }} <strong>{{ $t('schedule.cupMatch') }}</strong></div>
|
||||
<fieldset class="manual-match-type">
|
||||
<legend>{{ $t('schedule.fixtureType') }}</legend>
|
||||
<label><input v-model="manualMatchDialog.form.fixtureType" type="radio" value="league"> {{ $t('schedule.regularMatch') }}</label>
|
||||
<label><input v-model="manualMatchDialog.form.fixtureType" type="radio" value="cup"> {{ $t('schedule.cupMatch') }}</label>
|
||||
<label><input v-model="manualMatchDialog.form.fixtureType" type="radio" value="friendly"> {{ $t('schedule.friendlyMatch') }}</label>
|
||||
</fieldset>
|
||||
<p class="manual-match-type-hint">{{ $t(`schedule.fixtureTypeDescription.${manualMatchDialog.form.fixtureType}`) }}</p>
|
||||
<p v-if="manualMatchDialog.error" class="manual-match-error" role="alert">{{ manualMatchDialog.error }}</p>
|
||||
<div class="manual-match-grid">
|
||||
<label><span>{{ $t('schedule.ownTeam') }} *</span><select v-model="manualMatchDialog.form.clubTeamId" required><option value="">{{ $t('schedule.selectTeam') }}</option><option v-for="team in teams" :key="team.id" :value="String(team.id)">{{ team.name }} <template v-if="team.league?.name">({{ team.league.name }})</template></option></select></label>
|
||||
@@ -888,7 +894,7 @@ export default {
|
||||
showImportModal: false,
|
||||
manualMatchDialog: {
|
||||
isOpen: false, saving: false, error: '',
|
||||
form: { clubTeamId: '', opponentName: '', date: new Date().toISOString().slice(0, 10), time: '', homeAway: 'home', locationName: '', locationAddress: '', locationZip: '', locationCity: '', notes: '' }
|
||||
form: { fixtureType: 'league', clubTeamId: '', opponentName: '', date: new Date().toISOString().slice(0, 10), time: '', homeAway: 'home', locationName: '', locationAddress: '', locationZip: '', locationCity: '', notes: '' }
|
||||
},
|
||||
selectedFile: null,
|
||||
teams: [],
|
||||
@@ -984,7 +990,7 @@ export default {
|
||||
return (Array.isArray(matches) ? matches : []).filter((match) => !match?.isFriendly);
|
||||
},
|
||||
resetManualMatchDialogForm() {
|
||||
this.manualMatchDialog.form = { clubTeamId: this.selectedTeam?.id ? String(this.selectedTeam.id) : '', opponentName: '', date: new Date().toISOString().slice(0, 10), time: '', homeAway: 'home', locationName: '', locationAddress: '', locationZip: '', locationCity: '', notes: '' };
|
||||
this.manualMatchDialog.form = { fixtureType: 'league', clubTeamId: this.selectedTeam?.id ? String(this.selectedTeam.id) : '', opponentName: '', date: new Date().toISOString().slice(0, 10), time: '', homeAway: 'home', locationName: '', locationAddress: '', locationZip: '', locationCity: '', notes: '' };
|
||||
this.manualMatchDialog.error = '';
|
||||
},
|
||||
openManualMatchDialog() {
|
||||
@@ -1005,11 +1011,33 @@ export default {
|
||||
this.manualMatchDialog.saving = true;
|
||||
this.manualMatchDialog.error = '';
|
||||
try {
|
||||
if (form.fixtureType === 'friendly') {
|
||||
const ownTeam = this.teams.find((team) => String(team.id) === String(form.clubTeamId));
|
||||
if (!ownTeam?.name) {
|
||||
this.manualMatchDialog.error = this.$t('schedule.manualMatchRequired');
|
||||
return;
|
||||
}
|
||||
const prefill = {
|
||||
...this.emptyFriendlyMatchForm(),
|
||||
date: form.date,
|
||||
time: form.time,
|
||||
homeTeamName: form.homeAway === 'home' ? ownTeam.name : form.opponentName,
|
||||
guestTeamName: form.homeAway === 'home' ? form.opponentName : ownTeam.name,
|
||||
locationName: form.locationName,
|
||||
locationAddress: form.locationAddress,
|
||||
locationZip: form.locationZip,
|
||||
locationCity: form.locationCity,
|
||||
};
|
||||
this.manualMatchDialog.isOpen = false;
|
||||
this.resetManualMatchDialogForm();
|
||||
await this.openFriendlyMatchDialog(null, prefill);
|
||||
return;
|
||||
}
|
||||
await apiClient.post(`/matches/${this.currentClub}`, { ...form, clubTeamId: Number(form.clubTeamId) });
|
||||
this.manualMatchDialog.isOpen = false;
|
||||
this.resetManualMatchDialogForm();
|
||||
await this.refreshScheduleData();
|
||||
this.showInfo(this.$t('messages.success'), this.$t('schedule.manualMatchSaved'), '', 'success');
|
||||
this.showInfo(this.$t('messages.success'), this.$t(`schedule.manualMatchSaved.${form.fixtureType}`), '', 'success');
|
||||
} catch (error) {
|
||||
this.manualMatchDialog.error = getSafeErrorMessage(error, this.$t('schedule.manualMatchSaveFailed'));
|
||||
} finally {
|
||||
@@ -1730,7 +1758,7 @@ export default {
|
||||
this.friendlyMatchDialog.homeMembers = members;
|
||||
this.friendlyMatchDialog.guestMembers = [];
|
||||
},
|
||||
async openFriendlyMatchDialog(match = null) {
|
||||
async openFriendlyMatchDialog(match = null, prefill = null) {
|
||||
await this.loadFriendlyMembers(match);
|
||||
this.friendlyMatchDialog.match = match?.isFriendly ? match : null;
|
||||
this.friendlyMatchDialog.editingId = match?.isFriendly ? match.id : null;
|
||||
@@ -1756,7 +1784,7 @@ export default {
|
||||
guestParticipants: [...this.parseFriendlyArray(match.guestParticipants)],
|
||||
resultDetails: [...this.parseFriendlyArray(match.resultDetails)]
|
||||
}
|
||||
: this.emptyFriendlyMatchForm();
|
||||
: (prefill || this.emptyFriendlyMatchForm());
|
||||
this.syncFriendlyEditDoubleRows();
|
||||
await this.loadFriendlyVenues(match);
|
||||
const selectedVenue = this.findFriendlyVenueForForm();
|
||||
@@ -3892,8 +3920,10 @@ li {
|
||||
|
||||
.manual-match-form { display: flex; flex-direction: column; gap: 1rem; }
|
||||
.manual-match-intro { margin: 0; color: var(--text-muted, #6c757d); }
|
||||
.manual-match-type { padding: .65rem .8rem; border-left: 3px solid var(--primary-color); background: var(--surface-muted, #f5f7f6); font-size: .92rem; }
|
||||
.manual-match-type strong { margin-left: .4rem; }
|
||||
.manual-match-type { display: flex; flex-wrap: wrap; gap: .6rem 1rem; margin: 0; padding: .65rem .8rem; border: 1px solid var(--border-color); border-left: 3px solid var(--primary-color); background: var(--surface-muted, #f5f7f6); font-size: .92rem; }
|
||||
.manual-match-type legend { width: 100%; padding: 0 .2rem; font-size: .86rem; font-weight: 600; }
|
||||
.manual-match-type label { font-weight: 600; cursor: pointer; }
|
||||
.manual-match-type-hint { margin: -.35rem 0 0; color: var(--text-muted, #6c757d); font-size: .86rem; }
|
||||
.manual-match-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .85rem; }
|
||||
.manual-match-grid label, .manual-match-notes { display: grid; gap: .35rem; font-weight: 600; font-size: .9rem; }
|
||||
.manual-match-grid input, .manual-match-grid select, .manual-match-notes textarea { width: 100%; box-sizing: border-box; padding: .6rem .7rem; border: 1px solid var(--border-color); border-radius: 4px; background: var(--background-light, #fff); color: inherit; font: inherit; }
|
||||
|
||||
Reference in New Issue
Block a user