MelissaPaciente Fase 8: wire-up final (Dialog -> route /melissa/paciente?id=X)
PLANO DE 8 FASES COMPLETO. Os 2 callsites Melissa do PatientProntuario.vue
legacy (3593L Dialog) trocam por navegacao pra MelissaPaciente nativo via
router.push. PatientProntuario continua intocado pros 2 callsites legacy
fora do Melissa (TherapistDashboard, PatientsListPage).
MELISSAPACIENTE.VUE — wire-up interno
- Imports: useRouter + useConversationDrawerStore
- close(): emit + router.push('/melissa/pacientes')
- editPatient(): emit + router.push('/melissa/pacientes', query: {edit: id})
pra MelissaPacientes auto-abrir o cadastroFullDialog
- openWhatsapp(): emit + conversationDrawerStore.openForPatient({id, name,
phone, avatar_url}) — drawer global desce sobre Melissa
- addFinancial(): emit + toast "Em breve" (Fase 9 — dialog inline)
MELISSAPACIENTES.VUE
- Removeu import PatientProntuario + refs prontuarioOpen/prontuarioPatient
- Removeu <PatientProntuario> template (substituido por comentario)
- abrirProntuario(p): router.push('/melissa/paciente', query: {id})
- onMounted detecta route.query.edit -> abre cadastroFullDialog +
router.replace pra limpar query (handshake com MelissaPaciente)
- Comentario header atualizado
MELISSAAGENDA.VUE
- Removeu import PatientProntuario + refs prontuarioOpen/prontuarioPatient
- Removeu <PatientProntuario> template
- abrirProntuarioPorId(id): router.push pra rota Melissa nativa
- abrirProntuarioPaciente / openProntuario / kebab "Prontuario" delegam
pra abrirProntuarioPorId
MELISSALAYOUT.VUE
- Render <MelissaPaciente> simplificado: so @close="fecharSecao".
Acoes edit/open-whatsapp/add-financial ficam internas.
ESLint: 0 errors da minha mudanca (9 pre-existentes nos arquivos tocados
sao baseline; confirmados via git stash — mesmos errors em ambos lados).
PLANO COMPLETO. Total de 8 commits no branch (Fases 1-8). MelissaPaciente.vue
~2400L + 5 composables (~407L) + utils ~280L. PatientProntuario.vue
intocado pra fallback legacy (TherapistDashboard, PatientsListPage).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -50,6 +50,61 @@ Touched: none
|
||||
## [2026-05-08 00:00] session | Melissa cfg-* nativas + temas + cronometro DB
|
||||
Touched: none
|
||||
|
||||
## [2026-05-08 19:30] session | MelissaPaciente Fase 8 — wire-up final (Dialog -> route)
|
||||
Touched: none
|
||||
Detalhes: PLANO DE 8 FASES COMPLETO. Os 2 callsites Melissa do
|
||||
PatientProntuario.vue legacy (3593L Dialog) trocam por router.push pra
|
||||
/melissa/paciente?id=X. PatientProntuario continua intocado pros 2
|
||||
callsites legacy (TherapistDashboard, PatientsListPage) quando user nao
|
||||
esta no layout Melissa.
|
||||
|
||||
MELISSAPACIENTE.VUE — wire-up
|
||||
- useRouter + useConversationDrawerStore.
|
||||
- close(): emit + router.push('/melissa/pacientes') (volta pra lista).
|
||||
- editPatient(): emit + router.push('/melissa/pacientes', query: {edit: id})
|
||||
pra MelissaPacientes detectar e abrir o cadastroFullDialog automaticamente.
|
||||
- openWhatsapp(): emit + conversationDrawerStore.openForPatient({id, name,
|
||||
phone, avatar_url}) — drawer global desce sobre Melissa sem fechar.
|
||||
- addFinancial(): emit + toast "Em breve" (Fase 9 — dialog inline).
|
||||
|
||||
MELISSAPACIENTES.VUE — wire-up
|
||||
- Removeu import PatientProntuario, refs prontuarioOpen/prontuarioPatient,
|
||||
template PatientProntuario.
|
||||
- abrirProntuario(p): router.push('/melissa/paciente', query: {id}).
|
||||
- onMounted: detecta route.query.edit -> abre cadastroFullDialog +
|
||||
router.replace pra limpar a query. Permite navegacao MelissaPaciente
|
||||
-> MelissaPacientes?edit=X -> auto-open do cadastro.
|
||||
- Comentario header atualizado.
|
||||
|
||||
MELISSAAGENDA.VUE — wire-up
|
||||
- Removeu import PatientProntuario, refs prontuarioOpen/prontuarioPatient,
|
||||
template PatientProntuario.
|
||||
- abrirProntuarioPorId(id): router.push('/melissa/paciente', query: {id}).
|
||||
- abrirProntuarioPaciente() / openProntuario(patient) / item kebab
|
||||
"Prontuario" todos delegam pra abrirProntuarioPorId.
|
||||
|
||||
MELISSALAYOUT.VUE
|
||||
- Render do <MelissaPaciente> simplificado: so passa @close="fecharSecao".
|
||||
Acoes edit/open-whatsapp/add-financial agora ficam internas no MelissaPaciente.
|
||||
|
||||
ESLint: 0 errors da minha mudanca (9 errors pre-existentes nos arquivos
|
||||
tocados, mesmos de antes do diff — confirmados via git stash baseline).
|
||||
|
||||
PLANO COMPLETO. Status final por fase:
|
||||
1. Foundation (composables + skeleton) — done (Fase 1)
|
||||
2. Tab Visao Geral (KPIs ricos + timeline + msgs) — done (Fase 2)
|
||||
3. Tab Perfil (6 sections stacked + anchors) — done (Fase 3)
|
||||
4. Tab Prontuario MVP (evolucao via observacoes) — done (Fase 4)
|
||||
5. Tab Agenda (KPIs + filtros + grupos + acoes) — done (Fase 5)
|
||||
6. Tab Financeiro (KPIs + tabela + mark paid) — done (Fase 6)
|
||||
7. Tabs Documentos + Conversas (KPIs + embeds) — done (Fase 7)
|
||||
8. Wire-up final (Dialog -> route) — done (Fase 8)
|
||||
|
||||
PatientProntuario.vue (3593L) NAO foi deletado — continua usado pelo
|
||||
TherapistDashboard.vue (homepage do role therapist) e PatientsListPage.vue
|
||||
(rota /therapist/patients fora do Melissa). Quando user troca pra Melissa
|
||||
em /account/profile, ele ve a versao nativa (MelissaPaciente).
|
||||
|
||||
## [2026-05-08 18:30] session | MelissaPaciente Fase 7 — Tabs Documentos + Conversas
|
||||
Touched: none
|
||||
Detalhes: Duas tabs entregues numa sessao (sao mais leves: KPIs + embed
|
||||
|
||||
@@ -34,7 +34,6 @@ import MelissaAgendaSearchPopover from './MelissaAgendaSearchPopover.vue';
|
||||
import MelissaAgendaActionsPopover from './MelissaAgendaActionsPopover.vue';
|
||||
import PatientCadastroDialog from '@/components/ui/PatientCadastroDialog.vue';
|
||||
import ComponentCadastroRapido from '@/components/ComponentCadastroRapido.vue';
|
||||
import PatientProntuario from '@/features/patients/prontuario/PatientProntuario.vue';
|
||||
import { useConversationDrawerStore } from '@/stores/conversationDrawerStore';
|
||||
import { getSessionCounts } from '@/features/patients/services/patientsRepository';
|
||||
// `Menu` PrimeVue: NÃO importar explicitamente — projeto usa auto-import
|
||||
@@ -234,13 +233,9 @@ function pacienteRowDblclick(id) {
|
||||
abrirProntuarioPorId(id);
|
||||
}
|
||||
function abrirProntuarioPorId(id) {
|
||||
const p =
|
||||
props.pacientes.find((x) => x.id === id) ||
|
||||
pacientesAside.value.find((x) => x.id === id) ||
|
||||
null;
|
||||
if (!p) return;
|
||||
prontuarioPatient.value = { ...p };
|
||||
prontuarioOpen.value = true;
|
||||
if (!id) return;
|
||||
// Fase 8 wire-up: navega pra MelissaPaciente nativo.
|
||||
router.push({ path: '/melissa/paciente', query: { id: String(id) } });
|
||||
}
|
||||
|
||||
// ── Calendar (FullCalendar) ───────────────────────────────────
|
||||
@@ -992,8 +987,6 @@ function onPatientCreated() {
|
||||
// Pattern espelha PatientsListPage (goEdit/goConversation/openProntuario).
|
||||
// Aparece no .melissa-dock via Teleport quando há paciente selecionado.
|
||||
const conversationDrawerStore = useConversationDrawerStore();
|
||||
const prontuarioOpen = ref(false);
|
||||
const prontuarioPatient = ref(null);
|
||||
const sessionCountsMap = ref(new Map()); // id → count (cache)
|
||||
|
||||
// Cache pra patients carregados sob demanda — quando o pacienteSelecionadoId
|
||||
@@ -1169,9 +1162,8 @@ function abrirWhatsappPaciente() {
|
||||
}
|
||||
function abrirProntuarioPaciente() {
|
||||
const p = pacienteSelecionado.value;
|
||||
if (!p) return;
|
||||
prontuarioPatient.value = { ...p };
|
||||
prontuarioOpen.value = true;
|
||||
if (!p?.id) return;
|
||||
abrirProntuarioPorId(p.id);
|
||||
}
|
||||
// API pública pra MelissaLayout chamar via ref (botão "Editar paciente"
|
||||
// do MelissaEventoPanel). Abre o PatientCadastroDialog já no modo edição.
|
||||
@@ -1211,7 +1203,7 @@ const kebabItems = computed(() => {
|
||||
return [
|
||||
{ label: 'Sessões', icon: 'pi pi-history', command: () => { pacienteSelecionadoId.value = p.id; abrirSessoesPaciente(); } },
|
||||
{ label: 'WhatsApp', icon: 'pi pi-whatsapp', command: () => conversationDrawerStore.openForPatient(String(p.id)) },
|
||||
{ label: 'Prontuário', icon: 'pi pi-file', command: () => { prontuarioPatient.value = { ...p }; prontuarioOpen.value = true; } },
|
||||
{ label: 'Prontuário', icon: 'pi pi-file', command: () => abrirProntuarioPorId(p.id) },
|
||||
{ label: 'Editar', icon: 'pi pi-pencil', command: () => { editPatientId.value = String(p.id); cadastroFullDialog.value = true; } }
|
||||
];
|
||||
});
|
||||
@@ -1220,9 +1212,8 @@ const kebabItems = computed(() => {
|
||||
// MelissaEventoPanel emite ações que o parent precisa orquestrar com
|
||||
// a Agenda — aqui ficam os métodos invocáveis via ref.
|
||||
function openProntuario(patient) {
|
||||
if (!patient) return;
|
||||
prontuarioPatient.value = { ...patient };
|
||||
prontuarioOpen.value = true;
|
||||
if (!patient?.id) return;
|
||||
abrirProntuarioPorId(patient.id);
|
||||
}
|
||||
defineExpose({
|
||||
refetch: refetchEventosFc,
|
||||
@@ -1905,17 +1896,9 @@ defineExpose({
|
||||
<!-- Menu kebab (mobile) — abre via toggleKebab a partir de qualquer .ma-pat -->
|
||||
<Menu ref="kebabMenu" :model="kebabItems" popup append-to="body" />
|
||||
|
||||
<!-- Dialog Prontuário — reaproveita componente do PatientsListPage.
|
||||
:key força re-mount quando troca de paciente. Optional chain
|
||||
em prontuarioPatient pra blindar contra bloco-tree opt do Vue. -->
|
||||
<PatientProntuario
|
||||
v-if="prontuarioPatient"
|
||||
:key="prontuarioPatient?.id || 'none'"
|
||||
v-model="prontuarioOpen"
|
||||
:patient="prontuarioPatient"
|
||||
@close="prontuarioOpen = false"
|
||||
@edit="(id) => { prontuarioOpen = false; editPatientId = String(id); cadastroFullDialog = true; }"
|
||||
/>
|
||||
<!-- Prontuario migrado pra MelissaPaciente nativo (Fase 8 wire-up).
|
||||
abrirProntuarioPorId(id) navega pra /melissa/paciente?id=X. -->
|
||||
|
||||
</section>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1865,15 +1865,14 @@ function onKeydown(e) {
|
||||
@close="fecharSecao"
|
||||
/>
|
||||
|
||||
<!-- Pagina nativa do prontuario do paciente (Fase 1 foundation).
|
||||
ID vem via route.query.id (?id=xxx). Quando ID muda, MelissaPaciente
|
||||
refetcha tudo via composables (usePatientDetail/Sessions/etc). -->
|
||||
<!-- Pagina nativa do prontuario do paciente (Fase 8 wire-up).
|
||||
ID vem via route.query.id (?id=xxx). MelissaPaciente cuida
|
||||
internamente das acoes (close -> /melissa/pacientes; edit ->
|
||||
/melissa/pacientes?edit=<id>; open-whatsapp -> conversationDrawerStore). -->
|
||||
<MelissaPaciente
|
||||
v-if="layoutReady && secaoAberta === 'paciente'"
|
||||
:patient-id="String(route.query.id || '')"
|
||||
@close="fecharSecao"
|
||||
@edit="(id) => fecharSecao()"
|
||||
@open-whatsapp="(id) => fecharSecao()"
|
||||
/>
|
||||
|
||||
<MelissaPlano
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
* Prefixo CSS: .mpa-* (Melissa PAciente).
|
||||
*/
|
||||
import { ref, computed, watch, nextTick, onMounted, onBeforeUnmount } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
import { useConversationDrawerStore } from '@/stores/conversationDrawerStore';
|
||||
import MelissaConfigList from './MelissaConfigList.vue';
|
||||
import DocumentsListPage from '@/features/documents/DocumentsListPage.vue';
|
||||
import PatientConversationsTab from '@/features/patients/prontuario/PatientConversationsTab.vue';
|
||||
@@ -58,7 +60,9 @@ const props = defineProps({
|
||||
});
|
||||
const emit = defineEmits(['close', 'edit', 'add-financial', 'open-whatsapp']);
|
||||
|
||||
const router = useRouter();
|
||||
const toast = useToast();
|
||||
const conversationDrawerStore = useConversationDrawerStore();
|
||||
|
||||
// ── Composables de dados ───────────────────────────────────
|
||||
const detail = usePatientDetail();
|
||||
@@ -323,10 +327,55 @@ const kpiRealizadas = computed(() => sessionsHook.totalRealizadas.value);
|
||||
const kpiMensagens = computed(() => messagesHook.messages.value.length);
|
||||
|
||||
// ── Acoes ──────────────────────────────────────────────────
|
||||
function close() { emit('close'); }
|
||||
function editPatient() { emit('edit', props.patientId); }
|
||||
function addFinancial() { emit('add-financial', props.patientId); }
|
||||
function openWhatsapp() { emit('open-whatsapp', props.patientId); }
|
||||
// Volta pra lista de pacientes (preserva o estado de Melissa).
|
||||
function close() {
|
||||
emit('close');
|
||||
router.push('/melissa/pacientes');
|
||||
}
|
||||
|
||||
// Edit: navega pra /melissa/pacientes?edit=<id> e a propria
|
||||
// MelissaPacientes detecta esse query param e abre o cadastroFullDialog.
|
||||
function editPatient() {
|
||||
emit('edit', props.patientId);
|
||||
router.push({ path: '/melissa/pacientes', query: { edit: props.patientId } });
|
||||
}
|
||||
|
||||
// Open WhatsApp: usa o conversationDrawerStore global (mesmo padrao
|
||||
// que MelissaPacientes usa). O drawer desce sobre o Melissa sem fechar.
|
||||
function openWhatsapp() {
|
||||
emit('open-whatsapp', props.patientId);
|
||||
if (!props.patientId) return;
|
||||
const data = patientData.value || {};
|
||||
try {
|
||||
if (typeof conversationDrawerStore.openForPatient === 'function') {
|
||||
conversationDrawerStore.openForPatient({
|
||||
id: props.patientId,
|
||||
name: data.nome_completo || data.nome || '',
|
||||
phone: data.telefone || data.phone || '',
|
||||
avatar_url: data.avatar_url || data.avatar || ''
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: 'Falha ao abrir conversa',
|
||||
detail: e?.message || 'Erro ao abrir o drawer.',
|
||||
life: 3500
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add financial: por enquanto so emite. Futuro: dialog inline de
|
||||
// novo lancamento (Fase 9).
|
||||
function addFinancial() {
|
||||
emit('add-financial', props.patientId);
|
||||
toast.add({
|
||||
severity: 'info',
|
||||
summary: 'Em breve',
|
||||
detail: 'Dialog de novo lançamento será adicionado numa próxima sessão.',
|
||||
life: 3000
|
||||
});
|
||||
}
|
||||
|
||||
// ── Load data quando patientId muda ────────────────────────
|
||||
async function loadAll(id) {
|
||||
|
||||
@@ -18,13 +18,14 @@
|
||||
* e patient_patient_tag (via patientsRepository.listGroupsByPatient/Tags...)
|
||||
*
|
||||
* Integrações:
|
||||
* - PatientProntuario (overlay dialog) — abre via duplo-click no card ou
|
||||
* - MelissaPaciente (rota /melissa/paciente?id=X) — abre via duplo-click ou
|
||||
* botão "Abrir prontuário" da COL 3
|
||||
* - PatientCadastroDialog — cadastro completo / edição
|
||||
* - PatientCreatePopover + ComponentCadastroRapido — fluxo de novo paciente
|
||||
* - conversationDrawerStore — botão WhatsApp da COL 3
|
||||
*/
|
||||
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
import { useConfirm } from 'primevue/useconfirm';
|
||||
import { useMelissaPacientes } from './composables/useMelissaPacientes';
|
||||
@@ -40,7 +41,6 @@ import {
|
||||
softDeletePatient
|
||||
} from '@/features/patients/services/patientsRepository';
|
||||
import { usePatientLifecycle } from '@/composables/usePatientLifecycle';
|
||||
import PatientProntuario from '@/features/patients/prontuario/PatientProntuario.vue';
|
||||
import PatientCreatePopover from '@/components/ui/PatientCreatePopover.vue';
|
||||
import PatientCadastroDialog from '@/components/ui/PatientCadastroDialog.vue';
|
||||
import ComponentCadastroRapido from '@/components/ComponentCadastroRapido.vue';
|
||||
@@ -52,6 +52,8 @@ const emit = defineEmits(['close', 'patient-created', 'goto-agenda', 'goto-grupo
|
||||
const toast = useToast();
|
||||
const confirm = useConfirm();
|
||||
const tenantStore = useTenantStore();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const { reactivatePatient } = usePatientLifecycle();
|
||||
const conversationDrawerStore = useConversationDrawerStore();
|
||||
|
||||
@@ -284,6 +286,13 @@ onMounted(() => {
|
||||
isCompact.value = _mqCompact.matches;
|
||||
_mqCompact.addEventListener('change', _onMqCompactChange);
|
||||
}
|
||||
// Fase 8 wire-up: se navegou pra ca com ?edit=<id> (vindo do
|
||||
// MelissaPaciente), abre o cadastro full direto.
|
||||
if (route.query.edit) {
|
||||
editPatientId.value = String(route.query.edit);
|
||||
cadastroFullDialog.value = true;
|
||||
router.replace({ query: { ...route.query, edit: undefined } });
|
||||
}
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
if (_mqMobile) _mqMobile.removeEventListener('change', _onMqMobileChange);
|
||||
@@ -534,9 +543,6 @@ const cadastroFullDialog = ref(false);
|
||||
const quickDialog = ref(false);
|
||||
const editPatientId = ref(null);
|
||||
|
||||
const prontuarioOpen = ref(false);
|
||||
const prontuarioPatient = ref(null);
|
||||
|
||||
function openCreatePopover(e) {
|
||||
createPopoverRef.value?.toggle(e);
|
||||
}
|
||||
@@ -551,10 +557,12 @@ function onPatientCreated() {
|
||||
refetchTudo();
|
||||
}
|
||||
|
||||
// Abrir prontuario agora navega pra MelissaPaciente nativo (Fase 8 wire-up).
|
||||
// O Dialog PatientProntuario.vue legacy continua existindo pros 2 callsites
|
||||
// fora do Melissa (TherapistDashboard e PatientsListPage).
|
||||
function abrirProntuario(p) {
|
||||
if (!p) return;
|
||||
prontuarioPatient.value = { ...p };
|
||||
prontuarioOpen.value = true;
|
||||
if (!p?.id) return;
|
||||
router.push({ path: '/melissa/paciente', query: { id: String(p.id) } });
|
||||
}
|
||||
|
||||
function editarPaciente(p) {
|
||||
@@ -1349,15 +1357,9 @@ function sessaoStatusColor(s) {
|
||||
@created="onPatientCreated"
|
||||
/>
|
||||
|
||||
<!-- Dialog Prontuário — :key força re-mount quando troca de paciente -->
|
||||
<PatientProntuario
|
||||
v-if="prontuarioPatient"
|
||||
:key="prontuarioPatient?.id || 'none'"
|
||||
v-model="prontuarioOpen"
|
||||
:patient="prontuarioPatient"
|
||||
@close="prontuarioOpen = false"
|
||||
@edit="(id) => { prontuarioOpen = false; editPatientId = String(id); cadastroFullDialog = true; }"
|
||||
/>
|
||||
<!-- Prontuario migrado pra MelissaPaciente nativo (Fase 8 wire-up).
|
||||
abrirProntuario(p) navega pra /melissa/paciente?id=X via router. -->
|
||||
|
||||
|
||||
<!-- Dialog: Novo grupo (nome + cor) -->
|
||||
<Dialog
|
||||
|
||||
Reference in New Issue
Block a user