forked from RiseUP/riseup-squad20
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 { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
|
||||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
|
||||||
import { Label } from "@/components/ui/label";
|
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 { Badge } from "@/components/ui/badge";
|
||||||
import { DoctorRegistrationForm } from "@/components/forms/doctor-registration-form";
|
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 {
|
function normalizeMedico(m: any): Medico {
|
||||||
return {
|
return {
|
||||||
@ -64,6 +65,10 @@ export default function DoutoresPage() {
|
|||||||
const [showForm, setShowForm] = useState(false);
|
const [showForm, setShowForm] = useState(false);
|
||||||
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);
|
||||||
|
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 [searchResults, setSearchResults] = useState<Medico[]>([]);
|
||||||
const [searchMode, setSearchMode] = useState(false);
|
const [searchMode, setSearchMode] = useState(false);
|
||||||
const [searchTimeout, setSearchTimeout] = useState<NodeJS.Timeout | null>(null);
|
const [searchTimeout, setSearchTimeout] = useState<NodeJS.Timeout | null>(null);
|
||||||
@ -179,7 +184,7 @@ export default function DoutoresPage() {
|
|||||||
|
|
||||||
// Handler para o botão de busca
|
// Handler para o botão de busca
|
||||||
function handleClickBuscar() {
|
function handleClickBuscar() {
|
||||||
handleBuscarServidor();
|
void handleBuscarServidor();
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -253,6 +258,28 @@ export default function DoutoresPage() {
|
|||||||
setViewingDoctor(doctor);
|
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) {
|
async function handleDelete(id: string) {
|
||||||
if (!confirm("Excluir este médico?")) return;
|
if (!confirm("Excluir este médico?")) return;
|
||||||
@ -328,7 +355,7 @@ export default function DoutoresPage() {
|
|||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={handleBuscarServidor}
|
onClick={() => void handleBuscarServidor()}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
className="hover:bg-primary hover:text-white"
|
className="hover:bg-primary hover:text-white"
|
||||||
>
|
>
|
||||||
@ -394,11 +421,18 @@ export default function DoutoresPage() {
|
|||||||
<span className="sr-only">Abrir menu</span>
|
<span className="sr-only">Abrir menu</span>
|
||||||
</button>
|
</button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent align="end">
|
<DropdownMenuContent align="end">
|
||||||
<DropdownMenuItem onClick={() => handleView(doctor)}>
|
<DropdownMenuItem onClick={() => handleView(doctor)}>
|
||||||
<Eye className="mr-2 h-4 w-4" />
|
<Eye className="mr-2 h-4 w-4" />
|
||||||
Ver
|
Ver
|
||||||
</DropdownMenuItem>
|
</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))}>
|
<DropdownMenuItem onClick={() => handleEdit(String(doctor.id))}>
|
||||||
<Edit className="mr-2 h-4 w-4" />
|
<Edit className="mr-2 h-4 w-4" />
|
||||||
Editar
|
Editar
|
||||||
@ -466,6 +500,36 @@ export default function DoutoresPage() {
|
|||||||
<div className="text-sm text-muted-foreground">
|
<div className="text-sm text-muted-foreground">
|
||||||
Mostrando {displayedDoctors.length} {searchMode ? 'resultado(s) da busca' : `de ${doctors.length}`}
|
Mostrando {displayedDoctors.length} {searchMode ? 'resultado(s) da busca' : `de ${doctors.length}`}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -207,7 +207,7 @@ export default function PacientesPage() {
|
|||||||
onKeyDown={(e) => e.key === "Enter" && handleBuscarServidor()}
|
onKeyDown={(e) => e.key === "Enter" && handleBuscarServidor()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</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}>
|
<Button onClick={handleAdd}>
|
||||||
<Plus className="mr-2 h-4 w-4" />
|
<Plus className="mr-2 h-4 w-4" />
|
||||||
Novo paciente
|
Novo paciente
|
||||||
|
|||||||
@ -751,19 +751,37 @@ const ProfissionalPage = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// carregar relatórios para cada paciente encontrado (useReports não tem batch by multiple ids, então carregamos por paciente)
|
// Tentar carregar todos os relatórios em uma única chamada usando in.(...)
|
||||||
const allReports: any[] = [];
|
try {
|
||||||
for (const pid of patientIds) {
|
const reportsMod = await import('@/lib/reports');
|
||||||
try {
|
if (typeof reportsMod.listarRelatoriosPorPacientes === 'function') {
|
||||||
const rels = await import('@/lib/reports').then(m => m.listarRelatoriosPorPaciente(pid));
|
const batch = await reportsMod.listarRelatoriosPorPacientes(patientIds);
|
||||||
if (Array.isArray(rels)) allReports.push(...rels);
|
if (mounted) setLaudos(batch || []);
|
||||||
} catch (err) {
|
} else {
|
||||||
console.warn('[LaudoManager] falha ao carregar relatórios para paciente', pid, err);
|
// 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);
|
||||||
}
|
}
|
||||||
}
|
} catch (err) {
|
||||||
|
console.warn('[LaudoManager] erro ao carregar relatórios em batch, tentando por paciente individual', err);
|
||||||
if (mounted) {
|
const allReports: any[] = [];
|
||||||
setLaudos(allReports);
|
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) {
|
} catch (e) {
|
||||||
console.warn('[LaudoManager] erro ao carregar laudos para pacientes atribuídos:', 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 { useToast } from "@/hooks/use-toast";
|
||||||
|
|
||||||
import { assignRoleToUser, listAssignmentsForPatient, PatientAssignmentRole } from "@/lib/assignment";
|
import { assignRoleToUser, listAssignmentsForPatient, PatientAssignmentRole } from "@/lib/assignment";
|
||||||
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { listarProfissionais } from "@/lib/api";
|
import { listarProfissionais } from "@/lib/api";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -20,6 +21,7 @@ type Props = {
|
|||||||
|
|
||||||
export default function AssignmentForm({ patientId, open, onClose, onSaved }: Props) {
|
export default function AssignmentForm({ patientId, open, onClose, onSaved }: Props) {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const { user } = useAuth();
|
||||||
const [professionals, setProfessionals] = useState<any[]>([]);
|
const [professionals, setProfessionals] = useState<any[]>([]);
|
||||||
const [selectedProfessional, setSelectedProfessional] = useState<string | null>(null);
|
const [selectedProfessional, setSelectedProfessional] = useState<string | null>(null);
|
||||||
// default to Portuguese role values expected by the backend
|
// 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' });
|
if (!selectedProfessional) return toast({ title: 'Selecione um profissional', variant: 'default' });
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
await assignRoleToUser({ patient_id: patientId, user_id: selectedProfessional, role });
|
await assignRoleToUser({ patient_id: patientId, user_id: String(selectedProfessional), role, created_by: user?.id ?? null });
|
||||||
toast({ title: 'Atribuição criada', variant: 'default' });
|
toast({ title: 'Atribuição criada', variant: 'default' });
|
||||||
onSaved && onSaved();
|
onSaved && onSaved();
|
||||||
onClose();
|
onClose();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
@ -80,7 +82,8 @@ export default function AssignmentForm({ patientId, open, onClose, onSaved }: Pr
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{professionals.map((p) => (
|
{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>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
@ -173,6 +173,10 @@ export function DoctorRegistrationForm({
|
|||||||
console.log("[DoctorForm] Carregando médico ID:", doctorId);
|
console.log("[DoctorForm] Carregando médico ID:", doctorId);
|
||||||
const medico = await buscarMedicoPorId(String(doctorId));
|
const medico = await buscarMedicoPorId(String(doctorId));
|
||||||
console.log("[DoctorForm] Dados recebidos do API:", medico);
|
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:", {
|
console.log("[DoctorForm] Campos principais:", {
|
||||||
full_name: medico.full_name,
|
full_name: medico.full_name,
|
||||||
crm: medico.crm,
|
crm: medico.crm,
|
||||||
@ -411,7 +415,7 @@ async function handleSubmit(ev: React.FormEvent) {
|
|||||||
// 2. Cria usuário no Supabase Auth (direto via /auth/v1/signup)
|
// 2. Cria usuário no Supabase Auth (direto via /auth/v1/signup)
|
||||||
console.log('🔐 Criando usuário de autenticação...');
|
console.log('🔐 Criando usuário de autenticação...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const authResponse = await criarUsuarioMedico({
|
const authResponse = await criarUsuarioMedico({
|
||||||
email: form.email,
|
email: form.email,
|
||||||
full_name: form.full_name,
|
full_name: form.full_name,
|
||||||
@ -421,6 +425,25 @@ async function handleSubmit(ev: React.FormEvent) {
|
|||||||
if (authResponse.success && authResponse.user) {
|
if (authResponse.success && authResponse.user) {
|
||||||
console.log('✅ Usuário Auth criado:', authResponse.user.id);
|
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
|
// 3. Exibe popup com credenciais
|
||||||
setCredentials({
|
setCredentials({
|
||||||
email: authResponse.email,
|
email: authResponse.email,
|
||||||
|
|||||||
@ -296,6 +296,24 @@ export function PatientRegistrationForm({
|
|||||||
});
|
});
|
||||||
setShowCredentialsDialog(true);
|
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
|
// Limpa formulário mas NÃO fecha ainda - fechará quando o dialog de credenciais fechar
|
||||||
setForm(initial);
|
setForm(initial);
|
||||||
setPhotoPreview(null);
|
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
|
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;
|
user_id: string;
|
||||||
role: PatientAssignmentRole;
|
role: PatientAssignmentRole;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
created_by: string;
|
created_by: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateAssignmentInput {
|
export interface CreateAssignmentInput {
|
||||||
patient_id: string;
|
patient_id: string;
|
||||||
user_id: string;
|
user_id: string;
|
||||||
role: PatientAssignmentRole;
|
role: PatientAssignmentRole;
|
||||||
created_by?: string;
|
created_by?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== CONSTANTES =====
|
// ===== CONSTANTES =====
|
||||||
@ -140,7 +140,7 @@ export async function listAssignmentsForPatient(patientId: string): Promise<Pati
|
|||||||
*/
|
*/
|
||||||
export async function listAssignmentsForUser(userId: string): Promise<PatientAssignment[]> {
|
export async function listAssignmentsForUser(userId: string): Promise<PatientAssignment[]> {
|
||||||
console.log(`🔍 [ASSIGNMENT] Listando atribuições para o usuário: ${userId}`);
|
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 {
|
try {
|
||||||
const headers = getHeaders();
|
const headers = getHeaders();
|
||||||
|
|||||||
@ -312,3 +312,68 @@ export async function listarRelatoriosPorMedico(idMedico: string): Promise<Repor
|
|||||||
throw 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