diff --git a/package-lock.json b/package-lock.json index a672c1d..b9f9b87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33006,6 +33006,20 @@ "node": ">=14.0.0" } }, + "node_modules/react-scripts/node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/react-toastify": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz", diff --git a/src/pages/Agendamento.jsx b/src/pages/Agendamento.jsx index 89e9388..8daecec 100644 --- a/src/pages/Agendamento.jsx +++ b/src/pages/Agendamento.jsx @@ -19,444 +19,740 @@ import "./style/Agendamento.css"; import './style/FilaEspera.css'; import Spinner from '../components/Spinner.jsx'; - dayjs.locale('pt-br'); dayjs.extend(isBetween); dayjs.extend(localeData); - const Agendamento = ({ setDictInfo }) => { - const navigate = useNavigate(); - const [listaTodosAgendamentos, setListaTodosAgendamentos] = useState([]); - const [selectedID, setSelectedId] = useState('0'); - const [filaEsperaData, setFilaEsperaData] = useState([]); - const [FiladeEspera, setFiladeEspera] = useState(false); - const [PageNovaConsulta, setPageConsulta] = useState(false); - const [searchTerm, setSearchTerm] = useState(''); - const { getAuthorizationHeader } = useAuth(); - const [DictAgendamentosOrganizados, setAgendamentosOrganizados] = useState({}); - const [showDeleteModal, setShowDeleteModal] = useState(false); - const [ListaDeMedicos, setListaDeMedicos] = useState([]); - const [FiltredTodosMedicos, setFiltredTodosMedicos] = useState([]); - const [searchTermDoctor, setSearchTermDoctor] = useState(''); - const [MedicoFiltrado, setMedicoFiltrado] = useState({ id: "vazio" }); - const [cacheAgendamentos, setCacheAgendamentos] = useState([]); - const [appointmentToEdit, setAppointmentToEdit] = useState(null); - const [showConfirmModal, setShowConfirmModal] = useState(false); - const [motivoCancelamento, setMotivoCancelamento] = useState(""); - const [showSpinner, setShowSpinner] = useState(true); - const [waitlistSearch, setWaitlistSearch] = useState(''); - const [waitSortKey, setWaitSortKey] = useState(null); - const [waitSortDir, setWaitSortDir] = useState('asc'); - const [waitPage, setWaitPage] = useState(1); - const [waitPerPage, setWaitPerPage] = useState(10); - const authHeader = getAuthorizationHeader(); - const cacheMedicos = useMemo(() => ({}), []); - const cachePacientes = useMemo(() => ({}), []); - const [currentDate, setCurrentDate] = useState(dayjs()); - const [selectedDay, setSelectedDay] = useState(dayjs()); - - const [editingAppointmentId, setEditingAppointmentId] = useState(null); - - const [quickJump, setQuickJump] = useState({ - month: currentDate.month(), - year: currentDate.year() + const navigate = useNavigate(); + const [listaTodosAgendamentos, setListaTodosAgendamentos] = useState([]); + const [selectedID, setSelectedId] = useState('0'); + const [filaEsperaData, setFilaEsperaData] = useState([]); + const [FiladeEspera, setFiladeEspera] = useState(false); + const [PageNovaConsulta, setPageConsulta] = useState(false); + const [searchTerm, setSearchTerm] = useState(''); + const { getAuthorizationHeader } = useAuth(); + const [DictAgendamentosOrganizados, setAgendamentosOrganizados] = useState({}); + const [showDeleteModal, setShowDeleteModal] = useState(false); + const [ListaDeMedicos, setListaDeMedicos] = useState([]); + const [FiltredTodosMedicos, setFiltredTodosMedicos] = useState([]); + const [searchTermDoctor, setSearchTermDoctor] = useState(''); + const [MedicoFiltrado, setMedicoFiltrado] = useState({ id: "vazio" }); + const [cacheAgendamentos, setCacheAgendamentos] = useState([]); + const [appointmentToEdit, setAppointmentToEdit] = useState(null); + const [showConfirmModal, setShowConfirmModal] = useState(false); + const [motivoCancelamento, setMotivoCancelamento] = useState(""); + const [showSpinner, setShowSpinner] = useState(true); + const [waitlistSearch, setWaitlistSearch] = useState(''); + const [waitSortKey, setWaitSortKey] = useState(null); + const [waitSortDir, setWaitSortDir] = useState('asc'); + const [waitPage, setWaitPage] = useState(1); + const [waitPerPage, setWaitPerPage] = useState(10); + const authHeader = getAuthorizationHeader(); + const cacheMedicos = useMemo(() => ({}), []); + const cachePacientes = useMemo(() => ({}), []); + const [currentDate, setCurrentDate] = useState(dayjs()); + const [selectedDay, setSelectedDay] = useState(dayjs()); + + const [editingAppointmentId, setEditingAppointmentId] = useState(null); + + const [quickJump, setQuickJump] = useState({ + month: currentDate.month(), + year: currentDate.year() + }); + + const fetchAppointments = async () => { + const myHeaders = new Headers(); + myHeaders.append("Authorization", authHeader); + myHeaders.append("apikey", API_KEY); + const requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' }; + try { + const res = await fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?select=*", requestOptions); + const data = await res.json(); + setListaTodosAgendamentos(data); + } catch (err) { + console.error('Erro ao buscar agendamentos', err); + } + }; + + const updateAppointmentStatus = async (id, updates) => { + const myHeaders = new Headers(); + myHeaders.append("Authorization", authHeader); + myHeaders.append("apikey", API_KEY); + myHeaders.append("Content-Type", "application/json"); + myHeaders.append("Prefer", "return=representation"); + const requestOptions = { method: 'PATCH', headers: myHeaders, body: JSON.stringify(updates) }; + + try { + const response = await fetch(`https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?id=eq.${id}`, requestOptions); + if (response.ok) { + await fetchAppointments(); + return true; + } else { + console.error('Erro ao atualizar agendamento:', await response.text()); + return false; + } + } catch (error) { + console.error('Erro de rede/servidor:', error); + return false; + } + }; + + const deleteConsulta = async (id) => { + setShowSpinner(true); + const success = await updateAppointmentStatus(id, { + status: "cancelled", + cancellation_reason: motivoCancelamento, + updated_at: new Date().toISOString() }); + setShowSpinner(false); + if (success) { + setShowDeleteModal(false); + setMotivoCancelamento(""); + setSelectedId('0'); + } else { + alert("Falha ao cancelar a consulta."); + } + }; + const confirmConsulta = async (id) => { + setShowSpinner(true); + const success = await updateAppointmentStatus(id, { + status: "agendado", + cancellation_reason: null, + updated_at: new Date().toISOString() + }); + setShowSpinner(false); + if (success) { + setShowConfirmModal(false); + setSelectedId('0'); + } else { + alert("Falha ao reverter o cancelamento."); + } + }; - const fetchAppointments = async () => { - const myHeaders = new Headers(); myHeaders.append("Authorization", authHeader); myHeaders.append("apikey", API_KEY); - const requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' }; - try { - const res = await fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?select=*", requestOptions); - const data = await res.json(); - setListaTodosAgendamentos(data); - } catch (err) { - console.error('Erro ao buscar agendamentos', err); + const handleQuickJumpChange = (type, value) => { + setQuickJump(prev => ({ ...prev, [type]: Number(value) })); + }; + + useEffect(() => { + setQuickJump({ + month: currentDate.month(), + year: currentDate.year() + }); + }, [currentDate]); + + const applyQuickJump = () => { + let newDate = dayjs().year(quickJump.year).month(quickJump.month).date(1); + setCurrentDate(newDate); + setSelectedDay(newDate); + }; + + useEffect(() => { + if (!listaTodosAgendamentos.length) { setShowSpinner(false); return; } + setShowSpinner(true); + const fetchDados = async () => { + const newDict = {}; + const newFila = []; + for (const agendamento of listaTodosAgendamentos) { + if (!agendamento.doctor_id || !agendamento.patient_id) continue; + if (!cacheMedicos[agendamento.doctor_id]) { + cacheMedicos[agendamento.doctor_id] = (await GetDoctorByID(agendamento.doctor_id, authHeader))[0]; } - }; - - - const updateAppointmentStatus = async (id, updates) => { - const myHeaders = new Headers(); myHeaders.append("Authorization", authHeader); myHeaders.append("apikey", API_KEY); myHeaders.append("Content-Type", "application/json"); myHeaders.append("Prefer", "return=representation"); - const requestOptions = { method: 'PATCH', headers: myHeaders, body: JSON.stringify(updates) }; - - try { - const response = await fetch(`https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/appointments?id=eq.${id}`, requestOptions); - if (response.ok) { - await fetchAppointments(); - return true; - } else { - console.error('Erro ao atualizar agendamento:', await response.text()); - return false; - } - } catch (error) { - console.error('Erro de rede/servidor:', error); - return false; + if (!cachePacientes[agendamento.patient_id]) { + cachePacientes[agendamento.patient_id] = (await GetPatientByID(agendamento.patient_id, authHeader))[0]; } - }; + const medico = cacheMedicos[agendamento.doctor_id]; + const paciente = cachePacientes[agendamento.patient_id]; - - const deleteConsulta = async (id) => { - setShowSpinner(true); - const success = await updateAppointmentStatus(id, { status: "cancelled", cancellation_reason: motivoCancelamento, updated_at: new Date().toISOString() }); - setShowSpinner(false); - if (success) { - setShowDeleteModal(false); - setMotivoCancelamento(""); - setSelectedId('0'); - } else { - alert("Falha ao cancelar a consulta."); - } - }; - - const confirmConsulta = async (id) => { - setShowSpinner(true); - const success = await updateAppointmentStatus(id, { status: "agendado", cancellation_reason: null, updated_at: new Date().toISOString() }); - setShowSpinner(false); - if (success) { - setShowConfirmModal(false); - setSelectedId('0'); - } else { - alert("Falha ao reverter o cancelamento."); - } - }; - - - const handleQuickJumpChange = (type, value) => { - setQuickJump(prev => ({ ...prev, [type]: Number(value) })); - }; - - - useEffect(() => { - setQuickJump({ - month: currentDate.month(), - year: currentDate.year() - }); - }, [currentDate]); - - - const applyQuickJump = () => { - let newDate = dayjs().year(quickJump.year).month(quickJump.month).date(1); - setCurrentDate(newDate); - setSelectedDay(newDate); - }; - - - useEffect(() => { - if (!listaTodosAgendamentos.length) { setShowSpinner(false); return; } - setShowSpinner(true); - const fetchDados = async () => { - const newDict = {}; const newFila = []; - for (const agendamento of listaTodosAgendamentos) { - if (!agendamento.doctor_id || !agendamento.patient_id) continue; - if (!cacheMedicos[agendamento.doctor_id]) { cacheMedicos[agendamento.doctor_id] = (await GetDoctorByID(agendamento.doctor_id, authHeader))[0]; } - if (!cachePacientes[agendamento.patient_id]) { cachePacientes[agendamento.patient_id] = (await GetPatientByID(agendamento.patient_id, authHeader))[0]; } - const medico = cacheMedicos[agendamento.doctor_id]; - const paciente = cachePacientes[agendamento.patient_id]; - - const agendamentoMelhorado = { - ...agendamento, - medico_nome: medico?.full_name, - paciente_nome: paciente?.full_name, - paciente_cpf: paciente?.cpf - }; - - if (agendamento.status === "requested") { newFila.push({ agendamento: agendamentoMelhorado, Infos: agendamentoMelhorado }); } - else { - const DiaAgendamento = dayjs(agendamento.scheduled_at).format("YYYY-MM-DD"); - if (newDict[DiaAgendamento]) { newDict[DiaAgendamento].push(agendamentoMelhorado); } - else { newDict[DiaAgendamento] = [agendamentoMelhorado]; } - } - } - for (const key in newDict) { newDict[key].sort((a, b) => a.scheduled_at.localeCompare(b.scheduled_at)); } - setAgendamentosOrganizados(newDict); - setFilaEsperaData(newFila); - setShowSpinner(false); + const agendamentoMelhorado = { + ...agendamento, + medico_nome: medico?.full_name, + paciente_nome: paciente?.full_name, + paciente_cpf: paciente?.cpf }; - fetchDados(); - }, [listaTodosAgendamentos, authHeader, cacheMedicos, cachePacientes]); - - useEffect(() => { - fetchAppointments(); - GetAllDoctors(authHeader).then(docs => setListaDeMedicos(docs.map(d => ({ nomeMedico: d.full_name, idMedico: d.id })))); - }, [authHeader]); - - - const handleSearchMedicos = (term) => { }; - - - const filaEsperaFiltrada = useMemo(() => { - if (!waitlistSearch.trim()) return filaEsperaData; - const term = waitlistSearch.toLowerCase(); - return filaEsperaData.filter(item => (item?.Infos?.paciente_nome?.toLowerCase() || '').includes(term) || (item?.Infos?.paciente_cpf?.toLowerCase() || '').includes(term) || (item?.Infos?.nome_medico?.toLowerCase() || '').includes(term)); - }, [waitlistSearch, filaEsperaData]); - - const applySortingWaitlist = (arr) => { - if (!Array.isArray(arr) || !waitSortKey) return arr; - const copy = [...arr]; - if (waitSortKey === 'paciente') { copy.sort((a, b) => (a?.Infos?.paciente_nome || '').localeCompare((b?.Infos?.paciente_nome || ''))); } - else if (waitSortKey === 'medico') { copy.sort((a, b) => (a?.Infos?.nome_medico || '').localeCompare((b?.Infos?.nome_medico || ''))); } - else if (waitSortKey === 'data') { copy.sort((a, b) => new Date(a?.agendamento?.scheduled_at || 0) - new Date(b?.agendamento?.scheduled_at || 0)); } - if (waitSortDir === 'desc') copy.reverse(); - return copy; + if (agendamento.status === "requested") { + newFila.push({ agendamento: agendamentoMelhorado, Infos: agendamentoMelhorado }); + } else { + const DiaAgendamento = dayjs(agendamento.scheduled_at).format("YYYY-MM-DD"); + if (newDict[DiaAgendamento]) { + newDict[DiaAgendamento].push(agendamentoMelhorado); + } else { + newDict[DiaAgendamento] = [agendamentoMelhorado]; + } + } + } + for (const key in newDict) { + newDict[key].sort((a, b) => a.scheduled_at.localeCompare(b.scheduled_at)); + } + setAgendamentosOrganizados(newDict); + setFilaEsperaData(newFila); + setShowSpinner(false); }; - const filaEsperaOrdenada = applySortingWaitlist(filaEsperaFiltrada); - const waitTotalPages = Math.ceil(filaEsperaOrdenada.length / waitPerPage) || 1; - const waitIndiceInicial = (waitPage - 1) * waitPerPage; - const waitIndiceFinal = waitIndiceInicial + waitPerPage; - const filaEsperaPaginada = filaEsperaOrdenada.slice(waitIndiceInicial, waitIndiceFinal); - const gerarNumerosWaitPages = () => { - const paginas = []; const paginasParaMostrar = 5; - let inicio = Math.max(1, waitPage - Math.floor(paginasParaMostrar / 2)); - let fim = Math.min(waitTotalPages, inicio + paginasParaMostrar - 1); - inicio = Math.max(1, fim - paginasParaMostrar + 1); - for (let i = inicio; i <= fim; i++) { paginas.push(i); } - return paginas; - }; - useEffect(() => { setWaitPage(1); }, [waitlistSearch, waitSortKey, waitSortDir]); + fetchDados(); + }, [listaTodosAgendamentos, authHeader, cacheMedicos, cachePacientes]); - - const generateDateGrid = () => { - const grid = []; const startOfMonth = currentDate.startOf('month'); - let currentDay = startOfMonth.subtract(startOfMonth.day(), 'day'); - for (let i = 0; i < 42; i++) { grid.push(currentDay); currentDay = currentDay.add(1, 'day'); } - return grid; - }; - const dateGrid = useMemo(() => generateDateGrid(), [currentDate]); - const weekDays = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb']; - const handleDateClick = (day) => setSelectedDay(day); - - - const DeleteModal = () => ( -
Qual o motivo do cancelamento?
- -Tem certeza que deseja retirar o cancelamento?
- Isso reverterá o status do agendamento para Agendado. -Qual o motivo do cancelamento?
+ +Tem certeza que deseja retirar o cancelamento?
+ Isso reverterá o status do agendamento para Agendado. +{medico.nomeMedico}
+{medico.nomeMedico}
{selectedDay.format('D [de] MMMM [de] YYYY')}
+{selectedDay.format('D [de] MMMM [de] YYYY')}
Nenhuma consulta agendada.
| Nome do Paciente | CPF | Médico Solicitado | Data da Solicitação | Ações |
|---|---|---|---|---|
| {item?.Infos?.paciente_nome} | {item?.Infos?.paciente_cpf} | {item?.Infos?.nome_medico} | {dayjs(item.agendamento.scheduled_at).format('DD/MM/YYYY')} | |
{showSpinner ? Nenhuma solicitação encontrada. >)} | ||||
Nenhuma consulta agendada.
+| Nome do Paciente | +CPF | +Médico Solicitado | +Data da Solicitação | +Ações | +
|---|---|---|---|---|
| {item?.Infos?.paciente_nome} | +{item?.Infos?.paciente_cpf} | +{item?.Infos?.nome_medico} | +{dayjs(item.agendamento.scheduled_at).format('DD/MM/YYYY')} | ++ + | +
|
+
+ {showSpinner ? (
+
+ Nenhuma solicitação encontrada. + > + )} + |
+ ||||