Files
sgse-app/apps/web/src/lib/components/chat/ChatWindow.svelte

170 lines
4.6 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 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(() => {
if (!conversas) return null;
return conversas.find((c: any) => c._id === conversaId);
});
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">
<div
class="w-10 h-10 rounded-full bg-primary/20 flex items-center justify-center text-xl"
>
{getAvatarConversa()}
</div>
{#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 -->
<button
type="button"
class="btn btn-ghost btn-sm btn-circle"
onclick={() => (showScheduleModal = true)}
aria-label="Agendar mensagem"
title="Agendar mensagem"
>
<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="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
/>
</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}