add-userID
This commit is contained in:
parent
8bf953a689
commit
1a471357b7
@ -7,12 +7,13 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { MoreHorizontal, Plus, Search, Edit, Trash2, ArrowLeft, Eye } from "lucide-react";
|
||||
import { MoreHorizontal, Plus, Search, Edit, Trash2, ArrowLeft, Eye, Users } from "lucide-react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { DoctorRegistrationForm } from "@/components/forms/doctor-registration-form";
|
||||
|
||||
|
||||
import { listarMedicos, excluirMedico, buscarMedicos, buscarMedicoPorId, Medico } from "@/lib/api";
|
||||
import { listarMedicos, excluirMedico, buscarMedicos, buscarMedicoPorId, buscarPacientesPorIds, Medico } from "@/lib/api";
|
||||
import { listAssignmentsForUser } from '@/lib/assignment';
|
||||
|
||||
function normalizeMedico(m: any): Medico {
|
||||
return {
|
||||
@ -64,6 +65,10 @@ export default function DoutoresPage() {
|
||||
const [showForm, setShowForm] = useState(false);
|
||||
const [editingId, setEditingId] = useState<string | null>(null);
|
||||
const [viewingDoctor, setViewingDoctor] = useState<Medico | null>(null);
|
||||
const [assignedDialogOpen, setAssignedDialogOpen] = useState(false);
|
||||
const [assignedPatients, setAssignedPatients] = useState<any[]>([]);
|
||||
const [assignedLoading, setAssignedLoading] = useState(false);
|
||||
const [assignedDoctor, setAssignedDoctor] = useState<Medico | null>(null);
|
||||
const [searchResults, setSearchResults] = useState<Medico[]>([]);
|
||||
const [searchMode, setSearchMode] = useState(false);
|
||||
const [searchTimeout, setSearchTimeout] = useState<NodeJS.Timeout | null>(null);
|
||||
@ -179,7 +184,7 @@ export default function DoutoresPage() {
|
||||
|
||||
// Handler para o botão de busca
|
||||
function handleClickBuscar() {
|
||||
handleBuscarServidor();
|
||||
void handleBuscarServidor();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@ -253,6 +258,28 @@ export default function DoutoresPage() {
|
||||
setViewingDoctor(doctor);
|
||||
}
|
||||
|
||||
async function handleViewAssignedPatients(doctor: Medico) {
|
||||
setAssignedDoctor(doctor);
|
||||
setAssignedLoading(true);
|
||||
setAssignedPatients([]);
|
||||
try {
|
||||
const assigns = await listAssignmentsForUser(String(doctor.user_id ?? doctor.id));
|
||||
const patientIds = Array.isArray(assigns) ? assigns.map((a:any) => String(a.patient_id)).filter(Boolean) : [];
|
||||
if (patientIds.length) {
|
||||
const patients = await buscarPacientesPorIds(patientIds);
|
||||
setAssignedPatients(patients || []);
|
||||
} else {
|
||||
setAssignedPatients([]);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[DoutoresPage] erro ao carregar pacientes atribuídos:', e);
|
||||
setAssignedPatients([]);
|
||||
} finally {
|
||||
setAssignedLoading(false);
|
||||
setAssignedDialogOpen(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function handleDelete(id: string) {
|
||||
if (!confirm("Excluir este médico?")) return;
|
||||
@ -326,9 +353,9 @@ export default function DoutoresPage() {
|
||||
onKeyDown={handleSearchKeyDown}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={handleBuscarServidor}
|
||||
onClick={() => void handleBuscarServidor()}
|
||||
disabled={loading}
|
||||
className="hover:bg-primary hover:text-white"
|
||||
>
|
||||
@ -394,11 +421,18 @@ export default function DoutoresPage() {
|
||||
<span className="sr-only">Abrir menu</span>
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => handleView(doctor)}>
|
||||
<Eye className="mr-2 h-4 w-4" />
|
||||
Ver
|
||||
</DropdownMenuItem>
|
||||
|
||||
{/* Ver pacientes atribuídos ao médico */}
|
||||
<DropdownMenuItem onClick={() => handleViewAssignedPatients(doctor)}>
|
||||
<Users className="mr-2 h-4 w-4" />
|
||||
Ver pacientes atribuídos
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem onClick={() => handleEdit(String(doctor.id))}>
|
||||
<Edit className="mr-2 h-4 w-4" />
|
||||
Editar
|
||||
@ -466,6 +500,36 @@ export default function DoutoresPage() {
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Mostrando {displayedDoctors.length} {searchMode ? 'resultado(s) da busca' : `de ${doctors.length}`}
|
||||
</div>
|
||||
{/* Dialog para pacientes atribuídos */}
|
||||
<Dialog open={assignedDialogOpen} onOpenChange={(open) => { if (!open) { setAssignedDialogOpen(false); setAssignedPatients([]); setAssignedDoctor(null); } }}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Pacientes atribuídos{assignedDoctor ? ` - ${assignedDoctor.full_name}` : ''}</DialogTitle>
|
||||
<DialogDescription>
|
||||
Lista de pacientes atribuídos a este médico.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="py-4">
|
||||
{assignedLoading ? (
|
||||
<div>Carregando pacientes...</div>
|
||||
) : assignedPatients && assignedPatients.length ? (
|
||||
<div className="space-y-2">
|
||||
{assignedPatients.map((p:any) => (
|
||||
<div key={p.id} className="p-2 border rounded">
|
||||
<div className="font-medium">{p.full_name ?? p.nome ?? p.name ?? '(sem nome)'}</div>
|
||||
<div className="text-xs text-muted-foreground">ID: {p.id} {p.cpf ? `• CPF: ${p.cpf}` : ''}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div>Nenhum paciente atribuído encontrado.</div>
|
||||
)}
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button onClick={() => setAssignedDialogOpen(false)}>Fechar</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -207,7 +207,7 @@ export default function PacientesPage() {
|
||||
onKeyDown={(e) => e.key === "Enter" && handleBuscarServidor()}
|
||||
/>
|
||||
</div>
|
||||
<Button variant="secondary" onClick={handleBuscarServidor} className="hover:bg-primary hover:text-white">Buscar</Button>
|
||||
<Button variant="secondary" onClick={() => void handleBuscarServidor()} className="hover:bg-primary hover:text-white">Buscar</Button>
|
||||
<Button onClick={handleAdd}>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
Novo paciente
|
||||
|
||||
@ -751,19 +751,37 @@ const ProfissionalPage = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// carregar relatórios para cada paciente encontrado (useReports não tem batch by multiple ids, então carregamos por paciente)
|
||||
const allReports: any[] = [];
|
||||
for (const pid of patientIds) {
|
||||
try {
|
||||
const rels = await import('@/lib/reports').then(m => m.listarRelatoriosPorPaciente(pid));
|
||||
if (Array.isArray(rels)) allReports.push(...rels);
|
||||
} catch (err) {
|
||||
console.warn('[LaudoManager] falha ao carregar relatórios para paciente', pid, err);
|
||||
// Tentar carregar todos os relatórios em uma única chamada usando in.(...)
|
||||
try {
|
||||
const reportsMod = await import('@/lib/reports');
|
||||
if (typeof reportsMod.listarRelatoriosPorPacientes === 'function') {
|
||||
const batch = await reportsMod.listarRelatoriosPorPacientes(patientIds);
|
||||
if (mounted) setLaudos(batch || []);
|
||||
} else {
|
||||
// fallback: 请求 por paciente individual
|
||||
const allReports: any[] = [];
|
||||
for (const pid of patientIds) {
|
||||
try {
|
||||
const rels = await import('@/lib/reports').then(m => m.listarRelatoriosPorPaciente(pid));
|
||||
if (Array.isArray(rels)) allReports.push(...rels);
|
||||
} catch (err) {
|
||||
console.warn('[LaudoManager] falha ao carregar relatórios para paciente', pid, err);
|
||||
}
|
||||
}
|
||||
if (mounted) setLaudos(allReports);
|
||||
}
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
setLaudos(allReports);
|
||||
} catch (err) {
|
||||
console.warn('[LaudoManager] erro ao carregar relatórios em batch, tentando por paciente individual', err);
|
||||
const allReports: any[] = [];
|
||||
for (const pid of patientIds) {
|
||||
try {
|
||||
const rels = await import('@/lib/reports').then(m => m.listarRelatoriosPorPaciente(pid));
|
||||
if (Array.isArray(rels)) allReports.push(...rels);
|
||||
} catch (e) {
|
||||
console.warn('[LaudoManager] falha ao carregar relatórios para paciente', pid, e);
|
||||
}
|
||||
}
|
||||
if (mounted) setLaudos(allReports);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[LaudoManager] erro ao carregar laudos para pacientes atribuídos:', e);
|
||||
|
||||
@ -9,6 +9,7 @@ import { Input } from "@/components/ui/input";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
|
||||
import { assignRoleToUser, listAssignmentsForPatient, PatientAssignmentRole } from "@/lib/assignment";
|
||||
import { useAuth } from '@/hooks/useAuth';
|
||||
import { listarProfissionais } from "@/lib/api";
|
||||
|
||||
type Props = {
|
||||
@ -20,6 +21,7 @@ type Props = {
|
||||
|
||||
export default function AssignmentForm({ patientId, open, onClose, onSaved }: Props) {
|
||||
const { toast } = useToast();
|
||||
const { user } = useAuth();
|
||||
const [professionals, setProfessionals] = useState<any[]>([]);
|
||||
const [selectedProfessional, setSelectedProfessional] = useState<string | null>(null);
|
||||
// default to Portuguese role values expected by the backend
|
||||
@ -52,8 +54,8 @@ export default function AssignmentForm({ patientId, open, onClose, onSaved }: Pr
|
||||
if (!selectedProfessional) return toast({ title: 'Selecione um profissional', variant: 'default' });
|
||||
setLoading(true);
|
||||
try {
|
||||
await assignRoleToUser({ patient_id: patientId, user_id: selectedProfessional, role });
|
||||
toast({ title: 'Atribuição criada', variant: 'default' });
|
||||
await assignRoleToUser({ patient_id: patientId, user_id: String(selectedProfessional), role, created_by: user?.id ?? null });
|
||||
toast({ title: 'Atribuição criada', variant: 'default' });
|
||||
onSaved && onSaved();
|
||||
onClose();
|
||||
} catch (err: any) {
|
||||
@ -80,7 +82,8 @@ export default function AssignmentForm({ patientId, open, onClose, onSaved }: Pr
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{professionals.map((p) => (
|
||||
<SelectItem key={p.id} value={String(p.id)}>{p.full_name || p.name || p.email || p.id}</SelectItem>
|
||||
// prefer the auth user id (p.user_id) when available; fallback to p.id
|
||||
<SelectItem key={p.id} value={String(p.user_id ?? p.id)}>{p.full_name || p.name || p.email || p.user_id || p.id}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
@ -173,6 +173,10 @@ export function DoctorRegistrationForm({
|
||||
console.log("[DoctorForm] Carregando médico ID:", doctorId);
|
||||
const medico = await buscarMedicoPorId(String(doctorId));
|
||||
console.log("[DoctorForm] Dados recebidos do API:", medico);
|
||||
if (!medico) {
|
||||
console.warn('[DoctorForm] Médico não encontrado para ID:', doctorId);
|
||||
return;
|
||||
}
|
||||
console.log("[DoctorForm] Campos principais:", {
|
||||
full_name: medico.full_name,
|
||||
crm: medico.crm,
|
||||
@ -411,16 +415,35 @@ async function handleSubmit(ev: React.FormEvent) {
|
||||
// 2. Cria usuário no Supabase Auth (direto via /auth/v1/signup)
|
||||
console.log('🔐 Criando usuário de autenticação...');
|
||||
|
||||
try {
|
||||
try {
|
||||
const authResponse = await criarUsuarioMedico({
|
||||
email: form.email,
|
||||
full_name: form.full_name,
|
||||
phone_mobile: form.celular || '',
|
||||
});
|
||||
|
||||
|
||||
if (authResponse.success && authResponse.user) {
|
||||
console.log('✅ Usuário Auth criado:', authResponse.user.id);
|
||||
|
||||
|
||||
// Attempt to link the created auth user id to the doctors record
|
||||
try {
|
||||
// savedDoctorProfile may be an array or object depending on API
|
||||
const docId = (savedDoctorProfile && (savedDoctorProfile.id || (Array.isArray(savedDoctorProfile) ? savedDoctorProfile[0]?.id : undefined))) || null;
|
||||
if (docId) {
|
||||
console.log('[DoctorForm] Vinculando user_id ao médico:', { doctorId: docId, userId: authResponse.user.id });
|
||||
// dynamic import to avoid circular deps in some bundlers
|
||||
const api = await import('@/lib/api');
|
||||
if (api && typeof api.vincularUserIdMedico === 'function') {
|
||||
await api.vincularUserIdMedico(String(docId), String(authResponse.user.id));
|
||||
console.log('[DoctorForm] user_id vinculado com sucesso.');
|
||||
}
|
||||
} else {
|
||||
console.warn('[DoctorForm] Não foi possível determinar o ID do médico para vincular user_id. Doctor profile:', savedDoctorProfile);
|
||||
}
|
||||
} catch (linkErr) {
|
||||
console.warn('[DoctorForm] Falha ao vincular user_id ao médico:', linkErr);
|
||||
}
|
||||
|
||||
// 3. Exibe popup com credenciais
|
||||
setCredentials({
|
||||
email: authResponse.email,
|
||||
@ -429,18 +452,18 @@ async function handleSubmit(ev: React.FormEvent) {
|
||||
userType: 'médico',
|
||||
});
|
||||
setShowCredentialsDialog(true);
|
||||
|
||||
|
||||
// 4. Limpa formulário
|
||||
setForm(initial);
|
||||
setPhotoPreview(null);
|
||||
setServerAnexos([]);
|
||||
|
||||
|
||||
// 5. Notifica componente pai
|
||||
onSaved?.(savedDoctorProfile);
|
||||
} else {
|
||||
throw new Error('Falha ao criar usuário de autenticação');
|
||||
}
|
||||
|
||||
|
||||
} catch (authError: any) {
|
||||
console.error('❌ Erro ao criar usuário Auth:', authError);
|
||||
|
||||
|
||||
@ -296,6 +296,24 @@ export function PatientRegistrationForm({
|
||||
});
|
||||
setShowCredentialsDialog(true);
|
||||
|
||||
// Tenta vincular o user_id ao perfil do paciente recém-criado
|
||||
try {
|
||||
const apiMod = await import('@/lib/api');
|
||||
const pacienteId = savedPatientProfile?.id || (savedPatientProfile && (savedPatientProfile as any).id);
|
||||
const userId = (userResponse.user as any)?.id || (userResponse.user as any)?.user_id || (userResponse.user as any)?.id;
|
||||
if (pacienteId && userId && typeof apiMod.vincularUserIdPaciente === 'function') {
|
||||
console.log('[PatientForm] Vinculando user_id ao paciente:', pacienteId, userId);
|
||||
try {
|
||||
await apiMod.vincularUserIdPaciente(pacienteId, String(userId));
|
||||
console.log('[PatientForm] user_id vinculado com sucesso ao paciente');
|
||||
} catch (linkErr) {
|
||||
console.warn('[PatientForm] Falha ao vincular user_id ao paciente:', linkErr);
|
||||
}
|
||||
}
|
||||
} catch (dynErr) {
|
||||
console.warn('[PatientForm] Não foi possível importar helper para vincular user_id:', dynErr);
|
||||
}
|
||||
|
||||
// Limpa formulário mas NÃO fecha ainda - fechará quando o dialog de credenciais fechar
|
||||
setForm(initial);
|
||||
setPhotoPreview(null);
|
||||
|
||||
@ -859,6 +859,39 @@ export async function criarMedico(input: MedicoInput): Promise<Medico> {
|
||||
return Array.isArray(arr) ? arr[0] : (arr as Medico); // Retorno do médico
|
||||
}
|
||||
|
||||
/**
|
||||
* Vincula um user_id (auth user id) a um registro de médico existente.
|
||||
* Retorna o médico atualizado.
|
||||
*/
|
||||
export async function vincularUserIdMedico(medicoId: string | number, userId: string): Promise<Medico> {
|
||||
const url = `${REST}/doctors?id=eq.${encodeURIComponent(String(medicoId))}`;
|
||||
const payload = { user_id: String(userId) };
|
||||
const res = await fetch(url, {
|
||||
method: 'PATCH',
|
||||
headers: withPrefer({ ...baseHeaders(), 'Content-Type': 'application/json' }, 'return=representation'),
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
const arr = await parse<Medico[] | Medico>(res);
|
||||
return Array.isArray(arr) ? arr[0] : (arr as Medico);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Vincula um user_id (auth user id) a um registro de paciente existente.
|
||||
* Retorna o paciente atualizado.
|
||||
*/
|
||||
export async function vincularUserIdPaciente(pacienteId: string | number, userId: string): Promise<Paciente> {
|
||||
const url = `${REST}/patients?id=eq.${encodeURIComponent(String(pacienteId))}`;
|
||||
const payload = { user_id: String(userId) };
|
||||
const res = await fetch(url, {
|
||||
method: 'PATCH',
|
||||
headers: withPrefer({ ...baseHeaders(), 'Content-Type': 'application/json' }, 'return=representation'),
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
const arr = await parse<Paciente[] | Paciente>(res);
|
||||
return Array.isArray(arr) ? arr[0] : (arr as Paciente);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -13,14 +13,14 @@ export interface PatientAssignment {
|
||||
user_id: string;
|
||||
role: PatientAssignmentRole;
|
||||
created_at: string;
|
||||
created_by: string;
|
||||
created_by: string | null;
|
||||
}
|
||||
|
||||
export interface CreateAssignmentInput {
|
||||
patient_id: string;
|
||||
user_id: string;
|
||||
role: PatientAssignmentRole;
|
||||
created_by?: string;
|
||||
created_by?: string | null;
|
||||
}
|
||||
|
||||
// ===== CONSTANTES =====
|
||||
@ -140,7 +140,7 @@ export async function listAssignmentsForPatient(patientId: string): Promise<Pati
|
||||
*/
|
||||
export async function listAssignmentsForUser(userId: string): Promise<PatientAssignment[]> {
|
||||
console.log(`🔍 [ASSIGNMENT] Listando atribuições para o usuário: ${userId}`);
|
||||
const url = `${ASSIGNMENTS_URL}?user_id=eq.${userId}`;
|
||||
const url = `${ASSIGNMENTS_URL}?user_id=eq.${encodeURIComponent(userId)}`;
|
||||
|
||||
try {
|
||||
const headers = getHeaders();
|
||||
|
||||
@ -311,4 +311,69 @@ export async function listarRelatoriosPorMedico(idMedico: string): Promise<Repor
|
||||
console.error('❌ [API RELATÓRIOS] Erro ao buscar relatórios do médico:', erro);
|
||||
throw erro;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lista relatórios para vários pacientes em uma única chamada (usa in.(...)).
|
||||
* Retorna array vazio se nenhum id for fornecido.
|
||||
*/
|
||||
export async function listarRelatoriosPorPacientes(ids: string[]): Promise<Report[]> {
|
||||
try {
|
||||
if (!ids || !ids.length) return [];
|
||||
// sanitize ids and remove empties
|
||||
const cleaned = ids.map(i => String(i).trim()).filter(Boolean);
|
||||
if (!cleaned.length) return [];
|
||||
|
||||
// monta cláusula in.(id1,id2,...)
|
||||
const inClause = cleaned.join(',');
|
||||
const url = `${BASE_API_RELATORIOS}?patient_id=in.(${inClause})`;
|
||||
const headers = obterCabecalhos();
|
||||
const masked = (headers as any)['Authorization'] ? '<<masked>>' : undefined;
|
||||
console.debug('[listarRelatoriosPorPacientes] URL:', url);
|
||||
console.debug('[listarRelatoriosPorPacientes] Headers (masked):', { ...headers, Authorization: masked ? '<<masked>>' : undefined });
|
||||
|
||||
const resposta = await fetch(url, { method: 'GET', headers });
|
||||
const resultado = await tratarRespostaApi<Report[]>(resposta);
|
||||
console.log('✅ [API RELATÓRIOS] Relatórios encontrados para pacientes:', resultado.length);
|
||||
return resultado;
|
||||
} catch (erro) {
|
||||
console.error('❌ [API RELATÓRIOS] Erro ao buscar relatórios para vários pacientes:', erro);
|
||||
throw erro;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lista relatórios apenas para pacientes que foram atribuídos ao médico (userId).
|
||||
* - Recupera as atribuições via `listAssignmentsForUser(userId)`
|
||||
* - Extrai os patient_id e chama `listarRelatoriosPorPacientes` em batch
|
||||
*/
|
||||
export async function listarRelatoriosParaMedicoAtribuido(userId?: string): Promise<Report[]> {
|
||||
try {
|
||||
if (!userId) {
|
||||
console.warn('[listarRelatoriosParaMedicoAtribuido] userId ausente, retornando array vazio');
|
||||
return [];
|
||||
}
|
||||
|
||||
console.log('[listarRelatoriosParaMedicoAtribuido] buscando assignments para user:', userId);
|
||||
// importe dinamicamente para evitar possíveis ciclos
|
||||
const assignmentMod = await import('./assignment');
|
||||
const assigns = await assignmentMod.listAssignmentsForUser(String(userId));
|
||||
if (!assigns || !Array.isArray(assigns) || assigns.length === 0) {
|
||||
console.log('[listarRelatoriosParaMedicoAtribuido] nenhum paciente atribuído encontrado para user:', userId);
|
||||
return [];
|
||||
}
|
||||
|
||||
const patientIds = Array.from(new Set(assigns.map((a: any) => String(a.patient_id)).filter(Boolean)));
|
||||
if (!patientIds.length) {
|
||||
console.log('[listarRelatoriosParaMedicoAtribuido] nenhuma patient_id válida encontrada nas atribuições');
|
||||
return [];
|
||||
}
|
||||
|
||||
console.log('[listarRelatoriosParaMedicoAtribuido] carregando relatórios para pacientes:', patientIds);
|
||||
const rels = await listarRelatoriosPorPacientes(patientIds);
|
||||
return rels || [];
|
||||
} catch (err) {
|
||||
console.error('[listarRelatoriosParaMedicoAtribuido] erro:', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user