develop #83
@ -1,40 +1,39 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
||||||
import { MoreHorizontal, Plus, Search, Edit, Trash2, ArrowLeft, Eye } from "lucide-react";
|
import { MoreHorizontal, Plus, Search, Edit, Trash2, ArrowLeft, Eye } from "lucide-react";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { DoctorRegistrationForm, Medico } from "@/components/forms/doctor-registration-form";
|
import { DoctorRegistrationForm } from "@/components/forms/doctor-registration-form";
|
||||||
|
|
||||||
// Mock data for doctors
|
// >>> IMPORTES DA API <<<
|
||||||
const initialDoctors: Medico[] = [
|
import { listarMedicos, excluirMedico, Medico } from "@/lib/api";
|
||||||
{
|
|
||||||
id: "1",
|
|
||||||
nome: "Dr. João Silva",
|
|
||||||
especialidade: "Cardiologia",
|
|
||||||
crm: "12345-SP",
|
|
||||||
email: "joao.silva@example.com",
|
|
||||||
telefone: "(11) 99999-1234",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "2",
|
|
||||||
nome: "Dra. Maria Oliveira",
|
|
||||||
especialidade: "Pediatria",
|
|
||||||
crm: "54321-RJ",
|
|
||||||
email: "maria.oliveira@example.com",
|
|
||||||
telefone: "(21) 98888-5678",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function DoutoresPage() {
|
export default function DoutoresPage() {
|
||||||
const [doctors, setDoctors] = useState<Medico[]>(initialDoctors);
|
const [doctors, setDoctors] = useState<Medico[]>([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const [showForm, setShowForm] = useState(false);
|
const [showForm, setShowForm] = useState(false);
|
||||||
const [editingId, setEditingId] = useState<string | null>(null);
|
const [editingId, setEditingId] = useState<string | null>(null);
|
||||||
|
|
||||||
|
// Carrega da API
|
||||||
|
async function load() {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const list = await listarMedicos({ limit: 50 });
|
||||||
|
setDoctors(list ?? []);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
load();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const filtered = useMemo(() => {
|
const filtered = useMemo(() => {
|
||||||
if (!search.trim()) return doctors;
|
if (!search.trim()) return doctors;
|
||||||
const q = search.toLowerCase();
|
const q = search.toLowerCase();
|
||||||
@ -56,26 +55,17 @@ export default function DoutoresPage() {
|
|||||||
setShowForm(true);
|
setShowForm(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDelete(id: string) {
|
// Excluir via API e recarregar
|
||||||
|
async function handleDelete(id: string) {
|
||||||
if (!confirm("Excluir este médico?")) return;
|
if (!confirm("Excluir este médico?")) return;
|
||||||
setDoctors((prev) => prev.filter((x) => String(x.id) !== String(id)));
|
await excluirMedico(id);
|
||||||
|
await load();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSaved(medico: Medico) {
|
// Após salvar/criar/editar no form, fecha e recarrega
|
||||||
const saved = medico;
|
async function handleSaved() {
|
||||||
setDoctors((prev) => {
|
|
||||||
// Se não houver ID, é um novo médico
|
|
||||||
if (!saved.id) {
|
|
||||||
return [{ ...saved, id: String(Date.now()) }, ...prev];
|
|
||||||
}
|
|
||||||
// Se houver ID, é uma edição
|
|
||||||
const i = prev.findIndex((x) => String(x.id) === String(saved.id));
|
|
||||||
if (i < 0) return [{ ...saved, id: String(Date.now()) }, ...prev]; // Caso não encontre, adiciona
|
|
||||||
const clone = [...prev];
|
|
||||||
clone[i] = saved;
|
|
||||||
return clone;
|
|
||||||
});
|
|
||||||
setShowForm(false);
|
setShowForm(false);
|
||||||
|
await load();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showForm) {
|
if (showForm) {
|
||||||
@ -117,7 +107,7 @@ export default function DoutoresPage() {
|
|||||||
onChange={(e) => setSearch(e.target.value)}
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Button onClick={handleAdd}>
|
<Button onClick={handleAdd} disabled={loading}>
|
||||||
<Plus className="mr-2 h-4 w-4" />
|
<Plus className="mr-2 h-4 w-4" />
|
||||||
Novo Médico
|
Novo Médico
|
||||||
</Button>
|
</Button>
|
||||||
@ -136,7 +126,13 @@ export default function DoutoresPage() {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{filtered.length > 0 ? (
|
{loading ? (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell colSpan={5} className="text-center text-muted-foreground">
|
||||||
|
Carregando…
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : filtered.length > 0 ? (
|
||||||
filtered.map((doctor) => (
|
filtered.map((doctor) => (
|
||||||
<TableRow key={doctor.id}>
|
<TableRow key={doctor.id}>
|
||||||
<TableCell className="font-medium">{doctor.nome}</TableCell>
|
<TableCell className="font-medium">{doctor.nome}</TableCell>
|
||||||
@ -186,7 +182,9 @@ export default function DoutoresPage() {
|
|||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-sm text-muted-foreground">Mostrando {filtered.length} de {doctors.length}</div>
|
<div className="text-sm text-muted-foreground">
|
||||||
|
Mostrando {filtered.length} de {doctors.length}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,18 @@ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/u
|
|||||||
import { AlertCircle, ChevronDown, ChevronUp, FileImage, Loader2, Save, Upload, User, X, XCircle, Trash2 } from "lucide-react";
|
import { AlertCircle, ChevronDown, ChevronUp, FileImage, Loader2, Save, Upload, User, X, XCircle, Trash2 } from "lucide-react";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { Popover, PopoverTrigger, PopoverContent } from "@/components/ui/popover";
|
import { Popover, PopoverTrigger, PopoverContent } from "@/components/ui/popover";
|
||||||
|
import {
|
||||||
|
criarMedico,
|
||||||
|
atualizarMedico,
|
||||||
|
buscarMedicoPorId,
|
||||||
|
uploadFotoMedico,
|
||||||
|
listarAnexosMedico,
|
||||||
|
adicionarAnexoMedico,
|
||||||
|
removerAnexoMedico,
|
||||||
|
MedicoInput,
|
||||||
|
} from "@/lib/api";
|
||||||
|
|
||||||
|
import { buscarCepAPI } from "@/lib/api"; // use o seu já existente
|
||||||
|
|
||||||
// Mock data and types since API is not used for now
|
// Mock data and types since API is not used for now
|
||||||
|
|
||||||
@ -161,13 +173,57 @@ export function DoctorRegistrationForm({
|
|||||||
|
|
||||||
const title = useMemo(() => (mode === "create" ? "Cadastro de Médico" : "Editar Médico"), [mode]);
|
const title = useMemo(() => (mode === "create" ? "Cadastro de Médico" : "Editar Médico"), [mode]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Data loading logic would go here in a real scenario
|
let alive = true;
|
||||||
|
async function load() {
|
||||||
if (mode === "edit" && doctorId) {
|
if (mode === "edit" && doctorId) {
|
||||||
console.log("Loading doctor data for ID:", doctorId);
|
const medico = await buscarMedicoPorId(doctorId);
|
||||||
// Example: setForm(loadedDoctorData);
|
if (!alive) return;
|
||||||
|
// mapeia API -> estado do formulário
|
||||||
|
setForm({
|
||||||
|
photo: null,
|
||||||
|
nome: medico.nome ?? "",
|
||||||
|
nome_social: medico.nome_social ?? "",
|
||||||
|
crm: medico.crm ?? "",
|
||||||
|
estado_crm: medico.estado_crm ?? "",
|
||||||
|
rqe: medico.rqe ?? "",
|
||||||
|
formacao_academica: medico.formacao_academica ?? [],
|
||||||
|
curriculo: null, // se a API devolver URL, você pode exibir ao lado
|
||||||
|
especialidade: medico.especialidade ?? "",
|
||||||
|
cpf: medico.cpf ?? "",
|
||||||
|
rg: medico.rg ?? "",
|
||||||
|
sexo: medico.sexo ?? "",
|
||||||
|
data_nascimento: medico.data_nascimento ?? "",
|
||||||
|
email: medico.email ?? "",
|
||||||
|
telefone: medico.telefone ?? "",
|
||||||
|
celular: medico.celular ?? "",
|
||||||
|
contato_emergencia: medico.contato_emergencia ?? "",
|
||||||
|
cep: "",
|
||||||
|
logradouro: "",
|
||||||
|
numero: "",
|
||||||
|
complemento: "",
|
||||||
|
bairro: "",
|
||||||
|
cidade: "",
|
||||||
|
estado: "",
|
||||||
|
observacoes: medico.observacoes ?? "",
|
||||||
|
anexos: [],
|
||||||
|
tipo_vinculo: medico.tipo_vinculo ?? "",
|
||||||
|
dados_bancarios: medico.dados_bancarios ?? { banco: "", agencia: "", conta: "", tipo_conta: "" },
|
||||||
|
agenda_horario: medico.agenda_horario ?? "",
|
||||||
|
valor_consulta: medico.valor_consulta ? String(medico.valor_consulta) : "",
|
||||||
|
});
|
||||||
|
|
||||||
|
// (Opcional) listar anexos que já existem no servidor
|
||||||
|
try {
|
||||||
|
const list = await listarAnexosMedico(doctorId);
|
||||||
|
setServerAnexos(list ?? []);
|
||||||
|
} catch {}
|
||||||
}
|
}
|
||||||
}, [mode, doctorId]);
|
}
|
||||||
|
load();
|
||||||
|
return () => { alive = false; };
|
||||||
|
}, [mode, doctorId]);
|
||||||
|
|
||||||
|
|
||||||
function setField<T extends keyof FormData>(k: T, v: FormData[T]) {
|
function setField<T extends keyof FormData>(k: T, v: FormData[T]) {
|
||||||
setForm((s) => ({ ...s, [k]: v }));
|
setForm((s) => ({ ...s, [k]: v }));
|
||||||
@ -225,27 +281,26 @@ export function DoctorRegistrationForm({
|
|||||||
return n.replace(/(\d{5})(\d{0,3})/, (_, a, b) => `${a}${b ? "-" + b : ""}`);
|
return n.replace(/(\d{5})(\d{0,3})/, (_, a, b) => `${a}${b ? "-" + b : ""}`);
|
||||||
}
|
}
|
||||||
async function fillFromCEP(cep: string) {
|
async function fillFromCEP(cep: string) {
|
||||||
const clean = cep.replace(/\D/g, "");
|
const clean = cep.replace(/\D/g, "");
|
||||||
if (clean.length !== 8) return;
|
if (clean.length !== 8) return;
|
||||||
setSearchingCEP(true);
|
setSearchingCEP(true);
|
||||||
try {
|
try {
|
||||||
// Mocking API call
|
const res = await buscarCepAPI(clean);
|
||||||
console.log("Searching CEP:", clean);
|
if (res && !res.erro) {
|
||||||
// In a real app: const res = await buscarCepAPI(clean);
|
setField("logradouro", res.logradouro ?? "");
|
||||||
// Mock response:
|
setField("bairro", res.bairro ?? "");
|
||||||
const res = { logradouro: "Rua Fictícia", bairro: "Bairro dos Sonhos", localidade: "Cidade Exemplo", uf: "EX" };
|
setField("cidade", res.localidade ?? "");
|
||||||
if (res) {
|
setField("estado", res.uf ?? "");
|
||||||
setField("logradouro", res.logradouro ?? "");
|
} else {
|
||||||
setField("bairro", res.bairro ?? "");
|
setErrors((e) => ({ ...e, cep: "CEP não encontrado" }));
|
||||||
setField("cidade", res.localidade ?? "");
|
|
||||||
setField("estado", res.uf ?? "");
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
setErrors((e) => ({ ...e, cep: "Erro ao buscar CEP" }));
|
|
||||||
} finally {
|
|
||||||
setSearchingCEP(false);
|
|
||||||
}
|
}
|
||||||
|
} catch {
|
||||||
|
setErrors((e) => ({ ...e, cep: "Erro ao buscar CEP" }));
|
||||||
|
} finally {
|
||||||
|
setSearchingCEP(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function validateLocal(): boolean {
|
function validateLocal(): boolean {
|
||||||
const e: Record<string, string> = {};
|
const e: Record<string, string> = {};
|
||||||
@ -258,25 +313,75 @@ export function DoctorRegistrationForm({
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleSubmit(ev: React.FormEvent) {
|
async function handleSubmit(ev: React.FormEvent) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
if (!validateLocal()) return;
|
if (!validateLocal()) return;
|
||||||
|
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
console.log("Submitting form with data:", form);
|
setErrors((e) => ({ ...e, submit: "" }));
|
||||||
|
|
||||||
// Simulate API call
|
try {
|
||||||
setTimeout(() => {
|
// monta o payload esperado pela API
|
||||||
setSubmitting(false);
|
const payload: MedicoInput = {
|
||||||
const savedData: Medico = {
|
nome: form.nome,
|
||||||
id: doctorId ? String(doctorId) : String(Date.now()),
|
nome_social: form.nome_social || null,
|
||||||
...form,
|
cpf: form.cpf || null,
|
||||||
};
|
rg: form.rg || null,
|
||||||
onSaved?.(savedData);
|
sexo: form.sexo || null,
|
||||||
alert(mode === "create" ? "Médico cadastrado com sucesso! (simulado)" : "Médico atualizado com sucesso! (simulado)");
|
data_nascimento: form.data_nascimento || null,
|
||||||
if (inline) onClose?.();
|
telefone: form.telefone || null,
|
||||||
else onOpenChange?.(false);
|
celular: form.celular || null,
|
||||||
}, 1000);
|
contato_emergencia: form.contato_emergencia || null,
|
||||||
|
email: form.email || null,
|
||||||
|
crm: form.crm,
|
||||||
|
estado_crm: form.estado_crm || null,
|
||||||
|
rqe: form.rqe || null,
|
||||||
|
formacao_academica: form.formacao_academica ?? [],
|
||||||
|
curriculo_url: null, // se quiser, suba arquivo do currículo num endpoint próprio e salve a URL aqui
|
||||||
|
especialidade: form.especialidade,
|
||||||
|
observacoes: form.observacoes || null,
|
||||||
|
tipo_vinculo: form.tipo_vinculo || null,
|
||||||
|
dados_bancarios: form.dados_bancarios ?? null,
|
||||||
|
agenda_horario: form.agenda_horario || null,
|
||||||
|
valor_consulta: form.valor_consulta || null,
|
||||||
|
};
|
||||||
|
|
||||||
|
// cria ou atualiza
|
||||||
|
const saved = mode === "create"
|
||||||
|
? await criarMedico(payload)
|
||||||
|
: await atualizarMedico(doctorId as number, payload);
|
||||||
|
|
||||||
|
const medicoId = saved.id;
|
||||||
|
|
||||||
|
// foto (opcional)
|
||||||
|
if (form.photo) {
|
||||||
|
try {
|
||||||
|
await uploadFotoMedico(medicoId, form.photo);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Falha ao enviar foto:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// anexos locais (opcional)
|
||||||
|
if (form.anexos?.length) {
|
||||||
|
for (const f of form.anexos) {
|
||||||
|
try {
|
||||||
|
await adicionarAnexoMedico(medicoId, f);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Falha ao enviar anexo:", f.name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaved?.(saved);
|
||||||
|
if (inline) onClose?.();
|
||||||
|
else onOpenChange?.(false);
|
||||||
|
} catch (err: any) {
|
||||||
|
setErrors((e) => ({ ...e, submit: err?.message || "Erro ao salvar médico" }));
|
||||||
|
} finally {
|
||||||
|
setSubmitting(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function handlePhoto(e: React.ChangeEvent<HTMLInputElement>) {
|
function handlePhoto(e: React.ChangeEvent<HTMLInputElement>) {
|
||||||
const f = e.target.files?.[0];
|
const f = e.target.files?.[0];
|
||||||
|
|||||||
@ -61,8 +61,10 @@ export type PacienteInput = {
|
|||||||
|
|
||||||
|
|
||||||
const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? "https://mock.apidog.com/m1/1053378-0-default";
|
const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? "https://mock.apidog.com/m1/1053378-0-default";
|
||||||
|
const MEDICOS_BASE = process.env.NEXT_PUBLIC_MEDICOS_BASE_PATH ?? "/medicos";
|
||||||
|
|
||||||
const PATHS = {
|
export const PATHS = {
|
||||||
|
// Pacientes (já existia)
|
||||||
pacientes: "/pacientes",
|
pacientes: "/pacientes",
|
||||||
pacienteId: (id: string | number) => `/pacientes/${id}`,
|
pacienteId: (id: string | number) => `/pacientes/${id}`,
|
||||||
foto: (id: string | number) => `/pacientes/${id}/foto`,
|
foto: (id: string | number) => `/pacientes/${id}/foto`,
|
||||||
@ -70,8 +72,16 @@ const PATHS = {
|
|||||||
anexoId: (id: string | number, anexoId: string | number) => `/pacientes/${id}/anexos/${anexoId}`,
|
anexoId: (id: string | number, anexoId: string | number) => `/pacientes/${id}/anexos/${anexoId}`,
|
||||||
validarCPF: "/pacientes/validar-cpf",
|
validarCPF: "/pacientes/validar-cpf",
|
||||||
cep: (cep: string) => `/utils/cep/${cep}`,
|
cep: (cep: string) => `/utils/cep/${cep}`,
|
||||||
|
|
||||||
|
// Médicos (APONTANDO PARA PACIENTES por enquanto)
|
||||||
|
medicos: MEDICOS_BASE,
|
||||||
|
medicoId: (id: string | number) => `${MEDICOS_BASE}/${id}`,
|
||||||
|
medicoFoto: (id: string | number) => `${MEDICOS_BASE}/${id}/foto`,
|
||||||
|
medicoAnexos: (id: string | number) => `${MEDICOS_BASE}/${id}/anexos`,
|
||||||
|
medicoAnexoId: (id: string | number, anexoId: string | number) => `${MEDICOS_BASE}/${id}/anexos/${anexoId}`,
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|
||||||
function headers(kind: "json" | "form" = "json"): Record<string, string> {
|
function headers(kind: "json" | "form" = "json"): Record<string, string> {
|
||||||
const h: Record<string, string> = {};
|
const h: Record<string, string> = {};
|
||||||
const token = process.env.NEXT_PUBLIC_API_TOKEN?.trim();
|
const token = process.env.NEXT_PUBLIC_API_TOKEN?.trim();
|
||||||
@ -95,17 +105,22 @@ async function parse<T>(res: Response): Promise<T> {
|
|||||||
try {
|
try {
|
||||||
json = await res.json();
|
json = await res.json();
|
||||||
} catch {
|
} catch {
|
||||||
|
// ignora erro de parse vazio
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
// 🔴 ADICIONE ESSA LINHA AQUI:
|
||||||
|
console.error("[API ERROR]", res.url, res.status, json);
|
||||||
|
|
||||||
const code = json?.apidogError?.code ?? res.status;
|
const code = json?.apidogError?.code ?? res.status;
|
||||||
const msg = json?.apidogError?.message ?? res.statusText;
|
const msg = json?.apidogError?.message ?? res.statusText;
|
||||||
throw new Error(`${code}: ${msg}`);
|
throw new Error(`${code}: ${msg}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (json?.data ?? json) as T;
|
return (json?.data ?? json) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Pacientes (CRUD)
|
// Pacientes (CRUD)
|
||||||
//
|
//
|
||||||
@ -250,3 +265,150 @@ export async function buscarCepAPI(cep: string): Promise<{ logradouro?: string;
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// >>> ADICIONE (ou mova) ESTES TIPOS <<<
|
||||||
|
export type FormacaoAcademica = {
|
||||||
|
instituicao: string;
|
||||||
|
curso: string;
|
||||||
|
ano_conclusao: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DadosBancarios = {
|
||||||
|
banco: string;
|
||||||
|
agencia: string;
|
||||||
|
conta: string;
|
||||||
|
tipo_conta: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Medico = {
|
||||||
|
id: string;
|
||||||
|
nome?: string;
|
||||||
|
nome_social?: string | null;
|
||||||
|
cpf?: string;
|
||||||
|
rg?: string | null;
|
||||||
|
sexo?: string | null;
|
||||||
|
data_nascimento?: string | null;
|
||||||
|
telefone?: string;
|
||||||
|
celular?: string;
|
||||||
|
contato_emergencia?: string;
|
||||||
|
email?: string;
|
||||||
|
crm?: string;
|
||||||
|
estado_crm?: string;
|
||||||
|
rqe?: string;
|
||||||
|
formacao_academica?: FormacaoAcademica[];
|
||||||
|
curriculo_url?: string | null;
|
||||||
|
especialidade?: string;
|
||||||
|
observacoes?: string | null;
|
||||||
|
foto_url?: string | null;
|
||||||
|
tipo_vinculo?: string;
|
||||||
|
dados_bancarios?: DadosBancarios;
|
||||||
|
agenda_horario?: string;
|
||||||
|
valor_consulta?: number | string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MedicoInput = {
|
||||||
|
nome: string;
|
||||||
|
nome_social?: string | null;
|
||||||
|
cpf?: string | null;
|
||||||
|
rg?: string | null;
|
||||||
|
sexo?: string | null;
|
||||||
|
data_nascimento?: string | null;
|
||||||
|
telefone?: string | null;
|
||||||
|
celular?: string | null;
|
||||||
|
contato_emergencia?: string | null;
|
||||||
|
email?: string | null;
|
||||||
|
crm: string;
|
||||||
|
estado_crm?: string | null;
|
||||||
|
rqe?: string | null;
|
||||||
|
formacao_academica?: FormacaoAcademica[];
|
||||||
|
curriculo_url?: string | null;
|
||||||
|
especialidade: string;
|
||||||
|
observacoes?: string | null;
|
||||||
|
tipo_vinculo?: string | null;
|
||||||
|
dados_bancarios?: DadosBancarios | null;
|
||||||
|
agenda_horario?: string | null;
|
||||||
|
valor_consulta?: number | string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// MÉDICOS (CRUD)
|
||||||
|
//
|
||||||
|
// ======= MÉDICOS (forçando usar rotas de PACIENTES no mock) =======
|
||||||
|
|
||||||
|
export async function listarMedicos(params?: { page?: number; limit?: number; q?: string }): Promise<Medico[]> {
|
||||||
|
const query = new URLSearchParams();
|
||||||
|
if (params?.page) query.set("page", String(params.page));
|
||||||
|
if (params?.limit) query.set("limit", String(params.limit));
|
||||||
|
if (params?.q) query.set("q", params.q);
|
||||||
|
|
||||||
|
// FORÇA /pacientes
|
||||||
|
const url = `${API_BASE}/pacientes${query.toString() ? `?${query.toString()}` : ""}`;
|
||||||
|
const res = await fetch(url, { method: "GET", headers: headers("json") });
|
||||||
|
const data = await parse<ApiOk<Medico[]>>(res);
|
||||||
|
return (data as any)?.data ?? (data as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function buscarMedicoPorId(id: string | number): Promise<Medico> {
|
||||||
|
const url = `${API_BASE}/pacientes/${id}`; // FORÇA /pacientes
|
||||||
|
const res = await fetch(url, { method: "GET", headers: headers("json") });
|
||||||
|
const data = await parse<ApiOk<Medico>>(res);
|
||||||
|
return (data as any)?.data ?? (data as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function criarMedico(input: MedicoInput): Promise<Medico> {
|
||||||
|
const url = `${API_BASE}/pacientes`; // FORÇA /pacientes
|
||||||
|
const res = await fetch(url, { method: "POST", headers: headers("json"), body: JSON.stringify(input) });
|
||||||
|
const data = await parse<ApiOk<Medico>>(res);
|
||||||
|
return (data as any)?.data ?? (data as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function atualizarMedico(id: string | number, input: MedicoInput): Promise<Medico> {
|
||||||
|
const url = `${API_BASE}/pacientes/${id}`; // FORÇA /pacientes
|
||||||
|
const res = await fetch(url, { method: "PUT", headers: headers("json"), body: JSON.stringify(input) });
|
||||||
|
const data = await parse<ApiOk<Medico>>(res);
|
||||||
|
return (data as any)?.data ?? (data as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function excluirMedico(id: string | number): Promise<void> {
|
||||||
|
const url = `${API_BASE}/pacientes/${id}`; // FORÇA /pacientes
|
||||||
|
const res = await fetch(url, { method: "DELETE", headers: headers("json") });
|
||||||
|
await parse<any>(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function uploadFotoMedico(id: string | number, file: File): Promise<{ foto_url?: string; thumbnail_url?: string }> {
|
||||||
|
const url = `${API_BASE}/pacientes/${id}/foto`; // FORÇA /pacientes
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append("foto", file);
|
||||||
|
const res = await fetch(url, { method: "POST", headers: headers("form"), body: fd });
|
||||||
|
const data = await parse<ApiOk<{ foto_url?: string; thumbnail_url?: string }>>(res);
|
||||||
|
return (data as any)?.data ?? (data as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function removerFotoMedico(id: string | number): Promise<void> {
|
||||||
|
const url = `${API_BASE}/pacientes/${id}/foto`; // FORÇA /pacientes
|
||||||
|
const res = await fetch(url, { method: "DELETE", headers: headers("json") });
|
||||||
|
await parse<any>(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function listarAnexosMedico(id: string | number): Promise<any[]> {
|
||||||
|
const url = `${API_BASE}/pacientes/${id}/anexos`; // FORÇA /pacientes
|
||||||
|
const res = await fetch(url, { method: "GET", headers: headers("json") });
|
||||||
|
const data = await parse<ApiOk<any[]>>(res);
|
||||||
|
return (data as any)?.data ?? (data as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function adicionarAnexoMedico(id: string | number, file: File): Promise<any> {
|
||||||
|
const url = `${API_BASE}/pacientes/${id}/anexos`; // FORÇA /pacientes
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append("arquivo", file);
|
||||||
|
const res = await fetch(url, { method: "POST", headers: headers("form"), body: fd });
|
||||||
|
const data = await parse<ApiOk<any>>(res);
|
||||||
|
return (data as any)?.data ?? (data as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function removerAnexoMedico(id: string | number, anexoId: string | number): Promise<void> {
|
||||||
|
const url = `${API_BASE}/pacientes/${id}/anexos/${anexoId}`; // FORÇA /pacientes
|
||||||
|
const res = await fetch(url, { method: "DELETE", headers: headers("json") });
|
||||||
|
await parse<any>(res);
|
||||||
|
}
|
||||||
|
// ======= FIM: médicos usando rotas de pacientes =======
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user