feat(clubSettings): enhance club settings UI with loading and error handling
- Added loading and error states to the club settings view, improving user feedback during data retrieval. - Introduced new translations for error messages in the German locale, enhancing localization support. - Updated the save method to alert users when no club is selected, ensuring clarity in user actions.
This commit is contained in:
@@ -735,7 +735,9 @@
|
||||
"associationMemberNumberPlaceholder": "z. B. 12-3456",
|
||||
"save": "Speichern",
|
||||
"saved": "Gespeichert",
|
||||
"saveFailed": "Speichern fehlgeschlagen"
|
||||
"saveFailed": "Speichern fehlgeschlagen",
|
||||
"loadFailed": "Einstellungen konnten nicht geladen werden",
|
||||
"noClubSelected": "Bitte wählen Sie zuerst einen Verein aus."
|
||||
},
|
||||
"predefinedActivities": {
|
||||
"title": "Vordefinierte Aktivitäten",
|
||||
|
||||
@@ -26,7 +26,10 @@
|
||||
|
||||
<!-- Settings Tab -->
|
||||
<div v-if="activeTab === 'settings'">
|
||||
<section class="card">
|
||||
<p v-if="!currentClub" class="hint hint-warning">{{ $t('clubSettings.noClubSelected') }}</p>
|
||||
<p v-else-if="loading" class="hint">{{ $t('common.loading') }}</p>
|
||||
<p v-else-if="loadError" class="hint hint-error">{{ loadError }}</p>
|
||||
<section v-if="currentClub && !loading" class="card">
|
||||
<h2>{{ $t('clubSettings.greetingText') }}</h2>
|
||||
<div class="greeting-grid">
|
||||
<textarea v-model="greeting" class="greeting-input" rows="10" :placeholder="$t('clubSettings.greetingPlaceholder')"></textarea>
|
||||
@@ -43,12 +46,12 @@
|
||||
<p class="hint">{{ $t('clubSettings.greetingHint') }}</p>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<section v-if="currentClub && !loading" class="card">
|
||||
<h2>{{ $t('clubSettings.associationMemberNumber') }}</h2>
|
||||
<input v-model="associationMemberNumber" class="text-input" :placeholder="$t('clubSettings.associationMemberNumberPlaceholder')" />
|
||||
</section>
|
||||
|
||||
<section class="card actions-card">
|
||||
<section v-if="currentClub && !loading" class="card actions-card">
|
||||
<div class="actions">
|
||||
<button class="btn btn-primary" @click="save">{{ $t('clubSettings.save') }}</button>
|
||||
<span v-if="saved" class="saved-hint">{{ $t('clubSettings.saved') }}</span>
|
||||
@@ -72,6 +75,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import apiClient from '../apiClient';
|
||||
import TrainingGroupsTab from '../components/TrainingGroupsTab.vue';
|
||||
import TrainingTimesTab from '../components/TrainingTimesTab.vue';
|
||||
@@ -88,27 +92,54 @@ export default {
|
||||
greeting: '',
|
||||
associationMemberNumber: '',
|
||||
saved: false,
|
||||
loading: false,
|
||||
loadError: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const stored = localStorage.getItem('clubGreeting');
|
||||
if (stored) this.greeting = stored;
|
||||
const storedNr = localStorage.getItem('associationMemberNumber');
|
||||
if (storedNr) this.associationMemberNumber = storedNr;
|
||||
computed: {
|
||||
...mapGetters(['currentClub']),
|
||||
},
|
||||
watch: {
|
||||
currentClub: {
|
||||
handler(clubId) {
|
||||
if (clubId) this.loadClubSettings();
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async save() {
|
||||
localStorage.setItem('clubGreeting', this.greeting || '');
|
||||
localStorage.setItem('associationMemberNumber', this.associationMemberNumber || '');
|
||||
async loadClubSettings() {
|
||||
if (!this.currentClub) {
|
||||
this.greeting = '';
|
||||
this.associationMemberNumber = '';
|
||||
this.loadError = null;
|
||||
return;
|
||||
}
|
||||
this.loadError = null;
|
||||
this.loading = true;
|
||||
try {
|
||||
// Beispiel: aktuellen Club aus localStorage
|
||||
const clubId = localStorage.getItem('currentClub');
|
||||
if (clubId) {
|
||||
await apiClient.put(`/clubs/${clubId}/settings`, {
|
||||
greetingText: this.greeting,
|
||||
associationMemberNumber: this.associationMemberNumber,
|
||||
});
|
||||
}
|
||||
const response = await apiClient.get(`/clubs/${this.currentClub}`);
|
||||
const club = response.data;
|
||||
this.greeting = club?.greetingText ?? '';
|
||||
this.associationMemberNumber = club?.associationMemberNumber ?? '';
|
||||
} catch (e) {
|
||||
this.loadError = this.$t('clubSettings.loadFailed');
|
||||
this.greeting = '';
|
||||
this.associationMemberNumber = '';
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
if (!this.currentClub) {
|
||||
alert(this.$t('clubSettings.noClubSelected'));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await apiClient.put(`/clubs/${this.currentClub}/settings`, {
|
||||
greetingText: this.greeting,
|
||||
associationMemberNumber: this.associationMemberNumber,
|
||||
});
|
||||
this.saved = true;
|
||||
setTimeout(() => (this.saved = false), 1500);
|
||||
} catch (e) {
|
||||
@@ -148,6 +179,8 @@ export default {
|
||||
.btn.btn-primary:hover { background: var(--primary-hover); }
|
||||
.saved-hint { color: #28a745; font-weight: 600; }
|
||||
.hint { color: #666; font-size: 12px; margin-top: 8px; }
|
||||
.hint-warning { color: #856404; background: #fff3cd; padding: 12px; border-radius: 6px; }
|
||||
.hint-error { color: #721c24; background: #f8d7da; padding: 12px; border-radius: 6px; }
|
||||
|
||||
.tab-navigation {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user