fraction support on addRecipe, working on state management
This commit is contained in:
@@ -2,22 +2,17 @@ import { Autocomplete, TextField } from "@mui/material"
|
|||||||
import { ChangeEvent, useEffect, useRef, useState } from "react";
|
import { ChangeEvent, useEffect, useRef, useState } from "react";
|
||||||
import { useAuthContext } from "../../context/AuthContext";
|
import { useAuthContext } from "../../context/AuthContext";
|
||||||
import { DropdownData, IIngredient } from "../../schemas";
|
import { DropdownData, IIngredient } from "../../schemas";
|
||||||
|
import { IngredientFieldData } from "../../util/types";
|
||||||
import { Button } from "../ui";
|
import { Button } from "../ui";
|
||||||
|
|
||||||
interface IngredientSelectorProps {
|
interface IngredientSelectorProps {
|
||||||
position: number
|
position: number
|
||||||
ingredients: IIngredient[]
|
ingredients: IIngredient[]
|
||||||
units: DropdownData[]
|
units: DropdownData[]
|
||||||
|
getRowState: (input: IngredientFieldData) => void
|
||||||
destroy: (position: number) => void
|
destroy: (position: number) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RowState {
|
|
||||||
quantity: number
|
|
||||||
measurement: string | null
|
|
||||||
ingredientSelection: string | null
|
|
||||||
ingredients: IIngredient[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const createIngredient = (name: string, userid: string | number) => {
|
const createIngredient = (name: string, userid: string | number) => {
|
||||||
return {
|
return {
|
||||||
name: name,
|
name: name,
|
||||||
@@ -25,34 +20,102 @@ const createIngredient = (name: string, userid: string | number) => {
|
|||||||
} as IIngredient
|
} as IIngredient
|
||||||
}
|
}
|
||||||
|
|
||||||
function IngredientSelector({ position, ingredients, units, destroy }: IngredientSelectorProps) {
|
const quantityOptions: readonly any[] = [
|
||||||
|
{ name: "1/8" , value: 0.125 },
|
||||||
|
{ name: "1/4" , value: 0.250 },
|
||||||
|
{ name: "1/3" , value: 0.333 },
|
||||||
|
{ name: "3/8" , value: 0.375 },
|
||||||
|
{ name: "1/2" , value: 0.500 },
|
||||||
|
{ name: "5/8" , value: 0.625 },
|
||||||
|
{ name: "2/3" , value: 0.666 },
|
||||||
|
{ name: "3/4" , value: 0.750 },
|
||||||
|
{ name: "7/8" , value: 0.875 },
|
||||||
|
{ name: "1 1/4" , value: 1.250 },
|
||||||
|
{ name: "1 1/3" , value: 1.333 },
|
||||||
|
{ name: "1 1/2" , value: 1.500 },
|
||||||
|
{ name: "1 2/3" , value: 1.666 },
|
||||||
|
{ name: "1 3/4" , value: 1.750 },
|
||||||
|
{ name: "2 1/4" , value: 2.250 },
|
||||||
|
{ name: "2 1/3" , value: 2.333 },
|
||||||
|
{ name: "2 1/2" , value: 2.500 },
|
||||||
|
{ name: "2 3/4" , value: 2.750 },
|
||||||
|
{ name: "3 1/4" , value: 3.250 },
|
||||||
|
{ name: "3 1/2" , value: 3.500 },
|
||||||
|
{ name: "3 3/4" , value: 3.750 },
|
||||||
|
{ name: "4 1/4" , value: 4.250 },
|
||||||
|
{ name: "4 1/2" , value: 4.500 },
|
||||||
|
{ name: "4 3/4" , value: 4.750 },
|
||||||
|
{ name: "5 1/4" , value: 5.250 },
|
||||||
|
{ name: "5 1/2" , value: 5.500 },
|
||||||
|
{ name: "5 3/4" , value: 5.750 },
|
||||||
|
]
|
||||||
|
|
||||||
|
function IngredientSelector({ position, ingredients, units, getRowState, destroy }: IngredientSelectorProps) {
|
||||||
const { user } = useAuthContext();
|
const { user } = useAuthContext();
|
||||||
|
|
||||||
const [ingredientOptions, setIngredientOptions] = useState(ingredients.map(each => each.name));
|
const [ingredientOptions, setIngredientOptions] = useState(ingredients.map(each => each.name));
|
||||||
const [measurementUnits, setMeasurementUnits] = useState(units.map(each => each.name));
|
const [rowState, setRowState] = useState<IngredientFieldData>({
|
||||||
|
quantity: undefined,
|
||||||
const [rowState, setRowState] = useState<RowState>({
|
rowPosition: position,
|
||||||
quantity: 0,
|
measurement: undefined,
|
||||||
measurement: null,
|
ingredientSelection: undefined,
|
||||||
ingredientSelection: null,
|
|
||||||
ingredients: ingredients
|
ingredients: ingredients
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [quantityError, setQuantityError] = useState<null | string>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("Row " + position + " state changed:");
|
getRowState(rowState);
|
||||||
console.log(rowState);
|
}, [rowState, setRowState])
|
||||||
}, [rowState])
|
|
||||||
|
function validateQuantity(input: any) {
|
||||||
|
const value = new Number(input).valueOf();
|
||||||
|
|
||||||
|
if (Number.isNaN(value)) {
|
||||||
|
console.log('is nan');
|
||||||
|
setQuantityError("Please provide a valid input (number)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input) {
|
||||||
|
console.log('is null');
|
||||||
|
setRowState({ ...rowState, quantity: undefined });
|
||||||
|
setQuantityError(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setQuantityError(null);
|
||||||
|
setRowState({ ...rowState, quantity: value });
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table className="ingredient-widget"><tbody>
|
<table className="ingredient-widget"><tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td className="quantity-of-unit">
|
<td className="quantity-of-unit">
|
||||||
<TextField variant="outlined" label="Quantity" onChange={(e) => setRowState({...rowState, quantity: parseFloat(e.target.value) })} />
|
<Autocomplete
|
||||||
|
freeSolo
|
||||||
|
autoHighlight
|
||||||
|
options={quantityOptions.map(each => each.name)}
|
||||||
|
className="ui-creatable-component"
|
||||||
|
onChange={(event, value) => {
|
||||||
|
console.log(value);
|
||||||
|
validateQuantity(quantityOptions.filter(option => (option.name) == value)[0]['value'] as number);
|
||||||
|
}}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
variant="outlined"
|
||||||
|
color={(rowState.quantity == null) ? (quantityError ? "error" : "info") : (quantityError ? "error" : "success")}
|
||||||
|
label={quantityError ?? "Quantity"}
|
||||||
|
onChange={(e) => validateQuantity(e.target.value)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td className="ingredient-unit">
|
<td className="ingredient-unit">
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
autoHighlight
|
autoHighlight
|
||||||
options={measurementUnits}
|
options={units.map(each => each.name)}
|
||||||
className="ui-creatable-component"
|
className="ui-creatable-component"
|
||||||
renderInput={(params) => (
|
renderInput={(params) => (
|
||||||
<TextField
|
<TextField
|
||||||
@@ -62,7 +125,9 @@ function IngredientSelector({ position, ingredients, units, destroy }: Ingredien
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
onChange={(event, value) => {
|
onChange={(event, value) => {
|
||||||
setRowState({ ...rowState, measurement: value });
|
if (value) {
|
||||||
|
setRowState({ ...rowState, measurement: value });
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
@@ -103,7 +168,7 @@ function IngredientSelector({ position, ingredients, units, destroy }: Ingredien
|
|||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
ingredients: ingredients,
|
ingredients: ingredients,
|
||||||
ingredientSelection: null
|
ingredientSelection: undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,19 @@ 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 { DropdownData, IIngredient, IRecipe } from "../../schemas";
|
import { DropdownData, IIngredient, IRecipe } from "../../schemas";
|
||||||
import { useSelectorContext } from "../../context/SelectorContext";
|
|
||||||
import IngredientSelector from "../derived/IngredientSelector";
|
import IngredientSelector from "../derived/IngredientSelector";
|
||||||
import Protect from "../../util/Protect";
|
import Protect from "../../util/Protect";
|
||||||
import API from "../../util/API";
|
import API from "../../util/API";
|
||||||
import { v4 } from "uuid";
|
import { v4 } from "uuid";
|
||||||
import RichText from "../ui/RichText";
|
import RichText from "../ui/RichText";
|
||||||
import { Autocomplete, TextField } from "@mui/material";
|
import { Autocomplete, TextField } from "@mui/material";
|
||||||
|
import { IngredientFieldData } from "../../util/types";
|
||||||
|
import Toast from "../ui/Toast";
|
||||||
|
|
||||||
const AddRecipe = () => {
|
export default function AddRecipe() {
|
||||||
|
/**********************************
|
||||||
|
* STATE AND CONTEXT
|
||||||
|
*********************************/
|
||||||
const { user, token } = useAuthContext();
|
const { user, token } = useAuthContext();
|
||||||
|
|
||||||
// received recipe data
|
// received recipe data
|
||||||
@@ -21,76 +25,30 @@ const AddRecipe = () => {
|
|||||||
const [measurements, setMeasurements] = useState<DropdownData[]>([]);
|
const [measurements, setMeasurements] = useState<DropdownData[]>([]);
|
||||||
const [courseData, setCourseData] = useState<DropdownData[]>([]);
|
const [courseData, setCourseData] = useState<DropdownData[]>([]);
|
||||||
const [ingredientFields, setIngredientFields] = useState<Array<JSX.Element>>([]);
|
const [ingredientFields, setIngredientFields] = useState<Array<JSX.Element>>([]);
|
||||||
|
const [ingredientFieldData, setIngredientFieldData] = useState<Array<IngredientFieldData>>([]);
|
||||||
const [optionCount, setOptionCount] = useState(0);
|
const [optionCount, setOptionCount] = useState(0);
|
||||||
|
|
||||||
// status reporting
|
// status reporting
|
||||||
const [toast, setToast] = useState(<></>)
|
const [toast, setToast] = useState(<></>)
|
||||||
|
|
||||||
// store all ingredients on page mount
|
/**********************************
|
||||||
useEffect(() => {
|
* CALLBACKS FOR CHILD COMPONENTS
|
||||||
token && (async() => {
|
*********************************/
|
||||||
const ingredients = new API.Ingredient(token);
|
// callback to retrieve state from ingredient rows
|
||||||
const _dropdowns = new API.Dropdowns(token);
|
const getRowState = useCallback((value: IngredientFieldData) => {
|
||||||
const ingredientList = await ingredients.getAll();
|
setIngredientFieldData((prev) => {
|
||||||
const measurementList = await _dropdowns.getAllMeasurements();
|
const newState = prev;
|
||||||
const courseList = await _dropdowns.getAllCourses();
|
newState[value.rowPosition] = value;
|
||||||
|
return newState;
|
||||||
if (ingredientList) {
|
});
|
||||||
setIngredients((prev) => [...prev, ...ingredientList]);
|
}, [ingredientFieldData])
|
||||||
}
|
|
||||||
|
|
||||||
if (measurementList) {
|
|
||||||
setMeasurements((prev) => [...prev, ...measurementList]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (courseList) {
|
|
||||||
setCourseData((prev) => [...prev, ...courseList]);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}, [token])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (ingredients.length && measurements.length) {
|
|
||||||
setIngredientFields([<IngredientSelector key={v4()} position={optionCount} ingredients={ingredients} units={measurements} destroy={destroySelector} />]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [ingredients, measurements])
|
|
||||||
|
|
||||||
// once user information is available, store it in recipe data
|
|
||||||
useEffect(() => {
|
|
||||||
user && setInput((prev: IRecipe) => {
|
|
||||||
return {
|
|
||||||
...prev,
|
|
||||||
authoruserid: user.id!
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, [user])
|
|
||||||
|
|
||||||
// submit handler
|
|
||||||
const handleCreate = async () => {
|
|
||||||
if (!token) return;
|
|
||||||
|
|
||||||
for (let field of Object.keys(input)) {
|
|
||||||
if (!input[field as keyof IRecipe]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const recipe = new API.Recipe(token);
|
|
||||||
const result = await recipe.post(input);
|
|
||||||
|
|
||||||
const recipeID = result.recipe.id;
|
|
||||||
const recipeName = result.recipe.name;
|
|
||||||
|
|
||||||
setToast(
|
|
||||||
<Card>
|
|
||||||
<p>Created recipe {recipeName} successfully!</p>
|
|
||||||
<p>View your new recipe <a href={`/recipe/${recipeID}`}>here!</a></p>
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// callback passed to each ingredient row to enable the row to be closed
|
||||||
const destroySelector = useCallback((position: number) => {
|
const destroySelector = useCallback((position: number) => {
|
||||||
|
setIngredientFieldData((prev) => {
|
||||||
|
return [...prev.filter(each => each.rowPosition !== position)];
|
||||||
|
})
|
||||||
|
|
||||||
setIngredientFields((prev) => {
|
setIngredientFields((prev) => {
|
||||||
const newState = new Array<JSX.Element>();
|
const newState = new Array<JSX.Element>();
|
||||||
|
|
||||||
@@ -106,15 +64,118 @@ const AddRecipe = () => {
|
|||||||
})
|
})
|
||||||
}, [ingredientFields]);
|
}, [ingredientFields]);
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* PAGE MOUNT BEHAVIOR AND SIDE EFFECTS
|
||||||
|
*********************************/
|
||||||
|
// store all ingredients on page mount
|
||||||
|
useEffect(() => {
|
||||||
|
token && (async() => {
|
||||||
|
const ingredients = new API.Ingredient(token);
|
||||||
|
const _dropdowns = new API.Dropdowns(token);
|
||||||
|
const ingredientList = await ingredients.getAll();
|
||||||
|
const measurementList = await _dropdowns.getAllMeasurements();
|
||||||
|
const courseList = await _dropdowns.getAllCourses();
|
||||||
|
|
||||||
|
function filterDuplicateEntries(receivedList: any[], previousState: any) {
|
||||||
|
let newEntries = [];
|
||||||
|
for (let each of receivedList) {
|
||||||
|
if (previousState.includes(each)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
newEntries.push(each);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ingredientList) {
|
||||||
|
setIngredients((prev) => {
|
||||||
|
let newEntries = filterDuplicateEntries(ingredientList, prev);
|
||||||
|
return [...prev, ...newEntries];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (measurementList) {
|
||||||
|
setMeasurements((prev) => {
|
||||||
|
let newEntries = filterDuplicateEntries(measurementList, prev);
|
||||||
|
return [...prev, ...newEntries];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (courseList) {
|
||||||
|
setCourseData((prev) => {
|
||||||
|
let newEntries = filterDuplicateEntries(courseList, prev);
|
||||||
|
return [...prev, ...newEntries];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}, [token])
|
||||||
|
|
||||||
|
// mount the ingredient selection section once dependencies have loaded
|
||||||
|
useEffect(() => {
|
||||||
|
if (ingredients.length && measurements.length) {
|
||||||
|
setIngredientFields([<IngredientSelector key={v4()} position={optionCount} ingredients={ingredients} units={measurements} getRowState={getRowState} destroy={destroySelector} />]);
|
||||||
|
}
|
||||||
|
}, [ingredients, measurements])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(ingredientFieldData);
|
||||||
|
}, [getRowState]);
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* PAGE SPECIFIC FUNCTIONS
|
||||||
|
*********************************/
|
||||||
|
// submit handler
|
||||||
|
const handleCreate = async () => {
|
||||||
|
if (!user || !token) return;
|
||||||
|
|
||||||
|
// inject current user id into recipe entry
|
||||||
|
setInput({ ...input, authoruserid: user.id! });
|
||||||
|
|
||||||
|
for (let field of Object.keys(input)) {
|
||||||
|
// account for an edge case where this state may not have been set yet
|
||||||
|
if (field == 'authoruserid' as keyof IRecipe) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input[field as keyof IRecipe]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const recipe = new API.Recipe(token);
|
||||||
|
const result = await recipe.post(input);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
const recipeID = result.recipe.id;
|
||||||
|
const recipeName = result.recipe.name;
|
||||||
|
|
||||||
|
setToast(
|
||||||
|
<Toast>
|
||||||
|
<p>Created recipe {recipeName} successfully!</p>
|
||||||
|
<p>View your new recipe <a href={`/recipe/${recipeID}`}>here!</a></p>
|
||||||
|
</Toast>
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
setToast(
|
||||||
|
<Toast variant="fail">
|
||||||
|
<p>Error creating your recipe</p>
|
||||||
|
<p>Please refresh the browser window and try again.</p>
|
||||||
|
</Toast>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// logic for inserting a new ingredient row
|
||||||
function handleNewOption() {
|
function handleNewOption() {
|
||||||
setIngredientFields((prev) => [...prev, <IngredientSelector position={optionCount + 1} key={v4()} ingredients={ingredients} units={measurements} destroy={destroySelector} />])
|
setIngredientFields((prev) => [...prev, <IngredientSelector position={optionCount + 1} key={v4()} ingredients={ingredients} units={measurements} getRowState={getRowState} destroy={destroySelector} />])
|
||||||
setOptionCount(prev => prev + 1);
|
setOptionCount(prev => prev + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
/**********************************
|
||||||
console.log(courseData);
|
* RENDER
|
||||||
}, [courseData])
|
*********************************/
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Protect redirect="/add-recipe">
|
<Protect redirect="/add-recipe">
|
||||||
<h1>Add a New Recipe</h1>
|
<h1>Add a New Recipe</h1>
|
||||||
@@ -143,6 +204,7 @@ const AddRecipe = () => {
|
|||||||
getOptionLabel={(option) => option.name}
|
getOptionLabel={(option) => option.name}
|
||||||
/>}
|
/>}
|
||||||
</div>
|
</div>
|
||||||
|
<Button onClick={() => console.log(ingredientFieldData)}>Ingredient Field Data</Button>
|
||||||
|
|
||||||
{ ingredients && (
|
{ ingredients && (
|
||||||
<>
|
<>
|
||||||
@@ -170,5 +232,3 @@ const AddRecipe = () => {
|
|||||||
</Protect>
|
</Protect>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AddRecipe;
|
|
||||||
19
client/src/components/ui/Toast.tsx
Normal file
19
client/src/components/ui/Toast.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { FC } from "react";
|
||||||
|
import "/src/sass/components/Toast.scss";
|
||||||
|
|
||||||
|
type StyleVariant = "success" | "fail" | "warning"
|
||||||
|
|
||||||
|
interface ToastProps {
|
||||||
|
children: JSX.Element | JSX.Element[]
|
||||||
|
variant?: StyleVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
const Toast: FC<ToastProps> = ({ children, variant = "success" }) => {
|
||||||
|
return (
|
||||||
|
<div className={`ui-component-toast toast-variant-${variant}`}>
|
||||||
|
{ children }
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Toast;
|
||||||
18
client/src/sass/components/Toast.scss
Normal file
18
client/src/sass/components/Toast.scss
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
.ui-component-toast {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
|
||||||
|
.success {
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fail {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
background-color: yellow;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ChangeEvent, ChangeEventHandler, Dispatch, FC, ReactNode, SetStateAction } from "react";
|
import { ChangeEvent, ChangeEventHandler, Dispatch, FC, ReactNode, SetStateAction } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { Form } from "../components/ui";
|
import { Form } from "../components/ui";
|
||||||
import { IUser } from "../schemas";
|
import { DropdownData, IIngredient, IUser } from "../schemas";
|
||||||
|
|
||||||
export interface PortalBase {
|
export interface PortalBase {
|
||||||
children?: ReactNode | ReactNode[]
|
children?: ReactNode | ReactNode[]
|
||||||
@@ -46,6 +46,14 @@ interface CheckboxProps {
|
|||||||
FormElement: typeof Form
|
FormElement: typeof Form
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IngredientFieldData {
|
||||||
|
rowPosition: number
|
||||||
|
quantity: number | undefined
|
||||||
|
measurement: DropdownData['name'] | undefined
|
||||||
|
ingredientSelection: IIngredient['name'] | IIngredient | undefined
|
||||||
|
ingredients: Array<IIngredient>
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type declaration for react-select dropdown options
|
* Type declaration for react-select dropdown options
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -12,12 +12,20 @@ import { friendRouter } from "./friend";
|
|||||||
import { cuisineRouter } from "./cuisine";
|
import { cuisineRouter } from "./cuisine";
|
||||||
import { courseRouter } from "./course";
|
import { courseRouter } from "./course";
|
||||||
import { dropdownValueRouter } from "./dropdownValues";
|
import { dropdownValueRouter } from "./dropdownValues";
|
||||||
|
import { IUser } from "../schemas";
|
||||||
|
import { User } from "../models/user";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
|
let REQUESTCOUNT = 0;
|
||||||
|
|
||||||
export const routes = async (app: Express) => {
|
export const routes = async (app: Express) => {
|
||||||
// unprotected routes
|
// simple request counting middleware
|
||||||
authRoute(app);
|
app.use('/', (req, res, next) => {
|
||||||
|
REQUESTCOUNT++;
|
||||||
|
console.log("count: ", REQUESTCOUNT);
|
||||||
|
next();
|
||||||
|
})
|
||||||
|
|
||||||
// middleware to check for auth on cookies on each request in protected routes
|
// middleware to check for auth on cookies on each request in protected routes
|
||||||
app.use('/app', async (req, res, next) => {
|
app.use('/app', async (req, res, next) => {
|
||||||
@@ -27,18 +35,28 @@ export const routes = async (app: Express) => {
|
|||||||
if (!token) {
|
if (!token) {
|
||||||
res.status(403).send("Unauthorized, did not receive token");
|
res.status(403).send("Unauthorized, did not receive token");
|
||||||
} else {
|
} else {
|
||||||
jwt.verify(token, process.env.SESSIONSECRET as string, (err, data) => {
|
jwt.verify(token, process.env.SESSIONSECRET as string, async (err, data: any) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
res.status(403).send(err);
|
res.status(403).send(err);
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
const userInstance = new User();
|
||||||
req.user = data.user;
|
const foundUser = await userInstance.getOneByID(data.user.id);
|
||||||
|
|
||||||
|
if (foundUser) {
|
||||||
|
req.user = data.user as IUser;
|
||||||
|
} else {
|
||||||
|
res.status(403).send("Unauthorized, user not registered");
|
||||||
|
}
|
||||||
|
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// unprotected routes
|
||||||
|
authRoute(app);
|
||||||
|
|
||||||
// protected routes
|
// protected routes
|
||||||
userRoute(app);
|
userRoute(app);
|
||||||
friendRouter(app);
|
friendRouter(app);
|
||||||
|
|||||||
Reference in New Issue
Block a user