feat: enhance chat functionality with new conversation and meeting room features
- Added support for creating and managing group conversations and meeting rooms, allowing users to initiate discussions with multiple participants. - Implemented a modal for creating new conversations, including options for individual, group, and meeting room types. - Enhanced the chat list component to filter and display conversations based on type, improving user navigation. - Introduced admin functionalities for meeting rooms, enabling user management and role assignments within the chat interface. - Updated backend schema and API to accommodate new conversation types and related operations, ensuring robust data handling.
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
import UserStatusBadge from "./UserStatusBadge.svelte";
|
||||
import UserAvatar from "./UserAvatar.svelte";
|
||||
import ScheduleMessageModal from "./ScheduleMessageModal.svelte";
|
||||
import SalaReuniaoManager from "./SalaReuniaoManager.svelte";
|
||||
import { getAvatarUrl } from "$lib/utils/avatarGenerator";
|
||||
|
||||
interface Props {
|
||||
conversaId: string;
|
||||
@@ -16,8 +18,10 @@
|
||||
let { conversaId }: Props = $props();
|
||||
|
||||
let showScheduleModal = $state(false);
|
||||
let showSalaManager = $state(false);
|
||||
|
||||
const conversas = useQuery(api.chat.listarConversas, {});
|
||||
const isAdmin = useQuery(api.chat.verificarSeEhAdmin, { conversaId: conversaId as any });
|
||||
|
||||
const conversa = $derived(() => {
|
||||
console.log("🔍 [ChatWindow] Buscando conversa ID:", conversaId);
|
||||
@@ -36,8 +40,8 @@
|
||||
function getNomeConversa(): string {
|
||||
const c = conversa();
|
||||
if (!c) return "Carregando...";
|
||||
if (c.tipo === "grupo") {
|
||||
return c.nome || "Grupo sem nome";
|
||||
if (c.tipo === "grupo" || c.tipo === "sala_reuniao") {
|
||||
return c.nome || (c.tipo === "sala_reuniao" ? "Sala sem nome" : "Grupo sem nome");
|
||||
}
|
||||
return c.outroUsuario?.nome || "Usuário";
|
||||
}
|
||||
@@ -135,11 +139,64 @@
|
||||
? "Externo"
|
||||
: "Offline"}
|
||||
</p>
|
||||
{:else if conversa() && (conversa()?.tipo === "grupo" || conversa()?.tipo === "sala_reuniao")}
|
||||
<div class="flex items-center gap-2 mt-1">
|
||||
<p class="text-xs text-base-content/60">
|
||||
{conversa()?.participantesInfo?.length || 0} {conversa()?.participantesInfo?.length === 1 ? "participante" : "participantes"}
|
||||
</p>
|
||||
{#if conversa()?.participantesInfo && conversa()?.participantesInfo.length > 0}
|
||||
<div class="flex -space-x-2">
|
||||
{#each conversa()?.participantesInfo.slice(0, 5) as participante (participante._id)}
|
||||
<div class="relative w-5 h-5 rounded-full border-2 border-base-200 overflow-hidden bg-base-200" title={participante.nome}>
|
||||
{#if participante.fotoPerfilUrl}
|
||||
<img src={participante.fotoPerfilUrl} alt={participante.nome} class="w-full h-full object-cover" />
|
||||
{:else if participante.avatar}
|
||||
<img src={getAvatarUrl(participante.avatar)} alt={participante.nome} class="w-full h-full object-cover" />
|
||||
{:else}
|
||||
<img src={getAvatarUrl(participante.nome)} alt={participante.nome} class="w-full h-full object-cover" />
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
{#if conversa()?.participantesInfo.length > 5}
|
||||
<div class="w-5 h-5 rounded-full border-2 border-base-200 bg-base-300 flex items-center justify-center text-[8px] font-semibold text-base-content/70" title={`+${conversa()?.participantesInfo.length - 5} mais`}>
|
||||
+{conversa()?.participantesInfo.length - 5}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Botões de ação -->
|
||||
<div class="flex items-center gap-1">
|
||||
<!-- Botão Gerenciar Sala (apenas para salas de reunião) -->
|
||||
{#if conversa()?.tipo === "sala_reuniao"}
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center justify-center w-9 h-9 rounded-lg transition-all duration-300 group relative overflow-hidden"
|
||||
style="background: rgba(59, 130, 246, 0.1); border: 1px solid rgba(59, 130, 246, 0.2);"
|
||||
onclick={() => (showSalaManager = true)}
|
||||
aria-label="Gerenciar sala"
|
||||
title="Gerenciar sala de reunião"
|
||||
>
|
||||
<div class="absolute inset-0 bg-blue-500/0 group-hover:bg-blue-500/10 transition-colors duration-300"></div>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="w-5 h-5 text-blue-500 relative z-10 group-hover:scale-110 transition-transform"
|
||||
>
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M12 1v6m0 6v6M5.64 5.64l4.24 4.24m4.24 4.24l4.24 4.24M1 12h6m6 0h6M5.64 18.36l4.24-4.24m4.24-4.24l4.24-4.24"/>
|
||||
</svg>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<!-- Botão Agendar MODERNO -->
|
||||
<button
|
||||
type="button"
|
||||
@@ -186,3 +243,12 @@
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<!-- Modal de Gerenciamento de Sala -->
|
||||
{#if showSalaManager && conversa()?.tipo === "sala_reuniao"}
|
||||
<SalaReuniaoManager
|
||||
conversaId={conversaId as Id<"conversas">}
|
||||
isAdmin={isAdmin?.data ?? false}
|
||||
onClose={() => (showSalaManager = false)}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user