Refactor chat interface and enhance user experience
- Updated the ChatWindow component to provide clearer instructions and actions when no conversation is selected, improving user guidance. - Redesigned the MenuBar to display session timeout information more effectively. - Enhanced the SearchView component with a more user-friendly country selection using a Multiselect dropdown. - Improved the UserList component to display user age and gender, enhancing user profile visibility. - Updated various views (ChatView, FaqView, FeedbackView, PartnersView, RulesView, SafetyView) to include a consistent app branding link for better navigation. These changes collectively enhance the chat interface, improve user engagement, and streamline navigation across the application.
This commit is contained in:
@@ -1,79 +1,141 @@
|
||||
<template>
|
||||
<div class="chat-container">
|
||||
<header class="header">
|
||||
<div class="app-brand">
|
||||
<span class="app-brand-mark">S</span>
|
||||
<div class="app-brand-copy">
|
||||
<span class="app-brand-eyebrow">SingleChat</span>
|
||||
<h1>Chat</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="chatStore.isLoggedIn" class="header-status">
|
||||
<span class="header-status-chip">{{ chatStore.userName }}</span>
|
||||
<span v-if="chatStore.isoCountryCode" class="header-status-chip">{{ chatStore.isoCountryCode }}</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<MenuBar v-if="chatStore.isLoggedIn" />
|
||||
|
||||
<div class="horizontal-box" :class="{ 'horizontal-box-login': !chatStore.isLoggedIn, 'horizontal-box-app': chatStore.isLoggedIn }">
|
||||
<UserList v-if="chatStore.isLoggedIn" />
|
||||
|
||||
<div class="content">
|
||||
<div v-if="!chatStore.isLoggedIn" class="login-screen">
|
||||
<LoginForm />
|
||||
</div>
|
||||
|
||||
<div v-else class="main-content-wrapper">
|
||||
<div v-if="chatStore.errorMessage" class="error-message">
|
||||
{{ chatStore.errorMessage }}
|
||||
<div class="chat-container" :class="{ 'chat-container-auth': chatStore.isLoggedIn }">
|
||||
<template v-if="chatStore.isLoggedIn">
|
||||
<div class="auth-main-layout">
|
||||
<aside class="app-sidebar">
|
||||
<div class="sidebar-brand">
|
||||
<strong>SingleChat</strong>
|
||||
<span>Online Chat</span>
|
||||
</div>
|
||||
<div v-if="chatStore.commandTable" class="command-table-container">
|
||||
<div class="command-table-header">
|
||||
<strong>{{ chatStore.commandTable.title }}</strong>
|
||||
<button class="command-table-close" @click="chatStore.clearCommandTable()">Schließen</button>
|
||||
</div>
|
||||
<div class="command-table-scroll">
|
||||
<table class="command-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="(column, idx) in chatStore.commandTable.columns" :key="`head-${idx}`">
|
||||
{{ column }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIdx) in chatStore.commandTable.rows" :key="`row-${rowIdx}`">
|
||||
<td v-for="(cell, cellIdx) in row" :key="`cell-${rowIdx}-${cellIdx}`">
|
||||
{{ cell }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<nav class="sidebar-nav" aria-label="Hauptnavigation">
|
||||
<button
|
||||
type="button"
|
||||
:class="{ 'is-active': chatStore.currentView === 'chat' }"
|
||||
@click="goLobby"
|
||||
>
|
||||
<span class="nav-icon" aria-hidden="true">🏠</span>
|
||||
Lobby
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="{ 'is-active': chatStore.currentView === 'inbox', 'has-unread': chatStore.unreadChatsCount > 0 }"
|
||||
@click="chatStore.setView('inbox')"
|
||||
>
|
||||
<span class="nav-icon" aria-hidden="true">📥</span>
|
||||
{{ $t('menu_inbox') }}
|
||||
<span v-if="chatStore.unreadChatsCount > 0" class="sidebar-badge">{{ chatStore.unreadChatsCount }}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="{ 'is-active': chatStore.currentView === 'history' }"
|
||||
@click="chatStore.setView('history')"
|
||||
>
|
||||
<span class="nav-icon" aria-hidden="true">🕘</span>
|
||||
{{ $t('menu_history') }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
:class="{ 'is-active': chatStore.currentView === 'search' }"
|
||||
@click="chatStore.setView('search')"
|
||||
>
|
||||
<span class="nav-icon" aria-hidden="true">🔎</span>
|
||||
{{ $t('menu_search') }}
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div class="sidebar-profile">
|
||||
<span class="profile-avatar">{{ userInitials }}</span>
|
||||
<span>
|
||||
<strong>{{ chatStore.userName }}</strong>
|
||||
<small>{{ chatStore.country || 'SingleChat Member' }}</small>
|
||||
</span>
|
||||
</div>
|
||||
<SearchView v-if="chatStore.currentView === 'search'" />
|
||||
<InboxView v-else-if="chatStore.currentView === 'inbox'" />
|
||||
<HistoryView v-else-if="chatStore.currentView === 'history'" />
|
||||
<div v-else class="chat-content">
|
||||
<div v-if="chatStore.currentConversation && currentUserInfo" class="chat-header">
|
||||
<span :class="['chat-header-accent', 'chat-header-accent-' + currentUserInfo.gender]"></span>
|
||||
<div class="chat-header-main">
|
||||
<h2>{{ chatStore.currentConversation }}</h2>
|
||||
<div class="chat-header-info">
|
||||
<span v-if="currentUserInfo">{{ currentUserInfo.country }}</span>
|
||||
<span v-if="currentUserInfo">{{ currentUserInfo.age }} · {{ currentUserInfo.gender }}</span>
|
||||
</aside>
|
||||
|
||||
<section class="app-workspace">
|
||||
<header class="workspace-header">
|
||||
<h1>{{ pageTitle }}</h1>
|
||||
<MenuBar />
|
||||
<button type="button" class="icon-button" :title="chatStore.userName">{{ userInitials }}</button>
|
||||
</header>
|
||||
|
||||
<div class="horizontal-box horizontal-box-app">
|
||||
<UserList />
|
||||
|
||||
<div class="content">
|
||||
<div class="main-content-wrapper">
|
||||
<div v-if="chatStore.errorMessage" class="error-message">
|
||||
{{ chatStore.errorMessage }}
|
||||
</div>
|
||||
<div v-if="chatStore.commandTable" class="command-table-container">
|
||||
<div class="command-table-header">
|
||||
<strong>{{ chatStore.commandTable.title }}</strong>
|
||||
<button class="command-table-close" @click="chatStore.clearCommandTable()">Schließen</button>
|
||||
</div>
|
||||
<div class="command-table-scroll">
|
||||
<table class="command-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="(column, idx) in chatStore.commandTable.columns" :key="`head-${idx}`">
|
||||
{{ column }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(row, rowIdx) in chatStore.commandTable.rows" :key="`row-${rowIdx}`">
|
||||
<td v-for="(cell, cellIdx) in row" :key="`cell-${rowIdx}-${cellIdx}`">
|
||||
{{ cell }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<SearchView v-if="chatStore.currentView === 'search'" />
|
||||
<InboxView v-else-if="chatStore.currentView === 'inbox'" />
|
||||
<HistoryView v-else-if="chatStore.currentView === 'history'" />
|
||||
<div v-else class="chat-content">
|
||||
<div v-if="chatStore.currentConversation && currentUserInfo" class="chat-header">
|
||||
<span :class="['chat-header-accent', 'chat-header-accent-' + currentUserInfo.gender]"></span>
|
||||
<div class="chat-header-main">
|
||||
<h2>{{ chatStore.currentConversation }}</h2>
|
||||
<div class="chat-header-info">
|
||||
<span v-if="currentUserInfo">{{ currentUserInfo.country }}</span>
|
||||
<span v-if="currentUserInfo">{{ currentUserInfo.age }} · {{ currentUserInfo.gender }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ChatWindow />
|
||||
</div>
|
||||
<ChatInput />
|
||||
</div>
|
||||
</div>
|
||||
<ChatWindow />
|
||||
</div>
|
||||
<ChatInput />
|
||||
</section>
|
||||
</div>
|
||||
<ImprintContainer />
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<header class="header">
|
||||
<div class="app-brand">
|
||||
<span class="app-brand-mark">S</span>
|
||||
<div class="app-brand-copy">
|
||||
<span class="app-brand-eyebrow">SingleChat</span>
|
||||
<h1>Chat</h1>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="horizontal-box horizontal-box-login">
|
||||
<div class="content login-content-shell">
|
||||
<div class="login-screen">
|
||||
<LoginForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ImprintContainer />
|
||||
<ImprintContainer />
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -92,6 +154,29 @@ import ImprintContainer from '../components/ImprintContainer.vue';
|
||||
|
||||
const chatStore = useChatStore();
|
||||
|
||||
const userInitials = computed(() => {
|
||||
return (chatStore.userName || 'SC')
|
||||
.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.slice(0, 2)
|
||||
.map(part => part.charAt(0).toUpperCase())
|
||||
.join('') || 'SC';
|
||||
});
|
||||
|
||||
const pageTitle = computed(() => {
|
||||
if (chatStore.currentView === 'search') return 'Suchen';
|
||||
if (chatStore.currentView === 'inbox') return 'Posteingang';
|
||||
if (chatStore.currentView === 'history') return 'Verlauf';
|
||||
if (chatStore.currentConversation) return chatStore.currentConversation;
|
||||
return 'Lobby';
|
||||
});
|
||||
|
||||
function goLobby() {
|
||||
chatStore.currentConversation = null;
|
||||
chatStore.messages = [];
|
||||
chatStore.setView('chat');
|
||||
}
|
||||
|
||||
const currentUserInfo = computed(() => {
|
||||
if (!chatStore.currentConversation) return null;
|
||||
return chatStore.users.find(u => u.userName === chatStore.currentConversation);
|
||||
|
||||
Reference in New Issue
Block a user