fetches and displays measurement units
This commit is contained in:
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user