Copyright, Financeiro, Lançamentos, aprimoramentos de ui
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
<!--
|
||||
|--------------------------------------------------------------------------
|
||||
| Agência PSI
|
||||
|--------------------------------------------------------------------------
|
||||
| Criado e desenvolvido por Leonardo Nohama
|
||||
|
|
||||
| Tecnologia aplicada à escuta.
|
||||
| Estrutura para o cuidado.
|
||||
|
|
||||
| Arquivo: src/components/ui/PatientCadastroDialog.vue
|
||||
| Data: 2026
|
||||
| Local: São Carlos/SP — Brasil
|
||||
|--------------------------------------------------------------------------
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Dialog de cadastro/edição de paciente.
|
||||
| Abre PatientsCadastroPage em modo dialog (sem navegação de rota).
|
||||
|
|
||||
| Props:
|
||||
| modelValue (Boolean) — controla visibilidade
|
||||
| patientId (String) — null = novo, id = edição
|
||||
|
|
||||
| Emits:
|
||||
| update:modelValue — fecha
|
||||
| created — paciente criado ou atualizado com sucesso
|
||||
|--------------------------------------------------------------------------
|
||||
-->
|
||||
<template>
|
||||
<Dialog
|
||||
v-model:visible="isOpen"
|
||||
modal
|
||||
:draggable="false"
|
||||
:closable="false"
|
||||
:dismissableMask="false"
|
||||
:maximizable="false"
|
||||
:style="{ width: '90vw', maxWidth: '1100px', height: maximized ? '100vh' : '90vh' }"
|
||||
:contentStyle="{ padding: 0, overflow: 'auto', height: '100%' }"
|
||||
pt:mask:class="backdrop-blur-xs"
|
||||
>
|
||||
<!-- ── Header ─────────────────────────────────────── -->
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between w-full gap-3">
|
||||
<!-- Título -->
|
||||
<span class="text-base font-semibold text-[var(--text-color)] leading-tight">
|
||||
{{ patientId ? 'Editar Paciente' : 'Cadastro de Paciente' }}
|
||||
</span>
|
||||
|
||||
<!-- Botões à direita -->
|
||||
<div class="flex items-center gap-1 ml-auto">
|
||||
|
||||
<!-- Preencher tudo (só testMODE) -->
|
||||
<Button
|
||||
v-if="pageRef?.canSee?.('testMODE')"
|
||||
label="Preencher tudo"
|
||||
icon="pi pi-bolt"
|
||||
severity="secondary"
|
||||
outlined
|
||||
size="small"
|
||||
class="rounded-full"
|
||||
:disabled="pageRef?.saving?.value || pageRef?.deleting?.value"
|
||||
@click="pageRef?.fillRandomPatient?.()"
|
||||
/>
|
||||
|
||||
<!-- Excluir (só em edição) -->
|
||||
<Button
|
||||
v-if="patientId"
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
outlined
|
||||
size="small"
|
||||
class="rounded-full"
|
||||
:loading="pageRef?.deleting?.value"
|
||||
:disabled="pageRef?.saving?.value || pageRef?.deleting?.value"
|
||||
title="Excluir paciente"
|
||||
@click="pageRef?.confirmDelete?.()"
|
||||
/>
|
||||
|
||||
<!-- Maximizar -->
|
||||
<button
|
||||
class="w-8 h-8 rounded-lg border-none bg-transparent text-[var(--text-color-secondary)] cursor-pointer grid place-items-center text-sm transition-colors hover:bg-[var(--surface-ground)] hover:text-[var(--text-color)]"
|
||||
:title="maximized ? 'Restaurar' : 'Maximizar'"
|
||||
@click="maximized = !maximized"
|
||||
>
|
||||
<i :class="maximized ? 'pi pi-window-minimize' : 'pi pi-window-maximize'" />
|
||||
</button>
|
||||
|
||||
<!-- Fechar -->
|
||||
<button
|
||||
class="w-8 h-8 rounded-lg border-none bg-transparent text-[var(--text-color-secondary)] cursor-pointer grid place-items-center text-sm transition-colors hover:bg-[var(--surface-ground)] hover:text-[var(--text-color)]"
|
||||
title="Fechar"
|
||||
@click="isOpen = false"
|
||||
>
|
||||
<i class="pi pi-times" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ── Conteúdo ────────────────────────────────────── -->
|
||||
<PatientsCadastroPage
|
||||
ref="pageRef"
|
||||
:dialog-mode="true"
|
||||
:patient-id="patientId"
|
||||
@cancel="isOpen = false"
|
||||
@created="onCreated"
|
||||
/>
|
||||
|
||||
<!-- ── Footer ─────────────────────────────────────── -->
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-2">
|
||||
<Button
|
||||
label="Cancelar"
|
||||
severity="secondary"
|
||||
text
|
||||
:disabled="!!pageRef?.saving?.value || !!pageRef?.deleting?.value"
|
||||
@click="isOpen = false"
|
||||
/>
|
||||
<!-- Na rota de pacientes: só "Salvar" -->
|
||||
<Button
|
||||
v-if="isOnPatientsPage"
|
||||
label="Salvar"
|
||||
:loading="!!pageRef?.saving?.value"
|
||||
:disabled="!!pageRef?.saving?.value || !!pageRef?.deleting?.value"
|
||||
@click="submitWith('only')"
|
||||
/>
|
||||
<!-- Fora da rota de pacientes: "Salvar e fechar" + "Salvar e ver pacientes" -->
|
||||
<template v-else>
|
||||
<Button
|
||||
label="Salvar e fechar"
|
||||
severity="secondary"
|
||||
outlined
|
||||
:loading="pendingMode === 'only' && !!pageRef?.saving?.value"
|
||||
:disabled="!!pageRef?.saving?.value || !!pageRef?.deleting?.value"
|
||||
@click="submitWith('only')"
|
||||
/>
|
||||
<Button
|
||||
label="Salvar e ver pacientes"
|
||||
:loading="pendingMode === 'view' && !!pageRef?.saving?.value"
|
||||
:disabled="!!pageRef?.saving?.value || !!pageRef?.deleting?.value"
|
||||
@click="submitWith('view')"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import PatientsCadastroPage from '@/features/patients/cadastro/PatientsCadastroPage.vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Boolean, default: false },
|
||||
patientId: { type: String, default: null }
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue', 'created'])
|
||||
|
||||
const isOpen = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (v) => emit('update:modelValue', v)
|
||||
})
|
||||
|
||||
// Reset maximized when dialog opens
|
||||
watch(() => props.modelValue, (v) => { if (!v) maximized.value = false })
|
||||
|
||||
const maximized = ref(false)
|
||||
const pageRef = ref(null)
|
||||
const pendingMode = ref('only')
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const isOnPatientsPage = computed(() => {
|
||||
const p = String(route.path || '')
|
||||
return p.includes('/patients') || p.includes('/pacientes')
|
||||
})
|
||||
|
||||
function patientsListRoute () {
|
||||
const p = String(route.path || '')
|
||||
return p.startsWith('/therapist') ? '/therapist/patients' : '/admin/pacientes'
|
||||
}
|
||||
|
||||
function submitWith (mode) {
|
||||
pendingMode.value = mode
|
||||
pageRef.value?.onSubmit()
|
||||
}
|
||||
|
||||
async function onCreated (data) {
|
||||
isOpen.value = false
|
||||
emit('created', data)
|
||||
if (pendingMode.value === 'view') {
|
||||
await router.push(patientsListRoute())
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user