@@ -28,7 +28,7 @@
-
- {{ $t("randomchat.gender.title") }}
+ {{ $t("chat.randomchat.gender.title") }}
-
+
@@ -60,6 +60,7 @@
import DialogWidget from '@/components/DialogWidget.vue';
import { mapGetters } from 'vuex';
import axios from 'axios';
+import DOMPurify from 'dompurify';
export default {
name: 'RandomChatDialog',
@@ -69,7 +70,8 @@ export default {
computed: {
...mapGetters(['isLoggedIn', 'user']),
buttons() {
- return [{ text: this.$t('randomchat.close') }];
+ // Use translation key; DialogWidget will translate when isTitleTranslated=true
+ return [{ text: 'chat.randomchat.close' }];
},
},
data() {
@@ -113,26 +115,6 @@ export default {
this.$refs.dialog.open();
},
- async closeDialog() {
- // ① Stoppe alle laufenden Intervalle
- if (this.searchInterval) {
- clearInterval(this.searchInterval);
- this.searchInterval = null;
- }
- if (this.messagesInterval) {
- clearInterval(this.messagesInterval);
- this.messagesInterval = null;
- }
- // ② verlasse Chat auf Server-Seite
- this.$refs.dialog.close();
- await axios.post('/api/chat/exit', { id: this.userId });
- await this.removeUserFromChat();
- // Reset-Status
- this.chatIsRunning = false;
- this.partner = null;
- this.messages = [];
- },
-
async registerUser() {
try {
const response = await axios.post('/api/chat/register', {
@@ -146,9 +128,29 @@ export default {
},
async closeDialog() {
+ // Stop intervals first
+ if (this.searchInterval) {
+ clearInterval(this.searchInterval);
+ this.searchInterval = null;
+ }
+ if (this.messagesInterval) {
+ clearInterval(this.messagesInterval);
+ this.messagesInterval = null;
+ }
+ // Inform backend and cleanup
+ try {
+ if (this.userId) {
+ await axios.post('/api/chat/exit', { id: this.userId });
+ await this.removeUserFromChat();
+ }
+ } catch (e) {
+ // ignore
+ }
+ // Reset state and close widget
+ this.chatIsRunning = false;
+ this.partner = null;
+ this.messages = [];
this.$refs.dialog.close();
- await axios.post('/api/chat/exit', { id: this.userId });
- await this.removeUserFromChat();
},
async startRandomChat() {
@@ -160,7 +162,7 @@ export default {
async startSearch() {
this.searching = true;
await this.findMatch();
- this.messages.push({ type: 'system', tr: 'randomchat.waitingForMatch' });
+ this.messages.push({ type: 'system', tr: 'chat.randomchat.waitingForMatch' });
this.searchInterval = setInterval(this.findMatch, 500);
},
@@ -174,10 +176,10 @@ export default {
if (response.data.status === 'matched') {
this.searching = false;
clearInterval(this.searchInterval);
- const initText = this.$t('randomchat.chatpartner')
+ const initText = this.$t('chat.randomchat.chatpartner')
.replace(
'
',
- this.$t(`randomchat.partnergender${response.data.user.gender}`)
+ this.$t(`chat.randomchat.partnergender${response.data.user.gender}`)
)
.replace('', response.data.user.age);
this.messages = [{ type: 'system', text: initText }];
@@ -220,7 +222,7 @@ export default {
activities.forEach((act) => {
if (act.activity === 'otheruserleft') {
this.partner = null;
- this.messages.push({ type: 'system', tr: 'randomchat.userleftchat' });
+ this.messages.push({ type: 'system', tr: 'chat.randomchat.userleftchat' });
}
});
this.messages.push(...newMsgs);
@@ -237,10 +239,10 @@ export default {
async nextUser() {
await axios.post('/api/chat/leave', { id: this.userId });
this.partner = null;
- this.messages.push({ type: 'system', tr: 'randomchat.selfstopped' });
+ this.messages.push({ type: 'system', tr: 'chat.randomchat.selfstopped' });
if (this.autosearch) {
this.searchInterval = setInterval(this.findMatch, 500);
- this.messages.push({ type: 'system', tr: 'randomchat.waitingForMatch' });
+ this.messages.push({ type: 'system', tr: 'chat.randomchat.waitingForMatch' });
}
},
@@ -250,7 +252,7 @@ export default {
return `${txt}`;
}
const cls = message.type === 'self' ? 'rc-self' : 'rc-partner';
- const who = message.type === 'self' ? this.$t('randomchat.self') : this.$t('randomchat.partner');
+ const who = message.type === 'self' ? this.$t('chat.randomchat.self') : this.$t('chat.randomchat.partner');
return `${who}: ${message.text}`;
},
},
diff --git a/frontend/src/dialogues/socialnetwork/UserProfileDialog.vue b/frontend/src/dialogues/socialnetwork/UserProfileDialog.vue
index 005c00c..38163e6 100644
--- a/frontend/src/dialogues/socialnetwork/UserProfileDialog.vue
+++ b/frontend/src/dialogues/socialnetwork/UserProfileDialog.vue
@@ -67,7 +67,7 @@
![Entry Image]()
-
+
{{ new Date(entry.createdAt).toLocaleString() }}
@@ -96,6 +96,7 @@ import apiClient from '@/utils/axios.js';
import FolderItem from '../../components/FolderItem.vue';
import { Editor, EditorContent } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'
+import DOMPurify from 'dompurify';
export default {
name: 'UserProfileDialog',
@@ -369,7 +370,10 @@ export default {
} else {
this.friendshipState = 'waiting';
}
- }
+ },
+ sanitizedContent(entry) {
+ return DOMPurify.sanitize(entry.contentHtml);
+ },
}
};
diff --git a/frontend/src/dialogues/standard/DataPrivacyDialog.vue b/frontend/src/dialogues/standard/DataPrivacyDialog.vue
index 83c8fae..3cc65bf 100644
--- a/frontend/src/dialogues/standard/DataPrivacyDialog.vue
+++ b/frontend/src/dialogues/standard/DataPrivacyDialog.vue
@@ -11,13 +11,14 @@
@ok="handleOk"
name="DataPrivacyDialog"
>
-
+
-
\ No newline at end of file
diff --git a/frontend/src/views/admin/RoomsView.vue b/frontend/src/views/admin/RoomsView.vue
new file mode 100644
index 0000000..75f8f85
--- /dev/null
+++ b/frontend/src/views/admin/RoomsView.vue
@@ -0,0 +1,113 @@
+
+
+
{{ $t('admin.chatrooms.title') }}
+
+
+
+
+ | {{ $t('admin.chatrooms.roomName') }} |
+ {{ $t('admin.chatrooms.type') }} |
+ {{ $t('admin.chatrooms.isPublic') }} |
+ {{ $t('admin.chatrooms.actions') }} |
+
+
+
+
+ | {{ room.title }} |
+ {{ room.roomTypeTr || room.roomTypeId }} |
+ {{ room.isPublic ? $t('common.yes') : $t('common.no') }} |
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/views/home/NoLoginView.vue b/frontend/src/views/home/NoLoginView.vue
index 70b7c2d..b899fe8 100644
--- a/frontend/src/views/home/NoLoginView.vue
+++ b/frontend/src/views/home/NoLoginView.vue
@@ -68,13 +68,16 @@ export default {
methods: {
...mapActions(['login']),
openRandomChat() {
- this.$refs.randomChatDialog.open();
+ const dlg = this.$refs.randomChatDialog;
+ if (dlg && typeof dlg.open === 'function') dlg.open();
},
openRegisterDialog() {
- this.$refs.registerDialog.open();
+ const dlg = this.$refs.registerDialog;
+ if (dlg && typeof dlg.open === 'function') dlg.open();
},
openPasswordResetDialog() {
- this.$refs.passwordResetDialog.open();
+ const dlg = this.$refs.passwordResetDialog;
+ if (dlg && typeof dlg.open === 'function') dlg.open();
},
focusPassword() {
this.$refs.passwordInput.focus();
diff --git a/frontend/src/views/social/DiaryView.vue b/frontend/src/views/social/DiaryView.vue
index dd576f1..37ddf08 100644
--- a/frontend/src/views/social/DiaryView.vue
+++ b/frontend/src/views/social/DiaryView.vue
@@ -14,7 +14,7 @@
{{ $t('socialnetwork.diary.noEntries') }}
-
+
{{ new Date(entry.createdAt).toLocaleString() }}
@@ -39,6 +39,7 @@
import { mapGetters } from 'vuex';
import apiClient from '@/utils/axios.js';
import ChooseDialog from "@/dialogues/standard/ChooseDialog.vue";
+import DOMPurify from 'dompurify';
export default {
name: 'DiaryView',
@@ -59,6 +60,9 @@ export default {
...mapGetters(['user']),
},
methods: {
+ sanitizedText(entry) {
+ return DOMPurify.sanitize(entry.text);
+ },
async loadDiaryEntries(page) {
try {
console.log(page);
diff --git a/frontend/src/views/social/ForumTopicView.vue b/frontend/src/views/social/ForumTopicView.vue
index d815a9f..d1748ac 100644
--- a/frontend/src/views/social/ForumTopicView.vue
+++ b/frontend/src/views/social/ForumTopicView.vue
@@ -3,7 +3,7 @@
{{ forumTopic }}