205 lines
5.6 KiB
Svelte
205 lines
5.6 KiB
Svelte
<script lang="ts">
|
|
import { api } from '@sgse-app/backend/convex/_generated/api';
|
|
import type { Id, Doc } from '@sgse-app/backend/convex/_generated/dataModel';
|
|
import { useConvexClient } from 'convex-svelte';
|
|
import { XCircle, AlertTriangle, X, Clock } from 'lucide-svelte';
|
|
|
|
type PeriodoFerias = Doc<'ferias'> & {
|
|
funcionario?: Doc<'funcionarios'> | null;
|
|
gestor?: Doc<'usuarios'> | null;
|
|
time?: Doc<'times'> | null;
|
|
};
|
|
|
|
interface Props {
|
|
solicitacao: PeriodoFerias;
|
|
usuarioId: Id<'usuarios'>;
|
|
onSucesso?: () => void;
|
|
onCancelar?: () => void;
|
|
}
|
|
|
|
const { solicitacao, usuarioId, onSucesso, onCancelar }: Props = $props();
|
|
|
|
const client = useConvexClient();
|
|
|
|
let processando = $state(false);
|
|
let erro = $state('');
|
|
|
|
function getStatusBadge(status: string) {
|
|
const badges: Record<string, string> = {
|
|
aguardando_aprovacao: 'badge-warning',
|
|
aprovado: 'badge-success',
|
|
reprovado: 'badge-error',
|
|
data_ajustada_aprovada: 'badge-info',
|
|
EmFérias: 'badge-info',
|
|
Cancelado_RH: 'badge-error'
|
|
};
|
|
return badges[status] || 'badge-neutral';
|
|
}
|
|
|
|
function getStatusTexto(status: string) {
|
|
const textos: Record<string, string> = {
|
|
aguardando_aprovacao: 'Aguardando Aprovação',
|
|
aprovado: 'Aprovado',
|
|
reprovado: 'Reprovado',
|
|
data_ajustada_aprovada: 'Data Ajustada e Aprovada',
|
|
EmFérias: 'Em Férias',
|
|
Cancelado_RH: 'Cancelado RH'
|
|
};
|
|
return textos[status] || status;
|
|
}
|
|
|
|
async function cancelarPorRH() {
|
|
try {
|
|
processando = true;
|
|
erro = '';
|
|
|
|
await client.mutation(api.ferias.atualizarStatus, {
|
|
feriasId: solicitacao._id,
|
|
novoStatus: 'Cancelado_RH',
|
|
usuarioId: usuarioId
|
|
});
|
|
|
|
if (onSucesso) onSucesso();
|
|
} catch (e) {
|
|
erro = e instanceof Error ? e.message : String(e);
|
|
} finally {
|
|
processando = false;
|
|
}
|
|
}
|
|
|
|
function formatarData(data: number) {
|
|
return new Date(data).toLocaleString('pt-BR');
|
|
}
|
|
</script>
|
|
|
|
<div class="card bg-base-100 shadow-xl">
|
|
<div class="card-body">
|
|
<div class="mb-4 flex items-start justify-between">
|
|
<div>
|
|
<h2 class="card-title text-2xl">
|
|
{solicitacao.funcionario?.nome || 'Funcionário'}
|
|
</h2>
|
|
<p class="text-base-content/70 mt-1 text-sm">
|
|
Ano de Referência: {solicitacao.anoReferencia}
|
|
</p>
|
|
</div>
|
|
<div class={`badge ${getStatusBadge(solicitacao.status)} badge-lg`}>
|
|
{getStatusTexto(solicitacao.status)}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Período Solicitado -->
|
|
<div class="mt-4">
|
|
<h3 class="mb-3 text-lg font-semibold">Período Solicitado</h3>
|
|
<div class="bg-base-200 rounded-lg p-4">
|
|
<div class="grid grid-cols-3 gap-4 text-sm">
|
|
<div>
|
|
<span class="text-base-content/70">Início:</span>
|
|
<span class="ml-1 font-semibold"
|
|
>{new Date(solicitacao.dataInicio).toLocaleDateString('pt-BR')}</span
|
|
>
|
|
</div>
|
|
<div>
|
|
<span class="text-base-content/70">Fim:</span>
|
|
<span class="ml-1 font-semibold"
|
|
>{new Date(solicitacao.dataFim).toLocaleDateString('pt-BR')}</span
|
|
>
|
|
</div>
|
|
<div>
|
|
<span class="text-base-content/70">Dias:</span>
|
|
<span class="text-primary ml-1 font-bold">{solicitacao.diasFerias}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Observações -->
|
|
{#if solicitacao.observacao}
|
|
<div class="mt-4">
|
|
<h3 class="mb-2 font-semibold">Observações</h3>
|
|
<div class="bg-base-200 rounded-lg p-3 text-sm">
|
|
{solicitacao.observacao}
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
|
|
<!-- Histórico -->
|
|
{#if solicitacao.historicoAlteracoes && solicitacao.historicoAlteracoes.length > 0}
|
|
<div class="mt-4">
|
|
<h3 class="mb-2 font-semibold">Histórico</h3>
|
|
<div class="space-y-1">
|
|
{#each solicitacao.historicoAlteracoes as hist (hist.data)}
|
|
<div class="text-base-content/70 flex items-center gap-2 text-xs">
|
|
<Clock class="h-3 w-3" strokeWidth={2} />
|
|
<span>{formatarData(hist.data)}</span>
|
|
<span>-</span>
|
|
<span>{hist.acao}</span>
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
|
|
<!-- Ação: Cancelar por RH -->
|
|
{#if solicitacao.status !== 'Cancelado_RH'}
|
|
<div class="divider mt-6"></div>
|
|
<div class="alert alert-warning">
|
|
<AlertTriangle class="h-6 w-6 shrink-0 stroke-current" />
|
|
<div>
|
|
<h3 class="font-bold">Cancelar Férias</h3>
|
|
<div class="text-sm">
|
|
Ao cancelar as férias, o status será alterado para "Cancelado RH" e a solicitação não
|
|
poderá mais ser processada.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-actions mt-4 justify-end">
|
|
<button
|
|
type="button"
|
|
class="btn btn-error gap-2"
|
|
onclick={cancelarPorRH}
|
|
disabled={processando}
|
|
>
|
|
<X class="h-5 w-5" strokeWidth={2} />
|
|
Cancelar Férias (RH)
|
|
</button>
|
|
</div>
|
|
{:else}
|
|
<div class="divider mt-6"></div>
|
|
<div class="alert alert-error">
|
|
<XCircle class="h-6 w-6 shrink-0 stroke-current" />
|
|
<span>Esta solicitação já foi cancelada pelo RH.</span>
|
|
</div>
|
|
{/if}
|
|
|
|
<!-- Motivo Reprovação (se reprovado) -->
|
|
{#if solicitacao.status === 'reprovado' && solicitacao.motivoReprovacao}
|
|
<div class="alert alert-error mt-4">
|
|
<XCircle class="h-6 w-6 shrink-0 stroke-current" />
|
|
<div>
|
|
<div class="font-bold">Motivo da Reprovação:</div>
|
|
<div class="text-sm">{solicitacao.motivoReprovacao}</div>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
|
|
<!-- Erro -->
|
|
{#if erro}
|
|
<div class="alert alert-error mt-4">
|
|
<XCircle class="h-6 w-6 shrink-0 stroke-current" />
|
|
<span>{erro}</span>
|
|
</div>
|
|
{/if}
|
|
|
|
<!-- Botão Fechar -->
|
|
{#if onCancelar}
|
|
<div class="card-actions mt-4 justify-end">
|
|
<button type="button" class="btn" onclick={onCancelar} disabled={processando}>
|
|
Cancelar
|
|
</button>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
</div>
|