From cb7a0274627af99207c98772715270c930dc91a1 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Wed, 29 Apr 2026 09:16:29 +0200 Subject: [PATCH] feat(TournamentGroupsTab, TournamentTab): enhance input handling and normalization - Updated input fields in TournamentGroupsTab to use a normalization function for better handling of numeric inputs, allowing for empty values and ensuring minimum constraints. - Added blur event handlers to trigger updates on input loss of focus, improving user experience. - Modified TournamentTab to use nullish coalescing for safer access to group counts, enhancing robustness against undefined values. --- .../tournament/TournamentGroupsTab.vue | 34 +++++++++++++++---- frontend/src/views/TournamentTab.vue | 4 +-- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/tournament/TournamentGroupsTab.vue b/frontend/src/components/tournament/TournamentGroupsTab.vue index a3e0e06a..45cc1e92 100644 --- a/frontend/src/components/tournament/TournamentGroupsTab.vue +++ b/frontend/src/components/tournament/TournamentGroupsTab.vue @@ -42,9 +42,10 @@ @@ -59,8 +60,9 @@ type="number" :value="numberOfGroups" min="1" - @input="$emit('update:numberOfGroups', Math.max(1, parseInt($event.target.value || '1', 10) || 1))" - @change="$emit('group-count-change')" + @input="$emit('update:numberOfGroups', normalizeNumberInput($event.target.value, { min: 1, allowEmpty: true }))" + @keydown.enter.prevent="onNumberOfGroupsBlur($event.target.value)" + @blur="onNumberOfGroupsBlur($event.target.value)" /> @@ -226,11 +228,11 @@ export default { default: null }, groupsPerClassInput: { - type: Number, + type: [Number, String], default: 0 }, numberOfGroups: { - type: Number, + type: [Number, String], required: true }, groups: { @@ -306,6 +308,26 @@ export default { } }, methods: { + normalizeNumberInput(rawValue, { min = 0, allowEmpty = false } = {}) { + if (rawValue === '' || rawValue === null || rawValue === undefined) { + return allowEmpty ? '' : min; + } + const parsed = parseInt(String(rawValue), 10); + if (!Number.isFinite(parsed)) { + return allowEmpty ? '' : min; + } + return Math.max(min, parsed); + }, + onGroupsPerClassBlur(rawValue) { + const normalized = this.normalizeNumberInput(rawValue, { min: 0, allowEmpty: false }); + this.$emit('update:groupsPerClassInput', normalized); + this.$emit('group-count-change'); + }, + onNumberOfGroupsBlur(rawValue) { + const normalized = this.normalizeNumberInput(rawValue, { min: 1, allowEmpty: false }); + this.$emit('update:numberOfGroups', normalized); + this.$emit('group-count-change'); + }, groupRankingsForGroup(group) { const key = `${group.groupId}-${group.classId ?? 'null'}`; return this.groupRankings[key] || []; diff --git a/frontend/src/views/TournamentTab.vue b/frontend/src/views/TournamentTab.vue index 85707c1c..a76467ea 100644 --- a/frontend/src/views/TournamentTab.vue +++ b/frontend/src/views/TournamentTab.vue @@ -939,10 +939,10 @@ export default { return 0; } if (this.selectedViewClass === '__none__') { - return this.groupsPerClass['null'] || 0; + return this.groupsPerClass['null'] ?? 0; } const classId = Number(this.selectedViewClass); - return this.groupsPerClass[classId] || 0; + return this.groupsPerClass[classId] ?? 0; }, set(value) { if (this.selectedViewClass === null || this.selectedViewClass === undefined || this.selectedViewClass === '' || this.selectedViewClass === '__all__' || this.selectedViewClass === 'all') {