diff --git a/src/layout/melissa/MelissaCronometro.vue b/src/layout/melissa/MelissaCronometro.vue index 847c991..2b11c02 100644 --- a/src/layout/melissa/MelissaCronometro.vue +++ b/src/layout/melissa/MelissaCronometro.vue @@ -112,6 +112,8 @@ function toggle() { if (timer) clearInterval(timer); timer = null; running.value = false; + // Zera ao parar — sessão acabou, deixa pronto pra próxima + seconds.value = props.duracaoMinutos * 60; } else { if (timer) clearInterval(timer); timer = setInterval(() => { diff --git a/src/layout/melissa/MelissaLayout.vue b/src/layout/melissa/MelissaLayout.vue index eb8f3c0..eafa16c 100644 --- a/src/layout/melissa/MelissaLayout.vue +++ b/src/layout/melissa/MelissaLayout.vue @@ -15,6 +15,7 @@ * Rota atual (sandbox): /preview/melissa */ import { ref, computed, watch, onMounted, onBeforeUnmount, provide } from 'vue'; +import { useRouter, useRoute } from 'vue-router'; import { useToast } from 'primevue/usetoast'; import { useLayout } from '@/layout/composables/layout'; import { applyThemeEngine } from '@/theme/theme.options'; @@ -91,16 +92,26 @@ const SECOES = { medicos: { label: 'Médicos e referências', icon: 'pi pi-user-edit', descricao: 'Profissionais que encaminham ou recebem pacientes.' } }; -const secaoAberta = ref(null); // chave em SECOES, ou null +// Seção ativa = param `:secao?` da rota. URL é a fonte da verdade pra +// permitir back/forward e deep-link (ex: /preview/melissa/agenda abre o +// overlay da agenda direto). Se a chave for inválida, vira null. +const router = useRouter(); +const route = useRoute(); +const secaoAberta = computed(() => { + const s = route.params?.secao; + return s && SECOES[s] ? s : null; +}); function abrirSecao(key) { // Fecha overlays paralelos pra evitar empilhamento workspaceOpen.value = false; eventoSelecionado.value = null; - secaoAberta.value = key; + if (key === secaoAberta.value) return; // no-op, evita push duplicado + router.push({ name: 'PreviewMelissa', params: { secao: key } }); } function fecharSecao() { - secaoAberta.value = null; + if (!secaoAberta.value) return; + router.push({ name: 'PreviewMelissa', params: {} }); } // Prefs de layout/UI (toque, fundo, opacidade, formato hora) diff --git a/src/layout/melissa/MelissaPacientes.vue b/src/layout/melissa/MelissaPacientes.vue new file mode 100644 index 0000000..d55912a --- /dev/null +++ b/src/layout/melissa/MelissaPacientes.vue @@ -0,0 +1,1721 @@ + + + + + diff --git a/src/layout/melissa/composables/useMelissaPacientes.js b/src/layout/melissa/composables/useMelissaPacientes.js index bb92b44..fcff5e6 100644 --- a/src/layout/melissa/composables/useMelissaPacientes.js +++ b/src/layout/melissa/composables/useMelissaPacientes.js @@ -27,7 +27,16 @@ function normalizeStatus(s) { return v.charAt(0).toUpperCase() + v.slice(1); } -export function useMelissaPacientes() { +/** + * @param {object} [opts] + * @param {boolean} [opts.onlyActive=true] + * true (default, legado) = retorna só status='Ativo' (uso original: cards do + * resumo, cronômetro, eventos hoje — só faz sentido com ativos). + * false = retorna todos (Ativo + Inativo + Arquivado), pra páginas que + * precisam mostrar/filtrar por status (ex.: MelissaPacientes). + */ +export function useMelissaPacientes(opts = {}) { + const onlyActive = opts.onlyActive !== false; // default true (compat) const tenantStore = useTenantStore(); const pacientes = ref([]); @@ -66,7 +75,7 @@ export function useMelissaPacientes() { // ('ativo', 'Ativo', 'active', null...). Normaliza e filtra no client. const { data, error: err } = await supabase .from('patients') - .select('id, nome_completo, email_principal, telefone, status, avatar_url, last_attended_at, created_at') + .select('id, nome_completo, email_principal, telefone, status, avatar_url, last_attended_at, created_at, data_nascimento') .eq('owner_id', userId) .eq('tenant_id', tid) .order('nome_completo', { ascending: true }) @@ -82,10 +91,11 @@ export function useMelissaPacientes() { avatar_url: r.avatar_url || null, status: normalizeStatus(r.status), last_attended_at: r.last_attended_at || null, - created_at: r.created_at || null + created_at: r.created_at || null, + data_nascimento: r.data_nascimento || null })); - pacientes.value = todos.filter((p) => p.status === 'Ativo'); + pacientes.value = onlyActive ? todos.filter((p) => p.status === 'Ativo') : todos; } catch (e) { error.value = e?.message || 'Erro ao carregar pacientes'; pacientes.value = []; diff --git a/src/router/routes.misc.js b/src/router/routes.misc.js index 4d2ea03..ddae6e7 100644 --- a/src/router/routes.misc.js +++ b/src/router/routes.misc.js @@ -25,8 +25,11 @@ export default { // Sandbox do layout Melissa (Direção B — lockscreen-style) // Standalone, sem auth, sem AppLayout. Promovido de /preview/dashboard-win11. + // Param `:secao?` opcional reflete a seção aberta na URL (agenda, + // pacientes, conversas, etc.) — permite deep-link, back/forward, + // refresh preservando estado. { - path: 'preview/melissa', + path: 'preview/melissa/:secao?', name: 'PreviewMelissa', component: () => import('@/layout/melissa/MelissaLayout.vue') },