forked from RiseUP/riseup-squad23
333 lines
10 KiB
JavaScript
333 lines
10 KiB
JavaScript
import React, { useState, useEffect, useMemo } from "react";
|
|
import { useParams, useNavigate, useLocation } from "react-router-dom";
|
|
import DoctorForm from "../components/doctors/DoctorForm";
|
|
import { useAuth } from "../components/utils/AuthProvider";
|
|
import API_KEY from "../components/utils/apiKeys";
|
|
|
|
const ENDPOINT = "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors";
|
|
const ENDPOINT_AVAILABILITY = "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctor_availability";
|
|
|
|
const diasDaSemana = ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"];
|
|
const weekdayNumToStr = {
|
|
0: "sunday",
|
|
1: "monday",
|
|
2: "tuesday",
|
|
3: "wednesday",
|
|
4: "thursday",
|
|
5: "friday",
|
|
6: "saturday",
|
|
};
|
|
const weekdayStrToNum = Object.fromEntries(
|
|
Object.entries(weekdayNumToStr).map(([num, str]) => [str, Number(num)])
|
|
);
|
|
|
|
const EditDoctorPage = () => {
|
|
const { id } = useParams();
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
const { getAuthorizationHeader } = useAuth();
|
|
|
|
const [doctor, setDoctor] = useState(null);
|
|
const [availability, setAvailability] = useState([]);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
const [isSaving, setIsSaving] = useState(false);
|
|
|
|
const effectiveId = id;
|
|
|
|
const getHeaders = () => {
|
|
const myHeaders = new Headers();
|
|
const authHeader = getAuthorizationHeader();
|
|
if (authHeader) myHeaders.append("Authorization", authHeader);
|
|
myHeaders.append("Content-Type", "application/json");
|
|
if (API_KEY) myHeaders.append("apikey", API_KEY);
|
|
myHeaders.append("Prefer", "return=representation");
|
|
return myHeaders;
|
|
};
|
|
|
|
const salvarDisponibilidades = async (doctorId, horariosAtualizados) => {
|
|
try {
|
|
const headers = getHeaders();
|
|
const promises = [];
|
|
const currentIds = new Set();
|
|
|
|
for (const dia of horariosAtualizados) {
|
|
if (dia.isChecked && dia.blocos.length > 0) {
|
|
for (const bloco of dia.blocos) {
|
|
const inicio = bloco.inicio.includes(":") ? bloco.inicio : bloco.inicio + ":00";
|
|
const termino = bloco.termino.includes(":") ? bloco.termino : bloco.termino + ":00";
|
|
|
|
const payload = {
|
|
doctor_id: doctorId,
|
|
weekday: weekdayNumToStr[dia.weekday],
|
|
start_time: inicio,
|
|
end_time: termino,
|
|
slot_minutes: bloco.slot_minutes || 30,
|
|
appointment_type: bloco.appointment_type || "presencial",
|
|
active: true,
|
|
};
|
|
|
|
if (bloco.id && !bloco.isNew) {
|
|
currentIds.add(bloco.id);
|
|
promises.push(
|
|
fetch(`${ENDPOINT_AVAILABILITY}?id=eq.${bloco.id}`, {
|
|
method: "PATCH",
|
|
headers,
|
|
body: JSON.stringify(payload),
|
|
}).then((res) => {
|
|
if (!res.ok) throw new Error(`Erro no PATCH: ${res.status}`);
|
|
return { type: "PATCH", id: bloco.id };
|
|
})
|
|
);
|
|
} else {
|
|
promises.push(
|
|
fetch(ENDPOINT_AVAILABILITY, {
|
|
method: "POST",
|
|
headers,
|
|
body: JSON.stringify(payload),
|
|
})
|
|
.then((res) => res.json())
|
|
.then((data) => {
|
|
const createdItem = Array.isArray(data) ? data[0] : data;
|
|
if (createdItem && createdItem.id) {
|
|
return { type: "POST", id: createdItem.id };
|
|
}
|
|
return { type: "POST", id: null };
|
|
})
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const results = await Promise.all(promises);
|
|
|
|
results.forEach((res) => {
|
|
if (res.type === "POST" && res.id) currentIds.add(res.id);
|
|
});
|
|
|
|
const existingDisponibilidadesRes = await fetch(
|
|
`${ENDPOINT_AVAILABILITY}?doctor_id=eq.${String(doctorId)}`,
|
|
{ method: "GET", headers }
|
|
);
|
|
|
|
if (existingDisponibilidadesRes.ok) {
|
|
const existingDisponibilidades = await existingDisponibilidadesRes.json();
|
|
|
|
const deletePromises = existingDisponibilidades
|
|
.filter((disp) => !currentIds.has(disp.id))
|
|
.map((disp) =>
|
|
fetch(`${ENDPOINT_AVAILABILITY}?id=eq.${disp.id}`, {
|
|
method: "DELETE",
|
|
headers,
|
|
})
|
|
);
|
|
|
|
await Promise.all(deletePromises);
|
|
}
|
|
|
|
const updatedResponse = await fetch(
|
|
`${ENDPOINT_AVAILABILITY}?doctor_id=eq.${doctorId}&order=weekday.asc,start_time.asc`,
|
|
{ method: "GET", headers }
|
|
);
|
|
|
|
if (updatedResponse.ok) {
|
|
const updatedData = await updatedResponse.json();
|
|
setAvailability(updatedData);
|
|
}
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
const normalizeAvailabilityForForm = (availabilityData) => {
|
|
if (!Array.isArray(availabilityData)) return [];
|
|
|
|
const disponibilidadesMedico = availabilityData.filter((d) =>
|
|
String(d.doctor_id) === String(effectiveId) && d.active !== false
|
|
);
|
|
const blocosPorDia = {};
|
|
|
|
disponibilidadesMedico.forEach((d) => {
|
|
const num = typeof d.weekday === "string" ? weekdayStrToNum[d.weekday.toLowerCase()] : d.weekday;
|
|
if (num === undefined || num === null) return;
|
|
if (!blocosPorDia[num]) blocosPorDia[num] = [];
|
|
blocosPorDia[num].push({
|
|
id: d.id,
|
|
inicio: d.start_time?.substring(0, 5) || "07:00",
|
|
termino: d.end_time?.substring(0, 5) || "17:00",
|
|
slot_minutes: d.slot_minutes || 30,
|
|
appointment_type: d.appointment_type || "presencial",
|
|
isNew: false,
|
|
});
|
|
});
|
|
|
|
const resultado = [1, 2, 3, 4, 5, 6, 0].map((weekday) => {
|
|
const blocosDoDia = blocosPorDia[weekday] || [];
|
|
return {
|
|
dia: diasDaSemana[weekday],
|
|
weekday: weekday,
|
|
isChecked: blocosDoDia.length > 0,
|
|
blocos:
|
|
blocosDoDia.length > 0
|
|
? blocosDoDia
|
|
: [
|
|
{
|
|
id: null,
|
|
inicio: "07:00",
|
|
termino: "17:00",
|
|
slot_minutes: 30,
|
|
appointment_type: "presencial",
|
|
isNew: true,
|
|
},
|
|
],
|
|
};
|
|
});
|
|
|
|
return resultado;
|
|
};
|
|
|
|
const availabilityFormatted = useMemo(() => {
|
|
return normalizeAvailabilityForForm(availability);
|
|
}, [availability, effectiveId]);
|
|
|
|
useEffect(() => {
|
|
const fetchDoctorData = async () => {
|
|
if (!effectiveId || effectiveId === "edit") {
|
|
alert("ID do médico não encontrado");
|
|
navigate("/secretaria/medicos");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const doctorResponse = await fetch(`${ENDPOINT}?id=eq.${effectiveId}`, {
|
|
method: "GET",
|
|
headers: getHeaders(),
|
|
});
|
|
|
|
if (!doctorResponse.ok) {
|
|
throw new Error("Erro ao carregar dados do médico");
|
|
}
|
|
|
|
const doctorData = await doctorResponse.json();
|
|
if (doctorData.length === 0) {
|
|
throw new Error("Médico não encontrado");
|
|
}
|
|
|
|
setDoctor(doctorData[0]);
|
|
|
|
const availabilityResponse = await fetch(
|
|
`${ENDPOINT_AVAILABILITY}?doctor_id=eq.${effectiveId}&order=weekday.asc,start_time.asc`,
|
|
{
|
|
method: "GET",
|
|
headers: getHeaders(),
|
|
}
|
|
);
|
|
|
|
if (availabilityResponse.ok) {
|
|
const availabilityData = await availabilityResponse.json();
|
|
setAvailability(availabilityData);
|
|
} else {
|
|
setAvailability([]);
|
|
}
|
|
|
|
} catch (error) {
|
|
alert("Erro ao carregar dados do médico");
|
|
navigate("/secretaria/medicos");
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
if (effectiveId) {
|
|
fetchDoctorData();
|
|
}
|
|
}, [effectiveId, navigate]);
|
|
|
|
const handleSave = async (formData) => {
|
|
const { availability: updatedAvailability, ...doctorDataToSave } = formData;
|
|
|
|
try {
|
|
setIsSaving(true);
|
|
|
|
const response = await fetch(`${ENDPOINT}?id=eq.${effectiveId}`, {
|
|
method: "PATCH",
|
|
headers: getHeaders(),
|
|
body: JSON.stringify(doctorDataToSave),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error("Erro ao salvar dados do médico");
|
|
}
|
|
|
|
if (updatedAvailability && updatedAvailability.length > 0) {
|
|
await salvarDisponibilidades(effectiveId, updatedAvailability);
|
|
}
|
|
|
|
alert("Médico e horários atualizados com sucesso!");
|
|
navigate("/secretaria/medicos");
|
|
|
|
} catch (error) {
|
|
alert(`Erro ao salvar dados: ${error.message}`);
|
|
} finally {
|
|
setIsSaving(false);
|
|
}
|
|
console.log('Horários a serem salvos:', updatedAvailability);
|
|
};
|
|
|
|
const handleCancel = () => {
|
|
navigate("/secretaria/medicos");
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="container mt-4">
|
|
<div className="d-flex justify-content-center">
|
|
<div className="spinner-border" role="status">
|
|
<span className="visually-hidden">Carregando...</span>
|
|
</div>
|
|
</div>
|
|
<p className="text-center mt-2">
|
|
Carregando dados do médico ID: {effectiveId || "..."}
|
|
</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!doctor) {
|
|
if (!isLoading) {
|
|
return (
|
|
<div className="container mt-4">
|
|
<div className="alert alert-danger">
|
|
Médico não encontrado
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
const formData = {
|
|
...doctor,
|
|
availability: (doctor && doctor.availability) ? doctor.availability : availabilityFormatted,
|
|
};
|
|
|
|
return (
|
|
<div className="container mt-4">
|
|
<div className="row">
|
|
<div className="col-12">
|
|
<h1>Editar Médico</h1>
|
|
<DoctorForm
|
|
formData={formData}
|
|
setFormData={setDoctor}
|
|
onSave={handleSave}
|
|
onCancel={handleCancel}
|
|
isLoading={isSaving}
|
|
isEditing={true}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default EditDoctorPage; |