Skip to content

Commit

Permalink
Add field season
Browse files Browse the repository at this point in the history
  • Loading branch information
sepulzera committed Nov 14, 2024
1 parent ef9fbf1 commit 507e264
Show file tree
Hide file tree
Showing 35 changed files with 521 additions and 120 deletions.
2 changes: 2 additions & 0 deletions src/app/components/IntlMessagesCreator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useIntl } from 'react-intl';
import initCourses from './messages/Courses';
import initCuisines from './messages/Cuisines';
import initMeasurements from './messages/Measurements';
import initSeasons from './messages/Seasons';
import initTags from './messages/Tags';
import initValidations from './messages/Validations';

Expand All @@ -14,6 +15,7 @@ const IntlMessagesCreator = () => {
initCourses();
initCuisines();
initMeasurements();
initSeasons();
initTags();
initValidations();
}, [locale]);
Expand Down
22 changes: 22 additions & 0 deletions src/app/components/messages/Seasons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { defineMessages } from 'react-intl';

export default function initSeasons() {
defineMessages({
season_spring: {
id: 'season.Spring',
defaultMessage: 'Spring',
},
season_summer: {
id: 'season.Summer',
defaultMessage: 'Summer',
},
season_autumn: {
id: 'season.Autumn',
defaultMessage: 'Autumn',
},
season_winter: {
id: 'season.Winter',
defaultMessage: 'Winter',
},
});
}
24 changes: 20 additions & 4 deletions src/browse/components/SearchMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import '../css/filter.css';
import Icon from '../../common/components/Icon';
import P from '../../common/components/P';
import Chip from '../../common/components/Chip';
import Tooltip from '../../common/components/Tooltip';
import { CategoryCount, RatingCount } from '../store/FilterTypes';
import Filter from './Filter';

Expand All @@ -33,6 +34,11 @@ const messages = defineMessages({
description: 'Filter field rating',
defaultMessage: 'Ratings',
},
filter_season: {
id: 'filter.filter_season',
description: 'Filter field season',
defaultMessage: 'Seasons',
},
filter_tag: {
id: 'filter.filter_tag',
description: 'Filter field tag',
Expand Down Expand Up @@ -95,6 +101,7 @@ export interface ISearchMenuProps {
courses: Array<CategoryCount> | undefined;
cuisines: Array<CategoryCount> | undefined;
ratings: Array<RatingCount> | undefined;
seasons: Array<CategoryCount> | undefined;
tags: Array<CategoryCount> | undefined;

activeFilters: Record<string, string>;
Expand All @@ -106,7 +113,7 @@ export interface ISearchMenuProps {
}

const SearchMenu: React.FC<ISearchMenuProps> = ({
qs, courses, cuisines, ratings, tags,
qs, courses, cuisines, ratings, seasons, tags,
activeFilters, resetFilterUrl, openFilters, setOpenFilters,
buildUrl }: ISearchMenuProps) => {
const { formatMessage } = useIntl();
Expand Down Expand Up @@ -153,9 +160,11 @@ const SearchMenu: React.FC<ISearchMenuProps> = ({
{activeFiltersCount > 0 && (
<>
<Chip color='primary'>{activeFiltersCount}</Chip>
<Link className='clear-filter-desktop btn btn-transparent' to={resetFilterUrl} aria-label={formatMessage(messages.reset_filters)}>
<Icon icon='arrow-counterclockwise' variant='light' />
</Link>
<Tooltip id='clear-filter-desktop-btn-tooltip' tooltip={formatMessage(messages.reset_filters)}>
<Link className='clear-filter-desktop btn btn-transparent' to={resetFilterUrl} aria-label={formatMessage(messages.reset_filters)}>
<Icon icon='arrow-counterclockwise' variant='light' />
</Link>
</Tooltip>
</>
)}
</Card.Header>
Expand Down Expand Up @@ -190,6 +199,13 @@ const SearchMenu: React.FC<ISearchMenuProps> = ({
multiSelect
buildUrl = {buildUrl}
sort = 'off' />
<Filter
title = {formatMessage(messages.filter_season)}
qsTitle = 'season'
data = {seasons}
qs = {qs}
multiSelect
buildUrl = {buildUrl} />
<Filter
title = {formatMessage(messages.filter_tag)}
qsTitle = 'tag'
Expand Down
13 changes: 9 additions & 4 deletions src/browse/containers/SearchMenuContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ const SearchMenuContainer: React.FC<ISearchMenuContainerProps> = ({
qs, qsString, buildUrl }: ISearchMenuContainerProps) => {
const dispatch = useDispatch();

const courses = useSelector((state: RootState) => state.browse.browserFilter.courses.items);
const cuisines = useSelector((state: RootState) => state.browse.browserFilter.cuisines.items);
const ratings = useSelector((state: RootState) => state.browse.browserFilter.ratings.items);
const tags = useSelector((state: RootState) => state.browse.browserFilter.tags.items);
const courses = useSelector((state: RootState) => state.browse.browserFilter.filter_courses.items);
const cuisines = useSelector((state: RootState) => state.browse.browserFilter.filter_cuisines.items);
const ratings = useSelector((state: RootState) => state.browse.browserFilter.filter_ratings.items);
const seasons = useSelector((state: RootState) => state.browse.browserFilter.filter_seasons.items);
const tags = useSelector((state: RootState) => state.browse.browserFilter.filter_tags.items);

const [openFilters, setOpenFilters] = useState<Array<string>>(Object.keys(qs));

Expand All @@ -40,6 +41,9 @@ const SearchMenuContainer: React.FC<ISearchMenuContainerProps> = ({
if (openFilters.includes('rating') && ratings?.[qsString] == null) {
dispatchQueue.push(FilterActions.loadRatings(qsMergedDefaults));
}
if (openFilters.includes('season') && seasons?.[qsString] == null) {
dispatchQueue.push(FilterActions.loadSeasons(qsMergedDefaults));
}
if (openFilters.includes('tag') && tags?.[qsString] == null) {
dispatchQueue.push(FilterActions.loadTags(qsMergedDefaults));
}
Expand Down Expand Up @@ -74,6 +78,7 @@ const SearchMenuContainer: React.FC<ISearchMenuContainerProps> = ({
courses = {courses?.[qsString]}
cuisines = {cuisines?.[qsString]}
ratings = {ratings?.[qsString]}
seasons = {seasons?.[qsString]}
tags = {tags?.[qsString]}
qs = {qs}

Expand Down
13 changes: 10 additions & 3 deletions src/browse/css/filter.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
border: none;
}
.container.browser .sidebar .filter-group .list-group-title {
padding: 0 10px 0.25em 10px;
padding: 0 10px;
font-weight: bold;
margin-bottom: 0.25em;

min-height: 1.4em;
align-content: center;
}
.container.browser .sidebar .filter-group .list-group-title .chip {
padding: 0.25em 0.5em;
Expand Down Expand Up @@ -46,10 +50,12 @@ html[data-theme="dark"] .container.browser .sidebar .filter-group .list-group-ti
.container.browser .sidebar .filter-group .list-group-item:hover {
border: 0;
border-radius: 4px;
}
.container.browser .sidebar .filter-group .list-group-item:hover {
background-color: var(--hoverBg);
color: var(--primaryMain);
box-shadow: 0 0 0 1px var(--primaryText) inset;
}
.container.browser .sidebar .filter-group .list-group-item:focus {
box-shadow: 0 0 0 2px var(--primaryText) inset;
}
.container.browser .sidebar .filter-group .list-group-item.active {
background-color: transparent;
Expand Down Expand Up @@ -77,6 +83,7 @@ html[data-theme="dark"] .container.browser .sidebar .filter-group .list-group-ti

.container.browser .filter-panel .card-header h2 {
font-size: inherit;
font-weight: bold;
margin-bottom: 0;
}

Expand Down
21 changes: 20 additions & 1 deletion src/browse/store/FilterActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ACTION } from '../../common/store/ReduxHelper';
import { handleError } from '../../common/requestUtils';
import { objToSearchString } from '../../common/utility';
import { toBasicAction } from '../../common/store/redux';
import { BROWSE_FILTER_COURSE_STORE, BROWSE_FILTER_CUISINE_STORE, BROWSE_FILTER_RATING_STORE, BROWSE_FILTER_TAGS_STORE, FilterDispatch } from './FilterTypes';
import { BROWSE_FILTER_COURSE_STORE, BROWSE_FILTER_CUISINE_STORE, BROWSE_FILTER_RATING_STORE, BROWSE_FILTER_SEASON_STORE, BROWSE_FILTER_TAGS_STORE, FilterDispatch } from './FilterTypes';
import { extractSearchStringToFields } from './SearchActions';

const parsedFilter = (filters: Record<string, string>): Record<string, string> => {
Expand Down Expand Up @@ -72,6 +72,25 @@ export const loadRatings = (filter: Record<string, string>) => (dispatch: Filter
.catch(err => dispatch(handleError(err, BROWSE_FILTER_RATING_STORE)));
};

export const loadSeasons = (filters: Record<string, string>) => (dispatch: FilterDispatch) => {
dispatch({ ...toBasicAction(BROWSE_FILTER_SEASON_STORE, ACTION.LOADING) });

request()
.get(serverURLs.season_count)
.query(parsedFilter(filters))
.then(res => (
dispatch({
...toBasicAction(
BROWSE_FILTER_SEASON_STORE,
ACTION.GET_SUCCESS
),
id: objToSearchString(filters),
payload: res.body.results,
})
))
.catch(err => dispatch(handleError(err, BROWSE_FILTER_SEASON_STORE)));
};

export const loadTags = (filters: Record<string, string>) => (dispatch: FilterDispatch) => {
dispatch({ ...toBasicAction(BROWSE_FILTER_TAGS_STORE, ACTION.LOADING) });

Expand Down
4 changes: 3 additions & 1 deletion src/browse/store/FilterReducer.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { combineReducers, Reducer } from 'redux';

import ReduxHelper from '../../common/store/ReduxHelper';
import { BROWSE_FILTER_COURSE_STORE, BROWSE_FILTER_CUISINE_STORE, BROWSE_FILTER_RATING_STORE, BROWSE_FILTER_TAGS_STORE, CategoryCount, FilterAction, FilterState, RatingCount } from './FilterTypes';
import { BROWSE_FILTER_COURSE_STORE, BROWSE_FILTER_CUISINE_STORE, BROWSE_FILTER_RATING_STORE, BROWSE_FILTER_SEASON_STORE, BROWSE_FILTER_TAGS_STORE, CategoryCount, FilterAction, FilterState, RatingCount } from './FilterTypes';

const defaultCourseState = ReduxHelper.getMapReducerDefaultState<Array<CategoryCount>>(BROWSE_FILTER_COURSE_STORE);
const defaultCuisineState = ReduxHelper.getMapReducerDefaultState<Array<CategoryCount>>(BROWSE_FILTER_CUISINE_STORE);
const defaultRatingsState = ReduxHelper.getMapReducerDefaultState<Array<RatingCount>>(BROWSE_FILTER_RATING_STORE);
const defaultSeasonState = ReduxHelper.getMapReducerDefaultState<Array<CategoryCount>>(BROWSE_FILTER_SEASON_STORE);
const defaultTagsState = ReduxHelper.getMapReducerDefaultState<Array<RatingCount>>(BROWSE_FILTER_TAGS_STORE);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -20,6 +21,7 @@ const filters: Reducer<FilterState, FilterAction> = combineReducers({
[BROWSE_FILTER_COURSE_STORE]: createFilterWithNamedType(defaultCourseState),
[BROWSE_FILTER_CUISINE_STORE]: createFilterWithNamedType(defaultCuisineState),
[BROWSE_FILTER_RATING_STORE]: createFilterWithNamedType(defaultRatingsState),
[BROWSE_FILTER_SEASON_STORE]: createFilterWithNamedType(defaultSeasonState),
[BROWSE_FILTER_TAGS_STORE]: createFilterWithNamedType(defaultTagsState),
});

Expand Down
18 changes: 10 additions & 8 deletions src/browse/store/FilterTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,21 @@ export interface RatingCount {

export const BROWSE_FILTER_STORE = 'browserFilter';

export const BROWSE_FILTER_COURSE_STORE = 'courses';
export const BROWSE_FILTER_CUISINE_STORE = 'cuisines';
export const BROWSE_FILTER_RATING_STORE = 'ratings';
export const BROWSE_FILTER_TAGS_STORE = 'tags';
export const BROWSE_FILTER_COURSE_STORE = 'filter_courses';
export const BROWSE_FILTER_CUISINE_STORE = 'filter_cuisines';
export const BROWSE_FILTER_RATING_STORE = 'filter_ratings';
export const BROWSE_FILTER_SEASON_STORE = 'filter_seasons';
export const BROWSE_FILTER_TAGS_STORE = 'filter_tags';

export type CategoryCountState = MapReducerType<Array<CategoryCount>>;
export type RatingCountState = MapReducerType<Array<RatingCount>>;

export type FilterAction = GenericMapReducerAction<Array<CategoryCount>> | GenericMapReducerAction<Array<RatingCount>>;
export type FilterDispatch = ReduxDispatch<FilterAction>;
export interface FilterState {
courses: CategoryCountState;
cuisines: CategoryCountState;
ratings: RatingCountState;
tags: CategoryCountState;
filter_courses: CategoryCountState;
filter_cuisines: CategoryCountState;
filter_ratings: RatingCountState;
filter_seasons: CategoryCountState;
filter_tags: CategoryCountState;
}
7 changes: 4 additions & 3 deletions src/browse/store/SearchActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import { BROWSER_SEARCH_STORE, SearchDispatch, SearchResultDto, toSearchResult }
import { parseCSV } from '../utilts/utility';

const FILTER_QUERY_PARAMETER_MAPPING: Record<string, string> = {
cuisine: 'cuisine__slug',
author: 'author__username',
course: 'course__slug',
cuisine: 'cuisine__slug',
season: 'season__slug',
tag: 'tag__slug',
author: 'author__username',
};

const FIELDS = ['author', 'cuisine', 'course', 'directions', 'info', 'ordering', 'rating', 'source', 'tag', 'title'];
const FIELDS = ['author', 'course', 'cuisine', 'directions', 'info', 'ordering', 'rating', 'season', 'source', 'tag', 'title'];

export function extractSearchStringToFields(filters: Record<string, string>): Record<string, string> {
if (!filters.search || !filters.search.includes(':')) return filters;
Expand Down
8 changes: 5 additions & 3 deletions src/common/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ export const serverURLs = {
revoke_token: `${apiUrl}/accounts/revoke-auth-token/`,
browse: `${apiUrl}/recipe/recipes/?fields=id,slug,title,pub_date,rating,rating_count,tags,photo_thumbnail,info`,
mini_browse: `${apiUrl}/recipe/mini-browse/?fields=id,slug,title,pub_date,rating,rating_count,tags,photo_thumbnail,info`,
cuisine_count: `${apiUrl}/recipe_groups/cuisine-count/`,
cuisine: `${apiUrl}/recipe_groups/cuisine/`,
course_count: `${apiUrl}/recipe_groups/course-count/`,
course: `${apiUrl}/recipe_groups/course/`,
course_count: `${apiUrl}/recipe_groups/course-count/`,
cuisine: `${apiUrl}/recipe_groups/cuisine/`,
cuisine_count: `${apiUrl}/recipe_groups/cuisine-count/`,
season: `${apiUrl}/recipe_groups/season/`,
season_count: `${apiUrl}/recipe_groups/season-count/`,
ratings: `${apiUrl}/rating/rating/`,
rating_count: `${apiUrl}/rating/rating-count/`,
tag: `${apiUrl}/recipe_groups/tag/`,
Expand Down
58 changes: 47 additions & 11 deletions src/demo/store/browse.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/* eslint-disable func-names */

import { CategoryCount, RatingCount } from '../../browse/store/FilterTypes';
import { CourseDto, CuisineDto, RecipeDto, TagDto } from '../../recipe/store/RecipeTypes';
import { CourseDto, CuisineDto, RecipeDto, SeasonDto, TagDto } from '../../recipe/store/RecipeTypes';
import { demoCourses } from './courses';
import { demoCuisines } from './cuisines';
import { demoRecipes } from './recipe';
import { demoSeasons } from './seasons';
import { demoFindSearchRecipes } from './search';
import { demoGetAllTags } from './tags';
import { ObjectIterator, toQueryParams } from './utils';
Expand Down Expand Up @@ -37,6 +38,41 @@ export const ratingCountConfig = {
},
};

export const courseCountConfig = {
pattern: '(.*)/recipe_groups/course-count/(.*)',
fixtures: function (match: Array<string>) {
// console.log(`fixtures running for courseCountConfig. match=${JSON.stringify(match)}`);

if (match.length < 3) return {};
const queryParams: URLSearchParams = toQueryParams(match[2]);
const resultRecipes: Array<RecipeDto> = demoFindSearchRecipes(demoRecipes, queryParams);

const allCourses: Array<CourseDto> = demoCourses;

const courseCounts: Array<CategoryCount> = [];
allCourses.forEach(c => {
courseCounts.push({
id: c.id,
total: resultRecipes.filter(rec => rec.course?.title === c.title).length,
title: c.title,
slug: c.title,
});
});

const result: ObjectIterator<CategoryCount> = {
count: courseCounts.length,
next: null,
previous: null,
results: courseCounts,
};

return result;
},
get: function (_match: Array<string>, data: Record<string, string | number | boolean>) {
return { body : data };
},
};

export const cuisineCountConfig = {
pattern: '(.*)/recipe_groups/cuisine-count/(.*)',
fixtures: function (match: Array<string>) {
Expand Down Expand Up @@ -72,32 +108,32 @@ export const cuisineCountConfig = {
},
};

export const courseCountConfig = {
pattern: '(.*)/recipe_groups/course-count/(.*)',
export const seasonCountConfig = {
pattern: '(.*)/recipe_groups/season-count/(.*)',
fixtures: function (match: Array<string>) {
// console.log(`fixtures running for courseCountConfig. match=${JSON.stringify(match)}`);
// console.log(`fixtures running for seasonCountConfig. match=${JSON.stringify(match)}`);

if (match.length < 3) return {};
const queryParams: URLSearchParams = toQueryParams(match[2]);
const resultRecipes: Array<RecipeDto> = demoFindSearchRecipes(demoRecipes, queryParams);

const allCourses: Array<CourseDto> = demoCourses;
const allSeasons: Array<SeasonDto> = demoSeasons;

const courseCounts: Array<CategoryCount> = [];
allCourses.forEach(c => {
courseCounts.push({
const seasonCounts: Array<CategoryCount> = [];
allSeasons.forEach(c => {
seasonCounts.push({
id: c.id,
total: resultRecipes.filter(rec => rec.course?.title === c.title).length,
total: resultRecipes.filter(rec => rec.season?.title === c.title).length,
title: c.title,
slug: c.title,
});
});

const result: ObjectIterator<CategoryCount> = {
count: courseCounts.length,
count: seasonCounts.length,
next: null,
previous: null,
results: courseCounts,
results: seasonCounts,
};

return result;
Expand Down
Loading

0 comments on commit 507e264

Please sign in to comment.