diff --git a/src/components/AgendarConsulta/FormNovaConsulta.jsx b/src/components/AgendarConsulta/FormNovaConsulta.jsx index 435bc8e..a17c221 100644 --- a/src/components/AgendarConsulta/FormNovaConsulta.jsx +++ b/src/components/AgendarConsulta/FormNovaConsulta.jsx @@ -2,22 +2,93 @@ import InputMask from "react-input-mask"; import "./style/formagendamentos.css"; import { useState, useEffect } from "react"; - const FormNovaConsulta = ({ onCancel, patientID }) => { - + const [horariosDisponiveis, setHorariosDisponiveis] = useState([]); + const [carregandoHorarios, setCarregandoHorarios] = useState(false); + + const [isModoEmergencia, setIsModoEmergencia] = useState(false); const [selectedFile, setSelectedFile] = useState(null); const [anexos, setAnexos] = useState([]); const [loadingAnexos, setLoadingAnexos] = useState(false); - const [paciente, setPaciente] = useState({}) - const [acessibilidade, setAcessibilidade] = useState({cadeirante:false,idoso:false,gravida:false,bebe:false, autista:false }) + const [paciente, setPaciente] = useState({}); + const [acessibilidade, setAcessibilidade] = useState({ + cadeirante: false, + idoso: false, + gravida: false, + bebe: false, + autista: false, + }); + const [dadosAtendimento, setDadosAtendimento] = useState({ + profissional: "", + tipoAtendimento: "", + unidade: "", + dataAtendimento: "", + inicio: "", + termino: "", + solicitante: "", + observacoes: "", + }); - useEffect(() => { + // Variável de controle para saber se a grade de horário deve ser mostrada + const isReadyForSchedule = + dadosAtendimento.profissional && dadosAtendimento.dataAtendimento; + + const fetchHorariosDisponiveis = async (professionalId, date) => { + if (!isReadyForSchedule || isModoEmergencia) { + setHorariosDisponiveis([]); + return; + } + + setCarregandoHorarios(true); + setHorariosDisponiveis([]); + + var myHeaders = new Headers(); + myHeaders.append("Content-Type", "application/json"); + + const payload = { + doctor_id: professionalId, + date: date, + }; + + var requestOptions = { + method: "POST", + headers: myHeaders, + body: JSON.stringify(payload), + redirect: "follow", + }; + + try { + const res = await fetch( + "https://mock.apidog.com/m1/1053378-0-default/rest/v1/doctor_availability", + requestOptions + ); + const data = await res.json(); + + const slots = data.data && Array.isArray(data.data) ? data.data : []; + + setHorariosDisponiveis(slots); + + // Limpa o horário se o que estava selecionado não existe mais na nova grade + if (dadosAtendimento.inicio && !slots.includes(dadosAtendimento.inicio)) { + setDadosAtendimento((prev) => ({ ...prev, inicio: "", termino: "" })); + } + } catch (err) { + console.error("Erro ao buscar horários disponíveis:", err); + setHorariosDisponiveis([]); + } finally { + setCarregandoHorarios(false); + } + }; + + useEffect(() => { if (!patientID) return; const fetchAnexos = async () => { setLoadingAnexos(true); try { - const res = await fetch(`https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientID}/anexos`); + const res = await fetch( + `https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientID}/anexos` + ); const data = await res.json(); setAnexos(data.data || []); } catch (err) { @@ -30,6 +101,23 @@ const FormNovaConsulta = ({ onCancel, patientID }) => { fetchAnexos(); }, [patientID]); + useEffect(() => { + // Chama a busca apenas se estivermos no modo padrão E tivermos profissional e data + if (isReadyForSchedule && !isModoEmergencia) { + fetchHorariosDisponiveis( + dadosAtendimento.profissional, + dadosAtendimento.dataAtendimento + ); + } else if (!isReadyForSchedule) { + setHorariosDisponiveis([]); + } + }, [ + dadosAtendimento.profissional, + dadosAtendimento.dataAtendimento, + isModoEmergencia, + isReadyForSchedule, + ]); + const handleUpload = async () => { if (!selectedFile) return; @@ -37,13 +125,16 @@ const FormNovaConsulta = ({ onCancel, patientID }) => { formData.append("file", selectedFile); try { - const res = await fetch(`https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientID}/anexos`, { - method: "POST", - body: formData - }); + const res = await fetch( + `https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientID}/anexos`, + { + method: "POST", + body: formData, + } + ); if (res.ok) { const novoAnexo = await res.json(); - setAnexos(prev => [...prev, novoAnexo]); + setAnexos((prev) => [...prev, novoAnexo]); setSelectedFile(null); } else { console.error("Erro ao enviar anexo"); @@ -51,202 +142,352 @@ const FormNovaConsulta = ({ onCancel, patientID }) => { } catch (err) { console.error("Erro ao enviar anexo:", err); } - }; - - - const handleclickAcessibilidade = (id) => { - let resultado = acessibilidade[id] - - if(resultado === false){ setAcessibilidade({...acessibilidade, [id]:true}); console.log('mudou')} - - else if(resultado === true){ setAcessibilidade({...acessibilidade, [id]:false})} - console.log(id) - } - - - const FormatCPF = (valor) => { - console.log(valor) - - const digits = String(valor).replace(/\D/g, '').slice(0, 11); - BuscarPacienteExistentePeloCPF(valor) - - return digits - .replace(/(\d{3})(\d)/, '$1.$2') - .replace(/(\d{3})(\d)/, '$1.$2') - .replace(/(\d{3})(\d{1,2})$/, '$1-$2'); - } - - - const FormatTelefones = (valor) => { - const digits = String(valor).replace(/\D/g, '').slice(0, 11); - return digits - .replace(/(\d)/, '($1') - .replace(/(\d{2})(\d)/, '$1) $2' ) - .replace(/(\d)(\d{4})/, '$1 $2') - .replace(/(\d{4})(\d{4})/, '$1-$2') - } - - - const BuscarCPFnoBancodeDados = async (cpf) => { - - var myHeaders = new Headers(); - myHeaders.append("Authorization", "Bearer "); - myHeaders.append("Content-Type", "application/json"); - - var raw = JSON.stringify({ - "cpf": cpf - }); - - var requestOptions = { - method: 'POST', - headers: myHeaders, - body: raw, - redirect: 'follow' }; - const response = await fetch("https://mock.apidog.com/m1/1053378-0-default/pacientes/validar-cpf", requestOptions); - const result = await response.json(); - return result + const handleclickAcessibilidade = (id) => { + let resultado = acessibilidade[id]; - - } + if (resultado === false) { + setAcessibilidade({ ...acessibilidade, [id]: true }); + console.log("mudou"); + } else if (resultado === true) { + setAcessibilidade({ ...acessibilidade, [id]: false }); + } + console.log(id); + }; - const BuscarPacienteExistentePeloCPF = async (value) => { - - if(isNaN(value[13]) === false && value.length === 14)try { - const result = await BuscarCPFnoBancodeDados(value); - console.log("Resultado:", result); - - if (result.data.existe === true){ + const FormatCPF = (valor) => { + const digits = String(valor).replace(/\D/g, "").slice(0, 11); + BuscarPacienteExistentePeloCPF(valor); - var myHeaders = new Headers(); + return digits + .replace(/(\d{3})(\d)/, "$1.$2") + .replace(/(\d{3})(\d)/, "$1.$2") + .replace(/(\d{3})(\d{1,2})$/, "$1-$2"); + }; + + const FormatTelefones = (valor) => { + const digits = String(valor).replace(/\D/g, "").slice(0, 11); + return digits + .replace(/(\d)/, "($1") + .replace(/(\d{2})(\d)/, "$1) $2") + .replace(/(\d)(\d{4})/, "$1 $2") + .replace(/(\d{4})(\d{4})/, "$1-$2"); + }; + + const BuscarCPFnoBancodeDados = async (cpf) => { + var myHeaders = new Headers(); myHeaders.append("Authorization", "Bearer "); + myHeaders.append("Content-Type", "application/json"); + + var raw = JSON.stringify({ + cpf: cpf, + }); var requestOptions = { - method: 'GET', + method: "POST", headers: myHeaders, - redirect: 'follow' + body: raw, + redirect: "follow", }; - fetch("https://mock.apidog.com/m1/1053378-0-default/pacientes/", requestOptions) - .then(response => response.json()) - .then(result => setPaciente(result.data)) - .catch(error => console.log('error', error)); - } - + const response = await fetch( + "https://mock.apidog.com/m1/1053378-0-default/pacientes/validar-cpf", + requestOptions + ); + const result = await response.json(); + return result; + }; + const BuscarPacienteExistentePeloCPF = async (value) => { + if (isNaN(value[13]) === false && value.length === 14) + try { + const result = await BuscarCPFnoBancodeDados(value); - } catch (error) { - console.log("error", error); - } - //BuscarCPFnoBancodeDados(value) - } + if (result.data.existe === true) { + var myHeaders = new Headers(); + myHeaders.append("Authorization", "Bearer "); + + var requestOptions = { + method: "GET", + headers: myHeaders, + redirect: "follow", + }; + + fetch( + "https://mock.apidog.com/m1/1053378-0-default/pacientes/", + requestOptions + ) + .then((response) => response.json()) + .then((result) => setPaciente(result.data)) + .catch((error) => console.log("error", error)); + } + } catch (error) { + console.log("error", error); + } + }; const handleChange = (e) => { + const { value, name } = e.target; - const {value, name} = e.target; - - console.log(value, name) - - if(name === 'email'){ - setPaciente({...paciente, contato:{ - ...paciente.contato, - email:value - }}) - - } else if(name === 'telefone'){ - setPaciente({...paciente, contato:{ - ...paciente.contato, - telefone1:FormatTelefones(value) - }}) + if (name === "email") { + setPaciente({ + ...paciente, + contato: { + ...paciente.contato, + email: value, + }, + }); + } else if (name === "telefone") { + setPaciente({ + ...paciente, + contato: { + ...paciente.contato, + telefone1: FormatTelefones(value), + }, + }); + } else { + setPaciente({ ...paciente, [name]: value }); } - else{ - setPaciente({...paciente,[name]:value}) + }; + + const handleAtendimentoChange = (e) => { + const { value, name } = e.target; + setDadosAtendimento((prev) => ({ + ...prev, + [name]: value, + })); + }; + + const handleSubmitExcecao = async () => { + console.log( + "Modo Emergência Ativado: Tentando criar Exceção com novo endpoint." + ); + + const { + profissional, + dataAtendimento, + tipoAtendimento, + inicio, + termino, + observacoes, + } = dadosAtendimento; + + if ( + !profissional || + !dataAtendimento || + !tipoAtendimento || + !inicio || + !termino + ) { + alert( + "Por favor, preencha o Profissional, Data, Tipo e Horários para a exceção." + ); + return; } - } + + const payload = { + doctor_id: profissional, + date: dataAtendimento, + start_time: inicio + ":00", + end_time: termino + ":00", + kind: "liberacao", + reason: tipoAtendimento, + }; + + var myHeaders = new Headers(); + myHeaders.append("Content-Type", "application/json"); + + var requestOptions = { + method: "POST", + headers: myHeaders, + body: JSON.stringify(payload), + redirect: "follow", + }; + + try { + const response = await fetch( + "https://mock.apidog.com/m1/1053378-0-default/rest/v1/doctor_exceptions", + requestOptions + ); + const result = await response.json(); + + if (response.ok || response.status === 201) { + console.log("Exceção de emergência criada com sucesso:", result); + alert( + `Consulta de emergência agendada como exceção! Detalhes: ${JSON.stringify( + result + )}` + ); + } else { + console.error("Erro ao criar exceção de emergência:", result); + alert( + `Erro ao agendar exceção. Status: ${response.status}. Detalhes: ${ + result.message || JSON.stringify(result) + }` + ); + } + } catch (error) { + console.error("Erro na requisição para criar exceção:", error); + alert( + "Erro de comunicação com o servidor ou formato de resposta inválido." + ); + } + }; + + const handleSubmitPadrao = () => { + if (!isReadyForSchedule) { + alert( + "Por favor, preencha o Profissional e a Data do Atendimento antes de salvar." + ); + return; + } + if ( + !horariosDisponiveis.includes(dadosAtendimento.inicio) || + !horariosDisponiveis.includes(dadosAtendimento.termino) + ) { + alert( + "Por favor, selecione horários válidos dentro da grade do profissional." + ); + return; + } + + console.log("Salvando agendamento."); + alert("Agendamento salvo!"); + }; const handleSubmit = (e) => { e.preventDefault(); - alert("Agendamento salvo!"); + if (isModoEmergencia) { + handleSubmitExcecao(); + } else { + handleSubmitPadrao(); + } }; return (
- -

Informações do paciente

-
+
- +
- - e.target.value = FormatCPF(e.target.value)} /> - + + (e.target.value = FormatCPF(e.target.value))} + />
- +
-
+
-
+
- +
- +
- +
-
+
-
- -
- - +
+
+ + +
+
+ + +
+ +
+ + +
-
- - -
- -
- - -
-

Informações adicionais

- - - setSelectedFile(e.target.files[0])} - /> - {selectedFile && ( - - )} + + + setSelectedFile(e.target.files[0])} + /> + {selectedFile && ( + + )}
{loadingAnexos ? (

Carregando anexos...

@@ -259,109 +500,312 @@ const FormNovaConsulta = ({ onCancel, patientID }) => { )}

Informações do atendimento

- - -
- -
handleclickAcessibilidade(e.currentTarget.id)}> - - accessible -
+
+ + {isModoEmergencia && ( +

+ ⚠️ As informações de data e horário serão enviadas como uma + exceção fora da grade normal. +

+ )} +
-
handleclickAcessibilidade(e.currentTarget.id)}> - elderly -
- -
handleclickAcessibilidade(e.currentTarget.id)}> - pregnant_woman -
- -
handleclickAcessibilidade(e.currentTarget.id)}> - - -
- -
handleclickAcessibilidade(e.currentTarget.id)}> - -
- +
+
handleclickAcessibilidade(e.currentTarget.id)} + > + accessible
-
- -
- - -
- +
handleclickAcessibilidade(e.currentTarget.id)} + > + elderly +
+
handleclickAcessibilidade(e.currentTarget.id)} + > + + pregnant_woman + +
+ +
handleclickAcessibilidade(e.currentTarget.id)} + > + + + + + + +
+ +
handleclickAcessibilidade(e.currentTarget.id)} + > + + + +
+
+ +
+
+ + {/* INPUT: Nome do profissional (usado para habilitar a busca de horários) */} + +
- +
- -
-
- - -
- +
+
+ + +
- +
+ + {/* INPUT: Data de Atendimento (usada para habilitar a busca de horários) */} + +
+
+ +
+ {isModoEmergencia ? ( + // MODO EMERGÊNCIA: Input type="time" simples, sem restrição + <> +
+ + +
+
+ + +
+ + ) : // MODO PADRÃO + isReadyForSchedule ? ( + // ESTADO 2: Médico e Data ESCOLHIDOS -> Restringe para grade (SELECT) + <> +
+ + {carregandoHorarios ? ( + + ) : ( + + )} +
+ +
+ + +
+ + ) : ( + // ESTADO 1: Médico ou Data PENDENTE -> Permite entrada de tempo livre (INPUT TYPE="TIME") + <> +
+ + +
+
+ + +
+ + )} + +
+ + +
+
+
+ +
- - + +
-
+ + -
-
- - -
- -
- - -
- -
- - -
-
- - -
- - -
- - -
-
- - -
- - +
+ +
-
); }; -export default FormNovaConsulta; \ No newline at end of file +export default FormNovaConsulta; diff --git a/src/components/doctors/DoctorForm.jsx b/src/components/doctors/DoctorForm.jsx index 45ec0bf..4de5b56 100644 --- a/src/components/doctors/DoctorForm.jsx +++ b/src/components/doctors/DoctorForm.jsx @@ -1,37 +1,35 @@ -import React, { useState, useRef } from 'react'; -import { Link, useNavigate, useLocation } from 'react-router-dom'; +import React, { useState, useRef } from "react"; +import { Link, useNavigate, useLocation } from "react-router-dom"; function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { const navigate = useNavigate(); const location = useLocation(); const FormatTelefones = (valor) => { - const digits = String(valor).replace(/\D/g, '').slice(0, 11); + const digits = String(valor).replace(/\D/g, "").slice(0, 11); return digits - .replace(/(\d)/, '($1') - .replace(/(\d{2})(\d)/, '$1) $2') - .replace(/(\d)(\d{4})/, '$1 $2') - .replace(/(\d{4})(\d{4})/, '$1-$2'); + .replace(/(\d)/, "($1") + .replace(/(\d{2})(\d)/, "$1) $2") + .replace(/(\d)(\d{4})/, "$1 $2") + .replace(/(\d{4})(\d{4})/, "$1-$2"); }; const FormatCPF = (valor) => { - const digits = String(valor).replace(/\D/g, '').slice(0, 11); + const digits = String(valor).replace(/\D/g, "").slice(0, 11); return digits - .replace(/(\d{3})(\d)/, '$1.$2') - .replace(/(\d{3})(\d)/, '$1.$2') - .replace(/(\d{3})(\d{1,2})$/, '$1-$2'); + .replace(/(\d{3})(\d)/, "$1.$2") + .replace(/(\d{3})(\d)/, "$1.$2") + .replace(/(\d{3})(\d{1,2})$/, "$1-$2"); }; - const validarCPF = (cpf) => { - const cpfLimpo = cpf.replace(/\D/g, ''); - + const cpfLimpo = cpf.replace(/\D/g, ""); + if (cpfLimpo.length !== 11) return false; if (/^(\d)\1+$/.test(cpfLimpo)) return false; - - + let soma = 0; for (let i = 0; i < 9; i++) { soma += parseInt(cpfLimpo.charAt(i)) * (10 - i); @@ -46,15 +44,17 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { } resto = 11 - (soma % 11); let digito2 = resto === 10 || resto === 11 ? 0 : resto; - - - return digito1 === parseInt(cpfLimpo.charAt(9)) && digito2 === parseInt(cpfLimpo.charAt(10)); + + return ( + digito1 === parseInt(cpfLimpo.charAt(9)) && + digito2 === parseInt(cpfLimpo.charAt(10)) + ); }; const [avatarUrl, setAvatarUrl] = useState(null); const [showRequiredModal, setShowRequiredModal] = useState(false); const [emptyFields, setEmptyFields] = useState([]); - const [cpfError, setCpfError] = useState(''); + const [cpfError, setCpfError] = useState(""); const nomeRef = useRef(null); const cpfRef = useRef(null); @@ -70,63 +70,59 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { }); const handleToggleCollapse = (section) => { - setCollapsedSections(prevState => ({ + setCollapsedSections((prevState) => ({ ...prevState, - [section]: !prevState[section] + [section]: !prevState[section], })); }; const handleChange = (e) => { const { name, value, type, checked, files } = e.target; - if (value && emptyFields.includes(name)) { - setEmptyFields(prev => prev.filter(field => field !== name)); + setEmptyFields((prev) => prev.filter((field) => field !== name)); } - - if (name === 'cpf' && cpfError) { - setCpfError(''); + if (name === "cpf" && cpfError) { + setCpfError(""); } - if (type === 'checkbox') { - setFormData(prev => ({ ...prev, [name]: checked })); - } else if (type === 'file') { - setFormData(prev => ({ ...prev, [name]: files[0] })); + if (type === "checkbox") { + setFormData((prev) => ({ ...prev, [name]: checked })); + } else if (type === "file") { + setFormData((prev) => ({ ...prev, [name]: files[0] })); - if (name === 'foto' && files[0]) { + if (name === "foto" && files[0]) { const reader = new FileReader(); reader.onloadend = () => { setAvatarUrl(reader.result); }; reader.readAsDataURL(files[0]); - } else if (name === 'foto' && !files[0]) { + } else if (name === "foto" && !files[0]) { setAvatarUrl(null); } - - } else if (name.includes('cpf')) { + } else if (name.includes("cpf")) { let cpfFormatado = FormatCPF(value); - setFormData(prev => ({ ...prev, [name]: cpfFormatado })); + setFormData((prev) => ({ ...prev, [name]: cpfFormatado })); - - const cpfLimpo = cpfFormatado.replace(/\D/g, ''); + const cpfLimpo = cpfFormatado.replace(/\D/g, ""); if (cpfLimpo.length === 11) { if (!validarCPF(cpfFormatado)) { - setCpfError('CPF inválido'); + setCpfError("CPF inválido"); } else { - setCpfError(''); + setCpfError(""); } } - } else if (name.includes('phone')) { + } else if (name.includes("phone")) { let telefoneFormatado = FormatTelefones(value); - setFormData(prev => ({ ...prev, [name]: telefoneFormatado })); + setFormData((prev) => ({ ...prev, [name]: telefoneFormatado })); } else { - setFormData(prev => ({ ...prev, [name]: value })); + setFormData((prev) => ({ ...prev, [name]: value })); } }; const handleCepBlur = async () => { - const cep = formData.cep?.replace(/\D/g, ''); + const cep = formData.cep?.replace(/\D/g, ""); if (cep && cep.length === 8) { try { const response = await fetch(`https://viacep.com.br/ws/${cep}/json/`); @@ -134,50 +130,49 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { if (!data.erro) { setFormData((prev) => ({ ...prev, - street: data.logradouro || '', - neighborhood: data.bairro || '', - city: data.localidade || '', - state: data.uf || '' + street: data.logradouro || "", + neighborhood: data.bairro || "", + city: data.localidade || "", + state: data.uf || "", })); } else { setShowRequiredModal(true); - setEmptyFields(['cep']); + setEmptyFields(["cep"]); } } catch (error) { setShowRequiredModal(true); - setEmptyFields(['cep']); + setEmptyFields(["cep"]); } } }; - const scrollToEmptyField = (fieldName) => { let fieldRef = null; - + switch (fieldName) { - case 'full_name': + case "full_name": fieldRef = nomeRef; - setCollapsedSections(prev => ({ ...prev, dadosPessoais: true })); + setCollapsedSections((prev) => ({ ...prev, dadosPessoais: true })); break; - case 'cpf': + case "cpf": fieldRef = cpfRef; - setCollapsedSections(prev => ({ ...prev, dadosPessoais: true })); + setCollapsedSections((prev) => ({ ...prev, dadosPessoais: true })); break; - case 'email': + case "email": fieldRef = emailRef; - setCollapsedSections(prev => ({ ...prev, contato: true })); + setCollapsedSections((prev) => ({ ...prev, contato: true })); break; - case 'phone_mobile': + case "phone_mobile": fieldRef = telefoneRef; - setCollapsedSections(prev => ({ ...prev, contato: true })); + setCollapsedSections((prev) => ({ ...prev, contato: true })); break; - case 'crm_uf': + case "crm_uf": fieldRef = crmUfRef; - setCollapsedSections(prev => ({ ...prev, dadosPessoais: true })); + setCollapsedSections((prev) => ({ ...prev, dadosPessoais: true })); break; - case 'crm': + case "crm": fieldRef = crmRef; - setCollapsedSections(prev => ({ ...prev, dadosPessoais: true })); + setCollapsedSections((prev) => ({ ...prev, dadosPessoais: true })); break; default: return; @@ -186,21 +181,20 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { setTimeout(() => { if (fieldRef.current) { - fieldRef.current.scrollIntoView({ - behavior: 'smooth', - block: 'center' + fieldRef.current.scrollIntoView({ + behavior: "smooth", + block: "center", }); fieldRef.current.focus(); - - - fieldRef.current.style.border = '2px solid #dc3545'; - fieldRef.current.style.boxShadow = '0 0 0 0.2rem rgba(220, 53, 69, 0.25)'; - - + + fieldRef.current.style.border = "2px solid #dc3545"; + fieldRef.current.style.boxShadow = + "0 0 0 0.2rem rgba(220, 53, 69, 0.25)"; + setTimeout(() => { if (fieldRef.current) { - fieldRef.current.style.border = ''; - fieldRef.current.style.boxShadow = ''; + fieldRef.current.style.border = ""; + fieldRef.current.style.boxShadow = ""; } }, 3000); } @@ -210,18 +204,17 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { const handleSubmit = async () => { const missingFields = []; - if (!formData.full_name) missingFields.push('full_name'); - if (!formData.cpf) missingFields.push('cpf'); - if (!formData.email) missingFields.push('email'); - if (!formData.phone_mobile) missingFields.push('phone_mobile'); - if (!formData.crm_uf) missingFields.push('crm_uf'); - if (!formData.crm) missingFields.push('crm'); + if (!formData.full_name) missingFields.push("full_name"); + if (!formData.cpf) missingFields.push("cpf"); + if (!formData.email) missingFields.push("email"); + if (!formData.phone_mobile) missingFields.push("phone_mobile"); + if (!formData.crm_uf) missingFields.push("crm_uf"); + if (!formData.crm) missingFields.push("crm"); if (missingFields.length > 0) { setEmptyFields(missingFields); setShowRequiredModal(true); - - + setTimeout(() => { if (missingFields.length > 0) { scrollToEmptyField(missingFields[0]); @@ -230,26 +223,23 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { return; } - - const cpfLimpo = formData.cpf.replace(/\D/g, ''); + const cpfLimpo = formData.cpf.replace(/\D/g, ""); if (cpfLimpo.length !== 11) { setShowRequiredModal(true); - setEmptyFields(['cpf']); - setCpfError('CPF deve ter 11 dígitos'); - setTimeout(() => scrollToEmptyField('cpf'), 500); + setEmptyFields(["cpf"]); + setCpfError("CPF deve ter 11 dígitos"); + setTimeout(() => scrollToEmptyField("cpf"), 500); return; } - if (!validarCPF(formData.cpf)) { setShowRequiredModal(true); - setEmptyFields(['cpf']); - setCpfError('CPF inválido'); - setTimeout(() => scrollToEmptyField('cpf'), 500); + setEmptyFields(["cpf"]); + setCpfError("CPF inválido"); + setTimeout(() => scrollToEmptyField("cpf"), 500); return; } - try { await onSave({ ...formData }); @@ -300,7 +290,16 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { alignItems: "center", }} > -
Atenção
+
+ Atenção +
- + - @@ -631,4 +848,79 @@ function DoctorForm({ onSave, onCancel, formData, setFormData, isLoading }) { ); } +function WeeklyAvailabilityPicker() { + const days = ["Seg", "Ter", "Qua", "Qui", "Sex", "Sáb", "Dom"]; + const [availability, setAvailability] = useState( + days.reduce((acc, day) => ({ ...acc, [day]: [] }), {}) + ); + + const handleAddInterval = (day) => { + const newIntervals = [...availability[day], { start: "", end: "" }]; + const newAvailability = { ...availability, [day]: newIntervals }; + setAvailability(newAvailability); + }; + + const handleRemoveInterval = (day, index) => { + const newIntervals = availability[day].filter((_, i) => i !== index); + setAvailability({ ...availability, [day]: newIntervals }); + }; + + const handleTimeChange = (day, index, field, value) => { + const newIntervals = availability[day].map((interval, i) => + i === index ? { ...interval, [field]: value } : interval + ); + setAvailability({ ...availability, [day]: newIntervals }); + }; + + const handleSave = () => { + const data = []; + for (const [day, intervals] of Object.entries(availability)) { + intervals.forEach(({ start, end }) => { + const dayIndex = days.indexOf(day); + data.push({ day: dayIndex, start, end }); + }); + } + + fetch("https://mock.apidog.com/m1/1053378-0-default/rest/v1/doctor_availability", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(data), + }) + .then((res) => res.json()) + .then((res) => console.log("Salvo:", res)) + .catch((err) => console.error("Erro:", err)); + }; + + return ( +
+ {days.map((day) => ( +
+
{day}
+ {availability[day].map((interval, index) => ( +
+ handleTimeChange(day, index, "start", e.target.value)} + /> + até + handleTimeChange(day, index, "end", e.target.value)} + /> + +
+ ))} + +
+ ))} + +
+ ); +} + export default DoctorForm; \ No newline at end of file diff --git a/src/pages/DoctorCadastroManager.jsx b/src/pages/DoctorCadastroManager.jsx index 450e7f7..eb97f56 100644 --- a/src/pages/DoctorCadastroManager.jsx +++ b/src/pages/DoctorCadastroManager.jsx @@ -44,6 +44,7 @@ function DoctorCadastroManager() { number: doctorData.number || null, complement: doctorData.complement || null, phone2: doctorData.phone2 ? doctorData.phone2.replace(/\D/g, '') : null, + availability: doctorData.availability || {}, }; console.log('Dados limpos para envio:', cleanedData); diff --git a/src/pages/DoctorEditPage.jsx b/src/pages/DoctorEditPage.jsx index eecfb14..d5bd701 100644 --- a/src/pages/DoctorEditPage.jsx +++ b/src/pages/DoctorEditPage.jsx @@ -1,77 +1,115 @@ -import React from 'react' -import { GetDoctorByID } from '../components/utils/Functions-Endpoints/Doctor' -import DoctorForm from '../components/doctors/DoctorForm' -import { useAuth } from '../components/utils/AuthProvider' -import {useEffect, useState} from 'react' -import { useParams } from 'react-router-dom' -import API_KEY from '../components/utils/apiKeys' +import React, { useEffect, useState } from "react"; +import { GetDoctorByID } from "../components/utils/Functions-Endpoints/Doctor"; +import DoctorForm from "../components/doctors/DoctorForm"; +import { useAuth } from "../components/utils/AuthProvider"; +import { useParams } from "react-router-dom"; +import API_KEY from "../components/utils/apiKeys"; + const DoctorEditPage = () => { - const {getAuthorizationHeader, isAuthenticated} = useAuth(); - const [DoctorToPUT, setDoctorPUT] = useState({}) - - const Parametros = useParams() + const { getAuthorizationHeader } = useAuth(); + const [DoctorToPUT, setDoctorPUT] = useState({}); + const [availability, setAvailability] = useState([]); + const { id: DoctorID } = useParams(); - const DoctorID = Parametros.id + useEffect(() => { + const authHeader = getAuthorizationHeader(); -useEffect(() => { - - const authHeader = getAuthorizationHeader() + // Buscar médico + GetDoctorByID(DoctorID, authHeader) + .then((data) => setDoctorPUT(data[0])) + .catch((err) => console.error(err)); - GetDoctorByID(DoctorID, authHeader) - .then((data) => { - console.log(data, "médico vindo da API"); - setDoctorPUT(data[0]) - ; // supabase retorna array - }) - .catch((err) => console.error("Erro ao buscar paciente:", err)); + // Buscar disponibilidades + const fetchAvailability = async () => { + try { + const res = await fetch( + `https://mock.apidog.com/m1/1053378-0-default/rest/v1/doctor_availability/${DoctorID}`, + { headers: { apikey: API_KEY, Authorization: authHeader } } + ); + const data = await res.json(); + setAvailability(data.data || []); + } catch (err) { + console.error(err); + } + }; - -}, []) - const HandlePutDoctor = async () => { -const authHeader = getAuthorizationHeader() - + fetchAvailability(); + }, []); - var myHeaders = new Headers(); - myHeaders.append('apikey', API_KEY) - myHeaders.append("Authorization", authHeader); - myHeaders.append("Content-Type", "application/json"); - - var raw = JSON.stringify(DoctorToPUT); - - console.log("Enviando médico para atualização:", DoctorToPUT); - - var requestOptions = { - method: 'PUT', - headers: myHeaders, - body: raw, - redirect: 'follow' + // Atualizar uma disponibilidade + const updateAvailability = async (id, updatedData) => { + const authHeader = getAuthorizationHeader(); + try { + await fetch( + `https://mock.apidog.com/m1/1053378-0-default/rest/v1/doctor_availability/${id}`, + { + method: "PUT", + headers: { + apikey: API_KEY, + Authorization: authHeader, + "Content-Type": "application/json", + }, + body: JSON.stringify(updatedData), + } + ); + // atualizar localmente + setAvailability((prev) => + prev.map((a) => (a.id === id ? { ...a, ...updatedData } : a)) + ); + } catch (err) { + console.error(err); + } }; - try { - const response = await fetch(`https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors?id=eq.${DoctorID}`,requestOptions); - console.log(response) - - } catch (error) { - console.error("Erro ao atualizar paciente:", error); - throw error; - } - - } + // Deletar uma disponibilidade + const deleteAvailability = async (id) => { + const authHeader = getAuthorizationHeader(); + try { + await fetch( + `https://mock.apidog.com/m1/1053378-0-default/rest/v1/doctor_availability/${id}`, + { + method: "DELETE", + headers: { apikey: API_KEY, Authorization: authHeader }, + } + ); + setAvailability((prev) => prev.filter((a) => a.id !== id)); + } catch (err) { + console.error(err); + } + }; + const HandlePutDoctor = async () => { + const authHeader = getAuthorizationHeader(); + try { + await fetch( + `https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors?id=eq.${DoctorID}`, + { + method: "PUT", + headers: { + apikey: API_KEY, + Authorization: authHeader, + "Content-Type": "application/json", + }, + body: JSON.stringify(DoctorToPUT), + } + ); + } catch (err) { + console.error(err); + } + }; return (
- - - +
- ) -} + ); +}; -export default DoctorEditPage \ No newline at end of file +export default DoctorEditPage;