feat: Add 'atas' (minutes/records) management feature, and implement various improvements across UI, backend logic, and authentication.

This commit is contained in:
2025-12-02 16:37:48 -03:00
parent 05e7f1181d
commit 4bd9e21748
265 changed files with 29156 additions and 26460 deletions

View File

@@ -1,8 +1,8 @@
import { v } from 'convex/values';
import { api, internal } from './_generated/api';
import type { Id } from './_generated/dataModel';
import { action, internalMutation, internalQuery, mutation, query } from './_generated/server';
import { getCurrentUserFunction } from './auth';
import type { Id } from './_generated/dataModel';
import { api, internal } from './_generated/api';
/**
* Tipo de retorno da configuração do relógio
@@ -24,14 +24,13 @@ export const obterConfiguracao = query({
args: {},
handler: async (ctx): Promise<ConfiguracaoRelogioRetorno> => {
// Buscar todas as configurações e pegar a mais recente (por atualizadoEm)
const configs = await ctx.db
.query('configuracaoRelogio')
.collect();
const configs = await ctx.db.query('configuracaoRelogio').collect();
// Pegar a configuração mais recente (ordenar por atualizadoEm desc)
const config = configs.length > 0
? configs.sort((a, b) => (b.atualizadoEm || 0) - (a.atualizadoEm || 0))[0]
: null;
const config =
configs.length > 0
? configs.sort((a, b) => (b.atualizadoEm || 0) - (a.atualizadoEm || 0))[0]
: null;
if (!config) {
// Retornar configuração padrão (GMT-3 para Brasília)
@@ -42,7 +41,7 @@ export const obterConfiguracao = query({
fallbackParaPC: true,
ultimaSincronizacao: null,
offsetSegundos: null,
gmtOffset: -3, // GMT-3 para Brasília
gmtOffset: -3 // GMT-3 para Brasília
};
}
@@ -50,9 +49,9 @@ export const obterConfiguracao = query({
...config,
ultimaSincronizacao: config.ultimaSincronizacao ?? null, // Converter undefined para null
offsetSegundos: config.offsetSegundos ?? null, // Converter undefined para null
gmtOffset: config.gmtOffset ?? -3, // Padrão GMT-3 para Brasília se não configurado
gmtOffset: config.gmtOffset ?? -3 // Padrão GMT-3 para Brasília se não configurado
};
},
}
});
/**
@@ -62,14 +61,13 @@ export const obterConfiguracaoInternal = internalQuery({
args: {},
handler: async (ctx): Promise<ConfiguracaoRelogioRetorno> => {
// Buscar todas as configurações e pegar a mais recente (por atualizadoEm)
const configs = await ctx.db
.query('configuracaoRelogio')
.collect();
const configs = await ctx.db.query('configuracaoRelogio').collect();
// Pegar a configuração mais recente (ordenar por atualizadoEm desc)
const config = configs.length > 0
? configs.sort((a, b) => (b.atualizadoEm || 0) - (a.atualizadoEm || 0))[0]
: null;
const config =
configs.length > 0
? configs.sort((a, b) => (b.atualizadoEm || 0) - (a.atualizadoEm || 0))[0]
: null;
if (!config) {
// Retornar configuração padrão (GMT-3 para Brasília)
@@ -80,7 +78,7 @@ export const obterConfiguracaoInternal = internalQuery({
fallbackParaPC: true,
ultimaSincronizacao: null,
offsetSegundos: null,
gmtOffset: -3, // GMT-3 para Brasília
gmtOffset: -3 // GMT-3 para Brasília
};
}
@@ -88,9 +86,9 @@ export const obterConfiguracaoInternal = internalQuery({
...config,
ultimaSincronizacao: config.ultimaSincronizacao ?? null, // Converter undefined para null
offsetSegundos: config.offsetSegundos ?? null, // Converter undefined para null
gmtOffset: config.gmtOffset ?? -3, // Padrão GMT-3 para Brasília se não configurado
gmtOffset: config.gmtOffset ?? -3 // Padrão GMT-3 para Brasília se não configurado
};
},
}
});
/**
@@ -102,7 +100,7 @@ export const salvarConfiguracao = mutation({
portaNTP: v.optional(v.number()),
usarServidorExterno: v.boolean(),
fallbackParaPC: v.boolean(),
gmtOffset: v.optional(v.number()),
gmtOffset: v.optional(v.number())
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -123,13 +121,12 @@ export const salvarConfiguracao = mutation({
}
// Buscar configuração existente (pegar a mais recente)
const configs = await ctx.db
.query('configuracaoRelogio')
.collect();
const configExistente = configs.length > 0
? configs.sort((a, b) => (b.atualizadoEm || 0) - (a.atualizadoEm || 0))[0]
: null;
const configs = await ctx.db.query('configuracaoRelogio').collect();
const configExistente =
configs.length > 0
? configs.sort((a, b) => (b.atualizadoEm || 0) - (a.atualizadoEm || 0))[0]
: null;
if (configExistente) {
// Atualizar configuração existente
@@ -140,7 +137,7 @@ export const salvarConfiguracao = mutation({
fallbackParaPC: args.fallbackParaPC,
gmtOffset: args.gmtOffset ?? -3, // Padrão GMT-3 para Brasília
atualizadoPor: usuario._id as Id<'usuarios'>,
atualizadoEm: Date.now(),
atualizadoEm: Date.now()
});
return { configId: configExistente._id };
} else {
@@ -152,11 +149,11 @@ export const salvarConfiguracao = mutation({
fallbackParaPC: args.fallbackParaPC,
gmtOffset: args.gmtOffset ?? -3, // Padrão GMT-3 para Brasília
atualizadoPor: usuario._id as Id<'usuarios'>,
atualizadoEm: Date.now(),
atualizadoEm: Date.now()
});
return { configId };
}
},
}
});
/**
@@ -167,9 +164,9 @@ export const obterTempoServidor = query({
handler: async () => {
return {
timestamp: Date.now(),
data: new Date().toISOString(),
data: new Date().toISOString()
};
},
}
});
/**
@@ -191,14 +188,17 @@ export const sincronizarTempo = action({
args: {},
handler: async (ctx): Promise<SincronizacaoRetorno> => {
// Buscar configuração usando query interna para evitar referência circular
const config: ConfiguracaoRelogioRetorno = await ctx.runQuery(internal.configuracaoRelogio.obterConfiguracaoInternal, {});
const config: ConfiguracaoRelogioRetorno = await ctx.runQuery(
internal.configuracaoRelogio.obterConfiguracaoInternal,
{}
);
if (!config.usarServidorExterno) {
return {
sucesso: true,
timestamp: Date.now(),
usandoServidorExterno: false,
offsetSegundos: 0,
offsetSegundos: 0
};
}
@@ -208,7 +208,7 @@ export const sincronizarTempo = action({
try {
const servidorNTP = config.servidorNTP || 'pool.ntp.org';
let serverTime: number;
// Se o servidor configurado for uma URL HTTP/HTTPS, tentar usar diretamente
if (servidorNTP.startsWith('http://') || servidorNTP.startsWith('https://')) {
try {
@@ -216,7 +216,11 @@ export const sincronizarTempo = action({
if (!response.ok) {
throw new Error('Falha ao obter tempo do servidor configurado');
}
const data = (await response.json()) as { unixtime?: number; unixTime?: number; unixtimestamp?: number };
const data = (await response.json()) as {
unixtime?: number;
unixTime?: number;
unixtimestamp?: number;
};
// Tentar diferentes formatos de resposta
if (data.unixtime) {
serverTime = data.unixtime * 1000; // Converter segundos para milissegundos
@@ -261,7 +265,7 @@ export const sincronizarTempo = action({
if (configExistente) {
await ctx.runMutation(internal.configuracaoRelogio.atualizarSincronizacao, {
configId: configExistente._id,
offsetSegundos,
offsetSegundos
});
}
@@ -269,7 +273,7 @@ export const sincronizarTempo = action({
sucesso: true,
timestamp: serverTime, // Retorna UTC (sem GMT offset aplicado)
usandoServidorExterno: true,
offsetSegundos,
offsetSegundos
};
} catch (error) {
// Sempre usar fallback como última opção, mesmo se desabilitado
@@ -277,18 +281,18 @@ export const sincronizarTempo = action({
const aviso: string = config.fallbackParaPC
? 'Falha ao sincronizar com servidor externo, usando relógio do PC'
: 'Falha ao sincronizar com servidor externo. Fallback desabilitado, mas usando relógio do PC como última opção.';
console.warn('Erro ao sincronizar tempo com servidor externo:', error);
return {
sucesso: true,
timestamp: Date.now(),
usandoServidorExterno: false,
offsetSegundos: 0,
aviso,
aviso
};
}
},
}
});
/**
@@ -298,7 +302,7 @@ export const listarConfiguracoes = internalQuery({
args: {},
handler: async (ctx) => {
return await ctx.db.query('configuracaoRelogio').collect();
},
}
});
/**
@@ -307,13 +311,12 @@ export const listarConfiguracoes = internalQuery({
export const atualizarSincronizacao = internalMutation({
args: {
configId: v.id('configuracaoRelogio'),
offsetSegundos: v.number(),
offsetSegundos: v.number()
},
handler: async (ctx, args) => {
await ctx.db.patch(args.configId, {
ultimaSincronizacao: Date.now(),
offsetSegundos: args.offsetSegundos,
offsetSegundos: args.offsetSegundos
});
},
}
});