feat: unify editing and adjustment forms for point management
- Replaced separate editing and adjustment modes with a unified form that allows users to switch between editing hours and adjusting bank hours. - Introduced new state management for active tab selection and formatted time input. - Implemented functions to convert between time formats and calculate periods between dates. - Enhanced user experience with improved layout and validation for date and time inputs. - Updated the UI to reflect changes in the form structure, ensuring a more cohesive interaction for users managing point records.
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
let funcionarioSelecionado = $state<Id<'funcionarios'> | ''>('');
|
let funcionarioSelecionado = $state<Id<'funcionarios'> | ''>('');
|
||||||
let registroSelecionado = $state<Id<'registrosPonto'> | ''>('');
|
let registroSelecionado = $state<Id<'registrosPonto'> | ''>('');
|
||||||
let modoEdicao = $state(false);
|
let modoEdicao = $state(false);
|
||||||
let modoAjuste = $state(false);
|
let abaAtiva = $state<'editar' | 'ajustar'>('editar');
|
||||||
|
|
||||||
// Formulário de edição
|
// Formulário de edição
|
||||||
let horaNova = $state(8);
|
let horaNova = $state(8);
|
||||||
@@ -23,11 +23,72 @@
|
|||||||
let motivoDescricao = $state('');
|
let motivoDescricao = $state('');
|
||||||
let observacoes = $state('');
|
let observacoes = $state('');
|
||||||
|
|
||||||
|
// Campo de hora unificado (formato HH:mm)
|
||||||
|
let novaHoraFormatada = $state('08:00');
|
||||||
|
|
||||||
|
// Converter hora/minuto para formato HH:mm
|
||||||
|
function horaMinutoParaTime(hora: number, minuto: number): string {
|
||||||
|
return `${hora.toString().padStart(2, '0')}:${minuto.toString().padStart(2, '0')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converter formato HH:mm para hora/minuto
|
||||||
|
function timeParaHoraMinuto(time: string): { hora: number; minuto: number } {
|
||||||
|
const [h, m] = time.split(':').map(Number);
|
||||||
|
return { hora: h || 0, minuto: m || 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calcular período entre duas datas/horas em dias, horas e minutos
|
||||||
|
function calcularPeriodo(
|
||||||
|
dataInicio: string,
|
||||||
|
horaInicio: string,
|
||||||
|
dataFim: string,
|
||||||
|
horaFim: string
|
||||||
|
): { dias: number; horas: number; minutos: number } {
|
||||||
|
if (!dataInicio || !horaInicio || !dataFim || !horaFim) {
|
||||||
|
return { dias: 0, horas: 0, minutos: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
const inicio = new Date(`${dataInicio}T${horaInicio}:00`);
|
||||||
|
const fim = new Date(`${dataFim}T${horaFim}:00`);
|
||||||
|
|
||||||
|
if (fim < inicio) {
|
||||||
|
return { dias: 0, horas: 0, minutos: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
const diffMs = fim.getTime() - inicio.getTime();
|
||||||
|
const diffMinutos = Math.floor(diffMs / (1000 * 60));
|
||||||
|
|
||||||
|
const dias = Math.floor(diffMinutos / (24 * 60));
|
||||||
|
const minutosRestantes = diffMinutos % (24 * 60);
|
||||||
|
const horas = Math.floor(minutosRestantes / 60);
|
||||||
|
const minutos = minutosRestantes % 60;
|
||||||
|
|
||||||
|
return { dias, horas, minutos };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obter registro selecionado
|
||||||
|
const registroEmEdicao = $derived.by(() => {
|
||||||
|
if (!registroSelecionado) return null;
|
||||||
|
return registros.find((r) => r._id === registroSelecionado) || null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Formatar data do registro
|
||||||
|
const dataRegistroFormatada = $derived.by(() => {
|
||||||
|
if (!registroEmEdicao) return '';
|
||||||
|
const data = new Date(registroEmEdicao.data);
|
||||||
|
return data.toLocaleDateString('pt-BR', {
|
||||||
|
day: '2-digit',
|
||||||
|
month: '2-digit',
|
||||||
|
year: 'numeric',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Formulário de ajuste
|
// Formulário de ajuste
|
||||||
let tipoAjuste = $state<'compensar' | 'abonar' | 'descontar'>('compensar');
|
let tipoAjuste = $state<'compensar' | 'abonar' | 'descontar'>('compensar');
|
||||||
let periodoDias = $state(0);
|
let dataInicioAjuste = $state(new Date().toISOString().split('T')[0]!);
|
||||||
let periodoHoras = $state(0);
|
let horaInicioAjuste = $state('08:00');
|
||||||
let periodoMinutos = $state(0);
|
let dataFimAjuste = $state(new Date().toISOString().split('T')[0]!);
|
||||||
|
let horaFimAjuste = $state('18:00');
|
||||||
|
|
||||||
// Queries
|
// Queries
|
||||||
const subordinadosQuery = useQuery(api.times.listarSubordinadosDoGestorAtual, {});
|
const subordinadosQuery = useQuery(api.times.listarSubordinadosDoGestorAtual, {});
|
||||||
@@ -75,6 +136,7 @@
|
|||||||
registroSelecionado = registroId;
|
registroSelecionado = registroId;
|
||||||
horaNova = registro.hora;
|
horaNova = registro.hora;
|
||||||
minutoNova = registro.minuto;
|
minutoNova = registro.minuto;
|
||||||
|
novaHoraFormatada = horaMinutoParaTime(registro.hora, registro.minuto);
|
||||||
motivoId = '';
|
motivoId = '';
|
||||||
motivoTipo = '';
|
motivoTipo = '';
|
||||||
motivoDescricao = '';
|
motivoDescricao = '';
|
||||||
@@ -83,24 +145,40 @@
|
|||||||
modoAjuste = false;
|
modoAjuste = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function abrirAjuste() {
|
function abrirEdicaoComAjuste(registroId: Id<'registrosPonto'>) {
|
||||||
modoAjuste = true;
|
const registro = registros.find((r) => r._id === registroId);
|
||||||
modoEdicao = false;
|
if (!registro) return;
|
||||||
registroSelecionado = '';
|
|
||||||
tipoAjuste = 'compensar';
|
registroSelecionado = registroId;
|
||||||
periodoDias = 0;
|
horaNova = registro.hora;
|
||||||
periodoHoras = 0;
|
minutoNova = registro.minuto;
|
||||||
periodoMinutos = 0;
|
novaHoraFormatada = horaMinutoParaTime(registro.hora, registro.minuto);
|
||||||
motivoId = '';
|
motivoId = '';
|
||||||
motivoTipo = '';
|
motivoTipo = '';
|
||||||
motivoDescricao = '';
|
motivoDescricao = '';
|
||||||
observacoes = '';
|
observacoes = '';
|
||||||
|
modoEdicao = true;
|
||||||
|
abaAtiva = 'editar';
|
||||||
|
|
||||||
|
// Resetar campos de ajuste
|
||||||
|
tipoAjuste = 'compensar';
|
||||||
|
const hoje = new Date().toISOString().split('T')[0]!;
|
||||||
|
dataInicioAjuste = hoje;
|
||||||
|
dataFimAjuste = hoje;
|
||||||
|
horaInicioAjuste = '08:00';
|
||||||
|
horaFimAjuste = '18:00';
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelar() {
|
function cancelar() {
|
||||||
modoEdicao = false;
|
modoEdicao = false;
|
||||||
modoAjuste = false;
|
|
||||||
registroSelecionado = '';
|
registroSelecionado = '';
|
||||||
|
abaAtiva = 'editar';
|
||||||
|
novaHoraFormatada = '08:00';
|
||||||
|
const hoje = new Date().toISOString().split('T')[0]!;
|
||||||
|
dataInicioAjuste = hoje;
|
||||||
|
dataFimAjuste = hoje;
|
||||||
|
horaInicioAjuste = '08:00';
|
||||||
|
horaFimAjuste = '18:00';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function salvarEdicao() {
|
async function salvarEdicao() {
|
||||||
@@ -109,11 +187,14 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Converter hora formatada para hora/minuto
|
||||||
|
const { hora, minuto } = timeParaHoraMinuto(novaHoraFormatada);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await client.mutation(api.pontos.editarRegistroPonto, {
|
await client.mutation(api.pontos.editarRegistroPonto, {
|
||||||
registroId: registroSelecionado,
|
registroId: registroSelecionado,
|
||||||
horaNova,
|
horaNova: hora,
|
||||||
minutoNova,
|
minutoNova: minuto,
|
||||||
motivoId: motivoId || undefined,
|
motivoId: motivoId || undefined,
|
||||||
motivoTipo: motivoTipo || undefined,
|
motivoTipo: motivoTipo || undefined,
|
||||||
motivoDescricao: motivoDescricao || undefined,
|
motivoDescricao: motivoDescricao || undefined,
|
||||||
@@ -134,8 +215,21 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (periodoDias === 0 && periodoHoras === 0 && periodoMinutos === 0) {
|
if (!dataInicioAjuste || !horaInicioAjuste || !dataFimAjuste || !horaFimAjuste) {
|
||||||
toast.error('Informe pelo menos um período (dias, horas ou minutos)');
|
toast.error('Preencha todas as datas e horários do período');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calcular período entre início e fim
|
||||||
|
const { dias, horas, minutos } = calcularPeriodo(
|
||||||
|
dataInicioAjuste,
|
||||||
|
horaInicioAjuste,
|
||||||
|
dataFimAjuste,
|
||||||
|
horaFimAjuste
|
||||||
|
);
|
||||||
|
|
||||||
|
if (dias === 0 && horas === 0 && minutos === 0) {
|
||||||
|
toast.error('A data/hora final deve ser maior que a inicial');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,9 +237,9 @@
|
|||||||
await client.mutation(api.pontos.ajustarBancoHoras, {
|
await client.mutation(api.pontos.ajustarBancoHoras, {
|
||||||
funcionarioId: funcionarioSelecionado,
|
funcionarioId: funcionarioSelecionado,
|
||||||
tipoAjuste,
|
tipoAjuste,
|
||||||
periodoDias,
|
periodoDias: dias,
|
||||||
periodoHoras,
|
periodoHoras: horas,
|
||||||
periodoMinutos,
|
periodoMinutos: minutos,
|
||||||
motivoId: motivoId || undefined,
|
motivoId: motivoId || undefined,
|
||||||
motivoTipo: motivoTipo || undefined,
|
motivoTipo: motivoTipo || undefined,
|
||||||
motivoDescricao: motivoDescricao || undefined,
|
motivoDescricao: motivoDescricao || undefined,
|
||||||
@@ -182,7 +276,7 @@
|
|||||||
<select
|
<select
|
||||||
class="select select-bordered w-full"
|
class="select select-bordered w-full"
|
||||||
bind:value={funcionarioSelecionado}
|
bind:value={funcionarioSelecionado}
|
||||||
disabled={modoEdicao || modoAjuste}
|
disabled={modoEdicao}
|
||||||
>
|
>
|
||||||
<option value="">Selecione um funcionário</option>
|
<option value="">Selecione um funcionário</option>
|
||||||
{#each funcionarios as funcionario}
|
{#each funcionarios as funcionario}
|
||||||
@@ -194,193 +288,297 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Botões de Ação -->
|
<!-- Formulário Unificado de Edição e Ajuste -->
|
||||||
{#if funcionarioSelecionado && !modoEdicao && !modoAjuste}
|
|
||||||
<div class="flex gap-4 mb-6">
|
|
||||||
<button class="btn btn-primary gap-2" onclick={abrirAjuste}>
|
|
||||||
<TrendingUp class="h-4 w-4" />
|
|
||||||
Ajustar Banco de Horas
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<!-- Formulário de Edição -->
|
|
||||||
{#if modoEdicao && registroSelecionado}
|
{#if modoEdicao && registroSelecionado}
|
||||||
<div class="card bg-base-100 shadow-xl mb-6">
|
<div class="card bg-base-100 shadow-xl mb-6 border-2 border-primary/20">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title mb-4">Editar Registro de Ponto</h2>
|
<!-- Título com data -->
|
||||||
|
<div class="flex items-center justify-between mb-6 pb-4 border-b border-base-300">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div>
|
||||||
<div class="form-control">
|
<h2 class="card-title text-2xl text-primary mb-1">
|
||||||
<label class="label">
|
<Edit class="h-6 w-6" strokeWidth={2} />
|
||||||
<span class="label-text font-medium">Nova Hora</span>
|
Homologar Registro de Ponto
|
||||||
</label>
|
</h2>
|
||||||
<input
|
{#if dataRegistroFormatada}
|
||||||
type="number"
|
<p class="text-base-content/70 text-sm mt-1">
|
||||||
min="0"
|
Registro do dia <span class="font-semibold text-primary">{dataRegistroFormatada}</span>
|
||||||
max="23"
|
</p>
|
||||||
class="input input-bordered"
|
{/if}
|
||||||
bind:value={horaNova}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-control">
|
<!-- Abas -->
|
||||||
<label class="label">
|
<div class="tabs tabs-boxed mb-6 bg-base-200">
|
||||||
<span class="label-text font-medium">Novo Minuto</span>
|
<button
|
||||||
</label>
|
class="tab tab-lg {abaAtiva === 'editar' ? 'tab-active' : ''}"
|
||||||
<input
|
onclick={() => (abaAtiva = 'editar')}
|
||||||
type="number"
|
>
|
||||||
min="0"
|
<Edit class="h-4 w-4 mr-2" />
|
||||||
max="59"
|
Editar Horário
|
||||||
class="input input-bordered"
|
</button>
|
||||||
bind:value={minutoNova}
|
<button
|
||||||
/>
|
class="tab tab-lg {abaAtiva === 'ajustar' ? 'tab-active' : ''}"
|
||||||
|
onclick={() => (abaAtiva = 'ajustar')}
|
||||||
|
>
|
||||||
|
<TrendingUp class="h-4 w-4 mr-2" />
|
||||||
|
Ajustar Banco de Horas
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Conteúdo da Aba: Editar Horário -->
|
||||||
|
{#if abaAtiva === 'editar'}
|
||||||
|
<div class="space-y-6">
|
||||||
|
<!-- Hora Unificada -->
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-semibold text-base">
|
||||||
|
<Clock class="h-4 w-4 inline-block mr-2" />
|
||||||
|
Nova Hora
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="time"
|
||||||
|
class="input input-bordered input-primary w-full max-w-xs"
|
||||||
|
bind:value={novaHoraFormatada}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Grid de Motivos -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-semibold">Motivo (Tipo)</span>
|
||||||
|
<span class="label-text-alt text-error">*</span>
|
||||||
|
</label>
|
||||||
|
<select class="select select-bordered select-primary" bind:value={motivoTipo}>
|
||||||
|
<option value="">Selecione um tipo</option>
|
||||||
|
{#if motivos?.opcoesPadrao}
|
||||||
|
{#each motivos.opcoesPadrao as opcao}
|
||||||
|
<option value={opcao}>{opcao}</option>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-semibold">Descrição do Motivo</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-bordered input-primary"
|
||||||
|
bind:value={motivoDescricao}
|
||||||
|
placeholder="Informe detalhes adicionais sobre o motivo"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Observações -->
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-semibold">Observações</span>
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
class="textarea textarea-bordered textarea-primary"
|
||||||
|
bind:value={observacoes}
|
||||||
|
rows="4"
|
||||||
|
placeholder="Adicione observações relevantes sobre esta edição..."
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Botões de ação -->
|
||||||
|
<div class="flex gap-3 justify-end mt-8 pt-6 border-t border-base-300">
|
||||||
|
<button class="btn btn-ghost gap-2" onclick={cancelar}>
|
||||||
|
<X class="h-4 w-4" />
|
||||||
|
Cancelar
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary gap-2" onclick={salvarEdicao}>
|
||||||
|
<Save class="h-4 w-4" />
|
||||||
|
Salvar Alterações
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="form-control">
|
<!-- Conteúdo da Aba: Ajustar Banco de Horas -->
|
||||||
<label class="label">
|
{#if abaAtiva === 'ajustar'}
|
||||||
<span class="label-text font-medium">Motivo (Tipo)</span>
|
<div class="space-y-6">
|
||||||
</label>
|
<!-- Tipo de Ajuste -->
|
||||||
<select class="select select-bordered" bind:value={motivoTipo}>
|
<div class="form-control">
|
||||||
<option value="">Selecione um tipo</option>
|
<label class="label">
|
||||||
{#if motivos?.opcoesPadrao}
|
<span class="label-text font-semibold text-base">Tipo de Ajuste</span>
|
||||||
{#each motivos.opcoesPadrao as opcao}
|
<span class="label-text-alt text-error">*</span>
|
||||||
<option value={opcao}>{opcao}</option>
|
</label>
|
||||||
{/each}
|
<select class="select select-bordered select-primary w-full max-w-md" bind:value={tipoAjuste}>
|
||||||
|
<option value="compensar">Compensar</option>
|
||||||
|
<option value="abonar">Abonar</option>
|
||||||
|
<option value="descontar">Descontar em Folha</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Período com Data e Hora -->
|
||||||
|
<div class="bg-base-200/50 p-6 rounded-xl border border-base-300">
|
||||||
|
<label class="label mb-4">
|
||||||
|
<span class="label-text font-semibold text-base">
|
||||||
|
<Clock class="h-4 w-4 inline-block mr-2" />
|
||||||
|
Período do Ajuste
|
||||||
|
</span>
|
||||||
|
<span class="label-text-alt text-error">*</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<!-- Data e Hora Início -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h4 class="text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-primary"></div>
|
||||||
|
Início do Período
|
||||||
|
</h4>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-medium">Data Início</span>
|
||||||
|
<span class="label-text-alt text-error">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
class="input input-bordered input-primary"
|
||||||
|
bind:value={dataInicioAjuste}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-medium">Hora Início</span>
|
||||||
|
<span class="label-text-alt text-error">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="time"
|
||||||
|
class="input input-bordered input-primary"
|
||||||
|
bind:value={horaInicioAjuste}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Separador Visual -->
|
||||||
|
<div class="divider my-4">
|
||||||
|
<Clock class="h-4 w-4 text-base-content/40" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Data e Hora Fim -->
|
||||||
|
<div>
|
||||||
|
<h4 class="text-sm font-semibold text-base-content/80 mb-3 flex items-center gap-2">
|
||||||
|
<div class="w-2 h-2 rounded-full bg-secondary"></div>
|
||||||
|
Fim do Período
|
||||||
|
</h4>
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-medium">Data Fim</span>
|
||||||
|
<span class="label-text-alt text-error">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
class="input input-bordered input-primary"
|
||||||
|
bind:value={dataFimAjuste}
|
||||||
|
min={dataInicioAjuste}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-medium">Hora Fim</span>
|
||||||
|
<span class="label-text-alt text-error">*</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="time"
|
||||||
|
class="input input-bordered input-primary"
|
||||||
|
bind:value={horaFimAjuste}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Preview do Período Calculado -->
|
||||||
|
{#if dataInicioAjuste && horaInicioAjuste && dataFimAjuste && horaFimAjuste}
|
||||||
|
{@const periodoCalculado = calcularPeriodo(dataInicioAjuste, horaInicioAjuste, dataFimAjuste, horaFimAjuste)}
|
||||||
|
{#if periodoCalculado.dias > 0 || periodoCalculado.horas > 0 || periodoCalculado.minutos > 0}
|
||||||
|
<div class="mt-4 p-3 bg-primary/10 rounded-lg border border-primary/20">
|
||||||
|
<div class="text-xs font-semibold text-primary mb-1">Período Calculado:</div>
|
||||||
|
<div class="text-sm text-base-content">
|
||||||
|
{periodoCalculado.dias > 0 ? `${periodoCalculado.dias} dia${periodoCalculado.dias > 1 ? 's' : ''} ` : ''}
|
||||||
|
{periodoCalculado.horas > 0 ? `${periodoCalculado.horas} hora${periodoCalculado.horas > 1 ? 's' : ''} ` : ''}
|
||||||
|
{periodoCalculado.minutos > 0 ? `${periodoCalculado.minutos} minuto${periodoCalculado.minutos > 1 ? 's' : ''}` : ''}
|
||||||
|
{#if periodoCalculado.dias === 0 && periodoCalculado.horas === 0 && periodoCalculado.minutos === 0}
|
||||||
|
<span class="text-base-content/60">Período inválido</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</select>
|
</div>
|
||||||
|
|
||||||
|
<!-- Grid de Motivos -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-semibold">Motivo (Tipo)</span>
|
||||||
|
<span class="label-text-alt text-error">*</span>
|
||||||
|
</label>
|
||||||
|
<select class="select select-bordered select-primary" bind:value={motivoTipo}>
|
||||||
|
<option value="">Selecione um tipo</option>
|
||||||
|
{#if motivos?.opcoesPadrao}
|
||||||
|
{#each motivos.opcoesPadrao as opcao}
|
||||||
|
<option value={opcao}>{opcao}</option>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-semibold">Descrição do Motivo</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-bordered input-primary"
|
||||||
|
bind:value={motivoDescricao}
|
||||||
|
placeholder="Informe detalhes adicionais sobre o motivo"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Observações -->
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-semibold">Observações</span>
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
class="textarea textarea-bordered textarea-primary"
|
||||||
|
bind:value={observacoes}
|
||||||
|
rows="4"
|
||||||
|
placeholder="Adicione observações relevantes sobre este ajuste..."
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Botões de ação -->
|
||||||
|
<div class="flex gap-3 justify-end mt-8 pt-6 border-t border-base-300">
|
||||||
|
<button class="btn btn-ghost gap-2" onclick={cancelar}>
|
||||||
|
<X class="h-4 w-4" />
|
||||||
|
Cancelar
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary gap-2" onclick={salvarAjuste}>
|
||||||
|
<Save class="h-4 w-4" />
|
||||||
|
Salvar Ajuste
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
<div class="form-control">
|
|
||||||
<label class="label">
|
|
||||||
<span class="label-text font-medium">Descrição do Motivo</span>
|
|
||||||
</label>
|
|
||||||
<input type="text" class="input input-bordered" bind:value={motivoDescricao} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control md:col-span-2">
|
|
||||||
<label class="label">
|
|
||||||
<span class="label-text font-medium">Observações</span>
|
|
||||||
</label>
|
|
||||||
<textarea class="textarea textarea-bordered" bind:value={observacoes} rows="3"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex gap-2 mt-4">
|
|
||||||
<button class="btn btn-primary gap-2" onclick={salvarEdicao}>
|
|
||||||
<Save class="h-4 w-4" />
|
|
||||||
Salvar
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-ghost gap-2" onclick={cancelar}>
|
|
||||||
<X class="h-4 w-4" />
|
|
||||||
Cancelar
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<!-- Formulário de Ajuste -->
|
|
||||||
{#if modoAjuste}
|
|
||||||
<div class="card bg-base-100 shadow-xl mb-6">
|
|
||||||
<div class="card-body">
|
|
||||||
<h2 class="card-title mb-4">Ajustar Banco de Horas</h2>
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label">
|
|
||||||
<span class="label-text font-medium">Tipo de Ajuste</span>
|
|
||||||
</label>
|
|
||||||
<select class="select select-bordered" bind:value={tipoAjuste}>
|
|
||||||
<option value="compensar">Compensar</option>
|
|
||||||
<option value="abonar">Abonar</option>
|
|
||||||
<option value="descontar">Descontar em Folha</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label">
|
|
||||||
<span class="label-text font-medium">Dias</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
class="input input-bordered"
|
|
||||||
bind:value={periodoDias}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label">
|
|
||||||
<span class="label-text font-medium">Horas</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
max="23"
|
|
||||||
class="input input-bordered"
|
|
||||||
bind:value={periodoHoras}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label">
|
|
||||||
<span class="label-text font-medium">Minutos</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
min="0"
|
|
||||||
max="59"
|
|
||||||
class="input input-bordered"
|
|
||||||
bind:value={periodoMinutos}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label">
|
|
||||||
<span class="label-text font-medium">Motivo (Tipo)</span>
|
|
||||||
</label>
|
|
||||||
<select class="select select-bordered" bind:value={motivoTipo}>
|
|
||||||
<option value="">Selecione um tipo</option>
|
|
||||||
{#if motivos?.opcoesPadrao}
|
|
||||||
{#each motivos.opcoesPadrao as opcao}
|
|
||||||
<option value={opcao}>{opcao}</option>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control">
|
|
||||||
<label class="label">
|
|
||||||
<span class="label-text font-medium">Descrição do Motivo</span>
|
|
||||||
</label>
|
|
||||||
<input type="text" class="input input-bordered" bind:value={motivoDescricao} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-control md:col-span-2">
|
|
||||||
<label class="label">
|
|
||||||
<span class="label-text font-medium">Observações</span>
|
|
||||||
</label>
|
|
||||||
<textarea class="textarea textarea-bordered" bind:value={observacoes} rows="3"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex gap-2 mt-4">
|
|
||||||
<button class="btn btn-primary gap-2" onclick={salvarAjuste}>
|
|
||||||
<Save class="h-4 w-4" />
|
|
||||||
Salvar
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-ghost gap-2" onclick={cancelar}>
|
|
||||||
<X class="h-4 w-4" />
|
|
||||||
Cancelar
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Lista de Registros -->
|
<!-- Lista de Registros -->
|
||||||
{#if funcionarioSelecionado && !modoEdicao && !modoAjuste}
|
{#if funcionarioSelecionado && !modoEdicao}
|
||||||
<div class="card bg-base-100 shadow-xl mb-6">
|
<div class="card bg-base-100 shadow-xl mb-6">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title mb-4">Registros do Funcionário</h2>
|
<h2 class="card-title mb-4">Registros do Funcionário</h2>
|
||||||
@@ -419,7 +617,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm btn-outline btn-primary gap-2"
|
class="btn btn-sm btn-outline btn-primary gap-2"
|
||||||
onclick={() => abrirEdicao(registro._id)}
|
onclick={() => abrirEdicaoComAjuste(registro._id)}
|
||||||
>
|
>
|
||||||
<Edit class="h-4 w-4" />
|
<Edit class="h-4 w-4" />
|
||||||
Editar
|
Editar
|
||||||
@@ -436,7 +634,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Histórico de Homologações -->
|
<!-- Histórico de Homologações -->
|
||||||
{#if !modoEdicao && !modoAjuste}
|
{#if !modoEdicao}
|
||||||
<div class="card bg-base-100 shadow-xl">
|
<div class="card bg-base-100 shadow-xl">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="card-title mb-4">
|
<h2 class="card-title mb-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user