import React, { useState, useEffect, useMemo } from "react"; import HorariosDisponibilidade from "../components/doctors/HorariosDisponibilidade"; import { useAuth } from "../components/utils/AuthProvider"; import API_KEY from "../components/utils/apiKeys"; import "./style/DisponibilidadesDoctorPage.css"; const ENDPOINT = "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctor_availability"; const DOCTORS_ENDPOINT = "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors"; 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 DisponibilidadesDoctorPage = () => { const { getAuthorizationHeader } = useAuth(); const [disponibilidades, setDisponibilidades] = useState([]); const [doctors, setDoctors] = useState([]); const [searchTerm, setSearchTerm] = useState(""); const [editando, setEditando] = useState(null); const [expandedDoctors, setExpandedDoctors] = useState({}); const [showSuggestions, setShowSuggestions] = useState(false); const [availabilityEdit, setAvailabilityEdit] = useState([]); 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; }; useEffect(() => { const fetchDoctors = async () => { try { const requestOptions = { method: "GET", headers: getHeaders(), }; const response = await fetch(DOCTORS_ENDPOINT, requestOptions); const result = await response.json(); setDoctors(Array.isArray(result) ? result : []); } catch (error) { setDoctors([]); } }; fetchDoctors(); }, [getAuthorizationHeader]); useEffect(() => { const fetchDisponibilidades = async () => { try { const res = await fetch(ENDPOINT, { method: "GET", headers: getHeaders() }); if (res.ok) { const data = await res.json(); setDisponibilidades(Array.isArray(data) ? data : []); } } catch (error) { setDisponibilidades([]); } }; fetchDisponibilidades(); }, [getAuthorizationHeader]); const toggleExpandDoctor = (doctorId) => { setExpandedDoctors((prev) => ({ ...prev, [doctorId]: !prev[doctorId] })); }; const salvarTodasDisponibilidades = 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}?id=eq.${bloco.id}`, { method: "PATCH", headers, body: JSON.stringify(payload), }).then(() => ({ type: 'PATCH', id: bloco.id })) ); } else { promises.push( fetch(ENDPOINT, { method: "POST", headers, body: JSON.stringify(payload), }) .then(res => res.json()) .then(data => { const createdItem = Array.isArray(data) ? data[0] : data; return { type: 'POST', id: createdItem?.id }; }) ); } } } } const results = await Promise.all(promises); results.forEach(res => { if (res.type === 'POST' && res.id) currentIds.add(res.id); }); const existingRes = await fetch(`${ENDPOINT}?doctor_id=eq.${String(doctorId)}`, { method: "GET", headers }); if (existingRes.ok) { const existingData = await existingRes.json(); const deletePromises = existingData .filter(dbItem => !currentIds.has(dbItem.id)) .map(dbItem => fetch(`${ENDPOINT}?id=eq.${dbItem.id}`, { method: "DELETE", headers }) ); await Promise.all(deletePromises); } setEditando(null); setAvailabilityEdit([]); const res = await fetch(ENDPOINT, { method: "GET", headers: getHeaders() }); if (res.ok) { const data = await res.json(); setDisponibilidades(Array.isArray(data) ? data : []); } } catch (error) { console.error(error); } }; const deletarDisponibilidade = async (id) => { if (!window.confirm("Deseja realmente excluir esta disponibilidade?")) return; try { const res = await fetch(`${ENDPOINT}?id=eq.${id}`, { method: "DELETE", headers: getHeaders() }); if (res.ok) setDisponibilidades((prev) => prev.filter((d) => d.id !== id)); } catch (error) {} }; const disponibilidadesAgrupadas = useMemo(() => { const agrupadas = {}; doctors.forEach((doctor) => { agrupadas[doctor.id] = { doctor_id: doctor.id, doctor_name: doctor.full_name || doctor.name, disponibilidades: [], }; }); disponibilidades.forEach((disp) => { if (agrupadas[disp.doctor_id]) agrupadas[disp.doctor_id].disponibilidades.push(disp); }); Object.values(agrupadas).forEach((grupo) => { if (grupo.disponibilidades.length === 0) { grupo.disponibilidades.push({ id: `empty-${grupo.doctor_id}`, doctor_id: grupo.doctor_id, doctor_name: grupo.doctor_name, is_empty: true, }); } }); let resultado = Object.values(agrupadas); if (searchTerm) resultado = resultado.filter((grupo) => grupo.doctor_name.toLowerCase().includes(searchTerm.toLowerCase())); return resultado; }, [disponibilidades, doctors, searchTerm]); const formatTime = (timeString) => { if (!timeString) return ""; return timeString.includes(":") ? timeString.substring(0, 5) : timeString; }; const getDiaSemana = (weekday) => { const dias = { 0: "Domingo", 1: "Segunda", 2: "Terça", 3: "Quarta", 4: "Quinta", 5: "Sexta", 6: "Sábado", sunday: "Domingo", monday: "Segunda", tuesday: "Terça", wednesday: "Quarta", thursday: "Quinta", friday: "Sexta", saturday: "Sábado", }; const key = typeof weekday === "string" ? weekday.toLowerCase() : weekday; return dias[key] || "Desconhecido"; }; const initialAvailabilityParaEdicao = useMemo(() => { if (!editando) return []; const disponibilidadesMedico = disponibilidades.filter((d) => String(d.doctor_id) === String(editando)); const blocosPorDia = {}; disponibilidadesMedico.forEach((d) => { const num = typeof d.weekday === "string" ? weekdayStrToNum[d.weekday.toLowerCase()] : d.weekday; if (num === undefined) return; if (!blocosPorDia[num]) blocosPorDia[num] = []; if (d.active !== false) { blocosPorDia[num].push({ id: d.id, inicio: formatTime(d.start_time) || "07:00", termino: formatTime(d.end_time) || "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; }, [disponibilidades, editando]); const handleUpdateHorarios = (horariosAtualizados) => { if (!editando) return; setAvailabilityEdit(horariosAtualizados || []); }; const filteredDoctors = useMemo(() => { if (!searchTerm) return doctors; return doctors.filter((doc) => (doc.full_name || doc.name).toLowerCase().includes(searchTerm.toLowerCase())); }, [doctors, searchTerm]); const handleCancelarEdicao = () => { setEditando(null); setAvailabilityEdit([]); }; const handleDoctorSelect = (doctor) => { setSearchTerm(doctor.full_name || doctor.name); setShowSuggestions(false); }; const handleClearSearch = () => { setSearchTerm(""); setShowSuggestions(false); }; const getStatusBadgeClass = (disp) => { if (disp.is_empty) return "status-badge status-not-configured"; if (disp.active === false) return "status-badge status-inactive"; return "status-badge status-active"; }; const getStatusText = (disp) => { if (disp.is_empty) return "Não configurado"; if (disp.active === false) return "Inativa"; return "Ativa"; }; return (
Carregando médicos...
) : editando ? ( <>Carregando horários para edição...
)}Nenhum médico encontrado
) : ( disponibilidadesAgrupadas.map((grupo) => (| Dia da Semana | Início | Término | Intervalo (min) | Tipo | Status | Ações |
|---|---|---|---|---|---|---|
| {disp.is_empty ? "Nenhum horário cadastrado" : getDiaSemana(disp.weekday)} | {disp.is_empty ? "-" : formatTime(disp.start_time)} | {disp.is_empty ? "-" : formatTime(disp.end_time)} | {disp.is_empty ? "-" : disp.slot_minutes || 30} | {disp.is_empty ? "-" : disp.appointment_type || "presencial"} | {getStatusText(disp)} | {!disp.is_empty && } |