first commit

This commit is contained in:
Leonardo
2026-02-18 22:36:45 -03:00
parent ec6b6ef53a
commit 676042268b
122 changed files with 26354 additions and 1615 deletions
+173
View File
@@ -0,0 +1,173 @@
// src/services/patientGroups.js
import { supabase } from '@/lib/supabase/client'
function pickCount (row) {
return row?.patients_count ?? row?.patient_count ?? 0
}
async function getOwnerId () {
const { data, error } = await supabase.auth.getUser()
if (error) throw error
const uid = data?.user?.id
if (!uid) throw new Error('Sessão inválida.')
return uid
}
function normalizeNome (s) {
return String(s || '').trim().toLowerCase().replace(/\s+/g, ' ')
}
function isUniqueViolation (err) {
if (!err) return false
if (err.code === '23505') return true
const msg = String(err.message || '')
return /duplicate key value violates unique constraint/i.test(msg)
}
/**
* Lista grupos do usuário + grupos do sistema, já com contagem.
* Usa a view v_patient_groups_with_counts (preferencial).
* Fallback: tabela patient_groups + contagem pela pivot.
*/
export async function listGroupsWithCounts () {
const ownerId = await getOwnerId()
// 1) View (preferencial) — agora já é a fonte correta
const { data: vData, error: vErr } = await supabase
.from('v_patient_groups_with_counts')
.select('*')
.or(`owner_id.eq.${ownerId},is_system.eq.true`)
.order('nome', { ascending: true })
if (!vErr) {
return (vData || []).map(r => ({
...r,
patients_count: pickCount(r)
}))
}
// 2) Fallback (caso view não exista / erro de schema)
const { data: groups, error: gErr } = await supabase
.from('patient_groups')
.select('id,nome,cor,is_system,is_active,owner_id,created_at,updated_at')
.or(`owner_id.eq.${ownerId},is_system.eq.true`)
.order('nome', { ascending: true })
if (gErr) throw gErr
const ids = (groups || []).map(g => g.id).filter(Boolean)
if (!ids.length) return []
// conta pacientes por grupo na pivot
const { data: rel, error: rErr } = await supabase
.from('patient_group_patient')
.select('patient_group_id')
.in('patient_group_id', ids)
if (rErr) throw rErr
const counts = new Map()
for (const row of rel || []) {
const gid = row.patient_group_id
if (!gid) continue
counts.set(gid, (counts.get(gid) || 0) + 1)
}
return (groups || []).map(g => ({
...g,
patients_count: counts.get(g.id) || 0
}))
}
export async function createGroup (nome, cor = null) {
const ownerId = await getOwnerId()
const raw = String(nome || '').trim()
if (!raw) throw new Error('Nome do grupo é obrigatório.')
const nNorm = normalizeNome(raw)
// proteção extra no front: busca por igualdade "normalizada"
// (mantém RLS como autoridade final, mas evita UX ruim)
const { data: existing, error: exErr } = await supabase
.from('patient_groups')
.select('id,nome')
.eq('owner_id', ownerId)
.eq('is_system', false)
.limit(50)
if (!exErr && (existing || []).some(r => normalizeNome(r.nome) === nNorm)) {
throw new Error('Já existe um grupo com esse nome.')
}
const payload = {
owner_id: ownerId,
nome: raw,
cor: cor || null
}
const { data, error } = await supabase
.from('patient_groups')
.insert(payload)
.select('id,nome,cor,is_system,owner_id,is_active,created_at,updated_at')
.single()
if (error) {
if (isUniqueViolation(error)) throw new Error('Já existe um grupo com esse nome.')
throw error
}
return data
}
export async function updateGroup (id, nome, cor = null) {
const ownerId = await getOwnerId()
const raw = String(nome || '').trim()
if (!id) throw new Error('ID inválido.')
if (!raw) throw new Error('Nome do grupo é obrigatório.')
// (opcional) valida duplicidade entre os grupos do owner (não-system)
const nNorm = normalizeNome(raw)
const { data: existing, error: exErr } = await supabase
.from('patient_groups')
.select('id,nome')
.eq('owner_id', ownerId)
.eq('is_system', false)
.neq('id', id)
.limit(80)
if (!exErr && (existing || []).some(r => normalizeNome(r.nome) === nNorm)) {
throw new Error('Já existe um grupo com esse nome.')
}
const { data, error } = await supabase
.from('patient_groups')
.update({ nome: raw, cor: cor || null, updated_at: new Date().toISOString() })
.eq('id', id)
.eq('owner_id', ownerId)
.eq('is_system', false)
.select('id,nome,cor,is_system,owner_id,is_active,created_at,updated_at')
.single()
if (error) {
if (isUniqueViolation(error)) throw new Error('Já existe um grupo com esse nome.')
throw error
}
return data
}
export async function deleteGroup (id) {
const ownerId = await getOwnerId()
if (!id) throw new Error('ID inválido.')
const { error } = await supabase
.from('patient_groups')
.delete()
.eq('id', id)
.eq('owner_id', ownerId)
.eq('is_system', false)
if (error) throw error
return true
}