Skip to content

Commit

Permalink
Search Saved Meals (#241)
Browse files Browse the repository at this point in the history
Search by entire search term input. Case insensitive.
  • Loading branch information
ZengLawrence authored Nov 16, 2024
1 parent 2537a23 commit 1637c7f
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 7 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "diet-diary",
"version": "2.29.8",
"version": "2.30.0",
"private": true,
"homepage": ".",
"dependencies": {
Expand Down
4 changes: 3 additions & 1 deletion src/app/reducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -19,5 +20,6 @@ export default combineReducers(
savedMeals,
showSavedMeals,
warning,
savedMealState,
}
)
1 change: 1 addition & 0 deletions src/app/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion src/components/saved-meal/SavedMealCardsOffcanvas.tsx
Original file line number Diff line number Diff line change
@@ -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";

Expand All @@ -16,8 +17,9 @@ function SavedMealCardsOffcanvas(props: Props) {
<Offcanvas.Title>Saved Meals</Offcanvas.Title>
</Offcanvas.Header>
<Offcanvas.Body>
<SearchTermInput />
<div>Total: {_.size(props.meals)}</div>
<SavedMealCards meals={props.meals}/>
<SavedMealCards meals={props.meals} />
</Offcanvas.Body>
</Offcanvas>
);
Expand Down
17 changes: 17 additions & 0 deletions src/components/saved-meal/SearchTermInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Form from "react-bootstrap/Form";

interface Props {
searchTerm: string;
update: (s: string) => void;
}

export const SearchTermInput = (props: Props) => (
<Form>
<Form.Control
type="text"
placeholder="Type to search"
value={props.searchTerm}
onChange={e => props.update(e.target.value)}
/>
</Form>
)
15 changes: 13 additions & 2 deletions src/features/saved-meal/SavedMealCardsOffcanvas.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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) => ({
Expand Down
15 changes: 15 additions & 0 deletions src/features/saved-meal/SearchTermInput.ts
Original file line number Diff line number Diff line change
@@ -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);
27 changes: 27 additions & 0 deletions src/features/saved-meal/savedMealStateSlice.ts
Original file line number Diff line number Diff line change
@@ -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<string>) {
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;

0 comments on commit 1637c7f

Please sign in to comment.