diff --git a/package-lock.json b/package-lock.json index 271e8eb..c6790e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,10 +12,11 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.3.5", "bootstrap": "^5.2.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.4.1", + "react-router-dom": "^6.10.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }, @@ -3151,9 +3152,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.1.tgz", - "integrity": "sha512-eBV5rvW4dRFOU1eajN7FmYxjAIVz/mRHgUE9En9mBn6m3mulK3WTR5C3iQhL9MZ14rWAq+xOlEaCkDiW0/heOg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", + "integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==", "engines": { "node": ">=14" } @@ -5081,6 +5082,29 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.5.tgz", + "integrity": "sha512-glL/PvG/E+xCWwV8S6nCHcrfg1exGx7vxyUIivIA1iL7BIh6bePylCfVHwp6k13ao7SATxB6imau2kqY+I67kw==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", @@ -14657,6 +14681,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -14960,11 +14989,11 @@ } }, "node_modules/react-router": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.1.tgz", - "integrity": "sha512-OJASKp5AykDWFewgWUim1vlLr7yfD4vO/h+bSgcP/ix8Md+LMHuAjovA74MQfsfhQJGGN1nHRhwS5qQQbbBt3A==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", + "integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==", "dependencies": { - "@remix-run/router": "1.0.1" + "@remix-run/router": "1.5.0" }, "engines": { "node": ">=14" @@ -14974,12 +15003,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.1.tgz", - "integrity": "sha512-MY7NJCrGNVJtGp8ODMOBHu20UaIkmwD2V3YsAOUQoCXFk7Ppdwf55RdcGyrSj+ycSL9Uiwrb3gTLYSnzcRoXww==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz", + "integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==", "dependencies": { - "@remix-run/router": "1.0.1", - "react-router": "6.4.1" + "@remix-run/router": "1.5.0", + "react-router": "6.10.0" }, "engines": { "node": ">=14" @@ -20019,9 +20048,9 @@ "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" }, "@remix-run/router": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.1.tgz", - "integrity": "sha512-eBV5rvW4dRFOU1eajN7FmYxjAIVz/mRHgUE9En9mBn6m3mulK3WTR5C3iQhL9MZ14rWAq+xOlEaCkDiW0/heOg==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", + "integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==" }, "@rollup/plugin-babel": { "version": "5.3.1", @@ -21463,6 +21492,28 @@ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz", "integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==" }, + "axios": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.5.tgz", + "integrity": "sha512-glL/PvG/E+xCWwV8S6nCHcrfg1exGx7vxyUIivIA1iL7BIh6bePylCfVHwp6k13ao7SATxB6imau2kqY+I67kw==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + }, + "dependencies": { + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, "axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", @@ -28191,6 +28242,11 @@ } } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -28408,20 +28464,20 @@ "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==" }, "react-router": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.1.tgz", - "integrity": "sha512-OJASKp5AykDWFewgWUim1vlLr7yfD4vO/h+bSgcP/ix8Md+LMHuAjovA74MQfsfhQJGGN1nHRhwS5qQQbbBt3A==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", + "integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==", "requires": { - "@remix-run/router": "1.0.1" + "@remix-run/router": "1.5.0" } }, "react-router-dom": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.1.tgz", - "integrity": "sha512-MY7NJCrGNVJtGp8ODMOBHu20UaIkmwD2V3YsAOUQoCXFk7Ppdwf55RdcGyrSj+ycSL9Uiwrb3gTLYSnzcRoXww==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz", + "integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==", "requires": { - "@remix-run/router": "1.0.1", - "react-router": "6.4.1" + "@remix-run/router": "1.5.0", + "react-router": "6.10.0" } }, "react-scripts": { diff --git a/package.json b/package.json index 3b61e5f..cbf5b1f 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,11 @@ "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "axios": "^1.3.5", "bootstrap": "^5.2.2", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.4.1", + "react-router-dom": "^6.10.0", "react-scripts": "5.0.1", "web-vitals": "^2.1.4" }, diff --git a/src/App.jsx b/src/App.jsx index de514e1..4b86d9f 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,17 +1,33 @@ - import { Outlet } from "react-router-dom"; import Footer from "./Components/Footer"; import Navbar from "./Components/Navbar"; +import Home from "./pages/home"; +import Login from "./pages/login"; +import { BrowserRouter, Routes, Route } from "react-router-dom"; +import Detail from "./pages/detail"; +import NotFound from "./pages/not-found"; +import { useContext } from "react"; +import { ThemeContext } from "./contexts/theme-context"; function App() { + const { theme, handleChangeTheme } = useContext(ThemeContext); + return ( <> {/* //Na linha seguinte deverá ser feito um teste se a aplicação // está em dark mode e deverá utilizar a classe dark ou light */} -
+
+ + + } /> + } /> + } /> + } /> + +
diff --git a/src/Components/Card.jsx b/src/Components/Card.jsx index 51ec637..e10242d 100644 --- a/src/Components/Card.jsx +++ b/src/Components/Card.jsx @@ -1,7 +1,32 @@ +import { Link, useNavigate } from "react-router-dom"; import styles from "./Card.module.css"; +import { useEffect } from "react"; -const Card = () => { +//import {useState, useEffect} from 'react' +const Card = (props) => { + const {nome, sobrenome, usuario, matricula} = props.dados; +// const {matricula, setMatricula} = useState("") + const navigate = useNavigate() + +useEffect(() => { + const token = localStorage.getItem("ctd_token"); + + + console.log("Token no contexto: " + token); + if(token == null){ + navigate("/login") + } + else{ + + } +}, []); + + //useEffect(() => { + // const response = localStorage.getItem("@dentista_matricula"); + // saveMatricula(response); + //}, []); + return ( <> {/* //Na linha seguinte deverá ser feito um teste se a aplicação @@ -15,9 +40,10 @@ const Card = () => {
{/* Na linha seguinte o link deverá utilizar a matricula, nome e sobrenome do dentista que vem da API */} - -
Nome e Sobrenome do dentista
-
+ + +
{nome} {sobrenome}
+
diff --git a/src/Components/DetailCard.jsx b/src/Components/DetailCard.jsx index 3709ac0..1d002de 100644 --- a/src/Components/DetailCard.jsx +++ b/src/Components/DetailCard.jsx @@ -1,18 +1,48 @@ -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import ScheduleFormModal from "./ScheduleFormModal"; import styles from "./DetailCard.module.css"; +import { useParams } from "react-router-dom"; +import api from "../services/api"; const DetailCard = () => { + const { matricula } = useParams(); + const [dentista, setDentista] = useState({}); + const [token, setToken] = useState(""); + + async function getDentista(){ + const t = localStorage.getItem("ctd_token"); + setToken(t); + try{ + const response = await api.get(`/dentista?matricula=${matricula}`, { + headers: { + 'Authorization': `Bearer ${t}` + }}); + const d = { + nome: response.data.nome, + sobrenome: response.data.sobrenome, + matricula: response.data.matricula, + email: response.data.usuario.username + } + setDentista(d); + console.log(d); + } catch (error) { + console.log(error); + alert("Erro ao tentar pegar dados do Dentista"); + } + } useEffect(() => { //Nesse useEffect, você vai fazer um fetch na api passando o //id do dentista que está vindo do react-router e carregar os dados em algum estado + getDentista(); + }, []); + return ( //As instruções que estão com {''} precisam ser //substituídas com as informações que vem da api <> -

Detail about Dentist {'Nome do Dentista'}

+

Detail about Dentist {dentista.nome}

{/* //Na linha seguinte deverá ser feito um teste se a aplicação // está em dark mode e deverá utilizar o css correto */} @@ -28,12 +58,12 @@ const DetailCard = () => {
diff --git a/src/Components/LoginForm.jsx b/src/Components/LoginForm.jsx index b3900cf..f217413 100644 --- a/src/Components/LoginForm.jsx +++ b/src/Components/LoginForm.jsx @@ -1,16 +1,38 @@ import styles from "./Form.module.css"; +import { useContext } from "react"; +import { AuthContext } from "../contexts/auth-context"; +import api from "../services/api" +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; const LoginForm = () => { - const handleSubmit = (e) => { - //Nesse handlesubmit você deverá usar o preventDefault, - //enviar os dados do formulário e enviá-los no corpo da requisição - //para a rota da api que faz o login /auth - //lembre-se que essa rota vai retornar um Bearer Token e o mesmo deve ser salvo - //no localstorage para ser usado em chamadas futuras - //Com tudo ocorrendo corretamente, o usuário deve ser redirecionado a página principal,com react-router - //Lembre-se de usar um alerta para dizer se foi bem sucedido ou ocorreu um erro - }; + const { saveEmail, saveToken, setEstadoLogin } = useContext(AuthContext); + + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + + const navigate = useNavigate(); + async function logar() { + try { + const response = await api.post("/auth",{ + username: email, + password: password, + }) + console.log(response.data); + saveEmail(email); + saveToken(response.data.token); + setEstadoLogin("Logout"); + navigate("/"); + } catch (error) { + alert("Erro ao logar"); + } + } + + const handleSubmit = (e) => { + e.preventDefault(); + logar(); + } return ( <> {/* //Na linha seguinte deverá ser feito um teste se a aplicação @@ -25,6 +47,8 @@ const LoginForm = () => { placeholder="Login" name="login" required + value={email} + onChange={(event) => setEmail(event.target.value)} /> { name="password" type="password" required + value={password} + onChange={(event) => setPassword(event.target.value)} /> diff --git a/src/contexts/auth-context.jsx b/src/contexts/auth-context.jsx new file mode 100644 index 0000000..2c875f3 --- /dev/null +++ b/src/contexts/auth-context.jsx @@ -0,0 +1,45 @@ +import { createContext, useEffect, useState } from "react"; + +export const AuthContext = createContext({}); + +const AuthProvider = ({ children }) => { + const [stsLogin, setStsLogin] = useState("Login"); + + useEffect(() => { + const token = localStorage.getItem("ctd_token"); + console.log("Token no contexto: " + token); + if(token == null) + setStsLogin("Login"); + + else + setStsLogin("Logout"); + + }, []); + + function saveEmail(email) { + localStorage.setItem("ctd_email", email); + } + + function saveToken(token) { + localStorage.setItem("ctd_token", token); + } + + function removeUserStorage() { + localStorage.removeItem("ctd_email"); + localStorage.removeItem("ctd_token"); + } + + function setEstadoLogin(login){ + setStsLogin(login); + } + + return ( + + {children} + + ); +}; + +export default AuthProvider; \ No newline at end of file diff --git a/src/contexts/theme-context.jsx b/src/contexts/theme-context.jsx new file mode 100644 index 0000000..78c73b0 --- /dev/null +++ b/src/contexts/theme-context.jsx @@ -0,0 +1,21 @@ +import { createContext, useState } from "react"; + +export const ThemeContext = createContext({}); + +const ThemeProvider = ({ children }) => { + const [theme, setTheme] = useState("light"); + + const handleChangeTheme = () => { + theme === "light" ? setTheme("dark") : setTheme("light"); + } + + return ( + + {children} + + ); + }; + + export default ThemeProvider; \ No newline at end of file diff --git a/src/index.jsx b/src/index.jsx index b140d17..edfc60d 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -2,17 +2,19 @@ import React from "react"; import ReactDOM from "react-dom/client"; import "bootstrap/dist/css/bootstrap.min.css"; import "bootstrap/dist/js/bootstrap.min.js"; -import Navbar from "./Components/Navbar"; -import Home from "./Routes/Home"; -import Footer from "./Components/Footer"; import "./index.css"; +import App from "./App"; +import ThemeProvider from "./contexts/theme-context"; +import AuthProvider from "./contexts/auth-context"; const root = ReactDOM.createRoot(document.getElementById("root")); //Lembre-se de configurar suas rotas e seu contexto aqui root.render( - - -