- Implementazione TRASPORTI ! Passo 1

This commit is contained in:
Surya Paolo
2025-12-22 01:19:23 +01:00
parent 83a0cf653c
commit c9fc1a83d0
123 changed files with 27433 additions and 28 deletions

View File

@@ -0,0 +1,275 @@
<!-- ChatListPage.vue -->
<template>
<q-page class="chat-list-page">
<!-- Header -->
<div class="chat-list-page__header">
<div class="chat-list-page__title-section">
<q-icon name="forum" class="chat-list-page__icon" />
<div>
<h1 class="chat-list-page__title">Messaggi</h1>
<p class="chat-list-page__subtitle">Le tue conversazioni</p>
</div>
</div>
<!-- Search -->
<q-input
v-model="searchQuery"
placeholder="Cerca conversazione..."
outlined
dense
class="chat-list-page__search"
>
<template #prepend>
<q-icon name="search" />
</template>
<template v-if="searchQuery" #append>
<q-icon name="close" class="cursor-pointer" @click="searchQuery = ''" />
</template>
</q-input>
</div>
<!-- Tabs -->
<q-tabs
v-model="activeTab"
class="chat-list-page__tabs"
active-color="primary"
indicator-color="primary"
align="justify"
>
<q-tab name="all" label="Tutte" icon="inbox" />
<q-tab name="unread" icon="mark_email_unread">
<template #default>
<div class="chat-list-page__tab-content">
<span>Non lette</span>
<q-badge v-if="unreadCount > 0" color="negative" :label="unreadCount" />
</div>
</template>
</q-tab>
<q-tab name="rides" label="Viaggi" icon="directions_car" />
<q-tab name="archived" label="Archiviate" icon="archive" />
</q-tabs>
<!-- Content -->
<div class="chat-list-page__content">
<!-- Loading -->
<div v-if="loading" class="chat-list-page__loading">
<q-spinner-dots size="50px" color="primary" />
<p>Caricamento conversazioni...</p>
</div>
<!-- Empty State -->
<div v-else-if="filteredChats.length === 0" class="chat-list-page__empty">
<q-icon :name="emptyStateIcon" size="80px" color="grey-4" />
<h3>{{ emptyStateTitle }}</h3>
<p>{{ emptyStateMessage }}</p>
<q-btn
v-if="activeTab === 'all' && !searchQuery"
color="primary"
icon="explore"
label="Esplora viaggi"
rounded
unelevated
to="/trasporti"
/>
</div>
<!-- Chat List -->
<q-list v-else class="chat-list-page__list" separator>
<q-slide-item
v-for="chat in filteredChats"
:key="chat._id"
class="chat-list-page__item"
:class="{ 'chat-list-page__item--unread': chat.unreadCount > 0 }"
@left="onArchiveChat(chat)"
@right="onDeleteChat(chat)"
>
<template #left>
<div class="chat-list-page__slide-action chat-list-page__slide-action--archive">
<q-icon name="archive" />
<span>Archivia</span>
</div>
</template>
<template #right>
<div class="chat-list-page__slide-action chat-list-page__slide-action--delete">
<q-icon name="delete" />
<span>Elimina</span>
</div>
</template>
<q-item clickable @click="openChat(chat)">
<!-- Avatar -->
<q-item-section avatar>
<div class="chat-list-page__avatar-wrapper">
<q-avatar size="56px">
<img
v-if="getOtherParticipant(chat)?.profile?.img"
:src="getOtherParticipant(chat).profile.img"
:alt="getOtherParticipant(chat).name"
/>
<div v-else class="chat-list-page__avatar-placeholder">
{{ getInitials(getOtherParticipant(chat)) }}
</div>
</q-avatar>
<!-- Online indicator -->
<div
v-if="isOnline(getOtherParticipant(chat)?._id)"
class="chat-list-page__online-dot"
/>
<!-- Ride type badge -->
<q-badge
v-if="chat.rideInfo"
:color="chat.rideInfo.type === 'offer' ? 'positive' : 'negative'"
floating
rounded
class="chat-list-page__ride-badge"
>
<q-icon :name="chat.rideInfo.type === 'offer' ? 'directions_car' : 'hail'" size="12px" />
</q-badge>
</div>
</q-item-section>
<!-- Content -->
<q-item-section>
<q-item-label class="chat-list-page__name">
{{ getOtherParticipant(chat)?.name }} {{ getOtherParticipant(chat)?.surname }}
</q-item-label>
<!-- Ride info -->
<q-item-label v-if="chat.rideInfo" caption class="chat-list-page__ride-info">
<q-icon name="place" size="14px" />
{{ chat.rideInfo.departure }} {{ chat.rideInfo.destination }}
</q-item-label>
<!-- Last message -->
<q-item-label
caption
lines="1"
class="chat-list-page__last-message"
:class="{ 'chat-list-page__last-message--unread': chat.unreadCount > 0 }"
>
<q-icon
v-if="chat.lastMessage?.senderId === currentUserId"
:name="getMessageStatusIcon(chat.lastMessage)"
size="14px"
:color="chat.lastMessage?.read ? 'primary' : 'grey'"
/>
{{ getMessagePreview(chat.lastMessage) }}
</q-item-label>
</q-item-section>
<!-- Right side -->
<q-item-section side>
<div class="chat-list-page__meta">
<q-item-label caption class="chat-list-page__time">
{{ formatTime(chat.lastMessage?.createdAt || chat.updatedAt) }}
</q-item-label>
<q-badge
v-if="chat.unreadCount > 0"
color="primary"
:label="chat.unreadCount > 99 ? '99+' : chat.unreadCount"
rounded
class="chat-list-page__unread-badge"
/>
<q-icon
v-else-if="chat.pinned"
name="push_pin"
size="18px"
color="grey"
/>
</div>
</q-item-section>
</q-item>
</q-slide-item>
</q-list>
<!-- Load More -->
<div v-if="hasMore && !loading" class="chat-list-page__load-more">
<q-btn
flat
color="primary"
label="Carica altre conversazioni"
:loading="loadingMore"
@click="loadMore"
/>
</div>
</div>
<!-- FAB for new message -->
<q-page-sticky position="bottom-right" :offset="[18, 18]">
<q-fab
icon="edit"
direction="up"
color="primary"
:disable="loading"
>
<q-fab-action
color="secondary"
icon="person_search"
label="Cerca utente"
@click="showUserSearch = true"
/>
<q-fab-action
color="accent"
icon="group"
label="Nuovo gruppo"
@click="showGroupCreate = true"
/>
</q-fab>
</q-page-sticky>
<!-- User Search Dialog -->
<q-dialog v-model="showUserSearch" position="top">
<q-card class="chat-list-page__search-dialog">
<q-card-section>
<div class="text-h6">Nuova conversazione</div>
</q-card-section>
<q-card-section>
<q-input
v-model="userSearchQuery"
placeholder="Cerca per nome o username..."
outlined
autofocus
@update:model-value="searchUsers"
>
<template #prepend>
<q-icon name="search" />
</template>
</q-input>
<q-list v-if="searchedUsers.length > 0" class="q-mt-md">
<q-item
v-for="user in searchedUsers"
:key="user._id"
clickable
@click="startChatWith(user)"
>
<q-item-section avatar>
<q-avatar>
<img v-if="user.profile?.img" :src="user.profile.img" />
<span v-else>{{ getInitials(user) }}</span>
</q-avatar>
</q-item-section>
<q-item-section>
<q-item-label>{{ user.name }} {{ user.surname }}</q-item-label>
<q-item-label caption>@{{ user.username }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
<div v-else-if="userSearchQuery && !searchingUsers" class="text-center q-pa-md text-grey">
Nessun utente trovato
</div>
</q-card-section>
</q-card>
</q-dialog>
</q-page>
</template>
<script lang="ts" src="./ChatListPage.ts" />
<style lang="scss" src="./ChatListPage.scss" />