Merge remote-tracking branch 'origin' into feat-pedidos
This commit is contained in:
@@ -1,33 +1,37 @@
|
||||
<script lang="ts">
|
||||
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
import type { FunctionReference } from 'convex/server';
|
||||
import { useConvexClient, useQuery } from 'convex-svelte';
|
||||
import jsPDF from 'jspdf';
|
||||
import {
|
||||
Camera,
|
||||
CheckCircle2,
|
||||
Clock,
|
||||
LogIn,
|
||||
LogOut,
|
||||
Printer,
|
||||
TrendingDown,
|
||||
TrendingUp,
|
||||
XCircle
|
||||
} from 'lucide-svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import logoGovPE from '$lib/assets/logo_governo_PE.png';
|
||||
import { obterInformacoesDispositivo } from '$lib/utils/deviceInfo';
|
||||
import { obterTempoServidor } from '$lib/utils/sincronizacaoTempo';
|
||||
import {
|
||||
formatarDataHoraCompleta,
|
||||
formatarHoraPonto,
|
||||
getProximoTipoRegistro,
|
||||
getTipoRegistroLabel
|
||||
} from '$lib/utils/ponto';
|
||||
import { obterTempoServidor } from '$lib/utils/sincronizacaoTempo';
|
||||
import ErrorModal from '../ErrorModal.svelte';
|
||||
import ComprovantePonto from './ComprovantePonto.svelte';
|
||||
import {
|
||||
LogIn,
|
||||
LogOut,
|
||||
Clock,
|
||||
CheckCircle2,
|
||||
XCircle,
|
||||
TrendingUp,
|
||||
TrendingDown,
|
||||
Printer,
|
||||
Camera,
|
||||
AlertTriangle,
|
||||
Image as ImageIcon,
|
||||
Info
|
||||
} from 'lucide-svelte';
|
||||
import jsPDF from 'jspdf';
|
||||
import logoGovPE from '$lib/assets/logo_governo_PE.png';
|
||||
import { formatarDataHoraCompleta } from '$lib/utils/ponto';
|
||||
import RelogioSincronizado from './RelogioSincronizado.svelte';
|
||||
import WebcamCapture from './WebcamCapture.svelte';
|
||||
import ComprovantePonto from './ComprovantePonto.svelte';
|
||||
import ErrorModal from '../ErrorModal.svelte';
|
||||
|
||||
const client = useConvexClient();
|
||||
|
||||
@@ -35,30 +39,45 @@
|
||||
let refreshKey = $state(0);
|
||||
|
||||
// Queries
|
||||
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
||||
const currentUser = useQuery(api.auth.getCurrentUser as FunctionReference<'query'>);
|
||||
const configQuery = useQuery(api.configuracaoPonto.obterConfiguracao, {});
|
||||
|
||||
// Query para histórico e saldo do dia
|
||||
let funcionarioId = $derived(currentUser?.data?.funcionarioId ?? null);
|
||||
let dataHoje = $derived(new Date().toISOString().split('T')[0]!);
|
||||
|
||||
// Usar refreshKey para forçar atualização após registro
|
||||
const registrosHojeQuery = useQuery(api.pontos.listarRegistrosDia, {
|
||||
// Parâmetros reativos para queries de ponto
|
||||
const registrosHojeParams = $derived({
|
||||
data: dataHoje,
|
||||
_refresh: refreshKey
|
||||
});
|
||||
|
||||
const historicoSaldoQuery = useQuery(
|
||||
api.pontos.obterHistoricoESaldoDia,
|
||||
const historicoSaldoParams = $derived(
|
||||
funcionarioId && dataHoje ? { funcionarioId, data: dataHoje, _refresh: refreshKey } : 'skip'
|
||||
);
|
||||
|
||||
// Query para verificar dispensa ativa
|
||||
const dispensaQuery = useQuery(
|
||||
api.pontos.verificarDispensaAtiva,
|
||||
const dispensaParams = $derived(
|
||||
funcionarioId && dataHoje ? { funcionarioId, data: dataHoje } : 'skip'
|
||||
);
|
||||
|
||||
const registrosHojeQuery = $derived.by(() =>
|
||||
useQuery(api.pontos.listarRegistrosDia, registrosHojeParams)
|
||||
);
|
||||
|
||||
const historicoSaldoQuery = $derived.by(() =>
|
||||
useQuery(api.pontos.obterHistoricoESaldoDia, historicoSaldoParams)
|
||||
);
|
||||
|
||||
const dispensaQuery = $derived.by(() =>
|
||||
useQuery(api.pontos.verificarDispensaAtiva, dispensaParams)
|
||||
);
|
||||
|
||||
// Query para obter status atual do funcionário (férias/licença)
|
||||
const funcionarioStatusQuery = useQuery(
|
||||
api.funcionarios.getCurrent,
|
||||
currentUser?.data ? {} : 'skip'
|
||||
);
|
||||
|
||||
// Estados
|
||||
let mostrandoWebcam = $state(false);
|
||||
let registrando = $state(false);
|
||||
@@ -83,6 +102,12 @@
|
||||
let registrosHoje = $derived(registrosHojeQuery?.data || []);
|
||||
let config = $derived(configQuery?.data);
|
||||
|
||||
// Status de férias/licença do funcionário
|
||||
const funcionarioStatus = $derived(funcionarioStatusQuery?.data);
|
||||
const statusFerias = $derived(funcionarioStatus?.statusFerias ?? 'ativo');
|
||||
const emFerias = $derived(statusFerias === 'em_ferias');
|
||||
const emLicenca = $derived(statusFerias === 'em_licenca');
|
||||
|
||||
let proximoTipo = $derived.by(() => {
|
||||
if (registrosHoje.length === 0) {
|
||||
return 'entrada';
|
||||
@@ -210,6 +235,16 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Verificar se funcionário está em férias ou licença
|
||||
if (emFerias || emLicenca) {
|
||||
mensagemErroModal = 'Registro de ponto não permitido';
|
||||
detalhesErroModal = emFerias
|
||||
? 'Seu status atual é "Em Férias". Durante o período de férias não é permitido registrar ponto.'
|
||||
: 'Seu status atual é "Em Licença". Durante o período de licença não é permitido registrar ponto.';
|
||||
mostrarModalErro = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Verificar permissões antes de registrar
|
||||
const permissoes = await verificarPermissoes();
|
||||
if (!permissoes.localizacao || !permissoes.webcam) {
|
||||
@@ -597,9 +632,7 @@
|
||||
async function imprimirComprovante(registroId: Id<'registrosPonto'>) {
|
||||
try {
|
||||
// Buscar dados completos do registro
|
||||
const registro = await client.query(api.pontos.obterRegistro, {
|
||||
registroId
|
||||
});
|
||||
const registro = await client.query(api.pontos.obterRegistro, { registroId });
|
||||
|
||||
if (!registro) {
|
||||
alert('Registro não encontrado');
|
||||
@@ -831,6 +864,8 @@
|
||||
!coletandoInfo &&
|
||||
config !== undefined &&
|
||||
!estaDispensado &&
|
||||
!emFerias &&
|
||||
!emLicenca &&
|
||||
temFuncionarioAssociado
|
||||
);
|
||||
});
|
||||
@@ -844,7 +879,7 @@
|
||||
try {
|
||||
// Solicitar apenas permissão, sem iniciar o stream ainda
|
||||
await navigator.mediaDevices.getUserMedia({ video: true });
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// Ignorar erro silenciosamente - a permissão será solicitada quando necessário
|
||||
console.log('Permissão de webcam não concedida ainda');
|
||||
}
|
||||
@@ -868,7 +903,7 @@
|
||||
{ timeout: 2000, maximumAge: 0, enableHighAccuracy: false } // enableHighAccuracy false para ser mais rápido
|
||||
);
|
||||
});
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// Ignorar erro silenciosamente
|
||||
console.log('Permissão de geolocalização não concedida ainda');
|
||||
}
|
||||
@@ -879,11 +914,7 @@
|
||||
if (!config) return [];
|
||||
|
||||
const horarios = [
|
||||
{
|
||||
tipo: 'entrada',
|
||||
horario: config.horarioEntrada,
|
||||
label: config.nomeEntrada || 'Entrada 1'
|
||||
},
|
||||
{ tipo: 'entrada', horario: config.horarioEntrada, label: config.nomeEntrada || 'Entrada 1' },
|
||||
{
|
||||
tipo: 'saida_almoco',
|
||||
horario: config.horarioSaidaAlmoco,
|
||||
@@ -894,11 +925,7 @@
|
||||
horario: config.horarioRetornoAlmoco,
|
||||
label: config.nomeRetornoAlmoco || 'Entrada 2'
|
||||
},
|
||||
{
|
||||
tipo: 'saida',
|
||||
horario: config.horarioSaida,
|
||||
label: config.nomeSaida || 'Saída 2'
|
||||
}
|
||||
{ tipo: 'saida', horario: config.horarioSaida, label: config.nomeSaida || 'Saída 2' }
|
||||
];
|
||||
|
||||
const resultado = horarios.map((h) => {
|
||||
@@ -916,10 +943,7 @@
|
||||
console.log('[RegistroPonto] mapaHorarios atualizado:', {
|
||||
totalRegistrosHoje: registrosHoje.length,
|
||||
horariosComRegistro: resultado.filter((h) => h.registrado).length,
|
||||
registrosHoje: registrosHoje.map((r) => ({
|
||||
tipo: r.tipo,
|
||||
hora: `${r.hora}:${r.minuto}`
|
||||
}))
|
||||
registrosHoje: registrosHoje.map((r) => ({ tipo: r.tipo, hora: `${r.hora}:${r.minuto}` }))
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1041,19 +1065,7 @@
|
||||
<!-- Alerta de Funcionário Não Associado -->
|
||||
{#if !temFuncionarioAssociado}
|
||||
<div class="alert alert-error shadow-lg">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6 shrink-0 stroke-current"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<XCircle class="h-6 w-6 shrink-0 stroke-current" />
|
||||
<div>
|
||||
<h3 class="font-bold">Funcionário Não Associado</h3>
|
||||
<div class="text-sm">
|
||||
@@ -1068,19 +1080,7 @@
|
||||
<!-- Alerta de Dispensa -->
|
||||
{#if estaDispensado && motivoDispensa && temFuncionarioAssociado}
|
||||
<div class="alert alert-warning shadow-lg">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6 shrink-0 stroke-current"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||
/>
|
||||
</svg>
|
||||
<AlertTriangle class="h-6 w-6 shrink-0 stroke-current" />
|
||||
<div>
|
||||
<h3 class="font-bold">Registro de Ponto Dispensado</h3>
|
||||
<div class="text-sm">
|
||||
@@ -1093,9 +1093,28 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Alerta de Status de Férias/Licença -->
|
||||
{#if temFuncionarioAssociado && (emFerias || emLicenca)}
|
||||
<div class="alert alert-info shadow-lg">
|
||||
<Info class="h-6 w-6 shrink-0 stroke-current" />
|
||||
<div>
|
||||
<h3 class="font-bold">Status do Funcionário</h3>
|
||||
<div class="text-sm">
|
||||
{#if emFerias}
|
||||
Seu status atual é <strong>Em Férias</strong>. Durante o período de férias não é
|
||||
permitido registrar ponto.
|
||||
{:else}
|
||||
Seu status atual é <strong>Em Licença</strong>. Durante o período de licença não é
|
||||
permitido registrar ponto.
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Card de Registro de Ponto Modernizado -->
|
||||
<div
|
||||
class="card from-base-100 via-base-100 to-primary/5 border-base-300 mx-auto max-w-2xl border bg-gradient-to-br shadow-2xl"
|
||||
class="card from-base-100 via-base-100 to-primary/5 border-base-300 mx-auto max-w-2xl border bg-linear-to-br shadow-2xl"
|
||||
>
|
||||
<div id="card-registro-ponto-ref" class="card-body p-6">
|
||||
<!-- Cabeçalho -->
|
||||
@@ -1110,7 +1129,7 @@
|
||||
<div class="mb-5 flex justify-center">
|
||||
<div
|
||||
id="relogio-sincronizado-ref"
|
||||
class="card from-primary/10 to-primary/5 border-primary/20 w-full max-w-sm rounded-2xl border-2 bg-gradient-to-br p-5 shadow-lg"
|
||||
class="card from-primary/10 to-primary/5 border-primary/20 w-full max-w-sm rounded-2xl border-2 bg-linear-to-br p-5 shadow-lg"
|
||||
>
|
||||
<RelogioSincronizado />
|
||||
</div>
|
||||
@@ -1125,7 +1144,11 @@
|
||||
? 'Você não possui funcionário associado à sua conta'
|
||||
: estaDispensado
|
||||
? 'Você está dispensado de registrar ponto no momento'
|
||||
: ''}
|
||||
: emFerias
|
||||
? 'Você está em férias. Durante o período de férias não é permitido registrar ponto.'
|
||||
: emLicenca
|
||||
? 'Você está em licença. Durante o período de licença não é permitido registrar ponto.'
|
||||
: ''}
|
||||
>
|
||||
{#if registrando}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
@@ -1140,6 +1163,12 @@
|
||||
{:else if estaDispensado}
|
||||
<XCircle class="h-5 w-5" />
|
||||
Registro Indisponível
|
||||
{:else if emFerias}
|
||||
<XCircle class="h-5 w-5" />
|
||||
Em Férias
|
||||
{:else if emLicenca}
|
||||
<XCircle class="h-5 w-5" />
|
||||
Em Licença
|
||||
{:else if proximoTipo === 'entrada' || proximoTipo === 'retorno_almoco'}
|
||||
<LogIn class="h-5 w-5" />
|
||||
Registrar Entrada
|
||||
@@ -1176,7 +1205,7 @@
|
||||
|
||||
<!-- Próximo Registro -->
|
||||
<div
|
||||
class="card from-info/10 to-info/5 border-info/20 rounded-xl border-2 bg-gradient-to-br p-4 shadow-md"
|
||||
class="card from-info/10 to-info/5 border-info/20 rounded-xl border-2 bg-linear-to-br p-4 shadow-md"
|
||||
>
|
||||
<div class="flex items-center justify-center gap-2">
|
||||
<div class="bg-info/20 rounded-lg p-1.5">
|
||||
@@ -1212,9 +1241,9 @@
|
||||
<div
|
||||
class="relative h-full rounded-xl border-2 transition-all duration-300 hover:shadow-lg {horario.registrado
|
||||
? horario.dentroDoPrazo
|
||||
? 'from-success/20 to-success/10 border-success bg-gradient-to-br shadow-md'
|
||||
: 'from-error/20 to-error/10 border-error bg-gradient-to-br shadow-md'
|
||||
: 'from-base-200 to-base-300 border-base-300 bg-gradient-to-br'} p-5"
|
||||
? 'from-success/20 to-success/10 border-success bg-linear-to-br shadow-md'
|
||||
: 'from-error/20 to-error/10 border-error bg-linear-to-br shadow-md'
|
||||
: 'from-base-200 to-base-300 border-base-300 bg-linear-to-br'} p-5"
|
||||
>
|
||||
<!-- Status Icon -->
|
||||
<div class="absolute top-3 right-3">
|
||||
@@ -1314,7 +1343,7 @@
|
||||
<div class="relative">
|
||||
<!-- Linha vertical central da timeline -->
|
||||
<div
|
||||
class="from-primary/20 via-base-300 to-secondary/20 absolute top-0 bottom-0 left-1/2 w-1 -translate-x-1/2 transform bg-gradient-to-b"
|
||||
class="from-primary/20 via-base-300 to-secondary/20 absolute top-0 bottom-0 left-1/2 w-1 -translate-x-1/2 transform bg-linear-to-b"
|
||||
></div>
|
||||
|
||||
<!-- Container com duas colunas -->
|
||||
@@ -1348,9 +1377,9 @@
|
||||
<!-- Tipo de registro e status -->
|
||||
<div class="mb-2 flex items-center gap-2">
|
||||
{#if registro.dentroDoPrazo}
|
||||
<CheckCircle2 class="text-success h-4 w-4 flex-shrink-0" />
|
||||
<CheckCircle2 class="text-success h-4 w-4 shrink-0" />
|
||||
{:else}
|
||||
<XCircle class="text-error h-4 w-4 flex-shrink-0" />
|
||||
<XCircle class="text-error h-4 w-4 shrink-0" />
|
||||
{/if}
|
||||
<span class="text-base-content/80 text-sm font-semibold">
|
||||
{config
|
||||
@@ -1422,7 +1451,7 @@
|
||||
|
||||
<!-- Mostrar horários esperados que não foram registrados -->
|
||||
{#if config}
|
||||
{#each [{ tipo: 'entrada', horario: config.horarioEntrada, label: config.nomeEntrada || 'Entrada 1' }, { tipo: 'retorno_almoco', horario: config.horarioRetornoAlmoco, label: config.nomeRetornoAlmoco || 'Entrada 2' }] as horarioEsperado}
|
||||
{#each [{ tipo: 'entrada', horario: config.horarioEntrada, label: config.nomeEntrada || 'Entrada 1' }, { tipo: 'retorno_almoco', horario: config.horarioRetornoAlmoco, label: config.nomeRetornoAlmoco || 'Entrada 2' }] as horarioEsperado (horarioEsperado.tipo)}
|
||||
{#if !registrosOrdenados.find((r) => r.tipo === horarioEsperado.tipo)}
|
||||
<div class="relative opacity-50">
|
||||
<div
|
||||
@@ -1482,9 +1511,9 @@
|
||||
: getTipoRegistroLabel(registro.tipo)}
|
||||
</span>
|
||||
{#if registro.dentroDoPrazo}
|
||||
<CheckCircle2 class="text-success h-4 w-4 flex-shrink-0" />
|
||||
<CheckCircle2 class="text-success h-4 w-4 shrink-0" />
|
||||
{:else}
|
||||
<XCircle class="text-error h-4 w-4 flex-shrink-0" />
|
||||
<XCircle class="text-error h-4 w-4 shrink-0" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1548,7 +1577,7 @@
|
||||
|
||||
<!-- Mostrar horários esperados que não foram registrados -->
|
||||
{#if config}
|
||||
{#each [{ tipo: 'saida_almoco', horario: config.horarioSaidaAlmoco, label: config.nomeSaidaAlmoco || 'Saída 1' }, { tipo: 'saida', horario: config.horarioSaida, label: config.nomeSaida || 'Saída 2' }] as horarioEsperado}
|
||||
{#each [{ tipo: 'saida_almoco', horario: config.horarioSaidaAlmoco, label: config.nomeSaidaAlmoco || 'Saída 1' }, { tipo: 'saida', horario: config.horarioSaida, label: config.nomeSaida || 'Saída 2' }] as horarioEsperado (horarioEsperado.tipo)}
|
||||
{#if !registrosOrdenados.find((r) => r.tipo === horarioEsperado.tipo)}
|
||||
<div class="relative opacity-50">
|
||||
<div
|
||||
@@ -1589,19 +1618,19 @@
|
||||
<!-- Backdrop leve -->
|
||||
<div
|
||||
class="pointer-events-auto absolute inset-0 bg-black/20 transition-opacity duration-200"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
onclick={handleWebcamCancel}
|
||||
onkeydown={(e) => (e.key === 'Enter' || e.key === ' ') && handleWebcamCancel()}
|
||||
></div>
|
||||
|
||||
<!-- Modal Box -->
|
||||
<div
|
||||
class="bg-base-100 pointer-events-auto absolute z-10 flex max-h-[90vh] w-full max-w-2xl transform flex-col overflow-hidden rounded-2xl shadow-2xl transition-all duration-300"
|
||||
style="animation: slideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); {getModalStyle()}"
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<!-- Header fixo -->
|
||||
<div
|
||||
class="border-base-300 flex flex-shrink-0 items-center justify-between border-b px-6 py-4"
|
||||
>
|
||||
<div class="border-base-300 flex shrink-0 items-center justify-between border-b px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-primary/10 rounded-lg p-2">
|
||||
<Camera class="text-primary h-5 w-5" strokeWidth={2} />
|
||||
@@ -1737,19 +1766,19 @@
|
||||
<!-- Backdrop leve -->
|
||||
<div
|
||||
class="pointer-events-auto absolute inset-0 bg-black/20 transition-opacity duration-200"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
onclick={cancelarRegistro}
|
||||
onkeydown={(e) => (e.key === 'Enter' || e.key === ' ') && cancelarRegistro()}
|
||||
></div>
|
||||
|
||||
<!-- Modal Box -->
|
||||
<div
|
||||
class="bg-base-100 pointer-events-auto absolute z-10 flex max-h-[90vh] w-full max-w-3xl transform flex-col overflow-hidden rounded-2xl shadow-2xl transition-all duration-300"
|
||||
style="animation: slideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); {getModalStyle()}"
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<!-- Header fixo -->
|
||||
<div
|
||||
class="border-base-300 flex flex-shrink-0 items-center justify-between border-b px-6 py-4"
|
||||
>
|
||||
<div class="border-base-300 flex shrink-0 items-center justify-between border-b px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-primary/10 rounded-lg p-2">
|
||||
<Clock class="text-primary h-6 w-6" strokeWidth={2} />
|
||||
@@ -1776,25 +1805,12 @@
|
||||
<div class="modal-scroll flex-1 space-y-6 overflow-y-auto px-6 py-4">
|
||||
<!-- Card da Imagem -->
|
||||
<div
|
||||
class="card from-base-200 to-base-300 border-primary/20 border-2 bg-gradient-to-br shadow-lg"
|
||||
class="card from-base-200 to-base-300 border-primary/20 border-2 bg-linear-to-br shadow-lg"
|
||||
>
|
||||
<div class="card-body p-6">
|
||||
<div class="mb-4 flex items-center gap-2">
|
||||
<div class="bg-primary/10 rounded-lg p-1.5">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="text-primary h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
<ImageIcon class="text-primary h-5 w-5" strokeWidth={2} />
|
||||
</div>
|
||||
<h4 class="text-lg font-semibold">Foto Capturada</h4>
|
||||
</div>
|
||||
@@ -1812,7 +1828,7 @@
|
||||
|
||||
<!-- Card de Informações -->
|
||||
<div
|
||||
class="card from-primary/5 to-primary/10 border-primary/20 border-2 bg-gradient-to-br shadow-lg"
|
||||
class="card from-primary/5 to-primary/10 border-primary/20 border-2 bg-linear-to-br shadow-lg"
|
||||
>
|
||||
<div class="card-body p-6">
|
||||
<div class="mb-4 flex items-center gap-2">
|
||||
@@ -1863,19 +1879,7 @@
|
||||
|
||||
<!-- Aviso -->
|
||||
<div class="alert alert-info shadow-lg">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6 shrink-0 stroke-current"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<Info class="h-6 w-6 shrink-0 stroke-current" />
|
||||
<div>
|
||||
<h3 class="font-bold">Confirme os dados</h3>
|
||||
<div class="text-sm">
|
||||
@@ -1886,7 +1890,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Footer fixo com botões -->
|
||||
<div class="border-base-300 flex flex-shrink-0 justify-end gap-3 border-t px-6 py-4">
|
||||
<div class="border-base-300 flex shrink-0 justify-end gap-3 border-t px-6 py-4">
|
||||
<button
|
||||
class="btn btn-outline"
|
||||
onclick={cancelarRegistro}
|
||||
|
||||
Reference in New Issue
Block a user