250 lines
8.5 KiB
Vue
250 lines
8.5 KiB
Vue
<template>
|
|
<div class="account-settings">
|
|
<section class="account-settings__hero surface-card">
|
|
<span class="account-settings__eyebrow">Einstellungen</span>
|
|
<h2>{{ $t("settings.account.title") }}</h2>
|
|
<p>Benutzername, E-Mail, Passwort und Sichtbarkeit an einer Stelle pflegen.</p>
|
|
</section>
|
|
|
|
<section class="account-settings__panel surface-card">
|
|
<div class="account-settings__grid">
|
|
<label class="account-settings__field">
|
|
<span>{{ $t("settings.account.username") }}</span>
|
|
<input type="text" v-model="username" :placeholder="$t('settings.account.username')" />
|
|
</label>
|
|
|
|
<label class="account-settings__field">
|
|
<span>{{ $t("settings.account.email") }}</span>
|
|
<input type="text" v-model="email" :placeholder="$t('settings.account.email')" />
|
|
</label>
|
|
|
|
<label class="account-settings__field">
|
|
<span>{{ $t("settings.account.newpassword") }}</span>
|
|
<input type="password" v-model="newpassword" :placeholder="$t('settings.account.newpassword')"
|
|
autocomplete="new-password" :class="{ 'field-error': newpassword && !isNewPasswordValid }" />
|
|
<span v-if="newpassword && !isNewPasswordValid" class="form-error">Das neue Passwort sollte mindestens 8 Zeichen haben.</span>
|
|
</label>
|
|
|
|
<label class="account-settings__field">
|
|
<span>{{ $t("settings.account.newpasswordretype") }}</span>
|
|
<input type="password" v-model="newpasswordretype"
|
|
:placeholder="$t('settings.account.newpasswordretype')" autocomplete="new-password"
|
|
:class="{ 'field-error': newpasswordretype && !passwordsMatch }" />
|
|
<span v-if="newpasswordretype && !passwordsMatch" class="form-error">Die Passwörter stimmen nicht überein.</span>
|
|
</label>
|
|
|
|
<label class="account-settings__field account-settings__field--full">
|
|
<span>{{ $t("settings.account.oldpassword") }}</span>
|
|
<input type="password" v-model="oldpassword" :placeholder="$t('settings.account.oldpassword')"
|
|
autocomplete="current-password" :class="{ 'field-error': requiresOldPassword && !oldpassword.trim() }" />
|
|
<span v-if="requiresOldPassword && !oldpassword.trim()" class="form-error">Zum Passwortwechsel wird das aktuelle Passwort benötigt.</span>
|
|
</label>
|
|
</div>
|
|
|
|
<label class="account-settings__toggle">
|
|
<input type="checkbox" v-model="showInSearch" />
|
|
<span>{{ $t("settings.account.showinsearch") }}</span>
|
|
</label>
|
|
|
|
<div class="account-settings__actions">
|
|
<button @click="changeAccount">{{ $t("settings.account.changeaction") }}</button>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import apiClient from '@/utils/axios.js';
|
|
import { mapGetters } from 'vuex';
|
|
import { showApiError, showError, showSuccess } from '@/utils/feedback.js';
|
|
|
|
export default {
|
|
name: "AccountSettingsView",
|
|
components: {},
|
|
data() {
|
|
return {
|
|
username: "",
|
|
email: "",
|
|
newpassword: "",
|
|
newpasswordretype: "",
|
|
showInSearch: false,
|
|
oldpassword: "",
|
|
};
|
|
},
|
|
computed: {
|
|
...mapGetters(['user']),
|
|
requiresOldPassword() {
|
|
return this.newpassword.trim().length > 0;
|
|
},
|
|
isNewPasswordValid() {
|
|
return this.newpassword.length === 0 || this.newpassword.length >= 8;
|
|
},
|
|
passwordsMatch() {
|
|
return this.newpassword === this.newpasswordretype;
|
|
}
|
|
},
|
|
methods: {
|
|
async changeAccount() {
|
|
try {
|
|
// Prüfe ob ein neues Passwort eingegeben wurde
|
|
const hasNewPassword = this.newpassword && this.newpassword.trim() !== '';
|
|
|
|
if (hasNewPassword) {
|
|
if (!this.isNewPasswordValid) {
|
|
showError(this, 'Das neue Passwort ist noch zu kurz.');
|
|
return;
|
|
}
|
|
// Validiere Passwort-Wiederholung nur wenn ein neues Passwort eingegeben wurde
|
|
if (!this.passwordsMatch) {
|
|
showError(this, 'Die Passwörter stimmen nicht überein.');
|
|
return;
|
|
}
|
|
|
|
// Prüfe ob das alte Passwort eingegeben wurde
|
|
if (!this.oldpassword || this.oldpassword.trim() === '') {
|
|
showError(this, 'Bitte geben Sie Ihr aktuelles Passwort ein, um das Passwort zu ändern.');
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Bereite die Daten für den API-Aufruf vor
|
|
const accountData = {
|
|
userId: this.user.id,
|
|
settings: {
|
|
username: this.username,
|
|
email: this.email,
|
|
showinsearch: this.showInSearch
|
|
}
|
|
};
|
|
|
|
// Füge Passwort-Daten nur hinzu, wenn ein neues Passwort eingegeben wurde
|
|
if (hasNewPassword) {
|
|
accountData.settings.newpassword = this.newpassword;
|
|
accountData.settings.oldpassword = this.oldpassword;
|
|
}
|
|
|
|
// API-Aufruf zum Speichern der Account-Einstellungen
|
|
await apiClient.post('/api/settings/set-account', accountData);
|
|
|
|
showSuccess(this, 'Account-Einstellungen erfolgreich gespeichert.');
|
|
|
|
// Leere die Passwort-Felder nach erfolgreichem Speichern
|
|
this.newpassword = '';
|
|
this.newpasswordretype = '';
|
|
this.oldpassword = '';
|
|
|
|
} catch (error) {
|
|
console.error('Fehler beim Speichern der Account-Einstellungen:', error);
|
|
showApiError(this, error, 'Ein Fehler ist beim Speichern der Account-Einstellungen aufgetreten.');
|
|
}
|
|
}
|
|
},
|
|
async mounted() {
|
|
const response = await apiClient.post('/api/settings/account', { userId: this.user.id });
|
|
this.username = response.data.username;
|
|
this.showInSearch = response.data.showinsearch;
|
|
this.email = response.data.email;
|
|
|
|
// Stelle sicher, dass Passwort-Felder leer sind
|
|
this.newpassword = '';
|
|
this.newpasswordretype = '';
|
|
this.oldpassword = '';
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.account-settings {
|
|
display: grid;
|
|
gap: 18px;
|
|
max-width: 960px;
|
|
}
|
|
|
|
.account-settings__hero,
|
|
.account-settings__panel {
|
|
background: linear-gradient(180deg, rgba(255, 252, 247, 0.97), rgba(250, 244, 235, 0.95));
|
|
border: 1px solid var(--color-border);
|
|
border-radius: var(--radius-lg);
|
|
box-shadow: var(--shadow-soft);
|
|
}
|
|
|
|
.account-settings__hero {
|
|
padding: 26px 28px;
|
|
}
|
|
|
|
.account-settings__eyebrow {
|
|
display: inline-flex;
|
|
margin-bottom: 8px;
|
|
padding: 4px 10px;
|
|
border-radius: var(--radius-pill);
|
|
background: var(--color-primary-soft);
|
|
color: var(--color-text-secondary);
|
|
font-size: 0.78rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.account-settings__hero p {
|
|
margin: 0;
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
.account-settings__panel {
|
|
padding: 24px;
|
|
}
|
|
|
|
.account-settings__grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
gap: 16px;
|
|
}
|
|
|
|
.account-settings__field {
|
|
display: grid;
|
|
gap: 8px;
|
|
}
|
|
|
|
.account-settings__field span {
|
|
font-weight: 600;
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
.account-settings__field--full {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
.account-settings__toggle {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
margin-top: 18px;
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
.account-settings__actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
margin-top: 18px;
|
|
}
|
|
|
|
@media (max-width: 760px) {
|
|
.account-settings__grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.account-settings__hero,
|
|
.account-settings__panel {
|
|
padding: 20px;
|
|
}
|
|
|
|
.account-settings__actions {
|
|
justify-content: stretch;
|
|
}
|
|
|
|
.account-settings__actions button {
|
|
width: 100%;
|
|
}
|
|
}
|
|
</style>
|