Ajuste usuarios - Inicio agenda
This commit is contained in:
@@ -1,12 +1,28 @@
|
||||
// src/features/agenda/services/agendaRepository.js
|
||||
import { supabase } from '@/lib/supabase/client'
|
||||
import { useTenantStore } from '@/stores/tenantStore'
|
||||
|
||||
export async function getMyAgendaSettings () {
|
||||
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.')
|
||||
}
|
||||
}
|
||||
|
||||
async function getUid () {
|
||||
const { data: userRes, error: userErr } = await supabase.auth.getUser()
|
||||
if (userErr) throw userErr
|
||||
|
||||
const uid = userRes?.user?.id
|
||||
if (!uid) throw new Error('Usuário não autenticado.')
|
||||
return uid
|
||||
}
|
||||
|
||||
/**
|
||||
* Configurações da agenda (por owner)
|
||||
* Se você decidir que configurações são por tenant também, adicionamos tenant_id aqui.
|
||||
*/
|
||||
export async function getMyAgendaSettings () {
|
||||
const uid = await getUid()
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('agenda_configuracoes')
|
||||
@@ -18,16 +34,23 @@ export async function getMyAgendaSettings () {
|
||||
return data
|
||||
}
|
||||
|
||||
export async function listMyAgendaEvents ({ startISO, endISO }) {
|
||||
const { data: userRes, error: userErr } = await supabase.auth.getUser()
|
||||
if (userErr) throw userErr
|
||||
/**
|
||||
* Lista agenda do terapeuta (somente do owner logado) dentro do tenant ativo.
|
||||
* Isso impede misturar eventos caso o terapeuta atue em múltiplas clínicas.
|
||||
*/
|
||||
export async function listMyAgendaEvents ({ startISO, endISO, tenantId: tenantIdArg } = {}) {
|
||||
const uid = await getUid()
|
||||
|
||||
const uid = userRes?.user?.id
|
||||
if (!uid) throw new Error('Usuário não autenticado.')
|
||||
const tenantStore = useTenantStore()
|
||||
const tenantId = tenantIdArg || tenantStore.activeTenantId
|
||||
assertValidTenantId(tenantId)
|
||||
|
||||
if (!startISO || !endISO) throw new Error('Intervalo inválido (startISO/endISO).')
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('agenda_eventos')
|
||||
.select('*')
|
||||
.eq('tenant_id', tenantId)
|
||||
.eq('owner_id', uid)
|
||||
.gte('inicio_em', startISO)
|
||||
.lt('inicio_em', endISO)
|
||||
@@ -37,13 +60,26 @@ export async function listMyAgendaEvents ({ startISO, endISO }) {
|
||||
return data || []
|
||||
}
|
||||
|
||||
export async function listClinicEvents ({ ownerIds, startISO, endISO }) {
|
||||
/**
|
||||
* 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 []
|
||||
if (!startISO || !endISO) throw new Error('Intervalo inválido (startISO/endISO).')
|
||||
|
||||
// Sanitiza ownerIds
|
||||
const safeOwnerIds = ownerIds
|
||||
.filter(id => typeof id === 'string' && id && id !== 'null' && id !== 'undefined')
|
||||
|
||||
if (!safeOwnerIds.length) return []
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('agenda_eventos')
|
||||
.select('*')
|
||||
.in('owner_id', ownerIds)
|
||||
.eq('tenant_id', tenantId)
|
||||
.in('owner_id', safeOwnerIds)
|
||||
.gte('inicio_em', startISO)
|
||||
.lt('inicio_em', endISO)
|
||||
.order('inicio_em', { ascending: true })
|
||||
@@ -53,7 +89,7 @@ export async function listClinicEvents ({ ownerIds, startISO, endISO }) {
|
||||
}
|
||||
|
||||
export async function listTenantStaff (tenantId) {
|
||||
if (!tenantId || tenantId === 'null' || tenantId === 'undefined') return []
|
||||
assertValidTenantId(tenantId)
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('v_tenant_staff')
|
||||
@@ -64,10 +100,33 @@ export async function listTenantStaff (tenantId) {
|
||||
return data || []
|
||||
}
|
||||
|
||||
/**
|
||||
* Criação segura:
|
||||
* - injeta tenant_id do tenantStore
|
||||
* - injeta owner_id do usuário logado (ignora owner_id vindo de fora)
|
||||
*
|
||||
* Observação:
|
||||
* - Para admin/secretária criar para outros owners, o ideal é ter uma função separada
|
||||
* (ex.: createClinicAgendaEvento) que permita owner_id explicitamente.
|
||||
* Por enquanto, deixo esta função como "safe default" para terapeuta.
|
||||
*/
|
||||
export async function createAgendaEvento (payload) {
|
||||
const uid = await getUid()
|
||||
const tenantStore = useTenantStore()
|
||||
const tenantId = tenantStore.activeTenantId
|
||||
assertValidTenantId(tenantId)
|
||||
|
||||
if (!payload) throw new Error('Payload vazio.')
|
||||
|
||||
const insertPayload = {
|
||||
...payload,
|
||||
tenant_id: tenantId,
|
||||
owner_id: uid
|
||||
}
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('agenda_eventos')
|
||||
.insert(payload)
|
||||
.insert(insertPayload)
|
||||
.select('*')
|
||||
.single()
|
||||
|
||||
@@ -75,11 +134,24 @@ export async function createAgendaEvento (payload) {
|
||||
return data
|
||||
}
|
||||
|
||||
export async function updateAgendaEvento (id, patch) {
|
||||
/**
|
||||
* Atualização segura:
|
||||
* - filtra por id + tenant_id (evita update cruzado por acidente)
|
||||
* RLS deve reforçar isso no banco.
|
||||
*/
|
||||
export async function updateAgendaEvento (id, patch, { tenantId: tenantIdArg } = {}) {
|
||||
if (!id) throw new Error('ID inválido.')
|
||||
if (!patch) throw new Error('Patch vazio.')
|
||||
|
||||
const tenantStore = useTenantStore()
|
||||
const tenantId = tenantIdArg || tenantStore.activeTenantId
|
||||
assertValidTenantId(tenantId)
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('agenda_eventos')
|
||||
.update(patch)
|
||||
.eq('id', id)
|
||||
.eq('tenant_id', tenantId)
|
||||
.select('*')
|
||||
.single()
|
||||
|
||||
@@ -87,12 +159,61 @@ export async function updateAgendaEvento (id, patch) {
|
||||
return data
|
||||
}
|
||||
|
||||
export async function deleteAgendaEvento (id) {
|
||||
/**
|
||||
* Delete seguro:
|
||||
* - filtra por id + tenant_id
|
||||
*/
|
||||
export async function deleteAgendaEvento (id, { tenantId: tenantIdArg } = {}) {
|
||||
if (!id) throw new Error('ID inválido.')
|
||||
|
||||
const tenantStore = useTenantStore()
|
||||
const tenantId = tenantIdArg || tenantStore.activeTenantId
|
||||
assertValidTenantId(tenantId)
|
||||
|
||||
const { error } = await supabase
|
||||
.from('agenda_eventos')
|
||||
.delete()
|
||||
.eq('id', id)
|
||||
.eq('tenant_id', tenantId)
|
||||
|
||||
if (error) throw error
|
||||
return true
|
||||
}
|
||||
|
||||
// Adicione no mesmo arquivo: src/features/agenda/services/agendaRepository.js
|
||||
|
||||
/**
|
||||
* Criação para a área da clínica (admin/secretária):
|
||||
* - exige tenantId explícito (ou cai no tenantStore)
|
||||
* - 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: tenantIdArg } = {}) {
|
||||
const tenantStore = useTenantStore()
|
||||
const tenantId = tenantIdArg || tenantStore.activeTenantId
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user