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,7 +1,7 @@
import { v } from 'convex/values';
import type { Id } from './_generated/dataModel';
import type { MutationCtx, QueryCtx } from './_generated/server';
import { mutation, query } from './_generated/server';
import { Id } from './_generated/dataModel';
import type { QueryCtx, MutationCtx } from './_generated/server';
import { getCurrentUserFunction } from './auth';
// ========== HELPERS ==========
@@ -35,8 +35,11 @@ async function gerarRoomName(
const roomPrefix = configJitsi?.roomPrefix || 'sgse';
const timestamp = Date.now();
const random = Math.random().toString(36).substring(2, 9);
const conversaHash = conversaId.replace('conversas|', '').replace(/[^a-zA-Z0-9]/g, '').substring(0, 10);
const conversaHash = conversaId
.replace('conversas|', '')
.replace(/[^a-zA-Z0-9]/g, '')
.substring(0, 10);
return `${roomPrefix}-${tipo}-${conversaHash}-${timestamp}-${random}`;
}
@@ -93,10 +96,7 @@ export const criarChamada = mutation({
.query('chamadas')
.withIndex('by_conversa', (q) => q.eq('conversaId', args.conversaId))
.filter((q) =>
q.or(
q.eq(q.field('status'), 'aguardando'),
q.eq(q.field('status'), 'em_andamento')
)
q.or(q.eq(q.field('status'), 'aguardando'), q.eq(q.field('status'), 'em_andamento'))
)
.collect();
@@ -123,11 +123,15 @@ export const criarChamada = mutation({
gravando: false,
configuracoes: {
audioHabilitado: args.audioHabilitado ?? true,
videoHabilitado: args.videoHabilitado ?? (args.tipo === 'video'),
videoHabilitado: args.videoHabilitado ?? args.tipo === 'video',
participantesConfig: conversa.participantes.map((participanteId) => ({
usuarioId: participanteId,
audioHabilitado: participanteId === usuarioAtual._id ? (args.audioHabilitado ?? true) : true,
videoHabilitado: participanteId === usuarioAtual._id ? (args.videoHabilitado ?? (args.tipo === 'video')) : (args.tipo === 'video'),
audioHabilitado:
participanteId === usuarioAtual._id ? (args.audioHabilitado ?? true) : true,
videoHabilitado:
participanteId === usuarioAtual._id
? (args.videoHabilitado ?? args.tipo === 'video')
: args.tipo === 'video',
forcadoPeloAnfitriao: false
}))
},
@@ -280,15 +284,18 @@ export const adicionarParticipante = mutation({
// Atualizar participantes
const novosParticipantes = [...chamada.participantes, args.usuarioId];
// Atualizar configurações
const configParticipantes = chamada.configuracoes?.participantesConfig || [];
const novaConfig = [...configParticipantes, {
usuarioId: args.usuarioId,
audioHabilitado: chamada.configuracoes?.audioHabilitado ?? true,
videoHabilitado: chamada.configuracoes?.videoHabilitado ?? (chamada.tipo === 'video'),
forcadoPeloAnfitriao: false
}];
const novaConfig = [
...configParticipantes,
{
usuarioId: args.usuarioId,
audioHabilitado: chamada.configuracoes?.audioHabilitado ?? true,
videoHabilitado: chamada.configuracoes?.videoHabilitado ?? chamada.tipo === 'video',
forcadoPeloAnfitriao: false
}
];
await ctx.db.patch(args.chamadaId, {
participantes: novosParticipantes,
@@ -333,7 +340,7 @@ export const removerParticipante = mutation({
// Atualizar participantes
const novosParticipantes = chamada.participantes.filter((id) => id !== args.usuarioId);
// Atualizar configurações
const configParticipantes = chamada.configuracoes?.participantesConfig || [];
const novaConfig = configParticipantes.filter((config) => config.usuarioId !== args.usuarioId);
@@ -388,17 +395,32 @@ export const toggleAudioVideoParticipante = mutation({
// Adicionar configuração se não existir
configParticipantes.push({
usuarioId: args.participanteId,
audioHabilitado: args.tipo === 'audio' ? args.habilitado : (chamada.configuracoes?.audioHabilitado ?? true),
videoHabilitado: args.tipo === 'video' ? args.habilitado : (chamada.configuracoes?.videoHabilitado ?? (chamada.tipo === 'video')),
audioHabilitado:
args.tipo === 'audio'
? args.habilitado
: (chamada.configuracoes?.audioHabilitado ?? true),
videoHabilitado:
args.tipo === 'video'
? args.habilitado
: (chamada.configuracoes?.videoHabilitado ?? chamada.tipo === 'video'),
forcadoPeloAnfitriao: !ehOProprioParticipante && args.habilitado === false
});
} else {
// Atualizar configuração existente
configParticipantes[participanteIndex] = {
...configParticipantes[participanteIndex],
audioHabilitado: args.tipo === 'audio' ? args.habilitado : configParticipantes[participanteIndex].audioHabilitado,
videoHabilitado: args.tipo === 'video' ? args.habilitado : configParticipantes[participanteIndex].videoHabilitado,
forcadoPeloAnfitriao: !ehOProprioParticipante && !args.habilitado ? true : configParticipantes[participanteIndex].forcadoPeloAnfitriao
audioHabilitado:
args.tipo === 'audio'
? args.habilitado
: configParticipantes[participanteIndex].audioHabilitado,
videoHabilitado:
args.tipo === 'video'
? args.habilitado
: configParticipantes[participanteIndex].videoHabilitado,
forcadoPeloAnfitriao:
!ehOProprioParticipante && !args.habilitado
? true
: configParticipantes[participanteIndex].forcadoPeloAnfitriao
};
}
@@ -509,10 +531,7 @@ export const obterChamadaAtiva = query({
.query('chamadas')
.withIndex('by_conversa', (q) => q.eq('conversaId', args.conversaId))
.filter((q) =>
q.or(
q.eq(q.field('status'), 'aguardando'),
q.eq(q.field('status'), 'em_andamento')
)
q.or(q.eq(q.field('status'), 'aguardando'), q.eq(q.field('status'), 'em_andamento'))
)
.collect();
@@ -589,5 +608,3 @@ export const obterChamada = query({
return chamada;
}
});