Files
agenciapsilmno/src/features/notices/noticeService.js
T
Leonardo ee2967a075 M6: notices/conversations foundation — selects + repositories
Modulo 6 da Fase 1. noticesSelects.js extrai os 2 selects do
noticeService (GLOBAL_NOTICE_SELECT, NOTICE_DISMISSAL_SELECT) +
noticeService passa a usa-los (zero select inline). Conversations
ganha foundation: 3 services (_tenantGuards, conversationsSelects,
conversationsRepository). Channel factory (WhatsApp/SMS/Email) e
composables ficam pra sessao dedicada — escopo M6 era so destravar
o supabase.from() inline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 04:20:42 -03:00

118 lines
4.0 KiB
JavaScript

/*
|--------------------------------------------------------------------------
| 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 });
}