Add Vocab Trainer feature with routing, database schema, and translations

- Introduced Vocab Trainer functionality, including new routes for managing languages and chapters.
- Implemented database schema for vocab-related tables to ensure data integrity.
- Updated navigation and UI components to include Vocab Trainer in the social network menu.
- Added translations for Vocab Trainer in both German and English locales, enhancing user accessibility.
This commit is contained in:
Torsten Schulz (local)
2025-12-30 18:34:32 +01:00
parent a09220b881
commit 83597d9e02
24 changed files with 2135 additions and 3 deletions

View File

@@ -0,0 +1,106 @@
<template>
<h2>{{ $t('socialnetwork.vocab.newLanguageTitle') }}</h2>
<div class="box">
<label class="label">
{{ $t('socialnetwork.vocab.languageName') }}
<input v-model="name" type="text" />
</label>
<div class="actions">
<button :disabled="saving || !canSave" @click="create">
{{ saving ? $t('socialnetwork.vocab.saving') : $t('socialnetwork.vocab.create') }}
</button>
<button :disabled="saving" @click="cancel">{{ $t('Cancel') }}</button>
</div>
<div v-if="created" class="created">
<div><strong>{{ $t('socialnetwork.vocab.created') }}</strong></div>
<div>
{{ $t('socialnetwork.vocab.shareCode') }}:
<code>{{ created.shareCode }}</code>
</div>
<div class="hint">{{ $t('socialnetwork.vocab.shareHint') }}</div>
<button @click="openLanguage(created.id)">{{ $t('socialnetwork.vocab.openLanguage') }}</button>
</div>
</div>
</template>
<script>
import { mapActions } from 'vuex';
import apiClient from '@/utils/axios.js';
export default {
name: 'VocabNewLanguageView',
data() {
return {
name: '',
saving: false,
created: null,
};
},
computed: {
canSave() {
return this.name.trim().length >= 2;
},
},
methods: {
...mapActions(['loadMenu']),
cancel() {
this.$router.push('/socialnetwork/vocab');
},
openLanguage(id) {
this.$router.push(`/socialnetwork/vocab/${id}`);
},
async create() {
this.saving = true;
try {
const res = await apiClient.post('/api/vocab/languages', { name: this.name });
this.created = res.data;
// Menü sofort lokal aktualisieren (zusätzlich zum serverseitigen reloadmenu event)
try { await this.loadMenu(); } catch (_) {}
this.$root.$refs.messageDialog?.open(
this.$t('socialnetwork.vocab.createdMessage'),
this.$t('socialnetwork.vocab.createdTitle')
);
} catch (e) {
console.error('Create vocab language failed:', e);
this.$root.$refs.messageDialog?.open(
this.$t('socialnetwork.vocab.createError'),
this.$t('error.title')
);
} finally {
this.saving = false;
}
},
},
};
</script>
<style scoped>
.box {
background: #f6f6f6;
padding: 12px;
border: 1px solid #ccc;
}
.label {
display: block;
margin-bottom: 10px;
}
.actions {
display: flex;
gap: 8px;
}
.created {
margin-top: 12px;
padding: 10px;
background: #fff;
border: 1px solid #bbb;
}
.hint {
margin-top: 6px;
color: #555;
}
</style>