Compare commits
1 Commits
main
...
CrudUsuari
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f5031e24b |
510
package-lock.json
generated
510
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -9,8 +9,7 @@ import LandingPage from './pages/LandingPage';
|
|||||||
import PerfilFinanceiro from "./perfis/perfil_financeiro/PerfilFinanceiro";
|
import PerfilFinanceiro from "./perfis/perfil_financeiro/PerfilFinanceiro";
|
||||||
import Perfiladm from "./perfis/Perfil_adm/Perfiladm";
|
import Perfiladm from "./perfis/Perfil_adm/Perfiladm";
|
||||||
import PerfilMedico from "./perfis/Perfil_medico/PerfilMedico";
|
import PerfilMedico from "./perfis/Perfil_medico/PerfilMedico";
|
||||||
|
import PerfilUsuario from "./perfis/perfil_usuario/PerfilUsuario";
|
||||||
// COMBINADO: Importações de ambas as versões
|
|
||||||
import PerfilPaciente from "./perfis/Perfil_paciente/Perfilpaciente"
|
import PerfilPaciente from "./perfis/Perfil_paciente/Perfilpaciente"
|
||||||
import ProfilePage from "./pages/ProfilePage";
|
import ProfilePage from "./pages/ProfilePage";
|
||||||
import Header from "./components/Header/Header";
|
import Header from "./components/Header/Header";
|
||||||
@ -36,6 +35,7 @@ function App() {
|
|||||||
<Route path="/financeiro/*" element={<PerfilFinanceiro />} />
|
<Route path="/financeiro/*" element={<PerfilFinanceiro />} />
|
||||||
<Route path="/medico/*" element={<PerfilMedico />} />
|
<Route path="/medico/*" element={<PerfilMedico />} />
|
||||||
<Route path="/admin/*" element={<Perfiladm />} />
|
<Route path="/admin/*" element={<Perfiladm />} />
|
||||||
|
<Route path="/usuario/*" element={<PerfilUsuario />} />
|
||||||
|
|
||||||
{/* COMBINADO: Rotas de ambas as versões */}
|
{/* COMBINADO: Rotas de ambas as versões */}
|
||||||
<Route path="/paciente/*" element={<PerfilPaciente />} />
|
<Route path="/paciente/*" element={<PerfilPaciente />} />
|
||||||
|
|||||||
@ -34,9 +34,17 @@ const TrocardePerfis = () => {
|
|||||||
{ key: "financeiro", label: "Financeiro", route: "/financeiro" },
|
{ key: "financeiro", label: "Financeiro", route: "/financeiro" },
|
||||||
{ key: "admin", label: "Administração", route: "/admin" },
|
{ key: "admin", label: "Administração", route: "/admin" },
|
||||||
{ key: "paciente", label: "Paciente", route: "/paciente" },
|
{ key: "paciente", label: "Paciente", route: "/paciente" },
|
||||||
].filter(
|
{ key: "usuario", label: "Usuário", route: "/usuario" },
|
||||||
(opt) =>
|
];
|
||||||
showProfiles?.includes(opt.key) || showProfiles?.includes("admin")
|
|
||||||
|
// Normalize roles to lowercase so we can accept variations like 'user' or 'usuario'
|
||||||
|
const rolesLower = (showProfiles || []).map((r) => String(r).toLowerCase());
|
||||||
|
|
||||||
|
const filteredOptions = options.filter((opt) =>
|
||||||
|
rolesLower.includes(opt.key) ||
|
||||||
|
rolesLower.includes("admin") ||
|
||||||
|
// accept backend returning 'user' for the usuario profile
|
||||||
|
(opt.key === "usuario" && rolesLower.includes("user"))
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -48,7 +56,7 @@ const TrocardePerfis = () => {
|
|||||||
onChange={handleSelectChange}
|
onChange={handleSelectChange}
|
||||||
>
|
>
|
||||||
<option value="">Selecionar perfil</option>
|
<option value="">Selecionar perfil</option>
|
||||||
{options.map((opt) => (
|
{filteredOptions.map((opt) => (
|
||||||
<option key={opt.key} value={opt.route}>
|
<option key={opt.key} value={opt.route}>
|
||||||
{opt.label}
|
{opt.label}
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
@ -1,272 +1,203 @@
|
|||||||
/* --- ESTILO PARA ESCONDER O BOTÃO ORIGINAL DO VLIBRAS --- */
|
@import url('https://fonts.cdnfonts.com/css/open-dyslexic');
|
||||||
|
|
||||||
[vw-access-button] {
|
[vw-access-button] {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- ESTILOS GERAIS DO COMPONENTE --- */
|
|
||||||
.container-acessibilidade {
|
.container-acessibilidade {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
z-index: 99998;
|
z-index: 10000;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
pointer-events: none; /* Impede cliques no contêiner */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.botao-flutuante-acessibilidade {
|
.botao-flutuante-acessibilidade {
|
||||||
position: relative;
|
|
||||||
z-index: 2; /* Acima do menu */
|
|
||||||
background: linear-gradient(45deg, #007bff, #0056b3);
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 60px;
|
height: 60px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #007bff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-shadow: 0 5px 15px rgba(0, 91, 179, 0.4);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease;
|
justify-content: center;
|
||||||
margin-top: 15px; /* Distância do menu */
|
|
||||||
pointer-events: auto; /* Permite que o botão seja clicável */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.botao-flutuante-acessibilidade:hover {
|
|
||||||
transform: scale(1.1);
|
|
||||||
box-shadow: 0 8px 20px rgba(0, 91, 179, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* --- ESTILOS DO MENU "BALÃO" --- */
|
|
||||||
.menu-opcoes {
|
.menu-opcoes {
|
||||||
background-color: #ffffff;
|
position: absolute;
|
||||||
border-radius: 12px;
|
bottom: 70px;
|
||||||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
right: 0;
|
||||||
padding: 8px;
|
|
||||||
width: 280px;
|
width: 280px;
|
||||||
z-index: 1; /* Abaixo do botão principal */
|
max-height: calc(100vh - 100px);
|
||||||
border: 1px solid #e9ecef;
|
overflow-y: auto;
|
||||||
|
background-color: white;
|
||||||
/* Animação */
|
border-radius: 8px;
|
||||||
transform-origin: bottom center;
|
box-shadow: 0 6px 12px rgba(0,0,0,0.3);
|
||||||
transform: translateY(10px) scale(0.95);
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 15px;
|
||||||
|
transform: scale(0.95);
|
||||||
|
transform-origin: bottom right;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
transition: all 0.2s ease;
|
transition: transform 0.2s ease, opacity 0.2s ease, visibility 0.2s;
|
||||||
pointer-events: auto; /* Permite que o menu seja clicável */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-opcoes.aberto {
|
.menu-opcoes.aberto {
|
||||||
transform: translateY(0) scale(1);
|
transform: scale(1);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-titulo {
|
.menu-titulo {
|
||||||
font-size: 14px;
|
font-size: 18px;
|
||||||
font-weight: 600;
|
font-weight: bold;
|
||||||
color: #6c757d;
|
margin-bottom: 10px;
|
||||||
padding: 8px 12px;
|
text-align: center;
|
||||||
border-bottom: 1px solid #f1f3f5;
|
color: #333;
|
||||||
margin-bottom: 5px;
|
|
||||||
transition: color 0.2s ease, border-bottom-color 0.2s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- ESTILOS DOS BOTÕES E DA CHECKBOX NO MENU --- */
|
|
||||||
.menu-opcoes button,
|
.menu-opcoes button,
|
||||||
.checkbox-label-button {
|
.checkbox-label-button {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
gap: 10px;
|
||||||
background-color: transparent;
|
font-size: 15px;
|
||||||
border: none;
|
color: #333;
|
||||||
padding: 12px;
|
transition: background-color 0.2s;
|
||||||
text-align: left;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #212529;
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 8px;
|
|
||||||
transition: background-color 0.2s ease, color 0.2s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-opcoes button:hover,
|
.menu-opcoes button:hover,
|
||||||
.checkbox-label-button:hover {
|
.checkbox-label-button:hover {
|
||||||
background-color: #f8f9fa;
|
background-color: #f0f0f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- ESTILO DO INTERRUPTOR (CHECKBOX) --- */
|
|
||||||
.checkbox-label-button {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox-label-button input[type="checkbox"] {
|
.checkbox-label-button input[type="checkbox"] {
|
||||||
appearance: none;
|
margin-left: auto;
|
||||||
-webkit-appearance: none;
|
|
||||||
position: relative;
|
|
||||||
width: 44px;
|
|
||||||
height: 24px;
|
|
||||||
background-color: #ced4da;
|
|
||||||
border-radius: 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox-label-button input[type="checkbox"]::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 2px;
|
|
||||||
left: 2px;
|
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
background-color: white;
|
cursor: pointer;
|
||||||
border-radius: 50%;
|
|
||||||
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
|
||||||
transition: transform 0.3s ease-in-out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox-label-button input[type="checkbox"]:checked {
|
/* Tamanho da Fonte */
|
||||||
background-color: #0d6efd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox-label-button input[type="checkbox"]:checked::before {
|
|
||||||
transform: translateX(20px);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* --- ✨ NOVOS ESTILOS PARA O CONTROLE DE FONTE ✨ --- */
|
|
||||||
|
|
||||||
.font-size-control {
|
.font-size-control {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
padding: 10px;
|
||||||
padding: 8px 12px;
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
color: #212529;
|
border-radius: 8px;
|
||||||
transition: color 0.2s ease;
|
margin-bottom: 5px;
|
||||||
border-top: 1px solid #f1f3f5;
|
gap: 10px;
|
||||||
margin-top: 5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.font-size-label {
|
.font-size-label {
|
||||||
font-size: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.font-size-buttons {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
|
||||||
|
|
||||||
.font-size-buttons button {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 16px;
|
|
||||||
background-color: #e9ecef;
|
|
||||||
color: #495057;
|
|
||||||
border: 1px solid #dee2e6;
|
|
||||||
border-radius: 6px;
|
|
||||||
width: 36px;
|
|
||||||
height: 32px;
|
|
||||||
padding: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
transition: background-color 0.2s ease, color 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.font-size-buttons button:hover {
|
|
||||||
background-color: #dee2e6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.font-size-buttons button:disabled {
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
color: #adb5bd;
|
|
||||||
cursor: not-allowed;
|
|
||||||
border-color: #f1f3f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.font-size-display {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #495057;
|
font-size: 15px;
|
||||||
min-width: 45px;
|
}
|
||||||
|
.font-size-buttons {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.font-size-buttons button {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 38px;
|
||||||
|
height: 38px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
background-color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #333;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.font-size-buttons span {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
min-width: 50px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: color 0.2s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dark mode styles */
|
/* Fonte para Dislexia */
|
||||||
html[data-bs-theme="dark"] {
|
.dyslexia-font-active * {
|
||||||
|
font-family: 'Open-Dyslexic', sans-serif !important;
|
||||||
/* Floating button */
|
|
||||||
.botao-flutuante-acessibilidade {
|
|
||||||
background: linear-gradient(45deg, #212529, #343a40);
|
|
||||||
color: #f8f9fa;
|
|
||||||
box-shadow: 0 5px 15px rgba(33, 37, 41, 0.4);
|
|
||||||
}
|
|
||||||
.botao-flutuante-acessibilidade:hover {
|
|
||||||
box-shadow: 0 8px 20px rgba(33, 37, 41, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Menu balloon */
|
|
||||||
.menu-opcoes {
|
|
||||||
background-color: #23272b;
|
|
||||||
border: 1px solid #343a40;
|
|
||||||
box-shadow: 0 8px 25px rgba(0,0,0,0.4);
|
|
||||||
}
|
|
||||||
.menu-titulo {
|
|
||||||
color: #adb5bd;
|
|
||||||
border-bottom: 1px solid #343a40;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Menu buttons and checkbox */
|
|
||||||
.menu-opcoes button,
|
|
||||||
.checkbox-label-button {
|
|
||||||
color: #f8f9fa;
|
|
||||||
}
|
|
||||||
.menu-opcoes button:hover,
|
|
||||||
.checkbox-label-button:hover {
|
|
||||||
background-color: #343a40;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Checkbox switch */
|
|
||||||
.checkbox-label-button input[type="checkbox"] {
|
|
||||||
background-color: #495057;
|
|
||||||
}
|
|
||||||
.checkbox-label-button input[type="checkbox"]:checked {
|
|
||||||
background-color: #0d6efd;
|
|
||||||
}
|
|
||||||
.checkbox-label-button input[type="checkbox"]::before {
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Font size control */
|
|
||||||
.font-size-control {
|
|
||||||
color: #f8f9fa;
|
|
||||||
border-top: 1px solid #343a40;
|
|
||||||
}
|
|
||||||
.font-size-label {
|
|
||||||
color: #f8f9fa;
|
|
||||||
}
|
|
||||||
.font-size-buttons button {
|
|
||||||
background-color: #343a40;
|
|
||||||
color: #f8f9fa;
|
|
||||||
border: 1px solid #495057;
|
|
||||||
}
|
|
||||||
.font-size-buttons button:hover {
|
|
||||||
background-color: #495057;
|
|
||||||
}
|
|
||||||
.font-size-buttons button:disabled {
|
|
||||||
background-color: #23272b;
|
|
||||||
color: #6c757d;
|
|
||||||
border-color: #343a40;
|
|
||||||
}
|
|
||||||
.font-size-display {
|
|
||||||
color: #f8f9fa;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Espaçamento e Altura */
|
||||||
|
.letter-spacing-active p, .letter-spacing-active li, .letter-spacing-active span, .letter-spacing-active a, .letter-spacing-active div, .letter-spacing-active td, .letter-spacing-active h1, .letter-spacing-active h2, .letter-spacing-active h3, .letter-spacing-active h4, .letter-spacing-active h5, .letter-spacing-active h6 {
|
||||||
|
letter-spacing: 1.5px !important;
|
||||||
|
}
|
||||||
|
.line-height-active p, .line-height-active li, .line-height-active span, .line-height-active a, .line-height-active div, .line-height-active td, .line-height-active h1, .line-height-active h2, .line-height-active h3, .line-height-active h4, .line-height-active h5, .line-height-active h6 {
|
||||||
|
line-height: 3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Guia de Leitura */
|
||||||
|
.reading-guide-mask {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
z-index: 99999;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: all 0.05s ease-out;
|
||||||
|
}
|
||||||
|
.reading-guide-top {
|
||||||
|
top: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
.reading-guide-bottom {
|
||||||
|
bottom: 0;
|
||||||
|
top: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cursor Grande */
|
||||||
|
.big-cursor-active, .big-cursor-active * {
|
||||||
|
cursor: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="black" stroke="white" stroke-width="2" d="M13.64,21.97C13.14,22.21 12.54,22 12.31,21.5L10.13,16.76L7.62,18.78C7.45,18.92 7.24,19 7,19A1,1 0 0,1 6,18V4A1,1 0 0,1 7,3C7.24,3 7.45,3.08 7.62,3.22L16.39,10.22C16.78,10.5 16.88,11.05 16.6,11.45L13.64,21.97Z" /></svg>') 1 1, auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Filtros de Daltonismo */
|
||||||
|
.colorblind-protanopia { filter: url(#protanopia); }
|
||||||
|
.colorblind-deuteranopia { filter: url(#deuteranopia); }
|
||||||
|
.colorblind-tritanopia { filter: url(#tritanopia); }
|
||||||
|
.colorblind-achromatopsia { filter: url(#achromatopsia); }
|
||||||
|
|
||||||
|
.acessibilidade-select-control {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
.acessibilidade-select-control label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.acessibilidade-select-control select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark Mode */
|
||||||
|
.dark-mode .menu-opcoes { background-color: #2d2d2d; color: #f1f1f1; }
|
||||||
|
.dark-mode .menu-titulo { color: #f1f1f1; }
|
||||||
|
.dark-mode .menu-opcoes button, .dark-mode .checkbox-label-button { background-color: #424242; border-color: #555; color: #f1f1f1; }
|
||||||
|
.dark-mode .menu-opcoes button:hover, .dark-mode .checkbox-label-button:hover { background-color: #535353; }
|
||||||
|
.dark-mode .font-size-control, .dark-mode .acessibilidade-select-control { background-color: rgba(255, 255, 255, 0.1); }
|
||||||
|
.dark-mode .font-size-buttons button { background-color: #535353; color: #f1f1f1; border-color: #666; }
|
||||||
|
.dark-mode .acessibilidade-select-control select { background-color: #535353; color: #f1f1f1; border-color: #666; }
|
||||||
@ -2,41 +2,131 @@ import React, { useState, useEffect, useRef } from 'react';
|
|||||||
import './botaoacessibilidade.css'; // Importando o CSS
|
import './botaoacessibilidade.css'; // Importando o CSS
|
||||||
import { setTheme } from '../assets/static/js/components/dark';
|
import { setTheme } from '../assets/static/js/components/dark';
|
||||||
|
|
||||||
|
// Componente para o Guia de Leitura
|
||||||
|
function GuiaDeLeitura() {
|
||||||
|
const topMaskRef = useRef(null);
|
||||||
|
const bottomMaskRef = useRef(null);
|
||||||
|
useEffect(() => {
|
||||||
|
const handleMouseMove = (e) => {
|
||||||
|
if (topMaskRef.current && bottomMaskRef.current) {
|
||||||
|
const windowHeight = 40;
|
||||||
|
const offset = windowHeight / 2;
|
||||||
|
topMaskRef.current.style.height = `${e.clientY - offset}px`;
|
||||||
|
bottomMaskRef.current.style.top = `${e.clientY + offset}px`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.addEventListener('mousemove', handleMouseMove);
|
||||||
|
return () => { window.removeEventListener('mousemove', handleMouseMove); };
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div ref={topMaskRef} className="reading-guide-mask reading-guide-top"></div>
|
||||||
|
<div ref={bottomMaskRef} className="reading-guide-mask reading-guide-bottom"></div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- COMPONENTE PRINCIPAL ---
|
||||||
function BotaoAcessibilidade() {
|
function BotaoAcessibilidade() {
|
||||||
|
// Estados de todas as funcionalidades
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
const [isReadOnHoverActive, setIsReadOnHoverActive] = useState(false);
|
|
||||||
const [isDarkMode, setIsDarkMode] = useState(false);
|
const [isDarkMode, setIsDarkMode] = useState(false);
|
||||||
|
const [isReadOnHoverActive, setIsReadOnHoverActive] = useState(false);
|
||||||
|
const [fontSize, setFontSize] = useState(1);
|
||||||
|
const [isBigCursor, setIsBigCursor] = useState(false);
|
||||||
|
const [colorblindMode, setColorblindMode] = useState('none');
|
||||||
|
const [isReadingGuide, setIsReadingGuide] = useState(false);
|
||||||
|
const [isDyslexiaFont, setIsDyslexiaFont] = useState(false);
|
||||||
|
const [isLetterSpacing, setIsLetterSpacing] = useState(false);
|
||||||
|
const [isLineHeight, setIsLineHeight] = useState(false);
|
||||||
const lastSpokenTargetRef = useRef(null);
|
const lastSpokenTargetRef = useRef(null);
|
||||||
|
|
||||||
|
// Efeitos para aplicar as funcionalidades na página
|
||||||
|
useEffect(() => { setTheme(isDarkMode ? "dark" : "light", true); }, [isDarkMode]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTheme(isDarkMode ? "dark" : "light", true);
|
const originalFontSize = document.documentElement.style.fontSize;
|
||||||
}, [isDarkMode]);
|
document.documentElement.style.fontSize = `${fontSize * 100}%`;
|
||||||
|
return () => { document.documentElement.style.fontSize = originalFontSize; };
|
||||||
|
}, [fontSize]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isReadOnHoverActive) {
|
document.body.classList.toggle('big-cursor-active', isBigCursor);
|
||||||
window.speechSynthesis.cancel();
|
return () => { document.body.classList.remove('big-cursor-active'); };
|
||||||
return;
|
}, [isBigCursor]);
|
||||||
|
useEffect(() => {
|
||||||
|
document.body.classList.toggle('dyslexia-font-active', isDyslexiaFont);
|
||||||
|
return () => { document.body.classList.remove('dyslexia-font-active'); };
|
||||||
|
}, [isDyslexiaFont]);
|
||||||
|
useEffect(() => {
|
||||||
|
document.body.classList.toggle('letter-spacing-active', isLetterSpacing);
|
||||||
|
return () => { document.body.classList.remove('letter-spacing-active'); };
|
||||||
|
}, [isLetterSpacing]);
|
||||||
|
useEffect(() => {
|
||||||
|
document.body.classList.toggle('line-height-active', isLineHeight);
|
||||||
|
return () => { document.body.classList.remove('line-height-active'); };
|
||||||
|
}, [isLineHeight]);
|
||||||
|
useEffect(() => {
|
||||||
|
const classesToRemove = ['colorblind-protanopia', 'colorblind-deuteranopia', 'colorblind-tritanopia', 'colorblind-achromatopsia'];
|
||||||
|
document.documentElement.classList.remove(...classesToRemove);
|
||||||
|
if (colorblindMode !== 'none') {
|
||||||
|
document.documentElement.classList.add(`colorblind-${colorblindMode}`);
|
||||||
}
|
}
|
||||||
const handleMouseOver = (event) => {
|
}, [colorblindMode]);
|
||||||
const target = event.target;
|
// VERSÃO DEFINITIVA - Muito mais abrangente
|
||||||
if (target && target !== lastSpokenTargetRef.current && target.innerText) {
|
useEffect(() => {
|
||||||
const text = target.innerText.trim();
|
if (!isReadOnHoverActive) {
|
||||||
if (text.length > 0 && ['P', 'H1', 'H2', 'H3', 'BUTTON', 'A', 'LI', 'LABEL'].includes(target.tagName)) {
|
window.speechSynthesis.cancel();
|
||||||
lastSpokenTargetRef.current = target;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseOver = (event) => {
|
||||||
|
// Seletor muito mais completo, incluindo DIVs, SPANs, células de tabela, imagens e papéis de acessibilidade
|
||||||
|
const selector = 'P, H1, H2, H3, H4, H5, H6, BUTTON, A, LI, LABEL, SPAN, TD, TH, DT, DD, FIGCAPTION, [role="button"], [role="link"], [role="menuitem"], IMG';
|
||||||
|
const relevantElement = event.target.closest(selector);
|
||||||
|
|
||||||
|
if (relevantElement && relevantElement !== lastSpokenTargetRef.current) {
|
||||||
|
let textToSpeak = '';
|
||||||
|
|
||||||
|
// Lógica especial para IMAGENS: lê o atributo "alt"
|
||||||
|
if (relevantElement.tagName === 'IMG') {
|
||||||
|
textToSpeak = relevantElement.getAttribute('alt');
|
||||||
|
}
|
||||||
|
// Lógica para outros elementos: prioriza aria-label, depois title, e por último o texto interno
|
||||||
|
else {
|
||||||
|
textToSpeak =
|
||||||
|
relevantElement.getAttribute('aria-label') ||
|
||||||
|
relevantElement.getAttribute('title') ||
|
||||||
|
relevantElement.innerText;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textToSpeak) {
|
||||||
|
textToSpeak = textToSpeak.trim();
|
||||||
|
|
||||||
|
// Evita ler elementos que só têm elementos filhos, mas nenhum texto próprio direto
|
||||||
|
const hasTextAndNoChildren = textToSpeak.length > 0 && relevantElement.children.length === 0;
|
||||||
|
const hasTextAndIsBlock = textToSpeak.length > 0 && !['SPAN', 'A', 'STRONG', 'EM'].includes(relevantElement.tagName);
|
||||||
|
|
||||||
|
if (hasTextAndNoChildren || hasTextAndIsBlock) {
|
||||||
|
lastSpokenTargetRef.current = relevantElement;
|
||||||
window.speechSynthesis.cancel();
|
window.speechSynthesis.cancel();
|
||||||
const utterance = new SpeechSynthesisUtterance(text);
|
const utterance = new SpeechSynthesisUtterance(textToSpeak);
|
||||||
utterance.lang = 'pt-BR';
|
utterance.lang = 'pt-BR';
|
||||||
window.speechSynthesis.speak(utterance);
|
window.speechSynthesis.speak(utterance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
document.body.addEventListener('mouseover', handleMouseOver);
|
};
|
||||||
return () => {
|
|
||||||
document.body.removeEventListener('mouseover', handleMouseOver);
|
|
||||||
window.speechSynthesis.cancel();
|
|
||||||
};
|
|
||||||
}, [isReadOnHoverActive]);
|
|
||||||
|
|
||||||
|
document.body.addEventListener('mouseover', handleMouseOver);
|
||||||
|
return () => {
|
||||||
|
document.body.removeEventListener('mouseover', handleMouseOver);
|
||||||
|
window.speechSynthesis.cancel();
|
||||||
|
};
|
||||||
|
}, [isReadOnHoverActive]);
|
||||||
|
|
||||||
|
// Funções de controle
|
||||||
|
const handleIncreaseFontSize = () => setFontSize(prevSize => Math.min(prevSize + 0.1, 1.6));
|
||||||
|
const handleDecreaseFontSize = () => setFontSize(prevSize => Math.max(prevSize - 0.1, 0.8));
|
||||||
const handleVlibrasClick = () => {
|
const handleVlibrasClick = () => {
|
||||||
const originalVlibrasButton = document.querySelector('[vw-access-button]');
|
const originalVlibrasButton = document.querySelector('[vw-access-button]');
|
||||||
if (originalVlibrasButton) {
|
if (originalVlibrasButton) {
|
||||||
@ -47,53 +137,96 @@ function BotaoAcessibilidade() {
|
|||||||
setIsMenuOpen(false);
|
setIsMenuOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReadAloud = () => {
|
|
||||||
const selectedText = window.getSelection().toString().trim();
|
|
||||||
if (selectedText) {
|
|
||||||
window.speechSynthesis.cancel();
|
|
||||||
const utterance = new SpeechSynthesisUtterance(selectedText);
|
|
||||||
utterance.lang = 'pt-BR';
|
|
||||||
window.speechSynthesis.speak(utterance);
|
|
||||||
} else {
|
|
||||||
alert("Por favor, selecione um texto para ler em voz alta.");
|
|
||||||
}
|
|
||||||
setIsMenuOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`container-acessibilidade ${isDarkMode ? 'dark-mode' : ''}`}>
|
<div className={`container-acessibilidade ${isDarkMode ? 'dark-mode' : ''}`}>
|
||||||
|
{isReadingGuide && <GuiaDeLeitura />}
|
||||||
|
<svg style={{ position: 'absolute', height: 0, width: 0 }}>
|
||||||
|
<defs>
|
||||||
|
<filter id="protanopia"><feColorMatrix in="SourceGraphic" type="matrix" values="0.567, 0.433, 0, 0, 0, 0.558, 0.442, 0, 0, 0, 0, 0.242, 0.758, 0, 0, 0, 0, 0, 1, 0"/></filter>
|
||||||
|
<filter id="deuteranopia"><feColorMatrix in="SourceGraphic" type="matrix" values="0.625, 0.375, 0, 0, 0, 0.7, 0.3, 0, 0, 0, 0, 0.3, 0.7, 0, 0, 0, 0, 0, 1, 0"/></filter>
|
||||||
|
<filter id="tritanopia"><feColorMatrix in="SourceGraphic" type="matrix" values="0.95, 0.05, 0, 0, 0, 0, 0.433, 0.567, 0, 0, 0, 0.475, 0.525, 0, 0, 0, 0, 0, 1, 0"/></filter>
|
||||||
|
<filter id="achromatopsia"><feColorMatrix in="SourceGraphic" type="matrix" values="0.299, 0.587, 0.114, 0, 0, 0.299, 0.587, 0.114, 0, 0, 0.299, 0.587, 0.114, 0, 0, 0, 0, 0, 1, 0"/></filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
<div className={`menu-opcoes ${isMenuOpen ? 'aberto' : ''}`}>
|
<div className={`menu-opcoes ${isMenuOpen ? 'aberto' : ''}`}>
|
||||||
<div className="menu-titulo">Acessibilidade</div>
|
<div className="menu-titulo">Acessibilidade</div>
|
||||||
|
|
||||||
|
<div className="font-size-control">
|
||||||
|
<div className="font-size-label">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="4 7 4 4 20 4 20 7"></polyline><line x1="9" y1="20" x2="15" y2="20"></line><line x1="12" y1="4" x2="12" y2="20"></line></svg>
|
||||||
|
Tamanho da Fonte
|
||||||
|
</div>
|
||||||
|
<div className="font-size-buttons">
|
||||||
|
<button onClick={handleDecreaseFontSize} title="Diminuir Fonte">A-</button>
|
||||||
|
<span>{`${Math.round(fontSize * 100)}%`}</span>
|
||||||
|
<button onClick={handleIncreaseFontSize} title="Aumentar Fonte">A+</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="acessibilidade-select-control">
|
||||||
|
<label htmlFor="colorblind-select">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>
|
||||||
|
Modo Daltonismo
|
||||||
|
</label>
|
||||||
|
<select id="colorblind-select" value={colorblindMode} onChange={(e) => setColorblindMode(e.target.value)}>
|
||||||
|
<option value="none">Desativado</option>
|
||||||
|
<option value="protanopia">Protanopia</option>
|
||||||
|
<option value="deuteranopia">Deuteranopia</option>
|
||||||
|
<option value="tritanopia">Tritanopia</option>
|
||||||
|
<option value="achromatopsia">Monocromático</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<label htmlFor="darkModeCheckbox" className="checkbox-label-button">
|
<label htmlFor="darkModeCheckbox" className="checkbox-label-button">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>
|
||||||
Modo Escuro
|
Modo Escuro
|
||||||
<input
|
<input type="checkbox" id="darkModeCheckbox" checked={isDarkMode} onChange={() => setIsDarkMode(!isDarkMode)} />
|
||||||
type="checkbox"
|
|
||||||
id="darkModeCheckbox"
|
|
||||||
checked={isDarkMode}
|
|
||||||
onChange={() => setIsDarkMode(!isDarkMode)}
|
|
||||||
/>
|
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<label htmlFor="dyslexiaFontCheckbox" className="checkbox-label-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
|
||||||
|
Fonte para Dislexia
|
||||||
|
<input type="checkbox" id="dyslexiaFontCheckbox" checked={isDyslexiaFont} onChange={() => setIsDyslexiaFont(!isDyslexiaFont)} />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label htmlFor="letterSpacingCheckbox" className="checkbox-label-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
|
||||||
|
Espaçamento entre Letras
|
||||||
|
<input type="checkbox" id="letterSpacingCheckbox" checked={isLetterSpacing} onChange={() => setIsLetterSpacing(!isLetterSpacing)} />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label htmlFor="lineHeightCheckbox" className="checkbox-label-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
|
||||||
|
Altura da Linha
|
||||||
|
<input type="checkbox" id="lineHeightCheckbox" checked={isLineHeight} onChange={() => setIsLineHeight(!isLineHeight)} />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label htmlFor="readingGuideCheckbox" className="checkbox-label-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><line x1="8" y1="6" x2="21" y2="6"></line><line x1="8" y1="12" x2="21" y2="12"></line><line x1="8" y1="18" x2="21" y2="18"></line><line x1="3" y1="6" x2="3.01" y2="6"></line><line x1="3" y1="12" x2="3.01" y2="12"></line><line x1="3" y1="18" x2="3.01" y2="18"></line></svg>
|
||||||
|
Guia de Leitura
|
||||||
|
<input type="checkbox" id="readingGuideCheckbox" checked={isReadingGuide} onChange={() => setIsReadingGuide(!isReadingGuide)} />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label htmlFor="bigCursorCheckbox" className="checkbox-label-button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"></path><path d="M13 13l6 6"></path></svg>
|
||||||
|
Cursor Grande
|
||||||
|
<input type="checkbox" id="bigCursorCheckbox" checked={isBigCursor} onChange={() => setIsBigCursor(!isBigCursor)} />
|
||||||
|
</label>
|
||||||
|
|
||||||
<label htmlFor="readOnHoverCheckbox" className="checkbox-label-button">
|
<label htmlFor="readOnHoverCheckbox" className="checkbox-label-button">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"></path><path d="M13 13l6 6"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z"></path><path d="M13 13l6 6"></path></svg>
|
||||||
Leitura instantânea
|
Leitura instantânea
|
||||||
<input
|
<input type="checkbox" id="readOnHoverCheckbox" checked={isReadOnHoverActive} onChange={() => setIsReadOnHoverActive(!isReadOnHoverActive)} />
|
||||||
type="checkbox"
|
|
||||||
id="readOnHoverCheckbox"
|
|
||||||
checked={isReadOnHoverActive}
|
|
||||||
onChange={() => setIsReadOnHoverActive(!isReadOnHoverActive)}
|
|
||||||
/>
|
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
{/* ADICIONADO DE VOLTA: Botão para LIBRAS */}
|
||||||
<button onClick={handleVlibrasClick}>
|
<button onClick={handleVlibrasClick}>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 11V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v0" /><path d="M14 10V4a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v2" /><path d="M10 10.5V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v8" /><path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2h2.3" /></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 11V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v0" /><path d="M14 10V4a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v2" /><path d="M10 10.5V6a2 2 0 0 0-2-2v0a2 2 0 0 0-2 2v8" /><path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2h2.3" /></svg>
|
||||||
Traduzir para LIBRAS
|
Traduzir para LIBRAS
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button
|
|
||||||
className="botao-flutuante-acessibilidade"
|
<button className="botao-flutuante-acessibilidade" onClick={() => setIsMenuOpen(!isMenuOpen)} title="Menu de Acessibilidade">
|
||||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
|
||||||
title="Menu de Acessibilidade"
|
|
||||||
>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="30" height="30" fill="white">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="30" height="30" fill="white">
|
||||||
<path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z" />
|
<path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z" />
|
||||||
</svg>
|
</svg>
|
||||||
@ -101,6 +234,4 @@ function BotaoAcessibilidade() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
export default BotaoAcessibilidade;
|
||||||
export default BotaoAcessibilidade;
|
|
||||||
|
|
||||||
17
src/data/sidebar-items-usuario.json
Normal file
17
src/data/sidebar-items-usuario.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Menu",
|
||||||
|
"isTitle": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Cadastro de Pacientes",
|
||||||
|
"icon": "clipboard-heart-fill",
|
||||||
|
"url": "/usuario/pacientes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Laudo do Paciente",
|
||||||
|
"icon": "table",
|
||||||
|
"url": "/usuario/laudo"
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
@ -158,7 +158,8 @@ function PatientCadastroManager({ setCurrentPage }) {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setShowModal(false);
|
setShowModal(false);
|
||||||
navigate('/secretaria/pacientes');
|
// use relative navigation so this component works under different parent routes
|
||||||
|
navigate('..');
|
||||||
}, 2000);
|
}, 2000);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -200,10 +201,11 @@ function PatientCadastroManager({ setCurrentPage }) {
|
|||||||
|
|
||||||
<div className="modal-footer">
|
<div className="modal-footer">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowModal(false);
|
setShowModal(false);
|
||||||
if (infosModal.title === 'Sucesso') {
|
if (infosModal.title === 'Sucesso') {
|
||||||
navigate('/secretaria/pacientes');
|
// navigate to parent 'pacientes' route
|
||||||
|
navigate('..');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={`modal-confirm-button ${infosModal.title === 'Sucesso' ? 'success' : 'error'}`}
|
className={`modal-confirm-button ${infosModal.title === 'Sucesso' ? 'success' : 'error'}`}
|
||||||
@ -228,7 +230,7 @@ function PatientCadastroManager({ setCurrentPage }) {
|
|||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<PatientForm
|
<PatientForm
|
||||||
onSave={handleSavePatient}
|
onSave={handleSavePatient}
|
||||||
onCancel={() => navigate('/secretaria/pacientes')}
|
onCancel={() => navigate('..')}
|
||||||
formData={formData}
|
formData={formData}
|
||||||
setFormData={setFormData}
|
setFormData={setFormData}
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
|
|||||||
42
src/perfis/perfil_usuario/PerfilUsuario.jsx
Normal file
42
src/perfis/perfil_usuario/PerfilUsuario.jsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { Routes, Route } from "react-router-dom";
|
||||||
|
import Sidebar from "../../components/Sidebar";
|
||||||
|
import UsuarioItems from "../../data/sidebar-items-usuario.json";
|
||||||
|
import TablePaciente from "../../pages/TablePaciente";
|
||||||
|
import LaudoManager from "../../pages/LaudoManager";
|
||||||
|
import PatientCadastroManager from "../../pages/PatientCadastroManager";
|
||||||
|
import { Navigate } from "react-router-dom";
|
||||||
|
|
||||||
|
const UsuarioMensagens = () => (
|
||||||
|
<div>
|
||||||
|
<h2>Minhas Mensagens</h2>
|
||||||
|
<p>Aqui ficam as mensagens do usuário.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const UsuarioConfig = () => (
|
||||||
|
<div>
|
||||||
|
<h2>Configurações</h2>
|
||||||
|
<p>Opções de configuração do usuário.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
function PerfilUsuario({ onLogout }) {
|
||||||
|
return (
|
||||||
|
<div id="app" className="active">
|
||||||
|
<Sidebar onLogout={onLogout} menuItems={UsuarioItems} />
|
||||||
|
<div id="main">
|
||||||
|
<Routes>
|
||||||
|
<Route path="/" element={<Navigate to="pacientes/cadastro" replace />} />
|
||||||
|
<Route path="perfil" element={<Navigate to="pacientes/cadastro" replace />} />
|
||||||
|
<Route path="pacientes/cadastro" element={<PatientCadastroManager />} />
|
||||||
|
<Route path="pacientes" element={<TablePaciente />} />
|
||||||
|
<Route path="laudo" element={<LaudoManager />} />
|
||||||
|
<Route path="*" element={<h2>Página não encontrada</h2>} />
|
||||||
|
</Routes>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PerfilUsuario;
|
||||||
Loading…
x
Reference in New Issue
Block a user