Mergin com PaginasLogin

This commit is contained in:
jp-lima 2025-10-01 17:38:26 -03:00
commit 5c48c1ab3e
13 changed files with 614 additions and 25 deletions

View File

@ -1,13 +1,46 @@
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import { useState } from "react"; import { useState } from "react";
import Login from "./pages/Login";
import Register from "./pages/Register";
import Forgot from "./pages/ForgotPassword";
import PerfilSecretaria from "./perfis/perfil_secretaria/PerfilSecretaria"; import PerfilSecretaria from "./perfis/perfil_secretaria/PerfilSecretaria";
import LandingPage from './pages/LandingPage';
// Mantenha todas as importações de CSS globais aqui se houver!
function App() { function App() {
// O estado controla qual view mostrar: false = Landing Page, true = Dashboard
const [isInternalView, setIsInternalView] = useState(false);
const handleEnterSystem = () => {
setIsInternalView(true);
};
const handleExitSystem = () => {
setIsInternalView(false);
};
// Se não estiver na visualização interna, retorna a LandingPage.
if (!isInternalView) {
return ( return (
<div> <Router>
<PerfilSecretaria/> <Routes>
</div> <Route path="/" element={<LandingPage onEnterSystem={handleEnterSystem}/>} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/forgotPassword" element={<Forgot />} />
<Route path="/secretaria/*" element={<PerfilSecretaria />} />
<Route path="*" element={<h2>Página não encontrada</h2>} />
</Routes>
</Router>
)
}
// Se estiver na visualização interna, retorna o PerfilSecretaria
return (
// Passamos a função de saída (logout)
<PerfilSecretaria onLogout={handleExitSystem} />
); );
} }

View File

@ -1,3 +1,9 @@
.card-position {
padding-top: 1rem;
display: flex;
align-items: center;
justify-content: center;
}
.card { .card {
margin-bottom: 2.2rem; margin-bottom: 2.2rem;
border: none; border: none;

View File

@ -6,31 +6,31 @@
{ {
"name":"Início", "name":"Início",
"url": "/", "url": "/secretaria/inicio",
"icon": "house" "icon": "house"
}, },
{ {
"name": "Lista de Pacientes", "name": "Lista de Pacientes",
"icon": "clipboard-heart-fill", "icon": "clipboard-heart-fill",
"url": "/pacientes" "url": "/secretaria/pacientes"
}, },
{ {
"name": "Lista de Médico", "name": "Lista de Médico",
"icon": "hospital-fill", "icon": "hospital-fill",
"url": "/medicos" "url": "/secretaria/medicos"
}, },
{ {
"name": "Agendar consulta", "name": "Agendar consulta",
"icon": "calendar-plus-fill", "icon": "calendar-plus-fill",
"url": "/agendamento" "url": "/secretaria/agendamento"
}, },
{ {
"name": "Laudo do Paciente", "name": "Laudo do Paciente",
"icon": "table", "icon": "table",
"url": "/laudo" "url": "/secretaria/laudo"
} }
] ]

View File

@ -79,8 +79,7 @@ const HandlePutPatient = async () => {
<PatientForm <PatientForm
onSave={HandlePutPatient} onSave={HandlePutPatient}
onCancel={() => {setCurrentPage('table')}} onCancel={() => {navigate('/secretaria/pacientes')}}
setCurrentPage={setCurrentPage}
formData={PatientToPUT} formData={PatientToPUT}
setFormData={setPatientPUT} setFormData={setPatientPUT}
/> />

View File

@ -0,0 +1,82 @@
import React, { useState } from 'react';
import { Link } from "react-router-dom";
function ForgotPassword() {
const [email, setEmail] = useState("");
const [alert, setAlert] = useState("");
const handleChange = (e) => {
setEmail(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
if (email) {
// Simulate sending email
setAlert("E-mail de verificação enviado!");
// You can add your actual email logic here
} else {
setAlert("Preencha o campo de e-mail!");
}
};
return (
<>
<div className="mt-3 card-position">
<div className="col-lg-5 col-12">
<div className="card shadow-sm d-flex justify-content-between align-items-center">
<div id="auth-left">
<div className="auth-logo">
<br />
<Link to="/">
<h1 className="mb-4 text-center">MediConnect</h1>
</Link>
</div>
<h3 className="auth-title">Esqueci minha senha</h3>
<p className="auth-subtitle mb-5">
Informe seu e-mail e enviaremos um link para redefinir sua senha.
</p>
{alert && (
<div className="alert alert-info" role="alert">
{alert}
</div>
)}
<form onSubmit={handleSubmit}>
<div className="form-group position-relative has-icon-left mb-4">
<input
type="email"
className="form-control form-control-xl"
placeholder="E-mail"
value={email}
onChange={handleChange}
required
/>
<div className="form-control-icon">
<i className="bi bi-envelope" />
</div>
</div>
<button className="btn btn-primary btn-block btn-lg shadow-lg mt-5">
Enviar
</button>
</form>
<div className="text-center mt-5 text-lg fs-4">
<p className="text-gray-600">
Lembrou da sua senha?
<Link className="font-bold" to={'/login'}>
Entrar
</Link>
.
</p>
</div>
</div>
<div className="col-lg-7 d-none d-lg-block">
<div id="auth-right"></div>
</div>
</div>
</div>
</div>
</>
);
}
export default ForgotPassword;

View File

@ -1,11 +1,13 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { FaUser, FaUserPlus, FaCalendarAlt, FaCalendarCheck } from 'react-icons/fa'; import { FaUser, FaUserPlus, FaCalendarAlt, FaCalendarCheck } from 'react-icons/fa';
import './style/Inicio.css'; import './style/Inicio.css';
import { useAuth } from '../components/utils/AuthProvider'; import { useAuth } from '../components/utils/AuthProvider';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
function Inicio({ setCurrentPage }) { function Inicio() {
const {setAuthTokens} = useAuth() const { authTokens, setAuthTokens } = useAuth();
const navigate = useNavigate();
const [pacientes, setPacientes] = useState([]); const [pacientes, setPacientes] = useState([]);
const [agendamentos, setAgendamentos] = useState([]); const [agendamentos, setAgendamentos] = useState([]);
@ -120,21 +122,21 @@ function Inicio({ setCurrentPage }) {
<div className="quick-actions"> <div className="quick-actions">
<h2>Ações Rápidas</h2> <h2>Ações Rápidas</h2>
<div className="actions-grid"> <div className="actions-grid">
<div className="action-button" onClick={() => setCurrentPage('form-layout')}> <div className="action-button" onClick={() => navigate('/secretaria/pacientes/cadastro')}>
<FaUserPlus className="action-icon" /> <FaUserPlus className="action-icon" />
<div className="action-info"> <div className="action-info">
<span className="action-title">Novo Paciente</span> <span className="action-title">Novo Paciente</span>
<span className="action-desc">Cadastrar um novo paciente</span> <span className="action-desc">Cadastrar um novo paciente</span>
</div> </div>
</div> </div>
<div className="action-button" onClick={() => setCurrentPage('table')}> <div className="action-button" onClick={() => navigate('/secretaria/pacientes')}>
<FaUser className="action-icon" /> <FaUser className="action-icon" />
<div className="action-info"> <div className="action-info">
<span className="action-title">Lista de Pacientes</span> <span className="action-title">Lista de Pacientes</span>
<span className="action-desc">Ver todos os pacientes</span> <span className="action-desc">Ver todos os pacientes</span>
</div> </div>
</div> </div>
<div className="action-button" onClick={() => setCurrentPage('agendamento')}> <div className="action-button" onClick={() => navigate('/secretaria/agendamento')}>
<FaCalendarCheck className="action-icon" /> <FaCalendarCheck className="action-icon" />
<div className="action-info"> <div className="action-info">
<span className="action-title">Agendamentos</span> <span className="action-title">Agendamentos</span>
@ -159,7 +161,7 @@ function Inicio({ setCurrentPage }) {
<div className="no-appointments-content"> <div className="no-appointments-content">
<FaCalendarCheck className="no-appointments-icon" /> <FaCalendarCheck className="no-appointments-icon" />
<p>Nenhum agendamento para hoje</p> <p>Nenhum agendamento para hoje</p>
<button className="manage-button" onClick={() => setCurrentPage('agendamento')}> <button className="manage-button" onClick={() => navigate('/secretaria/agendamento')}>
Gerenciar Agendamentos Gerenciar Agendamentos
</button> </button>
</div> </div>

47
src/pages/LandingPage.jsx Normal file
View File

@ -0,0 +1,47 @@
import React from 'react';
import { useNavigate } from "react-router-dom";
import './style/LandingPage.css';
const LandingPage = () => {
const navigate = useNavigate();
return (
// Usa a classe de isolamento CSS
<div className="landing-page-public-view">
{/* CABEÇALHO */}
<header className="landing-header">
<div className="logo">
{/* Logo da Landing Page. O CSS irá estilizá-la corretamente. */}
<h1>MediConnect</h1>
</div>
<nav className="nav-menu">
<a href="#home">Início</a>
<a href="#services">Serviços</a>
<a href="#contact">Contato</a>
{/* Botão para entrar no sistema interno */}
<button className="access-button" onClick={() => navigate('/login')}>
Acessar Sistema
</button>
</nav>
</header>
{/* ÁREA DE DESTAQUE (HERO SECTION) */}
<div className="hero-section">
<div className="hero-content">
{/* Título Legível (Branco) */}
<h2 className="hero-title">
Descubra o Equilíbrio Perfeito de <br />Cuidado e Tecnologia.
</h2>
<p>
Somos focados em oferecer a melhor experiência para pacientes e a gestão mais eficiente para a clínica.
</p>
{/* Botão de ação principal: "Acessar Sistema" */}
<button className="main-action-button" onClick={() => navigate('/login')}>
Acessar Sistema
</button>
</div>
</div>
</div>
);
};
export default LandingPage;

131
src/pages/Login.jsx Normal file
View File

@ -0,0 +1,131 @@
import React, { useState } from 'react';
import { Link, useNavigate } from "react-router-dom";
function Login() {
const navigate = useNavigate();
const [form, setForm] = useState({
username: "",
password: ""
});
const [alert, setAlert] = useState("");
const [showPassword, setShowPassword] = useState(false);
const handleChange = (e) => {
setForm({ ...form, [e.target.name]: e.target.value });
};
const handleLogin = (e) => {
e.preventDefault();
if (form.username && form.password) {
// ...login logic...
navigate('/secretaria/inicio');
} else {
setAlert("Preencha todos os campos!");
}
};
return (
<>
<div className="mt-3 card-position">
<div className="col-lg-5 col-12">
<div className="card shadow-sm d-flex justify-content-between align-items-center">
<div id="auth-left">
<div className="auth-logo">
<br />
<Link to="/">
<h1 className="mb-4 text-center">MediConnect</h1>
</Link>
</div>
<h3 className="auth-title">Entrar</h3>
<p className="auth-subtitle mb-5">
Entre com os dados que você inseriu durante o registro.
</p>
{alert && (
<div className="alert alert-info" role="alert">
{alert}
</div>
)}
<form>
<div className="form-group position-relative has-icon-left mb-4">
<input
type="text"
name="username"
className="form-control form-control-xl"
placeholder="Username"
value={form.username}
onChange={handleChange}
required
/>
<div className="form-control-icon">
<i className="bi bi-person" />
</div>
</div>
<div className="form-group position-relative has-icon-left mb-4">
<input
type={showPassword ? "text" : "password"}
name="password"
className="form-control form-control-xl"
placeholder="Password"
value={form.password}
onChange={handleChange}
required
/>
<div className="form-control-icon">
<i className="bi bi-shield-lock" />
</div>
<button
type="button"
className="btn btn-sm"
style={{ position: "absolute", right: "10px", top: "10px", background: "none", border: "none" }}
onClick={() => setShowPassword(!showPassword)}
tabIndex={-1}
>
<i className={`bi ${showPassword ? "bi-eye-slash" : "bi-eye"}`}></i>
</button>
</div>
<div className="form-check form-check-lg d-flex align-items-end">
<input
className="form-check-input me-2"
type="checkbox"
defaultValue=""
id="flexCheckDefault"
/>
<label
className="form-check-label text-gray-600"
htmlFor="flexCheckDefault"
>
Manter-me conectado
</label>
</div>
<button className="btn btn-primary btn-block btn-lg shadow-lg mt-5"
onClick={handleLogin}>
Entrar
</button>
</form>
<div className="text-center mt-5 text-lg fs-4">
<p className="text-gray-600">
Não tem uma conta?
<Link className="font-bold" to={'/register'}>
Cadastre-se
</Link>
.
</p>
<p>
<Link className="font-bold" to={'/forgotPassword'}>
Esqueceu a senha?
</Link>
.
</p>
</div>
</div>
<div className="col-lg-7 d-none d-lg-block">
<div id="auth-right"></div>
</div>
</div>
</div>
</div>
</>
);
}
export default Login;

View File

@ -1,8 +1,10 @@
import {useState} from 'react'; import {useState} from 'react';
import React from 'react';
import { useNavigate } from 'react-router-dom';
import PatientForm from '../components/patients/PatientForm'; import PatientForm from '../components/patients/PatientForm';
import API_KEY from '../components/utils/apiKeys'; import API_KEY from '../components/utils/apiKeys';
import { useAuth } from '../components/utils/AuthProvider'; import { useAuth } from '../components/utils/AuthProvider';
import { useNavigate } from 'react-router-dom';
function PatientCadastroManager( {setCurrentPage} ) { function PatientCadastroManager( {setCurrentPage} ) {
const navigate = useNavigate() const navigate = useNavigate()
@ -97,7 +99,7 @@ function PatientCadastroManager( {setCurrentPage} ) {
<div className="col-12"> <div className="col-12">
<PatientForm <PatientForm
onSave={handleSavePatient} onSave={handleSavePatient}
onCancel={() => {navigate('/pacientes')}} onCancel={() => {navigate('/secretaria/pacientes')}}
formData={formData} formData={formData}
setFormData={setFormData} setFormData={setFormData}
/> />

182
src/pages/Register.jsx Normal file
View File

@ -0,0 +1,182 @@
import React, { useState } from 'react';
import { Link, useNavigate } from "react-router-dom";
function Register() {
const navigate = useNavigate();
const [form, setForm] = useState({
email: "",
username: "",
userType: "",
password: "",
confirmPassword: ""
});
const [alert, setAlert] = useState("");
const [showPassword, setShowPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const handleChange = (e) => {
setForm({ ...form, [e.target.name]: e.target.value });
};
const handleLogin = (e) => {
e.preventDefault();
if (
form.email &&
form.username &&
form.userType &&
form.password &&
form.confirmPassword
) {
if (form.password !== form.confirmPassword) {
setAlert("As senhas não coincidem!");
return;
}
// ...register logic...
navigate('/secretaria/inicio');
} else {
setAlert("Preencha todos os campos!");
}
};
return (
<>
<div className="mt-3 card-position">
<div className="col-lg-5 col-12">
<div className="card shadow-sm d-flex justify-content-between align-items-center">
<div id="auth-left">
<div className="auth-logo">
<br />
<Link to="/">
<h1 className="mb-4 text-center">MediConnect</h1>
</Link>
</div>
<h3 className="auth-title">Cadastre-se</h3>
<p className="auth-subtitle mb-5">
Insira seus dados para se registrar em nosso site.
</p>
{alert && (
<div className="alert alert-info" role="alert">
{alert}
</div>
)}
<form>
<div className="form-group position-relative has-icon-left mb-4">
<input
type="text"
name="email"
className="form-control form-control-xl"
placeholder="E-mail"
value={form.email}
onChange={handleChange}
required
/>
<div className="form-control-icon">
<i className="bi bi-envelope" />
</div>
</div>
<div className="form-group position-relative has-icon-left mb-4">
<input
type="text"
name="username"
className="form-control form-control-xl"
placeholder="Nome de usuário"
value={form.username}
onChange={handleChange}
required
/>
<div className="form-control-icon">
<i className="bi bi-person" />
</div>
</div>
<div className="form-group position-relative has-icon-left mb-4">
<select
name="userType"
className="form-control form-control-xl"
value={form.userType}
onChange={handleChange}
required
>
<option value="" disabled>
Selecione o tipo de usuário
</option>
<option value="paciente">Paciente</option>
<option value="secretaria">Secretaria</option>
<option value="medico">Médico</option>
<option value="admin">Admin</option>
</select>
<div className="form-control-icon">
<i className="bi bi-person" />
</div>
</div>
<div className="form-group position-relative has-icon-left mb-4">
<input
type={showPassword ? "text" : "password"}
name="password"
className="form-control form-control-xl"
placeholder="Senha"
value={form.password}
onChange={handleChange}
required
/>
<div className="form-control-icon">
<i className="bi bi-shield-lock" />
</div>
<button
type="button"
className="btn btn-sm"
style={{ position: "absolute", right: "10px", top: "10px", background: "none", border: "none" }}
onClick={() => setShowPassword(!showPassword)}
tabIndex={-1}
>
<i className={`bi ${showPassword ? "bi-eye-slash" : "bi-eye"}`}></i>
</button>
</div>
<div className="form-group position-relative has-icon-left mb-4">
<input
type={showConfirmPassword ? "text" : "password"}
name="confirmPassword"
className="form-control form-control-xl"
placeholder="Confirmar senha"
value={form.confirmPassword}
onChange={handleChange}
required
/>
<div className="form-control-icon">
<i className="bi bi-shield-lock" />
</div>
<button
type="button"
className="btn btn-sm"
style={{ position: "absolute", right: "10px", top: "10px", background: "none", border: "none" }}
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
tabIndex={-1}
>
<i className={`bi ${showConfirmPassword ? "bi-eye-slash" : "bi-eye"}`}></i>
</button>
</div>
<button className="btn btn-primary btn-block btn-lg shadow-lg mt-5"
onClick={handleLogin}>
Cadastrar
</button>
</form>
<div className="text-center mt-5 text-lg fs-4">
<p className="text-gray-600">
tem uma conta?
<Link className="font-bold" to={'/login'}>
Entrar
</Link>
.
</p>
</div>
</div>
<div className="col-lg-7 d-none d-lg-block">
<div id="auth-right"></div>
</div>
</div>
</div>
</div>
</>
);
}
export default Register;

View File

@ -156,10 +156,9 @@ function TablePaciente({ setCurrentPage, setPatientID }) {
<div className="card"> <div className="card">
<div className="card-header d-flex justify-content-between align-items-center"> <div className="card-header d-flex justify-content-between align-items-center">
<h4 className="card-title mb-0">Pacientes Cadastrados</h4> <h4 className="card-title mb-0">Pacientes Cadastrados</h4>
<Link to={'/pacientes/cadastro'}> <Link to={'/secretaria/pacientes/cadastro'}>
<button <button
className="btn btn-primary" className="btn btn-primary"
> >
<i className="bi bi-plus-circle"></i> Adicionar Paciente <i className="bi bi-plus-circle"></i> Adicionar Paciente
</button> </button>

View File

@ -0,0 +1,105 @@
/* src/pages/style/LandingPage.css */
/* O seletor .landing-page-public-view ajuda a isolar os estilos */
.landing-page-public-view {
min-height: 100vh;
background-color: #f0f2f5;
}
/* --- Cabeçalho --- */
.landing-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 50px;
background-color: white;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.05);
position: fixed;
width: 100%;
top: 0;
left: 0;
z-index: 1000;
}
/* Estilo para a logo DENTRO do cabeçalho da Landing Page */
.landing-header .logo h1 {
font-size: 1.8em;
color: #25396f;
font-weight: 700;
margin: 0; /* Remove margem que pode quebrar o layout */
padding: 0; /* Remove padding */
}
.nav-menu a {
text-decoration: none;
color: #333;
margin-left: 25px;
font-size: 1em;
transition: color 0.2s;
}
.nav-menu a:hover {
color: #5b56f8;
}
.nav-menu button:hover {
background-color: #4540d6;
}
.access-button {
background-color: #5b56f8;
color: white;
border: none;
padding: 8px 18px;
border-radius: 5px;
margin-left: 25px;
cursor: pointer;
font-weight: 600;
}
/* --- Área de Destaque (Hero Section) --- */
.hero-section {
display: flex;
justify-content: flex-start;
align-items: center;
padding: 100px 50px;
background: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.6)), url('https://picsum.photos/1200/600?random=4') center/cover;
color: white;
min-height: 600px;
padding-top: 100px;
}
.hero-content {
max-width: 700px;
text-align: left;
}
/* Título Branco e Legível */
.hero-content .hero-title {
font-size: 3.5em;
font-weight: 700;
margin-bottom: 20px;
color: #ffffff;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
}
.hero-content p {
font-size: 1.2em;
margin-bottom: 30px;
color: #ddd;
}
.main-action-button {
background-color: #5b56f8;
color: white;
border: none;
padding: 15px 30px;
border-radius: 5px;
font-size: 1.1em;
font-weight: 600;
cursor: pointer;
transition: background-color 0.3s;
}
.main-action-button:hover {
background-color: #4540d6;
}

View File

@ -1,4 +1,5 @@
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; //import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import { Routes, Route } from "react-router-dom";
import Sidebar from "../../components/Sidebar"; import Sidebar from "../../components/Sidebar";
import Inicio from "../../pages/Inicio"; import Inicio from "../../pages/Inicio";
@ -15,12 +16,12 @@ import DoctorEditPage from "../../pages/DoctorEditPage";
function PerfilSecretaria() { function PerfilSecretaria() {
return ( return (
<Router> // <Router>
<div id="app" className="active"> <div id="app" className="active">
<Sidebar /> <Sidebar />
<div id="main"> <div id="main">
<Routes> <Routes>
<Route path="/" element={<Inicio />} /> <Route path="/inicio" element={<Inicio />} />
<Route path="/pacientes/cadastro" element={<PatientCadastroManager />} /> <Route path="/pacientes/cadastro" element={<PatientCadastroManager />} />
<Route path="/medicos/cadastro" element={<DoctorCadastroManager />} /> <Route path="/medicos/cadastro" element={<DoctorCadastroManager />} />
<Route path="/pacientes" element={<TablePaciente />} /> <Route path="/pacientes" element={<TablePaciente />} />
@ -35,7 +36,7 @@ function PerfilSecretaria() {
</Routes> </Routes>
</div> </div>
</div> </div>
</Router> // </Router>
); );
} }