diff --git a/package-lock.json b/package-lock.json index 6d5623ee..d519cba8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "diet-diary", - "version": "2.29.8", + "version": "2.30.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "diet-diary", - "version": "2.29.8", + "version": "2.30.0", "workspaces": [ "packages/parser" ], diff --git a/package.json b/package.json index 6a448fe4..9b626f7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "diet-diary", - "version": "2.29.8", + "version": "2.30.0", "private": true, "homepage": ".", "dependencies": { diff --git a/src/app/reducers.ts b/src/app/reducers.ts index 83673f8f..61a1054a 100644 --- a/src/app/reducers.ts +++ b/src/app/reducers.ts @@ -6,7 +6,8 @@ import summaryType from "../features/day-page/summaryTypeSlice"; import targetState from "../features/target/targetStateSlice"; import savedMeals from "../features/saved-meal/savedMealsSlice"; import showSavedMeals from "../features/day-page/showSavedMealsSlice"; -import warning from "../features/warning/warningSlice" +import warning from "../features/warning/warningSlice"; +import savedMealState from "../features/saved-meal/savedMealStateSlice"; export default combineReducers( @@ -19,5 +20,6 @@ export default combineReducers( savedMeals, showSavedMeals, warning, + savedMealState, } ) diff --git a/src/app/selectors.ts b/src/app/selectors.ts index 4f406ca8..0ae885e3 100644 --- a/src/app/selectors.ts +++ b/src/app/selectors.ts @@ -12,6 +12,7 @@ export const targetStateSelector = (state: RootState) => state.targetState; export const savedMealsSelector = (state: RootState) => state.savedMeals; export const showSavedMealsSelector = (state: RootState) => state.showSavedMeals; export const warningSelector = (state: RootState) => state.warning; +export const savedMealStateSelector = (state: RootState) => state.savedMealState; export const targetSelector = createSelector( targetStateSelector, diff --git a/src/components/saved-meal/SavedMealCardsOffcanvas.tsx b/src/components/saved-meal/SavedMealCardsOffcanvas.tsx index d29e3f27..ccf9c829 100644 --- a/src/components/saved-meal/SavedMealCardsOffcanvas.tsx +++ b/src/components/saved-meal/SavedMealCardsOffcanvas.tsx @@ -1,5 +1,6 @@ import _ from "lodash"; import Offcanvas from "react-bootstrap/Offcanvas"; +import SearchTermInput from "../../features/saved-meal/SearchTermInput"; import { Food } from "../../model/Food"; import { SavedMealCards } from "./SavedMealCards"; @@ -16,8 +17,9 @@ function SavedMealCardsOffcanvas(props: Props) { Saved Meals +
Total: {_.size(props.meals)}
- +
); diff --git a/src/components/saved-meal/SearchTermInput.tsx b/src/components/saved-meal/SearchTermInput.tsx new file mode 100644 index 00000000..e322db1d --- /dev/null +++ b/src/components/saved-meal/SearchTermInput.tsx @@ -0,0 +1,17 @@ +import Form from "react-bootstrap/Form"; + +interface Props { + searchTerm: string; + update: (s: string) => void; +} + +export const SearchTermInput = (props: Props) => ( +
+ props.update(e.target.value)} + /> + +) diff --git a/src/features/saved-meal/SavedMealCardsOffcanvas.ts b/src/features/saved-meal/SavedMealCardsOffcanvas.ts index 4ad5b806..e000c752 100644 --- a/src/features/saved-meal/SavedMealCardsOffcanvas.ts +++ b/src/features/saved-meal/SavedMealCardsOffcanvas.ts @@ -1,6 +1,6 @@ import _ from "lodash"; import { connect } from "react-redux"; -import { savedMealsSelector, showSavedMealsSelector } from "../../app/selectors"; +import { savedMealsSelector, savedMealStateSelector, showSavedMealsSelector } from "../../app/selectors"; import { AppDispatch, RootState } from "../../app/store"; import SavedMealCardsOffcanvas from "../../components/saved-meal/SavedMealCardsOffcanvas"; import { Food } from "../../model/Food"; @@ -10,9 +10,20 @@ function indexedMeals(meals: { foods: Food[] }[]) { return _.map(meals, (m, index) => ({ index: index, foods: m.foods })); } +function hasTerm(meal: { foods: Food[] }, term: string): boolean { + const found = _.find(meal.foods, food => _.lowerCase(food.description).includes(term)); + return found ? true : false; +} + +function filterMeals(state: RootState) { + const searchTerm = _.lowerCase(savedMealStateSelector(state).searchTerm); + const meals = indexedMeals(savedMealsSelector(state)); + return _.filter(meals, m => hasTerm(m, searchTerm)); +} + const mapStateToProps = (state: RootState) => ({ show: showSavedMealsSelector(state), - meals: indexedMeals(savedMealsSelector(state)), + meals: filterMeals(state), }) const mapDispatchToProps = (dispatch: AppDispatch) => ({ diff --git a/src/features/saved-meal/SearchTermInput.ts b/src/features/saved-meal/SearchTermInput.ts new file mode 100644 index 00000000..a8463224 --- /dev/null +++ b/src/features/saved-meal/SearchTermInput.ts @@ -0,0 +1,15 @@ +import { connect } from "react-redux"; +import { savedMealStateSelector } from "../../app/selectors"; +import { AppDispatch, RootState } from "../../app/store"; +import { SearchTermInput } from "../../components/saved-meal/SearchTermInput"; +import { updateSearchTerm } from "./savedMealStateSlice"; + +const mapStateToProps = (state: RootState) => ({ + searchTerm: savedMealStateSelector(state).searchTerm, +}) + +const mapDispatchToProps = (dispatch: AppDispatch) => ({ + update: (newTerm: string) => dispatch(updateSearchTerm(newTerm)), +}) + +export default connect(mapStateToProps, mapDispatchToProps)(SearchTermInput); \ No newline at end of file diff --git a/src/features/saved-meal/savedMealStateSlice.ts b/src/features/saved-meal/savedMealStateSlice.ts new file mode 100644 index 00000000..c9adc375 --- /dev/null +++ b/src/features/saved-meal/savedMealStateSlice.ts @@ -0,0 +1,27 @@ +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; +import { addSavedMeal } from "../day-page/mealStatesSlice"; +import { hide } from "../day-page/showSavedMealsSlice"; + +interface SavedMealState { + searchTerm: string; +} + +const savedMealStateSlice = createSlice({ + name: "searchTerm", + initialState: { searchTerm: "" } as SavedMealState, + reducers: { + updateSearchTerm(state, action: PayloadAction) { + state.searchTerm = action.payload; + }, + }, + extraReducers: (builder) => { + builder.addCase(addSavedMeal, (state) => { + state.searchTerm = ""; + }).addCase(hide, (state) => { + state.searchTerm = ""; + }); + } +}); + +export const { updateSearchTerm } = savedMealStateSlice.actions; +export default savedMealStateSlice.reducer; \ No newline at end of file