feat: enhance call and point registration features with sensor data integration

- Updated the CallWindow component to include connection quality states and reconnection attempts, improving user experience during calls.
- Enhanced the ChatWindow to allow starting audio and video calls in a new window, providing users with more flexibility.
- Integrated accelerometer and gyroscope data collection in the RegistroPonto component, enabling validation of point registration authenticity.
- Improved error handling and user feedback for sensor permissions and data validation, ensuring a smoother registration process.
- Updated backend logic to validate sensor data and adjust confidence scores for point registration, enhancing security against spoofing.
This commit is contained in:
2025-11-22 20:49:52 -03:00
parent fc4b5c5ba5
commit f818756efc
15 changed files with 2100 additions and 275 deletions

View File

@@ -145,7 +145,7 @@
}
// Funções para chamadas
async function iniciarChamada(tipo: 'audio' | 'video'): Promise<void> {
async function iniciarChamada(tipo: 'audio' | 'video', abrirEmNovaJanela: boolean = false): Promise<void> {
if (chamadaAtual) {
errorTitle = 'Chamada já em andamento';
errorMessage =
@@ -165,6 +165,45 @@
videoHabilitado: tipo === 'video'
});
// Se deve abrir em nova janela
if (abrirEmNovaJanela && browser) {
const { abrirCallWindowEmPopup, verificarSuportePopup } = await import('$lib/utils/callWindowManager');
if (!verificarSuportePopup()) {
errorTitle = 'Popups bloqueados';
errorMessage = 'Seu navegador está bloqueando popups. Por favor, permita popups para este site e tente novamente.';
errorInstructions = 'Verifique as configurações do seu navegador para permitir popups.';
showErrorModal = true;
return;
}
// Buscar informações da chamada para obter roomName
const chamadaInfo = await client.query(api.chamadas.obterChamada, { chamadaId });
if (!chamadaInfo) {
throw new Error('Chamada não encontrada');
}
const meuPerfil = await client.query(api.auth.getCurrentUser, {});
const ehAnfitriao = chamadaInfo.criadoPor === meuPerfil?._id;
// Abrir em popup
const popup = abrirCallWindowEmPopup({
chamadaId: chamadaId as string,
conversaId: conversaId as string,
tipo,
roomName: chamadaInfo.roomName,
ehAnfitriao
});
if (!popup) {
throw new Error('Não foi possível abrir a janela de chamada');
}
// Não definir chamadaAtiva aqui, pois será gerenciada pela janela popup
return;
}
chamadaAtiva = chamadaId;
} catch (error) {
console.error('Erro ao iniciar chamada:', error);
@@ -316,33 +355,99 @@
<!-- Botões de ação -->
<div class="flex items-center gap-1">
<!-- Botões de Chamada -->
{#if !chamadaAtual}
<button
type="button"
class="btn btn-sm btn-circle btn-primary"
onclick={(e) => {
e.stopPropagation();
iniciarChamada('audio');
}}
disabled={iniciandoChamada}
aria-label="Ligação de áudio"
title="Iniciar ligação de áudio"
>
<Phone class="h-5 w-5" strokeWidth={2} />
</button>
<button
type="button"
class="btn btn-sm btn-circle btn-primary"
onclick={(e) => {
e.stopPropagation();
iniciarChamada('video');
}}
disabled={iniciandoChamada}
aria-label="Ligação de vídeo"
title="Iniciar ligação de vídeo"
>
<Video class="h-5 w-5" strokeWidth={2} />
</button>
{#if !chamadaAtual && !chamadaAtiva}
<div class="dropdown dropdown-end">
<button
type="button"
class="btn btn-sm btn-circle btn-primary"
onclick={(e) => {
e.stopPropagation();
iniciarChamada('audio', false);
}}
disabled={iniciandoChamada}
aria-label="Ligação de áudio"
title="Iniciar ligação de áudio"
>
<Phone class="h-5 w-5" strokeWidth={2} />
</button>
<ul
tabindex="0"
class="dropdown-content menu bg-base-100 rounded-box z-[100] w-52 p-2 shadow-lg border border-base-300"
>
<li>
<button
type="button"
onclick={(e) => {
e.stopPropagation();
iniciarChamada('audio', false);
}}
disabled={iniciandoChamada}
>
<Phone class="h-4 w-4" />
Áudio (nesta janela)
</button>
</li>
<li>
<button
type="button"
onclick={(e) => {
e.stopPropagation();
iniciarChamada('audio', true);
}}
disabled={iniciandoChamada}
>
<Phone class="h-4 w-4" />
Áudio (nova janela)
</button>
</li>
</ul>
</div>
<div class="dropdown dropdown-end">
<button
type="button"
class="btn btn-sm btn-circle btn-primary"
onclick={(e) => {
e.stopPropagation();
iniciarChamada('video', false);
}}
disabled={iniciandoChamada}
aria-label="Ligação de vídeo"
title="Iniciar ligação de vídeo"
>
<Video class="h-5 w-5" strokeWidth={2} />
</button>
<ul
tabindex="0"
class="dropdown-content menu bg-base-100 rounded-box z-[100] w-52 p-2 shadow-lg border border-base-300"
>
<li>
<button
type="button"
onclick={(e) => {
e.stopPropagation();
iniciarChamada('video', false);
}}
disabled={iniciandoChamada}
>
<Video class="h-4 w-4" />
Vídeo (nesta janela)
</button>
</li>
<li>
<button
type="button"
onclick={(e) => {
e.stopPropagation();
iniciarChamada('video', true);
}}
disabled={iniciandoChamada}
>
<Video class="h-4 w-4" />
Vídeo (nova janela)
</button>
</li>
</ul>
</div>
{/if}
<!-- Botão Sair (apenas para grupos e salas de reunião) -->