/* |-------------------------------------------------------------------------- | Agência PSI |-------------------------------------------------------------------------- | Criado e desenvolvido por Leonardo Nohama | | Tecnologia aplicada à escuta. | Estrutura para o cuidado. | | Arquivo: src/features/agenda/composables/useAgendaBloqueios.js | Data: 2026 | Local: São Carlos/SP — Brasil |-------------------------------------------------------------------------- | © 2026 — Todos os direitos reservados |-------------------------------------------------------------------------- */ // useAgendaBloqueios // Carrega e expõe rows de public.agenda_bloqueios + computed de events // background pra renderizar no FullCalendar (cinza). Usado pelos 3 layouts // da agenda (Melissa, Terapeuta/Rail, Clínica). // // Contrato: // - load(ownerId, rangeStart, rangeEnd) // carrega bloqueios cujo data_inicio esteja dentro do range OU que // sejam recorrentes (data_inicio pode estar em qualquer ponto, mas // o build de events filtra pra emitir só dentro do range visível) // - bloqueios ref(Array) // - loading ref(Bool) // - error ref(String) // - buildEventsForRange(rangeStart, rangeEnd) // wrapper sobre agendaMappers.buildBloqueioBackgroundEvents import { ref } from 'vue'; import { supabase } from '@/lib/supabase/client'; import { buildBloqueioBackgroundEvents } from '@/features/agenda/services/agendaMappers'; export function useAgendaBloqueios() { const bloqueios = ref([]); const loading = ref(false); const error = ref(''); // ownerIdOrIds: string (1 owner) ou Array (multi-owner, Clínica). async function load(ownerIdOrIds, rangeStart, rangeEnd) { if (!ownerIdOrIds) return; const ids = Array.isArray(ownerIdOrIds) ? ownerIdOrIds.filter(Boolean) : [ownerIdOrIds]; if (!ids.length) return; loading.value = true; error.value = ''; try { const isoStart = _toISODate(rangeStart); const isoEnd = _toISODate(rangeEnd); // Query: recorrentes (qualquer data) OU não-recorrentes com // data_inicio <= isoEnd e (data_fim ?? data_inicio) >= isoStart. // 2 queries simples + merge pra evitar string-building frágil. const baseNonRec = supabase .from('agenda_bloqueios') .select('*') .eq('recorrente', false) .lte('data_inicio', isoEnd) .or(`data_fim.gte.${isoStart},and(data_fim.is.null,data_inicio.gte.${isoStart})`); const baseRec = supabase .from('agenda_bloqueios') .select('*') .eq('recorrente', true); const [{ data: nonRec, error: e1 }, { data: rec, error: e2 }] = await Promise.all([ ids.length === 1 ? baseNonRec.eq('owner_id', ids[0]) : baseNonRec.in('owner_id', ids), ids.length === 1 ? baseRec.eq('owner_id', ids[0]) : baseRec.in('owner_id', ids) ]); if (e1) throw e1; if (e2) throw e2; bloqueios.value = [...(nonRec || []), ...(rec || [])]; } catch (e) { error.value = e?.message || 'Falha ao carregar bloqueios.'; bloqueios.value = []; } finally { loading.value = false; } } function buildEventsForRange(rangeStart, rangeEnd) { return buildBloqueioBackgroundEvents(bloqueios.value, rangeStart, rangeEnd); } return { bloqueios, loading, error, load, buildEventsForRange }; } function _toISODate(d) { if (!d) return null; const dt = d instanceof Date ? d : new Date(d); const y = dt.getFullYear(); const m = String(dt.getMonth() + 1).padStart(2, '0'); const day = String(dt.getDate()).padStart(2, '0'); return `${y}-${m}-${day}`; }