Adições finais
This commit is contained in:
parent
45ac442e4f
commit
be160327fb
@ -1,10 +1,9 @@
|
|||||||
//PatientForm.jsx
|
//PatientForm.jsx
|
||||||
//Nesta página falta: ajustar caminho do CSS
|
|
||||||
|
|
||||||
import { useState, useEffect, useRef } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { FormatTelefones, FormatPeso, FormatCPF } from '../../_assets/utils/Formatar/Format';
|
import { FormatTelefones, FormatPeso, FormatCPF } from '../../_assets/utils/Formatar/Format';
|
||||||
//import './PatientForm.css';
|
import '../../_assets/css/components/paciente/FormCadastroPaciente.css';
|
||||||
|
|
||||||
function PatientForm({ onSave, onCancel, formData, setFormData, isLoading }) {
|
function PatientForm({ onSave, onCancel, formData, setFormData, isLoading }) {
|
||||||
const [avatarUrl, setAvatarUrl] = useState(null);
|
const [avatarUrl, setAvatarUrl] = useState(null);
|
||||||
|
|||||||
@ -208,7 +208,6 @@ function DoctorCadastroManager() {
|
|||||||
<div className="page-heading">
|
<div className="page-heading">
|
||||||
<h3>Cadastro de Médicos</h3>
|
<h3>Cadastro de Médicos</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="page-content">
|
|
||||||
<section className="row">
|
<section className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<DoctorForm
|
<DoctorForm
|
||||||
@ -219,7 +218,6 @@ function DoctorCadastroManager() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
//PatientCadastroManager.jsx
|
//PatientCadastroManager.jsx
|
||||||
//Nesta página falta: mudar nomes
|
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
@ -226,7 +225,6 @@ function PatientCadastroManager() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="page-content">
|
|
||||||
<section className="row">
|
<section className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<PatientForm
|
<PatientForm
|
||||||
@ -238,7 +236,6 @@ function PatientCadastroManager() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
//DoctorEditPage.jsx
|
//DoctorEditPage.jsx
|
||||||
//Nesta página falta: mudar nomes
|
|
||||||
|
|
||||||
import { useState, useEffect, useMemo } from "react";
|
import { useState, useEffect, useMemo } from "react";
|
||||||
import { useParams, useNavigate, useLocation } from "react-router-dom";
|
import { useParams, useNavigate, useLocation } from "react-router-dom";
|
||||||
|
|||||||
@ -17,7 +17,8 @@ import dayjs from 'dayjs';
|
|||||||
dayjs.extend(weekday);
|
dayjs.extend(weekday);
|
||||||
dayjs.locale('pt-br');
|
dayjs.locale('pt-br');
|
||||||
|
|
||||||
const ENDPOINT_BASE = "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctor_exceptions";
|
const ENDPOINT_BASE = "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctor_exceptions";
|
||||||
|
const API_ROOT = "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1";
|
||||||
|
|
||||||
const getDateRange = (date, view) => {
|
const getDateRange = (date, view) => {
|
||||||
const startDayjs = dayjs(date);
|
const startDayjs = dayjs(date);
|
||||||
@ -28,27 +29,23 @@ const getDateRange = (date, view) => {
|
|||||||
toDate = startDayjs.format('YYYY-MM-DD');
|
toDate = startDayjs.format('YYYY-MM-DD');
|
||||||
titleRange = startDayjs.format('DD/MM/YYYY');
|
titleRange = startDayjs.format('DD/MM/YYYY');
|
||||||
} else if (view === 'semanal') {
|
} else if (view === 'semanal') {
|
||||||
|
let weekStart = startDayjs.startOf('week');
|
||||||
let weekStart = startDayjs.startOf('week');
|
if (weekStart.day() !== 1) {
|
||||||
if (weekStart.day() !== 1) {
|
weekStart = startDayjs.weekday(1);
|
||||||
weekStart = startDayjs.weekday(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const weekEnd = weekStart.add(6, 'day');
|
const weekEnd = weekStart.add(6, 'day');
|
||||||
|
|
||||||
fromDate = weekStart.format('YYYY-MM-DD');
|
fromDate = weekStart.format('YYYY-MM-DD');
|
||||||
toDate = weekEnd.format('YYYY-MM-DD');
|
toDate = weekEnd.format('YYYY-MM-DD');
|
||||||
titleRange = `Semana de ${weekStart.format('DD/MM')} a ${weekEnd.format('DD/MM')}`;
|
titleRange = `Semana de ${weekStart.format('DD/MM')} a ${weekEnd.format('DD/MM')}`;
|
||||||
|
|
||||||
} else if (view === 'mensal') {
|
} else if (view === 'mensal') {
|
||||||
const monthStart = startDayjs.startOf('month');
|
const monthStart = startDayjs.startOf('month');
|
||||||
const monthEnd = startDayjs.endOf('month');
|
const monthEnd = startDayjs.endOf('month');
|
||||||
|
|
||||||
fromDate = monthStart.format('YYYY-MM-DD');
|
fromDate = monthStart.format('YYYY-MM-DD');
|
||||||
toDate = monthEnd.format('YYYY-MM-DD');
|
toDate = monthEnd.format('YYYY-MM-DD');
|
||||||
titleRange = startDayjs.format('MMMM/YYYY').toUpperCase();
|
titleRange = startDayjs.format('MMMM/YYYY').toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
return { fromDate, toDate, titleRange };
|
return { fromDate, toDate, titleRange };
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -56,21 +53,25 @@ const ExcecoesDisponibilidade = () => {
|
|||||||
|
|
||||||
const { getAuthorizationHeader } = useAuth();
|
const { getAuthorizationHeader } = useAuth();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [pageNovaExcecao, setPageNovaExcecao] = useState(false);
|
const [pageNovaExcecao, setPageNovaExcecao] = useState(false);
|
||||||
const [excecoes, setExcecoes] = useState([]);
|
const [excecoes, setExcecoes] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||||
const [selectedExceptionId, setSelectedExceptionId] = useState(null);
|
const [selectedExceptionId, setSelectedExceptionId] = useState(null);
|
||||||
|
|
||||||
const [showSuccessModal, setShowSuccessModal] = useState(false);
|
const [showSuccessModal, setShowSuccessModal] = useState(false);
|
||||||
const [successMessage, setSuccessMessage] = useState('');
|
const [successMessage, setSuccessMessage] = useState('');
|
||||||
|
|
||||||
const [filtroMedicoId, setFiltroMedicoId] = useState('');
|
const [filtroMedicoId, setFiltroMedicoId] = useState('');
|
||||||
const [filtroData, setFiltroData] = useState(dayjs().format('YYYY-MM-DD'));
|
const [filtroData, setFiltroData] = useState(dayjs().format('YYYY-MM-DD'));
|
||||||
|
|
||||||
const [listaDeMedicos, setListaDeMedicos] = useState([]);
|
const [listaDeMedicos, setListaDeMedicos] = useState([]);
|
||||||
const [searchTermDoctor, setSearchTermDoctor] = useState('');
|
const [searchTermDoctor, setSearchTermDoctor] = useState('');
|
||||||
const [filteredDoctors, setFilteredDoctors] = useState([]);
|
const [filteredDoctors, setFilteredDoctors] = useState([]);
|
||||||
const [selectedDoctor, setSelectedDoctor] = useState(null);
|
const [selectedDoctor, setSelectedDoctor] = useState(null);
|
||||||
|
|
||||||
const [visualizacao, setVisualizacao] = useState('diario');
|
const [visualizacao, setVisualizacao] = useState('diario');
|
||||||
|
|
||||||
const resolveAuthHeader = () => {
|
const resolveAuthHeader = () => {
|
||||||
@ -80,56 +81,89 @@ const ExcecoesDisponibilidade = () => {
|
|||||||
} catch {
|
} catch {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const fetchExcecoes = useCallback(async (fromDate, toDate, doctorId) => {
|
const fetchExcecoes = useCallback(async (fromDate, toDate, doctorId) => {
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
let url = `${ENDPOINT_BASE}?select=*`;
|
let url = `${ENDPOINT_BASE}?select=*`;
|
||||||
|
|
||||||
if (doctorId) {
|
if (doctorId) url += `&doctor_id=eq.${doctorId}`;
|
||||||
url += `&doctor_id=eq.${doctorId}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
url += `&date=gte.${fromDate}&date=lte.${toDate}`;
|
url += `&date=gte.${fromDate}&date=lte.${toDate}`;
|
||||||
|
|
||||||
const myHeaders = new Headers();
|
const myHeaders = new Headers();
|
||||||
const authHeader = resolveAuthHeader();
|
const authHeader = resolveAuthHeader();
|
||||||
|
|
||||||
if (authHeader) myHeaders.append("Authorization", authHeader);
|
if (authHeader) myHeaders.append("Authorization", authHeader);
|
||||||
myHeaders.append("Content-Type", "application/json");
|
myHeaders.append("Content-Type", "application/json");
|
||||||
if (API_KEY) myHeaders.append("apikey", API_KEY);
|
if (API_KEY) myHeaders.append("apikey", API_KEY);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const requestOptions = {
|
const response = await fetch(url, { method: 'GET', headers: myHeaders });
|
||||||
method: 'GET',
|
const result = await response.json();
|
||||||
headers: myHeaders,
|
|
||||||
redirect: 'follow'
|
|
||||||
};
|
|
||||||
|
|
||||||
const response = await fetch(url, requestOptions);
|
|
||||||
const result = await response.json();
|
|
||||||
|
|
||||||
if (response.ok && Array.isArray(result)) {
|
|
||||||
setExcecoes(result);
|
|
||||||
} else {
|
|
||||||
setExcecoes([]);
|
|
||||||
console.error("Erro ao listar exceções (Status:", response.status, "):", result);
|
|
||||||
alert(`Erro ao carregar lista de exceções. Status: ${response.status}. Detalhes: ${result.message || JSON.stringify(result)}`);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Erro na requisição de listagem de exceções:', error);
|
|
||||||
setExcecoes([]);
|
|
||||||
alert("Erro de comunicação com o servidor ao listar exceções.");
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
}, [getAuthorizationHeader]);
|
|
||||||
|
|
||||||
const { fromDate, toDate, titleRange } = useMemo(() =>
|
if (response.ok && Array.isArray(result)) {
|
||||||
getDateRange(filtroData, visualizacao),
|
|
||||||
[filtroData, visualizacao]
|
// Buscar nomes de médicos
|
||||||
);
|
let doctors = [];
|
||||||
|
try {
|
||||||
|
doctors = await GetAllDoctors(authHeader);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Erro ao obter lista de médicos:', err);
|
||||||
|
doctors = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const doctorMap = {};
|
||||||
|
doctors.forEach(d => {
|
||||||
|
doctorMap[d.id] = d.full_name || d.name || d.display_name;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Buscar criadores
|
||||||
|
const createdByIds = [...new Set(result.map(r => r.created_by).filter(Boolean))];
|
||||||
|
const creatorMap = {};
|
||||||
|
|
||||||
|
if (createdByIds.length > 0) {
|
||||||
|
const idList = createdByIds.map(id => `"${id}"`).join(',');
|
||||||
|
const profilesUrl = `${API_ROOT}/profiles?select=*&id=in.(${idList})`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resProfiles = await fetch(profilesUrl, { method: 'GET', headers: myHeaders });
|
||||||
|
if (resProfiles.ok) {
|
||||||
|
const profiles = await resProfiles.json();
|
||||||
|
profiles.forEach(p => {
|
||||||
|
creatorMap[p.id] = p.full_name || p.name || p.username;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('Erro ao buscar profiles:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enriquecer exceções
|
||||||
|
const enriched = result.map(r => ({
|
||||||
|
...r,
|
||||||
|
doctor_name: doctorMap[r.doctor_id] || r.doctor_id,
|
||||||
|
created_by_name: creatorMap[r.created_by] || r.created_by
|
||||||
|
}));
|
||||||
|
|
||||||
|
setExcecoes(enriched);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
alert("Erro ao carregar exceções");
|
||||||
|
setExcecoes([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
alert("Erro ao comunicar com o servidor");
|
||||||
|
setExcecoes([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
|
||||||
|
}, [getAuthorizationHeader]);
|
||||||
|
|
||||||
|
const { fromDate, toDate, titleRange } = useMemo(() => getDateRange(filtroData, visualizacao), [filtroData, visualizacao]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchExcecoes(fromDate, toDate, filtroMedicoId);
|
fetchExcecoes(fromDate, toDate, filtroMedicoId);
|
||||||
@ -143,43 +177,29 @@ const ExcecoesDisponibilidade = () => {
|
|||||||
if (API_KEY) myHeaders.append("apikey", API_KEY);
|
if (API_KEY) myHeaders.append("apikey", API_KEY);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors?select=id,full_name', {
|
const response = await fetch(`${API_ROOT}/doctors?select=id,full_name`, { method: 'GET', headers: myHeaders });
|
||||||
method: 'GET',
|
|
||||||
headers: myHeaders
|
|
||||||
});
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const doctors = await response.json();
|
const doctors = await response.json();
|
||||||
setListaDeMedicos(doctors);
|
setListaDeMedicos(doctors);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (err) {
|
||||||
console.error('Erro ao buscar médicos:', error);
|
console.error('Erro ao buscar médicos:', err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchDoctors();
|
fetchDoctors();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSearchDoctors = (term) => {
|
const handleSearchDoctors = (term) => {
|
||||||
setSearchTermDoctor(term);
|
setSearchTermDoctor(term);
|
||||||
if (term.trim() === '') {
|
if (!term.trim()) return setFilteredDoctors([]);
|
||||||
setFilteredDoctors([]);
|
const filtered = listaDeMedicos.filter(doc => doc.full_name.toLowerCase().includes(term.toLowerCase()));
|
||||||
return;
|
|
||||||
}
|
|
||||||
const filtered = listaDeMedicos.filter(doc =>
|
|
||||||
doc.full_name.toLowerCase().includes(term.toLowerCase())
|
|
||||||
);
|
|
||||||
setFilteredDoctors(filtered);
|
setFilteredDoctors(filtered);
|
||||||
};
|
};
|
||||||
|
|
||||||
const limparFiltros = () => {
|
const deleteExcecao = async () => {
|
||||||
setSearchTermDoctor('');
|
if (!selectedExceptionId) return;
|
||||||
setFilteredDoctors([]);
|
|
||||||
setSelectedDoctor(null);
|
|
||||||
setFiltroMedicoId('');
|
|
||||||
setFiltroData(dayjs().format('YYYY-MM-DD'));
|
|
||||||
setVisualizacao('diario');
|
|
||||||
};
|
|
||||||
|
|
||||||
const deleteExcecao = async (id) => {
|
|
||||||
const myHeaders = new Headers();
|
const myHeaders = new Headers();
|
||||||
const authHeader = resolveAuthHeader();
|
const authHeader = resolveAuthHeader();
|
||||||
if (authHeader) myHeaders.append("Authorization", authHeader);
|
if (authHeader) myHeaders.append("Authorization", authHeader);
|
||||||
@ -187,33 +207,23 @@ const ExcecoesDisponibilidade = () => {
|
|||||||
myHeaders.append("Content-Type", "application/json");
|
myHeaders.append("Content-Type", "application/json");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${ENDPOINT_BASE}?id=eq.${id}`, {
|
const res = await fetch(`${ENDPOINT_BASE}?id=eq.${selectedExceptionId}`, { method: 'DELETE', headers: myHeaders });
|
||||||
method: 'DELETE',
|
|
||||||
headers: myHeaders,
|
|
||||||
redirect: 'follow'
|
|
||||||
});
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
setExcecoes(prev => prev.filter(x => x.id !== id));
|
setExcecoes(prev => prev.filter(x => x.id !== selectedExceptionId));
|
||||||
setShowDeleteModal(false);
|
setShowDeleteModal(false);
|
||||||
setSuccessMessage('Exceção excluída com sucesso!');
|
setSuccessMessage('Exceção excluída com sucesso!');
|
||||||
setShowSuccessModal(true);
|
setShowSuccessModal(true);
|
||||||
} else {
|
|
||||||
const text = await res.text();
|
|
||||||
console.error('Erro ao deletar exceção', res.status, text);
|
|
||||||
alert(`Erro ao excluir exceção. Status: ${res.status}. ${text}`);
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Erro na requisição de exclusão:', err);
|
console.error(err);
|
||||||
alert('Erro ao excluir exceção.');
|
alert('Erro ao excluir exceção');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleCancelForm = (recarregar = false) => {
|
const handleCancelForm = (reload = false) => {
|
||||||
setPageNovaExcecao(false);
|
setPageNovaExcecao(false);
|
||||||
if (recarregar) {
|
if (reload) fetchExcecoes(fromDate, toDate, filtroMedicoId);
|
||||||
fetchExcecoes(fromDate, toDate, filtroMedicoId);
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pageNovaExcecao) {
|
if (pageNovaExcecao) {
|
||||||
return <FormCriarExcecao onCancel={handleCancelForm} doctorID={filtroMedicoId} />;
|
return <FormCriarExcecao onCancel={handleCancelForm} doctorID={filtroMedicoId} />;
|
||||||
@ -221,259 +231,123 @@ const ExcecoesDisponibilidade = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<div className="d-flex justify-content-between align-items-center mb-3">
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '15px' }}>
|
|
||||||
<h1>Gerenciar Exceções de Disponibilidade</h1>
|
<h1>Gerenciar Exceções de Disponibilidade</h1>
|
||||||
<button
|
<button className="btn btn-primary" onClick={() => setPageNovaExcecao(true)}>+ Criar Nova Exceção</button>
|
||||||
className="btn-primary"
|
|
||||||
onClick={() => setPageNovaExcecao(true)}
|
|
||||||
style={{ padding: '10px 20px', fontSize: '14px', whiteSpace: 'nowrap' }}
|
|
||||||
>
|
|
||||||
+ Criar Nova Exceção
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="card p-3 mb-3" style={{ marginTop: '20px' }}>
|
{/* Filtros */}
|
||||||
<h5 className="mb-3">
|
<div className="card p-3 mb-4">
|
||||||
<i className="bi bi-funnel-fill me-2 text-primary"></i>
|
<h5 className="mb-3 fw-bold"><i className="bi bi-funnel-fill me-2 text-primary"></i>Filtros</h5>
|
||||||
Filtros
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
<div className="row g-3 mb-3">
|
<div className="row g-3 mb-3">
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<label className="form-label fw-bold">Buscar Médico</label>
|
<label className="form-label fw-bold">Buscar Médico</label>
|
||||||
<input
|
<input type="text" className="form-control" value={searchTermDoctor} placeholder="Digite o nome do médico" onChange={(e) => handleSearchDoctors(e.target.value)} />
|
||||||
type="text"
|
|
||||||
className="form-control"
|
{filteredDoctors.length > 0 && (
|
||||||
placeholder="Digite o nome do médico..."
|
|
||||||
value={searchTermDoctor}
|
|
||||||
onChange={(e) => handleSearchDoctors(e.target.value)}
|
|
||||||
/>
|
|
||||||
<small className="text-muted">Filtre as exceções por médico</small>
|
|
||||||
{searchTermDoctor && filteredDoctors.length > 0 && (
|
|
||||||
<div className="list-group mt-2" style={{ maxHeight: '200px', overflowY: 'auto' }}>
|
<div className="list-group mt-2" style={{ maxHeight: '200px', overflowY: 'auto' }}>
|
||||||
{filteredDoctors.map((doc) => (
|
{filteredDoctors.map(doc => (
|
||||||
<button
|
<button key={doc.id} className="list-group-item list-group-item-action" onClick={() => {
|
||||||
key={doc.id}
|
setSelectedDoctor(doc);
|
||||||
className="list-group-item list-group-item-action"
|
setFiltroMedicoId(doc.id);
|
||||||
onClick={() => {
|
setFilteredDoctors([]);
|
||||||
setSearchTermDoctor(doc.full_name);
|
setSearchTermDoctor(doc.full_name);
|
||||||
setFilteredDoctors([]);
|
}}>
|
||||||
setSelectedDoctor(doc);
|
|
||||||
setFiltroMedicoId(doc.id);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{doc.full_name}
|
{doc.full_name}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-md-6">
|
<div className="col-md-6">
|
||||||
<label className="form-label fw-bold">Data de Referência</label>
|
<label className="form-label fw-bold">Data base</label>
|
||||||
<input
|
<input type="date" className="form-control" value={filtroData} onChange={(e) => setFiltroData(e.target.value)} />
|
||||||
type="date"
|
|
||||||
className="form-control"
|
|
||||||
value={filtroData}
|
|
||||||
onChange={(e) => setFiltroData(e.target.value)}
|
|
||||||
/>
|
|
||||||
<small className="text-muted">Selecione a data base para visualização</small>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="d-flex justify-content-between align-items-center">
|
<div className="d-flex gap-2">
|
||||||
<div>
|
<button className={`btn btn-outline-primary ${visualizacao === 'diario' ? 'active' : ''}`} onClick={() => setVisualizacao('diario')}>Dia</button>
|
||||||
{selectedDoctor && (
|
<button className={`btn btn-outline-primary ${visualizacao === 'semanal' ? 'active' : ''}`} onClick={() => setVisualizacao('semanal')}>Semana</button>
|
||||||
<span className="badge bg-primary me-2">
|
<button className={`btn btn-outline-primary ${visualizacao === 'mensal' ? 'active' : ''}`} onClick={() => setVisualizacao('mensal')}>Mês</button>
|
||||||
<i className="bi bi-person-fill me-1"></i>
|
|
||||||
{selectedDoctor.full_name}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
<div className="contador-pacientes" style={{ display: 'inline-block' }}>
|
|
||||||
{excecoes.length} DE {excecoes.length} EXCEÇÕES ENCONTRADAS
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
className="btn btn-outline-secondary btn-sm"
|
|
||||||
onClick={limparFiltros}
|
|
||||||
>
|
|
||||||
<i className="bi bi-arrow-clockwise me-1"></i> Limpar Filtros
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='atendimento-eprocura'>
|
{/* Tabela */}
|
||||||
|
<section>
|
||||||
|
<h2 className="mb-3">Exceções em {titleRange} ({excecoes.length})</h2>
|
||||||
|
|
||||||
|
{loading ? (
|
||||||
|
<p>Carregando...</p>
|
||||||
|
) : excecoes.length === 0 ? (
|
||||||
|
<p>Nenhuma exceção encontrada.</p>
|
||||||
|
) : (
|
||||||
|
<table className="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Médico</th>
|
||||||
|
<th>Data</th>
|
||||||
|
<th>Início</th>
|
||||||
|
<th>Término</th>
|
||||||
|
<th>Motivo</th>
|
||||||
|
<th>Criado por</th>
|
||||||
|
<th>Ações</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{excecoes.map(exc => (
|
||||||
|
<tr key={exc.id}>
|
||||||
|
<td>{exc.doctor_name}</td>
|
||||||
|
<td>{dayjs(exc.date).format('DD/MM/YYYY')}</td>
|
||||||
|
<td>{exc.start_time ? dayjs(exc.start_time, 'HH:mm:ss').format('HH:mm') : '—'}</td>
|
||||||
|
<td>{exc.end_time ? dayjs(exc.end_time, 'HH:mm:ss').format('HH:mm') : '—'}</td>
|
||||||
|
<td>{exc.reason}</td>
|
||||||
|
<td>{exc.created_by_name}</td>
|
||||||
|
<td>
|
||||||
|
<button className="btn btn-sm btn-outline-secondary me-2" onClick={() => {
|
||||||
|
setFiltroMedicoId(exc.doctor_id);
|
||||||
|
setPageNovaExcecao(true);
|
||||||
|
}}>Editar</button>
|
||||||
|
|
||||||
<div className='container-btns-agenda-fila_esepera'>
|
<button className="btn btn-sm btn-outline-danger" onClick={() => {
|
||||||
<button
|
setSelectedExceptionId(exc.id);
|
||||||
className={`btn-agenda ${visualizacao === "diario" ? "opc-agenda-ativo" : ""}`}
|
setShowDeleteModal(true);
|
||||||
onClick={() => setVisualizacao('diario')}
|
}}>Excluir</button>
|
||||||
>
|
</td>
|
||||||
Dia
|
</tr>
|
||||||
</button>
|
))}
|
||||||
<button
|
</tbody>
|
||||||
className={`btn-fila-espera ${visualizacao === "semanal" ? "opc-filaespera-ativo" : ""}`}
|
</table>
|
||||||
onClick={() => setVisualizacao('semanal')}
|
)}
|
||||||
>
|
</section>
|
||||||
Semana
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className={`btn-fila-espera ${visualizacao === "mensal" ? "opc-filaespera-ativo" : ""}`}
|
|
||||||
onClick={() => setVisualizacao('mensal')}
|
|
||||||
>
|
|
||||||
Mês
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<section className='calendario-ou-filaespera'>
|
|
||||||
<div className="fila-container">
|
|
||||||
<h2 className="fila-titulo">Exceções em {titleRange} ({excecoes.length})</h2>
|
|
||||||
{loading ? (
|
|
||||||
<p>Carregando exceções...</p>
|
|
||||||
) : excecoes.length === 0 ? (
|
|
||||||
<p>Nenhuma exceção encontrada para os filtros aplicados.</p>
|
|
||||||
) : (
|
|
||||||
<table className="fila-tabela">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Médico (ID)</th>
|
|
||||||
<th>Data</th>
|
|
||||||
<th>Início</th>
|
|
||||||
<th>Término</th>
|
|
||||||
<th>Motivo</th>
|
|
||||||
<th>Criado por</th>
|
|
||||||
<th>Ações</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{excecoes.map((exc) => (
|
|
||||||
<tr key={exc.id}>
|
|
||||||
<td><p>{exc.doctor_id}</p></td>
|
|
||||||
<td>{dayjs(exc.date).format('DD/MM/YYYY')}</td>
|
|
||||||
<td>{exc.start_time ? dayjs(exc.start_time, 'HH:mm:ss').format('HH:mm') : '—'}</td>
|
|
||||||
<td>{exc.end_time ? dayjs(exc.end_time, 'HH:mm:ss').format('HH:mm') : '—'}</td>
|
|
||||||
<td><p>{exc.reason}</p></td>
|
|
||||||
<td>{exc.created_by || '—'}</td>
|
|
||||||
<td>
|
|
||||||
<div className="d-flex gap-2">
|
|
||||||
<button
|
|
||||||
className="btn btn-sm btn-edit"
|
|
||||||
onClick={() => {
|
|
||||||
setFiltroMedicoId(exc.doctor_id || '');
|
|
||||||
setPageNovaExcecao(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="bi bi-pencil me-1"></i> Editar
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
className="btn btn-sm btn-delete"
|
|
||||||
onClick={() => {
|
|
||||||
setSelectedExceptionId(exc.id);
|
|
||||||
setShowDeleteModal(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="bi bi-trash me-1"></i> Excluir
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
{/* Modal de exclusão */}
|
||||||
{showDeleteModal && (
|
{showDeleteModal && (
|
||||||
<div
|
<div className="modal-backdrop">
|
||||||
className="modal fade show delete-modal"
|
<div className="modal-container">
|
||||||
style={{
|
<h4>Confirmar exclusão</h4>
|
||||||
display: "block",
|
<p>Deseja realmente excluir esta exceção?</p>
|
||||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
<div className="d-flex gap-2 justify-content-end mt-3">
|
||||||
}}
|
<button className="btn btn-secondary" onClick={() => setShowDeleteModal(false)}>Cancelar</button>
|
||||||
tabIndex="-1"
|
<button className="btn btn-danger" onClick={deleteExcecao}>Excluir</button>
|
||||||
>
|
|
||||||
<div className="modal-dialog modal-dialog-centered">
|
|
||||||
<div className="modal-content">
|
|
||||||
<div className="modal-header" style={{ backgroundColor: '#dc3545', color: 'white' }}>
|
|
||||||
<h5 className="modal-title">
|
|
||||||
Confirmação de Exclusão
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="modal-body">
|
|
||||||
<p className="mb-0 fs-5">
|
|
||||||
Tem certeza que deseja excluir esta exceção?
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="modal-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-primary"
|
|
||||||
onClick={() => setShowDeleteModal(false)}
|
|
||||||
>
|
|
||||||
Cancelar
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-danger"
|
|
||||||
onClick={() => deleteExcecao(selectedExceptionId)}
|
|
||||||
>
|
|
||||||
Excluir
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
{showSuccessModal && (
|
{showSuccessModal && (
|
||||||
<div
|
<div className="modal-backdrop">
|
||||||
className="modal fade show delete-modal"
|
<div className="modal-container">
|
||||||
style={{
|
<h4>Sucesso</h4>
|
||||||
display: "block",
|
<p>{successMessage}</p>
|
||||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
<button className="btn btn-primary mt-2" onClick={() => setShowSuccessModal(false)}>Ok</button>
|
||||||
}}
|
|
||||||
tabIndex="-1"
|
|
||||||
>
|
|
||||||
<div className="modal-dialog modal-dialog-centered">
|
|
||||||
<div className="modal-content">
|
|
||||||
<div className="modal-header" style={{ backgroundColor: '#1e3a8a', color: 'white' }}>
|
|
||||||
<h5 className="modal-title">
|
|
||||||
Sucesso
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="modal-body">
|
|
||||||
<p className="mb-0 fs-5">
|
|
||||||
{successMessage}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="modal-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="btn btn-primary"
|
|
||||||
onClick={() => setShowSuccessModal(false)}
|
|
||||||
>
|
|
||||||
OK
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default ExcecoesDisponibilidade;
|
export default ExcecoesDisponibilidade;
|
||||||
Loading…
x
Reference in New Issue
Block a user