-
-
-
-
{{ headerTitle }}
-
{{ previewRange }}
+
+
+
+
+
+
{{ headerTitle }}
+
{{ previewRange }}
+
-
+
@@ -733,9 +766,9 @@ const googleCalendarUrl = computed(() => {
-
+
-
+
Selecione o tipo de compromisso para começar.
@@ -863,9 +896,9 @@ const googleCalendarUrl = computed(() => {
-
-
-
+
+
+
diff --git a/src/layout/melissa/MelissaPaciente.vue b/src/layout/melissa/MelissaPaciente.vue
index ba9add7..0c4056b 100644
--- a/src/layout/melissa/MelissaPaciente.vue
+++ b/src/layout/melissa/MelissaPaciente.vue
@@ -23,6 +23,7 @@ import { useRouter } from 'vue-router';
import { useToast } from 'primevue/usetoast';
import { useConversationDrawerStore } from '@/stores/conversationDrawerStore';
import { MELISSA_AGENDA_KEY } from './composables/useMelissaAgenda';
+import AgendaEventDialog from '@/features/agenda/components/AgendaEventDialog.vue';
import DocumentsListPage from '@/features/documents/DocumentsListPage.vue';
import PatientConversationsTab from '@/features/patients/prontuario/PatientConversationsTab.vue';
import PatientCadastroDialog from '@/components/ui/PatientCadastroDialog.vue';
@@ -458,8 +459,16 @@ function addFinancial() {
novoLancOpen.value = true;
}
-// Abre o AgendaEventDialog GLOBAL (mesmo que MelissaAgenda usa) com
-// paciente pre-selecionado. O dialog vive no MelissaLayout via provide.
+// Abre AgendaEventDialog LOCAL (instancia propria) com paciente fixo
+// e tipo='sessao' travado. Dados pesados (commitmentOptions, workRules,
+// allEvents, agendaSettings, feriados, ownerId, tenantId) vem via inject
+// do MelissaLayout. State do dialog (open/eventRow/start/end) e LOCAL
+// pra nao colidir com o dialog global da Agenda.
+const sessaoDialogOpen = ref(false);
+const sessaoDialogEventRow = ref(null);
+const sessaoDialogStartISO = ref(null);
+const sessaoDialogEndISO = ref(null);
+
function goAgendar() {
activeTab.value = 'agenda';
if (isMobile.value) drawerOpen.value = false;
@@ -467,7 +476,7 @@ function goAgendar() {
toast.add({ severity: 'warn', summary: 'Paciente sem ID', life: 2500 });
return;
}
- if (!melissaAgenda || typeof melissaAgenda.onCreateEventoForPatient !== 'function') {
+ if (!melissaAgenda?.ownerId?.value) {
toast.add({
severity: 'warn',
summary: 'Agenda indisponível',
@@ -476,21 +485,58 @@ function goAgendar() {
});
return;
}
- melissaAgenda.onCreateEventoForPatient(props.patientId);
+ // Defaults razoaveis: proximo slot 15min + duracao padrao da agenda.
+ const durMin =
+ melissaAgenda.settings?.value?.session_duration_min ??
+ melissaAgenda.settings?.value?.duracao_padrao_minutos ??
+ 50;
+ const base = new Date();
+ base.setSeconds(0, 0);
+ const remainder = base.getMinutes() % 15;
+ if (remainder !== 0) base.setMinutes(base.getMinutes() + (15 - remainder));
+
+ sessaoDialogEventRow.value = {
+ owner_id: melissaAgenda.ownerId.value,
+ terapeuta_id: null,
+ paciente_id: String(props.patientId),
+ tipo: 'sessao',
+ status: 'agendado',
+ titulo: null,
+ observacoes: null,
+ visibility_scope: 'public',
+ determined_commitment_id: null
+ };
+ sessaoDialogStartISO.value = base.toISOString();
+ sessaoDialogEndISO.value = new Date(base.getTime() + durMin * 60000).toISOString();
+ sessaoDialogOpen.value = true;
}
-// Watch o dialogOpen do AgendaEventDialog: quando ele fecha (true -> false)
-// refetcha sessoes + recorrencias do paciente. Cobre tanto save quanto
-// close-sem-salvar (idempotente; load() ja eh barato).
-if (melissaAgenda?.dialogOpen) {
- watch(melissaAgenda.dialogOpen, async (now, prev) => {
- if (prev && !now && props.patientId) {
- await Promise.all([
- sessionsHook.load(props.patientId),
- recorrenciasHook.load(props.patientId)
- ]);
- }
- });
+// Handlers do dialog local — delegam pros handlers globais do useMelissaAgenda
+// (M.onDialogSave/Delete) que ja sabem mexer com agenda_eventos +
+// recurrence_rules + exceptions. Apos fechar, refetcha sessions+recorrencias.
+async function onSessaoDialogSave(payload) {
+ if (typeof melissaAgenda?.onDialogSave === 'function') {
+ await melissaAgenda.onDialogSave(payload);
+ }
+ sessaoDialogOpen.value = false;
+ if (props.patientId) {
+ await Promise.all([
+ sessionsHook.load(props.patientId),
+ recorrenciasHook.load(props.patientId)
+ ]);
+ }
+}
+async function onSessaoDialogDelete(payload) {
+ if (typeof melissaAgenda?.onDialogDelete === 'function') {
+ await melissaAgenda.onDialogDelete(payload);
+ }
+ sessaoDialogOpen.value = false;
+ if (props.patientId) {
+ await Promise.all([
+ sessionsHook.load(props.patientId),
+ recorrenciasHook.load(props.patientId)
+ ]);
+ }
}
async function salvarLancamento() {
const f = novoLancForm.value;
@@ -2204,11 +2250,53 @@ onBeforeUnmount(() => {