bit of work on the form component

This commit is contained in:
Mikayla Dobson
2023-02-14 19:45:32 -06:00
parent 28c4747aba
commit a30960a1b4
8 changed files with 84 additions and 34 deletions

View File

@@ -54,11 +54,13 @@ const Friends: FC<{ targetUser?: IUser }> = ({ targetUser }) => {
<Card extraStyles="flex-row">
<h2>Friends ({ userList?.length ?? "0" }):</h2>
<div className="friends-list">
{
userList.map((user: IUser) => {
return <UserCard key={v4()} targetUser={user} />
})
}
</div>
<aside>
<p>Looking for someone else?</p>

View File

@@ -63,7 +63,7 @@ const AddRecipe = () => {
parent: "AddRecipe",
keys: ["name", "preptime", "course", "cuisine", "ingredients", "description"],
labels: ["Recipe Name:", "Prep Time:", "Course:", "Cuisine:", "Ingredients:", "Description:"],
dataTypes: ['text', 'text', 'custom picker', 'custom picker', 'custom picker', 'TINYMCE'],
dataTypes: ['text', 'text', 'custom picker', 'custom picker', 'SELECTOR', 'TINYMCE'],
initialState: input,
getState: getFormState,
richTextInitialValue: "<p>Enter recipe details here!</p>"

View File

@@ -1,10 +1,10 @@
import { FC } from "react"
import { MultiChildPortal } from "../../util/types"
import { FC } from "react";
const Card: FC<MultiChildPortal> = ({ children = <></>, extraStyles = ""}) => {
const Card: FC<{ children?: JSX.Element | JSX.Element[], extraStyles?: string }> = ({ children = <></>, extraStyles = ""}) => {
return (
<div className={`ui-card ${extraStyles}`}>
{ children }
{ Array.isArray(children) ? <>{children}</> : children }
</div>
)
}

View File

@@ -1,6 +1,10 @@
import { ChangeEvent, FC, useEffect, useState } from "react"
import { v4 } from "uuid"
import { useAuthContext } from "../../context/AuthContext";
import { IIngredient, IUser } from "../../schemas";
import API from "../../util/API";
import RichText from "./RichText"
import Selector from "./Selector";
import "/src/sass/components/Form.scss";
export interface FormConfig<T> {
@@ -27,6 +31,8 @@ const Form: FC<FormProps> = ({ parent, _config }) => {
const [state, setState] = useState<T>();
const [contents, setContents] = useState<JSX.Element[]>();
const { token } = useAuthContext();
// initial setup
useEffect(() => {
if (!config) setConfig({
@@ -66,35 +72,61 @@ const Form: FC<FormProps> = ({ parent, _config }) => {
})
}
async function populateSelector(key: string): Promise<any[] | null> {
if (!token) return null;
switch (key) {
case "ingredient":
const ingredients = new API.Ingredient(token);
const result = await ingredients.getAll();
if (result) return result;
break;
default:
break;
}
return null;
}
// mount the form once config has been loaded
useEffect(() => {
if (state && config) {
const result = config.keys.map((each: string, i: number) => {
if (config.dataTypes![i] == 'TINYMCE') {
return (
<div className="form-row-editor" id={`${config.parent}-row-${i}`} key={v4()}>
<label htmlFor={`${config.parent}-${each}`}>{config.labels![i]}</label>
<RichText id={`${config.parent}-${each}`} initialValue={config.richTextInitialValue} getState={(txt) => updateRichText(txt, i)} />
</div>
)
} else {
return (
<div className="form-row" id={`${config.parent}-row-${i}`} key={v4()}>
<label htmlFor={`${config.parent}-${each}`}>{config.labels![i]}</label>
<input
type={config.dataTypes![i]}
id={`${config.parent}-${each}`}
onChange={(e) => update(e, i)}
value={state[i as keyof T] as string}>
</input>
</div>
)
}
});
setContents(result);
(async() => {
const result = config.keys.map(async (each: string, i: number) => {
if (config.dataTypes![i] == 'TINYMCE') {
return (
<div className="form-row-editor" id={`${config.parent}-row-${i}`} key={v4()}>
<label htmlFor={`${config.parent}-${each}`}>{config.labels![i]}</label>
<RichText id={`${config.parent}-${each}`} initialValue={config.richTextInitialValue} getState={(txt) => updateRichText(txt, i)} />
</div>
)
} else if (config.dataTypes![i] == 'SELECTOR') {
type StrongType = Partial<T> & { id: number, name: string };
const storedResult = await (async() => {
const result = await populateSelector(config?.labels![i] || "");
if (result) return result as T[];
return null;
})();
return <Selector<StrongType> optionList={storedResult || []} />
} else {
return (
<div className="form-row" id={`${config.parent}-row-${i}`} key={v4()}>
<label htmlFor={`${config.parent}-${each}`}>{config.labels![i]}</label>
<input
type={config.dataTypes![i]}
id={`${config.parent}-${each}`}
onChange={(e) => update(e, i)}
value={state[i as keyof T] as string}>
</input>
</div>
)
}
});
const mappedContents = await Promise.all(result);
mappedContents && setContents(mappedContents);
})();
}
}, [config]);

View File

@@ -0,0 +1,17 @@
interface Entity {
id: string | number
name?: string
}
function Selector<T extends Entity>({ optionList }: { optionList: Array<T> }) {
// const Selector: FC<{ optionList: Array<T extends HasID> }> = ({ optionList }) => {
return (
<select className="ui-select-component">
{ optionList.map(item =>
<option id={`select-item-${item.name}-${item.id}`}>{item.name}</option>
)}
</select>
)
}
export default Selector

View File

@@ -46,10 +46,12 @@ const UserCard: UserCardType = ({ extraStyles, targetUser }) => {
return (
<Card extraStyles={'user-card' + extraStyles}>
<>
<div className="avatar"></div>
<h3><a href={`/profile?id=${targetUser.id}`}>{targetUser.firstname} {targetUser.lastname.substring(0,1)}.</a></h3>
<h4>@{targetUser.handle}</h4>
{ buttonVariant }
</>
</Card>
)
}

View File

@@ -42,7 +42,7 @@ module API {
};
}
async customRoute(method: CRUDMETHOD, path: string, data?: any, requireHeaders = true) {
protected async customRoute(method: CRUDMETHOD, path: string, data?: any, requireHeaders = true) {
switch (method) {
case CRUDMETHOD.GET:
return this.instance.get(this.endpoint + path, (requireHeaders && this.headers));
@@ -186,7 +186,6 @@ module API {
export class Ingredient extends RestController<IIngredient> {
constructor(token: string) {
if (!token) throw new Error("Missing required token");
super(Settings.getAPISTRING() + "/app/ingredients", token);
}
}

View File

@@ -20,8 +20,6 @@ export interface ProtectParams extends PortalBase {
interface UserCardProps extends PortalBase {
targetUser: IUser
canAdd?: boolean
liftData?: (data: any) => void
}
interface NavbarProps {