minor refactoring, light bug fixes
This commit is contained in:
@@ -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 (
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|||||||
53
client/src/components/ui/Navbar/variants.tsx
Normal file
53
client/src/components/ui/Navbar/variants.tsx
Normal 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 }
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -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>
|
||||||
Reference in New Issue
Block a user