/* |-------------------------------------------------------------------------- | Agência PSI |-------------------------------------------------------------------------- | Criado e desenvolvido por Leonardo Nohama | | Tecnologia aplicada à escuta. | Estrutura para o cuidado. | | Arquivo: src/features/notices/noticeService.js | Data: 2026 | Local: São Carlos/SP — Brasil |-------------------------------------------------------------------------- | © 2026 — Todos os direitos reservados |-------------------------------------------------------------------------- */ // Serviço central de acesso ao Supabase para Global Notices import { supabase } from '@/lib/supabase/client'; import { GLOBAL_NOTICE_SELECT, NOTICE_DISMISSAL_SELECT } from './noticesSelects'; // ── Leitura ──────────────────────────────────────────────────── /** * Busca todos os notices ativos e dentro do período de exibição. * A filtragem por role/context é feita no cliente (noticeStore) * para evitar lógica de array no PostgREST. */ export async function fetchActiveNotices() { const now = new Date().toISOString(); const { data, error } = await supabase.from('global_notices').select(GLOBAL_NOTICE_SELECT).eq('is_active', true).or(`starts_at.is.null,starts_at.lte.${now}`).or(`ends_at.is.null,ends_at.gte.${now}`).order('priority', { ascending: false }); if (error) throw error; return data || []; } /** * Busca todos os notices (sem filtro de ativo) — para o painel admin. */ export async function fetchAllNotices() { const { data, error } = await supabase.from('global_notices').select(GLOBAL_NOTICE_SELECT).order('priority', { ascending: false }).order('created_at', { ascending: false }); if (error) throw error; return data || []; } // ── Tracking ─────────────────────────────────────────────────── export async function trackView(noticeId) { try { await supabase.rpc('notice_track_view', { p_notice_id: noticeId }); } catch { /* silencioso — tracking não deve quebrar o app */ } } export async function trackClick(noticeId) { try { await supabase.rpc('notice_track_click', { p_notice_id: noticeId }); } catch {} } // ── Dismiss scope: 'user' (persiste no banco) ───────────────── export async function saveDismissal(noticeId, version) { const { data: { user } } = await supabase.auth.getUser(); if (!user?.id) return; await supabase.from('notice_dismissals').upsert({ notice_id: noticeId, user_id: user.id, version }, { onConflict: 'notice_id,user_id' }); } export async function loadUserDismissals() { const { data: { user } } = await supabase.auth.getUser(); if (!user?.id) return []; const { data } = await supabase.from('notice_dismissals').select(NOTICE_DISMISSAL_SELECT).eq('user_id', user.id); return data || []; } // ── Admin CRUD ───────────────────────────────────────────────── export async function createNotice(payload) { const { data: { user } } = await supabase.auth.getUser(); const { data, error } = await supabase .from('global_notices') .insert({ ...payload, created_by: user?.id }) .select() .single(); if (error) throw error; return data; } export async function updateNotice(id, payload) { const { data, error } = await supabase.from('global_notices').update(payload).eq('id', id).select().single(); if (error) throw error; return data; } export async function deleteNotice(id) { const { error } = await supabase.from('global_notices').delete().eq('id', id); if (error) throw error; } export async function toggleNoticeActive(id, isActive) { return updateNotice(id, { is_active: isActive }); }