diff --git a/client/package-lock.json b/client/package-lock.json index a118849..ff37395 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -11,11 +11,13 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.4.3", - "sass": "^1.56.1" + "sass": "^1.56.1", + "uuid": "^9.0.0" }, "devDependencies": { "@types/react": "^18.0.24", "@types/react-dom": "^18.0.8", + "@types/uuid": "^8.3.4", "@vitejs/plugin-react": "^2.2.0", "typescript": "^4.6.4", "vite": "^3.2.3" @@ -555,6 +557,12 @@ "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", "dev": true }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, "node_modules/@vitejs/plugin-react": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-2.2.0.tgz", @@ -1629,6 +1637,14 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vite": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.4.tgz", @@ -2071,6 +2087,12 @@ "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", "dev": true }, + "@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, "@vitejs/plugin-react": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-2.2.0.tgz", @@ -2713,6 +2735,11 @@ "picocolors": "^1.0.0" } }, + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + }, "vite": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.4.tgz", diff --git a/client/package.json b/client/package.json index 223d2d1..1dc7e76 100644 --- a/client/package.json +++ b/client/package.json @@ -12,11 +12,13 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.4.3", - "sass": "^1.56.1" + "sass": "^1.56.1", + "uuid": "^9.0.0" }, "devDependencies": { "@types/react": "^18.0.24", "@types/react-dom": "^18.0.8", + "@types/uuid": "^8.3.4", "@vitejs/plugin-react": "^2.2.0", "typescript": "^4.6.4", "vite": "^3.2.3" diff --git a/client/src/components/pages/Login.tsx b/client/src/components/pages/Login.tsx index 76ebf01..c63cb0a 100644 --- a/client/src/components/pages/Login.tsx +++ b/client/src/components/pages/Login.tsx @@ -1,8 +1,11 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { IUserAuth } from "../../schemas"; +import { attemptLogin } from "../../util/apiUtils"; import { Button, Page, Panel } from "../ui"; +import Form, { FormConfig } from "../ui/Form"; export default function Login() { + const [form, setForm] = useState(); const [input, setInput] = useState({ email: '', password: '' @@ -10,18 +13,31 @@ export default function Login() { const handleLogin = async () => { if (!input.email || !input.password) return; + const result = await attemptLogin(input); + console.log(result); } + const formConfig: FormConfig = { + parent: 'login', + keys: Object.keys(input), + labels: ["Email", "Password"], + dataTypes: Object.keys(input), + initialState: input, + setState: setInput, + submitButtonText: "Log In", + submitFunction: handleLogin + } + + useEffect(() => { + setForm(new Form(formConfig).mount()) + }, []) + return (

Hello! Nice to see you again.

- - setInput({...input, email: e.target.value})}> - - setInput({...input, password: e.target.value})}> - + { form } diff --git a/client/src/components/pages/Register/register.aboutyou.tsx b/client/src/components/pages/Register/register.aboutyou.tsx index 3cf9e6b..b6c741f 100644 --- a/client/src/components/pages/Register/register.aboutyou.tsx +++ b/client/src/components/pages/Register/register.aboutyou.tsx @@ -1,15 +1,48 @@ -import { Page } from "../../ui"; +import { useEffect, useMemo, useState } from "react"; +import { v4 } from "uuid"; +import { IUser } from "../../../schemas"; +import { attemptRegister } from "../../../util/apiUtils"; +import { Page, Panel } from "../../ui"; +import Divider from "../../ui/Divider"; +import Form, { FormConfig } from "../../ui/Form"; export default function AboutYou() { + const [form, setForm] = useState([

Loading content...

]); + const [input, setInput] = useState({ + firstname: '', + lastname: '', + handle: '', + email: '', + password: '', + active: true + }); + + const formConfig: FormConfig = { + parent: "register", + keys: Object.keys(input), + initialState: input, + labels: ['First Name', 'Last Name', 'Handle', 'Email', "Password", "Active?"], + dataTypes: ['text', 'text', 'text', 'email', 'password', 'text'], + setState: setInput, + submitButtonText: 'Register', + submitFunction: () => console.log(input) + } + + useEffect(() => { + setForm(new Form(formConfig).mount()); + }, []) + return (

Hi! Thanks for being here.

- {/* divider */} +

Tell us a bit about yourself:

- {/* auth form */} + + { form } +
) } \ No newline at end of file diff --git a/client/src/components/ui/Form.tsx b/client/src/components/ui/Form.tsx new file mode 100644 index 0000000..a24db07 --- /dev/null +++ b/client/src/components/ui/Form.tsx @@ -0,0 +1,83 @@ +import { ChangeEvent, Dispatch, SetStateAction, useState } from "react"; +import { v4 } from 'uuid'; + +/** + * For the generation of more complex form objects with + * larger stateful values; expects to receive an object of + * type T to a form which can mutate T with a state setter + * of type Dispatch> +**/ + +export interface FormConfig { + parent: string + keys: string[] + initialState: T + setState: Dispatch> + labels?: string[] + dataTypes?: string[] + submitFunction?: (params: any) => any + submitButtonText?: string +} + +export default class Form{ + public parent: string; + public labels: string[]; + public keys: string[]; + public dataTypes: any[] + public length: number; + public state: T; + public submitButtonText?: string; + public submitFunction?: (params: any) => any; + public setState: any + + constructor(config: FormConfig){ + this.parent = config.parent; + this.keys = config.keys; + this.labels = config.labels || this.keys; + this.length = config.keys.length; + this.submitFunction = config.submitFunction || undefined; + this.submitButtonText = config.submitButtonText || undefined; + this.dataTypes = config.dataTypes || new Array(this.keys.length).fill('text'); + this.state = config.initialState; + this.setState = config.setState; + } + + update(e: ChangeEvent, idx: number) { + let newState = { + ...this.state, + [this.keys[idx]]: e.target['value' as keyof EventTarget] + } + + this.state = newState; + this.setState(newState); + + console.log(this.state); + this.mount(); + } + + mount() { + let output = new Array(); + + for (let i = 0; i < this.length; i++) { + output.push( +
+ + this.update(e, i)} + value={this.state[i as keyof T] as string}> + +
+ ) + } + + if (this.submitFunction) { + output.push( + + ) + } + + return output; + } +} \ No newline at end of file diff --git a/client/src/components/ui/Navbar.tsx b/client/src/components/ui/Navbar.tsx index 7660b3f..4c5967f 100644 --- a/client/src/components/ui/Navbar.tsx +++ b/client/src/components/ui/Navbar.tsx @@ -11,7 +11,7 @@ const Navbar = () => { const navbarLoggedIn = (