/* |-------------------------------------------------------------------------- | Agência PSI |-------------------------------------------------------------------------- | Criado e desenvolvido por Leonardo Nohama | | Tecnologia aplicada à escuta. | Estrutura para o cuidado. | | Arquivo: src/composables/useFeriados.js | Data: 2026 | Local: São Carlos/SP — Brasil |-------------------------------------------------------------------------- | © 2026 — Todos os direitos reservados |-------------------------------------------------------------------------- */ import { ref, computed } from 'vue'; import { supabase } from '@/lib/supabase/client'; import { getFeriadosNacionais } from '@/utils/feriadosBR'; import { useMelissaCacheStore, MELISSA_CACHE_TTL } from '@/stores/melissaCacheStore'; // opts.cache (opt-in): habilita stale-while-revalidate via melissaCacheStore. // Default false pra preservar comportamento em páginas SaaS/admin que // editam feriados (esperam invalidação imediata após criar/remover). export function useFeriados(opts = {}) { const useCache = !!opts.cache; const cache = useCache ? useMelissaCacheStore() : null; const ano = ref(new Date().getFullYear()); const loading = ref(false); const municipais = ref([]); // linhas da tabela `feriados` // ── Nacionais (algoritmo, sem DB) ───────────────────────── const nacionais = computed(() => getFeriadosNacionais(ano.value).map((f) => ({ ...f, tipo: 'nacional' }))); // ── Todos juntos, ordenados por data ───────────────────── const todos = computed(() => [...nacionais.value, ...municipais.value.map((f) => ({ ...f, tipo: f.tipo || 'municipal' }))].sort((a, b) => a.data.localeCompare(b.data))); // ── Feriados de um mês (1–12) ───────────────────────────── function doMes(mes) { const m = String(mes).padStart(2, '0'); const prefix = `${ano.value}-${m}`; return todos.value.filter((f) => f.data.startsWith(prefix)); } // ── Próximos N dias ─────────────────────────────────────── function proximos(dias = 30) { const hoje = new Date(); const limite = new Date(hoje); limite.setDate(limite.getDate() + dias); const hojeISO = toISO(hoje); const limiteISO = toISO(limite); return todos.value.filter((f) => f.data >= hojeISO && f.data <= limiteISO); } function toISO(d) { return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; } async function _doFetch(tenantId, cacheKey) { const { data, error } = await supabase .from('feriados') .select('*') .or(`tenant_id.eq.${tenantId},tenant_id.is.null`) .gte('data', `${ano.value}-01-01`) .lte('data', `${ano.value}-12-31`) .order('data'); if (error) throw error; const rows = data || []; if (cache && cacheKey) cache.set('feriados', rows, cacheKey); municipais.value = rows; return rows; } // ── Load municipais do Supabase ─────────────────────────── async function load(tenantId, year) { if (year) ano.value = year; if (!tenantId) return; if (cache) { const cacheKey = `${tenantId}:${ano.value}`; const cached = cache.get('feriados', cacheKey, MELISSA_CACHE_TTL.feriados); if (cached) { municipais.value = cached; _doFetch(tenantId, cacheKey).catch((e) => { // eslint-disable-next-line no-console console.warn('[useFeriados] revalidate', e); }); return; } loading.value = true; try { await _doFetch(tenantId, cacheKey); } finally { loading.value = false; } return; } // Comportamento legado (sem cache) — páginas de admin que editam. loading.value = true; try { const { data, error } = await supabase .from('feriados') .select('*') .or(`tenant_id.eq.${tenantId},tenant_id.is.null`) .gte('data', `${ano.value}-01-01`) .lte('data', `${ano.value}-12-31`) .order('data'); if (error) throw error; municipais.value = data || []; } finally { loading.value = false; } } // ── Criar feriado municipal ─────────────────────────────── async function criar(payload) { const { data, error } = await supabase.from('feriados').insert(payload).select().single(); if (error) throw error; municipais.value = [...municipais.value, data].sort((a, b) => a.data.localeCompare(b.data)); if (cache) cache.invalidate('feriados'); return data; } // ── Remover feriado municipal ───────────────────────────── async function remover(id) { const { error } = await supabase.from('feriados').delete().eq('id', id); if (error) throw error; municipais.value = municipais.value.filter((f) => f.id !== id); if (cache) cache.invalidate('feriados'); } // ── Verificar duplicata ─────────────────────────────────── function isDuplicata(data, nome) { return todos.value.some((f) => f.data === data && f.nome.trim().toLowerCase() === nome.trim().toLowerCase()); } // ── Converter para eventos do FullCalendar (background) ── function toFcEvents(lista) { return lista.map((f) => ({ id: `feriado_${f.id || f.data}_${f.nome}`, title: f.nome, start: f.data, allDay: true, display: 'background', color: 'rgba(251, 191, 36, 0.25)', extendedProps: { _feriado: true, tipo: f.tipo } })); } const fcEvents = computed(() => toFcEvents(todos.value)); return { ano, loading, nacionais, municipais, todos, fcEvents, load, criar, remover, doMes, proximos, isDuplicata }; }