Implement room creation panel in MultiChatDialog: Add functionality for users to create new chat rooms with customizable settings, including visibility, age restrictions, and password protection. Enhance UI with a toggle button and form for room details.

This commit is contained in:
Torsten Schulz (local)
2026-03-04 22:42:48 +01:00
parent db8be34607
commit e76fdbe1ab

View File

@@ -3,9 +3,14 @@
@close="onDialogClose" width="75vw" height="75vh" name="MultiChatDialog" icon="multichat24.png"> @close="onDialogClose" width="75vw" height="75vh" name="MultiChatDialog" icon="multichat24.png">
<div class="dialog-widget-content"> <div class="dialog-widget-content">
<div class="multi-chat-top"> <div class="multi-chat-top">
<select v-model="selectedRoom" class="room-select"> <div class="room-left-controls">
<select v-model="selectedRoom" class="room-select">
<option v-for="room in rooms" :key="room.id" :value="room.id">{{ room.title }}</option> <option v-for="room in rooms" :key="room.id" :value="room.id">{{ room.title }}</option>
</select> </select>
<button class="create-room-toggle-btn" type="button" @click="toggleRoomCreatePanel">
{{ showRoomCreatePanel ? 'Chat anzeigen' : 'Raum anlegen' }}
</button>
</div>
<div class="right-controls"> <div class="right-controls">
<div class="status" :class="statusType"> <div class="status" :class="statusType">
<span class="dot"></span> <span class="dot"></span>
@@ -31,7 +36,7 @@
</div> </div>
</div> </div>
<div v-if="!showColorPicker" class="multi-chat-body"> <div v-if="!showColorPicker" class="multi-chat-body">
<div class="multi-chat-output" ref="output" @mouseenter="mouseOverOutput = true" <div v-if="!showRoomCreatePanel" class="multi-chat-output" ref="output" @mouseenter="mouseOverOutput = true"
@mouseleave="mouseOverOutput = false"> @mouseleave="mouseOverOutput = false">
<div v-for="msg in messages" :key="msg.id" class="chat-message"> <div v-for="msg in messages" :key="msg.id" class="chat-message">
<template v-if="msg.type === 'scream'"> <template v-if="msg.type === 'scream'">
@@ -53,6 +58,71 @@
</template> </template>
</div> </div>
</div> </div>
<div v-else class="room-create-panel">
<div class="room-create-title">Neuen Raum erstellen</div>
<div class="room-create-grid">
<label>
Raumname *
<input v-model.trim="roomCreateForm.roomName" type="text" placeholder="z. B. Lounge" />
</label>
<label>
Sichtbarkeit
<select v-model="roomCreateForm.visibility">
<option value="">(keine)</option>
<option value="public">public</option>
<option value="private">private</option>
</select>
</label>
<label>
public=true|false
<select v-model="roomCreateForm.publicFlag">
<option value="">(keine)</option>
<option value="true">true</option>
<option value="false">false</option>
</select>
</label>
<label>
gender
<select v-model="roomCreateForm.gender">
<option value="">(keine)</option>
<option value="m">m</option>
<option value="f">f</option>
<option value="any">any</option>
</select>
</label>
<label>
min_age
<input v-model.number="roomCreateForm.minAge" type="number" min="0" />
</label>
<label>
max_age
<input v-model.number="roomCreateForm.maxAge" type="number" min="0" />
</label>
<label>
Passwort
<input v-model.trim="roomCreateForm.password" type="text" placeholder="ohne Leerzeichen" />
</label>
<label>
right_id
<input v-model.number="roomCreateForm.rightId" type="number" min="1" />
</label>
<label>
type_id
<input v-model.number="roomCreateForm.typeId" type="number" min="1" />
</label>
<label class="checkbox-label">
<input type="checkbox" v-model="roomCreateForm.friendsOnly" />
friends_only=true
</label>
</div>
<div class="room-create-actions">
<button type="button" class="send-btn" @click="sendCreateRoomCommand">Raum erstellen</button>
<button type="button" class="create-room-reset-btn" @click="resetRoomCreateForm">Zurücksetzen</button>
</div>
<div class="room-create-preview">
Kommando: <code>{{ buildRoomCreateCommandPreview() || '/cr <raumname>' }}</code>
</div>
</div>
<div class="user-list"> <div class="user-list">
<div class="user-list-header">Teilnehmer ({{ usersInRoom.length }})</div> <div class="user-list-header">Teilnehmer ({{ usersInRoom.length }})</div>
<div class="user-list-items"> <div class="user-list-items">
@@ -168,10 +238,23 @@ export default {
token: null, token: null,
announcedRoomEnter: false, announcedRoomEnter: false,
showColorPicker: false, showColorPicker: false,
showRoomCreatePanel: false,
selectedColor: '#000000', selectedColor: '#000000',
lastColor: '#000000', lastColor: '#000000',
hexInput: '#000000', hexInput: '#000000',
hexInvalid: false, hexInvalid: false,
roomCreateForm: {
roomName: '',
visibility: '',
publicFlag: '',
gender: '',
minAge: null,
maxAge: null,
password: '',
friendsOnly: false,
rightId: null,
typeId: null
},
// Palette state // Palette state
paletteWidth: 420, paletteWidth: 420,
paletteHeight: 220, paletteHeight: 220,
@@ -224,6 +307,85 @@ export default {
} }
}, },
methods: { methods: {
getDefaultRoomCreateForm() {
return {
roomName: '',
visibility: '',
publicFlag: '',
gender: '',
minAge: null,
maxAge: null,
password: '',
friendsOnly: false,
rightId: null,
typeId: null
};
},
toggleRoomCreatePanel() {
this.showRoomCreatePanel = !this.showRoomCreatePanel;
if (!this.showRoomCreatePanel) return;
this.showColorPicker = false;
},
resetRoomCreateForm() {
this.roomCreateForm = this.getDefaultRoomCreateForm();
},
buildRoomCreateCommandPreview() {
return this.buildRoomCreateCommand();
},
buildRoomCreateCommand() {
const name = (this.roomCreateForm.roomName || '').trim();
if (!name) return '';
const parts = ['/cr', name];
if (this.roomCreateForm.visibility) parts.push(this.roomCreateForm.visibility);
if (this.roomCreateForm.publicFlag === 'true' || this.roomCreateForm.publicFlag === 'false') {
parts.push(`public=${this.roomCreateForm.publicFlag}`);
}
if (this.roomCreateForm.gender) parts.push(`gender=${this.roomCreateForm.gender}`);
if (Number.isInteger(this.roomCreateForm.minAge) && this.roomCreateForm.minAge >= 0) {
parts.push(`min_age=${this.roomCreateForm.minAge}`);
}
if (Number.isInteger(this.roomCreateForm.maxAge) && this.roomCreateForm.maxAge >= 0) {
parts.push(`max_age=${this.roomCreateForm.maxAge}`);
}
const password = (this.roomCreateForm.password || '').trim();
if (password) parts.push(`password=${password}`);
if (this.roomCreateForm.friendsOnly) parts.push('friends_only=true');
if (Number.isInteger(this.roomCreateForm.rightId) && this.roomCreateForm.rightId > 0) {
parts.push(`right_id=${this.roomCreateForm.rightId}`);
}
if (Number.isInteger(this.roomCreateForm.typeId) && this.roomCreateForm.typeId > 0) {
parts.push(`type_id=${this.roomCreateForm.typeId}`);
}
return parts.join(' ');
},
requestRoomRefreshAfterCreate() {
const requestRooms = () => {
if (this.isAdmin) this.sendWithToken({ type: 'reload_rooms' });
this.sendWithToken({ type: 'rooms' });
};
setTimeout(requestRooms, 500);
setTimeout(requestRooms, 1800);
},
sendCreateRoomCommand() {
if (!this.transportConnected) {
this.messages.push({ id: Date.now(), user: 'System', text: 'Keine Verbindung zum Chat-Server.' });
return;
}
const command = this.buildRoomCreateCommand();
if (!command) {
this.messages.push({ id: Date.now(), user: 'System', text: 'Bitte einen Raumnamen angeben.' });
return;
}
if ((this.roomCreateForm.password || '').includes(' ')) {
this.messages.push({ id: Date.now(), user: 'System', text: 'Passwort darf keine Leerzeichen enthalten.' });
return;
}
const payload = { type: 'message', message: command };
if (this.debug) console.log('[Chat WS >>]', payload);
this.sendWithToken(payload);
this.messages.push({ id: Date.now(), user: 'System', text: `Raum-Erstellung gesendet: ${command}` });
this.requestRoomRefreshAfterCreate();
},
selectTargetUser(name) { selectTargetUser(name) {
if (this.selectedTargetUser === name) { if (this.selectedTargetUser === name) {
this.selectedTargetUser = null; // toggle off this.selectedTargetUser = null; // toggle off
@@ -319,6 +481,7 @@ export default {
this.selectedTargetUser = null; this.selectedTargetUser = null;
this.input = ''; this.input = '';
this.showOptions = false; this.showOptions = false;
this.showRoomCreatePanel = false;
this.announcedRoomEnter = false; this.announcedRoomEnter = false;
this.$refs.dialog.open(); this.$refs.dialog.open();
// Stelle die WS-Verbindung her, wenn der Dialog geöffnet wird // Stelle die WS-Verbindung her, wenn der Dialog geöffnet wird
@@ -1481,10 +1644,24 @@ export default {
justify-content: space-between; justify-content: space-between;
} }
.room-left-controls {
display: flex;
align-items: center;
gap: 0.5em;
}
.room-select { .room-select {
min-width: 10em; min-width: 10em;
} }
.create-room-toggle-btn {
border: 1px solid #bbb;
background: #f5f5f5;
border-radius: 4px;
padding: 0.3em 0.8em;
cursor: pointer;
}
.right-controls { .right-controls {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -1591,6 +1768,64 @@ export default {
border: 1px solid #222; border: 1px solid #222;
} }
.room-create-panel {
border: 1px solid #222;
border-radius: 4px;
background: #fff;
padding: 0.7em;
overflow-y: auto;
}
.room-create-title {
font-weight: bold;
margin-bottom: 0.6em;
}
.room-create-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.6em;
}
.room-create-grid label {
display: flex;
flex-direction: column;
gap: 0.25em;
}
.room-create-grid input,
.room-create-grid select {
border: 1px solid #bbb;
border-radius: 3px;
padding: 0.35em 0.5em;
}
.checkbox-label {
flex-direction: row !important;
align-items: center;
gap: 0.4em !important;
}
.room-create-actions {
display: flex;
gap: 0.5em;
margin-top: 0.8em;
}
.create-room-reset-btn {
border: 1px solid #bbb;
background: #eee;
border-radius: 3px;
padding: 0.3em 0.8em;
cursor: pointer;
}
.room-create-preview {
margin-top: 0.7em;
font-size: 0.9em;
color: #444;
}
.chat-message { .chat-message {
margin-bottom: 0.3em; margin-bottom: 0.3em;
} }