From 75334b953f0d05287327a4b4e431bebb92f86ead Mon Sep 17 00:00:00 2001 From: Algusto-RC Date: Sun, 10 Dec 2023 15:31:02 -0300 Subject: [PATCH 1/2] teste --- frontend/src/pages/Home/index.js | 4 +- frontend/src/pages/Recommendations/index.js | 257 +++++++++++++++++++ frontend/src/pages/Recommendations/styles.js | 0 frontend/src/routes/index.js | 3 +- 4 files changed, 262 insertions(+), 2 deletions(-) create mode 100644 frontend/src/pages/Recommendations/index.js create mode 100644 frontend/src/pages/Recommendations/styles.js diff --git a/frontend/src/pages/Home/index.js b/frontend/src/pages/Home/index.js index f83266f3..f8b683e7 100644 --- a/frontend/src/pages/Home/index.js +++ b/frontend/src/pages/Home/index.js @@ -19,13 +19,15 @@ const Home = () => { - +
diff --git a/frontend/src/pages/Recommendations/index.js b/frontend/src/pages/Recommendations/index.js new file mode 100644 index 00000000..dd621473 --- /dev/null +++ b/frontend/src/pages/Recommendations/index.js @@ -0,0 +1,257 @@ +import {React, useState} from "react"; +import { useFormik } from "formik"; +import { useNavigate } from "react-router-dom"; +import { ChakraProvider } from "@chakra-ui/react"; +import ButtonCadastrar from "../../components/Button"; +import * as C from "./styles"; +import axios from "axios"; +import Header from "../../components/Header"; +import Footer from "../../components/Footer"; +import { + Input, + Box, + Center, + FormControl, + FormLabel, + Select, + Text, + Stack, + Flex, + Container, + Alert, + AlertIcon +} from "@chakra-ui/react"; +import { useToast } from "@chakra-ui/react"; +import * as yup from "yup"; + +const Recommendations = () => { + const navigate = useNavigate(); + const toast = useToast(); + + const [showAlert, setShowAlert] = useState(false); + + const formik = useFormik({ + initialValues: { + nomeEletiva: "", + descricao: "", + serie: "", + professor: "", + vagas: "", + horario: "", + }, + validationSchema: yup.object({ + nomeEletiva: yup + .string() + .required("O nome da eletiva é obrigatório") + .min(3, "O nome da eletiva deve ter pelo menos 3 caracteres") + .max(40, "O nome da eletiva deve ter no máximo 40 caracteres"), + descricao: yup + .string() + .required("A breve descrição é obrigatória") + .max(150, "A breve descrição deve ter no máximo 150 caracteres"), + serie: yup.string().required("A série é obrigatória"), + professor: yup + .string() + .required("O professor responsável é obrigatório") + .matches(/^[A-Za-z\s]+$/, "O nome do professor responsável não pode conter números"), + vagas: yup + .number() + .required("O número de vagas é obrigatório") + .min(15, "O número de vagas deve ser no mínimo 15") + .max(30, "O número de vagas deve ser no máximo 30"), + horario: yup + .number() + .required("O horário da disciplina é obrigatório") + .min(1, "O horário da disciplina deve ser no mínimo o primeiro horário(1)") + .max(5, "O horário da disciplina deve ser no máximo o quinto horário(5)"), + }), + onSubmit: async (values) => { + try { + const data = { + name: values.nomeEletiva, + description: values.descricao, + school_year: parseInt(values.serie), + teacher: values.professor, + vacancies: parseInt(values.vagas), + schedules: parseInt(values.horario), + }; + + const response = await axios.post("http://localhost:3001/elective/createElective", data); + + if (response.status === 201) { + toast({ + title: "Eletiva cadastrada.", + description: "Eletiva cadastrada com sucesso!", + status: "success", + duration: 2800, + isClosable: true, + position: "top", + }); + + // Sucesso, redirecionar ou realizar outras ações necessárias + + setShowAlert(true); + setTimeout(() => { + navigate("/home"); + }, 1000); + + } else { + // Exibir mensagem de erro + toast({ + title: "Erro ao cadastrar eletiva.", + description: response.data.message || "Erro desconhecido.", + status: "error", + duration: 2800, + isClosable: true, + position: "top", + }); + } + } catch (error) { + if(error.response.status === 401){ + toast({ + title: "Erro ao cadastrar eletiva.", + description: "Essa eletiva já existe!", + status: "error", + duration: 2800, + isClosable: true, + position: "top", + }); + } else { + toast({ + title: "Erro ao cadastrar eletiva.", + description: "Tente novamente mais tarde.", + status: "error", + duration: 2800, + isClosable: true, + position: "top", + }) + + console.log(error) + } + } + }, + }); + + + return ( + + + +
+ + + + +
+ + + CADASTRO DE ELETIVAS + +
+ Nome da eletiva + + {formik.touched.nomeEletiva && formik.errors.nomeEletiva && ( + + {formik.errors.nomeEletiva} + + )} + + Descrição da eletiva + + {formik.touched.descricao && formik.errors.descricao && ( + + {formik.errors.descricao} + + )} + + Série + + {formik.touched.serie && formik.errors.serie && ( + + {formik.errors.serie} + + )} + + Professor Responsável + + {formik.touched.professor && formik.errors.professor && ( + + {formik.errors.professor} + + )} + + + Número de vagas + + {formik.touched.vagas && formik.errors.vagas && ( + + {formik.errors.vagas} + + )} + + Horário da aula + + {formik.touched.horario && formik.errors.horario && ( + + {formik.errors.horario} + + )} + +
+ +
+ + + +
+
+ +
+
+
+
+ + + ); +}; + +export default Recommendations; diff --git a/frontend/src/pages/Recommendations/styles.js b/frontend/src/pages/Recommendations/styles.js new file mode 100644 index 00000000..e69de29b diff --git a/frontend/src/routes/index.js b/frontend/src/routes/index.js index c9d2bad8..4ba02a4c 100644 --- a/frontend/src/routes/index.js +++ b/frontend/src/routes/index.js @@ -8,6 +8,7 @@ import ExclusionTrilhas from "../pages/ExclusionTrilhas"; import ExclusionEletivas from "../pages/ExclusionEletivas" import CreateEletivas from "../pages/CreateEletivas"; import CreateTrilhas from "../pages/CreateTrilhas"; +import Recommendations from "../pages/Recommendations"; const Private = ({ Item }) => { const { signed } = useAuth(); @@ -26,7 +27,7 @@ const RoutesApp = () => { } /> } /> } /> - } /> + } /> From cabd557dbb660c4eba165e84705d98bc15a0e9d1 Mon Sep 17 00:00:00 2001 From: Algusto-RC Date: Mon, 11 Dec 2023 08:53:02 -0300 Subject: [PATCH 2/2] Melhorioas na tela de importar dados Co-authored-by: yaskisoba --- frontend/src/pages/Home/index.js | 2 +- frontend/src/pages/Recommendations/index.js | 384 +++++++------------ frontend/src/pages/Recommendations/styles.js | 68 ++++ frontend/src/pages/SendStudents/index.js | 64 +++- frontend/src/routes/index.js | 10 +- frontend/src/styles/global.js | 2 +- 6 files changed, 276 insertions(+), 254 deletions(-) diff --git a/frontend/src/pages/Home/index.js b/frontend/src/pages/Home/index.js index f8b683e7..880825d4 100644 --- a/frontend/src/pages/Home/index.js +++ b/frontend/src/pages/Home/index.js @@ -26,7 +26,7 @@ const Home = () => { Excluir eletiva
diff --git a/frontend/src/pages/Recommendations/index.js b/frontend/src/pages/Recommendations/index.js index dd621473..87980007 100644 --- a/frontend/src/pages/Recommendations/index.js +++ b/frontend/src/pages/Recommendations/index.js @@ -1,256 +1,170 @@ -import {React, useState} from "react"; -import { useFormik } from "formik"; -import { useNavigate } from "react-router-dom"; -import { ChakraProvider } from "@chakra-ui/react"; -import ButtonCadastrar from "../../components/Button"; -import * as C from "./styles"; -import axios from "axios"; -import Header from "../../components/Header"; -import Footer from "../../components/Footer"; +import React, { useState, useEffect } from 'react'; +import axios from 'axios'; +import { ChakraProvider, useDisclosure } from '@chakra-ui/react' +import Header from "../../components/Header/index.js"; +import Footer from "../../components/Footer/index.js"; + import { - Input, Box, - Center, - FormControl, - FormLabel, - Select, - Text, - Stack, Flex, + Heading, + Table, + Thead, + Tbody, + Tfoot, + Tr, + Th, + Td, + Checkbox, + TableContainer, + Button, + AlertDialog, + AlertDialogOverlay, + AlertDialogContent, + AlertDialogHeader, + AlertDialogBody, + AlertDialogFooter, Container, Alert, AlertIcon -} from "@chakra-ui/react"; -import { useToast } from "@chakra-ui/react"; -import * as yup from "yup"; +} from "@chakra-ui/react" +; const Recommendations = () => { - const navigate = useNavigate(); - const toast = useToast(); + const [trilhas, setTrilhas] = useState([]); + const [trilhasSelecionadas, setTrilhasSelecionadas] = useState([]); + + const { isOpen, onOpen, onClose } = useDisclosure() + const cancelRef = React.useRef() const [showAlert, setShowAlert] = useState(false); - - const formik = useFormik({ - initialValues: { - nomeEletiva: "", - descricao: "", - serie: "", - professor: "", - vagas: "", - horario: "", - }, - validationSchema: yup.object({ - nomeEletiva: yup - .string() - .required("O nome da eletiva é obrigatório") - .min(3, "O nome da eletiva deve ter pelo menos 3 caracteres") - .max(40, "O nome da eletiva deve ter no máximo 40 caracteres"), - descricao: yup - .string() - .required("A breve descrição é obrigatória") - .max(150, "A breve descrição deve ter no máximo 150 caracteres"), - serie: yup.string().required("A série é obrigatória"), - professor: yup - .string() - .required("O professor responsável é obrigatório") - .matches(/^[A-Za-z\s]+$/, "O nome do professor responsável não pode conter números"), - vagas: yup - .number() - .required("O número de vagas é obrigatório") - .min(15, "O número de vagas deve ser no mínimo 15") - .max(30, "O número de vagas deve ser no máximo 30"), - horario: yup - .number() - .required("O horário da disciplina é obrigatório") - .min(1, "O horário da disciplina deve ser no mínimo o primeiro horário(1)") - .max(5, "O horário da disciplina deve ser no máximo o quinto horário(5)"), - }), - onSubmit: async (values) => { + // Carregar trilhas do backend ao carregar o componente + useEffect(() => { + async function fetchTrilhas() { try { - const data = { - name: values.nomeEletiva, - description: values.descricao, - school_year: parseInt(values.serie), - teacher: values.professor, - vacancies: parseInt(values.vagas), - schedules: parseInt(values.horario), - }; - - const response = await axios.post("http://localhost:3001/elective/createElective", data); - - if (response.status === 201) { - toast({ - title: "Eletiva cadastrada.", - description: "Eletiva cadastrada com sucesso!", - status: "success", - duration: 2800, - isClosable: true, - position: "top", - }); - - // Sucesso, redirecionar ou realizar outras ações necessárias - - setShowAlert(true); - setTimeout(() => { - navigate("/home"); - }, 1000); - - } else { - // Exibir mensagem de erro - toast({ - title: "Erro ao cadastrar eletiva.", - description: response.data.message || "Erro desconhecido.", - status: "error", - duration: 2800, - isClosable: true, - position: "top", - }); - } + const response = await axios.get('http://localhost:3001/learningpath/learningpath'); // Endpoint para buscar trilhas + setTrilhas(response.data); // Define as trilhas na state 'trilhas' } catch (error) { - if(error.response.status === 401){ - toast({ - title: "Erro ao cadastrar eletiva.", - description: "Essa eletiva já existe!", - status: "error", - duration: 2800, - isClosable: true, - position: "top", - }); - } else { - toast({ - title: "Erro ao cadastrar eletiva.", - description: "Tente novamente mais tarde.", - status: "error", - duration: 2800, - isClosable: true, - position: "top", - }) - - console.log(error) - } + console.error('Erro ao buscar trilhas:', error); } - }, - }); - + } + fetchTrilhas(); + }, []); + + // Função para marcar/desmarcar trilha selecionada + const handleCheckboxChange = (id) => { + const isSelected = trilhasSelecionadas.includes(id); + + if (isSelected) { + // Se já estiver selecionado, remova da lista de selecionados + setTrilhasSelecionadas(trilhasSelecionadas.filter((eleId) => eleId !== id)); + } else { + // Se não estiver selecionado, adicione à lista de selecionados + setTrilhasSelecionadas([...trilhasSelecionadas, id]); + } + + console.log(trilhasSelecionadas) + }; + + + // Função para excluir trilhas selecionadas + const handleExcluirClick = async () => { + try { + // Enviar uma solicitação para excluir as eletivas selecionadas + trilhasSelecionadas.map(async (eletiva) => { + await axios.delete('http://localhost:3001/learningpath/deleteLearningPaths', { + data: { id: eletiva }, + }); + }) - return ( - - - -
- - - - -
- - - CADASTRO DE ELETIVAS - -
- Nome da eletiva - - {formik.touched.nomeEletiva && formik.errors.nomeEletiva && ( - - {formik.errors.nomeEletiva} - - )} - - Descrição da eletiva - - {formik.touched.descricao && formik.errors.descricao && ( - - {formik.errors.descricao} - - )} + // Atualizar a lista de eletivas após a exclusão + const response = await axios.get('http://localhost:3001/learningpath/learningpath'); + setTrilhas(response.data); + + // Limpar a lista de eletivas selecionadas + setTrilhasSelecionadas([]); + onClose(); + setTimeout(() => { + window.location.reload();; + }, 2000); + setShowAlert(true); + } catch (error) { + console.error('Erro ao excluir trilhas:', error); + } + }; - Série - - {formik.touched.serie && formik.errors.serie && ( - - {formik.errors.serie} - - )} - Professor Responsável - - {formik.touched.professor && formik.errors.professor && ( - - {formik.errors.professor} - - )} - - Número de vagas - - {formik.touched.vagas && formik.errors.vagas && ( - - {formik.errors.vagas} - - )} - - Horário da aula - - {formik.touched.horario && formik.errors.horario && ( - - {formik.errors.horario} - - )} - -
+ return ( + + +
+ + + + Exclusão de Trilhas + + + + + + + + + + + + {trilhas.map((linha) => ( + + + + + + ))} + +
Nome da eletivaAno letivo
{linha.name}{linha.school_year} handleCheckboxChange(linha.id)}>
+
+ + + + + + + Excluir Trilhas + + + + Você tem certeza? Essa ação não pode ser desfeita. + + + + + + + + + + +
+ {showAlert && ( + + + Trilhas excluídas com sucesso! + + )} +
+
+ + -
- - - -
-
- -
-
-
-
- - ); }; diff --git a/frontend/src/pages/Recommendations/styles.js b/frontend/src/pages/Recommendations/styles.js index e69de29b..4ce76ca2 100644 --- a/frontend/src/pages/Recommendations/styles.js +++ b/frontend/src/pages/Recommendations/styles.js @@ -0,0 +1,68 @@ +import styled from "styled-components"; + +export const Container = styled.div` + display: flex; + align-items: center; + //justify-content: center; + + flex-direction: column; + gap: 10px; + height: 100vh; + background-color: 'white'; +`; + +export const Content = styled.div` + gap: 15px; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + width: 100%; + height: 100%; + box-shadow: 0 1px 2px #0003; + background-color: #f4f4f2; + max-width: 650px; + max-height: 85%; + margin-top: 2%; + border-radius: 60px; +`; + +export const Label = styled.label` + font-size: 18px; + font-weight: 600; + color: #676767; +`; + +export const LabelSignup = styled.label` + font-size: 16px; + color: #676767; +`; + +export const labelError = styled.label` + font-size: 14px; + color: red; +`; + +export const Strong = styled.strong` + cursor: pointer; + + a { + text-decoration: none; + color: #676767; + } +`; +export const titulo = styled.div` + font-size: 150%; + font-weight: 600; + color: #243A69; + margin-left: 20px; + margin-top: 20px; + align: center; +`; +export const box = styled.div` +`; + +export const texto = styled.label` + color: #243A69; + +`; diff --git a/frontend/src/pages/SendStudents/index.js b/frontend/src/pages/SendStudents/index.js index f982d9f6..81dd1782 100644 --- a/frontend/src/pages/SendStudents/index.js +++ b/frontend/src/pages/SendStudents/index.js @@ -1,10 +1,9 @@ import React, { useState } from 'react'; import axios from 'axios'; -import { Container, Flex} from "@chakra-ui/react"; +import { Container, Flex, Box, Text, Button, Input, Center } from "@chakra-ui/react"; import Header from "../../components/Header/index.js"; import Footer from "../../components/Footer/index.js"; import { ChakraProvider } from "@chakra-ui/react"; - import { Link } from "react-router-dom"; const SendStudent = () => { @@ -29,19 +28,60 @@ const SendStudent = () => { } return ( - -
- - - - -