diff --git a/src/atoms/authModalAtom.ts b/src/atoms/authModalAtom.ts index 0812fa2..2007809 100644 --- a/src/atoms/authModalAtom.ts +++ b/src/atoms/authModalAtom.ts @@ -1,16 +1,36 @@ -import { atom } from "recoil" +import { atom } from "recoil"; +/** + * Interface which describes the state of the authentication modal. + * The modal has 2 properties: + * + * - `open` (boolean): whether it is open or not + * - `view` ("login" | "signup" | "resetPassword"): which specific view of the modal should be displayed + */ export interface AuthModalState { - open: boolean; - view: "login" | "signup" | "resetPassword"; -}; + open: boolean; + view: "login" | "signup" | "resetPassword"; +} +/** + * Describes the default state of the authentication modal. + * By default, the modal is closed and + * if no state is specified, it will open in the log in view. + */ const defaultModalState: AuthModalState = { - open: false, - view: "login", + open: false, + view: "login", }; +/** + * Atom which describes the state of the authentication modal. + * The atom has the state options defined by `AuthModalState` and + * uses the default state defined in `AuthModalState`. + * @requires AuthModalState + * @requires defaultModalState + * @see https://recoiljs.org/docs/basic-tutorial/atoms/ + */ export const authModalState = atom({ - key: "authModalState", - default: defaultModalState, -}); \ No newline at end of file + key: "authModalState", // unique identifier for the atom + default: defaultModalState, +}); diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx index bbf2946..d022878 100644 --- a/src/components/Layout/Layout.tsx +++ b/src/components/Layout/Layout.tsx @@ -1,6 +1,16 @@ import React from 'react'; import Navbar from '../Navbar/Navbar'; +/** + * Provides a common layout for the entire application. + * Each page in the application will follow this standard layout. + * Each page will display the navbar component. + * Each page will be different hence different children components can be passed. + * @param param0 children components for different pages + * @returns Navbar and children + * @see https://nextjs.org/docs/basic-features/layouts + * @requires src/components/Navbar/Navbar.tsx - navbar at the top of every page + */ const Layout:React.FC = ({ children }) => { return ( diff --git a/src/components/Modal/Auth/AuthInputs.tsx b/src/components/Modal/Auth/AuthInputs.tsx index 382f64c..747e143 100644 --- a/src/components/Modal/Auth/AuthInputs.tsx +++ b/src/components/Modal/Auth/AuthInputs.tsx @@ -9,6 +9,14 @@ type AuthInputsProps = { }; +/** + * Checks what the current view of the authentication modal state is. + * If the state is `login`, the the modal will display the log in view. + * If the state is `signup`, the modal will display the sign up view. + * @returns log in or sign up components views + * @requires ./Login - log in view + * @requires ./Signup - sign up view + */ const AuthInputs:React.FC = () => { const modalState = useRecoilValue(authModalState); diff --git a/src/components/Modal/Auth/AuthModal.tsx b/src/components/Modal/Auth/AuthModal.tsx index e9e5b46..b809552 100644 --- a/src/components/Modal/Auth/AuthModal.tsx +++ b/src/components/Modal/Auth/AuthModal.tsx @@ -18,14 +18,50 @@ import AuthInputs from "./AuthInputs"; import OAuthButtons from "./OAuthButtons"; import ResetPassword from "./ResetPassword"; +/** + * Displays an authentication modal while `open` is `true`. + * If the `open` is `false`, then the modal is closed. + * The modal has 3 different views as described by `authModalAtom`: + * + * - `login`: displays the log in view + * - `signup`: displays the signup view + * - `resetPassword`: displays the reset password view + * + * If the user is trying to log in or sign up, + * Third party authentication providers are displayed and + * sign up or log in forms are displayed. + * If the user is resetting the password, + * only the reset password elements are shown and + * Third party authentication providers and log in or sign up forms are not displayed. + * @returns authentication modal + * @requires ./AuthInputs - display correct form depending on `login` or `signup` state + * @requires ./OAuthButtons - third party authentication providers such as Google or GitHub + * @requires ./ResetPassword - display reset password view + * @see https://chakra-ui.com/docs/components/modal/usage + */ const AuthModal: React.FC = () => { const [modalState, setModalState] = useRecoilState(authModalState); + /** + * Keeps track of whether a user is authenticated via Firebase. + * It returns the `user` details, if it fails then `null` is stored. + * While communicating with Firebase, `loading` (boolean) is set to `true` and + * once the communication is complete it is set to `false`. + * `error` is null until an error takes place while communicating with Firebase. + */ const [user, loading, error] = useAuthState(auth); + /** + * If a user is authenticated, the modal will automatically close. + * This is used after signing up or logging in as once the user is authenticated, + * the modal does not need to be open. + */ useEffect(() => { if (user) handleClose(); }, [user]); + /** + * Closes the authentication modal by setting its state to `open` state to false. + */ const handleClose = () => { setModalState((prev) => ({ ...prev, @@ -37,6 +73,7 @@ const AuthModal: React.FC = () => { + {/* Dynamically display header depending on the authentication state */} {modalState.view === "login" && "Login"} {modalState.view === "signup" && "Sign Up"} diff --git a/src/components/Modal/Auth/Login.tsx b/src/components/Modal/Auth/Login.tsx index df97ba9..5c3cd74 100644 --- a/src/components/Modal/Auth/Login.tsx +++ b/src/components/Modal/Auth/Login.tsx @@ -1,13 +1,25 @@ -import React, { useState } from "react"; import { Button, Flex, Input, Text } from "@chakra-ui/react"; -import { useSetRecoilState } from "recoil"; -import { authModalState, AuthModalState } from "../../../atoms/authModalAtom"; +import React, { useState } from "react"; import { useSignInWithEmailAndPassword } from "react-firebase-hooks/auth"; +import { useSetRecoilState } from "recoil"; +import { authModalState } from "../../../atoms/authModalAtom"; import { auth } from "../../../firebase/clientApp"; import { FIREBASE_ERRORS } from "../../../firebase/errors"; type LoginProps = {}; +/** + * Allows the user to input the log in credentials (email and password) to log into the site. + * Contains 2 input fields, `Email` and `Password` and a log in button. + * + * If the credentials are correct, the user is signed in. + * If the credentials are incorrect, error messages are displayed. + * + * Buttons for resetting the password and signing up are present. + * Clicking these buttons would change the modal to the appropriate view. + * @returns Log in components view for modal. + * @see https://github.com/CSFrequency/react-firebase-hooks/tree/master/auth + */ const Login: React.FC = () => { const setAuthModalState = useSetRecoilState(authModalState); // Set global state const [loginForm, setLoginForm] = useState({ @@ -32,8 +44,8 @@ const Login: React.FC = () => { /** * Function to execute when the form is changed (when email and password are typed). - * Multiple inputs use the same onChange function. - * @param event(React.ChangeEvent) - the event that is triggered when the form is changed + * Multiple inputs use the same `onChange` function. + * @param event (React.ChangeEvent) - the event that is triggered when the form is changed */ const onChange = (event: React.ChangeEvent) => { // Update form state diff --git a/src/components/Modal/Auth/OAuthButtons.tsx b/src/components/Modal/Auth/OAuthButtons.tsx index ceb6baa..d97ac1d 100644 --- a/src/components/Modal/Auth/OAuthButtons.tsx +++ b/src/components/Modal/Auth/OAuthButtons.tsx @@ -7,6 +7,15 @@ import { import { auth } from "../../../firebase/clientApp"; import { FIREBASE_ERRORS } from "../../../firebase/errors"; +/** + * Displays third party authentication providers, in this case Google and GitHub. + * When a provider is clicked: + * - A new account is created if the user does not already exist + * - Signed in if it is an existing user + * - An error is displayed if the user already exist with a different provider. + * @returns + * @see https://github.com/CSFrequency/react-firebase-hooks/tree/master/auth + */ const OAuthButtons: React.FC = ({}) => { const [signInWithGoogle, userGoogle, loadingGoogle, errorGoogle] = useSignInWithGoogle(auth); diff --git a/src/components/Modal/Auth/ResetPassword.tsx b/src/components/Modal/Auth/ResetPassword.tsx index 23eb747..856c746 100644 --- a/src/components/Modal/Auth/ResetPassword.tsx +++ b/src/components/Modal/Auth/ResetPassword.tsx @@ -6,6 +6,13 @@ import { useSetRecoilState } from "recoil"; import { authModalState } from "../../../atoms/authModalAtom"; import { auth } from "../../../firebase/clientApp"; +/** + * Allows the user to reset their password. + * Takes the email as the input and sends the user an email from Firebase to reset the password. + * Once the email is submitted, a new view is shown telling the user to check their email. + * @returns + * @see https://github.com/CSFrequency/react-firebase-hooks/tree/master/auth + */ const ResetPassword: React.FC = () => { const setAuthModalState = useSetRecoilState(authModalState); const [email, setEmail] = useState(""); @@ -13,21 +20,29 @@ const ResetPassword: React.FC = () => { const [sendPasswordResetEmail, sending, error] = useSendPasswordResetEmail(auth); + /** + * This function is used as the event handler for a form submission. + * It will prevent the page from refreshing. + * Sends the email from Firebase to the email that was inputted in the form. + * @param event (React.FormEvent): the submit event triggered by the form + */ const onSubmit = async (event: React.FormEvent) => { - event.preventDefault(); + event.preventDefault(); // Prevent page from reloading - await sendPasswordResetEmail(email); - setSuccess(true); + await sendPasswordResetEmail(email); // try to send email + setSuccess(true); // once the email is successfully send }; return ( - Website logo + Website logo Reset your password + {/* Go to next page once the email is successfully sent */} {success ? ( Check your email ) : ( + // While the email has not been sent, show the form <> Enter the email associated with your account and we will send you a diff --git a/src/components/Modal/Auth/Signup.tsx b/src/components/Modal/Auth/Signup.tsx index 72c1569..94a2865 100644 --- a/src/components/Modal/Auth/Signup.tsx +++ b/src/components/Modal/Auth/Signup.tsx @@ -6,6 +6,16 @@ import { auth } from "../../../firebase/clientApp"; import { FIREBASE_ERRORS } from "../../../firebase/errors"; import { useCreateUserWithEmailAndPassword } from "react-firebase-hooks/auth"; +/** + * Allows the user to create an account by inputting the required credentials (email and password). + * There are 2 password fields to ensure that the user inputs the correct password. + * If the 2 passwords do not match, the account is not created and an error is displayed. + * If the email already exists, the account is not created and an error is displayed. + * + * A button to log in instead is available which would switch the modal to the log in view when clicked. + * @returns Sign up components view for modal. + * @see https://github.com/CSFrequency/react-firebase-hooks/tree/master/auth + */ const SignUp = () => { const setAuthModalState = useSetRecoilState(authModalState); // Set global state const [signUpForm, setSignUpForm] = useState({ diff --git a/src/components/Navbar/Navbar.tsx b/src/components/Navbar/Navbar.tsx index 1e98ee6..75ada63 100644 --- a/src/components/Navbar/Navbar.tsx +++ b/src/components/Navbar/Navbar.tsx @@ -1,29 +1,41 @@ - import { auth } from '@/firebase/clientApp'; -import { Flex, Image } from '@chakra-ui/react'; -import React from 'react'; -import { useAuthState } from 'react-firebase-hooks/auth'; -import RightContent from './RightContent/RightContent'; -import SearchInput from './SearchInput'; - - const Navbar:React.FC = () => { - const [user, loading, error] = useAuthState(auth); // will be passed to child components - return ( - - - Website logo - - {/* When screen size is mobile, SVG bellow is not displayed */} - Website text logo - - - {/* */} - - - ); - } - export default Navbar; \ No newline at end of file +import { auth } from "@/firebase/clientApp"; +import { Flex, Image } from "@chakra-ui/react"; +import React from "react"; +import { useAuthState } from "react-firebase-hooks/auth"; +import RightContent from "./RightContent/RightContent"; +import SearchInput from "./SearchInput"; + +/** + * Creates a navbar component which contains the following elements: + * + * - Logo which is visible on mobile and desktop sizes + * - Logo name which is visible only on desktop sizes + * - Search bar which is visible on mobile and desktop sizes and resizes dynamically + * @returns navbar component + * @requires ./RightContent/RightContent + * @requires ./SearchInput + */ +const Navbar: React.FC = () => { + const [user, loading, error] = useAuthState(auth); // will be passed to child components + return ( + + + {/* Logo which is always visible */} + Website logo + + {/* Logo name not visible on mobile */} + Website text logo + + + {/* */} + {/* Changes depending on whether user is authenticated or not */} + + + ); +}; +export default Navbar; diff --git a/src/components/Navbar/RightContent/AuthButtons.tsx b/src/components/Navbar/RightContent/AuthButtons.tsx index c1a607f..cffab34 100644 --- a/src/components/Navbar/RightContent/AuthButtons.tsx +++ b/src/components/Navbar/RightContent/AuthButtons.tsx @@ -2,8 +2,14 @@ import { authModalState } from "@/atoms/authModalAtom"; import { Button } from "@chakra-ui/react"; import React from "react"; import { useSetRecoilState } from "recoil"; -// import { authModalAtom } from "../../../atoms/authModalAtom"; +/** + * Displays 2 authentication buttons which open the authentication modal when clicked: + * + * - `Log In`: opens the log in modal + * - `Sign Up`: opens the sign up modal + * @returns Authentication buttons (log in and sign up) + */ const AuthButtons: React.FC = () => { const setAuthModalState = useSetRecoilState(authModalState);// Set global state return ( diff --git a/src/components/Navbar/RightContent/LogOutButton.tsx b/src/components/Navbar/RightContent/LogOutButton.tsx index 117f603..1001714 100644 --- a/src/components/Navbar/RightContent/LogOutButton.tsx +++ b/src/components/Navbar/RightContent/LogOutButton.tsx @@ -3,6 +3,10 @@ import { Button } from '@chakra-ui/react'; import { signOut } from 'firebase/auth'; import React from 'react'; +/** + * Displays a log out button which signs out the currently logged in user. + * @returns Log out button + */ const LogOutButton:React.FC = () => { return ( diff --git a/src/components/Navbar/RightContent/RightContent.tsx b/src/components/Navbar/RightContent/RightContent.tsx index c724885..d1ffb33 100644 --- a/src/components/Navbar/RightContent/RightContent.tsx +++ b/src/components/Navbar/RightContent/RightContent.tsx @@ -8,6 +8,15 @@ type RightContentProps = { user: any; }; +/** + * Right content is a section of the navbar which dynamically adjusts based on state. + * If the user is not authenticated, the right content will display log in and sign up buttons. + * If the user is authenticated, the right content will display the log out button. + * @param {user} - to manage state and adjust the UI based on said state + * @returns + * @requires ./AuthButtons + * @requires ./LogOutButton + */ const RightContent: React.FC = ({ user }) => { return ( <> diff --git a/src/components/Navbar/SearchInput.tsx b/src/components/Navbar/SearchInput.tsx index c5ea630..cfc7703 100644 --- a/src/components/Navbar/SearchInput.tsx +++ b/src/components/Navbar/SearchInput.tsx @@ -6,10 +6,17 @@ type SearchInputProps = { // user: }; +/** + * Search bar which would allow the user to carry out searches on the site. + * Search bar dynamically resizes depending on the screen size. + * It will use all the available space of the parent component (navbar). + * @returns Search component + * @see https://chakra-ui.com/docs/components/input/usage + */ const SearchInput: React.FC = () => { return ( // flexGrow uses the remaining space in the navbar - +