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 { useRef, useState } from "react";
import { IIngredient } from "../../schemas";
import { useEffect, useRef, useState } from "react";
import { DropdownData, IIngredient } from "../../schemas";
import { Button } from "../ui";
interface IngredientSelectorProps {
position: number
ingredients: IIngredient[]
units: DropdownData[]
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 [measurementUnits, setMeasurementUnits] = useState(units.map(each => each.name));
const [newOptions, setNewOptions] = useState(new Array<string>());
const [selected, setSelected] = useState(new Array<string>());
useEffect(() => {
console.log(units);
}, [])
return (
<div style={{ display: "flex", flexDirection: "row" }}>
<div className="ingredient-unit">
<label>Unit:</label>
</div>
<Autocomplete
autoHighlight
options={options}
className="ui-creatable-component"
renderInput={(params) => (
<TextField
{...params}
variant="filled"
placeholder="Ingredient Name"
<table style={{ display: "flex", flexDirection: "row", alignItems: "center" }}><tbody>
<tr>
<td className="quantity-of-unit">
<label>Quantity:</label>
<TextField />
</td>
<td className="ingredient-unit">
<label>Unit:</label>
<Autocomplete
autoHighlight
options={measurementUnits}
className="ui-creatable-component"
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]);
}
} */
}}
/>
)}
onKeyDown={(e) => {
if (e.code == 'Enter') {
const inputVal: string = e.target['value' as keyof EventTarget].toString();
console.log(inputVal)
if (inputVal.length) {
setSelected(prev => [...prev, inputVal])
setOptions((prev) => [...prev, inputVal]);
}
}
}}
/>
{/* @ts-ignore */}
<Button onClick={() => destroy(position)}>Close</Button>
</div>
</td>
<td className="ingredient-name">
<label>Ingredient:</label>
<Autocomplete
autoHighlight
options={options}
className="ui-creatable-component"
renderInput={(params) => (
<TextField
{...params}
variant="filled"
placeholder="Ingredient Name"
/>
)}
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 { useCallback, useEffect, useState } from "react";
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 { useSelectorContext } from "../../context/SelectorContext";
import IngredientSelector from "../derived/IngredientSelector";
@@ -9,35 +9,38 @@ import { v4 } from "uuid";
const AddRecipe = () => {
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 [triggerChange, setTriggerChange] = useState(false);
const [optionCount, setOptionCount] = useState(0);
const [toast, setToast] = useState(<></>)
const [input, setInput] = useState<IRecipe>({ name: '', preptime: '', description: '', authoruserid: '' })
// store all ingredients on page mount
useEffect(() => {
token && (async() => {
const ingredients = new API.Ingredient(token);
const _measurements = new API.Measurements(token);
const result = await ingredients.getAll();
const measurementList = await _measurements.getAll();
if (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])
useEffect(() => {
if (data.length) setTriggerChange(true);
}, [data, options])
if (data.length && measurements.length) {
setIngredientFields([<IngredientSelector key={v4()} position={optionCount} ingredients={data} units={measurements} destroy={destroySelector} />]);
}
}, [data, measurements])
// once user information is available, store it in recipe data
useEffect(() => {
@@ -50,10 +53,6 @@ const AddRecipe = () => {
})
}, [user])
useEffect(() => {
return;
}, [ingredientFields])
// submit handler
const handleCreate = async () => {
if (!token) return;
@@ -95,7 +94,7 @@ const AddRecipe = () => {
}, [ingredientFields]);
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);
}
@@ -107,17 +106,17 @@ const AddRecipe = () => {
<Panel id="create-recipe-panel" extraClasses="ui-form-component width-80">
<div className="form-row">
<label>Recipe Name:</label>
<input />
<input onChange={(e) => setInput({ ...input, name: e.target.value })} />
</div>
<div className="form-row">
<label>Prep Time:</label>
<input />
<input onChange={(e) => setInput({ ...input, preptime: e.target.value })} />
</div>
<div className="form-row">
<label>Course:</label>
<input />
<input placeholder="Replace me with dropdown!" />
</div>
{ data && (

View File

@@ -1,5 +1,5 @@
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";
module API {
@@ -223,6 +223,17 @@ module API {
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

View File

@@ -3,7 +3,7 @@ import pool from "../db";
export default class Dropdown {
async getMeasurements() {
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);
if (result.rows.length) return result.rows;
return null;

View File

@@ -5,7 +5,7 @@ import { DropdownDataType } from '../schemas';
const router = Router();
const DDInstance = new DropdownCtl();
export const dropdownValue = (app: Express) => {
export const dropdownValueRouter = (app: Express) => {
app.use('/app/dropdown', router);
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 { cuisineRouter } from "./cuisine";
import { courseRouter } from "./course";
import { dropdownValueRouter } from "./dropdownValues";
dotenv.config();
@@ -47,6 +48,7 @@ export const routes = async (app: Express) => {
subscriptionRoute(app);
groceryListRoute(app);
courseRouter(app);
dropdownValueRouter(app);
// deprecate?
cuisineRouter(app);