Revert "Feat many fixes"

This commit is contained in:
Kilder Costa
2025-11-11 16:41:40 -03:00
committed by GitHub
parent 1c197a7534
commit caff7035f7
51 changed files with 20765 additions and 22636 deletions

View File

@@ -1,423 +1,454 @@
<script lang="ts">
import { useQuery, useConvexClient } from 'convex-svelte';
import { api } from '@sgse-app/backend/convex/_generated/api';
import { abrirConversa } from '$lib/stores/chatStore';
import UserStatusBadge from './UserStatusBadge.svelte';
import UserAvatar from './UserAvatar.svelte';
import {
MessageSquare,
User,
Users,
Video,
X,
Search,
ChevronRight,
Plus,
UserX
} from 'lucide-svelte';
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
import { useQuery, useConvexClient } from "convex-svelte";
import { api } from "@sgse-app/backend/convex/_generated/api";
import { abrirConversa } from "$lib/stores/chatStore";
import UserStatusBadge from "./UserStatusBadge.svelte";
import UserAvatar from "./UserAvatar.svelte";
import {
MessageSquare,
User,
Users,
Video,
X,
Search,
ChevronRight,
Plus,
UserX,
} from "lucide-svelte";
interface Props {
onClose: () => void;
}
interface Props {
onClose: () => void;
}
let { onClose }: Props = $props();
let { onClose }: Props = $props();
const client = useConvexClient();
const usuarios = useQuery(api.usuarios.listarParaChat, {});
const meuPerfil = useQuery(api.usuarios.obterPerfil, {});
// Usuário atual
const currentUser = useQuery(api.auth.getCurrentUser, {});
const client = useConvexClient();
const usuarios = useQuery(api.usuarios.listarParaChat, {});
const meuPerfil = useQuery(api.usuarios.obterPerfil, {});
// Usuário atual
const currentUser = useQuery(api.auth.getCurrentUser, {});
let activeTab = $state<'individual' | 'grupo' | 'sala_reuniao'>('individual');
let searchQuery = $state('');
let selectedUsers = $state<Id<'usuarios'>[]>([]);
let groupName = $state('');
let salaReuniaoName = $state('');
let loading = $state(false);
let activeTab = $state<"individual" | "grupo" | "sala_reuniao">("individual");
let searchQuery = $state("");
let selectedUsers = $state<string[]>([]);
let groupName = $state("");
let salaReuniaoName = $state("");
let loading = $state(false);
const usuariosFiltrados = $derived(() => {
if (!usuarios?.data) return [];
const usuariosFiltrados = $derived(() => {
if (!usuarios?.data) return [];
// Filtrar o próprio usuário
const meuId = currentUser?.data?._id || meuPerfil?.data?._id;
let lista = usuarios.data.filter((u) => u._id !== meuId);
// Filtrar o próprio usuário
const meuId = currentUser?.data?._id || meuPerfil?.data?._id;
let lista = usuarios.data.filter((u: any) => u._id !== meuId);
// Aplicar busca
if (searchQuery.trim()) {
const query = searchQuery.toLowerCase();
lista = lista.filter(
(u) =>
u.nome?.toLowerCase().includes(query) ||
u.email?.toLowerCase().includes(query) ||
u.matricula?.toLowerCase().includes(query)
);
}
// Aplicar busca
if (searchQuery.trim()) {
const query = searchQuery.toLowerCase();
lista = lista.filter(
(u: any) =>
u.nome?.toLowerCase().includes(query) ||
u.email?.toLowerCase().includes(query) ||
u.matricula?.toLowerCase().includes(query),
);
}
// Ordenar: online primeiro, depois por nome
return lista.sort((a, b) => {
const statusOrder = {
online: 0,
ausente: 1,
externo: 2,
em_reuniao: 3,
offline: 4
};
const statusA = statusOrder[a.statusPresenca as keyof typeof statusOrder] ?? 4;
const statusB = statusOrder[b.statusPresenca as keyof typeof statusOrder] ?? 4;
// Ordenar: online primeiro, depois por nome
return lista.sort((a: any, b: any) => {
const statusOrder = {
online: 0,
ausente: 1,
externo: 2,
em_reuniao: 3,
offline: 4,
};
const statusA =
statusOrder[a.statusPresenca as keyof typeof statusOrder] ?? 4;
const statusB =
statusOrder[b.statusPresenca as keyof typeof statusOrder] ?? 4;
if (statusA !== statusB) return statusA - statusB;
return (a.nome || '').localeCompare(b.nome || '');
});
});
if (statusA !== statusB) return statusA - statusB;
return (a.nome || "").localeCompare(b.nome || "");
});
});
function toggleUserSelection(userId: Id<'usuarios'>) {
if (selectedUsers.includes(userId)) {
selectedUsers = selectedUsers.filter((id) => id !== userId);
} else {
selectedUsers = [...selectedUsers, userId];
}
}
function toggleUserSelection(userId: string) {
if (selectedUsers.includes(userId)) {
selectedUsers = selectedUsers.filter((id) => id !== userId);
} else {
selectedUsers = [...selectedUsers, userId];
}
}
async function handleCriarIndividual(userId: Id<'usuarios'>) {
try {
loading = true;
const conversaId = await client.mutation(api.chat.criarConversa, {
tipo: 'individual',
participantes: [userId]
});
abrirConversa(conversaId);
onClose();
} catch (error) {
console.error('Erro ao criar conversa:', error);
alert('Erro ao criar conversa');
} finally {
loading = false;
}
}
async function handleCriarIndividual(userId: string) {
try {
loading = true;
const conversaId = await client.mutation(api.chat.criarConversa, {
tipo: "individual",
participantes: [userId as any],
});
abrirConversa(conversaId);
onClose();
} catch (error) {
console.error("Erro ao criar conversa:", error);
alert("Erro ao criar conversa");
} finally {
loading = false;
}
}
async function handleCriarGrupo() {
console.log('selectedUsers', selectedUsers);
async function handleCriarGrupo() {
if (selectedUsers.length < 2) {
alert("Selecione pelo menos 2 participantes");
return;
}
if (selectedUsers.length < 2) {
alert('Selecione pelo menos 2 participantes');
return;
}
if (!groupName.trim()) {
alert("Digite um nome para o grupo");
return;
}
if (!groupName.trim()) {
alert('Digite um nome para o grupo');
return;
}
try {
loading = true;
const conversaId = await client.mutation(api.chat.criarConversa, {
tipo: "grupo",
participantes: selectedUsers as any,
nome: groupName.trim(),
});
abrirConversa(conversaId);
onClose();
} catch (error: any) {
console.error("Erro ao criar grupo:", error);
const mensagem =
error?.message || error?.data || "Erro desconhecido ao criar grupo";
alert(`Erro ao criar grupo: ${mensagem}`);
} finally {
loading = false;
}
}
try {
loading = true;
const conversaId = await client.mutation(api.chat.criarConversa, {
tipo: 'grupo',
participantes: selectedUsers,
nome: groupName.trim()
});
abrirConversa(conversaId);
onClose();
} catch (error) {
console.error('Erro ao criar grupo:', error);
alert('Erro ao criar grupo');
} finally {
loading = false;
}
}
async function handleCriarSalaReuniao() {
if (selectedUsers.length < 1) {
alert("Selecione pelo menos 1 participante");
return;
}
async function handleCriarSalaReuniao() {
if (selectedUsers.length < 1) {
alert('Selecione pelo menos 1 participante');
return;
}
if (!salaReuniaoName.trim()) {
alert("Digite um nome para a sala de reunião");
return;
}
if (!salaReuniaoName.trim()) {
alert('Digite um nome para a sala de reunião');
return;
}
try {
loading = true;
const conversaId = await client.mutation(api.chat.criarSalaReuniao, {
nome: salaReuniaoName.trim(),
participantes: selectedUsers
});
abrirConversa(conversaId);
onClose();
} catch (error) {
console.error('Erro ao criar sala de reunião:', error);
alert('Erro ao criar sala de reunião');
} finally {
loading = false;
}
}
try {
loading = true;
const conversaId = await client.mutation(api.chat.criarSalaReuniao, {
nome: salaReuniaoName.trim(),
participantes: selectedUsers as any,
});
abrirConversa(conversaId);
onClose();
} catch (error: any) {
console.error("Erro ao criar sala de reunião:", error);
const mensagem =
error?.message ||
error?.data ||
"Erro desconhecido ao criar sala de reunião";
alert(`Erro ao criar sala de reunião: ${mensagem}`);
} finally {
loading = false;
}
}
</script>
<dialog class="modal modal-open">
<div class="modal-box flex max-h-[85vh] max-w-2xl flex-col p-0">
<!-- Header -->
<div class="border-base-300 flex items-center justify-between border-b px-6 py-4">
<h2 class="flex items-center gap-2 text-2xl font-bold">
<MessageSquare class="text-primary h-6 w-6" />
Nova Conversa
</h2>
<button type="button" class="btn btn-sm btn-circle" onclick={onClose} aria-label="Fechar">
<X class="h-5 w-5" />
</button>
</div>
<dialog
class="modal modal-open"
onclick={(e) => e.target === e.currentTarget && onClose()}
>
<div
class="modal-box max-w-2xl max-h-[85vh] flex flex-col p-0"
onclick={(e) => e.stopPropagation()}
>
<!-- Header -->
<div
class="flex items-center justify-between px-6 py-4 border-b border-base-300"
>
<h2 class="text-2xl font-bold flex items-center gap-2">
<MessageSquare class="w-6 h-6 text-primary" />
Nova Conversa
</h2>
<button
type="button"
class="btn btn-ghost btn-sm btn-circle"
onclick={onClose}
aria-label="Fechar"
>
<X class="w-5 h-5" />
</button>
</div>
<!-- Tabs melhoradas -->
<div class="tabs tabs-boxed bg-base-200/50 p-4">
<button
type="button"
class={`tab flex items-center gap-2 transition-all duration-200 ${
activeTab === 'individual'
? 'tab-active bg-primary text-primary-content font-semibold'
: 'hover:bg-base-300'
}`}
onclick={() => {
activeTab = 'individual';
selectedUsers = [];
searchQuery = '';
}}
>
<User class="h-4 w-4" />
Individual
</button>
<button
type="button"
class={`tab flex items-center gap-2 transition-all duration-200 ${
activeTab === 'grupo'
? 'tab-active bg-primary text-primary-content font-semibold'
: 'hover:bg-base-300'
}`}
onclick={() => {
activeTab = 'grupo';
selectedUsers = [];
searchQuery = '';
}}
>
<Users class="h-4 w-4" />
Grupo
</button>
<button
type="button"
class={`tab flex items-center gap-2 transition-all duration-200 ${
activeTab === 'sala_reuniao'
? 'tab-active bg-primary text-primary-content font-semibold'
: 'hover:bg-base-300'
}`}
onclick={() => {
activeTab = 'sala_reuniao';
selectedUsers = [];
searchQuery = '';
}}
>
<Video class="h-4 w-4" />
Sala de Reunião
</button>
</div>
<!-- Tabs melhoradas -->
<div class="tabs tabs-boxed p-4 bg-base-200/50">
<button
type="button"
class={`tab flex items-center gap-2 transition-all duration-200 ${
activeTab === "individual"
? "tab-active bg-primary text-primary-content font-semibold"
: "hover:bg-base-300"
}`}
onclick={() => {
activeTab = "individual";
selectedUsers = [];
searchQuery = "";
}}
>
<User class="w-4 h-4" />
Individual
</button>
<button
type="button"
class={`tab flex items-center gap-2 transition-all duration-200 ${
activeTab === "grupo"
? "tab-active bg-primary text-primary-content font-semibold"
: "hover:bg-base-300"
}`}
onclick={() => {
activeTab = "grupo";
selectedUsers = [];
searchQuery = "";
}}
>
<Users class="w-4 h-4" />
Grupo
</button>
<button
type="button"
class={`tab flex items-center gap-2 transition-all duration-200 ${
activeTab === "sala_reuniao"
? "tab-active bg-primary text-primary-content font-semibold"
: "hover:bg-base-300"
}`}
onclick={() => {
activeTab = "sala_reuniao";
selectedUsers = [];
searchQuery = "";
}}
>
<Video class="w-4 h-4" />
Sala de Reunião
</button>
</div>
<!-- Content -->
<div class="flex-1 overflow-y-auto px-6 py-4">
{#if activeTab === 'grupo'}
<!-- Criar Grupo -->
<div class="mb-4">
<div class="label pb-2">
<span class="label-text font-semibold">Nome do Grupo</span>
</div>
<input
type="text"
placeholder="Digite o nome do grupo..."
class="input input-bordered focus:input-primary w-full transition-colors"
bind:value={groupName}
maxlength="50"
/>
</div>
<!-- Content -->
<div class="flex-1 overflow-y-auto px-6 py-4">
{#if activeTab === "grupo"}
<!-- Criar Grupo -->
<div class="mb-4">
<label class="label pb-2">
<span class="label-text font-semibold">Nome do Grupo</span>
</label>
<input
type="text"
placeholder="Digite o nome do grupo..."
class="input input-bordered w-full focus:input-primary transition-colors"
bind:value={groupName}
maxlength="50"
/>
</div>
<div class="mb-3">
<div class="label pb-2">
<span class="label-text font-semibold">
Participantes {selectedUsers.length > 0
? `(${selectedUsers.length} selecionado${selectedUsers.length > 1 ? 's' : ''})`
: ''}
</span>
</div>
</div>
{:else if activeTab === 'sala_reuniao'}
<!-- Criar Sala de Reunião -->
<div class="mb-4">
<div class="label pb-2">
<span class="label-text font-semibold">Nome da Sala de Reunião</span>
<span class="label-text-alt text-primary font-medium">👑 Você será o administrador</span
>
</div>
<input
type="text"
placeholder="Digite o nome da sala de reunião..."
class="input input-bordered focus:input-primary w-full transition-colors"
bind:value={salaReuniaoName}
maxlength="50"
/>
</div>
<div class="mb-3">
<label class="label pb-2">
<span class="label-text font-semibold">
Participantes {selectedUsers.length > 0
? `(${selectedUsers.length} selecionado${selectedUsers.length > 1 ? "s" : ""})`
: ""}
</span>
</label>
</div>
{:else if activeTab === "sala_reuniao"}
<!-- Criar Sala de Reunião -->
<div class="mb-4">
<label class="label pb-2">
<span class="label-text font-semibold">Nome da Sala de Reunião</span
>
<span class="label-text-alt text-primary font-medium"
>👑 Você será o administrador</span
>
</label>
<input
type="text"
placeholder="Digite o nome da sala de reunião..."
class="input input-bordered w-full focus:input-primary transition-colors"
bind:value={salaReuniaoName}
maxlength="50"
/>
</div>
<div class="mb-3">
<div class="label pb-2">
<span class="label-text font-semibold">
Participantes {selectedUsers.length > 0
? `(${selectedUsers.length} selecionado${selectedUsers.length > 1 ? 's' : ''})`
: ''}
</span>
</div>
</div>
{/if}
<div class="mb-3">
<label class="label pb-2">
<span class="label-text font-semibold">
Participantes {selectedUsers.length > 0
? `(${selectedUsers.length} selecionado${selectedUsers.length > 1 ? "s" : ""})`
: ""}
</span>
</label>
</div>
{/if}
<!-- Search melhorado -->
<div class="relative mb-4">
<input
type="text"
placeholder="Buscar usuários por nome, email ou matrícula..."
class="input input-bordered focus:input-primary w-full pl-10 transition-colors"
bind:value={searchQuery}
/>
<Search class="text-base-content/40 absolute top-1/2 left-3 h-5 w-5 -translate-y-1/2" />
</div>
<!-- Search melhorado -->
<div class="mb-4 relative">
<input
type="text"
placeholder="Buscar usuários por nome, email ou matrícula..."
class="input input-bordered w-full pl-10 focus:input-primary transition-colors"
bind:value={searchQuery}
/>
<Search
class="w-5 h-5 absolute left-3 top-1/2 -translate-y-1/2 text-base-content/40"
/>
</div>
<!-- Lista de usuários -->
<div class="space-y-2">
{#if usuarios?.data && usuariosFiltrados().length > 0}
{#each usuariosFiltrados() as usuario (usuario._id)}
{@const isSelected = selectedUsers.includes(usuario._id)}
<button
type="button"
class={`flex w-full items-center gap-3 rounded-xl border-2 px-4 py-3 text-left transition-all duration-200 ${
isSelected
? 'border-primary bg-primary/10 scale-[1.02] shadow-md'
: 'border-base-300 hover:bg-base-200 hover:border-primary/30 hover:shadow-sm'
} ${loading ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'}`}
onclick={() => {
if (loading) return;
if (activeTab === 'individual') {
handleCriarIndividual(usuario._id);
} else {
toggleUserSelection(usuario._id);
}
}}
disabled={loading}
>
<!-- Avatar -->
<div class="relative shrink-0">
<UserAvatar
avatar={usuario.avatar}
fotoPerfilUrl={usuario.fotoPerfilUrl}
nome={usuario.nome}
size="md"
/>
<div class="absolute -right-1 -bottom-1">
<UserStatusBadge status={usuario.statusPresenca || 'offline'} size="sm" />
</div>
</div>
<!-- Lista de usuários -->
<div class="space-y-2">
{#if usuarios?.data && usuariosFiltrados().length > 0}
{#each usuariosFiltrados() as usuario (usuario._id)}
{@const isSelected = selectedUsers.includes(usuario._id)}
<button
type="button"
class={`w-full text-left px-4 py-3 rounded-xl border-2 transition-all duration-200 flex items-center gap-3 ${
isSelected
? "border-primary bg-primary/10 shadow-md scale-[1.02]"
: "border-base-300 hover:bg-base-200 hover:border-primary/30 hover:shadow-sm"
} ${loading ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}`}
onclick={() => {
if (loading) return;
if (activeTab === "individual") {
handleCriarIndividual(usuario._id);
} else {
toggleUserSelection(usuario._id);
}
}}
disabled={loading}
>
<!-- Avatar -->
<div class="relative shrink-0">
<UserAvatar
avatar={usuario.avatar}
fotoPerfilUrl={usuario.fotoPerfilUrl}
nome={usuario.nome}
size="md"
/>
<div class="absolute -bottom-1 -right-1">
<UserStatusBadge
status={usuario.statusPresenca || "offline"}
size="sm"
/>
</div>
</div>
<!-- Info -->
<div class="min-w-0 flex-1">
<p class="text-base-content truncate font-semibold">
{usuario.nome}
</p>
<p class="text-base-content/60 truncate text-sm">
{usuario.email || usuario.matricula || 'Sem informações'}
</p>
</div>
<!-- Info -->
<div class="flex-1 min-w-0">
<p class="font-semibold text-base-content truncate">
{usuario.nome}
</p>
<p class="text-sm text-base-content/60 truncate">
{usuario.setor ||
usuario.email ||
usuario.matricula ||
"Sem informações"}
</p>
</div>
<!-- Checkbox melhorado (para grupo e sala de reunião) -->
{#if activeTab === 'grupo' || activeTab === 'sala_reuniao'}
<div class="shrink-0">
<input
type="checkbox"
class="checkbox checkbox-primary checkbox-lg"
checked={isSelected}
tabindex="-1"
onclick={(e) => {
e.stopPropagation();
if (!loading) toggleUserSelection(usuario._id);
}}
/>
</div>
{:else}
<!-- Ícone de seta para individual -->
<ChevronRight class="text-base-content/40 h-5 w-5" />
{/if}
</button>
{/each}
{:else if !usuarios?.data}
<div class="flex flex-col items-center justify-center py-12">
<span class="loading loading-spinner loading-lg text-primary"></span>
<p class="text-base-content/60 mt-4">Carregando usuários...</p>
</div>
{:else}
<div class="flex flex-col items-center justify-center py-12 text-center">
<UserX class="text-base-content/30 mb-4 h-16 w-16" />
<p class="text-base-content/70 font-medium">
{searchQuery.trim() ? 'Nenhum usuário encontrado' : 'Nenhum usuário disponível'}
</p>
{#if searchQuery.trim()}
<p class="text-base-content/50 mt-2 text-sm">
Tente buscar por nome, email ou matrícula
</p>
{/if}
</div>
{/if}
</div>
</div>
<!-- Checkbox melhorado (para grupo e sala de reunião) -->
{#if activeTab === "grupo" || activeTab === "sala_reuniao"}
<div class="shrink-0">
<input
type="checkbox"
class="checkbox checkbox-primary checkbox-lg"
checked={isSelected}
readonly
/>
</div>
{:else}
<!-- Ícone de seta para individual -->
<ChevronRight class="w-5 h-5 text-base-content/40" />
{/if}
</button>
{/each}
{:else if !usuarios?.data}
<div class="flex flex-col items-center justify-center py-12">
<span class="loading loading-spinner loading-lg text-primary"
></span>
<p class="mt-4 text-base-content/60">Carregando usuários...</p>
</div>
{:else}
<div
class="flex flex-col items-center justify-center py-12 text-center"
>
<UserX class="w-16 h-16 text-base-content/30 mb-4" />
<p class="text-base-content/70 font-medium">
{searchQuery.trim()
? "Nenhum usuário encontrado"
: "Nenhum usuário disponível"}
</p>
{#if searchQuery.trim()}
<p class="text-sm text-base-content/50 mt-2">
Tente buscar por nome, email ou matrícula
</p>
{/if}
</div>
{/if}
</div>
</div>
<!-- Footer (para grupo e sala de reunião) -->
{#if activeTab === 'grupo'}
<div class="border-base-300 bg-base-200/50 border-t px-6 py-4">
<button
type="button"
class="btn btn-primary btn-block btn-lg font-semibold shadow-lg transition-all duration-200 hover:shadow-xl"
onclick={handleCriarGrupo}
disabled={loading || selectedUsers.length < 2 || !groupName.trim()}
>
{#if loading}
<span class="loading loading-spinner"></span>
Criando grupo...
{:else}
<Plus class="h-5 w-5" />
Criar Grupo
{/if}
</button>
{#if selectedUsers.length < 2 && activeTab === 'grupo'}
<p class="text-base-content/50 mt-2 text-center text-xs">
Selecione pelo menos 2 participantes
</p>
{/if}
</div>
{:else if activeTab === 'sala_reuniao'}
<div class="border-base-300 bg-base-200/50 border-t px-6 py-4">
<button
type="button"
class="btn btn-primary btn-block btn-lg font-semibold shadow-lg transition-all duration-200 hover:shadow-xl"
onclick={handleCriarSalaReuniao}
disabled={loading || selectedUsers.length < 1 || !salaReuniaoName.trim()}
>
{#if loading}
<span class="loading loading-spinner"></span>
Criando sala...
{:else}
<Plus class="h-5 w-5" />
Criar Sala de Reunião
{/if}
</button>
{#if selectedUsers.length < 1 && activeTab === 'sala_reuniao'}
<p class="text-base-content/50 mt-2 text-center text-xs">
Selecione pelo menos 1 participante
</p>
{/if}
</div>
{/if}
</div>
<form method="dialog" class="modal-backdrop">
<button type="button" onclick={onClose}>fechar</button>
</form>
<!-- Footer (para grupo e sala de reunião) -->
{#if activeTab === "grupo"}
<div class="px-6 py-4 border-t border-base-300 bg-base-200/50">
<button
type="button"
class="btn btn-primary btn-block btn-lg font-semibold shadow-lg hover:shadow-xl transition-all duration-200"
onclick={handleCriarGrupo}
disabled={loading || selectedUsers.length < 2 || !groupName.trim()}
>
{#if loading}
<span class="loading loading-spinner"></span>
Criando grupo...
{:else}
<Plus class="w-5 h-5" />
Criar Grupo
{/if}
</button>
{#if selectedUsers.length < 2 && activeTab === "grupo"}
<p class="text-xs text-base-content/50 text-center mt-2">
Selecione pelo menos 2 participantes
</p>
{/if}
</div>
{:else if activeTab === "sala_reuniao"}
<div class="px-6 py-4 border-t border-base-300 bg-base-200/50">
<button
type="button"
class="btn btn-primary btn-block btn-lg font-semibold shadow-lg hover:shadow-xl transition-all duration-200"
onclick={handleCriarSalaReuniao}
disabled={loading ||
selectedUsers.length < 1 ||
!salaReuniaoName.trim()}
>
{#if loading}
<span class="loading loading-spinner"></span>
Criando sala...
{:else}
<Plus class="w-5 h-5" />
Criar Sala de Reunião
{/if}
</button>
{#if selectedUsers.length < 1 && activeTab === "sala_reuniao"}
<p class="text-xs text-base-content/50 text-center mt-2">
Selecione pelo menos 1 participante
</p>
{/if}
</div>
{/if}
</div>
<form method="dialog" class="modal-backdrop">
<button type="button" onclick={onClose}>fechar</button>
</form>
</dialog>