AgendaEventDialog: props lockType + lockPatient + slot #headerLeft (additivos)
User escolheu caminho A: modificar AgendaEventDialog em vez de copiar.
Mudancas SAO ADITIVAS — comportamento atual dos 5 callsites legacy
(TherapistDashboard, PatientsListPage, MelissaAgenda,
MelissaAgendamentosRecebidos, MelissaLayout) preservado.
VALIDACAO: rodei os 7 spec files do agenda — 301 testes passaram.
Zero regressao.
ADICIONADO em src/features/agenda/components/AgendaEventDialog.vue
- Prop lockType (Boolean, default false): pula step 1 (escolha de tipo)
e vai direto pro form. Watch immediate em [lockType, modelValue]
forca step.value=2 quando lockType=true e dialog abre.
- Prop lockPatient (Boolean, default false): esconde botoes "trocar"/
"limpar" do paciente. Mostra icon de lock com tooltip "Paciente do
prontuario". Cobre o cenario "criar sessao pra paciente fixo" sem
precisar do isEdit que o patientLocked computed exige.
- Slot #headerLeft: substitui o conteudo esquerdo do header (default
era header-dot + headerTitle + previewRange). Permite callsites
customizar com icon+title+subtitle proprios sem mexer no resto do
header (X / actions).
- v-if no Step 1: "step === 1 && !lockType"
- v-if nos buttons trocar/limpar: "!patientLocked && !lockPatient"
- Lock icon: "patientLocked || lockPatient" + tooltip dinamico
MELISSAPACIENTE.VUE
- Reverte o inject-only do commit 88dff50.
- Mantem o inject(MELISSA_AGENDA_KEY) APENAS pra LER dados pesados
(commitmentOptions, workRules, allEvents, agendaSettings, feriados,
ownerId, tenantId) — evita re-fetch.
- State LOCAL pro dialog: sessaoDialogOpen, sessaoDialogEventRow,
sessaoDialogStartISO, sessaoDialogEndISO. Nao colide com o dialog
global do MelissaLayout que continua na Agenda.
- goAgendar(): inicializa eventRow com paciente_id fixo + tipo='sessao'
+ defaults razoaveis (proximo slot 15min + duracao da agenda),
abre o dialog local.
- Handlers onSessaoDialogSave / onSessaoDialogDelete delegam pros
handlers globais (M.onDialogSave/Delete) e ao final refetcham
sessions+recorrencias do paciente in-place.
- Render <AgendaEventDialog> com lock-type=true + lock-patient=true
+ slot #headerLeft custom (icon pi-calendar-plus em quadrado
primary 40x40 + "Nova sessão" + nome do paciente como subtitulo).
Resultado: prontuario tem o MESMO componente da Agenda (form completo
de sessao, frequencia com preview de ocorrencias + conflitos,
vinculacao de servicos/billing, edicao de serie, etc) mas pre-fixado
no contexto do paciente, com header proprio e single source of truth.
ESLint: 31 errors pre-existentes em ambos arquivos (variaveis declaradas
nao usadas — confirmado via git stash baseline). 0 errors da minha
mudanca.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -105,7 +105,24 @@ const props = defineProps({
|
||||
feriados: { type: Array, default: () => [] },
|
||||
|
||||
// Rota para cadastro completo de paciente (abre em nova aba)
|
||||
newPatientRoute: { type: String, default: '' }
|
||||
newPatientRoute: { type: String, default: '' },
|
||||
|
||||
// ── Locks aditivos (default false — comportamento atual) ──────────
|
||||
// Usados pelo MelissaPaciente.vue pra abrir esse dialog ja em
|
||||
// contexto de Sessao + paciente fixo do prontuario. Os 5 callsites
|
||||
// existentes (TherapistDashboard, PatientsListPage, MelissaAgenda,
|
||||
// MelissaAgendamentosRecebidos, MelissaLayout) seguem com defaults.
|
||||
//
|
||||
// lockType=true: pula o step de escolha de tipo (commitment cards) e
|
||||
// vai direto pro form. Espera que eventRow ja venha com tipo+commitment
|
||||
// resolvidos (no MelissaPaciente: tipo='sessao').
|
||||
//
|
||||
// lockPatient=true: esconde os botoes "trocar"/"limpar" do paciente
|
||||
// e mostra o icon de lock (mesma UX do patientLocked computed que
|
||||
// ja existia pra modo edit, agora cobre tambem cenarios "criar sessao
|
||||
// pra paciente fixo").
|
||||
lockType: { type: Boolean, default: false },
|
||||
lockPatient: { type: Boolean, default: false }
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'save', 'delete', 'updateSeriesEvent', 'editSeriesOccurrence', 'updated']);
|
||||
@@ -176,6 +193,17 @@ const {
|
||||
resetForm
|
||||
} = _composer;
|
||||
|
||||
// Lock de tipo: quando lockType=true (callsite no contexto de Sessao do
|
||||
// paciente, ex: MelissaPaciente), pula o step 1 e vai direto pro form.
|
||||
// Watch immediate cobre tanto open quanto re-open com novo eventRow.
|
||||
watch(
|
||||
() => [props.lockType, props.modelValue],
|
||||
([locked, open]) => {
|
||||
if (locked && open) step.value = 2;
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// ── recorrência: opções estáticas (consts data — não migradas) ──
|
||||
const freqOpcoes = [
|
||||
{ value: 'avulsa', label: 'Avulsa' },
|
||||
@@ -718,13 +746,18 @@ const googleCalendarUrl = computed(() => {
|
||||
<Dialog v-model:visible="visible" modal :draggable="false" :dismissableMask="true" :style="{ width: '1000px', maxWidth: '96vw' }" :breakpoints="{ '960px': '96vw', '640px': '98vw' }" class="agenda-event-composer" pt:mask:class="backdrop-blur-xs">
|
||||
<template #header>
|
||||
<div class="w-full flex items-center justify-between gap-3">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<div class="header-dot shrink-0" :style="selectedCommitment?.bg_color ? { background: `#${selectedCommitment.bg_color}` } : {}" />
|
||||
<div class="min-w-0">
|
||||
<div class="font-semibold truncate text-base">{{ headerTitle }}</div>
|
||||
<div v-if="step === 2" class="text-xs text-color-secondary truncate">{{ previewRange }}</div>
|
||||
<!-- Slot headerLeft (override de chamadas como MelissaPaciente
|
||||
que precisam icon+title+subtitle custom). Default: dot
|
||||
colorido + headerTitle + previewRange. -->
|
||||
<slot name="headerLeft">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<div class="header-dot shrink-0" :style="selectedCommitment?.bg_color ? { background: `#${selectedCommitment.bg_color}` } : {}" />
|
||||
<div class="min-w-0">
|
||||
<div class="font-semibold truncate text-base">{{ headerTitle }}</div>
|
||||
<div v-if="step === 2" class="text-xs text-color-secondary truncate">{{ previewRange }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</slot>
|
||||
|
||||
<!-- actions moved to footer -->
|
||||
</div>
|
||||
@@ -733,9 +766,9 @@ const googleCalendarUrl = computed(() => {
|
||||
<!-- ConfirmDialog renderizado na página pai para evitar conflito de z-index com o Dialog -->
|
||||
|
||||
<!-- ══════════════════════════════════════════════ -->
|
||||
<!-- STEP 1 — escolha o tipo -->
|
||||
<!-- STEP 1 — escolha o tipo (oculto se lockType) -->
|
||||
<!-- ══════════════════════════════════════════════ -->
|
||||
<div v-if="step === 1" class="p-2">
|
||||
<div v-if="step === 1 && !lockType" class="p-2">
|
||||
<div class="mb-4 text-sm text-color-secondary">Selecione o tipo de compromisso para começar.</div>
|
||||
|
||||
<Message v-if="isDayBlocked" severity="warn" class="mb-4" :closable="false">
|
||||
@@ -863,9 +896,9 @@ const googleCalendarUrl = computed(() => {
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-1 shrink-0">
|
||||
<Button v-if="!patientLocked" icon="pi pi-pencil" severity="secondary" outlined size="small" class="rounded-full h-8 w-8" v-tooltip.top="'Trocar'" @click="openPacientePicker" />
|
||||
<Button v-if="!patientLocked" icon="pi pi-times" severity="secondary" text size="small" class="rounded-full h-8 w-8" v-tooltip.top="'Limpar'" @click="clearPaciente" />
|
||||
<span v-if="patientLocked" v-tooltip.top="'Paciente não pode ser alterado após criação'" class="flex items-center gap-1 text-xs text-color-secondary px-2"><i class="pi pi-lock" /></span>
|
||||
<Button v-if="!patientLocked && !lockPatient" icon="pi pi-pencil" severity="secondary" outlined size="small" class="rounded-full h-8 w-8" v-tooltip.top="'Trocar'" @click="openPacientePicker" />
|
||||
<Button v-if="!patientLocked && !lockPatient" icon="pi pi-times" severity="secondary" text size="small" class="rounded-full h-8 w-8" v-tooltip.top="'Limpar'" @click="clearPaciente" />
|
||||
<span v-if="patientLocked || lockPatient" v-tooltip.top="lockPatient ? 'Paciente do prontuário' : 'Paciente não pode ser alterado após criação'" class="flex items-center gap-1 text-xs text-color-secondary px-2"><i class="pi pi-lock" /></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user