|
|
|
|
@@ -1,18 +1,27 @@
|
|
|
|
|
<script lang="ts">
|
|
|
|
|
import { useConvexClient, useQuery } from 'convex-svelte';
|
|
|
|
|
import { api } from '@sgse-app/backend/convex/_generated/api';
|
|
|
|
|
import { useConvexClient, useQuery } from 'convex-svelte';
|
|
|
|
|
import { api } from '@sgse-app/backend/convex/_generated/api';
|
|
|
|
|
import AprovarFerias from '$lib/components/AprovarFerias.svelte';
|
|
|
|
|
import WizardSolicitacaoFerias from '$lib/components/ferias/WizardSolicitacaoFerias.svelte';
|
|
|
|
|
import WizardSolicitacaoAusencia from '$lib/components/ausencias/WizardSolicitacaoAusencia.svelte';
|
|
|
|
|
import AprovarAusencias from '$lib/components/AprovarAusencias.svelte';
|
|
|
|
|
import CalendarioAusencias from '$lib/components/ausencias/CalendarioAusencias.svelte';
|
|
|
|
|
import { generateAvatarGallery } from '$lib/utils/avatars';
|
|
|
|
|
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
|
|
|
|
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
|
|
|
|
import type { FunctionReturnType } from 'convex/server';
|
|
|
|
|
import { X, Calendar } from 'lucide-svelte';
|
|
|
|
|
import type { FunctionReturnType } from 'convex/server';
|
|
|
|
|
|
|
|
|
|
const client = useConvexClient();
|
|
|
|
|
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
|
|
|
|
const client = useConvexClient();
|
|
|
|
|
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
|
|
|
|
|
|
|
|
|
type FuncionarioAtual = FunctionReturnType<typeof api.funcionarios.getCurrent>;
|
|
|
|
|
type TimeAtual = FunctionReturnType<typeof api.times.obterTimeFuncionario>;
|
|
|
|
|
type MinhasSolicitacoes = FunctionReturnType<typeof api.ferias.listarMinhasSolicitacoes>;
|
|
|
|
|
type MinhasAusencias = FunctionReturnType<typeof api.ausencias.listarMinhasSolicitacoes>;
|
|
|
|
|
let funcionarioEstavel = $state<FuncionarioAtual | null>(null);
|
|
|
|
|
let meuTimeEstavel = $state<TimeAtual | null>(null);
|
|
|
|
|
let minhasSolicitacoesEstaveis = $state<MinhasSolicitacoes>([]);
|
|
|
|
|
let minhasAusenciasEstaveis = $state<MinhasAusencias>([]);
|
|
|
|
|
|
|
|
|
|
let abaAtiva = $state<
|
|
|
|
|
'meu-perfil' | 'minhas-ferias' | 'minhas-ausencias' | 'aprovar-ferias' | 'aprovar-ausencias'
|
|
|
|
|
@@ -44,126 +53,101 @@
|
|
|
|
|
// FuncionarioId disponível diretamente do usuário atual
|
|
|
|
|
const funcionarioIdDisponivel = $derived(currentUser?.data?.funcionarioId ?? null);
|
|
|
|
|
|
|
|
|
|
// Queries
|
|
|
|
|
const funcionarioQuery = $derived(
|
|
|
|
|
currentUser?.data?.funcionarioId ? useQuery(api.funcionarios.getCurrent, {}) : { data: null }
|
|
|
|
|
// Queries
|
|
|
|
|
const funcionarioQuery = $derived(
|
|
|
|
|
currentUser?.data?.funcionarioId ? useQuery(api.funcionarios.getCurrent, {}) : { data: null }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
if (funcionarioQuery?.data) {
|
|
|
|
|
funcionarioEstavel = funcionarioQuery.data;
|
|
|
|
|
} else if (!currentUser?.data?.funcionarioId) {
|
|
|
|
|
funcionarioEstavel = null;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const solicitacoesSubordinadosQuery = $derived(
|
|
|
|
|
currentUser?.data?._id
|
|
|
|
|
? useQuery(api.ferias.listarSolicitacoesSubordinados, {
|
|
|
|
|
gestorId: currentUser.data._id as Id<'usuarios'>
|
|
|
|
|
})
|
|
|
|
|
: { data: [] }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const ausenciasSubordinadosQuery = $derived(
|
|
|
|
|
currentUser?.data?._id
|
|
|
|
|
? useQuery(api.ausencias.listarSolicitacoesSubordinados, {
|
|
|
|
|
gestorId: currentUser.data._id as Id<'usuarios'>
|
|
|
|
|
})
|
|
|
|
|
: { data: [] }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const minhasSolicitacoesQuery = $derived(
|
|
|
|
|
funcionarioEstavel?._id
|
|
|
|
|
? useQuery(api.ferias.listarMinhasSolicitacoes, {
|
|
|
|
|
funcionarioId: funcionarioEstavel._id
|
|
|
|
|
})
|
|
|
|
|
: { data: [] }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const minhasAusenciasQuery = $derived(
|
|
|
|
|
funcionarioEstavel?._id
|
|
|
|
|
? useQuery(api.ausencias.listarMinhasSolicitacoes, {
|
|
|
|
|
funcionarioId: funcionarioEstavel._id
|
|
|
|
|
})
|
|
|
|
|
: { data: [] }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const meuTimeQuery = $derived(
|
|
|
|
|
funcionarioEstavel?._id
|
|
|
|
|
? useQuery(api.times.obterTimeFuncionario, {
|
|
|
|
|
funcionarioId: funcionarioEstavel._id
|
|
|
|
|
})
|
|
|
|
|
: { data: null }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
if (meuTimeQuery?.data) {
|
|
|
|
|
meuTimeEstavel = meuTimeQuery.data;
|
|
|
|
|
} else if (!funcionarioEstavel?._id) {
|
|
|
|
|
meuTimeEstavel = null;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const funcionario = $derived(funcionarioEstavel);
|
|
|
|
|
const solicitacoesSubordinados = $derived(solicitacoesSubordinadosQuery?.data || []);
|
|
|
|
|
const ausenciasSubordinados = $derived(ausenciasSubordinadosQuery?.data || []);
|
|
|
|
|
const meuTime = $derived(meuTimeEstavel);
|
|
|
|
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
if (Array.isArray(minhasSolicitacoesQuery?.data)) {
|
|
|
|
|
minhasSolicitacoesEstaveis = minhasSolicitacoesQuery.data;
|
|
|
|
|
} else if (!funcionarioEstavel?._id) {
|
|
|
|
|
minhasSolicitacoesEstaveis = [];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
if (Array.isArray(minhasAusenciasQuery?.data)) {
|
|
|
|
|
minhasAusenciasEstaveis = minhasAusenciasQuery.data;
|
|
|
|
|
} else if (!funcionarioEstavel?._id) {
|
|
|
|
|
minhasAusenciasEstaveis = [];
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const minhasSolicitacoes = $derived(minhasSolicitacoesEstaveis);
|
|
|
|
|
const minhasAusencias = $derived(minhasAusenciasEstaveis);
|
|
|
|
|
|
|
|
|
|
const timesSubordinadosQuery = $derived(useQuery(api.times.listarSubordinadosDoGestorAtual, {}));
|
|
|
|
|
const timesSubordinados = $derived(timesSubordinadosQuery?.data || []);
|
|
|
|
|
// Times gerenciados usam a query que já infere o gestor logado
|
|
|
|
|
const meusTimesGestor = $derived(timesSubordinados);
|
|
|
|
|
|
|
|
|
|
const rolePermiteAprovacao = $derived(
|
|
|
|
|
currentUser?.data?.role?.nome === 'TI_MASTER' || currentUser?.data?.role?.nome === 'TI_ADMIN'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const solicitacoesSubordinadosQuery = $derived(
|
|
|
|
|
currentUser?.data?._id
|
|
|
|
|
? useQuery(api.ferias.listarSolicitacoesSubordinados, {
|
|
|
|
|
gestorId: currentUser.data._id as Id<'usuarios'>
|
|
|
|
|
})
|
|
|
|
|
: { data: [] }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const ausenciasSubordinadosQuery = $derived(
|
|
|
|
|
currentUser?.data?._id
|
|
|
|
|
? useQuery(api.ausencias.listarSolicitacoesSubordinados, {
|
|
|
|
|
gestorId: currentUser.data._id as Id<'usuarios'>
|
|
|
|
|
})
|
|
|
|
|
: { data: [] }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const minhasSolicitacoesQuery = $derived(
|
|
|
|
|
funcionarioQuery.data
|
|
|
|
|
? useQuery(api.ferias.listarMinhasSolicitacoes, {
|
|
|
|
|
funcionarioId: funcionarioQuery.data._id
|
|
|
|
|
})
|
|
|
|
|
: { data: [] }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const minhasAusenciasQuery = $derived(
|
|
|
|
|
funcionarioQuery.data
|
|
|
|
|
? useQuery(api.ausencias.listarMinhasSolicitacoes, {
|
|
|
|
|
funcionarioId: funcionarioQuery.data._id
|
|
|
|
|
})
|
|
|
|
|
: { data: [] }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const meuTimeQuery = $derived(
|
|
|
|
|
funcionarioQuery.data
|
|
|
|
|
? useQuery(api.times.obterTimeFuncionario, {
|
|
|
|
|
funcionarioId: funcionarioQuery.data._id
|
|
|
|
|
})
|
|
|
|
|
: { data: null }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Query para times onde o usuário é gestor - usando $derived para garantir reatividade
|
|
|
|
|
const meusTimesGestorQuery = $derived(
|
|
|
|
|
currentUser?.data?._id
|
|
|
|
|
? useQuery(api.times.listarPorGestor, {
|
|
|
|
|
gestorId: currentUser.data._id as Id<'usuarios'>
|
|
|
|
|
})
|
|
|
|
|
: { data: [] }
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const funcionario = $derived(funcionarioQuery.data);
|
|
|
|
|
const solicitacoesSubordinados = $derived(solicitacoesSubordinadosQuery?.data || []);
|
|
|
|
|
const ausenciasSubordinados = $derived(ausenciasSubordinadosQuery?.data || []);
|
|
|
|
|
const minhasSolicitacoes = $derived(minhasSolicitacoesQuery?.data || []);
|
|
|
|
|
const minhasAusencias = $derived(minhasAusenciasQuery?.data || []);
|
|
|
|
|
const meuTime = $derived(meuTimeQuery?.data);
|
|
|
|
|
|
|
|
|
|
// Extração de meusTimesGestor
|
|
|
|
|
const meusTimesGestor = $derived(meusTimesGestorQuery?.data || []);
|
|
|
|
|
|
|
|
|
|
// Estado estável para controlar se é gestor (evita desaparecimento das abas)
|
|
|
|
|
let ehGestorEstavel = $state(false);
|
|
|
|
|
let ultimaVerificacaoGestor = $state<number | null>(null);
|
|
|
|
|
|
|
|
|
|
// Calcular se é gestor - com lógica mais robusta (sem atualizar estado aqui)
|
|
|
|
|
const ehGestorCalculado = $derived.by(() => {
|
|
|
|
|
// Verificar se tem times como gestor
|
|
|
|
|
const temTimesComoGestor = (meusTimesGestor || []).length > 0;
|
|
|
|
|
|
|
|
|
|
// Verificar se tem role de TI que pode aprovar (TI_MASTER, TI_ADMIN)
|
|
|
|
|
const rolePermiteAprovacao = currentUser?.data?.role?.nome === 'TI_MASTER' ||
|
|
|
|
|
currentUser?.data?.role?.nome === 'TI_ADMIN';
|
|
|
|
|
|
|
|
|
|
// Verificar se tem solicitações de subordinados (indica que é gestor)
|
|
|
|
|
const temSolicitacoesSubordinados = (solicitacoesSubordinados || []).length > 0 ||
|
|
|
|
|
(ausenciasSubordinados || []).length > 0;
|
|
|
|
|
|
|
|
|
|
// É gestor se: tem times OU tem role de TI OU tem solicitações de subordinados
|
|
|
|
|
return temTimesComoGestor || rolePermiteAprovacao || temSolicitacoesSubordinados;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Efeito para atualizar o estado estável (evita desaparecimento das abas)
|
|
|
|
|
$effect(() => {
|
|
|
|
|
const resultado = ehGestorCalculado;
|
|
|
|
|
|
|
|
|
|
// Log para depuração (apenas quando mudar)
|
|
|
|
|
if (import.meta.env.DEV && resultado !== ehGestorEstavel) {
|
|
|
|
|
console.log('🔍 [Perfil] Status de gestor mudou:', {
|
|
|
|
|
temTimesComoGestor: (meusTimesGestor || []).length > 0,
|
|
|
|
|
rolePermiteAprovacao: currentUser?.data?.role?.nome === 'TI_MASTER' || currentUser?.data?.role?.nome === 'TI_ADMIN',
|
|
|
|
|
role: currentUser?.data?.role?.nome,
|
|
|
|
|
temSolicitacoesSubordinados: (solicitacoesSubordinados || []).length > 0 || (ausenciasSubordinados || []).length > 0,
|
|
|
|
|
resultado,
|
|
|
|
|
meusTimesGestor: meusTimesGestor?.length || 0,
|
|
|
|
|
timestamp: new Date().toISOString()
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Atualizar estado estável apenas se o resultado for true (para manter as abas visíveis)
|
|
|
|
|
// ou se já passou tempo suficiente desde a última verificação
|
|
|
|
|
const agora = Date.now();
|
|
|
|
|
if (resultado) {
|
|
|
|
|
ehGestorEstavel = true;
|
|
|
|
|
ultimaVerificacaoGestor = agora;
|
|
|
|
|
} else if (ultimaVerificacaoGestor === null || (agora - ultimaVerificacaoGestor) > 5000) {
|
|
|
|
|
// Só atualiza para false se passou mais de 5 segundos desde a última verificação positiva
|
|
|
|
|
// Isso evita que as abas desapareçam durante atualizações temporárias das queries
|
|
|
|
|
ehGestorEstavel = resultado;
|
|
|
|
|
if (!resultado) {
|
|
|
|
|
ultimaVerificacaoGestor = agora;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Valor final usado para renderizar as abas
|
|
|
|
|
const ehGestor = $derived(ehGestorEstavel);
|
|
|
|
|
const ehGestor = $derived((timesSubordinados || []).length > 0 || rolePermiteAprovacao);
|
|
|
|
|
|
|
|
|
|
// Filtrar minhas solicitações
|
|
|
|
|
const solicitacoesFiltradas = $derived(
|
|
|
|
|
@@ -195,7 +179,8 @@
|
|
|
|
|
total: minhasSolicitacoes.length,
|
|
|
|
|
aguardando: minhasSolicitacoes.filter((s) => s.status === 'aguardando_aprovacao').length,
|
|
|
|
|
aprovadas: minhasSolicitacoes.filter(
|
|
|
|
|
(s) => s.status === 'aprovado' || s.status === 'data_ajustada_aprovada' || s.status === 'EmFérias'
|
|
|
|
|
(s) =>
|
|
|
|
|
s.status === 'aprovado' || s.status === 'data_ajustada_aprovada' || s.status === 'EmFérias'
|
|
|
|
|
).length,
|
|
|
|
|
reprovadas: minhasSolicitacoes.filter((s) => s.status === 'reprovado').length,
|
|
|
|
|
emFerias: funcionario?.statusFerias === 'em_ferias' ? 1 : 0
|
|
|
|
|
@@ -1396,7 +1381,9 @@
|
|
|
|
|
<tr>
|
|
|
|
|
<td>{periodo.anoReferencia}</td>
|
|
|
|
|
<td>
|
|
|
|
|
{formatarDataString(periodo.dataInicio)} - {formatarDataString(periodo.dataFim)}
|
|
|
|
|
{formatarDataString(periodo.dataInicio)} - {formatarDataString(
|
|
|
|
|
periodo.dataFim
|
|
|
|
|
)}
|
|
|
|
|
</td>
|
|
|
|
|
<td class="font-bold">{periodo.diasFerias} dias</td>
|
|
|
|
|
<td>
|
|
|
|
|
@@ -1773,9 +1760,8 @@
|
|
|
|
|
{#if periodo.time}
|
|
|
|
|
<div
|
|
|
|
|
class="badge badge-lg font-semibold"
|
|
|
|
|
style="background-color: {periodo.time
|
|
|
|
|
.cor}20; border-color: {periodo.time.cor}; color: {periodo.time
|
|
|
|
|
.cor}"
|
|
|
|
|
style="background-color: {periodo.time.cor}20; border-color: {periodo
|
|
|
|
|
.time.cor}; color: {periodo.time.cor}"
|
|
|
|
|
>
|
|
|
|
|
{periodo.time.nome}
|
|
|
|
|
</div>
|
|
|
|
|
@@ -1783,7 +1769,9 @@
|
|
|
|
|
</td>
|
|
|
|
|
<td class="font-semibold">{periodo.anoReferencia}</td>
|
|
|
|
|
<td class="font-semibold">
|
|
|
|
|
{formatarDataString(periodo.dataInicio)} - {formatarDataString(periodo.dataFim)}
|
|
|
|
|
{formatarDataString(periodo.dataInicio)} - {formatarDataString(
|
|
|
|
|
periodo.dataFim
|
|
|
|
|
)}
|
|
|
|
|
</td>
|
|
|
|
|
<td class="text-lg font-bold">{periodo.diasFerias}</td>
|
|
|
|
|
<td>
|
|
|
|
|
@@ -2286,9 +2274,18 @@
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
|
|
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
|
|
|
<div class="modal-backdrop" onclick={() => (mostrarWizard = false)}></div>
|
|
|
|
|
<div
|
|
|
|
|
class="modal-backdrop"
|
|
|
|
|
role="button"
|
|
|
|
|
tabindex="0"
|
|
|
|
|
onclick={() => (mostrarWizard = false)}
|
|
|
|
|
onkeydown={(event) => {
|
|
|
|
|
if (event.key === 'Enter' || event.key === ' ') {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
mostrarWizard = false;
|
|
|
|
|
}
|
|
|
|
|
}}
|
|
|
|
|
></div>
|
|
|
|
|
</dialog>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
|