Skip to content

Commit

Permalink
Add zoom level and selected view to context
Browse files Browse the repository at this point in the history
Signed-off-by: Cintia Sanchez Garcia <[email protected]>
  • Loading branch information
cynthia-sg committed Aug 30, 2023
1 parent 6d5bd97 commit 13c9d16
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 63 deletions.
70 changes: 67 additions & 3 deletions web/src/layout/context/AppContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { createContext, useCallback, useMemo, useState } from 'react';
import { createContext, useCallback, useEffect, useMemo, useState } from 'react';
import { useSearchParams } from 'react-router-dom';

import { DEFAULT_VIEW_MODE, DEFAULT_ZOOM_LEVELS, VIEW_MODE_PARAM, ZOOM_LEVELS } from '../../data';
import { useBreakpointDetect } from '../../hooks/useBreakpointDetect';
import { Breakpoint, ViewMode } from '../../types';
import itemsDataGetter from '../../utils/itemsDataGetter';

export type FullDataProps = {
Expand All @@ -14,9 +18,19 @@ export type ZoomProps = {
visibleZoomView?: ActiveSection;
};

export type ViewModeProps = {
selectedViewMode?: ViewMode;
};

export type ZoomLevelProps = {
zoomLevel: number;
};

export type ActionsContext = {
updateActiveItemId: (itemId?: string) => void;
updateActiveSection: (activeSection?: ActiveSection) => void;
updateViewMode: (viewMode: ViewMode) => void;
updateZoomLevel: (level: number) => void;
};

export interface ActiveSection {
Expand All @@ -32,12 +46,22 @@ interface Props {
export const FullDataContext = createContext<FullDataProps | null>(null);
export const ItemContext = createContext<ItemProps | null>(null);
export const ZoomContext = createContext<ZoomProps | null>(null);
export const ViewModeContext = createContext<ViewModeProps | null>(null);
export const ZoomLevelContext = createContext<ZoomLevelProps | null>(null);
export const AppActionsContext = createContext<ActionsContext | null>(null);

const AppContextProvider = (props: Props) => {
const [searchParams] = useSearchParams();
const point = useBreakpointDetect();
const [visibleItemId, setVisibleItemId] = useState<string | undefined>();
const [visibleZoomView, setVisibleZoomView] = useState<ActiveSection | undefined>();
const [fullDataReady, setFullDataReady] = useState<boolean>(false);
const [selectedViewMode, setSelectedViewMode] = useState<ViewMode>(
(searchParams.get(VIEW_MODE_PARAM) as ViewMode) || DEFAULT_VIEW_MODE
);
const [zoomLevel, setZoomLevel] = useState<number>(
point ? DEFAULT_ZOOM_LEVELS[point] : DEFAULT_ZOOM_LEVELS[Breakpoint.XL]
);

const updateActiveItemId = useCallback((id?: string) => {
setVisibleItemId(id);
Expand All @@ -47,6 +71,26 @@ const AppContextProvider = (props: Props) => {
setVisibleZoomView(section);
}, []);

const updateViewMode = useCallback((viewMode: ViewMode) => {
setSelectedViewMode(viewMode);
}, []);

const updateZoomLevel = useCallback((level: number) => {
setZoomLevel(level);

// Update card-size variable depending on zoom level
const bodyStyles = document.body.style;
bodyStyles.setProperty('--card-size-width', `${ZOOM_LEVELS[level][0]}px`);
bodyStyles.setProperty('--card-size-height', `${ZOOM_LEVELS[level][1]}px`);
}, []);

useEffect(() => {
if (point) {
updateZoomLevel(DEFAULT_ZOOM_LEVELS[point]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [point]);

const fullDataValue = useMemo(
() => ({
fullDataReady,
Expand All @@ -68,12 +112,28 @@ const AppContextProvider = (props: Props) => {
[visibleZoomView]
);

const viewModeValue = useMemo(
() => ({
selectedViewMode,
}),
[selectedViewMode]
);

const zoomLevelValue = useMemo(
() => ({
zoomLevel,
}),
[zoomLevel]
);

const contextActionsValue = useMemo(
() => ({
updateActiveItemId,
updateActiveSection,
updateViewMode,
updateZoomLevel,
}),
[updateActiveItemId, updateActiveSection]
[updateActiveItemId, updateActiveSection, updateViewMode, updateZoomLevel]
);

itemsDataGetter.subscribe({
Expand All @@ -86,7 +146,11 @@ const AppContextProvider = (props: Props) => {
<FullDataContext.Provider value={fullDataValue}>
<ItemContext.Provider value={itemValue}>
<ZoomContext.Provider value={zoomValue}>
<AppActionsContext.Provider value={contextActionsValue}>{props.children}</AppActionsContext.Provider>
<ViewModeContext.Provider value={viewModeValue}>
<ZoomLevelContext.Provider value={zoomLevelValue}>
<AppActionsContext.Provider value={contextActionsValue}>{props.children}</AppActionsContext.Provider>
</ZoomLevelContext.Provider>
</ViewModeContext.Provider>
</ZoomContext.Provider>
</ItemContext.Provider>
</FullDataContext.Provider>
Expand Down
14 changes: 7 additions & 7 deletions web/src/layout/explore/Content.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
import { memo } from 'react';
import { memo, useContext } from 'react';

import { ViewMode } from '../../types';
import arePropsEqual from '../../utils/areEqualProps';
import { CategoriesData } from '../../utils/prepareData';
import { ViewModeContext, ViewModeProps } from '../context/AppContext';
import CardCategory from './cardCategory';
import GridCategory from './gridCategory';

interface Props {
isSelected: boolean;
containerWidth: number;
data: CategoriesData;
selectedViewMode: ViewMode;
cardWidth: number;
categories_overridden?: string[];
}

// Memoized version of content to avoid unnecessary
const Content = memo(function Content(props: Props) {
const { selectedViewMode } = useContext(ViewModeContext) as ViewModeProps;

return (
<>
<div className={props.selectedViewMode === ViewMode.Grid ? 'd-block' : 'd-none'}>
<div className={selectedViewMode === ViewMode.Grid ? 'd-block' : 'd-none'}>
<GridCategory
containerWidth={props.containerWidth}
data={props.data}
cardWidth={props.cardWidth}
categories_overridden={props.categories_overridden}
/>
</div>
<div className={props.selectedViewMode === ViewMode.Card ? 'd-block' : 'd-none'}>
<div className={selectedViewMode === ViewMode.Card ? 'd-block' : 'd-none'}>
<CardCategory
isVisible={props.isSelected && props.selectedViewMode === ViewMode.Card}
isVisible={props.isSelected && selectedViewMode === ViewMode.Card}
data={props.data}
categories_overridden={props.categories_overridden}
/>
Expand Down
12 changes: 7 additions & 5 deletions web/src/layout/explore/gridCategory/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { isUndefined } from 'lodash';
import { memo, useContext, useEffect, useState } from 'react';
import { Link } from 'react-router-dom';

import { ZOOM_LEVELS } from '../../../data';
import { BaseItem, Item, SVGIconKind } from '../../../types';
import arePropsEqual from '../../../utils/areEqualProps';
import getGridCategoryLayout, {
Expand All @@ -15,14 +16,13 @@ import getGridCategoryLayout, {
import { SubcategoryData } from '../../../utils/prepareData';
import sortItemsByOrderValue from '../../../utils/sortItemsByOrderValue';
import SVGIcon from '../../common/SVGIcon';
import { ActionsContext, AppActionsContext } from '../../context/AppContext';
import { ActionsContext, AppActionsContext, ZoomLevelContext, ZoomLevelProps } from '../../context/AppContext';
import styles from './Grid.module.css';
import GridItem from './GridItem';

interface Props {
categoryData: { [key: string]: SubcategoryData };
containerWidth: number;
itemWidth: number;
categoryName: string;
isOverriden: boolean;
subcategories: SubcategoryDetails[];
Expand All @@ -31,28 +31,30 @@ interface Props {
}

const Grid = memo(function Grid(props: Props) {
const { zoomLevel } = useContext(ZoomLevelContext) as ZoomLevelProps;
const { updateActiveSection } = useContext(AppActionsContext) as ActionsContext;
const [grid, setGrid] = useState<GridCategoryLayout | undefined>();
const itemWidth = ZOOM_LEVELS[zoomLevel][0];

useEffect(() => {
if (props.containerWidth > 0) {
setGrid(
transformGridLayout({
grid: getGridCategoryLayout({
containerWidth: props.containerWidth,
itemWidth: props.itemWidth,
itemWidth: itemWidth,
categoryName: props.categoryName,
isOverriden: props.isOverriden,
subcategories: props.subcategories,
}),
itemWidth: props.itemWidth,
itemWidth: itemWidth,
containerWidth: props.containerWidth,
subcategories: props.subcategories,
})
);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.containerWidth, props.itemWidth, props.subcategories]);
}, [props.containerWidth, itemWidth, props.subcategories]);

if (isUndefined(grid)) return null;

Expand Down
2 changes: 0 additions & 2 deletions web/src/layout/explore/gridCategory/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import styles from './GridCategory.module.css';
interface Props {
containerWidth: number;
data: CategoriesData;
cardWidth: number;
categories_overridden?: string[];
}

Expand Down Expand Up @@ -66,7 +65,6 @@ const GridCategory = memo(function GridCategory(props: Props) {
<div className="d-flex flex-column align-items-stretch w-100">
<Grid
containerWidth={props.containerWidth}
itemWidth={props.cardWidth}
categoryName={cat}
isOverriden={isOverriden}
subcategories={subcategories}
Expand Down
67 changes: 21 additions & 46 deletions web/src/layout/explore/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,24 @@ import { isUndefined, throttle } from 'lodash';
import { Fragment, useCallback, useContext, useEffect, useRef, useState } from 'react';
import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';

import { DEFAULT_VIEW_MODE, DEFAULT_ZOOM_LEVELS, GROUP_PARAM, VIEW_MODE_PARAM, ZOOM_LEVELS } from '../../data';
import { useBreakpointDetect } from '../../hooks/useBreakpointDetect';
import {
ActiveFilters,
BaseData,
BaseItem,
Breakpoint,
FilterCategory,
Group,
Item,
SVGIconKind,
ViewMode,
} from '../../types';
import { GROUP_PARAM, VIEW_MODE_PARAM } from '../../data';
import { ActiveFilters, BaseData, BaseItem, FilterCategory, Group, Item, SVGIconKind, ViewMode } from '../../types';
import countVisibleItems from '../../utils/countVisibleItems';
import filterData from '../../utils/filterData';
import itemsDataGetter from '../../utils/itemsDataGetter';
import prepareData, { GroupData } from '../../utils/prepareData';
import NoData from '../common/NoData';
import SVGIcon from '../common/SVGIcon';
import { FullDataContext, FullDataProps } from '../context/AppContext';
import {
ActionsContext,
AppActionsContext,
FullDataContext,
FullDataProps,
ViewModeContext,
ViewModeProps,
ZoomLevelContext,
ZoomLevelProps,
} from '../context/AppContext';
import Content from './Content';
import Filters from './filters';
import ActiveFiltersList from './filters/ActiveFiltersList';
Expand All @@ -37,21 +35,17 @@ const TITLE_GAP = 40;
const Landscape = (props: Props) => {
const navigate = useNavigate();
const location = useLocation();
const point = useBreakpointDetect();
const { fullDataReady } = useContext(FullDataContext) as FullDataProps;
const { selectedViewMode } = useContext(ViewModeContext) as ViewModeProps;
const { zoomLevel } = useContext(ZoomLevelContext) as ZoomLevelProps;
const { updateViewMode, updateZoomLevel } = useContext(AppActionsContext) as ActionsContext;
const [searchParams] = useSearchParams();
const container = useRef<HTMLDivElement>(null);
const [containerWidth, setContainerWidth] = useState<number>(0);
const [landscapeData, setLandscapeData] = useState<Item[] | undefined>();
const [levelZoom, setLevelZoom] = useState<number>(
point ? DEFAULT_ZOOM_LEVELS[point] : DEFAULT_ZOOM_LEVELS[Breakpoint.XL]
);
const [selectedGroup, setSelectedGroup] = useState<string | undefined>(
props.data.groups ? searchParams.get(GROUP_PARAM) || props.data.groups[0].name : undefined
);
const [selectedViewMode, setSelectedViewMode] = useState<ViewMode>(
(searchParams.get(VIEW_MODE_PARAM) as ViewMode) || DEFAULT_VIEW_MODE
);
const [visibleItems, setVisibleItems] = useState<(BaseItem | Item)[]>(props.data.items);
const [visibleFiltersModal, setVisibleFiltersModal] = useState<boolean>(false);
const [activeFilters, setActiveFilters] = useState<ActiveFilters>({});
Expand Down Expand Up @@ -91,13 +85,6 @@ const Landscape = (props: Props) => {
}
}, [landscapeData]);

// Update card-size variable depending on zoom level
useEffect(() => {
const bodyStyles = document.body.style;
bodyStyles.setProperty('--card-size-width', `${ZOOM_LEVELS[levelZoom][0]}px`);
bodyStyles.setProperty('--card-size-height', `${ZOOM_LEVELS[levelZoom][1]}px`);
}, [levelZoom]);

const removeFilter = useCallback(
(name: FilterCategory, value: string) => {
const tmpActiveFilters: string[] = (activeFilters[name] || []).filter((f: string) => f !== value);
Expand Down Expand Up @@ -141,12 +128,6 @@ const Landscape = (props: Props) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [visibleItems, selectedGroup]);

useEffect(() => {
if (point) {
setLevelZoom(DEFAULT_ZOOM_LEVELS[point]);
}
}, [point]);

useEffect(() => {
const checkContainerWidth = throttle(() => {
if (container && container.current) {
Expand Down Expand Up @@ -226,7 +207,7 @@ const Landscape = (props: Props) => {
})}
onClick={() => {
if (!isActive) {
setSelectedViewMode(value);
updateViewMode(value);
updateQueryString(VIEW_MODE_PARAM, value);
}
}}
Expand All @@ -247,21 +228,19 @@ const Landscape = (props: Props) => {
<button
title="Increase zoom level"
className="btn btn-outline-primary rounded-0 fw-semibold"
disabled={levelZoom === 0}
disabled={zoomLevel === 0}
onClick={() => {
const newZoomLevel = levelZoom - 1;
setLevelZoom(newZoomLevel);
updateZoomLevel(zoomLevel - 1);
}}
>
<div className={styles.btnSymbol}>-</div>
</button>
<button
title="Decrease zoom level"
className="btn btn-outline-primary rounded-0 fw-semibold"
disabled={levelZoom === 10}
disabled={zoomLevel === 10}
onClick={() => {
const newZoomLevel = levelZoom + 1;
setLevelZoom(newZoomLevel);
updateZoomLevel(zoomLevel + 1);
}}
>
<div className={styles.btnSymbol}>+</div>
Expand Down Expand Up @@ -298,7 +277,7 @@ const Landscape = (props: Props) => {
)}

<div className="d-flex w-100 pt-1">
<div ref={container} className={`d-flex flex-column flex-grow-1 w-100 zoom-${levelZoom}`}>
<div ref={container} className={`d-flex flex-column flex-grow-1 w-100 zoom-${zoomLevel}`}>
{props.data.groups ? (
<>
{props.data.groups.map((group: Group) => {
Expand All @@ -309,8 +288,6 @@ const Landscape = (props: Props) => {
isSelected={isSelected}
containerWidth={containerWidth}
data={groupsData[group.name]}
cardWidth={ZOOM_LEVELS[levelZoom][0]}
selectedViewMode={selectedViewMode}
categories_overridden={props.data.categories_overridden}
/>
</div>
Expand All @@ -322,8 +299,6 @@ const Landscape = (props: Props) => {
isSelected
containerWidth={containerWidth}
data={groupsData.default}
cardWidth={ZOOM_LEVELS[levelZoom][0]}
selectedViewMode={selectedViewMode}
categories_overridden={props.data.categories_overridden}
/>
)}
Expand Down

0 comments on commit 13c9d16

Please sign in to comment.