This commit is contained in:
Leonardo
2026-03-06 06:37:13 -03:00
parent d58dc21297
commit f733db8436
146 changed files with 43436 additions and 12779 deletions
@@ -0,0 +1,131 @@
// src/features/agenda/services/agendaClinicRepository.js
import { supabase } from '@/lib/supabase/client'
function assertValidTenantId (tenantId) {
if (!tenantId || tenantId === 'null' || tenantId === 'undefined') {
throw new Error('Tenant ativo inválido. Selecione a clínica/tenant antes de carregar a agenda.')
}
}
function assertValidIsoRange (startISO, endISO) {
if (!startISO || !endISO) throw new Error('Intervalo inválido (startISO/endISO).')
}
function sanitizeOwnerIds (ownerIds) {
return (ownerIds || [])
.filter(id => typeof id === 'string' && id && id !== 'null' && id !== 'undefined')
}
/**
* Lista eventos para mosaico da clínica (admin/secretaria) dentro de um tenant específico.
* IMPORTANTE: SEM tenant_id aqui vira vazamento multi-tenant.
*/
export async function listClinicEvents ({ tenantId, ownerIds, startISO, endISO } = {}) {
assertValidTenantId(tenantId)
if (!ownerIds?.length) return []
assertValidIsoRange(startISO, endISO)
const safeOwnerIds = sanitizeOwnerIds(ownerIds)
if (!safeOwnerIds.length) return []
const { data, error } = await supabase
.from('agenda_eventos')
.select('*')
.eq('tenant_id', tenantId)
.in('owner_id', safeOwnerIds)
.gte('inicio_em', startISO)
.lt('inicio_em', endISO)
.order('inicio_em', { ascending: true })
if (error) throw error
return data || []
}
/**
* Lista profissionais/membros para montar colunas no mosaico.
* Usando view "v_tenant_staff" (como você já tem).
*/
export async function listTenantStaff (tenantId) {
assertValidTenantId(tenantId)
const { data, error } = await supabase
.from('v_tenant_staff')
.select('*')
.eq('tenant_id', tenantId)
if (error) throw error
return data || []
}
/**
* Criação para a área da clínica (admin/secretária):
* - exige tenantId explícito
* - permite definir owner_id (terapeuta dono do compromisso)
*
* Segurança real deve ser garantida por RLS:
* - clinic_admin/tenant_admin pode criar para qualquer owner dentro do tenant
* - therapist não deve conseguir passar daqui (guard + RLS)
*/
export async function createClinicAgendaEvento (payload, { tenantId } = {}) {
assertValidTenantId(tenantId)
if (!payload) throw new Error('Payload vazio.')
const ownerId = payload.owner_id
if (!ownerId || ownerId === 'null' || ownerId === 'undefined') {
throw new Error('owner_id é obrigatório para criação pela clínica.')
}
const insertPayload = {
...payload,
tenant_id: tenantId
}
const { data, error } = await supabase
.from('agenda_eventos')
.insert(insertPayload)
.select('*')
.single()
if (error) throw error
return data
}
/**
* Atualização segura para clínica:
* - filtra por id + tenant_id (evita update cruzado)
* - permite editar owner_id (caso você mova evento para outro profissional)
*/
export async function updateClinicAgendaEvento (id, patch, { tenantId } = {}) {
if (!id) throw new Error('ID inválido.')
if (!patch) throw new Error('Patch vazio.')
assertValidTenantId(tenantId)
const { data, error } = await supabase
.from('agenda_eventos')
.update(patch)
.eq('id', id)
.eq('tenant_id', tenantId)
.select('*')
.single()
if (error) throw error
return data
}
/**
* Delete seguro para clínica:
* - filtra por id + tenant_id
*/
export async function deleteClinicAgendaEvento (id, { tenantId } = {}) {
if (!id) throw new Error('ID inválido.')
assertValidTenantId(tenantId)
const { error } = await supabase
.from('agenda_eventos')
.delete()
.eq('id', id)
.eq('tenant_id', tenantId)
if (error) throw error
return true
}