roadmap #11: recently viewed (ultimos 5 pacientes acessados)

ROADMAP item #1.3 #11. localStorage por user_id pra isolar sessoes
diferentes no mesmo browser. ROADMAP sugeria localStorage OU tabela
user_recent_access — escolhi localStorage por simplicidade (sem
migration adicional + zero round-trip por visita).

composables/useRecentPatients.js:
- useRecentPatients() — composable reativo Tipo A: items + hasItems
  + addVisit + remove + clear + refresh
- registerPatientVisit(patient) — helper stateless pra usar fora
  de setup (ex: navigation guards, action handlers)
- Sincroniza entre instancias na mesma aba via CustomEvent + 'storage'
- Max 5 items. Dedup por id, novo no topo.

Wire-up de visita (registra ao carregar prontuario):
- MelissaPaciente.vue: registerPatientVisit no loadAll apos detail.load
- PatientProntuario.vue: registerPatientVisit em loadDetail apos p resolved

Wire-up de visualizacao (mostra quando query vazia):
- GlobalSearch.vue: grupo "Acessados recentemente" antes dos Atalhos.
  goTo("recent") navega pra /therapist/patients/:id.
- MelissaBusca.vue: grupo "Acessados recentemente". emit('paciente')
  reusando a logica do MelissaLayout que ja navega pra
  /melissa/paciente?id=X.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-21 05:17:51 -03:00
parent e7a9bdab5f
commit 2dae4a11ae
5 changed files with 248 additions and 0 deletions
@@ -32,6 +32,7 @@ import { useConversationDrawerStore } from '@/stores/conversationDrawerStore';
import DocumentsListPage from '@/features/documents/DocumentsListPage.vue';
import PatientConversationsTab from './PatientConversationsTab.vue';
import { registerPatientVisit } from '@/composables/useRecentPatients';
// ── PROPS / EMITS ──────────────────────────────────────────────
const props = defineProps({
@@ -934,6 +935,8 @@ async function loadDetail(id) {
const [p, rel] = await Promise.all([getPatientById(id), getPatientRelations(id)]);
if (!p) throw new Error('Paciente não retornou dados (RLS bloqueando ou ID não existe no banco).');
patientFull.value = p;
// Registra no "recentemente acessados" (localStorage)
try { await registerPatientVisit(p); } catch { /* ignore */ }
const [g, t] = await Promise.all([
getGroupsByIds(rel.groupIds || []),
getTagsByIds(rel.tagIds || []),