diff --git a/package.json b/package.json
index 52254b0..3710004 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"@fontsource/roboto": "^5.0.0",
"@mui/icons-material": "^5.11.16",
"@mui/material": "^5.13.1",
+ "fuse.js": "^6.6.2",
"gh-pages": "^5.0.0",
"i18next": "^23.2.3",
"i18next-browser-languagedetector": "^7.1.0",
diff --git a/src/App.tsx b/src/App.tsx
index 5101eea..7897427 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,40 +1,45 @@
import type { FoodList } from "./types/food";
-import { useState } from "react";
+import { useState, useEffect } from "react";
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import { currentMonth } from "./utils/utils";
import fetchData from "./loadData";
+import { FoodDBProvider } from "./contexts/FoodDB";
import FoodOfTheMonth from "./routes/FoodOfTheMonth";
import FoodPage from "./routes/FoodPage";
import Layout from "./routes/Layout";
import { NotFound } from "./routes/NotFound";
export default function App() {
- const [food, setFood] = useState([] as FoodList);
+ const [ food, setFood ] = useState([] as FoodList)
- if (food.length === 0) fetchData(setFood, `ITALIA-fruits-and-veggies.csv`);
+ useEffect(() => {
+ fetchData(setFood, "ITALIA-fruits-and-veggies.csv")
+ },[])
return food.length > 0 ? (
-
-
-
- } />
- }>
- }
- />
- }
- />
- }
- />
-
-
-
-
+
+
+
+
+ } />
+ }>
+ }
+ />
+ }
+ />
+ }
+ />
+
+
+
+
+
) : (
not loaded
);
diff --git a/src/components/HeaderBar.tsx b/src/components/HeaderBar.tsx
index 193f94a..7b51e8c 100644
--- a/src/components/HeaderBar.tsx
+++ b/src/components/HeaderBar.tsx
@@ -1,6 +1,5 @@
-import type { FoodList } from "../types/food";
-
-import { useRef, useEffect } from "react";
+import type { FoodList, FoodObject } from "../types/food";
+import i18next from "i18next";
import {
AppBar,
styled,
@@ -13,6 +12,8 @@ import MenuIcon from "@mui/icons-material/Menu";
import SearchIcon from "@mui/icons-material/Search";
import { useTranslation } from "react-i18next";
import { ArrowBackIosNew } from "@mui/icons-material";
+import Fuse from 'fuse.js'
+import { useRef, useEffect } from "react"
import { useNavigate, useLocation } from "react-router-dom";
type Props = {
@@ -42,11 +43,22 @@ export default function HeaderBar(props: Props) {
if (query.current.value === "") {
return food;
}
- return food.filter((item) => {
- return item.description[0].name
- .toLowerCase()
- .includes(query.current.value.trim().toLowerCase());
- });
+
+ // TODO: Load index pregenerated
+ const options = {
+ threshold: 0.3,
+ keys: [
+ { name: 'name-en', getFn: (food:FoodObject) => food.description[0].name },
+ { name: 'name-it', getFn: (food:FoodObject) => food.description[1].name }
+ ]
+ }
+
+ const fuse = new Fuse(food, options)
+ const searchText = query.current.value.trim().toLowerCase()
+ const searchLanguage:{[lang:string]:string} = {}
+ searchLanguage["name-" + i18next.language] = searchText
+
+ return fuse.search(searchLanguage).map((i) => i.item)
};
const Search = styled("div")(({ theme }) => ({
diff --git a/src/components/RenderFoods.tsx b/src/components/RenderFoods.tsx
index beca466..9c9626c 100644
--- a/src/components/RenderFoods.tsx
+++ b/src/components/RenderFoods.tsx
@@ -1,4 +1,3 @@
-
import type { FoodList } from "../types/food";
import Item from "./Item";
import { Box, Stack } from "@mui/material";
@@ -8,6 +7,10 @@ interface RenderFoodProps {
foodList: FoodList
}
+interface RenderFoodProps {
+ foodList: FoodList
+}
+
//render the grid of foods
const RenderFoods:FunctionComponent = (props:RenderFoodProps) => {
const foodList = props.foodList
diff --git a/src/contexts/FoodDB/index.tsx b/src/contexts/FoodDB/index.tsx
new file mode 100644
index 0000000..76e0389
--- /dev/null
+++ b/src/contexts/FoodDB/index.tsx
@@ -0,0 +1,21 @@
+import React from "react"
+import { Dispatch } from "react"
+import { reducer } from "./reducer"
+import { FoodList } from "../../types/food"
+
+
+export const FoodDBContext = React.createContext<[FoodList, Dispatch]>([
+ [] as FoodList,
+ () => null
+])
+
+
+export const FoodDBProvider = ({ children, initialState }:{ children: React.ReactNode, initialState: FoodList }) => {
+ const [state, dispatch] = React.useReducer(reducer, initialState)
+
+ return (
+
+ { children }
+
+ )
+}
diff --git a/src/contexts/FoodDB/reducer.tsx b/src/contexts/FoodDB/reducer.tsx
new file mode 100644
index 0000000..ab40d89
--- /dev/null
+++ b/src/contexts/FoodDB/reducer.tsx
@@ -0,0 +1,17 @@
+import { FoodList } from "../../types/food"
+
+export interface IFoodDBState {
+ foodDB: FoodList
+}
+
+export const reducer:React.Reducer = (state, action) => {
+ switch (action.type) {
+ case "initDB":
+ return { ...state, foodDB: action.payload };
+
+ default:
+ return state
+ }
+}
+
+export const initialState = { foodDB: {} }
diff --git a/src/routes/FoodOfTheMonth.tsx b/src/routes/FoodOfTheMonth.tsx
index 1897bc7..ca1d648 100644
--- a/src/routes/FoodOfTheMonth.tsx
+++ b/src/routes/FoodOfTheMonth.tsx
@@ -14,8 +14,12 @@ import {
import { ArrowLeft, ArrowRight } from "@mui/icons-material";
import RenderFoods from "../components/RenderFoods";
import { useTranslation } from "react-i18next";
+import { FoodDBContext } from "../contexts/FoodDB"
+import React from "react"
+
export default function FoodOfTheMonth({ food }: { food: FoodList }) {
+ const [food, _] = React.useContext(FoodDBContext)
const { selectedMonthNum } = useParams();
const { t } = useTranslation();
const monthNum = Number(selectedMonthNum) - 1;
@@ -24,6 +28,7 @@ export default function FoodOfTheMonth({ food }: { food: FoodList }) {
Veggies: [],
};
+
//month change arrows function
const navigate = useNavigate();
useEffect(() => {
@@ -37,6 +42,7 @@ export default function FoodOfTheMonth({ food }: { food: FoodList }) {
if (item.season[monthNum] === true) monthFood.push(item);
});
+
//filters the fruits and vegetables
const filterFoodType = (monthFood: FoodList, foodCategory: FoodCategory) =>
monthFood.filter((item) => item.category === foodCategory);
@@ -106,6 +112,7 @@ export default function FoodOfTheMonth({ food }: { food: FoodList }) {
/>
+
);
}
diff --git a/src/routes/FoodPage.tsx b/src/routes/FoodPage.tsx
index 24690bb..c26d66c 100644
--- a/src/routes/FoodPage.tsx
+++ b/src/routes/FoodPage.tsx
@@ -1,12 +1,14 @@
-import type { FoodList } from "../types/food";
import { currentMonth } from "../utils/utils";
import { useParams, useNavigate, Link } from "react-router-dom";
import { useEffect } from "react";
import { Box, Typography, Stack } from "@mui/material";
import { styled } from "@mui/material/styles";
import { useTranslation } from "react-i18next";
+import { FoodDBContext } from "../contexts/FoodDB"
+import React from "react"
-export default function FoodPage({ food }: { food: FoodList }) {
+export default function FoodPage() {
+ const [ food, _ ] = React.useContext(FoodDBContext)
const { id } = useParams();
const { t } = useTranslation();
diff --git a/yarn.lock b/yarn.lock
index a3849df..152fd30 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2343,6 +2343,11 @@ function-bind@^1.1.1:
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+fuse.js@^6.6.2:
+ version "6.6.2"
+ resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-6.6.2.tgz#fe463fed4b98c0226ac3da2856a415576dc9a111"
+ integrity sha512-cJaJkxCCxC8qIIcPBF9yGxY0W/tVZS3uEISDxhYIdtk8OL93pe+6Zj7LjCqVV4dzbqcriOZ+kQ/NE4RXZHsIGA==
+
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz"