Melissa polish + Prontuario Visao Geral + agenda historico

Sprints B (05-03) e C (05-04) acumulados:

- NotificationDrawer/Item redesign (visual mais limpo, ações inline)
- Dock pins compose (useMelissaDockPins) + cache store global (melissaCacheStore)
- MelissaAgenda: timeline FullCalendar parity + cards resumo, histórico
  card com useMelissaAgendaHistorico, MelissaEventoPanel ajustado
- useFeriados: cache opt-in pra evitar fetch redundante de feriados
- PatientProntuario: aba Visão Geral nova; PatientConversationsTab polish
- AgendaClinicMosaic / AgendaTerapeutaPage / useAgendaSettings: ajustes
  de paridade com Melissa
- DocumentsListPage: pequenos ajustes
- DB migration 20260504000001: fix do trigger pra status 'excluido' nas
  cancel_notifications

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-06 09:11:55 -03:00
parent 86311ef305
commit 957e912a7f
19 changed files with 5203 additions and 285 deletions
@@ -16,20 +16,53 @@
*/
import { ref } from 'vue';
import { getMyAgendaSettings, getMyWorkSchedule } from '../services/agendaRepository';
import { useMelissaCacheStore, MELISSA_CACHE_TTL } from '@/stores/melissaCacheStore';
// opts.cache (opt-in): habilita stale-while-revalidate via melissaCacheStore.
// Default false pra preservar comportamento de páginas de configuração que
// editam settings/workRules (esperam ver mudança imediata após salvar).
export function useAgendaSettings(opts = {}) {
const useCache = !!opts.cache;
const cache = useCache ? useMelissaCacheStore() : null;
export function useAgendaSettings() {
const loading = ref(false);
const error = ref('');
const settings = ref(null);
const workRules = ref([]); // [{ dia_semana, hora_inicio, hora_fim }]
async function _doFetch() {
const [cfg, rules] = await Promise.all([getMyAgendaSettings(), getMyWorkSchedule()]);
settings.value = cfg;
workRules.value = rules;
if (cache) {
// Cache key inclui owner_id da config — invalida automaticamente
// se o usuário trocar (multi-tenant ou alternar entre staff).
const key = cfg?.owner_id || 'anon';
cache.set('agendaSettings', { settings: cfg, workRules: rules }, key);
}
return { settings: cfg, workRules: rules };
}
async function load() {
if (cache) {
// Sem owner_id ainda, key vira 'anon' — pega qualquer cache
// do mesmo escopo (que normalmente é o user logado).
const cached = cache.get('agendaSettings', undefined, MELISSA_CACHE_TTL.agendaSettings);
if (cached) {
settings.value = cached.settings;
workRules.value = cached.workRules;
_doFetch().catch((e) => {
// eslint-disable-next-line no-console
console.warn('[useAgendaSettings] revalidate', e);
});
return;
}
}
loading.value = true;
error.value = '';
try {
const [cfg, rules] = await Promise.all([getMyAgendaSettings(), getMyWorkSchedule()]);
settings.value = cfg;
workRules.value = rules;
await _doFetch();
} catch (e) {
error.value = e?.message || 'Falha ao carregar configurações da agenda.';
settings.value = null;