feat: enhance dashboard functionality by adding user statistics, improving data filtering for dispensas, and refining timestamp handling to ensure accurate time zone management

This commit is contained in:
2025-12-24 08:26:47 -03:00
parent e548c2c678
commit b248472d65
5 changed files with 500 additions and 837 deletions

View File

@@ -636,45 +636,59 @@ export const registrarPonto = mutation({
.filter((q) => q.eq(q.field('ativo'), true))
.collect();
const dataConsulta = new Date(data);
// Helper para criar timestamp UTC a partir de data (YYYY-MM-DD), hora e minuto em GMT-3
// A hora informada está em GMT-3, então precisamos adicionar 3 horas para obter UTC
const offsetGMT3ParaUTC = 3 * 60 * 60 * 1000; // 3 horas em milissegundos
function criarTimestampUTCDeGMT3(data: string, hora: number, minuto: number): number {
const [ano, mes, dia] = data.split('-').map(Number);
return Date.UTC(ano, mes - 1, dia, hora, minuto, 0, 0) + offsetGMT3ParaUTC;
}
// Helper para criar timestamp UTC a partir de data (YYYY-MM-DD), hora e minuto que já estão em UTC
function criarTimestampUTC(data: string, horaUTC: number, minutoUTC: number): number {
const [ano, mes, dia] = data.split('-').map(Number);
return Date.UTC(ano, mes - 1, dia, horaUTC, minutoUTC, 0, 0);
}
// Obter timestamp atual em UTC
const agoraUTC = new Date();
const agoraTimestampUTC = agoraUTC.getTime();
// Timestamp da consulta (registro sendo feito) em UTC
// hora/minuto já estão em UTC (extraídos com getUTCHours/getUTCMinutes)
const timestampConsultaUTC = criarTimestampUTC(data, hora, minuto);
for (const dispensa of dispensas) {
// Se for isento, sempre está dispensado
if (dispensa.isento) {
throw new Error('Registro dispensado pelo gestor: Isento de registro (caso excepcional)');
}
// Verificar se está no período
const dataInicio = new Date(dispensa.dataInicio);
const dataFim = new Date(dispensa.dataFim);
// Calcular timestamps de início e fim da dispensa em UTC
const timestampInicioUTC = criarTimestampUTCDeGMT3(
dispensa.dataInicio,
dispensa.horaInicio,
dispensa.minutoInicio
);
const timestampFimUTC = criarTimestampUTCDeGMT3(
dispensa.dataFim,
dispensa.horaFim,
dispensa.minutoFim
);
if (dataConsulta >= dataInicio && dataConsulta <= dataFim) {
// Verificar hora e minuto se necessário
const timestampConsulta = new Date(
`${data}T${hora.toString().padStart(2, '0')}:${minuto.toString().padStart(2, '0')}:00`
).getTime();
const timestampInicio = new Date(
`${dispensa.dataInicio}T${dispensa.horaInicio.toString().padStart(2, '0')}:${dispensa.minutoInicio.toString().padStart(2, '0')}:00`
).getTime();
const timestampFim = new Date(
`${dispensa.dataFim}T${dispensa.horaFim.toString().padStart(2, '0')}:${dispensa.minutoFim.toString().padStart(2, '0')}:00`
).getTime();
if (timestampConsulta >= timestampInicio && timestampConsulta <= timestampFim) {
throw new Error(`Registro dispensado pelo gestor: ${dispensa.motivo}`);
}
}
// Verificar se expirou (desativar na mutation de registro)
const agora = new Date();
const dataFimTimestamp = new Date(
`${dispensa.dataFim}T${dispensa.horaFim.toString().padStart(2, '0')}:${dispensa.minutoFim.toString().padStart(2, '0')}:00`
).getTime();
if (agora.getTime() > dataFimTimestamp && !dispensa.isento) {
// Desativar dispensa expirada (mutation pode fazer isso)
// Desativar dispensa expirada ANTES de verificar bloqueio (após o fim)
// Verificar se AGORA já passou do horário de fim da dispensa
if (agoraTimestampUTC > timestampFimUTC) {
await ctx.db.patch(dispensa._id, {
ativo: false
});
continue; // Pular verificação de bloqueio se já expirou
}
// Verificar se AGORA está dentro do período da dispensa (não o horário do registro)
// Se o momento atual está dentro do período, bloqueia qualquer tentativa de registro
if (agoraTimestampUTC >= timestampInicioUTC && agoraTimestampUTC <= timestampFimUTC) {
throw new Error(`Registro dispensado pelo gestor: ${dispensa.motivo}`);
}
}
@@ -2883,10 +2897,7 @@ export const excluirHomologacao = mutation({
};
// Se a homologação tem valores anteriores, restaurar
if (
homologacao.horaAnterior !== undefined &&
homologacao.minutoAnterior !== undefined
) {
if (homologacao.horaAnterior !== undefined && homologacao.minutoAnterior !== undefined) {
patchData.hora = homologacao.horaAnterior;
patchData.minuto = homologacao.minutoAnterior;
}
@@ -3033,10 +3044,8 @@ export const removerDispensaRegistro = mutation({
throw new Error('Você não tem permissão para remover esta dispensa');
}
// Desativar dispensa
await ctx.db.patch(args.dispensaId, {
ativo: false
});
// Deletar dispensa do banco de dados
await ctx.db.delete(args.dispensaId);
return { success: true };
}
@@ -3117,14 +3126,49 @@ export const listarDispensas = query({
}
}
// Verificar se expirou (se não for isento)
// Verificar se está ativa ou expirada (considerando data, hora e minuto em GMT-3)
let expirada = false;
// GMT-3 está 3 horas ATRÁS do UTC
// Offset: +3 horas para converter GMT-3 para UTC
const offsetGMT3ParaUTC = 3 * 60 * 60 * 1000; // 3 horas em milissegundos
// Obter data/hora atual em UTC
const agoraUTC = new Date();
const agoraTimestampUTC = agoraUTC.getTime();
// Helper para criar timestamp UTC a partir de data (YYYY-MM-DD), hora e minuto em GMT-3
// A hora informada está em GMT-3, então precisamos adicionar 3 horas para obter UTC
// Exemplo: 08:00 GMT-3 = 11:00 UTC
function criarTimestampUTCDeGMT3(data: string, hora: number, minuto: number): number {
const [ano, mes, dia] = data.split('-').map(Number);
// Date.UTC cria timestamp UTC
// Se a hora está em GMT-3, adicionamos 3 horas para obter o equivalente UTC
return Date.UTC(ano, mes - 1, dia, hora, minuto, 0, 0) + offsetGMT3ParaUTC;
}
if (!d.isento) {
const agora = new Date();
const dataFimTimestamp = new Date(
`${d.dataFim}T${d.horaFim.toString().padStart(2, '0')}:${d.minutoFim.toString().padStart(2, '0')}:00`
).getTime();
expirada = agora.getTime() > dataFimTimestamp;
// Para dispensas não isentas, verificar se está dentro do período
const dataInicioTimestamp = criarTimestampUTCDeGMT3(
d.dataInicio,
d.horaInicio,
d.minutoInicio
);
const dataFimTimestamp = criarTimestampUTCDeGMT3(d.dataFim, d.horaFim, d.minutoFim);
// Está expirada se estiver antes do início OU depois do fim
// Está ativa se: dataInicioTimestamp <= agoraTimestampUTC <= dataFimTimestamp
expirada =
agoraTimestampUTC < dataInicioTimestamp || agoraTimestampUTC > dataFimTimestamp;
} else {
// Se for isento, verificar apenas se já passou do início
const dataInicioTimestamp = criarTimestampUTCDeGMT3(
d.dataInicio,
d.horaInicio,
d.minutoInicio
);
// Se ainda não começou, está expirada (não ativa ainda)
expirada = agoraTimestampUTC < dataInicioTimestamp;
}
return {
@@ -3349,7 +3393,16 @@ export const verificarDispensaAtiva = query({
.filter((q) => q.eq(q.field('ativo'), true))
.collect();
const dataConsulta = new Date(args.data);
// Helper para criar timestamp UTC a partir de data (YYYY-MM-DD), hora e minuto em GMT-3
const offsetGMT3ParaUTC = 3 * 60 * 60 * 1000; // 3 horas em milissegundos
function criarTimestampUTCDeGMT3(data: string, hora: number, minuto: number): number {
const [ano, mes, dia] = data.split('-').map(Number);
return Date.UTC(ano, mes - 1, dia, hora, minuto, 0, 0) + offsetGMT3ParaUTC;
}
// Obter timestamp atual em UTC
const agoraUTC = new Date();
const agoraTimestampUTC = agoraUTC.getTime();
for (const dispensa of dispensas) {
// Se for isento, sempre está dispensado
@@ -3361,33 +3414,39 @@ export const verificarDispensaAtiva = query({
};
}
// Verificar se está no período
const dataInicio = new Date(dispensa.dataInicio);
const dataFim = new Date(dispensa.dataFim);
// Calcular timestamps de início e fim da dispensa em UTC
const timestampInicioUTC = criarTimestampUTCDeGMT3(
dispensa.dataInicio,
dispensa.horaInicio,
dispensa.minutoInicio
);
const timestampFimUTC = criarTimestampUTCDeGMT3(
dispensa.dataFim,
dispensa.horaFim,
dispensa.minutoFim
);
// Se a data está dentro do período
if (dataConsulta >= dataInicio && dataConsulta <= dataFim) {
// Se hora e minuto foram fornecidos, verificar também
if (args.hora !== undefined && args.minuto !== undefined) {
const timestampConsulta = new Date(
`${args.data}T${args.hora.toString().padStart(2, '0')}:${args.minuto.toString().padStart(2, '0')}:00`
).getTime();
const timestampInicio = new Date(
`${dispensa.dataInicio}T${dispensa.horaInicio.toString().padStart(2, '0')}:${dispensa.minutoInicio.toString().padStart(2, '0')}:00`
).getTime();
const timestampFim = new Date(
`${dispensa.dataFim}T${dispensa.horaFim.toString().padStart(2, '0')}:${dispensa.minutoFim.toString().padStart(2, '0')}:00`
).getTime();
// Verificar se AGORA já passou do horário de fim da dispensa
// Se já expirou, não está mais dispensado
if (agoraTimestampUTC > timestampFimUTC) {
// Dispensa expirada, continuar para próxima
continue;
}
if (timestampConsulta >= timestampInicio && timestampConsulta <= timestampFim) {
return {
dispensado: true,
dispensa,
motivo: dispensa.motivo
};
}
} else {
// Apenas verificar data
// Se hora e minuto foram fornecidos, verificar timestamp completo
if (args.hora !== undefined && args.minuto !== undefined) {
const timestampConsultaUTC = criarTimestampUTCDeGMT3(args.data, args.hora, args.minuto);
if (timestampConsultaUTC >= timestampInicioUTC && timestampConsultaUTC <= timestampFimUTC) {
return {
dispensado: true,
dispensa,
motivo: dispensa.motivo
};
}
} else {
// Se apenas data foi fornecida, verificar se AGORA está dentro do período
// (não apenas a data, mas também o horário)
if (agoraTimestampUTC >= timestampInicioUTC && agoraTimestampUTC <= timestampFimUTC) {
return {
dispensado: true,
dispensa,