diff --git a/src/layout/melissa/MelissaAgenda.vue b/src/layout/melissa/MelissaAgenda.vue index 4b1ff5e..467fa23 100644 --- a/src/layout/melissa/MelissaAgenda.vue +++ b/src/layout/melissa/MelissaAgenda.vue @@ -22,6 +22,7 @@ import dayGridPlugin from '@fullcalendar/daygrid'; import listPlugin from '@fullcalendar/list'; import interactionPlugin from '@fullcalendar/interaction'; import ptBrLocale from '@fullcalendar/core/locales/pt-br'; +import { FC_TOUCH_DEFAULTS } from '@/features/agenda/utils/fcDefaults'; import { useMelissaEventosRange, useMelissaTodasSessoesPaciente } from './composables/useMelissaEventos'; import { MELISSA_AGENDA_KEY } from './composables/useMelissaAgenda'; import { useMelissaPacientesAside } from './composables/useMelissaPacientesAside'; @@ -244,7 +245,11 @@ const VIEW_MAP = { dia: 'timeGridDay', semana: 'timeGridWeek', mes: 'dayGridMonth', - lista: 'listWeek' + // listAll é view custom (configurada em fcOptions.views) — cobre 2 anos + // (1 ano antes + 1 ano depois de hoje). Substituiu listWeek que mostrava + // só 7 dias e escondia recorrências semanais/quinzenais futuras. Cap do + // loadAndExpand é 730d (MAX_RANGE_DAYS), 2 anos cai exatamente no limite. + lista: 'listAll' }; const fcRef = ref(null); @@ -384,6 +389,11 @@ const fcEvents = computed(() => { const evPid = ev.patient_id || ev.paciente_id; if (onlySess && !evPid) continue; if (pacienteId && evPid !== pacienteId) continue; + // Eventos cujo paciente foi arquivado/desativado ganham classe + // visual ("inativo") — borda tracejada + opacidade reduzida no CSS + // abaixo. Mantem a cor do commitment pra nao perder contexto. + const pStatus = ev.paciente_status; + const isInactivePatient = pStatus === 'Arquivado' || pStatus === 'Inativo'; out.push({ id: ev.id, title: ev.label, @@ -392,6 +402,7 @@ const fcEvents = computed(() => { backgroundColor: `${ev.color}26`, // ~15% opacity borderColor: ev.color, textColor: 'white', + classNames: isInactivePatient ? ['ma-evt--inactive-patient'] : undefined, extendedProps: ev }); } @@ -403,6 +414,19 @@ const fcEvents = computed(() => { return out; }); +// Hint pra trocar pra view 'lista' quando há ocorrências de recorrência +// visíveis em view dia/semana/mês. Cada view dessas cobre janela curta +// (1d / 7d / ~35d) — séries semanais com 4+ ocorrências sempre extrapolam. +// Lista cobre 2 anos centrada no usuário, então mostra passado/presente/futuro. +// Não mostra no modo "Ver todas" (já tá em modo lista paralela) nem na própria +// view lista. Some quando nenhum virtual aparece (sem recorrência ativa visível). +const showRecurrenceHint = computed(() => { + if (calendarView.value === 'lista') return false; + if (verTodasSessoes.value) return false; + if (!eventosSemana.value?.length) return false; + return eventosSemana.value.some((ev) => ev.is_occurrence); +}); + // ── slotMinTime / slotMaxTime baseado em timeMode ───────────── // 24: 00–24h. 12: 06–18h. my: range das workRules (snap em 30min). function _hhmmToMin(t) { @@ -492,11 +516,22 @@ function slotLabelContent(arg) { const fcOptions = computed(() => ({ plugins: [timeGridPlugin, dayGridPlugin, listPlugin, interactionPlugin], + ...FC_TOUCH_DEFAULTS, locale: ptBrLocale, headerToolbar: false, // toolbar é nossa (custom glass) initialView: VIEW_MAP[calendarView.value] || 'timeGridWeek', initialDate: refDate.value, nowIndicator: true, + // View custom "listAll": list view cobrindo 2 anos. Usada quando user clica + // o toggle "Lista" — exibe passadas + presentes + futuras numa varredura só. + // setView('lista') faz gotoDate(hoje - 1 ano) pra centrar. + views: { + listAll: { + type: 'list', + duration: { years: 2 }, + buttonText: 'Lista' + } + }, // Drag/resize/select habilitam apenas com M (composable disponível) — // standalone (sem M) fica readonly por compat (preview puro). editable: !!M, @@ -696,6 +731,14 @@ function goToday() { fcApi()?.today(); } function setView(v) { calendarView.value = v; fcApi()?.changeView(VIEW_MAP[v]); + // Lista cobre 2 anos — abrimos centrado: pula pra (hoje - 1 ano) pra + // mostrar passado + presente + futuro de uma vez. Outras views mantém + // o refDate atual (datesSet sincroniza viewStart/End normalmente). + if (v === 'lista') { + const umAnoAtras = new Date(); + umAnoAtras.setFullYear(umAnoAtras.getFullYear() - 1); + fcApi()?.gotoDate(umAnoAtras); + } } // ── Menu de Bloqueio (toolbar) ───────────────────────────────── @@ -1574,16 +1617,21 @@ defineExpose({ @bloqueio="onActionsBloqueio" /> -