minor refactoring, light bug fixes

This commit is contained in:
Mikayla Dobson
2022-11-26 10:07:40 -06:00
parent 1445245d60
commit 99c48d2a6e
6 changed files with 103 additions and 71 deletions

View File

@@ -1,20 +1,16 @@
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useAuthContext } from "../../context/AuthContext"; import { useAuthContext } from "../../context/AuthContext";
import { IUserAuth } from "../../schemas";
import { attemptLogin } from "../../util/apiUtils"; import { attemptLogin } from "../../util/apiUtils";
import { Button, Page, Panel } from "../ui"; import { IUserAuth } from "../../schemas";
import Form, { FormConfig } from "../ui/Form"; import { Button, Form, Page, Panel } from "../ui";
export default function Login() { export default function Login() {
// setup and local state // setup and local state
const authContext = useAuthContext(); const authContext = useAuthContext();
const navigate = useNavigate(); const navigate = useNavigate();
const [form, setForm] = useState<JSX.Element[]>(); const [form, setForm] = useState<JSX.Element[]>();
const [input, setInput] = useState<IUserAuth>({ const [input, setInput] = useState<IUserAuth>({ email: '', password: '' });
email: '',
password: ''
})
// retrieve and store state from form // retrieve and store state from form
const getFormState = useCallback((received: IUserAuth) => { const getFormState = useCallback((received: IUserAuth) => {
@@ -29,18 +25,19 @@ export default function Login() {
navigate('/'); navigate('/');
} }
const formConfig: FormConfig<IUserAuth> = { // check for logged in user and mount form
parent: 'login',
keys: Object.keys(input),
labels: ["Email", "Password"],
dataTypes: Object.keys(input),
initialState: input,
getState: getFormState
}
useEffect(() => { useEffect(() => {
if (authContext.user) navigate('/'); if (authContext.user) navigate('/');
setForm(new Form<IUserAuth>(formConfig).mount()) setForm(
new Form<IUserAuth>({
parent: 'login',
keys: Object.keys(input),
labels: ["Email", "Password"],
dataTypes: Object.keys(input),
initialState: input,
getState: getFormState
}).mount()
);
}, []) }, [])
return ( return (

View File

@@ -22,7 +22,6 @@ export default class Form<T>{
public labels: string[]; public labels: string[];
public keys: string[]; public keys: string[];
public dataTypes: any[] public dataTypes: any[]
public length: number;
public state: T; public state: T;
public getState: (received: T) => void public getState: (received: T) => void
@@ -30,7 +29,6 @@ export default class Form<T>{
this.parent = config.parent; this.parent = config.parent;
this.keys = config.keys; this.keys = config.keys;
this.labels = config.labels || this.keys; this.labels = config.labels || this.keys;
this.length = config.keys.length;
this.dataTypes = config.dataTypes || new Array(this.keys.length).fill('text'); this.dataTypes = config.dataTypes || new Array(this.keys.length).fill('text');
this.state = config.initialState; this.state = config.initialState;
this.getState = config.getState; this.getState = config.getState;
@@ -49,7 +47,7 @@ export default class Form<T>{
mount() { mount() {
let output = new Array<JSX.Element>(); let output = new Array<JSX.Element>();
for (let i = 0; i < this.length; i++) { for (let i = 0; i < this.keys.length; i++) {
output.push( output.push(
<div id={`${this.parent}-row-${i}`} key={v4()}> <div id={`${this.parent}-row-${i}`} key={v4()}>
<label htmlFor={`${this.parent}-${this.keys[i]}`}>{this.labels[i]}</label> <label htmlFor={`${this.parent}-${this.keys[i]}`}>{this.labels[i]}</label>

View File

@@ -1,70 +1,36 @@
import { useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { LoggedIn, NotLoggedIn, Registering } from "./variants";
import { useAuthContext } from "../../../context/AuthContext"; import { useAuthContext } from "../../../context/AuthContext";
import { attemptLogout } from "../../../util/apiUtils";
import { IUser } from "../../../schemas"; import { IUser } from "../../../schemas";
import Button from "../Button";
import "/src/sass/components/Navbar.scss"; import "/src/sass/components/Navbar.scss";
const Navbar = () => { const Navbar = () => {
// setup and local state // setup and local state
const navigate = useNavigate(); const navigate = useNavigate();
const authContext = useAuthContext(); const authContext = useAuthContext();
const [received, setReceived] = useState<IUser>(); const [received, setReceived] = useState<IUser | undefined>();
const [displayed, setDisplayed] = useState<JSX.Element>(); const [displayed, setDisplayed] = useState<JSX.Element>();
// helper to unwrap async result // lift and store state from navbar variants
const handleLogout = async () => { const liftChange = useCallback((newValue: IUser | undefined) => {
const success = await attemptLogout(); authContext.user = newValue;
if (success) setReceived(undefined); setReceived(newValue);
}, [])
const variants = {
loggedin: <LoggedIn navigate={navigate} received={received} liftChange={liftChange} />,
notloggedin: <NotLoggedIn navigate={navigate} received={received} />,
registering: <Registering navigate={navigate} received={received} />
} }
// jsx variations
const navbarLoggedIn = (
<div id="navbar">
<div className="navbar-block">
<a onClick={() => navigate('/')}>RECIPIN</a>
</div>
<div className="navbar-block">
<p>Hi, {received?.firstname}.</p>
<span id="search-icon"></span>
<Button onClick={() => navigate('/profile')}>Profile</Button>
<Button onClick={handleLogout}>Log Out</Button>
</div>
</div>
)
const navbarNotLoggedIn = (
<div id="navbar">
<div className="navbar-block">
<a onClick={() => navigate('/')}>RECIPIN</a>
</div>
<div className='navbar-block'>
<button onClick={() => navigate('/login')}>LOG IN</button>
</div>
</div>
)
const navbarRegistering = (
<div id="navbar">
<div className="navbar-block">
<a onClick={() => navigate('/')}>RECIPIN</a>
</div>
<div className="navbar-block">
<p>Hi, {received?.firstname}.</p>
</div>
</div>
)
// side effects for live rendering // side effects for live rendering
useEffect(() => { useEffect(() => {
console.log(authContext);
authContext && setReceived(authContext.user); authContext && setReceived(authContext.user);
}, [authContext]) }, [authContext])
useEffect(() => { useEffect(() => {
console.log(received); setDisplayed(received ? variants.loggedin : variants.notloggedin);
setDisplayed(received ? navbarLoggedIn : navbarNotLoggedIn);
}, [received, setReceived]); }, [received, setReceived]);
return displayed || <p>Loading...</p>; return displayed || <p>Loading...</p>;

View File

@@ -0,0 +1,53 @@
import { attemptLogout } from "../../../util/apiUtils";
import { NavbarType } from "../../../util/types";
import Button from "../Button";
const LoggedIn: NavbarType = ({ received, liftChange, navigate }) => {
const handleLogout = async () => {
const success = await attemptLogout();
if (success) liftChange!(undefined);
navigate('/');
}
return (
<div id="navbar">
<div className="navbar-block">
<a onClick={() => navigate('/')}>RECIPIN</a>
</div>
<div className="navbar-block">
<p>Hi, {received?.firstname}.</p>
<span id="search-icon"></span>
<Button onClick={() => navigate('/profile')}>Profile</Button>
<Button onClick={handleLogout}>Log Out</Button>
</div>
</div>
)
}
const NotLoggedIn: NavbarType = ({ navigate }) => {
return (
<div id="navbar">
<div className="navbar-block">
<a onClick={() => navigate('/')}>RECIPIN</a>
</div>
<div className='navbar-block'>
<button onClick={() => navigate('/login')}>LOG IN</button>
</div>
</div>
)
}
const Registering: NavbarType = ({ received, navigate }) => {
return (
<div id="navbar">
<div className="navbar-block">
<a onClick={() => navigate('/')}>RECIPIN</a>
</div>
<div className="navbar-block">
<p>Hi, {received?.firstname}.</p>
</div>
</div>
)
}
export { LoggedIn, NotLoggedIn, Registering }

View File

@@ -1,9 +1,19 @@
import Button from "./Button"; import Button from "./Button";
import Card from "./Card";
import Divider from "./Divider";
import Form from "./Form";
import Navbar from "./Navbar";
import Page from "./Page"; import Page from "./Page";
import Panel from "./Panel"; import Panel from "./Panel";
import UserCard from "./UserCard";
export { export {
Button, Button,
Card,
Divider,
Form,
Navbar,
Page, Page,
Panel Panel,
UserCard
} }

View File

@@ -1,4 +1,5 @@
import { FC, ReactNode } from "react"; import { Dispatch, FC, ReactNode, SetStateAction } from "react";
import { useNavigate } from "react-router-dom";
import { IUser } from "../schemas"; import { IUser } from "../schemas";
interface PortalBase { interface PortalBase {
@@ -18,8 +19,15 @@ interface UserCardProps extends PortalBase {
user: IUser user: IUser
} }
interface NavbarProps {
received: IUser | undefined
navigate: (path: string) => void
liftChange?: (newValue: IUser | undefined) => void
}
export type PageComponent = FC<PortalBase> export type PageComponent = FC<PortalBase>
export type PanelComponent = FC<PortalBase> export type PanelComponent = FC<PortalBase>
export type ButtonComponent = FC<ButtonParams> export type ButtonComponent = FC<ButtonParams>
export type ProtectPortal = FC<MultiChildPortal> export type ProtectPortal = FC<MultiChildPortal>
export type UserCardType = FC<UserCardProps> export type UserCardType = FC<UserCardProps>
export type NavbarType = FC<NavbarProps>