diff --git a/README.md b/README.md index d6191dd92..1ad9fc2c8 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,23 @@ -![StackUp Banner]([https://tinkerhub.frappe.cloud/files/stackup%20banner.jpeg]) -# Project Name -Long Description about project. This project do that. This project is awesome... +![stackup banner](https://github.com/uncode11/sample/assets/127462092/ca27e233-ff3b-4830-add4-57658152f341) +#Quizzy +Simple Quiz App where User can Attend Quiz and Admin can create Quiz.A simplw Project... ## Team members -1. Name [Embed personal github URL] -2. Name [Embed perosnal github URL] +1. Unais [[github URL](https://github.com/uncode11)] +2. Aswathi [[github URL](https://github.com/Aswathivalsan)] +3. Jaseem [[github URL](https://github.com/JASEEMCTR)] +4. Shahana shani [[github URL](https://github.com/Shahanashani)] ## Team Id -Team id here +Dino ## Link to product walkthrough [link to video] ## How it Works ? 1. Explaining the working of project 2. Embed video of project demo ## Libraries used -Library Name - Version +React - 18.2 +Node -9+ +Mongodb-7 + +Express-latest ## How to configure Instructions for setting up project ## How to Run diff --git a/resources/Backend/Readmeb.md b/resources/Backend/Readmeb.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/resources/Backend/Readmeb.md @@ -0,0 +1 @@ + diff --git a/resources/Backend/config/config.md b/resources/Backend/config/config.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/resources/Backend/config/config.md @@ -0,0 +1 @@ + diff --git a/resources/Backend/controllers/con.md b/resources/Backend/controllers/con.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/resources/Backend/controllers/con.md @@ -0,0 +1 @@ + diff --git a/resources/Backend/middleware/mid.m b/resources/Backend/middleware/mid.m new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/resources/Backend/middleware/mid.m @@ -0,0 +1 @@ + diff --git a/resources/Backend/models/models.md b/resources/Backend/models/models.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/resources/Backend/models/models.md @@ -0,0 +1 @@ + diff --git a/resources/Backend/routes/routes.md b/resources/Backend/routes/routes.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/resources/Backend/routes/routes.md @@ -0,0 +1 @@ + diff --git a/resources/Frontend/public/favicon.png b/resources/Frontend/public/favicon.png new file mode 100644 index 000000000..5003944c3 Binary files /dev/null and b/resources/Frontend/public/favicon.png differ diff --git a/resources/Frontend/public/index.html b/resources/Frontend/public/index.html new file mode 100644 index 000000000..4e07108ea --- /dev/null +++ b/resources/Frontend/public/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + Quizzy + + + +
+ + diff --git a/resources/Frontend/readmef.md b/resources/Frontend/readmef.md new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/resources/Frontend/readmef.md @@ -0,0 +1 @@ + diff --git a/resources/Frontend/src/App.css b/resources/Frontend/src/App.css new file mode 100644 index 000000000..c4f4da9ce --- /dev/null +++ b/resources/Frontend/src/App.css @@ -0,0 +1,13 @@ + +.App { + min-height: 100vh; + display: flex; + background-image: url("./background.jpg"); + background-size: cover; + background-position: center; + font-family: Arial, Helvetica, sans-serif; +} + +::-webkit-scrollbar { + display: none; +} diff --git a/resources/Frontend/src/App.js b/resources/Frontend/src/App.js new file mode 100644 index 000000000..66612d1ff --- /dev/null +++ b/resources/Frontend/src/App.js @@ -0,0 +1,28 @@ +import "./App.css"; +import { Route, Routes } from "react-router-dom"; +import { ChakraProvider } from "@chakra-ui/react"; +import Homepage from "./pages/Homepage"; +import Mainpage from "./pages/Mainpage"; +import TestPage from "./components/others/testpage"; +import ProfilePage from "./components/others/profile"; +import LeaderboardPage from "./components/others/leaderboard"; +import UploadQuestionPage from "./components/others/upload"; + +function App() { + return ( + + + + } exact /> + } /> + } exact /> + } exact /> + } exact /> + } exact /> + + + + ); +} + +export default App; diff --git a/resources/Frontend/src/App.test.js b/resources/Frontend/src/App.test.js new file mode 100644 index 000000000..1f03afeec --- /dev/null +++ b/resources/Frontend/src/App.test.js @@ -0,0 +1,8 @@ +import { render, screen } from '@testing-library/react'; +import App from './App'; + +test('renders learn react link', () => { + render(); + const linkElement = screen.getByText(/learn react/i); + expect(linkElement).toBeInTheDocument(); +}); diff --git a/resources/Frontend/src/background.jpg b/resources/Frontend/src/background.jpg new file mode 100644 index 000000000..b8d31ffd9 Binary files /dev/null and b/resources/Frontend/src/background.jpg differ diff --git a/resources/Frontend/src/components/authentication/Login.js b/resources/Frontend/src/components/authentication/Login.js new file mode 100644 index 000000000..ce5988bba --- /dev/null +++ b/resources/Frontend/src/components/authentication/Login.js @@ -0,0 +1,120 @@ +import React, { useState } from "react"; +import { FormControl, FormLabel } from "@chakra-ui/form-control"; +import { Input, InputGroup, InputRightElement } from "@chakra-ui/input"; +import { VStack } from "@chakra-ui/layout"; +import { Button } from "@chakra-ui/react"; +import axios from "axios"; +import { useToast } from "@chakra-ui/react"; +import { useNavigate } from "react-router-dom"; + +const Login = () => { + const [show, setShow] = useState(false); + const [email, setEmail] = useState(); + const [password, setPassword] = useState(); + const [loading, setLoading] = useState(false); + + const toast = useToast(); + const navigate = useNavigate(); + + const handleClick = () => setShow(!show); + + const submitHandler = async () => { + setLoading(true); + + if (!email || !password) { + toast({ + title: "Please fill all the fields", + status: "warning", + duration: 5000, + isClosable: true, + position: "bottom", + }); + setLoading(false); + return; + } + + try { + const config = { + headers: { + "Content-type": "application/json", + }, + }; + const { data } = await axios.post( + "http://localhost:5000/user/login", + { email, password }, + config + ); + + toast({ + title: "Login Successful", + status: "success", + duration: 5000, + isClosable: true, + position: "top", + }); + + localStorage.setItem("userInfo", JSON.stringify(data)); + //here we are storing the userInfo to the localstorage to use this in future + + setLoading(false); + navigate("/main", { replace: "true" }); + window.location.reload(); + } catch (error) { + toast({ + title: "Error Occurred", + description: error.response.data.message, + status: "error", + duration: 5000, + isClosable: true, + position: "bottom", + }); + setLoading(false); + } + }; + + return ( + + + Email + { + setEmail(e.target.value); + }} + autoComplete="off" + /> + + + Password + + { + setPassword(e.target.value); + }} + autoComplete="off" + /> + + + + + + + + ); +}; + +export default Login; diff --git a/resources/Frontend/src/components/authentication/Signup.js b/resources/Frontend/src/components/authentication/Signup.js new file mode 100644 index 000000000..4cdd0b08b --- /dev/null +++ b/resources/Frontend/src/components/authentication/Signup.js @@ -0,0 +1,175 @@ +import React, { useState } from "react"; +import { FormControl, FormLabel } from "@chakra-ui/form-control"; +import { Input, InputGroup, InputRightElement } from "@chakra-ui/input"; +import { VStack } from "@chakra-ui/layout"; +import { Button, useToast, Select } from "@chakra-ui/react"; +import axios from "axios"; +import { useNavigate } from "react-router-dom"; + +const Signup = () => { + const [show, setShow] = useState(false); + const [name, setName] = useState(); + const [email, setEmail] = useState(); + const [confirmpassword, setConfirmpassword] = useState(); + const [password, setPassword] = useState(); + const [isTeacher, setIsTeacher] = useState(false); + const [loading, setLoading] = useState(); + const toast = useToast(); + const navigate = useNavigate(); + + const handleClick = () => setShow(!show); + + const submitHandler = async () => { + setLoading(true); + if (!name || !email || !password || !confirmpassword) { + toast({ + title: "Please fill all the fields", + status: "warning", + duration: 5000, + isClosable: true, + position: "bottom", + }); + setLoading(false); + return; + } + + if (password !== confirmpassword) { + toast({ + title: "Passwords do not match", + status: "warning", + duration: 5000, + isClosable: true, + position: "bottom", + }); + setLoading(false); + return; + } + + try { + const config = { + headers: { + "Content-type": "application/json", + }, + }; + + const { data } = await axios.post( + "http://localhost:5000/user", + { name, email, isTeacher, password }, + config + ); + + toast({ + title: "Registration Successful", + status: "success", + duration: 5000, + isClosable: true, + position: "bottom", + }); + + localStorage.setItem("userInfo", JSON.stringify(data)); + + setLoading(false); + navigate("/main", { replace: true }); + window.location.reload(); + } catch (error) { + toast({ + title: "Error Occurred", + description: error.response.data.message, + status: "error", + duration: 5000, + isClosable: true, + position: "bottom", + }); + setLoading(false); + } + }; + + return ( + + + Name + { + setName(e.target.value); + }} + autoComplete="off" + /> + + + Email + { + setEmail(e.target.value); + }} + autoComplete="off" + /> + + + + Are you a Admin ? (Only Admins/Coordinator can upload questions) + + + + + Password + + { + setPassword(e.target.value); + }} + autoComplete="off" + /> + + + + + + + Confirm Password + + { + setConfirmpassword(e.target.value); + }} + autoComplete="off" + /> + + + + + + + + ); +}; + +export default Signup; diff --git a/resources/Frontend/src/components/others/leaderboard.js b/resources/Frontend/src/components/others/leaderboard.js new file mode 100644 index 000000000..419b822ca --- /dev/null +++ b/resources/Frontend/src/components/others/leaderboard.js @@ -0,0 +1,152 @@ +import React, { useState, useEffect } from "react"; +import { + Box, + Text, + Table, + Thead, + Tbody, + Tr, + Th, + Td, + Select, +} from "@chakra-ui/react"; +import axios from "axios"; +import Navbar from "./navbar"; + +const LeaderboardPage = () => { + const [leaderboardData, setLeaderboardData] = useState([]); + const [lang_id, setLangId] = useState(""); + const userInfo = JSON.parse(localStorage.getItem("userInfo")); + const [topics, settopics] = useState([]); + const [shouldShow, setShouldShow] = useState(false); + + const fetchtopics = async () => { + try { + const config = { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${userInfo.token}`, + }, + }; + const response = await axios.get( + `http://localhost:5000/quiz/topics`, + config + ); + settopics(response.data); + } catch (error) { + console.error("Error fetching topic data:", error); + } + }; + + useEffect(() => { + fetchtopics(); + }, ); + + useEffect(() => { + const getLeaderboard = async (selectedLangId) => { + const config = { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${userInfo.token}`, + }, + }; + try { + const response = await axios.get( + `http://localhost:5000/performance/leaderboard?lang_id=${selectedLangId}`, + config + ); + setLeaderboardData(response.data); + } catch (err) { + console.log( + "Error occurred in fetching leaderboard data from the database " + err + ); + } + }; + + getLeaderboard(lang_id); + if (lang_id !== "") { + setShouldShow(true); + } else { + setShouldShow(false); + } + // eslint-disable-next-line + }, [lang_id]); + + return ( + <> + + + {shouldShow ? ( + + Leaderboard for {lang_id.toUpperCase()} + + ) : ( + <> + + Leaderboard + + + )} + + + + + + + + + + + {leaderboardData.length > 0 ? ( + + {leaderboardData.map((entry, index) => ( + + + + + + + ))} + + ) : ( + + + + + + )} +
RankNameEmailScore
{index + 1}{entry.uid.name}{entry.uid.email}{entry.score_percent}
No data available
+
+ + ); +}; + +export default LeaderboardPage; diff --git a/resources/Frontend/src/components/others/navbar.js b/resources/Frontend/src/components/others/navbar.js new file mode 100644 index 000000000..06fda31c6 --- /dev/null +++ b/resources/Frontend/src/components/others/navbar.js @@ -0,0 +1,110 @@ +import React from "react"; +import { + Box, + Flex, + Spacer, + Link, + Text, + Avatar, + IconButton, + Drawer, + DrawerOverlay, + DrawerContent, + DrawerHeader, + DrawerBody, + useDisclosure, +} from "@chakra-ui/react"; +import { HamburgerIcon, CloseIcon } from "@chakra-ui/icons"; + +const Navbar = () => { + const navbarStyle = { + position: "fixed", + top: 0, + left: 0, + width: "100%", + zIndex: 1000, + }; + const linkStyle = { + textDecoration: "none", + }; + const user = JSON.parse(localStorage.getItem("userInfo")); + const { isOpen, onOpen, onClose } = useDisclosure(); + + return ( + + } + aria-label="Open Menu" + display={{ base: "block", md: "none" }} + onClick={onOpen} + /> + + + + + {" "} + } + size="sm" + aria-label="Close" + onClick={onClose} + position="absolute" + top={2} + right={2} + />{" "} + Menu + + + + + Give Test + + + + + + Upload Question + + + + + Leaderboard + + + + + + Profile + + + + + + + + + Give Test + + + + + Leaderboard + + + + + Upload Question + + + + + + + Profile + + + + ); +}; + +export default Navbar; diff --git a/resources/Frontend/src/components/others/profile.js b/resources/Frontend/src/components/others/profile.js new file mode 100644 index 000000000..969cdcce7 --- /dev/null +++ b/resources/Frontend/src/components/others/profile.js @@ -0,0 +1,135 @@ +import React, { useEffect, useState } from "react"; +import { Box, Text, Button, Container, useToast } from "@chakra-ui/react"; +import Navbar from "./navbar"; +import { useNavigate } from "react-router-dom"; +import axios from "axios"; + +const ProfilePage = () => { + const navigate = useNavigate(); + const userInfo = JSON.parse(localStorage.getItem("userInfo")); + const [proficiencyArr, setProficiencyArr] = useState([]); + const toast = useToast(); + + useEffect(() => { + const getProficiency = async () => { + const config = { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${userInfo.token}`, + }, + }; + try { + const response = await axios.get( + `http://localhost:5000/performance/proficiency?uid=${userInfo._id}`, + config + ); + setProficiencyArr(response.data); + } catch (error) { + console.error("Error fetching proficiency data: ", error); + } + }; + + getProficiency(); + }, [userInfo.token, userInfo._id]); + + const user = { + username: userInfo.name, + email: userInfo.email, + }; + + const handleLogout = () => { + localStorage.removeItem("userInfo"); + navigate("/", { replace: "true" }); + }; + + const handleReset = async () => { + const config = { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${userInfo.token}`, + }, + }; + try { + const isResetDone = await axios.get( + `http://localhost:5000/performance/deletehistory?uid=${userInfo._id}`, + config + ); + if (isResetDone) { + toast({ + title: "History Reset", + description: + "Your performance history has been deleted successfully. Restart your learning journey freshly.", + status: "success", + duration: 5000, + isClosable: true, + }); + } + } catch (error) { + console.error("Error in resetting history: ", error); + } + }; + + return ( + <> + + + + + Profile + + + Role: {userInfo.isTeacher ? <>Teacher : <>Student} + + Name: {user.username} + Email: {user.email} + + + + + Proficiency List + + {proficiencyArr.length > 0 ? ( + proficiencyArr.map((prof) => ( + + + {prof.topic_id} : {prof.proficiencyLevel} + + + )) + ) : ( + No data available to show + )} + + + + + ); +}; + +export default ProfilePage; diff --git a/resources/Frontend/src/components/others/testpage.js b/resources/Frontend/src/components/others/testpage.js new file mode 100644 index 000000000..57f48e0da --- /dev/null +++ b/resources/Frontend/src/components/others/testpage.js @@ -0,0 +1,285 @@ +import React, { useState, useEffect } from "react"; +import { + Box, + Text, + VStack, + Radio, + RadioGroup, + Button, + Container, + Select, + Modal, + ModalOverlay, + ModalContent, + ModalHeader, + ModalBody, + ModalFooter, + ModalCloseButton, + useDisclosure, + Center, +} from "@chakra-ui/react"; +import axios from "axios"; +import Navbar from "./navbar"; + +const TestPage = () => { + const [questions, setQuestions] = useState([]); + const [category, setCategory] = useState(""); + const [lang_id, setLangId] = useState(""); + const [initialRenderQuestions, setInitialRenderQuestions] = useState(true); + const [initialRenderAnswers, setInitialRenderAnswers] = useState(true); + const userInfo = JSON.parse(localStorage.getItem("userInfo")); + const [topics, settopics] = useState([]); + + const { isOpen, onOpen, onClose } = useDisclosure(); + const [responseDetails, setResponseDetails] = useState({}); + const [shouldShow, setShouldShow] = useState(false); + const [selectedAnswers, setSelectedAnswers] = useState({}); + + const fetchtopics = async () => { + try { + const config = { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${userInfo.token}`, + }, + }; + const response = await axios.get( + `http://localhost:5000/quiz/topics`, + config + ); + settopics(response.data); + } catch (error) { + console.error("Error fetching topic data:", error); + } + }; + + const getQuestions = async (lang_id, category) => { + try { + const config = { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${userInfo.token}`, + }, + }; + const response = await axios.post( + "http://localhost:5000/quiz/questions", + { + topic_id: lang_id, + category: category, + }, + config + ); + if (lang_id && category) { + setQuestions(response.data); + } + } catch (err) { + console.log("Error occurred in fetching questions from the database"); + console.log(err); + } + }; + + useEffect(() => { + fetchtopics(); + }, ); + + useEffect(() => { + // This will prevent the first render + if (initialRenderQuestions) { + setInitialRenderQuestions(false); + return; + } + if (lang_id !== "" && category !== "") { + getQuestions(lang_id, category); + setShouldShow(true); + } else { + setShouldShow(false); + } + // eslint-disable-next-line + }, [lang_id, category]); + + // This part of code will fill "-1" as answer of every mcq questions whenever the questions are set + useEffect(() => { + // This will prevent the first render + if (initialRenderAnswers) { + setInitialRenderAnswers(false); + return; + } + if (questions.length) { + setSelectedAnswers((prevSelectedAnswers) => { + const updatedAnswers = { ...prevSelectedAnswers }; + questions.forEach((question) => { + updatedAnswers[question._id] = "-1"; + }); + return updatedAnswers; + }); + } + // eslint-disable-next-line + }, [questions]); + + const handleOptionSelect = (questionId, selectedOption) => { + setSelectedAnswers({ + ...selectedAnswers, + [questionId]: selectedOption, + }); + }; + const handleSubmit = async () => { + try { + const dataToSend = { + uid: userInfo._id, + pairs: Object.entries(selectedAnswers).map( + ([objectId, givenAnswer]) => ({ + objectId: objectId, + givenAnswer: givenAnswer, + }) + ), + }; + const config = { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${userInfo.token}`, + }, + }; + const response = await axios.post( + "http://localhost:5000/quiz/answers", + dataToSend, + config + ); + setResponseDetails(response.data); + onOpen(); + } catch (error) { + console.error("Error submitting test:", error); + alert("Error submitting test. Please try again."); + } + }; + + return ( + <> + + + + + Quiz Result + + + Total Questions: {responseDetails.totalMarks} + Attempted: {responseDetails.attempted} + Unattempted: {responseDetails.unAttempted} + Correctly Answered: {responseDetails.corrected} + Incorectly Answered: {responseDetails.incorrected} + Total Marks: {responseDetails.totalMarks} + Your Score: {responseDetails.score} + Accuracy: {responseDetails.accuracy}% + Negative Marking Per Each Question: -0.5(50%) + + + + + + + + + Fun Quiz + + + + {shouldShow ? ( + + + Quiz of {lang_id.toUpperCase()} (LEVEL: {category.toUpperCase()}) + +
+ {questions.map((question, ind) => ( + + + {ind + 1}. {question.desc} + + + handleOptionSelect(question._id, value) + } + display="flex" + flexDirection="column" + > + {JSON.parse(question.options).map((option, index) => ( + + {option} + + ))} + + + ))} +
+ +
+
+
+ ) : ( + + Select a topic and the difficulty level for the quiz + + )} +
+ + ); +}; + +export default TestPage; diff --git a/resources/Frontend/src/components/others/upload.js b/resources/Frontend/src/components/others/upload.js new file mode 100644 index 000000000..07f9cf239 --- /dev/null +++ b/resources/Frontend/src/components/others/upload.js @@ -0,0 +1,210 @@ +import { + Box, + Container, + FormControl, + FormLabel, + Input, + Select, + Text, + Divider, + Button, + Center, + useToast, +} from "@chakra-ui/react"; +import React, { useState } from "react"; +import axios from "axios"; +import Navbar from "../others/navbar"; + +function UploadQuestion() { + const [langId, setLangId] = useState(""); + const [category, setCategory] = useState(""); + const [desc, setDesc] = useState(""); + const [option1, setOption1] = useState(""); + const [option2, setOption2] = useState(""); + const [option3, setOption3] = useState(""); + const [option4, setOption4] = useState(""); + const [correctAnswer, setCorrectAnswer] = useState(""); + const userInfo = JSON.parse(localStorage.getItem("userInfo")); + const toast = useToast(); + const handleSubmit = async (event) => { + event.preventDefault(); + const dataToSend = { + uid: userInfo._id, + lang_id: langId, + category: category, + desc: desc, + option1: option1, + option2: option2, + option3: option3, + option4: option4, + correct_answer: correctAnswer, + }; + try { + const config = { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${userInfo.token}`, + }, + }; + const isSent = await axios.post( + "http://localhost:5000/quiz/upload", + dataToSend, + config + ); + if (isSent) { + toast({ + title: "Question Uploaded", + description: "Your question has been successfully uploaded.", + status: "success", + duration: 5000, + isClosable: true, + }); + } + } catch (err) { + console.error(err); + alert("Question uploading failed, please try again."); + } + }; + return ( + <> + + + + Let's Add some quizzes.. + + + +
+ + Topic + { + setLangId(e.target.value); + }} + /> + + + + Question + { + setDesc(e.target.value); + }} + /> + + + + Option 1 + { + setOption1(e.target.value); + }} + /> + + + + Option 2 + { + setOption2(e.target.value); + }} + /> + + + + Option 3 + { + setOption3(e.target.value); + }} + /> + + + + Option 4 + { + setOption4(e.target.value); + }} + /> + + + + Category + + + + + Correct Answer + + +
+ +
+
+
+
+ + ); +} + +export default UploadQuestion; diff --git a/resources/Frontend/src/index.css b/resources/Frontend/src/index.css new file mode 100644 index 000000000..ec2585e8c --- /dev/null +++ b/resources/Frontend/src/index.css @@ -0,0 +1,13 @@ +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/resources/Frontend/src/index.js b/resources/Frontend/src/index.js new file mode 100644 index 000000000..b5ca9041f --- /dev/null +++ b/resources/Frontend/src/index.js @@ -0,0 +1,15 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import "./index.css"; +import App from "./App"; +import { ChakraProvider } from "@chakra-ui/react"; +import { BrowserRouter } from "react-router-dom"; + +const root = ReactDOM.createRoot(document.getElementById("root")); +root.render( + + + + + +); diff --git a/resources/Frontend/src/pages/Homepage.js b/resources/Frontend/src/pages/Homepage.js new file mode 100644 index 000000000..364caf67e --- /dev/null +++ b/resources/Frontend/src/pages/Homepage.js @@ -0,0 +1,112 @@ +import { React, useEffect } from "react"; +import { + Container, + Box, + Text, + Tab, + Tabs, + TabList, + TabPanel, + TabPanels, + Center, + Stack, + Link, +} from "@chakra-ui/react"; +import Login from "../components/authentication/Login"; +import Signup from "../components/authentication/Signup"; +import { useNavigate } from "react-router-dom"; + +const Homepage = () => { + const navigate = useNavigate(); + + useEffect(() => { + const user = JSON.parse(localStorage.getItem("userInfo")); + if (user) { + navigate("/main"); + } + }, [navigate]); + + return ( + + + +
Quizzzy
+
+
+ + + + Login + Sign Up + + + + + + + + + + + + + + + GitHub + + + LinkedIn + + + FaceBook + + Instagram + + + + The team dino + + +
+ ); +}; + +export default Homepage; diff --git a/resources/Frontend/src/pages/Mainpage.js b/resources/Frontend/src/pages/Mainpage.js new file mode 100644 index 000000000..ed0a9b131 --- /dev/null +++ b/resources/Frontend/src/pages/Mainpage.js @@ -0,0 +1,35 @@ +import React from "react"; +import { Box, Heading, Text } from "@chakra-ui/react"; +import Navbar from "../components/others/navbar"; + +const Mainpage = () => { + return ( + <> + + + + Welcome Quizzy ! + + + lets do some fun quizz... + + + + ); +}; + +export default Mainpage; diff --git a/resources/Frontend/src/reportWebVitals.js b/resources/Frontend/src/reportWebVitals.js new file mode 100644 index 000000000..5253d3ad9 --- /dev/null +++ b/resources/Frontend/src/reportWebVitals.js @@ -0,0 +1,13 @@ +const reportWebVitals = onPerfEntry => { + if (onPerfEntry && onPerfEntry instanceof Function) { + import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { + getCLS(onPerfEntry); + getFID(onPerfEntry); + getFCP(onPerfEntry); + getLCP(onPerfEntry); + getTTFB(onPerfEntry); + }); + } +}; + +export default reportWebVitals; diff --git a/resources/Frontend/src/setupTests.js b/resources/Frontend/src/setupTests.js new file mode 100644 index 000000000..8f2609b7b --- /dev/null +++ b/resources/Frontend/src/setupTests.js @@ -0,0 +1,5 @@ +// jest-dom adds custom jest matchers for asserting on DOM nodes. +// allows you to do things like: +// expect(element).toHaveTextContent(/react/i) +// learn more: https://github.com/testing-library/jest-dom +import '@testing-library/jest-dom';