forked from RiseUP/riseup-squad20
add-assignament-endpoints
This commit is contained in:
parent
52c3e544f3
commit
8bf953a689
@ -317,6 +317,16 @@ export default function PacientesPage() {
|
|||||||
</Dialog>
|
</Dialog>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Assignment dialog */}
|
||||||
|
{assignDialogOpen && assignPatientId && (
|
||||||
|
<AssignmentForm
|
||||||
|
patientId={assignPatientId}
|
||||||
|
open={assignDialogOpen}
|
||||||
|
onClose={() => { setAssignDialogOpen(false); setAssignPatientId(null); }}
|
||||||
|
onSaved={() => { setAssignDialogOpen(false); setAssignPatientId(null); loadAll(); }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="text-sm text-muted-foreground">Mostrando {filtered.length} de {patients.length}</div>
|
<div className="text-sm text-muted-foreground">Mostrando {filtered.length} de {patients.length}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -737,23 +737,45 @@ const ProfissionalPage = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// carregar laudos ao montar
|
// carregar laudos ao montar - somente dos pacientes atribuídos ao médico logado
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let mounted = true;
|
let mounted = true;
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
await loadReports();
|
// obter assignments para o usuário logado
|
||||||
|
const assignments = await import('@/lib/assignment').then(m => m.listAssignmentsForUser(user?.id || ''));
|
||||||
|
const patientIds = Array.isArray(assignments) ? assignments.map(a => String(a.patient_id)).filter(Boolean) : [];
|
||||||
|
|
||||||
|
if (patientIds.length === 0) {
|
||||||
|
if (mounted) setLaudos([]);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setLaudos(allReports);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// erro tratado no hook
|
console.warn('[LaudoManager] erro ao carregar laudos para pacientes atribuídos:', e);
|
||||||
|
if (mounted) setLaudos(reports || []);
|
||||||
}
|
}
|
||||||
if (mounted) setLaudos(reports || []);
|
|
||||||
})();
|
})();
|
||||||
return () => { mounted = false; };
|
return () => { mounted = false; };
|
||||||
}, [loadReports]);
|
}, [user?.id]);
|
||||||
|
|
||||||
// sincroniza quando reports mudarem no hook
|
// sincroniza quando reports mudarem no hook (fallback)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLaudos(reports || []);
|
if (!laudos || laudos.length === 0) setLaudos(reports || []);
|
||||||
}, [reports]);
|
}, [reports]);
|
||||||
|
|
||||||
const [activeTab, setActiveTab] = useState("descobrir");
|
const [activeTab, setActiveTab] = useState("descobrir");
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
|
|||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { useToast } from "@/hooks/use-toast";
|
import { useToast } from "@/hooks/use-toast";
|
||||||
|
|
||||||
import { assignRoleToUser, listAssignmentsForPatient } from "@/lib/assignment";
|
import { assignRoleToUser, listAssignmentsForPatient, PatientAssignmentRole } from "@/lib/assignment";
|
||||||
import { listarProfissionais } from "@/lib/api";
|
import { listarProfissionais } from "@/lib/api";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -22,7 +22,8 @@ export default function AssignmentForm({ patientId, open, onClose, onSaved }: Pr
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const [professionals, setProfessionals] = useState<any[]>([]);
|
const [professionals, setProfessionals] = useState<any[]>([]);
|
||||||
const [selectedProfessional, setSelectedProfessional] = useState<string | null>(null);
|
const [selectedProfessional, setSelectedProfessional] = useState<string | null>(null);
|
||||||
const [role, setRole] = useState<string>("doctor");
|
// default to Portuguese role values expected by the backend
|
||||||
|
const [role, setRole] = useState<PatientAssignmentRole>("medico");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [existing, setExisting] = useState<any[]>([]);
|
const [existing, setExisting] = useState<any[]>([]);
|
||||||
|
|
||||||
@ -48,11 +49,11 @@ export default function AssignmentForm({ patientId, open, onClose, onSaved }: Pr
|
|||||||
}, [open, patientId]);
|
}, [open, patientId]);
|
||||||
|
|
||||||
async function handleSave() {
|
async function handleSave() {
|
||||||
if (!selectedProfessional) return toast({ title: 'Selecione um profissional', variant: 'warning' });
|
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: selectedProfessional, role });
|
||||||
toast({ title: 'Atribuição criada', variant: 'success' });
|
toast({ title: 'Atribuição criada', variant: 'default' });
|
||||||
onSaved && onSaved();
|
onSaved && onSaved();
|
||||||
onClose();
|
onClose();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
@ -87,8 +88,19 @@ export default function AssignmentForm({ patientId, open, onClose, onSaved }: Pr
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Label>Role</Label>
|
<Label>Role</Label>
|
||||||
<Input value={role} onChange={(e) => setRole(e.target.value)} />
|
<Input
|
||||||
<div className="text-xs text-muted-foreground mt-1">Ex: doctor, nurse</div>
|
value={role}
|
||||||
|
onChange={(e) => {
|
||||||
|
const v = String(e.target.value || '').toLowerCase().trim();
|
||||||
|
// Map common english values to portuguese expected by backend
|
||||||
|
if (v === 'doctor') return setRole('medico');
|
||||||
|
if (v === 'nurse') return setRole('enfermeiro');
|
||||||
|
if (v === 'medico' || v === 'enfermeiro') return setRole(v as PatientAssignmentRole);
|
||||||
|
// fallback: keep current role (ignore unknown input)
|
||||||
|
return setRole(role);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="text-xs text-muted-foreground mt-1">Ex: medico, enfermeiro (inglês: doctor → medico)</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{existing && existing.length > 0 && (
|
{existing && existing.length > 0 && (
|
||||||
|
|||||||
@ -838,6 +838,12 @@ export async function buscarMedicosPorIds(ids: Array<string | number>): Promise<
|
|||||||
return unique;
|
return unique;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Alias/backwards-compat: listarProfissionais usado por components
|
||||||
|
export async function listarProfissionais(params?: { page?: number; limit?: number; q?: string; }): Promise<Medico[]> {
|
||||||
|
// Reuse listarMedicos implementation to avoid duplication
|
||||||
|
return await listarMedicos(params);
|
||||||
|
}
|
||||||
|
|
||||||
// Dentro de lib/api.ts
|
// Dentro de lib/api.ts
|
||||||
export async function criarMedico(input: MedicoInput): Promise<Medico> {
|
export async function criarMedico(input: MedicoInput): Promise<Medico> {
|
||||||
console.log("Enviando os dados para a API:", input); // Log para depuração
|
console.log("Enviando os dados para a API:", input); // Log para depuração
|
||||||
|
|||||||
@ -78,7 +78,9 @@ export async function assignRoleToUser(input: CreateAssignmentInput): Promise<Pa
|
|||||||
statusText: response.statusText,
|
statusText: response.statusText,
|
||||||
body: errorBody,
|
body: errorBody,
|
||||||
});
|
});
|
||||||
throw new Error(`Erro ao atribuir função: ${response.statusText} (${response.status})`);
|
// Include body (when available) to help debugging (e.g., constraint violations)
|
||||||
|
const bodySnippet = errorBody ? ` - body: ${errorBody}` : '';
|
||||||
|
throw new Error(`Erro ao atribuir função: ${response.statusText} (${response.status})${bodySnippet}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const createdAssignment = await response.json();
|
const createdAssignment = await response.json();
|
||||||
@ -131,3 +133,52 @@ export async function listAssignmentsForPatient(patientId: string): Promise<Pati
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lista todas as atribuições para um dado usuário (médico/enfermeiro).
|
||||||
|
* Útil para obter os patient_id dos pacientes atribuídos ao usuário.
|
||||||
|
*/
|
||||||
|
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}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const headers = getHeaders();
|
||||||
|
console.debug('[ASSIGNMENT] GET', url, 'headers(masked)=', {
|
||||||
|
...headers,
|
||||||
|
Authorization: headers.Authorization ? '<<masked>>' : undefined,
|
||||||
|
});
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
// dump raw text for debugging when content-type isn't JSON or when empty
|
||||||
|
const contentType = response.headers.get('content-type') || '';
|
||||||
|
const txt = await response.clone().text().catch(() => '');
|
||||||
|
console.debug('[ASSIGNMENT] response status=', response.status, response.statusText, 'content-type=', contentType, 'bodyPreview=', txt ? (txt.length > 1000 ? txt.slice(0,1000) + '...[truncated]' : txt) : '<empty>');
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorBody = txt || '';
|
||||||
|
console.error("❌ [ASSIGNMENT] Erro ao listar atribuições por usuário:", {
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
body: errorBody,
|
||||||
|
});
|
||||||
|
throw new Error(`Erro ao listar atribuições por usuário: ${response.status} ${response.statusText} - body: ${errorBody}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let assignments: any = [];
|
||||||
|
try {
|
||||||
|
assignments = await response.json();
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('[ASSIGNMENT] não foi possível parsear JSON, usando texto cru como fallback');
|
||||||
|
assignments = txt ? JSON.parse(txt) : [];
|
||||||
|
}
|
||||||
|
console.log(`✅ [ASSIGNMENT] ${Array.isArray(assignments) ? assignments.length : 0} atribuições encontradas para o usuário.`);
|
||||||
|
return Array.isArray(assignments) ? assignments : [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ [ASSIGNMENT] Erro inesperado ao listar atribuições por usuário:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user