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:
@@ -181,8 +181,15 @@ export function useMelissaAgenda() {
|
||||
);
|
||||
|
||||
// ── Settings + workRules ────────────────────────────────────
|
||||
const { settings, workRules, load: loadSettings } = useAgendaSettings();
|
||||
const ownerId = computed(() => settings.value?.owner_id || '');
|
||||
// cache: stale-while-revalidate via melissaCacheStore — abertura
|
||||
// subsequente da Agenda na mesma sessão usa cache instantâneo.
|
||||
const { settings, workRules, load: loadSettings } = useAgendaSettings({ cache: true });
|
||||
// _bootUid: pegado em paralelo no mount via supabase.auth.getUser().
|
||||
// Sem isso, ownerId ficava null até loadSettings completar (~300ms),
|
||||
// bloqueando o primeiro fetch dos eventos. Como owner_id da agenda
|
||||
// é literalmente o uid do user logado, podemos resolver imediato.
|
||||
const _bootUid = ref('');
|
||||
const ownerId = computed(() => settings.value?.owner_id || _bootUid.value || '');
|
||||
|
||||
// ── Eventos reais (CRUD) ────────────────────────────────────
|
||||
const {
|
||||
@@ -245,7 +252,16 @@ export function useMelissaAgenda() {
|
||||
});
|
||||
|
||||
// ── Feriados + commitment services ──────────────────────────
|
||||
const { todos: feriados, fcEvents: feriadoFcEvents, load: loadFeriadosBase } = useFeriados();
|
||||
// Instância única de useFeriados — antes MelissaAgenda.vue criava
|
||||
// sua própria também, fazendo dupla requisição de feriados municipais
|
||||
// toda vez que a agenda abria. Agora MelissaAgenda lê esses refs do
|
||||
// composable injetado (M.feriadosAno, M.loadFeriadosBase, etc).
|
||||
const {
|
||||
todos: feriados,
|
||||
fcEvents: feriadoFcEvents,
|
||||
load: loadFeriadosBase,
|
||||
ano: feriadosAno
|
||||
} = useFeriados({ cache: true });
|
||||
const { saveRuleItems, propagateToSerie } = useCommitmentServices();
|
||||
|
||||
// ── Linhas combinadas (real + virtual) ──────────────────────
|
||||
@@ -294,13 +310,18 @@ export function useMelissaAgenda() {
|
||||
const e = viewEnd.value;
|
||||
if (!s || !e) return;
|
||||
|
||||
// Aguarda ownerId — settings é async
|
||||
if (!ownerId.value) {
|
||||
const unwatch = watch(ownerId, async (v) => {
|
||||
if (!v) return;
|
||||
unwatch();
|
||||
await _reloadRange();
|
||||
});
|
||||
// Espera ownerId E tenant — qualquer um faltando significa boot
|
||||
// ainda em curso (auth/tenantStore/settings async). Watcher one-shot
|
||||
// re-dispara assim que o último ficar disponível, sem polling.
|
||||
if (!ownerId.value || !clinicTenantId.value) {
|
||||
const unwatch = watch(
|
||||
() => [ownerId.value, clinicTenantId.value],
|
||||
([uid, tid]) => {
|
||||
if (!uid || !tid) return;
|
||||
unwatch();
|
||||
_reloadRange();
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -308,9 +329,14 @@ export function useMelissaAgenda() {
|
||||
const end = new Date(e);
|
||||
const tid = clinicTenantId.value;
|
||||
|
||||
// Etapa 1: eventos reais — `rows` é reativo, FullCalendar re-renderiza
|
||||
// assim que esse await resolve (o user já vê as sessões agendadas).
|
||||
await loadMyRange(start.toISOString(), end.toISOString(), ownerId.value);
|
||||
|
||||
// Expande regras + merge com sessões reais
|
||||
// Etapa 2: ocorrências virtuais (regras de recorrência expandidas).
|
||||
// Continuamos awaitando porque saveRule/cancel dependem do estado
|
||||
// final estar pronto pra UI consistente, mas a janela visual onde
|
||||
// o usuário vê só eventos reais é a metade do tempo de antes.
|
||||
const merged = await loadAndExpand(ownerId.value, start, end, rows.value, tid);
|
||||
_occurrenceRows.value = merged.filter((r) => r.is_occurrence);
|
||||
}
|
||||
@@ -320,8 +346,37 @@ export function useMelissaAgenda() {
|
||||
}
|
||||
|
||||
// ── Inicialização ───────────────────────────────────────────
|
||||
onMounted(async () => {
|
||||
await loadSettings();
|
||||
// Boot paralelo: auth uid + tenant + settings todos disparam ao mesmo
|
||||
// tempo. Antes era serial (loadSettings precisava terminar pra ownerId
|
||||
// ficar disponível e o watch disparar _reloadRange) — adicionava ~300ms
|
||||
// de waterfall antes da primeira query de eventos sair.
|
||||
onMounted(() => {
|
||||
// 1) Resolve o uid o quanto antes — destrava _reloadRange.
|
||||
// getSession() lê do storage local (fast path, <10ms);
|
||||
// getUser() faria round-trip pro auth server. Fallback pro
|
||||
// getUser só se a sessão ainda não estiver no storage.
|
||||
supabase.auth.getSession()
|
||||
.then(({ data }) => {
|
||||
const uid = data?.session?.user?.id;
|
||||
if (uid) {
|
||||
_bootUid.value = uid;
|
||||
} else {
|
||||
// Cold start sem sessão hidratada — fallback pro round-trip.
|
||||
return supabase.auth.getUser().then(({ data: u }) => {
|
||||
if (u?.user?.id) _bootUid.value = u.user.id;
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => { /* noop — settings ainda pode resolver */ });
|
||||
|
||||
// 2) Garante que o tenant está hidratado (idempotente — se já
|
||||
// estiver carregado, retorna imediato).
|
||||
if (typeof tenantStore.ensureLoaded === 'function') {
|
||||
tenantStore.ensureLoaded().catch(() => {});
|
||||
}
|
||||
|
||||
// 3) Settings em paralelo (não bloqueia mais nada)
|
||||
loadSettings();
|
||||
});
|
||||
|
||||
// Refetch settings + workRules quando o user salva jornada/ritmo/online
|
||||
@@ -354,11 +409,10 @@ export function useMelissaAgenda() {
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// Reload quando view muda OU quando settings/ownerId aparece
|
||||
// Reload quando o range visível muda. _reloadRange já tem guard
|
||||
// interno pra esperar uid+tenant (one-shot watcher) — sem necessidade
|
||||
// de outro watch global em ownerId, que disparava _reloadRange duplicado.
|
||||
watch([viewStart, viewEnd], _reloadRange);
|
||||
watch(ownerId, (v) => {
|
||||
if (v) _reloadRange();
|
||||
});
|
||||
|
||||
// ──────────────────────────────────────────────────────────
|
||||
// Handlers — populados na Stage 2
|
||||
@@ -405,6 +459,8 @@ export function useMelissaAgenda() {
|
||||
commitmentOptions,
|
||||
feriados,
|
||||
feriadoFcEvents,
|
||||
feriadosAno,
|
||||
loadFeriadosBase,
|
||||
allEventsForDialog,
|
||||
|
||||
// Handlers
|
||||
|
||||
Reference in New Issue
Block a user