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