refactor: clean up Svelte components and improve code readability

- Refactored multiple Svelte components to enhance code clarity and maintainability.
- Standardized formatting and indentation across various files for consistency.
- Improved error handling messages in the AprovarAusencias component for better user feedback.
- Updated class names in the UI components to align with the new design system.
- Removed unnecessary whitespace and comments to streamline the codebase.
This commit is contained in:
2025-11-08 10:11:40 -03:00
parent 28107b4050
commit 01138b3e1c
24 changed files with 4655 additions and 1927 deletions

View File

@@ -6,7 +6,17 @@
import { ptBR } from "date-fns/locale";
import { onMount } from "svelte";
import { authStore } from "$lib/stores/auth.svelte";
import { Bell, Mail, AtSign, Users, Calendar, Clock, BellOff, Trash2, X } from "lucide-svelte";
import {
Bell,
Mail,
AtSign,
Users,
Calendar,
Clock,
BellOff,
Trash2,
X,
} from "lucide-svelte";
// Queries e Client
const client = useConvexClient();
@@ -18,31 +28,46 @@
});
let modalOpen = $state(false);
let notificacoesFerias = $state<Array<{ _id: string; mensagem: string; tipo: string; _creationTime: number }>>([]);
let notificacoesAusencias = $state<Array<{ _id: string; mensagem: string; tipo: string; _creationTime: number }>>([]);
let notificacoesFerias = $state<
Array<{
_id: string;
mensagem: string;
tipo: string;
_creationTime: number;
}>
>([]);
let notificacoesAusencias = $state<
Array<{
_id: string;
mensagem: string;
tipo: string;
_creationTime: number;
}>
>([]);
let limpandoNotificacoes = $state(false);
// Helpers para obter valores das queries
const count = $derived(
(typeof countQuery === "number" ? countQuery : countQuery?.data) ?? 0
(typeof countQuery === "number" ? countQuery : countQuery?.data) ?? 0,
);
const todasNotificacoes = $derived(
(Array.isArray(todasNotificacoesQuery)
? todasNotificacoesQuery
: todasNotificacoesQuery?.data) ?? []
: todasNotificacoesQuery?.data) ?? [],
);
// Separar notificações lidas e não lidas
const notificacoesNaoLidas = $derived(
todasNotificacoes.filter((n) => !n.lida)
);
const notificacoesLidas = $derived(
todasNotificacoes.filter((n) => n.lida)
todasNotificacoes.filter((n) => !n.lida),
);
const notificacoesLidas = $derived(todasNotificacoes.filter((n) => n.lida));
// Atualizar contador no store
$effect(() => {
const totalNotificacoes = count + (notificacoesFerias?.length || 0) + (notificacoesAusencias?.length || 0);
const totalNotificacoes =
count +
(notificacoesFerias?.length || 0) +
(notificacoesAusencias?.length || 0);
notificacoesCount.set(totalNotificacoes);
});
@@ -56,7 +81,7 @@
api.ferias.obterNotificacoesNaoLidas,
{
usuarioId: usuarioStore.usuario._id,
}
},
);
notificacoesFerias = notifsFerias || [];
}
@@ -76,14 +101,20 @@
api.ausencias.obterNotificacoesNaoLidas,
{
usuarioId: usuarioStore.usuario._id,
}
},
);
notificacoesAusencias = notifsAusencias || [];
} catch (queryError: unknown) {
// Silenciar erro se a função não estiver disponível ainda (Convex não sincronizado)
const errorMessage = queryError instanceof Error ? queryError.message : String(queryError);
const errorMessage =
queryError instanceof Error
? queryError.message
: String(queryError);
if (!errorMessage.includes("Could not find public function")) {
console.error("Erro ao buscar notificações de ausências:", queryError);
console.error(
"Erro ao buscar notificações de ausências:",
queryError,
);
}
notificacoesAusencias = [];
}
@@ -201,7 +232,10 @@
function handleClickOutside(event: MouseEvent) {
const target = event.target as HTMLElement;
if (!target.closest(".notification-popup") && !target.closest(".notification-bell")) {
if (
!target.closest(".notification-popup") &&
!target.closest(".notification-bell")
) {
modalOpen = false;
}
}
@@ -233,7 +267,7 @@
>
<!-- Efeito de brilho no hover -->
<div
class="absolute inset-0 bg-gradient-to-br from-white/0 to-white/20 opacity-0 group-hover:opacity-100 transition-opacity duration-300"
class="absolute inset-0 bg-linear-to-br from-white/0 to-white/20 opacity-0 group-hover:opacity-100 transition-opacity duration-300"
></div>
<!-- Anel de pulso sutil -->
@@ -271,52 +305,59 @@
{/if}
</button>
<!-- Popup Flutuante de Notificações -->
{#if modalOpen}
<div class="notification-popup fixed right-4 top-24 z-[100] w-[calc(100vw-2rem)] max-w-2xl max-h-[calc(100vh-7rem)] flex flex-col bg-base-100 rounded-2xl shadow-2xl border border-base-300 overflow-hidden backdrop-blur-sm" style="animation: slideDown 0.2s ease-out;">
<!-- Header -->
<div class="flex items-center justify-between px-6 py-4 border-b border-base-300 bg-gradient-to-r from-primary/5 to-primary/10">
<h3 class="text-2xl font-bold text-primary">Notificações</h3>
<div class="flex items-center gap-2">
{#if notificacoesNaoLidas.length > 0}
<!-- Popup Flutuante de Notificações -->
{#if modalOpen}
<div
class="notification-popup fixed right-4 top-24 z-[100] w-[calc(100vw-2rem)] max-w-2xl max-h-[calc(100vh-7rem)] flex flex-col bg-base-100 rounded-2xl shadow-2xl border border-base-300 overflow-hidden backdrop-blur-sm"
style="animation: slideDown 0.2s ease-out;"
>
<!-- Header -->
<div
class="flex items-center justify-between px-6 py-4 border-b border-base-300 bg-linear-to-r from-primary/5 to-primary/10"
>
<h3 class="text-2xl font-bold text-primary">Notificações</h3>
<div class="flex items-center gap-2">
{#if notificacoesNaoLidas.length > 0}
<button
type="button"
class="btn btn-sm btn-ghost"
onclick={handleLimparNotificacoesNaoLidas}
disabled={limpandoNotificacoes}
>
<Trash2 class="w-4 h-4" />
Limpar não lidas
</button>
{/if}
{#if todasNotificacoes.length > 0}
<button
type="button"
class="btn btn-sm btn-error btn-outline"
onclick={handleLimparTodasNotificacoes}
disabled={limpandoNotificacoes}
>
<Trash2 class="w-4 h-4" />
Limpar todas
</button>
{/if}
<button
type="button"
class="btn btn-sm btn-ghost"
onclick={handleLimparNotificacoesNaoLidas}
disabled={limpandoNotificacoes}
class="btn btn-sm btn-circle btn-ghost"
onclick={closeModal}
>
<Trash2 class="w-4 h-4" />
Limpar não lidas
<X class="w-5 h-5" />
</button>
{/if}
{#if todasNotificacoes.length > 0}
<button
type="button"
class="btn btn-sm btn-error btn-outline"
onclick={handleLimparTodasNotificacoes}
disabled={limpandoNotificacoes}
>
<Trash2 class="w-4 h-4" />
Limpar todas
</button>
{/if}
<button
type="button"
class="btn btn-sm btn-circle btn-ghost"
onclick={closeModal}
>
<X class="w-5 h-5" />
</button>
</div>
</div>
</div>
<!-- Lista de notificações -->
<div class="flex-1 overflow-y-auto px-2 py-4">
<!-- Lista de notificações -->
<div class="flex-1 overflow-y-auto px-2 py-4">
{#if todasNotificacoes.length > 0 || notificacoesFerias.length > 0 || notificacoesAusencias.length > 0}
<!-- Notificações não lidas -->
{#if notificacoesNaoLidas.length > 0}
<div class="mb-4">
<h4 class="text-sm font-semibold text-primary mb-2 px-2">Não lidas</h4>
<h4 class="text-sm font-semibold text-primary mb-2 px-2">
Não lidas
</h4>
{#each notificacoesNaoLidas as notificacao (notificacao._id)}
<button
type="button"
@@ -329,7 +370,10 @@
{#if notificacao.tipo === "nova_mensagem"}
<Mail class="w-5 h-5 text-primary" strokeWidth={1.5} />
{:else if notificacao.tipo === "mencao"}
<AtSign class="w-5 h-5 text-warning" strokeWidth={1.5} />
<AtSign
class="w-5 h-5 text-warning"
strokeWidth={1.5}
/>
{:else}
<Users class="w-5 h-5 text-info" strokeWidth={1.5} />
{/if}
@@ -341,21 +385,27 @@
<p class="text-sm font-semibold text-primary">
{notificacao.remetente.nome}
</p>
<p class="text-xs text-base-content/70 mt-1 line-clamp-2">
<p
class="text-xs text-base-content/70 mt-1 line-clamp-2"
>
{notificacao.descricao}
</p>
{:else if notificacao.tipo === "mencao" && notificacao.remetente}
<p class="text-sm font-semibold text-warning">
{notificacao.remetente.nome} mencionou você
</p>
<p class="text-xs text-base-content/70 mt-1 line-clamp-2">
<p
class="text-xs text-base-content/70 mt-1 line-clamp-2"
>
{notificacao.descricao}
</p>
{:else}
<p class="text-sm font-semibold text-base-content">
{notificacao.titulo}
</p>
<p class="text-xs text-base-content/70 mt-1 line-clamp-2">
<p
class="text-xs text-base-content/70 mt-1 line-clamp-2"
>
{notificacao.descricao}
</p>
{/if}
@@ -377,7 +427,9 @@
<!-- Notificações lidas -->
{#if notificacoesLidas.length > 0}
<div class="mb-4">
<h4 class="text-sm font-semibold text-base-content/60 mb-2 px-2">Lidas</h4>
<h4 class="text-sm font-semibold text-base-content/60 mb-2 px-2">
Lidas
</h4>
{#each notificacoesLidas as notificacao (notificacao._id)}
<button
type="button"
@@ -388,9 +440,15 @@
<!-- Ícone -->
<div class="flex-shrink-0 mt-1">
{#if notificacao.tipo === "nova_mensagem"}
<Mail class="w-5 h-5 text-primary/60" strokeWidth={1.5} />
<Mail
class="w-5 h-5 text-primary/60"
strokeWidth={1.5}
/>
{:else if notificacao.tipo === "mencao"}
<AtSign class="w-5 h-5 text-warning/60" strokeWidth={1.5} />
<AtSign
class="w-5 h-5 text-warning/60"
strokeWidth={1.5}
/>
{:else}
<Users class="w-5 h-5 text-info/60" strokeWidth={1.5} />
{/if}
@@ -402,21 +460,27 @@
<p class="text-sm font-medium text-primary/70">
{notificacao.remetente.nome}
</p>
<p class="text-xs text-base-content/60 mt-1 line-clamp-2">
<p
class="text-xs text-base-content/60 mt-1 line-clamp-2"
>
{notificacao.descricao}
</p>
{:else if notificacao.tipo === "mencao" && notificacao.remetente}
<p class="text-sm font-medium text-warning/70">
{notificacao.remetente.nome} mencionou você
</p>
<p class="text-xs text-base-content/60 mt-1 line-clamp-2">
<p
class="text-xs text-base-content/60 mt-1 line-clamp-2"
>
{notificacao.descricao}
</p>
{:else}
<p class="text-sm font-medium text-base-content/70">
{notificacao.titulo}
</p>
<p class="text-xs text-base-content/60 mt-1 line-clamp-2">
<p
class="text-xs text-base-content/60 mt-1 line-clamp-2"
>
{notificacao.descricao}
</p>
{/if}
@@ -433,7 +497,9 @@
<!-- Notificações de Férias -->
{#if notificacoesFerias.length > 0}
<div class="mb-4">
<h4 class="text-sm font-semibold text-purple-600 mb-2 px-2">Férias</h4>
<h4 class="text-sm font-semibold text-purple-600 mb-2 px-2">
Férias
</h4>
{#each notificacoesFerias as notificacao (notificacao._id)}
<button
type="button"
@@ -443,7 +509,10 @@
<div class="flex items-start gap-3">
<!-- Ícone -->
<div class="flex-shrink-0 mt-1">
<Calendar class="w-5 h-5 text-purple-600" strokeWidth={2} />
<Calendar
class="w-5 h-5 text-purple-600"
strokeWidth={2}
/>
</div>
<!-- Conteúdo -->
@@ -469,12 +538,15 @@
<!-- Notificações de Ausências -->
{#if notificacoesAusencias.length > 0}
<div class="mb-4">
<h4 class="text-sm font-semibold text-orange-600 mb-2 px-2">Ausências</h4>
<h4 class="text-sm font-semibold text-orange-600 mb-2 px-2">
Ausências
</h4>
{#each notificacoesAusencias as notificacao (notificacao._id)}
<button
type="button"
class="w-full text-left px-4 py-3 hover:bg-base-200 rounded-lg transition-colors mb-2 border-l-4 border-orange-600"
onclick={() => handleClickNotificacaoAusencias(notificacao._id)}
onclick={() =>
handleClickNotificacaoAusencias(notificacao._id)}
>
<div class="flex items-start gap-3">
<!-- Ícone -->
@@ -504,30 +576,37 @@
{:else}
<!-- Sem notificações -->
<div class="px-4 py-12 text-center text-base-content/50">
<BellOff class="w-16 h-16 mx-auto mb-4 opacity-50" strokeWidth={1.5} />
<BellOff
class="w-16 h-16 mx-auto mb-4 opacity-50"
strokeWidth={1.5}
/>
<p class="text-base font-medium">Nenhuma notificação</p>
<p class="text-sm mt-1">Você está em dia!</p>
</div>
{/if}
</div>
<!-- Footer com estatísticas -->
{#if todasNotificacoes.length > 0 || notificacoesFerias.length > 0 || notificacoesAusencias.length > 0}
<div class="px-6 py-4 border-t border-base-300 bg-base-200/50">
<div class="flex items-center justify-between text-xs text-base-content/60">
<span>
Total: {todasNotificacoes.length + notificacoesFerias.length + notificacoesAusencias.length} notificações
</span>
{#if notificacoesNaoLidas.length > 0}
<span class="text-primary font-semibold">
{notificacoesNaoLidas.length} não lidas
<!-- Footer com estatísticas -->
{#if todasNotificacoes.length > 0 || notificacoesFerias.length > 0 || notificacoesAusencias.length > 0}
<div class="px-6 py-4 border-t border-base-300 bg-base-200/50">
<div
class="flex items-center justify-between text-xs text-base-content/60"
>
<span>
Total: {todasNotificacoes.length +
notificacoesFerias.length +
notificacoesAusencias.length} notificações
</span>
{/if}
{#if notificacoesNaoLidas.length > 0}
<span class="text-primary font-semibold">
{notificacoesNaoLidas.length} não lidas
</span>
{/if}
</div>
</div>
</div>
{/if}
</div>
{/if}
{/if}
</div>
{/if}
</div>
<style>
@@ -582,4 +661,3 @@
}
}
</style>