feat(navigation): enhance adult verification handling and notifications

- Updated navigationController to simplify the eroticChat menu structure.
- Enhanced adminService to notify users of adult verification status changes, including previous status.
- Improved AppNavigation and related components to register and unregister socket listeners for adult verification updates.
- Added localized messages for adult verification notifications in English, German, and Spanish.
- Introduced a verification hint in the EroticAccessView to guide users on document submission.
This commit is contained in:
Torsten Schulz (local)
2026-03-27 13:23:44 +01:00
parent 82223676a6
commit 07604cc9fa
8 changed files with 175 additions and 35 deletions

View File

@@ -69,7 +69,7 @@
<script>
import apiClient from '@/utils/axios.js';
import { mapGetters } from 'vuex';
import { showApiError, showError, showSuccess } from '@/utils/feedback.js';
import { showApiError, showError, showInfo, showSuccess } from '@/utils/feedback.js';
export default {
name: "AccountSettingsView",
@@ -88,7 +88,7 @@ export default {
};
},
computed: {
...mapGetters(['user']),
...mapGetters(['user', 'socket']),
requiresOldPassword() {
return this.newpassword.trim().length > 0;
},
@@ -115,6 +115,33 @@ export default {
}
},
methods: {
async loadAccount() {
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;
this.isAdult = !!response.data.isAdult;
this.adultVerificationStatus = response.data.adultVerificationStatus || 'none';
this.adultVerificationRequest = response.data.adultVerificationRequest || null;
},
registerSocketListeners(sock) {
if (!sock) return;
this._adultVerificationChangedHandler = async (payload = {}) => {
await this.loadAccount();
if (payload.status === 'approved') {
showInfo(this, this.$t('socialnetwork.erotic.notifications.approved'));
} else if (payload.status === 'rejected') {
showInfo(this, this.$t('socialnetwork.erotic.notifications.rejected'));
}
};
sock.on('adultVerificationChanged', this._adultVerificationChangedHandler);
},
unregisterSocketListeners() {
if (this.socket && this._adultVerificationChangedHandler) {
this.socket.off('adultVerificationChanged', this._adultVerificationChangedHandler);
}
this._adultVerificationChangedHandler = null;
},
async changeAccount() {
try {
// Prüfe ob ein neues Passwort eingegeben wurde
@@ -172,19 +199,27 @@ export default {
},
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;
this.isAdult = !!response.data.isAdult;
this.adultVerificationStatus = response.data.adultVerificationStatus || 'none';
this.adultVerificationRequest = response.data.adultVerificationRequest || null;
if (this.socket) {
this.registerSocketListeners(this.socket);
}
await this.loadAccount();
// Stelle sicher, dass Passwort-Felder leer sind
this.newpassword = '';
this.newpasswordretype = '';
this.oldpassword = '';
},
watch: {
socket(newSocket) {
this.unregisterSocketListeners();
if (newSocket) {
this.registerSocketListeners(newSocket);
}
}
},
beforeUnmount() {
this.unregisterSocketListeners();
}
};
</script>

View File

@@ -27,6 +27,11 @@
</router-link>
</div>
<div class="erotic-access-hint">
<strong>{{ $t('socialnetwork.erotic.verificationHintTitle') }}</strong>
<span>{{ $t('socialnetwork.erotic.verificationHintBody') }}</span>
</div>
<form v-if="canRequestVerification" class="erotic-access-form" @submit.prevent="requestVerification">
<label>
<span>{{ $t('socialnetwork.erotic.documentLabel') }}</span>
@@ -47,7 +52,7 @@
<script>
import apiClient from '@/utils/axios.js';
import { mapGetters } from 'vuex';
import { showApiError, showSuccess } from '@/utils/feedback.js';
import { showApiError, showInfo, showSuccess } from '@/utils/feedback.js';
export default {
name: 'EroticAccessView',
@@ -59,7 +64,7 @@ export default {
};
},
computed: {
...mapGetters(['user']),
...mapGetters(['user', 'socket']),
status() {
return this.account?.adultVerificationStatus || 'none';
},
@@ -89,6 +94,25 @@ export default {
const response = await apiClient.post('/api/settings/account', { userId: this.user.id });
this.account = response.data;
},
registerSocketListeners(sock) {
if (!sock) return;
this._adultVerificationChangedHandler = async (payload = {}) => {
await this.loadAccount();
if (payload.status === 'approved') {
showInfo(this, this.$t('socialnetwork.erotic.notifications.approved'));
this.$router.replace('/socialnetwork/erotic/pictures');
} else if (payload.status === 'rejected') {
showInfo(this, this.$t('socialnetwork.erotic.notifications.rejected'));
}
};
sock.on('adultVerificationChanged', this._adultVerificationChangedHandler);
},
unregisterSocketListeners() {
if (this.socket && this._adultVerificationChangedHandler) {
this.socket.off('adultVerificationChanged', this._adultVerificationChangedHandler);
}
this._adultVerificationChangedHandler = null;
},
handleFileChange(event) {
this.documentFile = event.target.files?.[0] || null;
},
@@ -114,10 +138,24 @@ export default {
}
},
async mounted() {
if (this.socket) {
this.registerSocketListeners(this.socket);
}
await this.loadAccount();
if (this.account?.adultAccessEnabled) {
this.$router.replace('/socialnetwork/erotic/pictures');
}
},
watch: {
socket(newSocket) {
this.unregisterSocketListeners();
if (newSocket) {
this.registerSocketListeners(newSocket);
}
}
},
beforeUnmount() {
this.unregisterSocketListeners();
}
};
</script>
@@ -175,7 +213,8 @@ export default {
}
.erotic-access-request,
.erotic-access-form {
.erotic-access-form,
.erotic-access-hint {
display: grid;
gap: 10px;
}
@@ -187,6 +226,13 @@ export default {
color: var(--color-text-secondary);
}
.erotic-access-hint {
padding: 14px 16px;
border-radius: var(--radius-md);
background: rgba(164, 98, 72, 0.08);
color: var(--color-text-secondary);
}
.erotic-access-actions {
display: flex;
gap: 12px;