fetches and displays measurement units

This commit is contained in:
Mikayla Dobson
2023-02-16 17:57:40 -06:00
parent 8ae6cf4ab0
commit 9e146f0825
6 changed files with 104 additions and 54 deletions

View File

@@ -1,49 +1,86 @@
import { Autocomplete, TextField } from "@mui/material" import { Autocomplete, TextField } from "@mui/material"
import { useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { IIngredient } from "../../schemas"; import { DropdownData, IIngredient } from "../../schemas";
import { Button } from "../ui"; import { Button } from "../ui";
interface IngredientSelectorProps { interface IngredientSelectorProps {
position: number position: number
ingredients: IIngredient[] ingredients: IIngredient[]
units: DropdownData[]
destroy: (position: number) => void destroy: (position: number) => void
} }
function IngredientSelector({ position, ingredients, destroy }: IngredientSelectorProps) { function IngredientSelector({ position, ingredients, units, destroy }: IngredientSelectorProps) {
const [options, setOptions] = useState(ingredients.map(each => each.name)); const [options, setOptions] = useState(ingredients.map(each => each.name));
const [measurementUnits, setMeasurementUnits] = useState(units.map(each => each.name));
const [newOptions, setNewOptions] = useState(new Array<string>()); const [newOptions, setNewOptions] = useState(new Array<string>());
const [selected, setSelected] = useState(new Array<string>()); const [selected, setSelected] = useState(new Array<string>());
useEffect(() => {
console.log(units);
}, [])
return ( return (
<div style={{ display: "flex", flexDirection: "row" }}> <table style={{ display: "flex", flexDirection: "row", alignItems: "center" }}><tbody>
<div className="ingredient-unit"> <tr>
<label>Unit:</label> <td className="quantity-of-unit">
</div> <label>Quantity:</label>
<Autocomplete <TextField />
autoHighlight </td>
options={options} <td className="ingredient-unit">
className="ui-creatable-component" <label>Unit:</label>
renderInput={(params) => ( <Autocomplete
<TextField autoHighlight
{...params} options={measurementUnits}
variant="filled" className="ui-creatable-component"
placeholder="Ingredient Name" renderInput={(params) => (
<TextField
{...params}
variant="filled"
placeholder="Unit of Measurement"
/>
)}
onKeyDown={(e) => {
console.log(e.code);
/* if (e.code == 'Enter') {
const inputVal: string = e.target['value' as keyof EventTarget].toString();
if (inputVal.length) {
setSelected(prev => [...prev, inputVal])
setOptions((prev) => [...prev, inputVal]);
}
} */
}}
/> />
)} </td>
onKeyDown={(e) => { <td className="ingredient-name">
if (e.code == 'Enter') { <label>Ingredient:</label>
const inputVal: string = e.target['value' as keyof EventTarget].toString(); <Autocomplete
console.log(inputVal) autoHighlight
if (inputVal.length) { options={options}
setSelected(prev => [...prev, inputVal]) className="ui-creatable-component"
setOptions((prev) => [...prev, inputVal]); renderInput={(params) => (
} <TextField
} {...params}
}} variant="filled"
/> placeholder="Ingredient Name"
{/* @ts-ignore */} />
<Button onClick={() => destroy(position)}>Close</Button> )}
</div> onKeyDown={(e) => {
if (e.code == 'Enter') {
const inputVal: string = e.target['value' as keyof EventTarget].toString();
if (inputVal.length) {
setSelected(prev => [...prev, inputVal])
setOptions((prev) => [...prev, inputVal]);
}
}
}}
/>
</td>
<td>
<Button onClick={() => destroy(position)}>Close</Button>
</td>
</tr>
</tbody></table>
) )
} }

View File

@@ -1,7 +1,7 @@
import { useAuthContext } from "../../context/AuthContext"; import { useAuthContext } from "../../context/AuthContext";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { Button, Card, Divider, Page, Panel } from "../ui" import { Button, Card, Divider, Page, Panel } from "../ui"
import { IIngredient, IRecipe } from "../../schemas"; import { DropdownData, IIngredient, IRecipe } from "../../schemas";
import API from "../../util/API"; import API from "../../util/API";
import { useSelectorContext } from "../../context/SelectorContext"; import { useSelectorContext } from "../../context/SelectorContext";
import IngredientSelector from "../derived/IngredientSelector"; import IngredientSelector from "../derived/IngredientSelector";
@@ -9,35 +9,38 @@ import { v4 } from "uuid";
const AddRecipe = () => { const AddRecipe = () => {
const { user, token } = useAuthContext(); const { user, token } = useAuthContext();
const { data, setData, options, setOptions } = useSelectorContext(); const { data, setData } = useSelectorContext();
const [input, setInput] = useState<IRecipe>({ name: '', preptime: '', description: '', authoruserid: '' })
const [measurements, setMeasurements] = useState<DropdownData[]>([]);
const [ingredientFields, setIngredientFields] = useState<Array<JSX.Element>>([]); const [ingredientFields, setIngredientFields] = useState<Array<JSX.Element>>([]);
const [triggerChange, setTriggerChange] = useState(false);
const [optionCount, setOptionCount] = useState(0); const [optionCount, setOptionCount] = useState(0);
const [toast, setToast] = useState(<></>) const [toast, setToast] = useState(<></>)
const [input, setInput] = useState<IRecipe>({ name: '', preptime: '', description: '', authoruserid: '' })
// store all ingredients on page mount // store all ingredients on page mount
useEffect(() => { useEffect(() => {
token && (async() => { token && (async() => {
const ingredients = new API.Ingredient(token); const ingredients = new API.Ingredient(token);
const _measurements = new API.Measurements(token);
const result = await ingredients.getAll(); const result = await ingredients.getAll();
const measurementList = await _measurements.getAll();
if (result) { if (result) {
setData((prev) => [...prev, ...result]); setData((prev) => [...prev, ...result]);
}
// once async data is received, derive its new states
setOptions(result.map((each: IIngredient) => {
return { label: each.name, value: each.id }
}));
setIngredientFields([<IngredientSelector key={v4()} position={optionCount} ingredients={result} destroy={destroySelector} />]); if (measurementList) {
setMeasurements((prev) => [...prev, ...measurementList]);
} }
})(); })();
}, [token]) }, [token])
useEffect(() => { useEffect(() => {
if (data.length) setTriggerChange(true); if (data.length && measurements.length) {
}, [data, options]) setIngredientFields([<IngredientSelector key={v4()} position={optionCount} ingredients={data} units={measurements} destroy={destroySelector} />]);
}
}, [data, measurements])
// once user information is available, store it in recipe data // once user information is available, store it in recipe data
useEffect(() => { useEffect(() => {
@@ -50,10 +53,6 @@ const AddRecipe = () => {
}) })
}, [user]) }, [user])
useEffect(() => {
return;
}, [ingredientFields])
// submit handler // submit handler
const handleCreate = async () => { const handleCreate = async () => {
if (!token) return; if (!token) return;
@@ -95,7 +94,7 @@ const AddRecipe = () => {
}, [ingredientFields]); }, [ingredientFields]);
function handleNewOption() { function handleNewOption() {
setIngredientFields((prev) => [...prev, <IngredientSelector position={optionCount + 1} key={v4()} ingredients={data} destroy={destroySelector} />]) setIngredientFields((prev) => [...prev, <IngredientSelector position={optionCount + 1} key={v4()} ingredients={data} units={measurements} destroy={destroySelector} />])
setOptionCount(prev => prev + 1); setOptionCount(prev => prev + 1);
} }
@@ -107,17 +106,17 @@ const AddRecipe = () => {
<Panel id="create-recipe-panel" extraClasses="ui-form-component width-80"> <Panel id="create-recipe-panel" extraClasses="ui-form-component width-80">
<div className="form-row"> <div className="form-row">
<label>Recipe Name:</label> <label>Recipe Name:</label>
<input /> <input onChange={(e) => setInput({ ...input, name: e.target.value })} />
</div> </div>
<div className="form-row"> <div className="form-row">
<label>Prep Time:</label> <label>Prep Time:</label>
<input /> <input onChange={(e) => setInput({ ...input, preptime: e.target.value })} />
</div> </div>
<div className="form-row"> <div className="form-row">
<label>Course:</label> <label>Course:</label>
<input /> <input placeholder="Replace me with dropdown!" />
</div> </div>
{ data && ( { data && (

View File

@@ -1,5 +1,5 @@
import { AxiosError, AxiosHeaders, AxiosRequestHeaders, AxiosResponse } from "axios"; import { AxiosError, AxiosHeaders, AxiosRequestHeaders, AxiosResponse } from "axios";
import { IUser, IUserAuth, IFriendship, IRecipe, IIngredient, ICollection, IGroceryList } from "../schemas"; import { IUser, IUserAuth, IFriendship, IRecipe, IIngredient, ICollection, IGroceryList, DropdownData } from "../schemas";
import { default as _instance } from "./axiosInstance"; import { default as _instance } from "./axiosInstance";
module API { module API {
@@ -223,6 +223,17 @@ module API {
super(Settings.getAPISTRING() + "/app/grocery-list", token) super(Settings.getAPISTRING() + "/app/grocery-list", token)
} }
} }
export class Measurements extends RestController<DropdownData> {
constructor(token: string) {
super(Settings.getAPISTRING() + "/app/dropdown", token);
}
override async getAll() {
const response = await this.instance.get(this.endpoint + "?datatype=measurement", this.headers);
return Promise.resolve(response.data);
}
}
} }
export default API export default API

View File

@@ -3,7 +3,7 @@ import pool from "../db";
export default class Dropdown { export default class Dropdown {
async getMeasurements() { async getMeasurements() {
try { try {
const statement = `SELECT * FROM recipin.dropdownVals WHERE datatype = MEASUREMENTS`; const statement = `SELECT * FROM recipin.dropdownVals WHERE datatype = 'MEASUREMENTS'`;
const result = await pool.query(statement); const result = await pool.query(statement);
if (result.rows.length) return result.rows; if (result.rows.length) return result.rows;
return null; return null;

View File

@@ -5,7 +5,7 @@ import { DropdownDataType } from '../schemas';
const router = Router(); const router = Router();
const DDInstance = new DropdownCtl(); const DDInstance = new DropdownCtl();
export const dropdownValue = (app: Express) => { export const dropdownValueRouter = (app: Express) => {
app.use('/app/dropdown', router); app.use('/app/dropdown', router);
router.get('/', async (req, res, next) => { router.get('/', async (req, res, next) => {
@@ -24,4 +24,5 @@ export const dropdownValue = (app: Express) => {
} }
}) })
return router;
} }

View File

@@ -11,6 +11,7 @@ import { subscriptionRoute } from "./subscription";
import { friendRouter } from "./friend"; import { friendRouter } from "./friend";
import { cuisineRouter } from "./cuisine"; import { cuisineRouter } from "./cuisine";
import { courseRouter } from "./course"; import { courseRouter } from "./course";
import { dropdownValueRouter } from "./dropdownValues";
dotenv.config(); dotenv.config();
@@ -47,6 +48,7 @@ export const routes = async (app: Express) => {
subscriptionRoute(app); subscriptionRoute(app);
groceryListRoute(app); groceryListRoute(app);
courseRouter(app); courseRouter(app);
dropdownValueRouter(app);
// deprecate? // deprecate?
cuisineRouter(app); cuisineRouter(app);