190 lines
5.7 KiB
Svelte
190 lines
5.7 KiB
Svelte
<script lang="ts">
|
|
import { useQuery } from "convex-svelte";
|
|
import { api } from "@sgse-app/backend/convex/_generated/api";
|
|
import { voltarParaLista } from "$lib/stores/chatStore";
|
|
import type { Id } from "@sgse-app/backend/convex/_generated/dataModel";
|
|
import MessageList from "./MessageList.svelte";
|
|
import MessageInput from "./MessageInput.svelte";
|
|
import UserStatusBadge from "./UserStatusBadge.svelte";
|
|
import UserAvatar from "./UserAvatar.svelte";
|
|
import ScheduleMessageModal from "./ScheduleMessageModal.svelte";
|
|
|
|
interface Props {
|
|
conversaId: string;
|
|
}
|
|
|
|
let { conversaId }: Props = $props();
|
|
|
|
let showScheduleModal = $state(false);
|
|
|
|
const conversas = useQuery(api.chat.listarConversas, {});
|
|
|
|
const conversa = $derived(() => {
|
|
console.log("🔍 [ChatWindow] Buscando conversa ID:", conversaId);
|
|
console.log("📋 [ChatWindow] Conversas disponíveis:", conversas?.data);
|
|
|
|
if (!conversas?.data || !Array.isArray(conversas.data)) {
|
|
console.log("⚠️ [ChatWindow] conversas.data não é um array ou está vazio");
|
|
return null;
|
|
}
|
|
|
|
const encontrada = conversas.data.find((c: any) => c._id === conversaId);
|
|
console.log("✅ [ChatWindow] Conversa encontrada:", encontrada);
|
|
return encontrada;
|
|
});
|
|
|
|
function getNomeConversa(): string {
|
|
const c = conversa();
|
|
if (!c) return "Carregando...";
|
|
if (c.tipo === "grupo") {
|
|
return c.nome || "Grupo sem nome";
|
|
}
|
|
return c.outroUsuario?.nome || "Usuário";
|
|
}
|
|
|
|
function getAvatarConversa(): string {
|
|
const c = conversa();
|
|
if (!c) return "💬";
|
|
if (c.tipo === "grupo") {
|
|
return c.avatar || "👥";
|
|
}
|
|
if (c.outroUsuario?.avatar) {
|
|
return c.outroUsuario.avatar;
|
|
}
|
|
return "👤";
|
|
}
|
|
|
|
function getStatusConversa(): any {
|
|
const c = conversa();
|
|
if (c && c.tipo === "individual" && c.outroUsuario) {
|
|
return c.outroUsuario.statusPresenca || "offline";
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function getStatusMensagem(): string | null {
|
|
const c = conversa();
|
|
if (c && c.tipo === "individual" && c.outroUsuario) {
|
|
return c.outroUsuario.statusMensagem || null;
|
|
}
|
|
return null;
|
|
}
|
|
</script>
|
|
|
|
<div class="flex flex-col h-full">
|
|
<!-- Header -->
|
|
<div class="flex items-center gap-3 px-4 py-3 border-b border-base-300 bg-base-200">
|
|
<!-- Botão Voltar -->
|
|
<button
|
|
type="button"
|
|
class="btn btn-ghost btn-sm btn-circle"
|
|
onclick={voltarParaLista}
|
|
aria-label="Voltar"
|
|
>
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke-width="1.5"
|
|
stroke="currentColor"
|
|
class="w-5 h-5"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
d="M10.5 19.5 3 12m0 0 7.5-7.5M3 12h18"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- Avatar e Info -->
|
|
<div class="relative flex-shrink-0">
|
|
{#if conversa() && conversa()?.tipo === "individual" && conversa()?.outroUsuario}
|
|
<UserAvatar
|
|
avatar={conversa()?.outroUsuario?.avatar}
|
|
fotoPerfilUrl={conversa()?.outroUsuario?.fotoPerfilUrl}
|
|
nome={conversa()?.outroUsuario?.nome || "Usuário"}
|
|
size="md"
|
|
/>
|
|
{:else}
|
|
<div
|
|
class="w-10 h-10 rounded-full bg-primary/20 flex items-center justify-center text-xl"
|
|
>
|
|
{getAvatarConversa()}
|
|
</div>
|
|
{/if}
|
|
{#if getStatusConversa()}
|
|
<div class="absolute bottom-0 right-0">
|
|
<UserStatusBadge status={getStatusConversa()} size="sm" />
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<div class="flex-1 min-w-0">
|
|
<p class="font-semibold text-base-content truncate">{getNomeConversa()}</p>
|
|
{#if getStatusMensagem()}
|
|
<p class="text-xs text-base-content/60 truncate">{getStatusMensagem()}</p>
|
|
{:else if getStatusConversa()}
|
|
<p class="text-xs text-base-content/60">
|
|
{getStatusConversa() === "online"
|
|
? "Online"
|
|
: getStatusConversa() === "ausente"
|
|
? "Ausente"
|
|
: getStatusConversa() === "em_reuniao"
|
|
? "Em reunião"
|
|
: getStatusConversa() === "externo"
|
|
? "Externo"
|
|
: "Offline"}
|
|
</p>
|
|
{/if}
|
|
</div>
|
|
|
|
<!-- Botões de ação -->
|
|
<div class="flex items-center gap-1">
|
|
<!-- Botão Agendar MODERNO -->
|
|
<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(139, 92, 246, 0.1); border: 1px solid rgba(139, 92, 246, 0.2);"
|
|
onclick={() => (showScheduleModal = true)}
|
|
aria-label="Agendar mensagem"
|
|
title="Agendar mensagem"
|
|
>
|
|
<div class="absolute inset-0 bg-purple-500/0 group-hover:bg-purple-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-purple-500 relative z-10 group-hover:scale-110 transition-transform"
|
|
>
|
|
<circle cx="12" cy="12" r="10"/>
|
|
<polyline points="12 6 12 12 16 14"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mensagens -->
|
|
<div class="flex-1 overflow-hidden">
|
|
<MessageList conversaId={conversaId as any} />
|
|
</div>
|
|
|
|
<!-- Input -->
|
|
<div class="border-t border-base-300">
|
|
<MessageInput conversaId={conversaId as any} />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Modal de Agendamento -->
|
|
{#if showScheduleModal}
|
|
<ScheduleMessageModal
|
|
conversaId={conversaId as any}
|
|
onClose={() => (showScheduleModal = false)}
|
|
/>
|
|
{/if}
|
|
|