Melissa: deep-link via URL + Pacientes (WIP) + cronometro reset

Roteamento por URL (substitui o ref local secaoAberta):
- routes.misc.js: rota vira /preview/melissa/:secao? — param opcional
- MelissaLayout.vue: secaoAberta agora e computed do route.params.secao,
  validado contra SECOES (chave invalida -> null). abrirSecao/fecharSecao
  fazem router.push em vez de mutar ref. Habilita back/forward, refresh
  e deep-link tipo /preview/melissa/agenda.

Pagina Pacientes (WIP, ainda nao wireada no slot do Layout):
- src/layout/melissa/MelissaPacientes.vue (novo, ~? linhas) — fullscreen
  3-col espelhando MelissaAgenda: aside esquerda com filtros (status /
  grupos / tags), lista central com cards + busca, quick view direita
  com KPIs do paciente selecionado + acoes.
- Carrega pacientes (todos os status), grupos/tags do tenant, vinculos
  patient_groups + patient_tags + session counts em paralelo.
- Integra PatientProntuario (overlay), PatientCadastroDialog,
  PatientCreatePopover + ComponentCadastroRapido, e
  conversationDrawerStore (acao WhatsApp da quick view).

useMelissaPacientes ganha opcao { onlyActive }:
- default true (compat com cards do resumo / cronometro / eventos hoje
  — so faz sentido com ativos)
- false retorna Ativo + Inativo + Arquivado, pra uso na pagina nova
- select agora inclui data_nascimento (necessario pros KPIs da quick view)

Cronometro: zera ao parar — terminou a sessao, fica pronto pra proxima
sem precisar reabrir o popover.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-04-28 17:12:15 -03:00
parent 7b67bd083a
commit 06bce11e1c
5 changed files with 1755 additions and 8 deletions
@@ -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 = [];