feat: improve point registration processing feedback with step-by-step messages and update modal positioning across components.

This commit is contained in:
2025-11-28 16:50:45 -03:00
parent 330d376930
commit 501751c22f
4 changed files with 70 additions and 34 deletions

View File

@@ -13,20 +13,20 @@
let modalPosition = $state<{ top: number; left: number } | null>(null);
// Função para calcular a posição baseada no relógio sincronizado
// Função para calcular a posição baseada no card de registro de ponto
function calcularPosicaoModal() {
// Procurar pelo elemento do relógio sincronizado
const relogioRef = document.getElementById('relogio-sincronizado-ref');
// Procurar pelo elemento do card de registro de ponto
const cardRef = document.getElementById('card-registro-ponto-ref');
if (relogioRef) {
const rect = relogioRef.getBoundingClientRect();
if (cardRef) {
const rect = cardRef.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// Posicionar o modal na mesma posição do relógio sincronizado
// Centralizado horizontalmente no card do relógio
// Posicionar o modal na mesma posição do card de registro
// Centralizado horizontalmente no card
const left = rect.left + (rect.width / 2);
// Posicionar abaixo do card do relógio com um pequeno espaçamento
// Posicionar abaixo do card com um pequeno espaçamento
const top = rect.bottom + 20;
return {

View File

@@ -21,20 +21,20 @@
let gerando = $state(false);
let modalPosition = $state<{ top: number; left: number } | null>(null);
// Função para calcular a posição baseada no relógio sincronizado
// Função para calcular a posição baseada no card de registro de ponto
function calcularPosicaoModal() {
// Procurar pelo elemento do relógio sincronizado
const relogioRef = document.getElementById('relogio-sincronizado-ref');
// Procurar pelo elemento do card de registro de ponto
const cardRef = document.getElementById('card-registro-ponto-ref');
if (relogioRef) {
const rect = relogioRef.getBoundingClientRect();
if (cardRef) {
const rect = cardRef.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// Posicionar o modal na mesma posição do relógio sincronizado
// Centralizado horizontalmente no card do relógio
// Posicionar o modal na mesma posição do card de registro
// Centralizado horizontalmente no card
const left = rect.left + (rect.width / 2);
// Posicionar abaixo do card do relógio com um pequeno espaçamento
// Posicionar abaixo do card com um pequeno espaçamento
const top = rect.bottom + 20;
return {

View File

@@ -65,6 +65,7 @@
let mostrandoModalConfirmacao = $state(false);
let dataHoraAtual = $state<{ data: string; hora: string } | null>(null);
let aguardandoProcessamento = $state(false);
let etapaProcessamento = $state<'coletando' | 'sincronizando' | 'upload' | 'registrando' | null>(null);
const registrosHoje = $derived(registrosHojeQuery?.data || []);
const config = $derived(configQuery?.data);
@@ -204,15 +205,19 @@
registrando = true;
sucesso = null;
coletandoInfo = true;
aguardandoProcessamento = true;
etapaProcessamento = 'coletando';
try {
// Coletar informações do dispositivo
etapaProcessamento = 'coletando';
const informacoesDispositivo = await obterInformacoesDispositivo();
// Nota: A permissão de sensor não é impeditiva - apenas câmera e localização são obrigatórias
coletandoInfo = false;
// Obter tempo sincronizado e aplicar GMT offset (igual ao relógio)
etapaProcessamento = 'sincronizando';
const configRelogio = await client.query(api.configuracaoRelogio.obterConfiguracao, {});
// Usar gmtOffset da configuração, sem valor padrão, pois 0 é um valor válido
const gmtOffset = configRelogio.gmtOffset ?? 0;
@@ -262,6 +267,7 @@
let imagemId: Id<'_storage'> | undefined = undefined;
if (imagemCapturada) {
try {
etapaProcessamento = 'upload';
imagemId = await uploadImagem(imagemCapturada);
} catch (error) {
console.error('Erro ao fazer upload da imagem:', error);
@@ -272,6 +278,7 @@
}
// Registrar ponto
etapaProcessamento = 'registrando';
const resultado = await client.mutation(api.pontos.registrarPonto, {
imagemId,
informacoesDispositivo,
@@ -314,6 +321,7 @@
} catch (error) {
console.error('Erro ao registrar ponto:', error);
aguardandoProcessamento = false;
etapaProcessamento = null;
let mensagemErro = 'Erro desconhecido ao registrar ponto';
let detalhesErro = 'Tente novamente em alguns instantes.';
@@ -392,6 +400,7 @@
registrando = false;
coletandoInfo = false;
aguardandoProcessamento = false;
etapaProcessamento = null;
}
}
@@ -518,7 +527,11 @@
function confirmarRegistro() {
mostrandoModalConfirmacao = false;
aguardandoProcessamento = true;
etapaProcessamento = 'coletando';
// Usar setTimeout para garantir que o modal de processamento apareça antes de iniciar o registro
setTimeout(() => {
registrarPonto();
}, 100);
}
function cancelarRegistro() {
@@ -855,20 +868,20 @@
// Posicionamento dos modais
let modalPosition = $state<{ top: number; left: number } | null>(null);
// Função para calcular a posição baseada no relógio sincronizado
// Função para calcular a posição baseada no card de registro de ponto
function calcularPosicaoModal() {
// Procurar pelo elemento do relógio sincronizado
const relogioRef = document.getElementById('relogio-sincronizado-ref');
// Procurar pelo elemento do card de registro de ponto
const cardRef = document.getElementById('card-registro-ponto-ref');
if (relogioRef) {
const rect = relogioRef.getBoundingClientRect();
if (cardRef) {
const rect = cardRef.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// Posicionar o modal na mesma posição do relógio sincronizado
// Centralizado horizontalmente no card do relógio
// Posicionar o modal na mesma posição do card de registro
// Centralizado horizontalmente no card
const left = rect.left + (rect.width / 2);
// Posicionar abaixo do card do relógio com um pequeno espaçamento
// Posicionar abaixo do card com um pequeno espaçamento
const top = rect.bottom + 20;
return {
@@ -1009,7 +1022,7 @@
<!-- Card de Registro de Ponto Modernizado -->
<div class="card bg-gradient-to-br from-base-100 via-base-100 to-primary/5 border border-base-300 shadow-2xl max-w-2xl mx-auto">
<div class="card-body p-6">
<div id="card-registro-ponto-ref" class="card-body p-6">
<!-- Cabeçalho -->
<div class="flex items-center justify-center gap-3 mb-6">
<div class="p-2.5 bg-primary/10 rounded-xl">
@@ -1498,8 +1511,32 @@
>
<div class="flex flex-col items-center gap-4 text-center">
<span class="loading loading-spinner loading-lg text-primary"></span>
<h3 id="modal-aguardando-title" class="text-xl font-bold text-base-content">Processando Registro</h3>
<p class="text-base-content/70">Por favor, aguarde enquanto processamos seu registro de ponto...</p>
<h3 id="modal-aguardando-title" class="text-xl font-bold text-base-content">
{#if etapaProcessamento === 'coletando'}
Coletando Informações
{:else if etapaProcessamento === 'sincronizando'}
Sincronizando Horário
{:else if etapaProcessamento === 'upload'}
Enviando Foto
{:else if etapaProcessamento === 'registrando'}
Registrando Ponto
{:else}
Processando Registro
{/if}
</h3>
<p class="text-base-content/70">
{#if etapaProcessamento === 'coletando'}
Coletando informações do dispositivo e localização...
{:else if etapaProcessamento === 'sincronizando'}
Sincronizando o horário com o servidor...
{:else if etapaProcessamento === 'upload'}
Enviando a foto capturada para o servidor...
{:else if etapaProcessamento === 'registrando'}
Finalizando o registro de ponto no sistema...
{:else}
Por favor, aguarde enquanto processamos seu registro de ponto...
{/if}
</p>
</div>
</div>
</div>
@@ -1540,7 +1577,7 @@
<button
class="btn btn-sm btn-circle btn-ghost hover:bg-base-300"
onclick={cancelarRegistro}
disabled={registrando}
disabled={registrando || aguardandoProcessamento}
>
<XCircle class="h-5 w-5" />
</button>
@@ -1658,7 +1695,7 @@
<button
class="btn btn-outline"
onclick={cancelarRegistro}
disabled={registrando}
disabled={registrando || aguardandoProcessamento}
>
<XCircle class="h-5 w-5" />
Cancelar
@@ -1666,11 +1703,11 @@
<button
class="btn btn-primary gap-2"
onclick={confirmarRegistro}
disabled={registrando}
disabled={registrando || aguardandoProcessamento}
>
{#if registrando}
{#if registrando || aguardandoProcessamento}
<span class="loading loading-spinner loading-sm"></span>
Registrando...
Processando...
{:else}
<CheckCircle2 class="h-5 w-5" />
Confirmar Registro

View File

@@ -1,6 +1,5 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "sgse-app",