refactor: integrate current user data across components

- Replaced instances of `authStore` with `currentUser` to streamline user authentication handling.
- Updated permission checks and user-related data retrieval to utilize the new `useQuery` for better performance and clarity.
- Cleaned up component structures and improved formatting for consistency and readability.
- Enhanced error handling and user feedback mechanisms in various components to improve user experience.
This commit is contained in:
2025-11-08 10:52:33 -03:00
parent 01138b3e1c
commit 9a5f2b294d
28 changed files with 2312 additions and 1235 deletions

View File

@@ -4,7 +4,15 @@
import type { Id } from "@sgse-app/backend/convex/_generated/dataModel";
import UserAvatar from "./UserAvatar.svelte";
import UserStatusBadge from "./UserStatusBadge.svelte";
import { X, Users, UserPlus, ArrowUp, ArrowDown, Trash2, Search } from "lucide-svelte";
import {
X,
Users,
UserPlus,
ArrowUp,
ArrowDown,
Trash2,
Search,
} from "lucide-svelte";
interface Props {
conversaId: Id<"conversas">;
@@ -37,17 +45,18 @@
const conv = conversa();
const usuarios = todosUsuarios();
if (!conv || !usuarios || usuarios.length === 0) return [];
const participantesInfo = conv.participantesInfo || [];
if (!Array.isArray(participantesInfo) || participantesInfo.length === 0) return [];
if (!Array.isArray(participantesInfo) || participantesInfo.length === 0)
return [];
return participantesInfo
.map((p: any) => {
try {
// p pode ser um objeto com _id ou apenas um ID
const participanteId = p?._id || p;
if (!participanteId) return null;
const usuario = usuarios.find((u: any) => {
try {
return String(u?._id) === String(participanteId);
@@ -56,13 +65,15 @@
}
});
if (!usuario) return null;
// Combinar dados do usuário com dados do participante (se p for objeto)
return {
...usuario,
...(typeof p === 'object' && p !== null && p !== undefined ? p : {}),
...(typeof p === "object" && p !== null && p !== undefined
? p
: {}),
// Garantir que _id existe e priorizar o do usuario
_id: usuario._id
_id: usuario._id,
};
} catch (err) {
console.error("Erro ao processar participante:", err, p);
@@ -84,17 +95,21 @@
const usuarios = todosUsuarios();
if (!usuarios || usuarios.length === 0) return [];
const participantesIds = conversa()?.participantes || [];
return usuarios.filter((u: any) => !participantesIds.some((pid: any) => String(pid) === String(u._id)));
return usuarios.filter(
(u: any) =>
!participantesIds.some((pid: any) => String(pid) === String(u._id)),
);
});
const usuariosFiltrados = $derived(() => {
const disponiveis = usuariosDisponiveis();
if (!searchQuery.trim()) return disponiveis;
const query = searchQuery.toLowerCase();
return disponiveis.filter((u: any) =>
(u.nome || "").toLowerCase().includes(query) ||
(u.email || "").toLowerCase().includes(query) ||
(u.matricula || "").toLowerCase().includes(query)
return disponiveis.filter(
(u: any) =>
(u.nome || "").toLowerCase().includes(query) ||
(u.email || "").toLowerCase().includes(query) ||
(u.matricula || "").toLowerCase().includes(query),
);
});
@@ -114,10 +129,13 @@
try {
loading = `remover-${participanteId}`;
error = null;
const resultado = await client.mutation(api.chat.removerParticipanteSala, {
conversaId,
participanteId: participanteId as any,
});
const resultado = await client.mutation(
api.chat.removerParticipanteSala,
{
conversaId,
participanteId: participanteId as any,
},
);
if (!resultado.sucesso) {
error = resultado.erro || "Erro ao remover participante";
@@ -175,10 +193,13 @@
try {
loading = `adicionar-${usuarioId}`;
error = null;
const resultado = await client.mutation(api.chat.adicionarParticipanteSala, {
conversaId,
participanteId: usuarioId as any,
});
const resultado = await client.mutation(
api.chat.adicionarParticipanteSala,
{
conversaId,
participanteId: usuarioId as any,
},
);
if (!resultado.sucesso) {
error = resultado.erro || "Erro ao adicionar participante";
@@ -193,16 +214,26 @@
}
</script>
<dialog class="modal modal-open" onclick={(e) => e.target === e.currentTarget && onClose()}>
<div class="modal-box max-w-2xl max-h-[80vh] flex flex-col p-0" onclick={(e) => e.stopPropagation()}>
<dialog
class="modal modal-open"
onclick={(e) => e.target === e.currentTarget && onClose()}
>
<div
class="modal-box max-w-2xl max-h-[80vh] 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">
<div
class="flex items-center justify-between px-6 py-4 border-b border-base-300"
>
<div>
<h2 class="text-xl font-semibold flex items-center gap-2">
<Users class="w-5 h-5 text-primary" />
Gerenciar Sala de Reunião
</h2>
<p class="text-sm text-base-content/60">{conversa()?.nome || "Sem nome"}</p>
<p class="text-sm text-base-content/60">
{conversa()?.nome || "Sem nome"}
</p>
</div>
<button
type="button"
@@ -240,7 +271,11 @@
{#if error}
<div class="mx-6 mt-2 alert alert-error">
<span>{error}</span>
<button type="button" class="btn btn-sm btn-ghost" onclick={() => (error = null)}>
<button
type="button"
class="btn btn-sm btn-ghost"
onclick={() => (error = null)}
>
<X class="w-4 h-4" />
</button>
</div>
@@ -252,13 +287,17 @@
<!-- Loading conversas -->
<div class="flex items-center justify-center py-8">
<span class="loading loading-spinner loading-lg"></span>
<span class="ml-2 text-sm text-base-content/60">Carregando conversa...</span>
<span class="ml-2 text-sm text-base-content/60"
>Carregando conversa...</span
>
</div>
{:else if !todosUsuariosQuery?.data}
<!-- Loading usuários -->
<div class="flex items-center justify-center py-8">
<span class="loading loading-spinner loading-lg"></span>
<span class="ml-2 text-sm text-base-content/60">Carregando usuários...</span>
<span class="ml-2 text-sm text-base-content/60"
>Carregando usuários...</span
>
</div>
{:else if activeTab === "participantes"}
<!-- Lista de Participantes -->
@@ -273,27 +312,34 @@
class="flex items-center gap-3 p-3 rounded-lg border border-base-300 hover:bg-base-200 transition-colors"
>
<!-- Avatar -->
<div class="relative flex-shrink-0">
<div class="relative shrink-0">
<UserAvatar
avatar={participante.avatar}
fotoPerfilUrl={participante.fotoPerfilUrl || participante.fotoPerfil}
fotoPerfilUrl={participante.fotoPerfilUrl ||
participante.fotoPerfil}
nome={participante.nome || "Usuário"}
size="sm"
/>
<div class="absolute bottom-0 right-0">
<UserStatusBadge status={participante.statusPresenca || "offline"} size="sm" />
<UserStatusBadge
status={participante.statusPresenca || "offline"}
size="sm"
/>
</div>
</div>
<!-- Info -->
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2">
<p class="font-medium text-base-content truncate">{participante.nome || "Usuário"}</p>
<p class="font-medium text-base-content truncate">
{participante.nome || "Usuário"}
</p>
{#if ehAdmin}
<span class="badge badge-primary badge-sm">Admin</span>
{/if}
{#if ehCriador}
<span class="badge badge-secondary badge-sm">Criador</span>
<span class="badge badge-secondary badge-sm">Criador</span
>
{/if}
</div>
<p class="text-sm text-base-content/60 truncate">
@@ -313,7 +359,8 @@
title="Rebaixar administrador"
>
{#if isLoading && loading?.includes("rebaixar")}
<span class="loading loading-spinner loading-xs"></span>
<span class="loading loading-spinner loading-xs"
></span>
{:else}
<ArrowDown class="w-4 h-4" />
{/if}
@@ -327,7 +374,8 @@
title="Promover a administrador"
>
{#if isLoading && loading?.includes("promover")}
<span class="loading loading-spinner loading-xs"></span>
<span class="loading loading-spinner loading-xs"
></span>
{:else}
<ArrowUp class="w-4 h-4" />
{/if}
@@ -365,7 +413,9 @@
class="input input-bordered w-full pl-10"
bind:value={searchQuery}
/>
<Search class="w-5 h-5 absolute left-3 top-1/2 -translate-y-1/2 text-base-content/40" />
<Search
class="w-5 h-5 absolute left-3 top-1/2 -translate-y-1/2 text-base-content/40"
/>
</div>
<div class="space-y-2">
@@ -380,7 +430,7 @@
disabled={isLoading}
>
<!-- Avatar -->
<div class="relative flex-shrink-0">
<div class="relative shrink-0">
<UserAvatar
avatar={usuario.avatar}
fotoPerfilUrl={usuario.fotoPerfilUrl || usuario.fotoPerfil}
@@ -388,13 +438,18 @@
size="sm"
/>
<div class="absolute bottom-0 right-0">
<UserStatusBadge status={usuario.statusPresenca || "offline"} size="sm" />
<UserStatusBadge
status={usuario.statusPresenca || "offline"}
size="sm"
/>
</div>
</div>
<!-- Info -->
<div class="flex-1 min-w-0">
<p class="font-medium text-base-content truncate">{usuario.nome || "Usuário"}</p>
<p class="font-medium text-base-content truncate">
{usuario.nome || "Usuário"}
</p>
<p class="text-sm text-base-content/60 truncate">
{usuario.setor || usuario.email || ""}
</p>
@@ -410,7 +465,9 @@
{/each}
{:else}
<div class="text-center py-8 text-base-content/50">
{searchQuery.trim() ? "Nenhum usuário encontrado" : "Todos os usuários já são participantes"}
{searchQuery.trim()
? "Nenhum usuário encontrado"
: "Todos os usuários já são participantes"}
</div>
{/if}
</div>
@@ -428,4 +485,3 @@
<button type="button" onclick={onClose}>fechar</button>
</form>
</dialog>