feat: Add 'atas' (minutes/records) management feature, and implement various improvements across UI, backend logic, and authentication.

This commit is contained in:
2025-12-02 16:37:48 -03:00
parent 05e7f1181d
commit 4bd9e21748
265 changed files with 29156 additions and 26460 deletions

View File

@@ -1,14 +1,18 @@
<script lang="ts">
import { onMount } from 'svelte';
import { Calendar } from '@fullcalendar/core';
import ptBrLocale from '@fullcalendar/core/locales/pt-br';
import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin from '@fullcalendar/interaction';
import multiMonthPlugin from '@fullcalendar/multimonth';
import ptBrLocale from '@fullcalendar/core/locales/pt-br';
import { onMount } from 'svelte';
import { SvelteDate } from 'svelte/reactivity';
interface Props {
periodosExistentes?: Array<{ dataInicio: string; dataFim: string; dias: number }>;
periodosExistentes?: Array<{
dataInicio: string;
dataFim: string;
dias: number;
}>;
onPeriodoAdicionado?: (periodo: { dataInicio: string; dataFim: string; dias: number }) => void;
onPeriodoRemovido?: (index: number) => void;
maxPeriodos?: number;
@@ -17,7 +21,7 @@
readonly?: boolean;
}
let {
const {
periodosExistentes = [],
onPeriodoAdicionado,
onPeriodoRemovido,
@@ -99,7 +103,10 @@
selectable: !readonly,
selectMirror: true,
unselectAuto: false,
events: eventos.map((evento) => ({ ...evento, extendedProps: { ...evento.extendedProps } })),
events: eventos.map((evento) => ({
...evento,
extendedProps: { ...evento.extendedProps }
})),
// Estilo customizado
buttonText: {

View File

@@ -1,13 +1,13 @@
<script lang="ts">
import { useQuery } from 'convex-svelte';
import { api } from '@sgse-app/backend/convex/_generated/api';
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
import { useQuery } from 'convex-svelte';
interface Props {
funcionarioId: Id<'funcionarios'>;
}
let { funcionarioId }: Props = $props();
const { funcionarioId }: Props = $props();
// Queries
const saldosQuery = useQuery(api.saldoFerias.listarSaldos, { funcionarioId });
@@ -31,8 +31,8 @@
const reprovadas = $derived(solicitacoes.filter((s) => s.status === 'reprovado').length);
// Canvas para gráfico de pizza
let canvasSaldo = $state<HTMLCanvasElement>();
let canvasStatus = $state<HTMLCanvasElement>();
const canvasSaldo = $state<HTMLCanvasElement>();
const canvasStatus = $state<HTMLCanvasElement>();
// Função para desenhar gráfico de pizza moderno
function desenharGraficoPizza(

View File

@@ -1,8 +1,8 @@
<script lang="ts">
import { useQuery, useConvexClient } from 'convex-svelte';
import { api } from '@sgse-app/backend/convex/_generated/api';
import { toast } from 'svelte-sonner';
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
import { useConvexClient, useQuery } from 'convex-svelte';
import { toast } from 'svelte-sonner';
interface Props {
funcionarioId: Id<'funcionarios'>;
@@ -10,7 +10,7 @@
onCancelar?: () => void;
}
let { funcionarioId, onSucesso, onCancelar }: Props = $props();
const { funcionarioId, onSucesso, onCancelar }: Props = $props();
// Cliente Convex
const client = useConvexClient();
@@ -20,13 +20,13 @@
const totalPassos = 3;
// Dados da solicitação
let anoSelecionado = $state(new Date().getFullYear());
const anoSelecionado = $state(new Date().getFullYear());
let periodosFerias: Array<{
dataInicio: string;
dataFim: string;
dias: number;
}> = $state([]);
let observacao = $state('');
const observacao = $state('');
let processando = $state(false);
// Estados para os selects de data
@@ -34,7 +34,9 @@
let dataFimPeriodo = $state('');
// Queries
const funcionarioQuery = useQuery(api.funcionarios.getById, { id: funcionarioId });
const funcionarioQuery = useQuery(api.funcionarios.getById, {
id: funcionarioId
});
const funcionario = $derived(funcionarioQuery?.data);
const regimeTrabalho = $derived(funcionario?.regimeTrabalho || 'clt');
@@ -127,7 +129,9 @@
// Verificar se o total não excede 30 dias
const novoTotal = totalDiasSelecionados + dias;
if (novoTotal > 30) {
toast.error(`O total não pode exceder 30 dias. Você já tem ${totalDiasSelecionados} dias, adicionando ${dias} dias totalizaria ${novoTotal} dias.`);
toast.error(
`O total não pode exceder 30 dias. Você já tem ${totalDiasSelecionados} dias, adicionando ${dias} dias totalizaria ${novoTotal} dias.`
);
return;
}
}
@@ -135,7 +139,9 @@
// Verificar se o total não excede o saldo disponível
const novoTotal = totalDiasSelecionados + dias;
if (saldo && novoTotal > saldo.diasDisponiveis) {
toast.error(`Total de dias (${novoTotal}) excede saldo disponível (${saldo.diasDisponiveis})`);
toast.error(
`Total de dias (${novoTotal}) excede saldo disponível (${saldo.diasDisponiveis})`
);
return;
}
@@ -149,7 +155,7 @@
];
toast.success(`Período de ${dias} dias adicionado! ✅`);
// Limpar campos
dataInicioPeriodo = '';
dataFimPeriodo = '';
@@ -263,14 +269,17 @@
</div>
<!-- Label do passo -->
<p class="mt-3 text-center text-sm font-semibold" class:text-primary={passoAtual === i + 1}>
<p
class="mt-3 text-center text-sm font-semibold"
class:text-primary={passoAtual === i + 1}
>
{labels[i]}
</p>
<!-- Linha conectora -->
{#if i < totalPassos - 1}
<div
class="absolute left-1/2 top-6 z-10 h-1 transition-all duration-300"
class="absolute top-6 left-1/2 z-10 h-1 transition-all duration-300"
style="width: calc(100% - 1.5rem); margin-left: calc(50% + 0.75rem);"
class:bg-primary={passoAtual > i + 1}
class:bg-base-300={passoAtual <= i + 1}
@@ -303,7 +312,9 @@
style:border-width={anoSelecionado === ano ? '2px' : undefined}
style:color={anoSelecionado === ano ? '#000000' : undefined}
style:background-color={anoSelecionado === ano ? 'transparent' : undefined}
style:box-shadow={anoSelecionado === ano ? '0 0 10px rgba(249, 115, 22, 0.3)' : undefined}
style:box-shadow={anoSelecionado === ano
? '0 0 10px rgba(249, 115, 22, 0.3)'
: undefined}
onclick={() => (anoSelecionado = ano)}
>
{ano}
@@ -413,7 +424,8 @@
</p>
{#if ehEstatutarioPEOuMunicipal}
<p class="mt-2 text-sm font-semibold">
⚠️ Regras: Períodos de 15 ou 30 dias. Máximo 2 períodos. Total não pode exceder 30 dias.
⚠️ Regras: Períodos de 15 ou 30 dias. Máximo 2 períodos. Total não pode
exceder 30 dias.
</p>
{/if}
</div>
@@ -494,27 +506,24 @@
</p>
{#if ehEstatutarioPEOuMunicipal}
<p class="mt-2 text-sm font-semibold">
⚠️ Regras: Períodos de 15 ou 30 dias. Máximo 2 períodos. Total não pode exceder 30 dias.
⚠️ Regras: Períodos de 15 ou 30 dias. Máximo 2 períodos. Total não pode exceder 30
dias.
</p>
{/if}
</div>
</div>
<!-- Formulário para adicionar período -->
<div class="card bg-base-100 shadow-lg mb-6">
<div class="card bg-base-100 mb-6 shadow-lg">
<div class="card-body">
<h3 class="card-title mb-4">Adicionar Período</h3>
<div class="grid grid-cols-1 gap-4 md:grid-cols-3">
<div class="form-control">
<label class="label">
<span class="label-text font-semibold">Data Início</span>
</label>
<input
type="date"
class="input input-bordered"
bind:value={dataInicioPeriodo}
/>
<input type="date" class="input input-bordered" bind:value={dataInicioPeriodo} />
</div>
<div class="form-control">
@@ -534,7 +543,7 @@
<span class="label-text font-semibold">Dias</span>
</label>
<div class="input input-bordered flex items-center">
<span class="font-bold text-primary">{diasPeriodoAtual}</span>
<span class="text-primary font-bold">{diasPeriodoAtual}</span>
<span class="ml-2 text-sm opacity-70">dias</span>
</div>
</div>
@@ -569,7 +578,7 @@
<!-- Lista de períodos adicionados -->
{#if periodosFerias.length > 0}
<div class="card bg-base-100 shadow-lg mb-6">
<div class="card bg-base-100 mb-6 shadow-lg">
<div class="card-body">
<h3 class="card-title mb-4">Períodos Adicionados ({periodosFerias.length})</h3>
<div class="space-y-3">