diff --git a/src/PagesAdm/gestao.css b/src/PagesAdm/gestao.css index 17c8e49..9951eae 100644 --- a/src/PagesAdm/gestao.css +++ b/src/PagesAdm/gestao.css @@ -1,26 +1,3 @@ -:root { - --primary-blue: #1e3a8a; - --light-blue: #E6F2FF; - --medium-blue: #D1E7FF; - --border-blue: #B8D4F0; - --warning-light: #FFF3CD; - --warning-dark: #856404; - --warning-border: #FFEAA7; - --danger-light: #F8D7DA; - --danger-dark: #721C24; - --danger-border: #F5C6CB; - --bg-light: #f8f9fa; - --border-light: #dee2e6; - --text-muted: #6c757d; - --text-dark: #495057; - --spacing-xs: 0.25rem; - --spacing-sm: 0.5rem; - --spacing-md: 1rem; - --spacing-lg: 1.5rem; - --border-radius: 0.375rem; -} - -/* ===== ESTILOS EXISTENTES DO DASHBOARD ===== */ .dashboard-container { padding: 2rem; font-family: 'Arial', sans-serif; @@ -67,6 +44,68 @@ box-shadow: 0 4px 12px rgba(30, 58, 138, 0.4); } +.filters-container { + background: #fff; + border-radius: 12px; + padding: 1.2rem; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + margin-bottom: 2rem; +} + +.filters-title { + font-size: 16px; + font-weight: bold; + margin-bottom: 0.3rem; + color: #333; +} + +.filters-subtitle { + font-size: 0.85rem; + color: #666; + margin-bottom: 1rem; +} + +.filters-content { + display: flex; + gap: 0.8rem; + align-items: center; +} + +.filters-input { + flex: 1; + padding: 0.5rem 0.8rem; + border: 1px solid #d1d5db; + border-radius: 6px; + font-size: 0.9rem; + color: #333; + min-width: 200px; + transition: all 0.2s ease; +} + +.filters-input:focus { + border-color: #1e3a8a; + box-shadow: 0 0 0 2px rgba(30, 58, 138, 0.1); + outline: none; +} + +.filters-select { + padding: 0.5rem 0.8rem; + border: 1px solid #d1d5db; + border-radius: 6px; + font-size: 0.9rem; + background: #fff; + color: #333; + cursor: pointer; + min-width: 140px; + transition: all 0.2s ease; +} + +.filters-select:focus { + border-color: #1e3a8a; + box-shadow: 0 0 0 2px rgba(30, 58, 138, 0.1); + outline: none; +} + .cards-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); @@ -117,396 +156,283 @@ .user-table-container { background: #fff; border-radius: 12px; - padding: 1.5rem; + padding: 1.2rem; box-shadow: 0 2px 8px rgba(0,0,0,0.1); - margin-top: 1rem; + margin-top: 2rem; } -/* ===== ESTILOS DA TABELA AVANÇADA ===== */ -.table-paciente-filters { - background-color: var(--bg-light); - border: 1px solid var(--border-light); - border-radius: var(--border-radius); - padding: var(--spacing-md); - margin-bottom: var(--spacing-md); +.user-table-container h2 { + font-size: 18px; + font-weight: bold; + margin-bottom: 0.3rem; + color: #333; } -.table-paciente-filters h5 { - color: var(--text-dark); - font-weight: 600; - font-size: 1.1rem; +.user-table-container p { + font-size: 0.9rem; + color: #666; + margin-bottom: 1rem; } -.table-paciente-table { +.user-table { width: 100%; border-collapse: collapse; - margin-top: 1rem; } -.table-paciente-table th { - background-color: var(--bg-light); - color: var(--text-dark); +.user-table th, +.user-table td { + padding: 10px 12px; + text-align: left; + border-bottom: 1px solid #e0e0e0; +} + +.user-table th { + background-color: #f3f4f6; + color: #333; font-weight: 600; - padding: 12px 8px; - border-bottom: 2px solid var(--border-light); - vertical-align: middle; font-size: 0.9rem; } -.table-paciente-table td { - padding: 12px 8px; - vertical-align: middle; - border-bottom: 1px solid var(--border-light); - font-size: 0.875rem; +.user-table tr { + transition: background-color 0.2s ease; } -.table-paciente-table tbody tr:hover { - background-color: rgba(0, 0, 0, 0.025); +.user-table tr:hover { + background-color: #f0f4ff; } -.insurance-badge { - background-color: transparent !important; - color: var(--text-dark) !important; - padding: 0.35em 0.65em; - font-size: 0.75em; +.profile-badge { + background-color: #1e3a8a; + color: white; + padding: 4px 10px; + border-radius: 6px; + font-size: 0.8rem; font-weight: 500; - border: 1px solid var(--border-light); - border-radius: var(--border-radius); + display: inline-block; } .status-badge { - padding: 0.35em 0.65em; - font-size: 0.75em; + padding: 4px 10px; + border-radius: 6px; + font-size: 0.8rem; + color: #fff; font-weight: 500; - border-radius: var(--border-radius); display: inline-block; text-transform: capitalize; } .status-badge.ativo { - background-color: var(--primary-blue); - color: white; + background-color: #1e3a8a; } .status-badge.inativo { - background-color: var(--text-muted); - color: white; + background-color: #6c757d; } -.anniversary-badge { - background-color: #ffc107; - color: #000; - padding: 0.35em 0.65em; - font-size: 0.75em; - border-radius: 50%; +.actions { + display: flex; + gap: 8px; + flex-wrap: wrap; } -.btn-view { - background-color: var(--light-blue) !important; - color: #004085 !important; - border: 1px solid var(--border-blue); - padding: 0.375rem 0.75rem; - font-size: 0.875rem; - border-radius: var(--border-radius); - transition: all 0.15s ease-in-out; -} - -.btn-view:hover { - background-color: var(--medium-blue) !important; - border-color: #9EC5FE; -} - -.btn-edit { - background-color: var(--warning-light) !important; - color: var(--warning-dark) !important; - border: 1px solid var(--warning-border); - padding: 0.375rem 0.75rem; - font-size: 0.875rem; - border-radius: var(--border-radius); - transition: all 0.15s ease-in-out; -} - -.btn-edit:hover { - background-color: #FFEEBA !important; - border-color: #FFE087; -} - -.btn-delete { - background-color: var(--danger-light) !important; - color: var(--danger-dark) !important; - border: 1px solid var(--danger-border); - padding: 0.375rem 0.75rem; - font-size: 0.875rem; - border-radius: var(--border-radius); - transition: all 0.15s ease-in-out; -} - -.btn-delete:hover { - background-color: #F1B0B7 !important; - border-color: #ED969E; -} - -.advanced-filters { - border: 1px solid var(--border-light); - border-radius: var(--border-radius); - background-color: white; -} - -.advanced-filters h6 { - color: var(--text-dark); - font-size: 0.9rem; - font-weight: 600; -} - -.form-label.fw-bold { - color: var(--text-dark); - font-size: 0.875rem; -} - -.delete-modal .modal-header { - background-color: rgba(220, 53, 69, 0.1); - border-bottom: 1px solid rgba(220, 53, 69, 0.2); -} - -.delete-modal .modal-title { - color: #dc3545; - font-weight: 600; -} - -.contador-pacientes { - background-color: var(--primary-blue); - color: white; - padding: 0.5em 0.75em; - font-size: 0.875em; - font-weight: 500; - border-radius: var(--border-radius); - text-align: center; - display: inline-block; -} - -/* Paginação */ -.pagination { - margin-bottom: 0; -} - -.page-link { - color: var(--text-dark); - border: 1px solid var(--border-light); - padding: 0.375rem 0.75rem; - font-size: 0.875rem; -} - -.page-link:hover { - color: var(--primary-blue); - background-color: #e9ecef; - border-color: var(--border-light); -} - -.page-item.active .page-link { - background-color: var(--primary-blue); - border-color: var(--primary-blue); - color: white; -} - -.page-item.disabled .page-link { - color: var(--text-muted); - background-color: var(--bg-light); - border-color: var(--border-light); -} - -/* ===== AJUSTES ESPECÍFICOS PARA OS FILTROS ===== */ -.table-paciente-filters .form-select-sm { - font-size: 0.825rem; - padding: 0.35rem 0.5rem; - border-radius: 0.25rem; -} - -.table-paciente-filters .form-label.small { +.action-btn { + border: none; + padding: 6px 12px; font-size: 0.8rem; font-weight: 500; - color: #6c757d; - min-width: auto; - white-space: nowrap; -} - -/* Alinhamento dos grupos de filtro */ -.table-paciente-filters .d-flex.align-items-center.gap-2 { - flex-wrap: nowrap; -} - -/* Ajuste do contador */ -.contador-pacientes { - background-color: #1e3a8a; - color: white; - padding: 0.4rem 0.8rem; - font-size: 0.8rem; - font-weight: 600; - border-radius: 0.375rem; - text-align: center; - display: inline-block; - letter-spacing: 0.5px; -} - -/* Botão de filtros avançados */ -.btn-link { - color: #1e3a8a !important; - font-weight: 500; + cursor: pointer; transition: all 0.2s ease; + border-radius: 4px; + display: inline-flex; + align-items: center; + gap: 4px; } -.btn-link:hover { - color: #162d6b !important; +.action-btn.detalhes { + background-color: #e6f2ff; + color: #004085; + border: 1px solid #b8d4ff; +} + +.action-btn.detalhes:hover { + background-color: #cce4ff; transform: translateY(-1px); } -/* Ajustes responsivos para mobile */ -@media (max-width: 768px) { - .dashboard-container { - padding: 1rem; - } - - .dashboard-header { - flex-direction: column; - gap: 1rem; - align-items: flex-start; - } - - .table-paciente-filters .d-flex.flex-wrap.align-items-center.gap-3 { - gap: 1rem !important; - flex-direction: column; - align-items: flex-start; - } - - .table-paciente-filters .d-flex.align-items-center.gap-2 { - width: 100%; - justify-content: space-between; - } - - .table-paciente-filters .form-select-sm.compact-select { - min-width: 100% !important; - margin-top: 0.25rem; - } - - .vr.d-none.d-md-block { - display: none !important; - } - - .table-paciente-table { - font-size: 0.875rem; - } - - .table-paciente-table th, - .table-paciente-table td { - padding: 10px 6px; - } - - .btn-view, - .btn-edit, - .btn-delete { - padding: 0.25rem 0.5rem; - font-size: 0.75rem; - } - - .table-paciente-filters .d-flex { - flex-direction: column; - gap: 0.5rem; - } - - .table-paciente-filters .form-select { - min-width: 100% !important; - } - - .patient-name-container { - flex-direction: column; - align-items: flex-start !important; - gap: 0.25rem; - } - - .d-flex.justify-content-between.align-items-center { - flex-direction: column; - gap: 1rem; - align-items: stretch !important; - } - - .table-paciente-table thead th:nth-child(6), - .table-paciente-table tbody td:nth-child(6) { - display: none; - } +.action-btn.editar { + background-color: #fff3cd; + color: #856405; + border: 1px solid #ffeaa7; } -/* Estilo para os selects quando estão ativos */ -.form-select-sm:focus { - border-color: #1e3a8a; - box-shadow: 0 0 0 0.2rem rgba(30, 58, 138, 0.25); +.action-btn.editar:hover { + background-color: #ffeaa7; + transform: translateY(-1px); } -/* Ajuste do botão limpar filtros */ -.btn-outline-secondary.btn-sm { - border-color: #6c757d; - color: #6c757d; - font-size: 0.8rem; - padding: 0.35rem 0.75rem; +.action-btn.excluir { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f1b0b7; } -.btn-outline-secondary.btn-sm:hover { - background-color: #6c757d; +.action-btn.excluir:hover { + background-color: #f1b0b7; + transform: translateY(-1px); +} + +.save-btn { + background-color: #1e3a8a; color: white; -} - -/* Melhoria na aparência dos filtros avançados */ -.advanced-filters { - background-color: #f8f9fa; - border: 1px solid #dee2e6 !important; -} - -.advanced-filters .form-control-sm { - font-size: 0.825rem; -} - -.advanced-filters h6 { - color: #495057; - font-size: 0.9rem; + border: none; + padding: 8px 16px; + border-radius: 6px; font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; } -.compact-select { - font-size: 0.9rem; - padding: 0.45rem 0.5rem; - min-width: 150px; +.save-btn:hover { + background-color: #162d6b; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(30, 58, 138, 0.3); } -/* Badge de Perfil */ -.badge-medico { +.edit-btn { + background-color: #fff3cd; + color: #856405; + border: 1px solid #ffeaa7; + padding: 8px 16px; + border-radius: 6px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; +} + +.edit-btn:hover { + background-color: #ffeaa7; + transform: translateY(-1px); +} + +html[data-bs-theme="dark"] .dashboard-container { + background-color: #121212; + color: #e0e0e0; +} + +html[data-bs-theme="dark"] .dashboard-header, +html[data-bs-theme="dark"] .dashboard-title, +html[data-bs-theme="dark"] .dashboard-subtitle { + color: #e0e0e0; +} + +html[data-bs-theme="dark"] .new-user-btn { background-color: #1e3a8a; - color: white; - padding: 0.35rem 0.75rem; - border-radius: 0.375rem; - font-size: 0.85rem; - font-weight: 500; } -.badge-paciente { +html[data-bs-theme="dark"] .new-user-btn:hover { + background-color: #162d6b; +} + +html[data-bs-theme="dark"] .filters-container, +html[data-bs-theme="dark"] .user-table-container { + background: #1a1a1a; + box-shadow: 0 2px 8px rgba(0,0,0,0.4); +} + +html[data-bs-theme="dark"] .filters-title, +html[data-bs-theme="dark"] .user-table-container h2 { + color: #e0e0e0; +} + +html[data-bs-theme="dark"] .filters-subtitle, +html[data-bs-theme="dark"] .user-table-container p { + color: #bdbdbd; +} + +html[data-bs-theme="dark"] .filters-input, +html[data-bs-theme="dark"] .filters-select { + background: #232323; + color: #e0e0e0; + border-color: #333; +} + +html[data-bs-theme="dark"] .filters-input:focus, +html[data-bs-theme="dark"] .filters-select:focus { + border-color: #1e3a8a; + box-shadow: 0 0 0 2px rgba(30, 58, 138, 0.2); +} + +html[data-bs-theme="dark"] .cards-container .card { + background-color: #181818; + color: #e0e0e0; + box-shadow: 0 2px 6px rgba(0,0,0,0.4); +} + +html[data-bs-theme="dark"] .highlight:hover { + background: #1a1f2e; + border: 1px solid #1e3a8a33; +} + +html[data-bs-theme="dark"] .card-label { + color: #888; +} + +html[data-bs-theme="dark"] .card-value { + color: #e0e0e0; +} + +html[data-bs-theme="dark"] .card-extra { + color: #bdbdbd; +} + +html[data-bs-theme="dark"] .card-extra.positive { + color: #1e3a8a; +} + +html[data-bs-theme="dark"] .user-table th { + background-color: #232323; + color: #e0e0e0; +} + +html[data-bs-theme="dark"] .user-table td { + color: #e0e0e0; + border-bottom: 1px solid #333; +} + +html[data-bs-theme="dark"] .user-table tr:hover { + background-color: #1a1f2e; +} + +html[data-bs-theme="dark"] .profile-badge { background-color: #1e3a8a; - color: white; - padding: 0.35rem 0.75rem; - border-radius: 0.375rem; - font-size: 0.85rem; - font-weight: 500; } -@media (max-width: 576px) { - .cards-container { - grid-template-columns: 1fr; - } - - .table-paciente-table thead th:nth-child(3), - .table-paciente-table thead th:nth-child(4), - .table-paciente-table tbody td:nth-child(3), - .table-paciente-table tbody td:nth-child(4) { - display: none; - } - - .user-table-container { - padding: 1rem; - } +html[data-bs-theme="dark"] .action-btn.detalhes { + background-color: #e6f2ff; + color: #004085; + border: 1px solid #b8d4ff; +} + +html[data-bs-theme="dark"] .action-btn.detalhes:hover { + background-color: #cce4ff; +} + +html[data-bs-theme="dark"] .action-btn.editar { + background-color: #fff3cd; + color: #856405; + border: 1px solid #ffeaa7; +} + +html[data-bs-theme="dark"] .action-btn.editar:hover { + background-color: #ffeaa7; +} + +html[data-bs-theme="dark"] .action-btn.excluir { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f1b0b7; +} + +html[data-bs-theme="dark"] .action-btn.excluir:hover { + background-color: #f1b0b7; } \ No newline at end of file diff --git a/src/PagesAdm/gestao.jsx b/src/PagesAdm/gestao.jsx index 3494da6..a5ecd88 100644 --- a/src/PagesAdm/gestao.jsx +++ b/src/PagesAdm/gestao.jsx @@ -1,186 +1,9 @@ -import React, { useState, useEffect } from "react"; +import React from "react"; import "./gestao.css"; -import { GetAllDoctors } from "../components/utils/Functions-Endpoints/Doctor"; -import { GetAllPatients } from "../components/utils/Functions-Endpoints/Patient"; -import API_KEY from "../components/utils/apiKeys"; function UserDashboard() { - // Estados principais - const [usuarios, setUsuarios] = useState([]); - const [busca, setBusca] = useState(""); - const [filtroPerfil, setFiltroPerfil] = useState("Todos"); - const [filtroStatus, setFiltroStatus] = useState("Todos"); - const [filtroDepartamento, setFiltroDepartamento] = useState("Todos"); - const [showFiltrosAvancados, setShowFiltrosAvancados] = useState(false); - const [loading, setLoading] = useState(true); - - // Estados de paginação - const [paginaAtual, setPaginaAtual] = useState(1); - const [itensPorPagina, setItensPorPagina] = useState(10); - - // Estados de ordenação - const [sortKey, setSortKey] = useState(null); - const [sortDir, setSortDir] = useState('asc'); - - // Estados para modais - const [showDeleteModal, setShowDeleteModal] = useState(false); - const [selectedUserId, setSelectedUserId] = useState(null); - - // Buscar dados reais da API - useEffect(() => { - const fetchUsuarios = async () => { - try { - setLoading(true); - const access_token = localStorage.getItem("access_token"); - const authHeader = access_token ? `Bearer ${access_token}` : null; - - // Buscar médicos e pacientes em paralelo - const [medicos, pacientes] = await Promise.all([ - GetAllDoctors(authHeader), - GetAllPatients(authHeader) - ]); - - console.log("Médicos:", medicos); - console.log("Pacientes:", pacientes); - - // Transformar médicos - const usuariosMedicos = medicos.map(medico => ({ - id: `doctor-${medico.id}`, - nome: medico.full_name || "Nome não informado", - email: medico.email || "Email não informado", - perfil: "Médico", - departamento: medico.specialization || "Não informado", - status: "ativo", - ultimoAcesso: medico.updated_at || medico.created_at || new Date().toISOString(), - dataCadastro: medico.created_at || new Date().toISOString(), - telefone: medico.phone || "Não informado", - crm: medico.crm - })); - - // Transformar pacientes - const usuariosPacientes = pacientes.map(paciente => ({ - id: `patient-${paciente.id}`, - nome: paciente.full_name || "Nome não informado", - email: paciente.email || "Email não informado", - perfil: "Paciente", - departamento: "Pacientes", - status: "ativo", - ultimoAcesso: paciente.updated_at || paciente.created_at || new Date().toISOString(), - dataCadastro: paciente.created_at || new Date().toISOString(), - telefone: paciente.phone || "Não informado", - cpf: paciente.cpf - })); - - // Combinar todos os usuários - const todosUsuarios = [...usuariosMedicos, ...usuariosPacientes]; - setUsuarios(todosUsuarios); - } catch (error) { - console.error("Erro ao buscar usuários:", error); - } finally { - setLoading(false); - } - }; - - fetchUsuarios(); - }, []); - - // Funções auxiliares - const formatarData = (dataString) => { - const data = new Date(dataString); - return data.toLocaleDateString('pt-BR', { - day: '2-digit', - month: '2-digit', - year: 'numeric', - hour: '2-digit', - minute: '2-digit' - }); - }; - - const calcularDiasDesdeUltimoAcesso = (dataString) => { - const ultimoAcesso = new Date(dataString); - const hoje = new Date(); - const diffTime = Math.abs(hoje - ultimoAcesso); - return Math.ceil(diffTime / (1000 * 60 * 60 * 24)); - }; - - // Filtragem - const usuariosFiltrados = usuarios.filter(usuario => { - const passaBusca = busca === "" || - usuario.nome.toLowerCase().includes(busca.toLowerCase()) || - usuario.email.toLowerCase().includes(busca.toLowerCase()); - - const passaPerfil = filtroPerfil === "Todos" || usuario.perfil === filtroPerfil; - const passaStatus = filtroStatus === "Todos" || usuario.status === filtroStatus; - const passaDepartamento = filtroDepartamento === "Todos" || usuario.departamento === filtroDepartamento; - - return passaBusca && passaPerfil && passaStatus && passaDepartamento; - }); - - // Ordenação - const aplicarOrdenacao = (arr) => { - if (!sortKey) return arr; - - const copia = [...arr]; - copia.sort((a, b) => { - if (sortKey === 'nome') { - return a.nome.localeCompare(b.nome); - } else if (sortKey === 'dataCadastro') { - return new Date(a.dataCadastro) - new Date(b.dataCadastro); - } else if (sortKey === 'ultimoAcesso') { - return new Date(a.ultimoAcesso) - new Date(b.ultimoAcesso); - } - return 0; - }); - - return sortDir === 'desc' ? copia.reverse() : copia; - }; - - const usuariosOrdenados = aplicarOrdenacao(usuariosFiltrados); - - // Paginação - const totalPaginas = Math.ceil(usuariosFiltrados.length / itensPorPagina); - const indiceInicial = (paginaAtual - 1) * itensPorPagina; - const indiceFinal = indiceInicial + itensPorPagina; - const usuariosPaginados = usuariosOrdenados.slice(indiceInicial, indiceFinal); - - // Navegação de páginas - const irParaPagina = (pagina) => setPaginaAtual(pagina); - const avancarPagina = () => paginaAtual < totalPaginas && setPaginaAtual(p => p + 1); - const voltarPagina = () => paginaAtual > 1 && setPaginaAtual(p => p - 1); - - const gerarNumerosPaginas = () => { - const paginas = []; - const paginasParaMostrar = 5; - let inicio = Math.max(1, paginaAtual - Math.floor(paginasParaMostrar / 2)); - let fim = Math.min(totalPaginas, inicio + paginasParaMostrar - 1); - inicio = Math.max(1, fim - paginasParaMostrar + 1); - - for (let i = inicio; i <= fim; i++) paginas.push(i); - return paginas; - }; - - // Funções de ação - const limparFiltros = () => { - setBusca(""); - setFiltroPerfil("Todos"); - setFiltroStatus("Todos"); - setFiltroDepartamento("Todos"); - setPaginaAtual(1); - }; - - const excluirUsuario = (id) => { - setUsuarios(prev => prev.filter(u => u.id !== id)); - setShowDeleteModal(false); - }; - - // Resetar paginação quando filtros mudarem - useEffect(() => { - setPaginaAtual(1); - }, [busca, filtroPerfil, filtroStatus, filtroDepartamento, sortKey, sortDir]); - return (
- {/* Header */}

Gestão de Usuários

@@ -191,363 +14,125 @@ function UserDashboard() {
- {/* Cards de Estatísticas */}

Total de Usuários

-

{loading ? "..." : usuarios.length}

-

Médicos e Pacientes

-
-
-

Médicos

-

{loading ? "..." : usuarios.filter(u => u.perfil === 'Médico').length}

-

Profissionais cadastrados

-
-
-

Pacientes

-

{loading ? "..." : usuarios.filter(u => u.perfil === 'Paciente').length}

-

Pacientes cadastrados

+

15

+

+3 este mês

Usuários Ativos

-

{loading ? "..." : usuarios.filter(u => u.status === 'ativo').length}

-

{usuarios.length > 0 ? ((usuarios.filter(u => u.status === 'ativo').length / usuarios.length) * 100).toFixed(1) : 0}% do total

+

12

+

80.0% do total

+
+
+

Tempo Médio Sessão

+

2h 30min

+

Última semana

+
+
+

Usuários Hoje

+

10

+

+2 desde ontem

+
+
+ +
+

Filtros

+

+ Use os filtros abaixo para encontrar usuários específicos +

+
+ + +
- {/* Container Principal da Tabela */}
- - {/* Filtros Avançados - FORMATADO */} -
-
- Filtros -
- - {/* Busca */} -
- setBusca(e.target.value)} - /> -
- - {/* Linha de Filtros Básicos */} -
- {/* Perfil */} -
- - -
- - {/* Status */} -
- - -
- - {/* Departamento */} -
- - setFiltroDepartamento(e.target.value || 'Todos')} - style={{ minWidth: "180px" }} - /> -
- - {/* Separador */} -
- - {/* Ordenação */} -
- - -
-
- - {/* Linha de Ações */} -
- - - -
- - {/* Filtros Avançados (Ocultos por padrão) */} - {showFiltrosAvancados && ( -
-
Filtros Avançados
-
-
- - setFiltroDepartamento(e.target.value || 'Todos')} - /> -
-
- - setFiltroPerfil(e.target.value || 'Todos')} - /> -
-
-
- )} - - {/* Contador */} -
-
- {usuariosFiltrados.length} DE {usuarios.length} USUÁRIOS ENCONTRADOS -
-
-
- - {/* Tabela de Usuários */} -
- {loading ? ( -
-
- Carregando... -
-

Carregando usuários...

-
- ) : ( - - - - - - - - - - - - {usuariosPaginados.length > 0 ? ( - usuariosPaginados.map((usuario) => ( - - - - - - - - )) - ) : ( - - - - )} - -
NomeEmailPerfilEspecialização/CategoriaAções
-
- {usuario.nome} -
-
{usuario.email} - - {usuario.perfil} - - {usuario.departamento} -
- - - -
-
-
- -

Nenhum usuário encontrado com os filtros aplicados.

- {(busca || filtroPerfil !== "Todos" || filtroStatus !== "Todos" || filtroDepartamento !== "Todos") && ( - - )} -
-
- )} - - {/* Paginação */} - {usuariosFiltrados.length > 0 && ( -
-
- Itens por página: - -
- -
- - Página {paginaAtual} de {totalPaginas} • - Mostrando {indiceInicial + 1}-{Math.min(indiceFinal, usuariosFiltrados.length)} de {usuariosFiltrados.length} usuários - - - -
-
- )} -
+

Usuários do Sistema

+

Lista completa de usuários e suas permissões

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NomeEmailPerfilDepartamentoStatusÚltimo AcessoAções
Ana Silvaana.silva@mediconnect.comGestão / CoordenaçãoAdministraçãoAtivo20/12/2024, 08:30 + + + +
Dr. Carlos Santoscarlos.santos@mediconnect.comMédicoCardiologiaAtivo19/12/2024, 14:20 + + + +
Maria Oliveiramaria.oliveira@mediconnect.comSecretáriaRecepçãoAtivo20/12/2024, 07:45 + + + +
Dr. João Pereirajoao.pereira@mediconnect.comMédicoOrtopediaInativo15/12/2024, 16:30 + + + +
- - {/* Modal de Confirmação de Exclusão */} - {showDeleteModal && ( -
- e.target.classList.contains("modal") && setShowDeleteModal(false) - } - > -
-
-
-
- Confirmação de Exclusão -
-
- -
-

- Tem certeza que deseja excluir este usuário? -

-

- Esta ação não pode ser desfeita. -

-
- -
- - - -
-
-
-
- )}
); } diff --git a/src/PagesMedico/DoctorAgendamentoManager.jsx b/src/PagesMedico/DoctorAgendamentoManager.jsx index febf524..567646c 100644 --- a/src/PagesMedico/DoctorAgendamentoManager.jsx +++ b/src/PagesMedico/DoctorAgendamentoManager.jsx @@ -1,4 +1,3 @@ -// src/PagesMedico/DoctorAgendamentoManager.jsx import React, { useState, useMemo, useEffect, useCallback } from "react"; import { useNavigate } from "react-router-dom"; import API_KEY from "../components/utils/apiKeys.js"; @@ -16,11 +15,9 @@ import { Edit, Trash2, CheckCircle, - FileText, } from "lucide-react"; import "../pages/style/Agendamento.css"; import "../pages/style/FilaEspera.css"; -import "../pages/style/TableDoctor.css"; import Spinner from "../components/Spinner.jsx"; dayjs.locale("pt-br"); @@ -293,18 +290,6 @@ const Agendamento = () => { setPageConsulta(true); }; - const handleCreateReport = (appointment) => { - navigate("/medico/novo-relatorio", { - state: { - appointment, - patient_id: appointment.patient_id, - doctor_id: appointment.doctor_id, - paciente_nome: appointment.paciente_nome, - medico_nome: appointment.medico_nome, - }, - }); - }; - const handleSearchMedicos = (term) => { setSearchTermDoctor(term); if (term.trim()) { @@ -464,17 +449,89 @@ const Agendamento = () => {

Agendar nova consulta

{!PageNovaConsulta ? (
+ {user?.role !== "doctor" && ( +
+
+ + Filtrar por Médico +
+
+ handleSearchMedicos(e.target.value)} + /> + + Buscar médico para filtrar consultas + + + {searchTermDoctor && FiltredTodosMedicos.length > 0 && ( +
+ {FiltredTodosMedicos.map((medico) => ( + + ))} +
+ )} +
+ + {MedicoFiltrado.id !== "vazio" && ( +
+ + + {searchTermDoctor} + + +
+ )} +
+ )}
@@ -484,7 +541,7 @@ const Agendamento = () => { style={{ display: "flex", gap: "10px", marginBottom: "20px" }} > ) : ( )} - - {app.status !== "cancelled" && ( - - )} - {app.status !== "cancelled" && (
-
Realizado
-
Confirmado
-
Agendado
-
Cancelado
+
+ Realizado +
+
+ Confirmado +
+
+ Agendado +
+
+ Cancelado +

{currentDate.format("MMMM [de] YYYY")}

) : ( -
-
-
-

Fila de Espera

-
-
-
-
- Filtros -
- - {/* Busca */} -
- setWaitlistSearch(e.target.value)} - /> +
+
+
+
+
+

Fila de Espera

- - {/* Linha de Filtros Básicos */} -
- {/* Ordenação */} -
- - -
-
- - {/* Contador */} -
-
- {filaEsperaFiltrada.length} DE {filaEsperaData.length} SOLICITAÇÕES ENCONTRADAS -
-
-
- - {/* ===== TABELA SIMPLIFICADA ===== */} -
- - - - - - - - - - - - {filaEsperaPaginada.length > 0 ? ( - filaEsperaPaginada.map((item, index) => ( - - - - - - - - )) - ) : ( - - - - )} - -
Nome do PacienteCPFMédico SolicitadoData da SolicitaçãoAções
{item?.Infos?.paciente_nome}{item?.Infos?.paciente_cpf}{item?.Infos?.medico_nome} - {dayjs(item.agendamento.scheduled_at).format("DD/MM/YYYY")} - -
-
- {showSpinner ? ( - - ) : ( - <> - -

Nenhuma solicitação encontrada.

- - )} + + + + +
-
- - {/* ===== PAGINAÇÃO ===== */} - {filaEsperaFiltrada.length > 0 && ( -
-
- Itens por página: - -
-
- - Página {waitPage} de {waitTotalPages} • Mostrando {waitIndiceInicial + 1}- - {Math.min(waitIndiceFinal, filaEsperaFiltrada.length)} de {filaEsperaFiltrada.length} - - +
+ + Página {waitPage} de {waitTotalPages} • + Mostrando {waitIndiceInicial + 1}- + {Math.min( + waitIndiceFinal, + filaEsperaFiltrada.length + )}{" "} + de {filaEsperaFiltrada.length} + + +
+
+ )}
- )} +
-
+
-
)}
diff --git a/src/PagesMedico/DoctorRelatorioManager.jsx b/src/PagesMedico/DoctorRelatorioManager.jsx index 3501732..6f86f00 100644 --- a/src/PagesMedico/DoctorRelatorioManager.jsx +++ b/src/PagesMedico/DoctorRelatorioManager.jsx @@ -10,7 +10,6 @@ import { useNavigate } from 'react-router-dom'; import html2pdf from 'html2pdf.js'; import TiptapViewer from './TiptapViewer'; import './styleMedico/DoctorRelatorioManager.css'; -import '../pages/style/TableDoctor.css'; const DoctorRelatorioManager = () => { const navigate = useNavigate(); @@ -26,15 +25,12 @@ const DoctorRelatorioManager = () => { const [relatorioModal, setRelatorioModal] = useState(null); const [termoPesquisa, setTermoPesquisa] = useState(''); const [filtroExame, setFiltroExame] = useState(''); + const [examesDisponiveis, setExamesDisponiveis] = useState([]); const [modalIndex, setModalIndex] = useState(0); - const [loadingPacientes, setLoadingPacientes] = useState(false); const [paginaAtual, setPaginaAtual] = useState(1); const [itensPorPagina, setItensPorPagina] = useState(10); - const [sortKey, setSortKey] = useState(''); - const [sortDir, setSortDir] = useState('asc'); - const totalPaginas = Math.max(1, Math.ceil(relatoriosFinais.length / itensPorPagina)); const indiceInicial = (paginaAtual - 1) * itensPorPagina; const indiceFinal = indiceInicial + itensPorPagina; @@ -50,6 +46,7 @@ const DoctorRelatorioManager = () => { if (authHeader) myHeaders.append('Authorization', authHeader); const requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' }; + let userId = null; let userFullName = null; try { @@ -63,10 +60,12 @@ const DoctorRelatorioManager = () => { console.warn('Não foi possível obter UserInfos (pode não estar logado):', err); } + const baseUrl = "https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/reports?select=*"; let data = []; if (userId) { + try { const res = await fetch(`${baseUrl}&doctor_id=eq.${userId}`, requestOptions); data = await res.json(); @@ -75,6 +74,7 @@ const DoctorRelatorioManager = () => { data = []; } + if ((!Array.isArray(data) || data.length === 0) && userId) { try { const res2 = await fetch(`${baseUrl}&created_by=eq.${userId}`, requestOptions); @@ -87,6 +87,7 @@ const DoctorRelatorioManager = () => { if ((!Array.isArray(data) || data.length === 0) && userFullName) { try { + const encodedName = encodeURIComponent(userFullName); const res3 = await fetch(`${baseUrl}&requested_by=eq.${encodedName}`, requestOptions); data = await res3.json(); @@ -107,6 +108,7 @@ const DoctorRelatorioManager = () => { } } + const uniqueMap = new Map(); (Array.isArray(data) ? data : []).forEach(r => { if (r && r.id) uniqueMap.set(r.id, r); @@ -140,13 +142,13 @@ const DoctorRelatorioManager = () => { }; }, [authHeader]); + useEffect(() => { const fetchRelData = async () => { - setLoadingPacientes(true); const pacientes = []; const medicos = []; - for (let i = 0; i < relatoriosOriginais.length; i++) { - const rel = relatoriosOriginais[i]; + for (let i = 0; i < relatoriosFinais.length; i++) { + const rel = relatoriosFinais[i]; try { const pacienteRes = await GetPatientByID(rel.patient_id, authHeader); @@ -160,6 +162,7 @@ const DoctorRelatorioManager = () => { const docRes = await GetDoctorByID(rel.doctor_id, authHeader); medicos.push(Array.isArray(docRes) ? docRes[0] : docRes); } else if (rel.created_by) { + const docRes = await GetDoctorByID(rel.created_by, authHeader); medicos.push(Array.isArray(docRes) ? docRes[0] : docRes); } else if (rel.requested_by) { @@ -173,82 +176,14 @@ const DoctorRelatorioManager = () => { } setPacientesComRelatorios(pacientes); setMedicosComRelatorios(medicos); - setLoadingPacientes(false); }; - if (relatoriosOriginais.length > 0) fetchRelData(); + if (relatoriosFinais.length > 0) fetchRelData(); else { setPacientesComRelatorios([]); setMedicosComRelatorios([]); - setLoadingPacientes(false); } - }, [relatoriosOriginais, authHeader]); - - // Filtragem e Ordenação - useEffect(() => { - // Aguardar o carregamento dos pacientes antes de filtrar - if (loadingPacientes) { - return; - } - - const q = (termoPesquisa || '').toLowerCase().trim(); - const ex = (filtroExame || '').toLowerCase().trim(); - - let items = relatoriosOriginais || []; - - // Aplicar filtros - if (q || ex) { - items = items.filter((r, idx) => { - let passaBusca = true; - let passaExame = true; - - if (q) { - const paciente = pacientesComRelatorios[idx]; - const patientName = (paciente?.full_name || r.patient_name || r.patient_fullname || '').toString().toLowerCase(); - const patientCPF = (paciente?.cpf || '').toString().toLowerCase(); - const pedido = (r.id || r.request_id || r.request || '').toString().toLowerCase(); - passaBusca = patientName.includes(q) || patientCPF.includes(q) || pedido.includes(q) || (r.patient_id && r.patient_id.toString().includes(q)); - } - - if (ex) { - passaExame = (r.exam || r.exame || '').toLowerCase().includes(ex); - } - - return passaBusca && passaExame; - }); - } - - // Aplicar ordenação - if (sortKey) { - items = [...items].sort((a, b) => { - let aValue = ''; - let bValue = ''; - - if (sortKey === 'paciente') { - const aIdx = relatoriosOriginais.findIndex(r => r.id === a.id); - const bIdx = relatoriosOriginais.findIndex(r => r.id === b.id); - const aPaciente = pacientesComRelatorios[aIdx]; - const bPaciente = pacientesComRelatorios[bIdx]; - aValue = (aPaciente?.full_name || a.patient_name || a.patient_fullname || '').toLowerCase(); - bValue = (bPaciente?.full_name || b.patient_name || b.patient_fullname || '').toLowerCase(); - } else if (sortKey === 'exame') { - aValue = (a.exam || a.exame || '').toLowerCase(); - bValue = (b.exam || b.exame || '').toLowerCase(); - } else if (sortKey === 'data') { - aValue = new Date(a.due_at || a.date || a.created_at || 0); - bValue = new Date(b.due_at || b.date || b.created_at || 0); - } - - if (aValue < bValue) return sortDir === 'asc' ? -1 : 1; - if (aValue > bValue) return sortDir === 'asc' ? 1 : -1; - return 0; - }); - } - - setRelatoriosFiltrados(items); - setRelatoriosFinais(items); - setPaginaAtual(1); - }, [termoPesquisa, filtroExame, relatoriosOriginais, sortKey, sortDir, pacientesComRelatorios, loadingPacientes]); + }, [relatoriosFinais, authHeader]); const abrirModal = (relatorio, pageIndex) => { const globalIndex = relatoriosFinais.findIndex(r => r.id === relatorio.id); @@ -258,11 +193,10 @@ const DoctorRelatorioManager = () => { setShowModal(true); }; + const limparFiltros = () => { setTermoPesquisa(''); setFiltroExame(''); - setSortKey(''); - setSortDir('asc'); setRelatoriosFinais(relatoriosOriginais); setPaginaAtual(1); }; @@ -282,257 +216,41 @@ const DoctorRelatorioManager = () => { html2pdf().set(opt).from(elemento).save(); }; - const irParaPagina = (pagina) => setPaginaAtual(pagina); - const avancarPagina = () => paginaAtual < totalPaginas && setPaginaAtual(p => p + 1); - const voltarPagina = () => paginaAtual > 1 && setPaginaAtual(p => p - 1); + const irParaPagina = (pagina) => { + setPaginaAtual(pagina); + }; + + const avancarPagina = () => { + if (paginaAtual < totalPaginas) { + setPaginaAtual(paginaAtual + 1); + } + }; + + const voltarPagina = () => { + if (paginaAtual > 1) { + setPaginaAtual(paginaAtual - 1); + } + }; const gerarNumerosPaginas = () => { const paginas = []; const paginasParaMostrar = 5; + let inicio = Math.max(1, paginaAtual - Math.floor(paginasParaMostrar / 2)); let fim = Math.min(totalPaginas, inicio + paginasParaMostrar - 1); + inicio = Math.max(1, fim - paginasParaMostrar + 1); - for (let i = inicio; i <= fim; i++) paginas.push(i); + + for (let i = inicio; i <= fim; i++) { + paginas.push(i); + } + return paginas; }; return (
-
-

Lista de Relatórios

-
- -
-
-
-

Relatórios Cadastrados

- - - -
- -
- {/* ===== FILTROS PADRONIZADOS ===== */} -
-
- Filtros -
- - {/* Busca */} -
- setTermoPesquisa(e.target.value)} - /> -
- - {/* Linha de Filtros Básicos - TUDO EM UMA LINHA SÓ */} -
- {/* Filtro Exame */} -
- - setFiltroExame(e.target.value)} - style={{ minWidth: "180px" }} - /> -
- - {/* Separador */} -
- - {/* Ordenação */} -
- - -
-
- - {/* Linha de Ações */} -
-
{/* Espaço vazio para alinhamento */} - - -
- - {/* Contador */} -
-
- {relatoriosFinais.length} DE {relatoriosOriginais.length} RELATÓRIOS ENCONTRADOS -
-
-
- - {/* ===== TABELA SIMPLIFICADA ===== */} -
- - - - - - - - - - - - {relatoriosPaginados.length > 0 ? ( - relatoriosPaginados.map((relatorio, index) => { - const globalIndex = relatoriosFinais.findIndex(r => r.id === relatorio.id); - const paciente = pacientesComRelatorios[globalIndex]; - const dataRelatorio = relatorio.due_at || relatorio.date || relatorio.created_at; - const dataFormatada = dataRelatorio ? new Date(dataRelatorio).toLocaleDateString('pt-BR') : '—'; - - return ( - - - - - - - - ); - }) - ) : ( - - - - )} - -
PacienteCPFExameDataAções
-
- {paciente?.full_name || 'Carregando...'} -
-
{paciente?.cpf || 'Carregando...'} - - {relatorio.exam || '—'} - - - - {dataFormatada} - - -
- - -
-
-
- -

Nenhum relatório encontrado com os filtros aplicados.

- {(termoPesquisa || filtroExame) && ( - - )} -
-
- - {/* ===== PAGINAÇÃO ===== */} - {relatoriosFinais.length > 0 && ( -
-
- Itens por página: - -
- -
- - Página {paginaAtual} de {totalPaginas} • - Mostrando {indiceInicial + 1}-{Math.min(indiceFinal, relatoriosFinais.length)} de {relatoriosFinais.length} relatórios - - - -
-
- )} -
-
-
-
- - {/* ===== MODAL DE DETALHES ===== */} - {showModal && relatorioModal && ( + {showModal && (
@@ -578,8 +296,161 @@ const DoctorRelatorioManager = () => {
)} + +

Lista de Relatórios

+
+
+
+
+
+

Relatórios Cadastrados

+ + + +
+
+
+
+ Filtros +
+
+
+
+ + setTermoPesquisa(e.target.value)} + /> +
+
+
+
+ + setFiltroExame(e.target.value)} + /> +
+
+
+ +
+
+
+
+ {relatoriosFinais.length} DE {relatoriosOriginais.length} RELATÓRIOS ENCONTRADOS +
+
+
+ +
+ + + + + + + + + + + {relatoriosPaginados.length > 0 ? ( + relatoriosPaginados.map((relatorio, index) => { + const globalIndex = relatoriosFinais.findIndex(r => r.id === relatorio.id); + const paciente = pacientesComRelatorios[globalIndex]; + return ( + + + + + + + ); + }) + ) : ( + + )} + +
PacienteCPFExame
{paciente?.full_name || 'Carregando...'}{paciente?.cpf || 'Carregando...'}{relatorio.exam} +
+ + +
+
Nenhum relatório encontrado.
+ + {relatoriosFinais.length > 0 && ( +
+
+ Itens por página: + +
+ +
+ + Página {paginaAtual} de {totalPaginas} • + Mostrando {indiceInicial + 1}-{Math.min(indiceFinal, relatoriosFinais.length)} de {relatoriosFinais.length} itens + + + +
+
+ )} +
+
+
+
+
+
); }; -export default DoctorRelatorioManager; \ No newline at end of file +export default DoctorRelatorioManager; diff --git a/src/PagesMedico/FormNovoRelatorio.jsx b/src/PagesMedico/FormNovoRelatorio.jsx index 4f9dfd0..2f2aabe 100644 --- a/src/PagesMedico/FormNovoRelatorio.jsx +++ b/src/PagesMedico/FormNovoRelatorio.jsx @@ -1,6 +1,5 @@ -// src/PagesMedico/FormNovoRelatorio.jsx import React, { useEffect, useState, useRef } from 'react'; -import { useNavigate, useLocation } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import API_KEY from '../components/utils/apiKeys'; import { useAuth } from '../components/utils/AuthProvider'; import TiptapEditor from './TiptapEditor'; @@ -13,7 +12,6 @@ const FormNovoRelatorio = () => { const { getAuthorizationHeader } = useAuth(); const authHeader = getAuthorizationHeader(); const navigate = useNavigate(); - const location = useLocation(); const [patients, setPatients] = useState([]); const [doctors, setDoctors] = useState([]); @@ -35,7 +33,6 @@ const FormNovoRelatorio = () => { const [showDoctorDropdown, setShowDoctorDropdown] = useState(false); const patientRef = useRef(); const doctorRef = useRef(); - const [lockedFromAppointment, setLockedFromAppointment] = useState(false); useEffect(() => { let mounted = true; @@ -132,24 +129,7 @@ const FormNovoRelatorio = () => { const handleEditorChange = (html) => setForm(prev => ({ ...prev, contentHtml: html })); - useEffect(() => { - if (location && location.state && location.state.appointment) { - const appt = location.state.appointment; - const paciente_nome = location.state.paciente_nome || appt.paciente_nome || ''; - const medico_nome = location.state.medico_nome || appt.medico_nome || ''; - setForm(prev => ({ - ...prev, - patient_id: appt.patient_id || prev.patient_id, - patient_name: paciente_nome || prev.patient_name, - patient_birth: prev.patient_birth || '', - doctor_id: appt.doctor_id || prev.doctor_id, - doctor_name: medico_nome || prev.doctor_name, - contentHtml: generateTemplate(paciente_nome, prev.patient_birth || '', medico_nome) - })); - setLockedFromAppointment(true); - } - }, [location]); - + // 🔹 Agora com created_by sendo o ID do usuário logado const handleSubmit = async (e) => { e.preventDefault(); if (!form.patient_id) return alert('Selecione o paciente (clicando no item) antes de salvar.'); @@ -169,6 +149,7 @@ const FormNovoRelatorio = () => { requested_by: form.doctor_name || '' }; + // Busca o id do usuário logado (via token) let userId = null; try { const token = authHeader?.replace(/^Bearer\s+/i, '') || ''; @@ -208,6 +189,8 @@ const FormNovoRelatorio = () => { } const created = await res.json(); + console.log('Relatório criado:', created); + window.dispatchEvent(new Event('reports:refresh')); alert('Relatório criado com sucesso!'); navigate('/medico/relatorios'); @@ -228,12 +211,11 @@ const FormNovoRelatorio = () => { { if (!lockedFromAppointment) { setPatientQuery(e.target.value); setShowPatientDropdown(true); } }} - onFocus={() => { if (!lockedFromAppointment) setShowPatientDropdown(true); }} - disabled={lockedFromAppointment} + value={patientQuery} + onChange={(e) => { setPatientQuery(e.target.value); setShowPatientDropdown(true); }} + onFocus={() => setShowPatientDropdown(true)} /> - {!lockedFromAppointment && showPatientDropdown && patientQuery && ( + {showPatientDropdown && patientQuery && (
    {filteredPatients.length > 0 ? filteredPatients.map(p => (
  • choosePatient(p)}> @@ -250,12 +232,11 @@ const FormNovoRelatorio = () => { { if (!lockedFromAppointment) { setDoctorQuery(e.target.value); setShowDoctorDropdown(true); } }} - onFocus={() => { if (!lockedFromAppointment) setShowDoctorDropdown(true); }} - disabled={lockedFromAppointment} + value={doctorQuery} + onChange={(e) => { setDoctorQuery(e.target.value); setShowDoctorDropdown(true); }} + onFocus={() => setShowDoctorDropdown(true)} /> - {!lockedFromAppointment && showDoctorDropdown && doctorQuery && ( + {showDoctorDropdown && doctorQuery && (
      {filteredDoctors.length > 0 ? filteredDoctors.map(d => (
    • chooseDoctor(d)}> @@ -280,4 +261,4 @@ const FormNovoRelatorio = () => { ); }; -export default FormNovoRelatorio; +export default FormNovoRelatorio; \ No newline at end of file diff --git a/src/PagesMedico/styleMedico/Agendamento.css b/src/PagesMedico/styleMedico/Agendamento.css index c4e80f6..5f01d68 100644 --- a/src/PagesMedico/styleMedico/Agendamento.css +++ b/src/PagesMedico/styleMedico/Agendamento.css @@ -1,7 +1,9 @@ -/* src/pages/style/Agendamento.css */ +/* --- Esconde a barra de unidade e profissional --- */ .unidade-selecionarprofissional { display: none; } + +/* --- Posiciona a barra de busca corretamente --- */ .busca-atendimento { display: flex; align-items: center; @@ -9,11 +11,53 @@ padding: 0 10px; gap: 15px; } + .busca-atendimento > div:first-child { - width: 400px; - display: flex; - align-items: center; + width: 400px; + display: flex; + align-items: center; } + +@media (max-width: 768px) { + .busca-atendimento { + flex-direction: column; + align-items: stretch; + gap: 10px; + } + + .busca-atendimento > div:first-child { + width: 100%; + } + + .btns-e-legenda-container { + flex-direction: column; + align-items: flex-start; + gap: 10px; + } + + .legenda-tabela { + flex-wrap: wrap; + gap: 8px; + } +} + +@media (max-width: 576px) { + .busca-atendimento { + padding: 0 5px; + } + + .btns-e-legenda-container { + padding: 0 5px; + } + + .btn-selecionar-tabeladia, + .btn-selecionar-tabelasemana, + .btn-selecionar-tabelames { + padding: 6px 8px; + font-size: medium; + } +} + .busca-atendimento input { margin-left: 8px; border-radius: 8px; @@ -21,6 +65,7 @@ width: 100%; border: 1px solid #ccc; } + .busca-atendimento select { padding: 8px; border-radius: 8px; @@ -29,6 +74,8 @@ font-weight: bold; border: none; } + +/* --- Estilos dos botões de Dia, Semana, Mês --- */ .btn-selecionar-tabeladia, .btn-selecionar-tabelasemana, .btn-selecionar-tabelames { @@ -39,12 +86,15 @@ border-style: hidden; cursor: pointer; } + .btn-selecionar-tabeladia { border-radius: 10px 0px 0px 10px; } + .btn-selecionar-tabelames { border-radius: 0px 10px 10px 0px; } + .btn-selecionar-tabeladia.ativo, .btn-selecionar-tabelasemana.ativo, .btn-selecionar-tabelames.ativo { @@ -52,6 +102,8 @@ border-color: darkcyan; font-weight: bolder; } + +/* --- Container dos botões e legenda --- */ .btns-e-legenda-container { display: flex; justify-content: space-between; @@ -59,10 +111,13 @@ margin-top: 10px; padding: 0 10px; } + +/* --- Legendas --- */ .legenda-tabela { display: flex; gap: 15px; } + #status-card-consulta-realizado, .legenda-item-realizado { background-color: #b7ffbd; border: 3px solid #91d392; @@ -70,6 +125,7 @@ font-weight: bold; border-radius: 10px; } + #status-card-consulta-cancelado, .legenda-item-cancelado { background-color: #ffb7cc; border: 3px solid #ff6c84; @@ -77,6 +133,7 @@ font-weight: bold; border-radius: 10px; } + #status-card-consulta-confirmado, .legenda-item-confirmado { background-color: #eef8fb; border: 3px solid #d8dfe7; @@ -84,6 +141,7 @@ font-weight: bold; border-radius: 10px; } + #status-card-consulta-agendado, .legenda-item-agendado { background-color: #f7f7c4; border: 3px solid #f3ce67; @@ -91,6 +149,8 @@ font-weight: bold; border-radius: 10px; } + +/* --- Estrutura Geral --- */ .calendario { border-collapse: collapse; width: 100%; @@ -100,9 +160,11 @@ border: 1px solid #eee; background-color: #ffffff; } + .calendario-ou-filaespera { margin-top: 0; } + .container-btns-agenda-fila_esepera { margin-top: 30px; display: flex; @@ -110,6 +172,7 @@ gap: 20px; margin-left: 20px; } + .btn-fila-espera, .btn-agenda { background-color: transparent; @@ -121,35 +184,44 @@ font-weight: bold; cursor: pointer; } + .opc-filaespera-ativo, .opc-agenda-ativo { color: white; background-color: #5980fd; } + + +/* Dark mode styles */ html[data-bs-theme="dark"] { background-color: #181a1b; color: #e0e0e0; } + html[data-bs-theme="dark"] .calendario { background-color: #23272a; border: 1px solid #333; box-shadow: 0 4px 12px rgba(0,0,0,0.25); } + html[data-bs-theme="dark"] .busca-atendimento input { background-color: #23272a; color: #e0e0e0; border: 1px solid #444; } + html[data-bs-theme="dark"] .busca-atendimento select { background-color: #5980fd; color: #fff; } + html[data-bs-theme="dark"] .btn-selecionar-tabeladia, html[data-bs-theme="dark"] .btn-selecionar-tabelasemana, html[data-bs-theme="dark"] .btn-selecionar-tabelames { background-color: #23272a; color: #e0e0e0; } + html[data-bs-theme="dark"] .btn-selecionar-tabeladia.ativo, html[data-bs-theme="dark"] .btn-selecionar-tabelasemana.ativo, html[data-bs-theme="dark"] .btn-selecionar-tabelames.ativo { @@ -157,66 +229,44 @@ html[data-bs-theme="dark"] .btn-selecionar-tabelames.ativo { color: #fff; border-color: #3a5ccc; } + html[data-bs-theme="dark"] .btn-fila-espera, html[data-bs-theme="dark"] .btn-agenda { background-color: #23272a; color: #e0e0e0; border-bottom: 3px solid transparent; } + html[data-bs-theme="dark"] .opc-filaespera-ativo, html[data-bs-theme="dark"] .opc-agenda-ativo { background-color: #5980fd; color: #fff; } + html[data-bs-theme="dark"] #status-card-consulta-realizado, html[data-bs-theme="dark"] .legenda-item-realizado { background-color: #1e2e1e; border: 3px solid #2e4d2e; color: #b7ffbd; } + html[data-bs-theme="dark"] #status-card-consulta-cancelado, html[data-bs-theme="dark"] .legenda-item-cancelado { background-color: #2e1e23; border: 3px solid #4d2e36; color: #ffb7cc; } + html[data-bs-theme="dark"] #status-card-consulta-confirmado, html[data-bs-theme="dark"] .legenda-item-confirmado { background-color: #1e2327; border: 3px solid #2e3a4d; color: #eef8fb; } + html[data-bs-theme="dark"] #status-card-consulta-agendado, html[data-bs-theme="dark"] .legenda-item-agendado { background-color: #2e2e1e; border: 3px solid #4d4d2e; color: #f7f7c4; -} -.appointment-actions .btn-action { - margin-left: 6px; -} -.btn-action.btn-report-blue { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 6px; - padding: 8px 10px; - border-radius: 10px; - border: none; - cursor: pointer; - font-size: 0.95rem; - line-height: 1; - box-shadow: 0 4px 8px rgba(41, 98, 255, 0.12); - transition: transform 0.08s ease, box-shadow 0.12s ease; - background: linear-gradient(180deg, #2f6bff 0%, #1e52d6 100%); - color: #ffffff; -} -.btn-action.btn-report-blue:hover, -.btn-action.btn-report-blue:focus { - transform: translateY(-2px); - box-shadow: 0 6px 14px rgba(41, 98, 255, 0.18); -} -.btn-action.btn-report-blue svg { - stroke: #ffffff; - color: #ffffff; -} +} \ No newline at end of file diff --git a/src/PagesMedico/styleMedico/NovoRelatorioAudio.css b/src/PagesMedico/styleMedico/NovoRelatorioAudio.css index 8a38863..591eef3 100644 --- a/src/PagesMedico/styleMedico/NovoRelatorioAudio.css +++ b/src/PagesMedico/styleMedico/NovoRelatorioAudio.css @@ -85,13 +85,35 @@ @media (max-width: 900px) { .ai-editor-container { flex-direction: column; + min-height: auto; } .editor-sidebar { width: 100%; height: auto; + box-shadow: 0 4px 10px rgba(0,0,0,0.1); + } + .preview-area { + padding: 20px; } .paper-a4 { width: 100%; + min-height: auto; padding: 15mm; + box-shadow: none; + } +} + +@media (max-width: 576px) { + .ai-editor-container { + padding: 0; + } + .editor-sidebar { + padding: 15px; + } + .preview-area { + padding: 10px; + } + .paper-a4 { + padding: 10mm; } } \ No newline at end of file diff --git a/src/PagesPaciente/ConsultasPaciente.jsx b/src/PagesPaciente/ConsultasPaciente.jsx index 4f5fb41..45de7a0 100644 --- a/src/PagesPaciente/ConsultasPaciente.jsx +++ b/src/PagesPaciente/ConsultasPaciente.jsx @@ -10,7 +10,6 @@ import localeData from 'dayjs/plugin/localeData'; import { ChevronLeft, ChevronRight, Edit, Trash2 } from 'lucide-react'; import "../pages/style/Agendamento.css"; import '../pages/style/FilaEspera.css'; -import '../pages/style/TableDoctor.css'; import Spinner from '../components/Spinner.jsx'; dayjs.locale('pt-br'); @@ -38,13 +37,6 @@ const Agendamento = ({ setDictInfo }) => { const [appointmentToCancel, setAppointmentToCancel] = useState(null); const [cancellationReason, setCancellationReason] = useState(''); - // Estados para filtro, ordenação e paginação da fila de espera - 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 = useMemo(() => getAuthorizationHeader(), [getAuthorizationHeader]); useEffect(() => { @@ -179,51 +171,6 @@ const Agendamento = ({ setDictInfo }) => { const weekDays = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb']; const handleDateClick = (day) => setSelectedDay(day); - // Filtro e ordenação da fila de espera - const filaEsperaFiltrada = useMemo(() => { - if (!waitlistSearch.trim()) return filaEsperaData; - const term = waitlistSearch.toLowerCase(); - return filaEsperaData.filter( - (item) => - (item?.Infos?.medico_nome?.toLowerCase() || '').includes(term) - ); - }, [waitlistSearch, filaEsperaData]); - - const applySortingWaitlist = (arr) => { - if (!Array.isArray(arr) || !waitSortKey) return arr; - const copy = [...arr]; - if (waitSortKey === 'medico') { - copy.sort((a, b) => (a?.Infos?.medico_nome || '').localeCompare(b?.Infos?.medico_nome || '')); - } else if (waitSortKey === 'data') { - copy.sort((a, b) => - new Date(a?.agendamento?.created_at || 0) - new Date(b?.agendamento?.created_at || 0) - ); - } - if (waitSortDir === 'desc') copy.reverse(); - return copy; - }; - - 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]); - - if (isLoading) { return (
      @@ -333,173 +280,46 @@ const Agendamento = ({ setDictInfo }) => {
) : ( -
-
-
-

Minhas Solicitações em Fila de Espera

-
-
- {/* ===== FILTROS PADRONIZADOS ===== */} -
-
- Filtros -
- - {/* Busca */} -
- setWaitlistSearch(e.target.value)} - /> -
- - {/* Linha de Filtros Básicos */} -
- {/* Ordenação */} -
- - -
-
- - {/* Contador */} -
-
- {filaEsperaFiltrada.length} DE {filaEsperaData.length} SOLICITAÇÕES ENCONTRADAS -
-
-
- - {/* ===== TABELA SIMPLIFICADA ===== */} -
- - - - - - - - - - {filaEsperaPaginada.length > 0 ? ( - filaEsperaPaginada.map((item) => ( - - - - +
+
+
+
+

Minhas Solicitações em Fila de Espera

+
+
+
Médico SolicitadoData da SolicitaçãoAções
Dr(a). {item.Infos?.medico_nome}{dayjs(item.agendamento.created_at).format('DD/MM/YYYY HH:mm')} - -
+ + + + + - )) - ) : ( - - - - )} - -
Médico SolicitadoData da SolicitaçãoAções
-
- -

Nenhuma solicitação na fila de espera.

-
-
- - {/* ===== PAGINAÇÃO ===== */} - {filaEsperaFiltrada.length > 0 && ( -
-
- Itens por página: - -
- -
- - Página {waitPage} de {waitTotalPages} • - Mostrando {waitIndiceInicial + 1}-{Math.min(waitIndiceFinal, filaEsperaFiltrada.length)} de {filaEsperaFiltrada.length} solicitações - - - -
+ + + ))) : ( + + +
Nenhuma solicitação na fila de espera.
+ + + )} + +
- )} +
-
+
)} @@ -508,52 +328,38 @@ const Agendamento = ({ setDictInfo }) => { )} - {/* ===== MODAL DE CANCELAMENTO ===== */} {isCancelModalOpen && ( -
e.target.classList.contains("modal") && setIsCancelModalOpen(false)} - > -
-
-
-
Confirmação de Cancelamento
-
- -
-

Deseja realmente cancelar esta consulta?

-

Esta ação não pode ser desfeita.

- - - -
- -
- - - -
+
+
+
+

Confirmação de Cancelamento

+ +
+
+

Qual o motivo do cancelamento?

+ +
+
+ +
diff --git a/src/PagesPaciente/style.css b/src/PagesPaciente/style.css index 2d0b21f..e675e55 100644 --- a/src/PagesPaciente/style.css +++ b/src/PagesPaciente/style.css @@ -1,14 +1,71 @@ /* Estilo geral do card para agrupar e dar um formato */ .card-consulta { - background-color: #007bff; /* Um tom de azul padrão */ - display: flex; /* Para colocar horário e info lado a lado */ - border-radius: 10px; /* Cantos arredondados */ - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Sombra suave */ - overflow: hidden; /* Garante que o fundo azul não 'vaze' */ - /* width: 280px; /* Largura de exemplo */ + background-color: #007bff; + display: flex; + border-radius: 10px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + overflow: hidden; margin: 20px; - font-family: Arial, sans-serif; /* Fonte legível */ + font-family: Arial, sans-serif; +} + +@media (max-width: 768px) { + .card-consulta { + flex-direction: column; + margin: 10px; + } + + .horario-container { + border-right: none; + border-bottom: 1px solid #0056b3; + padding: 10px 15px; + } + + .horario { + font-size: 1.8em; + } + + .info-container { + flex-direction: column; + align-items: flex-start; + gap: 1rem; + padding: 15px; + } + + .actions-container { + opacity: 1; + visibility: visible; + background: none; + backdrop-filter: none; + -webkit-backdrop-filter: none; + border: none; + box-shadow: none; + margin-left: 0; + padding: 0; + justify-content: flex-start; + margin-top: 10px; + } + + .card-consulta:hover .actions-container { + transform: none; + } +} + +@media (max-width: 576px) { + .horario { + font-size: 1.5em; + } + + .informacao { + font-size: 1em; + } + + .btn-edit-custom-style, + .btn-delete-custom-style { + padding: 6px 10px; + font-size: 0.8rem; + } } /* 1. Estilo para o Horário (Fundo Azul e Texto Branco/Grande) */ diff --git a/src/components/AgendarConsulta/style/card-consulta.css b/src/components/AgendarConsulta/style/card-consulta.css index 34d8dea..285a558 100644 --- a/src/components/AgendarConsulta/style/card-consulta.css +++ b/src/components/AgendarConsulta/style/card-consulta.css @@ -1,3 +1,10 @@ +@media (max-width: 768px) { + .container-cardconsulta { + padding-right: 80px; /* Espaço para os botões */ + position: relative; + } +} + .actions-container { display: flex; gap: 8px; @@ -84,4 +91,50 @@ .tabelamensal .container-cardconsulta{ width: 24rem; +} + +@media (max-width: 768px) { + .actions-container { + opacity: 1; + visibility: visible; + background: none; + backdrop-filter: none; + -webkit-backdrop-filter: none; + border: none; + box-shadow: none; + margin-left: 0; + padding: 0; + justify-content: flex-end; + position: absolute; + top: 10px; + right: 10px; + } + + .container-cardconsulta:hover .actions-container { + transform: none; + } + + .tabelamensal .container-cardconsulta { + width: 100%; + max-width: 100%; + } +} + +@media (max-width: 576px) { + .container-cardconsulta { + padding-right: 10px; /* Remove o padding extra para telas muito pequenas */ + } + + .actions-container { + position: static; + margin-top: 10px; + justify-content: flex-start; + } + + .btn-edit-custom-style, + .btn-delete-custom-style, + .btn-confirm-style { + padding: 6px 10px; + font-size: 0.8rem; + } } \ No newline at end of file diff --git a/src/components/AgendarConsulta/style/formagendamentos.css b/src/components/AgendarConsulta/style/formagendamentos.css index d3fc9ae..0b1135a 100644 --- a/src/components/AgendarConsulta/style/formagendamentos.css +++ b/src/components/AgendarConsulta/style/formagendamentos.css @@ -183,6 +183,67 @@ textarea{ gap: 16px; } +@media (max-width: 768px) { + .campos-informacoes-paciente, + .campo-informacoes-atendimento { + flex-direction: column; + gap: 10px; + } + + #informacoes-atendimento-segunda-linha { + flex-direction: column; + gap: 10px; + } + + #informacoes-atendimento-segunda-linha-esquerda select[name="unidade"], + input[type="time"], + select[name=solicitante], + .campo-de-input { + width: 100% !important; + max-width: 100%; + } + + .tipo_atendimento { + margin-left: 0; + } + + .linha { + flex-direction: column; + align-items: stretch; + gap: 10px; + } + + .sessao-contador { + width: 100px; + } +} + +@media (max-width: 576px) { + .form-container { + padding: 15px; + } + + .form-title { + font-size: 22px; + } + + .form-agendamento input, + .form-agendamento select, + .form-agendamento textarea { + font-size: 13px; + } + + .form-actions { + flex-direction: column; + gap: 10px; + } + + .btn-primary, + .btn-cancel { + width: 100%; + } +} + .campo-de-input { flex: 1; display: flex; diff --git a/src/components/Estilo/Toggle.css b/src/components/Estilo/Toggle.css index 299f874..731f0cf 100644 --- a/src/components/Estilo/Toggle.css +++ b/src/components/Estilo/Toggle.css @@ -259,18 +259,6 @@ z-index: 10; } -/* Estilo para o item Início para ficar com borda semelhante aos blocos */ -.inicio-item .sidebar-link { - border: 1px solid var(--toggle-border); - border-radius: 8px; - background: var(--toggle-bg); - padding: 10px 12px; -} - -.inicio-item .sidebar-link:hover { - background-color: var(--toggle-hover); -} - .logout-button { display: flex; align-items: center; diff --git a/src/components/Header/Header.css b/src/components/Header/Header.css index 6d708d6..292356f 100644 --- a/src/components/Header/Header.css +++ b/src/components/Header/Header.css @@ -223,6 +223,8 @@ z-index: 2001; margin-top: 80px; margin-right: 20px; + /* Adicionado para responsividade */ + max-width: 90vw; } .suporte-card { @@ -309,6 +311,8 @@ z-index: 3001; margin-top: 80px; margin-right: 20px; + /* Adicionado para responsividade */ + max-width: 90vw; } .chat-online { @@ -462,6 +466,81 @@ } /* Responsividade */ +@media (max-width: 768px) { + .header-container { + padding: 10px 15px; + } + + .right-corner-elements { + gap: 15px; + } + + .profile-picture-container { + width: 40px; + height: 40px; + } + + .suporte-card-container, + .chat-container { + margin-top: 60px; + margin-right: 10px; + margin-left: 10px; + } + + .suporte-card, + .chat-online { + width: calc(100vw - 20px); + max-width: none; + } +} + +@media (max-width: 576px) { + .header-container { + padding: 8px 10px; + } + + .right-corner-elements { + gap: 10px; + } + + .profile-picture-container { + width: 35px; + height: 35px; + } + + .phone-icon-container { + font-size: 20px; + } + + .suporte-card-container, + .chat-container { + margin-top: 50px; + margin-right: 5px; + margin-left: 5px; + } + + .suporte-card { + padding: 1rem; + } + + .chat-online { + width: calc(100vw - 10px); + height: 80vh; /* Limita a altura para telas pequenas */ + } + + .chat-input { + padding: 0.75rem; + } + + .chat-campo { + padding: 0.5rem; + } + + .chat-enviar { + padding: 0.5rem 1rem; + } +} + @media (max-width: 768px) { .header-container { padding: 10px 15px; @@ -525,31 +604,3 @@ color: #fff; cursor: pointer; } - -/* Avatar Styles */ -.profile-avatar-image { - width: 100%; - height: 100%; - border-radius: 50%; - object-fit: cover; -} - -.profile-placeholder-loading { - display: flex; - align-items: center; - justifyContent: center; - fontSize: 20px; -} - -.profile-placeholder-initials { - display: flex; - align-items: center; - justify-content: center; - font-size: 18px; - font-weight: bold; - color: #fff; - background-color: #6c63ff; - text-transform: uppercase; - width: 100%; - height: 100%; -} diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index b4a3921..18df67f 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -2,11 +2,10 @@ import React, { useState, useRef, useEffect } from 'react'; import { createPortal } from 'react-dom'; import { useNavigate, useLocation } from 'react-router-dom'; -import API_KEY from '../utils/apiKeys'; -import { UserInfos } from '../utils/Functions-Endpoints/General'; import './Header.css'; const Header = () => { + // --- hooks (sempre na mesma ordem) --- const [isDropdownOpen, setIsDropdownOpen] = useState(false); const [isSuporteCardOpen, setIsSuporteCardOpen] = useState(false); const [isChatOpen, setIsChatOpen] = useState(false); @@ -14,89 +13,40 @@ const Header = () => { const [mensagens, setMensagens] = useState([]); const [showLogoutModal, setShowLogoutModal] = useState(false); const [avatarUrl, setAvatarUrl] = useState(null); - const [uploadingAvatar, setUploadingAvatar] = useState(false); - const [userName, setUserName] = useState(''); - const [userId, setUserId] = useState(null); const navigate = useNavigate(); const location = useLocation(); - const fileInputRef = useRef(null); const chatInputRef = useRef(null); const mensagensContainerRef = useRef(null); + // foco quando abre chat useEffect(() => { if (isChatOpen && chatInputRef.current) { chatInputRef.current.focus(); } }, [isChatOpen]); + // scroll automático quando nova mensagem useEffect(() => { if (mensagensContainerRef.current) { mensagensContainerRef.current.scrollTop = mensagensContainerRef.current.scrollHeight; } }, [mensagens]); + // carrega avatar se existir useEffect(() => { - const loadUserAndAvatar = async () => { - try { - const token = localStorage.getItem('access_token') || localStorage.getItem('token') || localStorage.getItem('authToken') || sessionStorage.getItem('token'); - - if (!token) return; - - const userInfo = await UserInfos(`Bearer ${token}`); - - const userIdFromInfo = userInfo?.id || userInfo?.user?.id || userInfo?.sub; - - const userFullName = - userInfo?.full_name || - userInfo?.user?.full_name || - userInfo?.profile?.full_name || - userInfo?.user?.user_metadata?.full_name || - userInfo?.user?.email || - userInfo?.email || - 'Usuário'; - - setUserId(userIdFromInfo); - setUserName(userFullName); - - if (!userIdFromInfo) return; - - const avatarPath = `${userIdFromInfo}/avatar.jpg`; - - const myHeaders = new Headers(); - myHeaders.append('apikey', API_KEY); - myHeaders.append('Authorization', `Bearer ${token}`); - - const response = await fetch( - `https://yuanqfswhberkoevtmfr.supabase.co/storage/v1/object/public/avatars/${avatarPath}`, - { method: 'GET', headers: myHeaders, redirect: 'follow' } - ); - - if (response.ok) { - const blob = await response.blob(); - const url = URL.createObjectURL(blob); - setAvatarUrl(url); - } else { - const authResponse = await fetch( - `https://yuanqfswhberkoevtmfr.supabase.co/storage/v1/object/avatars/${avatarPath}`, - { method: 'GET', headers: myHeaders, redirect: 'follow' } - ); - - if (authResponse.ok) { - const blob = await authResponse.blob(); - const url = URL.createObjectURL(blob); - setAvatarUrl(url); - } - } - } catch (err) { - console.warn('Erro ao carregar usuário/avatar:', err); - } + const loadAvatar = () => { + const localAvatar = localStorage.getItem('user_avatar'); + if (localAvatar) setAvatarUrl(localAvatar); }; - - loadUserAndAvatar(); + loadAvatar(); + const onStorage = () => loadAvatar(); + window.addEventListener('storage', onStorage); + return () => window.removeEventListener('storage', onStorage); }, []); + // ESC fecha qualquer overlay/portal aberto (logout / suporte / chat) useEffect(() => { const onKey = (e) => { if (e.key === 'Escape') { @@ -109,6 +59,7 @@ const Header = () => { return () => window.removeEventListener('keydown', onKey); }, [showLogoutModal, isSuporteCardOpen, isChatOpen]); + // --- handlers logout (mantive comportamento) --- const handleLogoutClick = () => { setShowLogoutModal(true); setIsDropdownOpen(false); @@ -148,6 +99,7 @@ const Header = () => { }, }); } catch (err) { + // ignora erro de rede / endpoint — prossegue para limpar local console.warn('logout endpoint error (ignored):', err); } } @@ -165,6 +117,7 @@ const Header = () => { const handleLogoutCancel = () => setShowLogoutModal(false); + // --- profile / suporte / chat handlers --- const handleProfileClick = () => { setIsDropdownOpen(!isDropdownOpen); if (isSuporteCardOpen) setIsSuporteCardOpen(false); @@ -176,75 +129,6 @@ const Header = () => { setIsDropdownOpen(false); }; - const handleAvatarClick = () => { - if (fileInputRef.current) { - fileInputRef.current.click(); - } - }; - - const handleAvatarUpload = async (event) => { - const file = event.target.files?.[0]; - if (!file) return; - - // Validar tipo de arquivo - if (!file.type.startsWith('image/')) { - alert('Por favor, selecione um arquivo de imagem válido.'); - return; - } - - // Validar tamanho (máximo 5MB) - if (file.size > 5 * 1024 * 1024) { - alert('A imagem deve ter no máximo 5MB.'); - return; - } - - try { - setUploadingAvatar(true); - - if (!userId) { - alert('Usuário não identificado. Faça login novamente.'); - return; - } - - const avatarPath = `${userId}/avatar.jpg`; - const token = localStorage.getItem('access_token') || localStorage.getItem('token') || localStorage.getItem('authToken') || sessionStorage.getItem('token'); - - const formData = new FormData(); - formData.append('file', file); - - const myHeaders = new Headers(); - myHeaders.append('apikey', API_KEY); - if (token) myHeaders.append('Authorization', `Bearer ${token}`); - - const response = await fetch( - `https://yuanqfswhberkoevtmfr.supabase.co/storage/v1/object/avatars/${avatarPath}`, - { - method: 'POST', - headers: myHeaders, - body: formData, - redirect: 'follow' - } - ); - - if (response.ok) { - // Recarregar avatar - const url = URL.createObjectURL(file); - setAvatarUrl(url); - alert('Avatar atualizado com sucesso!'); - } else { - const errorText = await response.text(); - console.error('Erro ao fazer upload:', errorText); - alert('Erro ao fazer upload do avatar. Tente novamente.'); - } - } catch (err) { - console.error('Erro no upload:', err); - alert('Erro ao fazer upload do avatar. Tente novamente.'); - } finally { - setUploadingAvatar(false); - if (fileInputRef.current) fileInputRef.current.value = ''; - } - }; - const handleSuporteClick = () => { setIsSuporteCardOpen((s) => !s); setIsDropdownOpen(false); @@ -307,6 +191,7 @@ const Header = () => { }, 900); }; + // --- subcomponentes (UI) --- const SuporteCardContent = ({ onOpenChat }) => (

Suporte

@@ -474,10 +359,12 @@ const Header = () => { ); }; + // --- evita render na rota de login (mantendo hooks invocados) --- if (location.pathname === '/login') { return null; } + // --- JSX principal (header visual) --- return (
@@ -492,54 +379,12 @@ const Header = () => {
- -
- {uploadingAvatar ? ( -
- -
- ) : avatarUrl ? ( - Avatar - ) : userName ? ( -
- {(() => { - const words = userName.trim().split(/\s+/).filter(w => w.length > 0); - if (words.length >= 2) { - return words.slice(0, 2).map(w => w[0]).join(''); - } else if (words.length === 1 && words[0].length >= 2) { - return words[0].substring(0, 2); - } else { - return words[0]?.[0] || 'U'; - } - })()} -
- ) : ( -
- )} +
+
{isDropdownOpen && (
e.stopPropagation()}> -
diff --git a/src/components/Sidebar.jsx b/src/components/Sidebar.jsx index 0fdbe4c..006a396 100644 --- a/src/components/Sidebar.jsx +++ b/src/components/Sidebar.jsx @@ -242,14 +242,6 @@ function Sidebar({ menuItems }) {
    - - {/* Botão Início fixo */} -
  • - - - Início - -
  • {roleUser.includes("admin") && diff --git a/src/index.css b/src/index.css index bd5bd6d..43cf021 100644 --- a/src/index.css +++ b/src/index.css @@ -1,13 +1,19 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} +*, +*::before, +*::after { + box-sizing: border-box; +} + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/src/pages/Agendamento.jsx b/src/pages/Agendamento.jsx index 223f0d2..8daecec 100644 --- a/src/pages/Agendamento.jsx +++ b/src/pages/Agendamento.jsx @@ -338,7 +338,41 @@ const Agendamento = ({ setDictInfo }) => { {!PageNovaConsulta ? (
    - +
    +
    +
    +
    +
    + handleSearchMedicos(e.target.value)} + /> +
    +
    + {searchTermDoctor && FiltredTodosMedicos.length > 0 && ( +
    + {FiltredTodosMedicos.map((medico) => ( +
    { + setSearchTermDoctor(medico.nomeMedico); + setFiltredTodosMedicos([]); + setMedicoFiltrado(medico); + }} + > +

    {medico.nomeMedico}

    +
    + ))} +
    + )} +
    +
    +
    + + {/* ABA + BOTÕES NA MESMA BARRA */}
    - - {gerarNumerosWaitPages().map(pagina => ( -
  • + {filaEsperaFiltrada.length > 0 && ( +
    +
    + Itens por página: + +
    +
    + + Página {waitPage} de {waitTotalPages} • Mostrando {waitIndiceInicial + 1}-{Math.min(waitIndiceFinal, filaEsperaFiltrada.length)} de {filaEsperaFiltrada.length} + + + {gerarNumerosWaitPages().map(pagina => ( +
  • + +
  • + ))} +
  • + +
  • +
+ +
-
- )} + )} +
@@ -719,4 +755,4 @@ const Agendamento = ({ setDictInfo }) => { ); }; -export default Agendamento; \ No newline at end of file +export default Agendamento; diff --git a/src/pages/DoctorTable.jsx b/src/pages/DoctorTable.jsx index b7175da..e5becd7 100644 --- a/src/pages/DoctorTable.jsx +++ b/src/pages/DoctorTable.jsx @@ -1,17 +1,17 @@ import React, { useState, useEffect } from "react"; import API_KEY from "../components/utils/apiKeys"; import { useAuth } from "../components/utils/AuthProvider"; -import { Link, useNavigate } from "react-router-dom"; +import { Link } from "react-router-dom"; import "./style/TableDoctor.css"; -function TableDoctor({ setDictInfo }) { +function TableDoctor({setDictInfo}) { const { getAuthorizationHeader, isAuthenticated } = useAuth(); - const navigate = useNavigate(); const [medicos, setMedicos] = useState([]); const [search, setSearch] = useState(""); const [filtroEspecialidade, setFiltroEspecialidade] = useState("Todos"); const [filtroAniversariante, setFiltroAniversariante] = useState(false); + const [showFiltrosAvancados, setShowFiltrosAvancados] = useState(false); const [filtroCidade, setFiltroCidade] = useState(""); const [filtroEstado, setFiltroEstado] = useState(""); @@ -20,8 +20,6 @@ function TableDoctor({ setDictInfo }) { const [dataInicial, setDataInicial] = useState(""); const [dataFinal, setDataFinal] = useState(""); - const [sortKey, setSortKey] = useState(null); - const [sortDir, setSortDir] = useState('asc'); const [paginaAtual, setPaginaAtual] = useState(1); const [itensPorPagina, setItensPorPagina] = useState(10); @@ -29,11 +27,52 @@ function TableDoctor({ setDictInfo }) { const [showDeleteModal, setShowDeleteModal] = useState(false); const [selectedDoctorId, setSelectedDoctorId] = useState(null); - // ===== FUNÇÕES AUXILIARES ===== + const [sortKey, setSortKey] = useState(null); + const [sortDir, setSortDir] = useState('asc'); + + const limparFiltros = () => { + setSearch(""); + setFiltroEspecialidade("Todos"); + setFiltroAniversariante(false); + setShowFiltrosAvancados(false); + setFiltroCidade(""); + setFiltroEstado(""); + setIdadeMinima(""); + setIdadeMaxima(""); + setDataInicial(""); + setDataFinal(""); + setPaginaAtual(1); + }; + + const deleteDoctor = async (id) => { + const authHeader = getAuthorizationHeader() + console.log(id, 'teu id') + + var myHeaders = new Headers(); + myHeaders.append('apikey', API_KEY); + myHeaders.append("Authorization", authHeader) + + var requestOptions = { method: "DELETE", redirect: "follow", headers: myHeaders }; + + try { + const result = await fetch( + `https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors?id=eq.${id}`, + requestOptions + ); + setMedicos((prev) => prev.filter((p) => p.id !== id)); + console.log(result) + } catch (error) { + console.log("Deu problema", error); + } finally { + setShowDeleteModal(false); + } + }; + const ehAniversariante = (dataNascimento) => { if (!dataNascimento) return false; const hoje = new Date(); const nascimento = new Date(dataNascimento); + return ( hoje.getDate() === nascimento.getDate() && hoje.getMonth() === nascimento.getMonth() @@ -46,44 +85,17 @@ function TableDoctor({ setDictInfo }) { const nascimento = new Date(dataNascimento); let idade = hoje.getFullYear() - nascimento.getFullYear(); const mes = hoje.getMonth() - nascimento.getMonth(); + if (mes < 0 || (mes === 0 && hoje.getDate() < nascimento.getDate())) { idade--; } return idade; }; - // ===== FUNÇÕES DE API ===== - const deleteDoctor = async (id) => { - const authHeader = getAuthorizationHeader(); - var myHeaders = new Headers(); - myHeaders.append('apikey', API_KEY); - myHeaders.append("Authorization", authHeader); - var requestOptions = { - method: "DELETE", - redirect: "follow", - headers: myHeaders - }; - - try { - const response = await fetch( - `https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/doctors?id=eq.${id}`, - requestOptions - ); - - if (!response.ok) { - throw new Error(`Erro ${response.status}: ${response.statusText}`); - } - - setMedicos((prev) => prev.filter((p) => p.id !== id)); - } catch (error) { - console.error("Erro ao excluir médico:", error); - } finally { - setShowDeleteModal(false); - } - }; - useEffect(() => { - const authHeader = getAuthorizationHeader(); + const authHeader = getAuthorizationHeader() + console.log(authHeader, 'aqui autorização') + var myHeaders = new Headers(); myHeaders.append("apikey", API_KEY); myHeaders.append("Authorization", `${authHeader}`); @@ -99,20 +111,6 @@ function TableDoctor({ setDictInfo }) { .catch(error => console.log('error', error)); }, [isAuthenticated, getAuthorizationHeader]); - // ===== FILTRAGEM ===== - const limparFiltros = () => { - setSearch(""); - setFiltroEspecialidade("Todos"); - setFiltroAniversariante(false); - setFiltroCidade(""); - setFiltroEstado(""); - setIdadeMinima(""); - setIdadeMaxima(""); - setDataInicial(""); - setDataFinal(""); - setPaginaAtual(1); - }; - const medicosFiltrados = Array.isArray(medicos) ? medicos.filter((medico) => { const buscaNome = medico.full_name?.toLowerCase().includes(search.toLowerCase()); const buscaCPF = medico.cpf?.toLowerCase().includes(search.toLowerCase()); @@ -120,24 +118,35 @@ function TableDoctor({ setDictInfo }) { const passaBusca = search === "" || buscaNome || buscaCPF || buscaEmail; const passaEspecialidade = filtroEspecialidade === "Todos" || medico.specialty === filtroEspecialidade; - const passaAniversario = filtroAniversariante ? ehAniversariante(medico.birth_date) : true; - const passaCidade = filtroCidade ? medico.city?.toLowerCase().includes(filtroCidade.toLowerCase()) : true; - const passaEstado = filtroEstado ? medico.state?.toLowerCase().includes(filtroEstado.toLowerCase()) : true; + + const passaAniversario = filtroAniversariante + ? ehAniversariante(medico.birth_date) + : true; + + const passaCidade = filtroCidade ? + medico.city?.toLowerCase().includes(filtroCidade.toLowerCase()) : true; + + const passaEstado = filtroEstado ? + medico.state?.toLowerCase().includes(filtroEstado.toLowerCase()) : true; const idade = calcularIdade(medico.birth_date); const passaIdadeMinima = idadeMinima ? idade >= parseInt(idadeMinima) : true; const passaIdadeMaxima = idadeMaxima ? idade <= parseInt(idadeMaxima) : true; - const passaDataInicial = dataInicial ? medico.created_at && new Date(medico.created_at) >= new Date(dataInicial) : true; - const passaDataFinal = dataFinal ? medico.created_at && new Date(medico.created_at) <= new Date(dataFinal) : true; + const passaDataInicial = dataInicial ? + medico.created_at && new Date(medico.created_at) >= new Date(dataInicial) : true; - return passaBusca && passaEspecialidade && passaAniversario && + const passaDataFinal = dataFinal ? + medico.created_at && new Date(medico.created_at) <= new Date(dataFinal) : true; + + const resultado = passaBusca && passaEspecialidade && passaAniversario && passaCidade && passaEstado && passaIdadeMinima && passaIdadeMaxima && passaDataInicial && passaDataFinal; + + return resultado; }) : []; - // ===== ORDENAÇÃO ===== - const aplicarOrdenacao = (arr) => { + const applySorting = (arr) => { if (!Array.isArray(arr) || !sortKey) return arr; const copy = [...arr]; if (sortKey === 'nome') { @@ -149,25 +158,44 @@ function TableDoctor({ setDictInfo }) { return copy; }; - const medicosOrdenados = aplicarOrdenacao(medicosFiltrados); + const medicosOrdenados = applySorting(medicosFiltrados); - // ===== PAGINAÇÃO ===== const totalPaginas = Math.ceil(medicosFiltrados.length / itensPorPagina); const indiceInicial = (paginaAtual - 1) * itensPorPagina; const indiceFinal = indiceInicial + itensPorPagina; const medicosPaginados = medicosOrdenados.slice(indiceInicial, indiceFinal); - const irParaPagina = (pagina) => setPaginaAtual(pagina); - const avancarPagina = () => paginaAtual < totalPaginas && setPaginaAtual(p => p + 1); - const voltarPagina = () => paginaAtual > 1 && setPaginaAtual(p => p - 1); + + const irParaPagina = (pagina) => { + setPaginaAtual(pagina); + }; + const avancarPagina = () => { + if (paginaAtual < totalPaginas) { + setPaginaAtual(paginaAtual + 1); + } + }; + + const voltarPagina = () => { + if (paginaAtual > 1) { + setPaginaAtual(paginaAtual - 1); + } + }; + + const gerarNumerosPaginas = () => { const paginas = []; const paginasParaMostrar = 5; + let inicio = Math.max(1, paginaAtual - Math.floor(paginasParaMostrar / 2)); let fim = Math.min(totalPaginas, inicio + paginasParaMostrar - 1); + inicio = Math.max(1, fim - paginasParaMostrar + 1); - for (let i = inicio; i <= fim; i++) paginas.push(i); + + for (let i = inicio; i <= fim; i++) { + paginas.push(i); + } + return paginas; }; @@ -180,364 +208,359 @@ function TableDoctor({ setDictInfo }) {

Lista de Médicos

-
-
-
-

Médicos Cadastrados

- - - -
- -
- {/* ===== FILTROS PADRONIZADOS ===== */} -
-
- Filtros -
- - {/* Busca */} -
- setSearch(e.target.value)} - /> +
+
+
+
+

Médicos Cadastrados

+ + +
- {/* Linha de Filtros Básicos - MESMO PADRÃO DA TABLE PACIENTE */} -
- {/* Especialidade */} -
- - -
+
+
+
+ {" "} + Filtros +
- {/* Aniversariantes */} -
- - -
+
+ setSearch(e.target.value)} + /> + + Digite o nome completo, CPF ou email + +
- {/* Separador */} -
+
+ - {/* Ordenação */} -
- - -
-
- - {/* Linha de Ações */} -
- - - -
- - {/* Filtros Avançados */} - {showFiltrosAvancados && ( -
-
Filtros Avançados
-
-
- - setFiltroCidade(e.target.value)} - /> +
+
-
- - setFiltroEstado(e.target.value)} - /> + + +
+
+ Ordenar por: + {(() => { + const sortValue = sortKey ? `${sortKey}-${sortDir}` : ''; + return ( + + ); + })()}
-
- - setIdadeMinima(e.target.value)} - min="0" - max="150" - /> +
+ +
+ + + +
+ + {showFiltrosAvancados && ( +
+
Filtros Avançados
+ +
+
+ + setFiltroCidade(e.target.value)} + /> +
+
+ + setFiltroEstado(e.target.value)} + /> +
+ +
+ + setIdadeMinima(e.target.value)} + min="0" + max="150" + /> +
+
+ + setIdadeMaxima(e.target.value)} + min="0" + max="150" + /> +
+ +
+ + setDataInicial(e.target.value)} + /> +
+
+ + setDataFinal(e.target.value)} + /> +
+
-
- - setIdadeMaxima(e.target.value)} - min="0" - max="150" - /> -
-
- - setDataInicial(e.target.value)} - /> -
-
- - setDataFinal(e.target.value)} - /> + )} + +
+
+ {medicosFiltrados.length} DE {medicos.length} MÉDICOS ENCONTRADOS
- )} - {/* Contador */} -
-
- {medicosFiltrados.length} DE {medicos.length} MÉDICOS ENCONTRADOS -
-
-
+
+ + + + + + + + + + + + {medicosPaginados.length > 0 ? ( + medicosPaginados.map((medico) => ( + + + + + + -
NomeCPFEspecialidadeEmailAções
+
+ {medico.full_name} + {ehAniversariante(medico.birth_date) && ( + + + + )} +
+
{medico.cpf} + + {medico.specialty || 'Não informado'} + + {medico.email || 'Não informado'} +
+ + + - {/* ===== TABELA SIMPLIFICADA ===== */} -
- - - - - - - - - - - - {medicosPaginados.length > 0 ? ( - medicosPaginados.map((medico) => ( - - + + )) + ) : ( + + - - - - - - )) - ) : ( - - - + + + )} + +
NomeCPFEspecialidadeEmailAções
-
- {medico.full_name} -
- {ehAniversariante(medico.birth_date) && ( - - - + + + + + +
+
+
+ +

Nenhum médico encontrado com os filtros aplicados.

+ {(search || filtroEspecialidade !== "Todos" || filtroAniversariante || + filtroCidade || filtroEstado || idadeMinima || idadeMaxima || dataInicial || dataFinal) && ( + )}
- -
{medico.cpf} - - {medico.specialty || 'Não informado'} - - {medico.email || 'Não informado'} -
- - - -
-
-
- -

Nenhum médico encontrado com os filtros aplicados.

- {(search || filtroEspecialidade !== "Todos" || filtroAniversariante || - filtroCidade || filtroEstado || idadeMinima || idadeMaxima || dataInicial || dataFinal) && ( - - )} -
-
+ + {medicosFiltrados.length > 0 && ( +
+
+ Itens por página: + +
+ +
+ + Página {paginaAtual} de {totalPaginas} • + Mostrando {indiceInicial + 1}-{Math.min(indiceFinal, medicosFiltrados.length)} de {medicosFiltrados.length} médicos + + + +
+
)} -
- - {/* ===== PAGINAÇÃO ===== */} - {medicosFiltrados.length > 0 && ( -
-
- Itens por página: - -
- -
- - Página {paginaAtual} de {totalPaginas} • - Mostrando {indiceInicial + 1}-{Math.min(indiceFinal, medicosFiltrados.length)} de {medicosFiltrados.length} médicos - - - -
- )} +
-
+
- {/* ===== MODAL DE EXCLUSÃO ===== */} {showDeleteModal && (
e.target.classList.contains("modal") && setShowDeleteModal(false)} + onClick={(e) => + e.target.classList.contains("modal") && setShowDeleteModal(false) + } >
-
Confirmação de Exclusão
+
+ Confirmação de Exclusão +
-

Tem certeza que deseja excluir este médico?

-

Esta ação não pode ser desfeita.

+

+ Tem certeza que deseja excluir este médico? +

@@ -565,4 +588,4 @@ function TableDoctor({ setDictInfo }) { ); } -export default TableDoctor; \ No newline at end of file +export default TableDoctor; diff --git a/src/pages/LaudoManager.jsx b/src/pages/LaudoManager.jsx index d269663..e881d77 100644 --- a/src/pages/LaudoManager.jsx +++ b/src/pages/LaudoManager.jsx @@ -9,7 +9,6 @@ import { useNavigate } from 'react-router-dom'; import html2pdf from 'html2pdf.js'; import TiptapViewer from '../PagesMedico/TiptapViewer' import '../PagesMedico/styleMedico/DoctorRelatorioManager.css'; -import './style/TableDoctor.css'; const LaudoManager = () => { const navigate = useNavigate(); @@ -32,8 +31,6 @@ const LaudoManager = () => { const [paginaAtual, setPaginaAtual] = useState(1); const [itensPorPagina, setItensPorPagina] = useState(10); - const [sortKey, setSortKey] = useState(null); - const [sortDir, setSortDir] = useState('asc'); const [noPermissionText, setNoPermissionText] = useState(null); @@ -131,25 +128,9 @@ const LaudoManager = () => { const limparFiltros = () => { setTermoPesquisa(''); setFiltroExame(''); - setSortKey(null); - setSortDir('asc'); setRelatoriosFinais(relatoriosOriginais); }; - const applySorting = (arr) => { - if (!Array.isArray(arr) || !sortKey) return arr; - const copy = [...arr]; - if (sortKey === 'paciente') { - copy.sort((a, b) => (a.patient_name || '').localeCompare(b.patient_name || '')); - } else if (sortKey === 'exame') { - copy.sort((a, b) => (a.exam || a.exame || '').localeCompare(b.exam || b.exame || '')); - } else if (sortKey === 'data') { - copy.sort((a, b) => new Date(a.created_at || 0) - new Date(b.created_at || 0)); - } - if (sortDir === 'desc') copy.reverse(); - return copy; - }; - const BaixarPDFdoRelatorio = (nome_paciente, idx) => { const elemento = document.getElementById(`folhaA4-${idx}`); if (!elemento) { @@ -234,11 +215,10 @@ const LaudoManager = () => { } if (ex) items = items.filter(r => (r.exam || r.exame || '').toLowerCase().includes(ex)); - const itemsOrdenados = applySorting(items); - setRelatoriosFiltrados(itemsOrdenados); - setRelatoriosFinais(itemsOrdenados); + setRelatoriosFiltrados(items); + setRelatoriosFinais(items); setPaginaAtual(1); - }, [termoPesquisa, filtroExame, relatoriosOriginais, sortKey, sortDir]); + }, [termoPesquisa, filtroExame, relatoriosOriginais]); const irParaPagina = (pagina) => setPaginaAtual(pagina); const avancarPagina = () => { if (paginaAtual < totalPaginas) setPaginaAtual(paginaAtual + 1); }; @@ -256,118 +236,76 @@ const LaudoManager = () => { return (

Lista de Relatórios

- -
-
-
-

Relatórios Cadastrados

- -
- -
- {/* ===== FILTROS PADRONIZADOS ===== */} -
-
- Filtros -
- - {/* Busca */} -
- setTermoPesquisa(e.target.value)} - /> -
- - {/* Linha de Filtros Básicos */} -
- {/* Tipo de Exame */} -
- - setFiltroExame(e.target.value)} - style={{ minWidth: "180px" }} - /> -
- - {/* Separador */} -
- - {/* Ordenação */} -
- - + Adicionar Relatório +
- {/* Linha de Ações */} -
- -
- - {/* Contador */} -
-
- {relatoriosFinais.length} DE {relatoriosOriginais.length} RELATÓRIOS ENCONTRADOS +
+
+
+ Filtros +
+
+
+
+ + setTermoPesquisa(e.target.value)} + /> +
+
+
+
+ + setFiltroExame(e.target.value)} + /> +
+
+
+ +
+
+
+
+ {relatoriosFinais.length} DE {relatoriosOriginais.length} RELATÓRIOS ENCONTRADOS +
+
-
-
- {/* ===== TABELA SIMPLIFICADA ===== */} -
- - {/* ===== TABELA SIMPLIFICADA ===== */} -
- - - - - - - - - +
+
PacienteCPFExameAções
+ + + + + + + + {relatoriosPaginados.length > 0 ? ( relatoriosPaginados.map((relatorio, index) => { @@ -387,6 +325,8 @@ const LaudoManager = () => { Editar + + @@ -400,19 +340,11 @@ const LaudoManager = () => { ); }) ) : ( - - - + )}
PacienteCPFExame
-
- -

Nenhum relatório encontrado.

-
-
Nenhum relatório encontrado.
- {/* ===== PAGINAÇÃO ===== */} {relatoriosFinais.length > 0 && (
@@ -432,13 +364,13 @@ const LaudoManager = () => {
-
- - Página {paginaAtual} de {totalPaginas} • - Mostrando {indiceInicial + 1}-{Math.min(indiceFinal, relatoriosFinais.length)} de {relatoriosFinais.length} relatórios - +
+ + Página {paginaAtual} de {totalPaginas} • + Mostrando {indiceInicial + 1}-{Math.min(indiceFinal, relatoriosFinais.length)} de {relatoriosFinais.length} itens + -
-
- + +
+ {showModal && relatorioModal && (
diff --git a/src/pages/ProfilePage.jsx b/src/pages/ProfilePage.jsx index 5620f76..a41bfe8 100644 --- a/src/pages/ProfilePage.jsx +++ b/src/pages/ProfilePage.jsx @@ -1,7 +1,5 @@ -import React, { useState, useEffect, useCallback, useRef } from "react"; +import React, { useState, useEffect, useCallback } from "react"; import { useLocation, useNavigate } from "react-router-dom"; -import API_KEY from "../components/utils/apiKeys"; -import { UserInfos } from "../components/utils/Functions-Endpoints/General"; import "./style/ProfilePage.css"; const ROLES = { @@ -31,9 +29,6 @@ const ProfilePage = () => { const [avatarUrl, setAvatarUrl] = useState(null); const [isEditingName, setIsEditingName] = useState(false); const [error, setError] = useState(null); - const [userId, setUserId] = useState(null); - const [uploadingAvatar, setUploadingAvatar] = useState(false); - const fileInputRef = useRef(null); useEffect(() => { @@ -47,62 +42,22 @@ const ProfilePage = () => { useEffect(() => { - const loadProfileData = async () => { - try { - const token = localStorage.getItem('access_token') || localStorage.getItem('token') || localStorage.getItem('authToken') || sessionStorage.getItem('token'); - - if (!token) return; - - const userInfo = await UserInfos(`Bearer ${token}`); - - const userIdFromInfo = userInfo?.id || userInfo?.user?.id || userInfo?.sub; - const userFullName = - userInfo?.full_name || - userInfo?.user?.full_name || - userInfo?.profile?.full_name || - userInfo?.user?.user_metadata?.full_name || - 'Usuário'; - const email = userInfo?.user?.email || userInfo?.email || 'email@example.com'; - - setUserId(userIdFromInfo); - setUserName(userFullName); - setUserEmail(email); - - if (!userIdFromInfo) return; - - const avatarPath = `${userIdFromInfo}/avatar.jpg`; - - const myHeaders = new Headers(); - myHeaders.append('apikey', API_KEY); - myHeaders.append('Authorization', `Bearer ${token}`); - - const response = await fetch( - `https://yuanqfswhberkoevtmfr.supabase.co/storage/v1/object/public/avatars/${avatarPath}`, - { method: 'GET', headers: myHeaders, redirect: 'follow' } - ); - - if (response.ok) { - const blob = await response.blob(); - const url = URL.createObjectURL(blob); - setAvatarUrl(url); - } else { - const authResponse = await fetch( - `https://yuanqfswhberkoevtmfr.supabase.co/storage/v1/object/avatars/${avatarPath}`, - { method: 'GET', headers: myHeaders, redirect: 'follow' } - ); - - if (authResponse.ok) { - const blob = await authResponse.blob(); - const url = URL.createObjectURL(blob); - setAvatarUrl(url); - } - } - } catch (err) { - console.warn('Erro ao carregar perfil:', err); + const loadProfileData = () => { + const localAvatar = localStorage.getItem('user_avatar'); + if (localAvatar) { + setAvatarUrl(localAvatar); } }; loadProfileData(); + + + const handleStorageChange = () => { + loadProfileData(); + }; + + window.addEventListener('storage', handleStorageChange); + return () => window.removeEventListener('storage', handleStorageChange); }, []); const handleNameSave = () => { @@ -126,73 +81,6 @@ const ProfilePage = () => { const handleClose = () => navigate(-1); - const handleAvatarClick = () => { - if (fileInputRef.current) { - fileInputRef.current.click(); - } - }; - - const handleAvatarUpload = async (event) => { - const file = event.target.files?.[0]; - if (!file) return; - - if (!file.type.startsWith('image/')) { - alert('Por favor, selecione um arquivo de imagem válido.'); - return; - } - - if (file.size > 5 * 1024 * 1024) { - alert('A imagem deve ter no máximo 5MB.'); - return; - } - - try { - setUploadingAvatar(true); - - if (!userId) { - alert('Usuário não identificado. Faça login novamente.'); - return; - } - - const avatarPath = `${userId}/avatar.jpg`; - const token = localStorage.getItem('access_token') || localStorage.getItem('token') || localStorage.getItem('authToken') || sessionStorage.getItem('token'); - - const formData = new FormData(); - formData.append('file', file); - - const myHeaders = new Headers(); - myHeaders.append('apikey', API_KEY); - if (token) myHeaders.append('Authorization', `Bearer ${token}`); - - const response = await fetch( - `https://yuanqfswhberkoevtmfr.supabase.co/storage/v1/object/avatars/${avatarPath}`, - { - method: 'POST', - headers: myHeaders, - body: formData, - redirect: 'follow' - } - ); - - if (response.ok) { - const url = URL.createObjectURL(file); - setAvatarUrl(url); - alert('Avatar atualizado com sucesso!'); - window.dispatchEvent(new Event('storage')); - } else { - const errorText = await response.text(); - console.error('Erro ao fazer upload:', errorText); - alert('Erro ao fazer upload do avatar. Tente novamente.'); - } - } catch (err) { - console.error('Erro no upload:', err); - alert('Erro ao fazer upload do avatar. Tente novamente.'); - } finally { - setUploadingAvatar(false); - if (fileInputRef.current) fileInputRef.current.value = ''; - } - }; - return (
@@ -206,53 +94,33 @@ const ProfilePage = () => {
-
- {uploadingAvatar ? ( -
- -
- ) : avatarUrl ? ( + {avatarUrl ? ( Avatar do usuário { setAvatarUrl(null); + localStorage.removeItem('user_avatar'); }} /> ) : (
- {(() => { - const words = userName.trim().split(/\s+/).filter(w => w.length > 0); - if (words.length >= 2) { - return words.slice(0, 2).map(w => w[0]).join(''); - } else if (words.length === 1 && words[0].length >= 2) { - return words[0].substring(0, 2); - } else { - return words[0]?.[0] || 'U'; - } - })()} + {userName.split(' ').map(n => n[0]).join('').toUpperCase()}
)}
- +

+ Gerencie seu avatar no menu do perfil acima +

diff --git a/src/pages/TablePaciente.jsx b/src/pages/TablePaciente.jsx index 7b7de22..2ebafe4 100644 --- a/src/pages/TablePaciente.jsx +++ b/src/pages/TablePaciente.jsx @@ -6,7 +6,8 @@ import "./style/TablePaciente.css"; import ModalErro from "../components/utils/fetchErros/ModalErro"; import manager from "../components/utils/fetchErros/ManagerFunction"; -function TablePaciente({ setCurrentPage, setPatientID, setDictInfo }) { +function TablePaciente({ setCurrentPage, setPatientID,setDictInfo }) { + const { getAuthorizationHeader, isAuthenticated } = useAuth(); const navigate = useNavigate(); @@ -23,9 +24,11 @@ function TablePaciente({ setCurrentPage, setPatientID, setDictInfo }) { const [dataInicial, setDataInicial] = useState(""); const [dataFinal, setDataFinal] = useState(""); + const [sortKey, setSortKey] = useState(null); const [sortDir, setSortDir] = useState('asc'); + const [paginaAtual, setPaginaAtual] = useState(1); const [itensPorPagina, setItensPorPagina] = useState(10); @@ -33,55 +36,25 @@ function TablePaciente({ setCurrentPage, setPatientID, setDictInfo }) { const [selectedPatientId, setSelectedPatientId] = useState(null); const [showModalError, setShowModalError] = useState(""); - const [ErrorInfo, setErrorInfo] = useState({}); - // Funções auxiliares - const ehAniversariante = (dataNascimento) => { - if (!dataNascimento) return false; - const hoje = new Date(); - const nascimento = new Date(dataNascimento); - return ( - hoje.getDate() === nascimento.getDate() && - hoje.getMonth() === nascimento.getMonth() - ); - }; + const [ErrorInfo, setErrorInfo] = useState({}) - const calcularIdade = (dataNascimento) => { - if (!dataNascimento) return 0; - const hoje = new Date(); - const nascimento = new Date(dataNascimento); - let idade = hoje.getFullYear() - nascimento.getFullYear(); - const mes = hoje.getMonth() - nascimento.getMonth(); - if (mes < 0 || (mes === 0 && hoje.getDate() < nascimento.getDate())) { - idade--; - } - return idade; - }; - - const formatarData = (dataString) => { - if (!dataString) return 'Nunca'; - const data = new Date(dataString); - return data.toLocaleDateString('pt-BR', { - day: '2-digit', - month: '2-digit', - year: 'numeric', - hour: '2-digit', - minute: '2-digit' - }); - }; - - // Funções de API (mantidas do seu código original) const GetAnexos = async (id) => { var myHeaders = new Headers(); myHeaders.append("Authorization", "Bearer "); - var requestOptions = { method: "GET", headers: myHeaders, redirect: "follow" }; - + + var requestOptions = { + method: "GET", + headers: myHeaders, + redirect: "follow", + }; try { const response = await fetch( `https://mock.apidog.com/m1/1053378-0-default/pacientes/${id}/anexos`, requestOptions ); const result = await response.json(); + return result.data; } catch (error) { console.log("error", error); @@ -91,11 +64,20 @@ function TablePaciente({ setCurrentPage, setPatientID, setDictInfo }) { const DeleteAnexo = async (patientID) => { const RespostaGetAnexos = await GetAnexos(patientID); + for (let i = 0; i < RespostaGetAnexos.length; i++) { const idAnexo = RespostaGetAnexos[i].id; + + console.log("anexos", RespostaGetAnexos); + var myHeaders = new Headers(); myHeaders.append("Authorization", "Bearer "); - var requestOptions = { method: "DELETE", headers: myHeaders, redirect: "follow" }; + + var requestOptions = { + method: "DELETE", + headers: myHeaders, + redirect: "follow", + }; fetch( `https://mock.apidog.com/m1/1053378-0-default/pacientes/${patientID}/anexos/${idAnexo}`, @@ -108,10 +90,14 @@ function TablePaciente({ setCurrentPage, setPatientID, setDictInfo }) { }; const deletePatient = async (id) => { - const authHeader = getAuthorizationHeader(); + + const authHeader = getAuthorizationHeader() + console.log(id) var myHeaders = new Headers(); myHeaders.append('apikey', API_KEY); - myHeaders.append("Authorization", authHeader); + myHeaders.append("Authorization", authHeader) + + var requestOptions = { method: "DELETE", redirect: "follow", headers: myHeaders }; try { @@ -120,6 +106,7 @@ function TablePaciente({ setCurrentPage, setPatientID, setDictInfo }) { requestOptions ); setPacientes((prev) => prev.filter((p) => p.id !== id)); + console.log(result) } catch (error) { console.log("Deu problema", error); } finally { @@ -132,38 +119,83 @@ function TablePaciente({ setCurrentPage, setPatientID, setDictInfo }) { }; useEffect(() => { - const authHeader = getAuthorizationHeader(); + + const authHeader = getAuthorizationHeader() + + console.log(authHeader, 'aqui autorização') + var myHeaders = new Headers(); myHeaders.append("apikey", API_KEY); myHeaders.append("Authorization", `${authHeader}`); - var requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' }; + var requestOptions = { + method: 'GET', + headers: myHeaders, + redirect: 'follow' + }; - fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/patients", requestOptions) - .then(response => { - if (!response.ok) { - return response.json().then(errorData => { - const errorObject = { - httpStatus: response.status, - apiCode: errorData.code, - message: errorData.message || response.statusText, - details: errorData.details, - hint: errorData.hint - }; - throw errorObject; - }); - } - return response.json(); - }) - .then(result => { - setPacientes(result); - setShowModalError(false); - }) - .catch(error => { - manager(setShowModalError, RefreshingToken, setErrorInfo, error); + fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/patients", requestOptions) + .then(response => { + + + if (!response.ok) { + + return response.json().then(errorData => { + + const errorObject = { + httpStatus: response.status, + apiCode: errorData.code, + message: errorData.message || response.statusText, + details: errorData.details, + hint: errorData.hint + }; + + console.error("ERRO DETALHADO:", errorObject); + throw errorObject; }); + + } + + + return response.json(); + }) + .then(result => { + + setPacientes(result); + console.log("Sucesso:", result); + + setShowModalError(false); + }) + .catch(error => { + console.error(error, "deu erro") + manager(setShowModalError, RefreshingToken, setErrorInfo, error) + + }); }, [isAuthenticated, getAuthorizationHeader]); - // Filtragem + const ehAniversariante = (dataNascimento) => { + if (!dataNascimento) return false; + const hoje = new Date(); + const nascimento = new Date(dataNascimento); + + return ( + hoje.getDate() === nascimento.getDate() && + hoje.getMonth() === nascimento.getMonth() + ); + }; + + const calcularIdade = (dataNascimento) => { + if (!dataNascimento) return 0; + const hoje = new Date(); + const nascimento = new Date(dataNascimento); + let idade = hoje.getFullYear() - nascimento.getFullYear(); + const mes = hoje.getMonth() - nascimento.getMonth(); + + if (mes < 0 || (mes === 0 && hoje.getDate() < nascimento.getDate())) { + idade--; + } + return idade; + }; + const limparFiltros = () => { setSearch(""); setFiltroConvenio("Todos"); @@ -179,31 +211,48 @@ function TablePaciente({ setCurrentPage, setPatientID, setDictInfo }) { }; const pacientesFiltrados = Array.isArray(pacientes) ? pacientes.filter((paciente) => { + const buscaNome = paciente.full_name?.toLowerCase().includes(search.toLowerCase()); const buscaCPF = paciente.cpf?.toLowerCase().includes(search.toLowerCase()); - const buscaEmail = paciente.email?.toLowerCase().includes(search.toLowerCase()); - const passaBusca = search === "" || buscaNome || buscaCPF || buscaEmail; + const passaBusca = search === "" || buscaNome || buscaCPF; + const passaConvenio = filtroConvenio === "Todos" || paciente.insurance_plan === filtroConvenio; - const passaVIP = filtroVIP ? paciente.vip === true : true; - const passaAniversario = filtroAniversariante ? ehAniversariante(paciente.birth_date) : true; - const passaCidade = filtroCidade ? paciente.city?.toLowerCase().includes(filtroCidade.toLowerCase()) : true; - const passaEstado = filtroEstado ? paciente.state?.toLowerCase().includes(filtroEstado.toLowerCase()) : true; + const passaVIP = filtroVIP ? paciente.vip === true : true; + const passaAniversario = filtroAniversariante + ? ehAniversariante(paciente.birth_date) + : true; + + + const passaCidade = filtroCidade ? + paciente.city?.toLowerCase().includes(filtroCidade.toLowerCase()) : true; + + const passaEstado = filtroEstado ? + paciente.state?.toLowerCase().includes(filtroEstado.toLowerCase()) : true; + + const idade = calcularIdade(paciente.birth_date); const passaIdadeMinima = idadeMinima ? idade >= parseInt(idadeMinima) : true; const passaIdadeMaxima = idadeMaxima ? idade <= parseInt(idadeMaxima) : true; - const passaDataInicial = dataInicial ? paciente.last_appointment && new Date(paciente.last_appointment) >= new Date(dataInicial) : true; - const passaDataFinal = dataFinal ? paciente.last_appointment && new Date(paciente.last_appointment) <= new Date(dataFinal) : true; + + const passaDataInicial = dataInicial ? + paciente.last_appointment && new Date(paciente.last_appointment) >= new Date(dataInicial) : true; - return passaBusca && passaConvenio && passaVIP && passaAniversario && + const passaDataFinal = dataFinal ? + paciente.last_appointment && new Date(paciente.last_appointment) <= new Date(dataFinal) : true; + + + const resultado = passaBusca && passaConvenio && passaVIP && passaAniversario && passaCidade && passaEstado && passaIdadeMinima && passaIdadeMaxima && passaDataInicial && passaDataFinal; + + return resultado; }) : []; - // Ordenação - const aplicarOrdenacao = (arr) => { + + const applySorting = (arr) => { if (!Array.isArray(arr) || !sortKey) return arr; const copy = [...arr]; if (sortKey === 'nome') { @@ -215,28 +264,48 @@ function TablePaciente({ setCurrentPage, setPatientID, setDictInfo }) { return copy; }; - const pacientesOrdenados = aplicarOrdenacao(pacientesFiltrados); + const pacientesOrdenados = applySorting(pacientesFiltrados); - // Paginação const totalPaginas = Math.ceil(pacientesFiltrados.length / itensPorPagina); const indiceInicial = (paginaAtual - 1) * itensPorPagina; const indiceFinal = indiceInicial + itensPorPagina; const pacientesPaginados = pacientesOrdenados.slice(indiceInicial, indiceFinal); - const irParaPagina = (pagina) => setPaginaAtual(pagina); - const avancarPagina = () => paginaAtual < totalPaginas && setPaginaAtual(p => p + 1); - const voltarPagina = () => paginaAtual > 1 && setPaginaAtual(p => p - 1); + + const irParaPagina = (pagina) => { + setPaginaAtual(pagina); + }; + + const avancarPagina = () => { + if (paginaAtual < totalPaginas) { + setPaginaAtual(paginaAtual + 1); + } + }; + + const voltarPagina = () => { + if (paginaAtual > 1) { + setPaginaAtual(paginaAtual - 1); + } + }; + const gerarNumerosPaginas = () => { const paginas = []; const paginasParaMostrar = 5; + let inicio = Math.max(1, paginaAtual - Math.floor(paginasParaMostrar / 2)); let fim = Math.min(totalPaginas, inicio + paginasParaMostrar - 1); + inicio = Math.max(1, fim - paginasParaMostrar + 1); - for (let i = inicio; i <= fim; i++) paginas.push(i); + + for (let i = inicio; i <= fim; i++) { + paginas.push(i); + } + return paginas; }; + useEffect(() => { setPaginaAtual(1); }, [search, filtroConvenio, filtroVIP, filtroAniversariante, filtroCidade, filtroEstado, idadeMinima, idadeMaxima, dataInicial, dataFinal, sortKey, sortDir]); @@ -246,372 +315,366 @@ function TablePaciente({ setCurrentPage, setPatientID, setDictInfo }) {

Lista de Pacientes

-
-
-
-

Pacientes Cadastrados

- - - -
- -
- {/* ===== FILTROS PADRONIZADOS ===== */} -
-
- Filtros -
- - {/* Busca */} -
- setSearch(e.target.value)} - /> +
+
+
+
+

Pacientes Cadastrados

+ + +
- {/* Linha de Filtros Básicos - TUDO EM UMA LINHA SÓ */} -
- {/* Convênio */} -
- - -
+
+
+
+ {" "} + Filtros +
- {/* Status VIP */} -
- - -
+
+ setSearch(e.target.value)} + /> + + Digite o nome completo ou número do CPF + +
- {/* Aniversariantes */} -
- - -
+
+ - {/* Separador */} -
+ - {/* Ordenação */} -
- - -
-
+ - {/* Linha de Ações */} -
- - - -
- - {/* Filtros Avançados */} - {showFiltrosAvancados && ( -
-
Filtros Avançados
-
-
- - setFiltroCidade(e.target.value)} - /> +
+
+ Ordenar por: + {(() => { + const sortValue = sortKey ? `${sortKey}-${sortDir}` : ''; + return ( + + ); + })()}
-
- - setFiltroEstado(e.target.value)} - /> +
+ +
+ + + +
+ + {showFiltrosAvancados && ( +
+
Filtros Avançados
+ +
+
+ + setFiltroCidade(e.target.value)} + /> +
+
+ + setFiltroEstado(e.target.value)} + /> +
+ +
+ + setIdadeMinima(e.target.value)} + min="0" + max="150" + /> +
+
+ + setIdadeMaxima(e.target.value)} + min="0" + max="150" + /> +
+ +
+ + setDataInicial(e.target.value)} + /> +
+
+ + setDataFinal(e.target.value)} + /> +
+
-
- - setIdadeMinima(e.target.value)} - min="0" - max="150" - /> -
-
- - setIdadeMaxima(e.target.value)} - min="0" - max="150" - /> -
-
- - setDataInicial(e.target.value)} - /> -
-
- - setDataFinal(e.target.value)} - /> + )} + +
+
+ {pacientesFiltrados.length} DE {pacientes.length} PACIENTES ENCONTRADOS
- )} - {/* Contador */} -
-
- {pacientesFiltrados.length} DE {pacientes.length} PACIENTES ENCONTRADOS -
-
-
+
+ + + + + + + + + + + + {pacientesPaginados.length > 0 ? ( + pacientesPaginados.map((paciente) => ( + + + + + + - - )) - ) : ( - - - + + + {gerarNumerosPaginas().map(pagina => ( +
  • + +
  • + ))} + +
  • + +
  • + + + + )} - -
    NomeCPFConvênioEmailAções
    +
    + {paciente.full_name} +
    + {ehAniversariante(paciente.birth_date) && ( + + + + )} + {paciente.vip && ( + + VIP + + )} +
    +
    +
    {paciente.cpf} + + {paciente.insurance_plan || 'Não informado'} + + {paciente.email || 'Não informado'} +
    + + + - {/* ===== TABELA SIMPLIFICADA ===== */} -
    - - - - - - - - - - - - {pacientesPaginados.length > 0 ? ( - pacientesPaginados.map((paciente) => ( - - + + )) + ) : ( + + - - - - + + )} + +
    NomeCPFConvênioEmailAções
    -
    - {paciente.full_name} -
    - {ehAniversariante(paciente.birth_date) && ( - - - - )} - {paciente.vip && ( - - VIP - + + + +
    +
    +
    + +

    Nenhum paciente encontrado com os filtros aplicados.

    + {(search || filtroConvenio !== "Todos" || filtroVIP || filtroAniversariante || + filtroCidade || filtroEstado || idadeMinima || idadeMaxima || dataInicial || dataFinal) && ( + )}
    - -
    {paciente.cpf} - - {paciente.insurance_plan || '-'} - - {paciente.email || 'Não informado'} -
    - -
    + + + {pacientesFiltrados.length > 0 && ( +
    +
    + Itens por página: + +
    + +
    + + Página {paginaAtual} de {totalPaginas} • + Mostrando {indiceInicial + 1}-{Math.min(indiceFinal, pacientesFiltrados.length)} de {pacientesFiltrados.length} pacientes + + +
    -
    -
    - -

    Nenhum paciente encontrado com os filtros aplicados.

    - {(search || filtroConvenio !== "Todos" || filtroVIP || filtroAniversariante || - filtroCidade || filtroEstado || idadeMinima || idadeMaxima || dataInicial || dataFinal) && ( - - )} -
    -
    - - {/* ===== PAGINAÇÃO ===== */} - {pacientesFiltrados.length > 0 && ( -
    -
    - Itens por página: - -
    - -
    - - Página {paginaAtual} de {totalPaginas} • - Mostrando {indiceInicial + 1}-{Math.min(indiceFinal, pacientesFiltrados.length)} de {pacientesFiltrados.length} pacientes - - - -
    - )} +
    -
    +
    - {/* ===== MODAL DE EXCLUSÃO ===== */} {showDeleteModal && (
    e.target.classList.contains("modal") && setShowDeleteModal(false)} + onClick={(e) => + e.target.classList.contains("modal") && setShowDeleteModal(false) + } >
    -
    Confirmação de Exclusão
    +
    + Confirmação de Exclusão +
    -

    Tem certeza que deseja excluir este paciente?

    -

    Esta ação não pode ser desfeita.

    +

    + Tem certeza que deseja excluir este paciente? +

    @@ -639,4 +702,4 @@ function TablePaciente({ setCurrentPage, setPatientID, setDictInfo }) { ); } -export default TablePaciente; \ No newline at end of file +export default TablePaciente; diff --git a/src/pages/style/Agendamento.css b/src/pages/style/Agendamento.css index 806e78c..124ff0a 100644 --- a/src/pages/style/Agendamento.css +++ b/src/pages/style/Agendamento.css @@ -43,6 +43,33 @@ margin-left: 0; } +@media (max-width: 576px) { + .busca-atendimento { + flex-direction: column; + gap: 10px; + } + +.container-btns-agenda-fila_esepera { + flex-direction: column; + align-items: flex-start; + gap: 10px; + flex-wrap: wrap; /* Adicionado para permitir quebra de linha nos botões */ +} + +.btns-gerenciamento-e-consulta { + width: 100%; + justify-content: space-between; + flex-wrap: wrap; /* Adicionado para permitir quebra de linha nos botões */ +} + +.btn-adicionar-consulta { + padding: 8px 12px; /* Reduzido o padding */ + font-size: 0.8rem; /* Reduzido o tamanho da fonte */ + white-space: normal; /* Permite quebra de linha no texto do botão */ + text-align: center; +} +} + .container-btns-agenda-fila_esepera { margin-top: 20px; margin-left: 0; @@ -57,7 +84,7 @@ background-color: transparent; border: 0; border-bottom: 2px solid transparent; - padding: 12px 24px; + padding: 10px 12px; /* Reduzido o padding */ border-radius: 0; font-weight: 600; color: #718096; @@ -108,7 +135,23 @@ font-family: 'Inter', sans-serif; margin-top: 20px; } + +@media (max-width: 768px) { + .calendar-wrapper { + flex-direction: column; + padding: 16px; + } +} .calendar-info-panel { flex: 0 0 300px; border-right: 1px solid #E2E8F0; padding-right: 24px; display: flex; flex-direction: column; } + +@media (max-width: 768px) { + .calendar-info-panel { + border-right: none; + border-bottom: 1px solid #E2E8F0; + padding-right: 0; + padding-bottom: 16px; + } +} .info-date-display { background-color: #EDF2F7; border-radius: 8px; padding: 12px; text-align: center; margin-bottom: 16px; } .info-date-display span { font-weight: 600; color: #718096; text-transform: uppercase; font-size: 0.9rem; } .info-date-display strong { display: block; font-size: 2.5rem; font-weight: 700; color: #2D3748; } @@ -135,6 +178,14 @@ .nav-buttons button { padding: 8px 12px; border-radius: 6px; border: 1px solid #CBD5E0; background-color: #fff; font-weight: 600; cursor: pointer; transition: all 0.2s; } .nav-buttons button:hover { background-color: #EDF2F7; } .calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; } + +@media (max-width: 1200px) { + .calendar-grid { grid-template-columns: repeat(4, 1fr); } +} + +@media (max-width: 768px) { + .calendar-grid { grid-template-columns: repeat(2, 1fr); } +} .day-header { font-weight: 600; color: #718096; text-align: center; padding: 8px 0; font-size: 0.875rem; } .day-cell { min-height: 110px; border-radius: 8px; border: 1px solid #E2E8F0; padding: 8px; transition: background-color 0.2s, border-color 0.2s; cursor: pointer; position: relative; } .day-cell span { font-weight: 600; color: #4A5568; } @@ -233,7 +284,7 @@ } @media (max-width: 576px) { - .calendar-grid { grid-template-columns: repeat(2, 1fr); } + .calendar-grid { grid-template-columns: 1fr; } /* 1 coluna em telas muito pequenas */ .date-indicator h2 { font-size: 1.25rem; } .legend-item { font-size: 0.75rem; padding: 4px 8px; } .appointment-item { flex-direction: column; align-items: stretch; gap: 8px; } @@ -284,6 +335,7 @@ .btns-gerenciamento-e-consulta { display: flex; gap: 10px; + flex-wrap: wrap; /* Permite quebra de linha */ } .container-btns-agenda-fila_esepera { display: flex; diff --git a/src/pages/style/FilaEspera.css b/src/pages/style/FilaEspera.css index 18c8f49..8ba91fc 100644 --- a/src/pages/style/FilaEspera.css +++ b/src/pages/style/FilaEspera.css @@ -190,6 +190,12 @@ html, body { } /* ===== Fila de Espera ===== */ + +@media (max-width: 992px) { + .fila-container { + overflow-x: auto; + } +} .fila-container { width: 100%; max-width: none; @@ -286,6 +292,13 @@ html, body { transition: border-color 0.2s; } +@media (max-width: 768px) { + .busca-fila-espera { + width: 100%; + position: static; + } +} + .busca-fila-espera:focus { border-color: #888; } diff --git a/src/pages/style/FinanceiroDashboard.css b/src/pages/style/FinanceiroDashboard.css index b43b433..6d83da1 100644 --- a/src/pages/style/FinanceiroDashboard.css +++ b/src/pages/style/FinanceiroDashboard.css @@ -21,6 +21,12 @@ margin-bottom: 10px; } +@media (max-width: 1200px) { + .summary-card { + min-width: 180px; + } +} + .summary-card { flex: 1; min-width: 200px; @@ -232,6 +238,13 @@ html[data-bs-theme="dark"] .btn-delete { box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1); } +@media (max-width: 576px) { + .modal-card { + padding: 16px; + max-height: 95vh; + } +} + .modal-header { display: flex; justify-content: space-between; @@ -336,6 +349,14 @@ textarea { width: 30%; } +@media (max-width: 768px) { + .financeiro-wrap .input-field:not(.modal-card *), + .financeiro-wrap .select-field:not(.modal-card *), + .financeiro-wrap textarea:not(.modal-card *) { + width: 100%; + } +} + .modal-card .input-field, .modal-card .select-field, .modal-card textarea { diff --git a/src/pages/style/Inicio.css b/src/pages/style/Inicio.css index a7da5d5..8772147 100644 --- a/src/pages/style/Inicio.css +++ b/src/pages/style/Inicio.css @@ -1,3 +1,134 @@ +/* Container Principal */ + +/* Responsividade */ +@media (max-width: 1200px) { + .dashboard-container { + padding: 1.5rem; + } +} + +@media (max-width: 768px) { + .dashboard-container { + padding: 1rem; + } + + .dashboard-header h1 { + font-size: 1.5rem; + } + + .dashboard-header p { + margin-bottom: 1.5rem; + } + + .stats-grid { + grid-template-columns: 1fr 1fr; /* 2 colunas em tablets */ + gap: 1rem; + } + + .stat-value { + font-size: 1.5rem; + } + + .stat-icon-wrapper { + width: 40px; + height: 40px; + } + + .stat-icon { + font-size: 1rem; + } + + .actions-grid { + grid-template-columns: 1fr; /* 1 coluna em tablets */ + gap: 1rem; + } + + .action-icon { + font-size: 1.8rem; + } + + .action-title { + font-size: 0.9rem; + } + + .appointments-section { + padding: 1.5rem; + } + + .agendamento-info { + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + } + + .agendamento-time-date { + flex-direction: row; + gap: 1rem; + min-width: auto; + } + + .agendamento-detalhes { + min-width: auto; + } +} + +@media (max-width: 576px) { + .dashboard-container { + padding: 0.5rem; + } + + .dashboard-header h1 { + font-size: 1.3rem; + } + + .dashboard-header p { + margin-bottom: 1rem; + } + + .stats-grid { + grid-template-columns: 1fr; /* 1 coluna em celulares */ + } + + .stat-card { + padding: 1rem; + } + + .stat-value { + font-size: 1.3rem; + } + + .action-button { + padding: 1rem; + } + + .appointments-section { + padding: 1rem; + } + + .agendamento-item { + padding: 0.75rem 1rem; + } + + .agendamento-hora { + font-size: 1.1rem; + } + + .agendamento-data { + font-size: 0.7rem; + } + + .agendamento-paciente, + .agendamento-medico { + font-size: 0.85rem; + } + + .manage-button, + .view-all-button { + padding: 0.6rem 1.2rem; + font-size: 0.8rem; + } +} + /* Container Principal */ .dashboard-container { padding: 2rem; diff --git a/src/pages/style/TableDoctor.css b/src/pages/style/TableDoctor.css index 64d342c..8ec8809 100644 --- a/src/pages/style/TableDoctor.css +++ b/src/pages/style/TableDoctor.css @@ -1,114 +1,79 @@ -/* ===== VARIÁVEIS CSS ===== */ -:root { - --primary-color: #1e3a8a; - --secondary-color: #3b82f6; - --bg-light: #f8f9fa; - --border-light: #dee2e6; - --text-primary: #495057; - --text-muted: #6c757d; - --border-radius: 0.375rem; - --box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); - --spacing-sm: 0.5rem; - --spacing-md: 1rem; - --spacing-lg: 1.5rem; -} - -/* ===== CONTAINER PRINCIPAL ===== */ .table-doctor-container { - padding: 1.5rem; - background-color: white; + line-height: 2.5; +} + +/* Adiciona responsividade para a tabela */ +@media (max-width: 992px) { + .table-doctor-card { + overflow-x: auto; + } +} + +.table-doctor-container { + line-height: 2.5; } -/* ===== CARD ===== */ .table-doctor-card { border: none; - box-shadow: var(--box-shadow); - border-radius: var(--border-radius); + box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075); } .table-doctor-card .card-header { - background-color: var(--bg-light); - border-bottom: 1px solid var(--border-light); + background-color: #f8f9fa; + border-bottom: 1px solid #dee2e6; padding: 1rem 1.25rem; - display: flex; - justify-content: space-between; - align-items: center; } -.table-doctor-card .card-header h4 { - margin-bottom: 0; - color: var(--text-primary); - font-weight: 600; -} - -/* ===== FILTROS ===== */ .table-doctor-filters { - background-color: var(--bg-light); - border: 1px solid var(--border-light); - border-radius: var(--border-radius); - padding: 1rem; - margin-bottom: 1rem; + background-color: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 0.375rem; } .table-doctor-filters h5 { - color: var(--text-primary); + color: #495057; font-weight: 600; - margin-bottom: 1rem; - display: flex; - align-items: center; - gap: 0.5rem; } -/* ===== TABELA ===== */ .table-doctor-table { width: 100%; border-collapse: collapse; - margin-bottom: 0; } .table-doctor-table th { - background-color: var(--bg-light); - color: var(--text-primary); + background-color: #f8f9fa; + color: #495057; font-weight: 600; padding: 15px 8px; - border-bottom: 2px solid var(--border-light); + border-bottom: 2px solid #dee2e6; vertical-align: middle; - text-align: left; } .table-doctor-table td { padding: 15px 8px; vertical-align: middle; - border-bottom: 1px solid var(--border-light); + border-bottom: 1px solid #dee2e6; } .table-doctor-table tbody tr:hover { background-color: rgba(0, 0, 0, 0.025); - transition: background-color 0.15s ease-in-out; } -/* ===== BADGES ===== */ + .specialty-badge { - background-color: var(--primary-color) !important; + background-color: #1e3a8a !important; color: white !important; padding: 0.35em 0.65em; font-size: 0.75em; font-weight: 500; - border-radius: 0.25rem; } -.status-badge { - padding: 0.35em 0.65em; - font-size: 0.75em; +.results-badge { + background-color: #1e3a8a; + color: white; + padding: 0.5em 0.75em; + font-size: 0.875em; font-weight: 500; - border-radius: 0.25rem; -} - -.vip-badge { - background-color: #ffc107; - color: #000; - padding: 0.35em 0.65em; - font-size: 0.75em; } .anniversary-badge { @@ -118,22 +83,12 @@ font-size: 0.75em; } -.results-badge { - background-color: var(--primary-color); - color: white; - padding: 0.5em 0.75em; - font-size: 0.875em; - font-weight: 500; -} - -/* ===== BOTÕES DE AÇÃO ===== */ .btn-view { background-color: #E6F2FF !important; color: #004085 !important; border: 1px solid #B8D4F0; padding: 0.375rem 0.75rem; font-size: 0.875rem; - transition: all 0.15s ease-in-out; } .btn-view:hover { @@ -147,7 +102,6 @@ border: 1px solid #FFEAA7; padding: 0.375rem 0.75rem; font-size: 0.875rem; - transition: all 0.15s ease-in-out; } .btn-edit:hover { @@ -161,7 +115,6 @@ border: 1px solid #F5C6CB; padding: 0.375rem 0.75rem; font-size: 0.875rem; - transition: all 0.15s ease-in-out; } .btn-delete:hover { @@ -169,71 +122,22 @@ border-color: #ED969E; } -/* ===== CONTADOR ===== */ -.contador-medicos { - background-color: var(--primary-color); - color: white; - padding: 0.5em 0.75em; - font-size: 0.875em; - font-weight: 500; - border-radius: var(--border-radius); - text-align: center; - display: inline-block; -} - -/* ===== PAGINAÇÃO ===== */ -.pagination { - margin-bottom: 0; -} - -.page-link { - color: var(--text-primary); - border: 1px solid var(--border-light); - padding: 0.375rem 0.75rem; - font-size: 0.875rem; -} - -.page-link:hover { - color: var(--primary-color); - background-color: #e9ecef; - border-color: var(--border-light); -} - -.page-item.active .page-link { - background-color: var(--primary-color); - border-color: var(--primary-color); - color: white; -} - -.page-item.disabled .page-link { - color: var(--text-muted); - background-color: var(--bg-light); - border-color: var(--border-light); -} -/* ===== FILTROS AVANÇADOS ===== */ .advanced-filters { - border: 1px solid var(--border-light) !important; - border-radius: var(--border-radius); - background-color: var(--bg-light); - padding: 1rem; + border: 1px solid #dee2e6; + border-radius: 0.375rem; + background-color: white; } .advanced-filters h6 { - color: var(--text-primary); + color: #495057; font-weight: 600; - font-size: 0.9rem; -} - -.advanced-filters .form-control-sm { - font-size: 0.825rem; } .form-label.fw-bold { - color: var(--text-primary); + color: #495057; font-size: 0.875rem; } -/* ===== MODAL DE EXCLUSÃO ===== */ .delete-modal .modal-header { background-color: rgba(220, 53, 69, 0.1); border-bottom: 1px solid rgba(220, 53, 69, 0.2); @@ -244,7 +148,6 @@ font-weight: 600; } -/* ===== FILTROS ESPECÍFICOS ===== */ .filter-especialidade { min-width: 180px !important; max-width: 200px; @@ -268,133 +171,18 @@ gap: 0.75rem; } -/* ===== SELECTS COMPACTOS ===== */ -.form-select-sm.compact-select { - min-width: 150px; - border: 1px solid var(--border-light); - border-radius: var(--border-radius); +@media (max-width: 576px) { + .table-doctor-card .card-header { padding: 0.75rem 1rem; } + .table-doctor-table th, .table-doctor-table td { padding: 8px 6px; } + .table-doctor-table thead th:nth-child(2), + .table-doctor-table thead th:nth-child(4), + .table-doctor-table tbody td:nth-child(2), + .table-doctor-table tbody td:nth-child(4) { display: none; } + .filter-buttons-container { width: 100%; } + .filter-btn { width: 100%; } } -.form-select.form-select-sm.w-auto { - border: 1px solid var(--border-light); - border-radius: var(--border-radius); - font-size: 0.875rem; -} - -.form-select-sm:focus { - border-color: var(--primary-color); - box-shadow: 0 0 0 0.2rem rgba(30, 58, 138, 0.25); -} - -.btn-outline-secondary.btn-sm { - border-color: var(--text-muted); - color: var(--text-muted); - font-size: 0.8rem; - padding: 0.35rem 0.75rem; -} - -.btn-outline-secondary.btn-sm:hover { - background-color: var(--text-muted); - color: white; -} - -/* ===== ESTADOS VAZIOS ===== */ -.empty-state { - padding: 2rem; - text-align: center; - color: var(--text-muted); -} - -.empty-state td { - border-bottom: none; - padding: 2rem !important; -} - -.text-center.py-4 .text-muted { - padding: 2rem; -} - -.text-center.py-4 .bi-search { - font-size: 3rem; - opacity: 0.5; -} - -.text-center.py-4 p { - margin-bottom: 0.5rem; - font-size: 1.1rem; -} - -.text-center.py-4 td { - border-bottom: none; - padding: 2rem !important; -} - -/* ===== BADGES DE FILTROS ATIVOS ===== */ -.filters-active .badge { - font-size: 0.75em; - padding: 0.4em 0.65em; - margin-bottom: 0.25rem; -} - -/* ===== SEÇÃO DE PAGINAÇÃO ===== */ -.d-flex.justify-content-between.align-items-center { - border-top: 1px solid var(--border-light); - padding-top: 1rem; - margin-top: 1rem; -} - -/* ===== NOME DE PACIENTE/MÉDICO COM BADGES ===== */ -.patient-name-container, -.doctor-name-container { - display: flex; - align-items: center; - flex-wrap: wrap; -} - -.patient-badges, -.doctor-badges { - display: flex; - gap: 0.25rem; - margin-left: 0.5rem; -} - -/* ===== TRANSIÇÕES ===== */ -.table-doctor-table tbody tr { - transition: background-color 0.15s ease-in-out; -} - -/* ===== RESPONSIVIDADE ===== */ @media (max-width: 768px) { - .table-doctor-container { - padding: 1rem; - } - - .table-doctor-card .card-header { - flex-direction: column; - gap: 1rem; - align-items: flex-start; - } - - .table-doctor-filters .d-flex.flex-wrap.align-items-center.gap-3 { - gap: 1rem !important; - flex-direction: column; - align-items: flex-start; - } - - .table-doctor-filters .d-flex.align-items-center.gap-2 { - width: 100%; - justify-content: space-between; - } - - .table-doctor-filters .form-select-sm.compact-select { - min-width: 100% !important; - margin-top: 0.25rem; - } - - .vr.d-none.d-md-block { - display: none !important; - } - .table-doctor-table { font-size: 0.875rem; } @@ -411,48 +199,6 @@ font-size: 0.75rem; } - .table-doctor-filters .d-flex { - flex-direction: column; - gap: 0.5rem; - } - - .table-doctor-filters .form-select { - min-width: 100% !important; - } - - .patient-name-container, - .doctor-name-container { - flex-direction: column; - align-items: flex-start !important; - gap: 0.25rem; - } - - .d-flex.justify-content-between.align-items-center { - flex-direction: column; - gap: 1rem; - align-items: stretch !important; - } - - .d-flex.justify-content-between.align-items-center > div { - justify-content: center !important; - } - - .pagination { - flex-wrap: wrap; - justify-content: center; - } - - .me-3.text-muted { - text-align: center; - margin-bottom: 0.5rem; - font-size: 0.8rem; - } - - .contador-medicos { - font-size: 0.8rem; - padding: 0.4em 0.6em; - } - .filtros-basicos { flex-direction: column; align-items: stretch; @@ -472,43 +218,142 @@ flex: 1; text-align: center; } +} - /* Ocultar colunas em mobile */ - .table-doctor-table thead th:nth-child(3), - .table-doctor-table thead th:nth-child(4), - .table-doctor-table tbody td:nth-child(3), - .table-doctor-table tbody td:nth-child(4) { - display: none; +.empty-state { + padding: 2rem; + text-align: center; + color: #6c757d; +} + +.empty-state td { + border-bottom: none; + padding: 2rem !important; +} + +.filters-active .badge { + font-size: 0.75em; + padding: 0.4em 0.65em; +} + +.table-doctor-table tbody tr { + transition: background-color 0.15s ease-in-out; +} + +.btn-view, +.btn-edit, +.btn-delete { + transition: all 0.15s ease-in-out; +} + + + +.contador-medicos { + background-color: #1e3a8a; + color: white; + padding: 0.5em 0.75em; + font-size: 0.875em; + font-weight: 500; + border-radius: 0.375rem; + text-align: center; + display: inline-block; +} + + +.pagination { + margin-bottom: 0; +} + +.page-link { + color: #495057; + border: 1px solid #dee2e6; + padding: 0.375rem 0.75rem; + font-size: 0.875rem; +} + +.page-link:hover { + color: #1e3a8a; + background-color: #e9ecef; + border-color: #dee2e6; +} + +.page-item.active .page-link { + background-color: #1e3a8a; + border-color: #1e3a8a; + color: white; +} + +.page-item.disabled .page-link { + color: #6c757d; + background-color: #f8f9fa; + border-color: #dee2e6; +} + + +.d-flex.justify-content-between.align-items-center { + border-top: 1px solid #dee2e6; + padding-top: 1rem; + margin-top: 1rem; +} + + +.text-center.py-4 .text-muted { + padding: 2rem; +} + +.text-center.py-4 .bi-search { + font-size: 3rem; + opacity: 0.5; +} + +.text-center.py-4 p { + margin-bottom: 0.5rem; + font-size: 1.1rem; +} + +.text-center.py-4 td { + border-bottom: none; + padding: 2rem !important; +} + + +@media (max-width: 768px) { + .d-flex.justify-content-between.align-items-center { + flex-direction: column; + gap: 1rem; + align-items: stretch !important; + } + + .d-flex.justify-content-between.align-items-center > div { + justify-content: center !important; + } + + .pagination { + flex-wrap: wrap; + justify-content: center; + } + + .me-3.text-muted { + text-align: center; + margin-bottom: 0.5rem; + font-size: 0.8rem; + } + + .contador-medicos { + font-size: 0.8rem; + padding: 0.4em 0.6em; } } -@media (max-width: 576px) { - .table-doctor-card .card-header { - padding: 0.75rem 1rem; - } - - .table-doctor-table th, - .table-doctor-table td { - padding: 8px 6px; - } - - .table-doctor-filters .btn-sm { - width: 100%; - } +.form-select.form-select-sm.w-auto { + border: 1px solid #dee2e6; + border-radius: 0.375rem; + font-size: 0.875rem; +} - .filter-buttons-container { - width: 100%; - } - .filter-btn { - width: 100%; - } - - /* Ocultar mais colunas em telas muito pequenas */ - .table-doctor-table thead th:nth-child(2), - .table-doctor-table thead th:nth-child(5), - .table-doctor-table tbody td:nth-child(2), - .table-doctor-table tbody td:nth-child(5) { - display: none; - } +.filters-active .badge { + font-size: 0.75em; + padding: 0.4em 0.65em; + margin-bottom: 0.25rem; } \ No newline at end of file diff --git a/src/pages/style/TablePaciente.css b/src/pages/style/TablePaciente.css index 04aabb1..93ef7f7 100644 --- a/src/pages/style/TablePaciente.css +++ b/src/pages/style/TablePaciente.css @@ -1,29 +1,14 @@ -/* ===== VARIÁVEIS CSS PADRONIZADAS ===== */ -:root { - --primary-blue: #1e3a8a; - --light-blue: #E6F2FF; - --medium-blue: #D1E7FF; - --border-blue: #B8D4F0; - --warning-light: #FFF3CD; - --warning-dark: #856404; - --warning-border: #FFEAA7; - --danger-light: #F8D7DA; - --danger-dark: #721C24; - --danger-border: #F5C6CB; - --success-light: #d1edff; - --success-dark: #0d6efd; - --bg-light: #f1f4fb; - --border-light: #dee2e6; - --text-muted: #6c757d; - --text-dark: #495057; - --spacing-xs: 0.25rem; - --spacing-sm: 0.5rem; - --spacing-md: 1rem; - --spacing-lg: 1.5rem; - --border-radius: 0.375rem; +.table-paciente-container { + line-height: 2.5; +} + +/* Adiciona responsividade para a tabela */ +@media (max-width: 992px) { + .table-paciente-card { + overflow-x: auto; + } } -/* ===== ESTILOS EXISTENTES MANTIDOS ===== */ .table-paciente-container { line-height: 2.5; } @@ -37,71 +22,65 @@ background-color: #f8f9fa; border-bottom: 1px solid #dee2e6; padding: 1rem 1.25rem; - display: flex; - justify-content: space-between; - align-items: center; } -/* ===== ESTILOS PADRONIZADOS DA TABELA ===== */ .table-paciente-filters { - background-color: var(--bg-light); - border: 1px solid var(--border-light); - border-radius: var(--border-radius); - padding: var(--spacing-md); - margin-bottom: var(--spacing-md); + background-color: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 0.375rem; } .table-paciente-filters h5 { - color: var(--text-dark); + color: #495057; font-weight: 600; - font-size: 1.1rem; } .table-paciente-table { width: 100%; border-collapse: collapse; - margin-top: 1rem; } .table-paciente-table th { - background-color: var(--bg-light); - color: var(--text-dark); + background-color: #f8f9fa; + color: #495057; font-weight: 600; - padding: 12px 8px; - border-bottom: 2px solid var(--border-light); + padding: 15px 8px; + border-bottom: 2px solid #dee2e6; vertical-align: middle; - font-size: 0.9rem; } .table-paciente-table td { - padding: 12px 8px; + padding: 15px 8px; vertical-align: middle; - border-bottom: 1px solid var(--border-light); - font-size: 0.875rem; + border-bottom: 1px solid #dee2e6; } .table-paciente-table tbody tr:hover { background-color: rgba(0, 0, 0, 0.025); } -/* ===== BADGES E STATUS ===== */ .insurance-badge { - background-color: transparent !important; - color: var(--text-dark) !important; - padding: 0.35em 0.65em; - font-size: 0.75em; - font-weight: 500; - border: 1px solid var(--border-light); - border-radius: var(--border-radius); -} - -.vip-badge { - background-color: var(--primary-blue) !important; + background-color: #6c757d !important; color: white !important; padding: 0.35em 0.65em; font-size: 0.75em; font-weight: 500; - border-radius: var(--border-radius); +} + +.vip-badge { + background-color: #1e3a8a !important; + color: white !important; + padding: 0.35em 0.65em; + font-size: 0.75em; + font-weight: 500; +} + +.results-badge { + background-color: #1e3a8a; + color: white; + padding: 0.5em 0.75em; + font-size: 0.875em; + font-weight: 500; } .anniversary-badge { @@ -109,52 +88,27 @@ color: #000; padding: 0.35em 0.65em; font-size: 0.75em; - border-radius: 50%; } -.status-badge { - padding: 0.35em 0.65em; - font-size: 0.75em; - font-weight: 500; - border-radius: var(--border-radius); - display: inline-block; - text-transform: capitalize; -} - -.status-badge.ativo { - background-color: var(--primary-blue); - color: white; -} - -.status-badge.inativo { - background-color: var(--text-muted); - color: white; -} - -/* ===== BOTÕES DE AÇÃO ===== */ .btn-view { - background-color: var(--light-blue) !important; + background-color: #E6F2FF !important; color: #004085 !important; - border: 1px solid var(--border-blue); + border: 1px solid #B8D4F0; padding: 0.375rem 0.75rem; font-size: 0.875rem; - border-radius: var(--border-radius); - transition: all 0.15s ease-in-out; } .btn-view:hover { - background-color: var(--medium-blue) !important; + background-color: #D1E7FF !important; border-color: #9EC5FE; } .btn-edit { - background-color: var(--warning-light) !important; - color: var(--warning-dark) !important; - border: 1px solid var(--warning-border); + background-color: #FFF3CD !important; + color: #856404 !important; + border: 1px solid #FFEAA7; padding: 0.375rem 0.75rem; font-size: 0.875rem; - border-radius: var(--border-radius); - transition: all 0.15s ease-in-out; } .btn-edit:hover { @@ -163,13 +117,11 @@ } .btn-delete { - background-color: var(--danger-light) !important; - color: var(--danger-dark) !important; - border: 1px solid var(--danger-border); + background-color: #F8D7DA !important; + color: #721C24 !important; + border: 1px solid #F5C6CB; padding: 0.375rem 0.75rem; font-size: 0.875rem; - border-radius: var(--border-radius); - transition: all 0.15s ease-in-out; } .btn-delete:hover { @@ -177,25 +129,22 @@ border-color: #ED969E; } -/* ===== FILTROS AVANÇADOS ===== */ .advanced-filters { - border: 1px solid var(--border-light); - border-radius: var(--border-radius); + border: 1px solid #dee2e6; + border-radius: 0.375rem; background-color: white; } .advanced-filters h6 { - color: var(--text-dark); - font-size: 0.9rem; + color: #495057; font-weight: 600; } .form-label.fw-bold { - color: var(--text-dark); + color: #495057; font-size: 0.875rem; } -/* ===== MODAL DE EXCLUSÃO ===== */ .delete-modal .modal-header { background-color: rgba(220, 53, 69, 0.1); border-bottom: 1px solid rgba(220, 53, 69, 0.2); @@ -206,103 +155,6 @@ font-weight: 600; } -/* ===== CONTADOR DE PACIENTES ===== */ -.contador-pacientes { - background-color: var(--primary-blue); - color: white; - padding: 0.5em 0.75em; - font-size: 0.875em; - font-weight: 500; - border-radius: var(--border-radius); - text-align: center; - display: inline-block; -} - -/* ===== PAGINAÇÃO ===== */ -.pagination { - margin-bottom: 0; -} - -.page-link { - color: var(--text-dark); - border: 1px solid var(--border-light); - padding: 0.375rem 0.75rem; - font-size: 0.875rem; -} - -.page-link:hover { - color: var(--primary-blue); - background-color: #e9ecef; - border-color: var(--border-light); -} - -.page-item.active .page-link { - background-color: var(--primary-blue); - border-color: var(--primary-blue); - color: white; -} - -.page-item.disabled .page-link { - color: var(--text-muted); - background-color: var(--bg-light); - border-color: var(--border-light); -} - -/* ===== AJUSTES ESPECÍFICOS PARA OS FILTROS ===== */ -.table-paciente-filters .form-select-sm { - font-size: 0.825rem; - padding: 0.35rem 0.5rem; - border-radius: 0.25rem; -} - -.table-paciente-filters .form-label.small { - font-size: 0.8rem; - font-weight: 500; - color: #6c757d; - min-width: auto; - white-space: nowrap; -} - -/* Alinhamento dos grupos de filtro */ -.table-paciente-filters .d-flex.align-items-center.gap-2 { - flex-wrap: nowrap; -} - -/* Ajuste do contador */ -.contador-pacientes { - background-color: #1e3a8a; - color: white; - padding: 0.4rem 0.8rem; - font-size: 0.8rem; - font-weight: 600; - border-radius: 0.375rem; - text-align: center; - display: inline-block; - letter-spacing: 0.5px; -} - -/* Botão de filtros avançados */ -.btn-link { - color: #1e3a8a !important; - font-weight: 500; - transition: all 0.2s ease; -} - -.btn-link:hover { - color: #162d6b !important; - transform: translateY(-1px); -} - -/* Selects compactos */ -.compact-select { - font-size: 0.9rem; - padding: 0.45rem 0.5rem; - min-width: 150px; - border: 1px solid var(--border-light); - border-radius: var(--border-radius); -} - -/* ===== ESTADOS VAZIOS ===== */ .empty-state { padding: 2rem; text-align: center; @@ -314,6 +166,128 @@ padding: 2rem !important; } +.filters-active .badge { + font-size: 0.75em; + padding: 0.4em 0.65em; +} + +.table-paciente-table tbody tr { + transition: background-color 0.15s ease-in-out; +} + +.btn-view, +.btn-edit, +.btn-delete { + transition: all 0.15s ease-in-out; +} + +@media (max-width: 768px) { + .table-paciente-table { + font-size: 0.875rem; + } + + .table-paciente-table th, + .table-paciente-table td { + padding: 10px 6px; + } + + .btn-view, + .btn-edit, + .btn-delete { + padding: 0.25rem 0.5rem; + font-size: 0.75rem; + } + + .table-paciente-filters .d-flex { + flex-direction: column; + gap: 0.5rem; + } + + .table-paciente-filters .form-select { + min-width: 100% !important; + } + + .patient-name-container { + flex-direction: column; + align-items: flex-start !important; + gap: 0.25rem; + } + + .patient-badges { + margin-left: 0 !important; + } +} + +.compact-select { + font-size: 1.0rem; + padding: 0.45rem 0.5rem; +} + +.compact-select option { + font-size: 0.875rem; +} + +.table-paciente-filters .btn-sm { + font-size: 0.8rem; + white-space: nowrap; +} + +.table-paciente-filters .d-flex { + align-items: center; + gap: 8px; +} + +/* ===== ESTILOS PARA PAGINAÇÃO ===== */ + +.contador-pacientes { + background-color: #1e3a8a; + color: white; + padding: 0.5em 0.75em; + font-size: 0.875em; + font-weight: 500; + border-radius: 0.375rem; + text-align: center; + display: inline-block; +} + +/* Estilos para a paginação */ +.pagination { + margin-bottom: 0; +} + +.page-link { + color: #495057; + border: 1px solid #dee2e6; + padding: 0.375rem 0.75rem; + font-size: 0.875rem; +} + +.page-link:hover { + color: #1e3a8a; + background-color: #e9ecef; + border-color: #dee2e6; +} + +.page-item.active .page-link { + background-color: #1e3a8a; + border-color: #1e3a8a; + color: white; +} + +.page-item.disabled .page-link { + color: #6c757d; + background-color: #f8f9fa; + border-color: #dee2e6; +} + +/* Ajustes para a seção de paginação */ +.d-flex.justify-content-between.align-items-center { + border-top: 1px solid #dee2e6; + padding-top: 1rem; + margin-top: 1rem; +} + +/* Estilos para empty state */ .text-center.py-4 .text-muted { padding: 2rem; } @@ -333,147 +307,6 @@ padding: 2rem !important; } -/* ===== RESPONSIVIDADE ===== */ -@media (max-width: 768px) { - .table-paciente-container { - padding: 1rem; - } - - .table-paciente-card .card-header { - flex-direction: column; - gap: 1rem; - align-items: flex-start; - } - - .table-paciente-filters .d-flex.flex-wrap.align-items-center.gap-3 { - gap: 1rem !important; - flex-direction: column; - align-items: flex-start; - } - - .table-paciente-filters .d-flex.align-items-center.gap-2 { - width: 100%; - justify-content: space-between; - } - - .table-paciente-filters .form-select-sm.compact-select { - min-width: 100% !important; - margin-top: 0.25rem; - } - - .vr.d-none.d-md-block { - display: none !important; - } - - .table-paciente-table { - font-size: 0.875rem; - } - - .table-paciente-table th, - .table-paciente-table td { - padding: 10px 6px; - } - - .btn-view, - .btn-edit, - .btn-delete { - padding: 0.25rem 0.5rem; - font-size: 0.75rem; - } - - .table-paciente-filters .d-flex { - flex-direction: column; - gap: 0.5rem; - } - - .table-paciente-filters .form-select { - min-width: 100% !important; - } - - .patient-name-container { - flex-direction: column; - align-items: flex-start !important; - gap: 0.25rem; - } - - .d-flex.justify-content-between.align-items-center { - flex-direction: column; - gap: 1rem; - align-items: stretch !important; - } - - /* Ocultar colunas em mobile */ - .table-paciente-table thead th:nth-child(3), - .table-paciente-table thead th:nth-child(4), - .table-paciente-table tbody td:nth-child(3), - .table-paciente-table tbody td:nth-child(4) { - display: none; - } -} - -@media (max-width: 576px) { - .table-paciente-card .card-header { - padding: 0.75rem 1rem; - } - - .table-paciente-table th, - .table-paciente-table td { - padding: 8px 6px; - } - - .table-paciente-filters .btn-sm { - width: 100%; - } - - /* Ocultar mais colunas em telas muito pequenas */ - .table-paciente-table thead th:nth-child(2), - .table-paciente-table thead th:nth-child(5), - .table-paciente-table tbody td:nth-child(2), - .table-paciente-table tbody td:nth-child(5) { - display: none; - } -} - -/* ===== MELHORIAS VISUAIS ===== */ -.form-select-sm:focus { - border-color: #1e3a8a; - box-shadow: 0 0 0 0.2rem rgba(30, 58, 138, 0.25); -} - -.btn-outline-secondary.btn-sm { - border-color: #6c757d; - color: #6c757d; - font-size: 0.8rem; - padding: 0.35rem 0.75rem; -} - -.btn-outline-secondary.btn-sm:hover { - background-color: #6c757d; - color: white; -} - -.advanced-filters { - background-color: var(--bg-light); - border: 1px solid #dee2e6 !important; -} - -.advanced-filters .form-control-sm { - font-size: 0.825rem; -} - -.advanced-filters h6 { - color: #495057; - font-size: 0.9rem; - font-weight: 600; -} - -/* Ajustes para a seção de paginação */ -.d-flex.justify-content-between.align-items-center { - border-top: 1px solid #dee2e6; - padding-top: 1rem; - margin-top: 1rem; -} - /* Responsividade para paginação */ @media (max-width: 768px) { .d-flex.justify-content-between.align-items-center { @@ -510,26 +343,19 @@ font-size: 0.875rem; } -/* Melhorar a aparência dos badges de paciente */ -.patient-badges { - display: flex; - gap: 0.25rem; - margin-left: 0.5rem; +/* Melhorar a aparência dos badges de filtros ativos */ +.filters-active .badge { + font-size: 0.75em; + padding: 0.4em 0.65em; + margin-bottom: 0.25rem; } -.patient-name-container { - display: flex; - align-items: center; - flex-wrap: wrap; -} - -/* Transições suaves */ -.table-paciente-table tbody tr { - transition: background-color 0.15s ease-in-out; -} - -.btn-view, -.btn-edit, -.btn-delete { - transition: all 0.15s ease-in-out; +@media (max-width: 576px) { + .table-paciente-card .card-header { padding: 0.75rem 1rem; } + .table-paciente-table th, .table-paciente-table td { padding: 8px 6px; } + .table-paciente-table thead th:nth-child(2), + .table-paciente-table thead th:nth-child(4), + .table-paciente-table tbody td:nth-child(2), + .table-paciente-table tbody td:nth-child(4) { display: none; } + .table-paciente-filters .btn-sm { width: 100%; } } \ No newline at end of file