feature/consultations #22
@ -56,7 +56,7 @@ import {
|
|||||||
import { mockAppointments, mockProfessionals } from "@/lib/mocks/appointment-mocks";
|
import { mockAppointments, mockProfessionals } from "@/lib/mocks/appointment-mocks";
|
||||||
import { CalendarRegistrationForm } from "@/components/forms/calendar-registration-form";
|
import { CalendarRegistrationForm } from "@/components/forms/calendar-registration-form";
|
||||||
|
|
||||||
// --- Helper Functions ---
|
|
||||||
const formatDate = (date: string | Date) => {
|
const formatDate = (date: string | Date) => {
|
||||||
if (!date) return "";
|
if (!date) return "";
|
||||||
return new Date(date).toLocaleDateString("pt-BR", {
|
return new Date(date).toLocaleDateString("pt-BR", {
|
||||||
@ -73,14 +73,12 @@ const capitalize = (s: string) => {
|
|||||||
return s.charAt(0).toUpperCase() + s.slice(1);
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Main Page Component ---
|
|
||||||
export default function ConsultasPage() {
|
export default function ConsultasPage() {
|
||||||
const [appointments, setAppointments] = useState(mockAppointments);
|
const [appointments, setAppointments] = useState(mockAppointments);
|
||||||
const [showForm, setShowForm] = useState(false);
|
const [showForm, setShowForm] = useState(false);
|
||||||
const [editingAppointment, setEditingAppointment] = useState<any | null>(null);
|
const [editingAppointment, setEditingAppointment] = useState<any | null>(null);
|
||||||
const [viewingAppointment, setViewingAppointment] = useState<any | null>(null);
|
const [viewingAppointment, setViewingAppointment] = useState<any | null>(null);
|
||||||
|
|
||||||
// Converte o objeto da consulta para o formato esperado pelo formulário
|
|
||||||
const mapAppointmentToFormData = (appointment: any) => {
|
const mapAppointmentToFormData = (appointment: any) => {
|
||||||
const professional = mockProfessionals.find(p => p.id === appointment.professional);
|
const professional = mockProfessionals.find(p => p.id === appointment.professional);
|
||||||
const appointmentDate = new Date(appointment.time);
|
const appointmentDate = new Date(appointment.time);
|
||||||
@ -89,14 +87,12 @@ export default function ConsultasPage() {
|
|||||||
id: appointment.id,
|
id: appointment.id,
|
||||||
patientName: appointment.patient,
|
patientName: appointment.patient,
|
||||||
professionalName: professional ? professional.name : '',
|
professionalName: professional ? professional.name : '',
|
||||||
appointmentDate: appointmentDate.toISOString().split('T')[0], // Formato YYYY-MM-DD
|
appointmentDate: appointmentDate.toISOString().split('T')[0],
|
||||||
startTime: appointmentDate.toTimeString().split(' ')[0].substring(0, 5), // Formato HH:MM
|
startTime: appointmentDate.toTimeString().split(' ')[0].substring(0, 5),
|
||||||
endTime: new Date(appointmentDate.getTime() + appointment.duration * 60000).toTimeString().split(' ')[0].substring(0, 5),
|
endTime: new Date(appointmentDate.getTime() + appointment.duration * 60000).toTimeString().split(' ')[0].substring(0, 5),
|
||||||
status: appointment.status,
|
status: appointment.status,
|
||||||
appointmentType: appointment.type,
|
appointmentType: appointment.type,
|
||||||
notes: appointment.notes,
|
notes: appointment.notes,
|
||||||
// Adicione outros campos do paciente aqui se necessário (cpf, rg, etc.)
|
|
||||||
// Eles não existem no mock de agendamento, então virão vazios
|
|
||||||
cpf: '',
|
cpf: '',
|
||||||
rg: '',
|
rg: '',
|
||||||
birthDate: '',
|
birthDate: '',
|
||||||
@ -129,24 +125,22 @@ export default function ConsultasPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSave = (formData: any) => {
|
const handleSave = (formData: any) => {
|
||||||
// Como o formulário edita campos que não estão na tabela,
|
|
||||||
// precisamos mapear de volta para o formato original do agendamento.
|
|
||||||
// Para a simulação, vamos atualizar apenas os campos que existem no mock.
|
|
||||||
const updatedAppointment = {
|
const updatedAppointment = {
|
||||||
id: formData.id,
|
id: formData.id,
|
||||||
patient: formData.patientName,
|
patient: formData.patientName,
|
||||||
time: new Date(`${formData.appointmentDate}T${formData.startTime}`).toISOString(),
|
time: new Date(`${formData.appointmentDate}T${formData.startTime}`).toISOString(),
|
||||||
duration: 30, // Duração não está no form, então mantemos um valor fixo
|
duration: 30,
|
||||||
type: formData.appointmentType as any,
|
type: formData.appointmentType as any,
|
||||||
status: formData.status as any,
|
status: formData.status as any,
|
||||||
professional: appointments.find(a => a.id === formData.id)?.professional || '', // Mantém o ID do profissional
|
professional: appointments.find(a => a.id === formData.id)?.professional || '',
|
||||||
notes: formData.notes,
|
notes: formData.notes,
|
||||||
};
|
};
|
||||||
|
|
||||||
setAppointments(prev =>
|
setAppointments(prev =>
|
||||||
prev.map(a => a.id === updatedAppointment.id ? updatedAppointment : a)
|
prev.map(a => a.id === updatedAppointment.id ? updatedAppointment : a)
|
||||||
);
|
);
|
||||||
handleCancel(); // Fecha o formulário
|
handleCancel();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (showForm && editingAppointment) {
|
if (showForm && editingAppointment) {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import { MoreHorizontal, Plus, Search, Edit, Trash2, ArrowLeft, Eye } from "luci
|
|||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { DoctorRegistrationForm } from "@/components/forms/doctor-registration-form";
|
import { DoctorRegistrationForm } from "@/components/forms/doctor-registration-form";
|
||||||
|
|
||||||
// >>> IMPORTES DA API <<<
|
|
||||||
import { listarMedicos, excluirMedico, Medico } from "@/lib/api";
|
import { listarMedicos, excluirMedico, Medico } from "@/lib/api";
|
||||||
|
|
||||||
export default function DoutoresPage() {
|
export default function DoutoresPage() {
|
||||||
@ -22,7 +22,7 @@ export default function DoutoresPage() {
|
|||||||
const [editingId, setEditingId] = useState<string | null>(null);
|
const [editingId, setEditingId] = useState<string | null>(null);
|
||||||
const [viewingDoctor, setViewingDoctor] = useState<Medico | null>(null);
|
const [viewingDoctor, setViewingDoctor] = useState<Medico | null>(null);
|
||||||
|
|
||||||
// Carrega da API
|
|
||||||
async function load() {
|
async function load() {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
@ -62,14 +62,14 @@ export default function DoutoresPage() {
|
|||||||
setViewingDoctor(doctor);
|
setViewingDoctor(doctor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Excluir via API e recarregar
|
|
||||||
async function handleDelete(id: string) {
|
async function handleDelete(id: string) {
|
||||||
if (!confirm("Excluir este médico?")) return;
|
if (!confirm("Excluir este médico?")) return;
|
||||||
await excluirMedico(id);
|
await excluirMedico(id);
|
||||||
await load();
|
await load();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Após salvar/criar/editar no form, fecha e recarrega
|
|
||||||
async function handleSaved() {
|
async function handleSaved() {
|
||||||
setShowForm(false);
|
setShowForm(false);
|
||||||
await load();
|
await load();
|
||||||
|
|||||||
@ -276,7 +276,7 @@ export default function PacientesPage() {
|
|||||||
<div className="grid grid-cols-4 items-center gap-4">
|
<div className="grid grid-cols-4 items-center gap-4">
|
||||||
<Label className="text-right">Endereço</Label>
|
<Label className="text-right">Endereço</Label>
|
||||||
<span className="col-span-3">
|
<span className="col-span-3">
|
||||||
{`${viewingPatient.endereco.logradouro}, ${viewingPatient.endereco.numero} - ${viewingPatient.endereco.bairro}, ${viewingPatient.endereco.cidade} - ${viewingPatient.endereco.estado}`}
|
{`${viewingPatient.endereco?.logradouro || ''}, ${viewingPatient.endereco?.numero || ''} - ${viewingPatient.endereco?.bairro || ''}, ${viewingPatient.endereco?.cidade || ''} - ${viewingPatient.endereco?.estado || ''}`}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-4 items-center gap-4">
|
<div className="grid grid-cols-4 items-center gap-4">
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { AppointmentForm } from "@/components/forms/appointment-form";
|
import { CalendarRegistrationForm } from "@/components/forms/calendar-registration-form";
|
||||||
import HeaderAgenda from "@/components/agenda/HeaderAgenda";
|
import HeaderAgenda from "@/components/agenda/HeaderAgenda";
|
||||||
import FooterAgenda from "@/components/agenda/FooterAgenda";
|
import FooterAgenda from "@/components/agenda/FooterAgenda";
|
||||||
|
|
||||||
@ -10,23 +10,22 @@ export default function NovoAgendamentoPage() {
|
|||||||
|
|
||||||
const handleSave = (data: any) => {
|
const handleSave = (data: any) => {
|
||||||
console.log("Salvando novo agendamento...", data);
|
console.log("Salvando novo agendamento...", data);
|
||||||
// Aqui viria a chamada da API para criar um novo agendamento
|
|
||||||
alert("Novo agendamento salvo (simulado)!");
|
alert("Novo agendamento salvo (simulado)!");
|
||||||
router.push("/consultas"); // Volta para a lista após salvar
|
router.push("/consultas");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
router.back(); // Simplesmente volta para a página anterior
|
router.back();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex flex-col bg-white">
|
<div className="min-h-screen flex flex-col bg-white">
|
||||||
<HeaderAgenda />
|
<HeaderAgenda />
|
||||||
<main className="flex-1 mx-auto w-full max-w-7xl px-8 py-8">
|
<main className="flex-1 mx-auto w-full max-w-7xl px-8 py-8">
|
||||||
<AppointmentForm
|
<CalendarRegistrationForm
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
initialData={{}} // Passa um objeto vazio para o modo de criação
|
initialData={{}}
|
||||||
/>
|
/>
|
||||||
</main>
|
</main>
|
||||||
<FooterAgenda />
|
<FooterAgenda />
|
||||||
|
|||||||
@ -7,15 +7,10 @@ import { Label } from "@/components/ui/label";
|
|||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { Calendar, Search, ChevronDown, Upload, FileDown, Tag } from "lucide-react";
|
import { Calendar, Search, ChevronDown, Upload, FileDown, Tag } from "lucide-react";
|
||||||
|
|
||||||
// Este é um formulário genérico para Criar e Editar um agendamento.
|
|
||||||
// Ele não tem Header ou Footer, apenas o conteúdo do formulário em si.
|
|
||||||
|
|
||||||
export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any) {
|
export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any) {
|
||||||
const [formData, setFormData] = useState(initialData || {});
|
const [formData, setFormData] = useState(initialData || {});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Se os dados iniciais mudarem (ex: usuário clica em outro item para editar),
|
|
||||||
// atualizamos o estado do formulário.
|
|
||||||
setFormData(initialData || {});
|
setFormData(initialData || {});
|
||||||
}, [initialData]);
|
}, [initialData]);
|
||||||
|
|
||||||
@ -31,7 +26,6 @@ export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any)
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit} className="space-y-8">
|
<form onSubmit={handleSubmit} className="space-y-8">
|
||||||
{/* ==== INFORMAÇÕES DO PACIENTE ==== */}
|
|
||||||
<div className="border rounded-md p-6 space-y-4 bg-white">
|
<div className="border rounded-md p-6 space-y-4 bg-white">
|
||||||
<h2 className="font-medium">Informações do paciente</h2>
|
<h2 className="font-medium">Informações do paciente</h2>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-12 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-12 gap-4">
|
||||||
@ -40,7 +34,7 @@ export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any)
|
|||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Search className="pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" />
|
<Search className="pointer-events-none absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" />
|
||||||
<Input
|
<Input
|
||||||
name="patientName" // Nome do campo para o estado
|
name="patientName"
|
||||||
placeholder="Digite o nome do paciente"
|
placeholder="Digite o nome do paciente"
|
||||||
className="h-10 pl-8"
|
className="h-10 pl-8"
|
||||||
value={formData.patientName || ''}
|
value={formData.patientName || ''}
|
||||||
@ -82,7 +76,7 @@ export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any)
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ==== INFORMAÇÕES DO ATENDIMENTO ==== */}
|
{}
|
||||||
<div className="border rounded-md p-6 space-y-4 bg-white">
|
<div className="border rounded-md p-6 space-y-4 bg-white">
|
||||||
<h2 className="font-medium">Informações do atendimento</h2>
|
<h2 className="font-medium">Informações do atendimento</h2>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-12 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||||
@ -137,7 +131,6 @@ export function CalendarRegistrationForm({ initialData, onSave, onCancel }: any)
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Botões de Ação */}
|
|
||||||
<div className="flex justify-end gap-2">
|
<div className="flex justify-end gap-2">
|
||||||
<Button type="button" variant="outline" onClick={onCancel}>Cancelar</Button>
|
<Button type="button" variant="outline" onClick={onCancel}>Cancelar</Button>
|
||||||
<Button type="submit">Salvar</Button>
|
<Button type="submit">Salvar</Button>
|
||||||
|
|||||||
@ -24,9 +24,7 @@ import {
|
|||||||
MedicoInput,
|
MedicoInput,
|
||||||
} from "@/lib/api";
|
} from "@/lib/api";
|
||||||
|
|
||||||
import { buscarCepAPI } from "@/lib/api"; // use o seu já existente
|
import { buscarCepAPI } from "@/lib/api";
|
||||||
|
|
||||||
// Mock data and types since API is not used for now
|
|
||||||
|
|
||||||
type FormacaoAcademica = {
|
type FormacaoAcademica = {
|
||||||
instituicao: string;
|
instituicao: string;
|
||||||
@ -179,7 +177,6 @@ export function DoctorRegistrationForm({
|
|||||||
if (mode === "edit" && doctorId) {
|
if (mode === "edit" && doctorId) {
|
||||||
const medico = await buscarMedicoPorId(doctorId);
|
const medico = await buscarMedicoPorId(doctorId);
|
||||||
if (!alive) return;
|
if (!alive) return;
|
||||||
// mapeia API -> estado do formulário
|
|
||||||
setForm({
|
setForm({
|
||||||
photo: null,
|
photo: null,
|
||||||
nome: medico.nome ?? "",
|
nome: medico.nome ?? "",
|
||||||
@ -188,7 +185,7 @@ export function DoctorRegistrationForm({
|
|||||||
estado_crm: medico.estado_crm ?? "",
|
estado_crm: medico.estado_crm ?? "",
|
||||||
rqe: medico.rqe ?? "",
|
rqe: medico.rqe ?? "",
|
||||||
formacao_academica: medico.formacao_academica ?? [],
|
formacao_academica: medico.formacao_academica ?? [],
|
||||||
curriculo: null, // se a API devolver URL, você pode exibir ao lado
|
curriculo: null,
|
||||||
especialidade: medico.especialidade ?? "",
|
especialidade: medico.especialidade ?? "",
|
||||||
cpf: medico.cpf ?? "",
|
cpf: medico.cpf ?? "",
|
||||||
rg: medico.rg ?? "",
|
rg: medico.rg ?? "",
|
||||||
@ -213,7 +210,7 @@ export function DoctorRegistrationForm({
|
|||||||
valor_consulta: medico.valor_consulta ? String(medico.valor_consulta) : "",
|
valor_consulta: medico.valor_consulta ? String(medico.valor_consulta) : "",
|
||||||
});
|
});
|
||||||
|
|
||||||
// (Opcional) listar anexos que já existem no servidor
|
|
||||||
try {
|
try {
|
||||||
const list = await listarAnexosMedico(doctorId);
|
const list = await listarAnexosMedico(doctorId);
|
||||||
setServerAnexos(list ?? []);
|
setServerAnexos(list ?? []);
|
||||||
@ -320,7 +317,6 @@ export function DoctorRegistrationForm({
|
|||||||
setErrors((e) => ({ ...e, submit: "" }));
|
setErrors((e) => ({ ...e, submit: "" }));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// monta o payload esperado pela API
|
|
||||||
const payload: MedicoInput = {
|
const payload: MedicoInput = {
|
||||||
nome: form.nome,
|
nome: form.nome,
|
||||||
nome_social: form.nome_social || null,
|
nome_social: form.nome_social || null,
|
||||||
@ -336,7 +332,7 @@ export function DoctorRegistrationForm({
|
|||||||
estado_crm: form.estado_crm || null,
|
estado_crm: form.estado_crm || null,
|
||||||
rqe: form.rqe || null,
|
rqe: form.rqe || null,
|
||||||
formacao_academica: form.formacao_academica ?? [],
|
formacao_academica: form.formacao_academica ?? [],
|
||||||
curriculo_url: null, // se quiser, suba arquivo do currículo num endpoint próprio e salve a URL aqui
|
curriculo_url: null,
|
||||||
especialidade: form.especialidade,
|
especialidade: form.especialidade,
|
||||||
observacoes: form.observacoes || null,
|
observacoes: form.observacoes || null,
|
||||||
tipo_vinculo: form.tipo_vinculo || null,
|
tipo_vinculo: form.tipo_vinculo || null,
|
||||||
@ -345,14 +341,12 @@ export function DoctorRegistrationForm({
|
|||||||
valor_consulta: form.valor_consulta || null,
|
valor_consulta: form.valor_consulta || null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// cria ou atualiza
|
|
||||||
const saved = mode === "create"
|
const saved = mode === "create"
|
||||||
? await criarMedico(payload)
|
? await criarMedico(payload)
|
||||||
: await atualizarMedico(doctorId as number, payload);
|
: await atualizarMedico(doctorId as number, payload);
|
||||||
|
|
||||||
const medicoId = saved.id;
|
const medicoId = saved.id;
|
||||||
|
|
||||||
// foto (opcional)
|
|
||||||
if (form.photo) {
|
if (form.photo) {
|
||||||
try {
|
try {
|
||||||
await uploadFotoMedico(medicoId, form.photo);
|
await uploadFotoMedico(medicoId, form.photo);
|
||||||
@ -361,7 +355,6 @@ export function DoctorRegistrationForm({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// anexos locais (opcional)
|
|
||||||
if (form.anexos?.length) {
|
if (form.anexos?.length) {
|
||||||
for (const f of form.anexos) {
|
for (const f of form.anexos) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user