Optimize servings control
This commit is contained in:
parent
e6ea18bef8
commit
f980d4d86d
4 changed files with 220 additions and 166 deletions
|
|
@ -1,9 +1,9 @@
|
|||
import { useEffect, useState } from "react"
|
||||
import {useEffect, useState} from "react"
|
||||
import RecipeListItem from "./RecipeListItem"
|
||||
import type { RecipeModel } from "../../models/RecipeModel"
|
||||
import { fetchRecipeList } from "../../api/points/CompactRecipePoint"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
import { getRecipeAddUrl, getRecipeDetailUrl, getRecipeListUrl } from "../../routes"
|
||||
import type {RecipeModel} from "../../models/RecipeModel"
|
||||
import {fetchRecipeList} from "../../api/points/CompactRecipePoint"
|
||||
import {useNavigate} from "react-router-dom"
|
||||
import {getRecipeAddUrl, getRecipeDetailUrl, getRecipeListUrl} from "../../routes"
|
||||
import RecipeListToolbar from "./RecipeListToolbar"
|
||||
|
||||
/**
|
||||
|
|
@ -12,58 +12,61 @@ import RecipeListToolbar from "./RecipeListToolbar"
|
|||
*/
|
||||
export default function RecipeListPage() {
|
||||
|
||||
const navigate = useNavigate()
|
||||
const [recipeList, setRecipeList] = useState<RecipeModel[]|null>(null)
|
||||
const [searchString, setSearchString] = useState<string>("")
|
||||
// load recipes once on render and whenever search string changes
|
||||
// @todo add delay. Only reload list if the search string hasn't changed for ~200 ms
|
||||
const navigate = useNavigate()
|
||||
const [recipeList, setRecipeList] = useState<RecipeModel[] | null>(null)
|
||||
const [searchString, setSearchString] = useState<string>("")
|
||||
// load recipes once on render and whenever search string changes
|
||||
// @todo add delay. Only reload list if the search string hasn't changed for ~200 ms
|
||||
useEffect(() => {
|
||||
console.log("loading recipe list with searchString", searchString)
|
||||
const loadRecipeList = async () => {
|
||||
try {
|
||||
// Fetch recipe list
|
||||
const data = await fetchRecipeList(searchString)
|
||||
// @todo add and use compact recipe mapper
|
||||
setRecipeList(data)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
loadRecipeList()
|
||||
}, [,searchString])
|
||||
|
||||
const handleAdd = () => {
|
||||
navigate(getRecipeAddUrl())
|
||||
}
|
||||
console.log("loading recipe list with searchString", searchString)
|
||||
const loadRecipeList = async () => {
|
||||
try {
|
||||
// Fetch recipe list
|
||||
const data = await fetchRecipeList(searchString)
|
||||
// @todo add and use compact recipe mapper
|
||||
setRecipeList(data)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
loadRecipeList()
|
||||
}, [, searchString])
|
||||
|
||||
if(!recipeList) { return <div>Loading!</div>}
|
||||
return (
|
||||
/*Container spanning entire screen used to center content horizontally */
|
||||
<div className="app-bg">
|
||||
{/* Container defining the maximum width of the content */}
|
||||
<div className="content-container">
|
||||
{/* Header - remains in position when scrolling */}
|
||||
<div className="sticky bg-gray-100 top-0 left-0 right-0 pb-4 border-b-2 border-gray-300">
|
||||
<h1 className="content-title">Recipes</h1>
|
||||
<RecipeListToolbar
|
||||
onAddClicked={handleAdd}
|
||||
onSearchStringChanged={setSearchString}
|
||||
numberOfRecipes={recipeList.length}
|
||||
/>
|
||||
const handleAdd = () => {
|
||||
navigate(getRecipeAddUrl())
|
||||
}
|
||||
|
||||
if (!recipeList) {
|
||||
return <div>Loading!</div>
|
||||
}
|
||||
return (
|
||||
/*Container spanning entire screen used to center content horizontally */
|
||||
<div className="app-bg">
|
||||
{/* Container defining the maximum width of the content */}
|
||||
<div className="content-container">
|
||||
{/* Header - remains in position when scrolling */}
|
||||
<div className="sticky-header">
|
||||
<h1 className="content-title">Recipes</h1>
|
||||
<RecipeListToolbar
|
||||
onAddClicked={handleAdd}
|
||||
onSearchStringChanged={setSearchString}
|
||||
numberOfRecipes={recipeList.length}
|
||||
/>
|
||||
</div>
|
||||
{/*Content - List of recipe cards */}
|
||||
<div className="w-full pt-4">
|
||||
<div
|
||||
className="grid gap-6 grid-cols-[repeat(auto-fit,minmax(220px,auto))] max-w-6xl mx-auto justify-center">
|
||||
{recipeList.map((recipe) => (
|
||||
<RecipeListItem
|
||||
key={recipe.id}
|
||||
title={recipe.title}
|
||||
targetPath={recipe.id !== undefined ? getRecipeDetailUrl(recipe.id) : getRecipeListUrl()} // @todo proper error handling
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/*Content - List of recipe cards */}
|
||||
<div className="w-full pt-4">
|
||||
<div className="grid gap-6 grid-cols-[repeat(auto-fit,minmax(220px,auto))] max-w-6xl mx-auto justify-center">
|
||||
{recipeList.map((recipe) => (
|
||||
<RecipeListItem
|
||||
key={recipe.id}
|
||||
title={recipe.title}
|
||||
targetPath={recipe.id !== undefined ? getRecipeDetailUrl(recipe.id) : getRecipeListUrl()} // @todo proper error handling
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue