Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #33 - Create Backend Provider and Data Context consumers/providers #37

Merged
merged 2 commits into from
Oct 31, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions app/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import ErrorCatcher from './ErrorCatcher';
import Dashboard from './Dashboard';
import { WidgetsList } from './Widget';

import BackendProvider from './Backend/Provider';

// App Helmet: Controls HTML <head> elements with SideEffect
// - Set a default title and title template, translated
const AppHelmet = (props) => {
Expand All @@ -31,12 +33,14 @@ const AppProviders = (props) => {
return (
<TranslatorProvider translations={ props.translations }>
<HelmetProvider>
<AppHelmet language={ props.language } />
<Router>
<div className='App' id='router-container'>
{ props.children }
</div>
</Router>
<BackendProvider>
<AppHelmet language={ props.language } />
<Router>
<div className='App' id='router-container'>
{ props.children }
</div>
</Router>
</BackendProvider>
</HelmetProvider>
</TranslatorProvider>
);
Expand Down
59 changes: 59 additions & 0 deletions app/src/Backend/Bcn/BcnContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { Component } from 'react';
import BcnData from './index';

const BcnContext = React.createContext();

function BcnProvider({children}) {
return (
<BcnContext.Provider value={BcnData}>
{children}
</BcnContext.Provider>
);
}

function BcnConsumer({children}) {
return (
<BcnContext.Consumer>
{context => {
if (context === undefined) {
throw new Error('BcnConsumer must be used within a BcnProvider');
}

return children(context);
}}
</BcnContext.Consumer>
);
}

function useBcnData() {
const context = React.useContext(BcnContext);

if (context === undefined) {
throw new Error('useBcnData must be used within a BcnProvider');
}

return context;
}

function withBcnDataHandler(WrappedComponent) {
return (
class GetBcnData extends Component {
render() {
return (
<BcnContext.Consumer>
{context => {
if (context === undefined) {
throw new Error('BcnConsumer must be used within a BcnProvider');
}

return <WrappedComponent {...this.props} bcnDataHandler={context} />;
}}
</BcnContext.Consumer>
);
}
}
);
}

export default BcnProvider;
export { withBcnDataHandler, BcnConsumer, useBcnData, BcnContext };
emibcn marked this conversation as resolved.
Show resolved Hide resolved
59 changes: 59 additions & 0 deletions app/src/Backend/Charts/ChartsContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { Component } from 'react';
import ChartsData from './index';

const ChartsContext = React.createContext();

function ChartsProvider({children}) {
return (
<ChartsContext.Provider value={ChartsData}>
{children}
</ChartsContext.Provider>
);
}

function ChartsConsumer({children}) {
return (
<ChartsContext.Consumer>
{context => {
if (context === undefined) {
throw new Error('ChartsConsumer must be used within a ChartsProvider');
}

return children(context);
}}
</ChartsContext.Consumer>
);
}

function useChartsData() {
const context = React.useContext(ChartsContext);

if (context === undefined) {
throw new Error('useChartsData must be used within a ChartsProvider');
}

return context;
}

function withChartsDataHandler(WrappedComponent) {
return (
class GetChartsData extends Component {
render() {
return (
<ChartsContext.Consumer>
{context => {
if (context === undefined) {
throw new Error('ChartsConsumer must be used within a ChartsProvider');
}

return <WrappedComponent {...this.props} chartsDataHandler={context} />;
}}
</ChartsContext.Consumer>
);
}
}
);
}

export default ChartsProvider;
export { withChartsDataHandler, ChartsConsumer, useChartsData, ChartsContext };
59 changes: 59 additions & 0 deletions app/src/Backend/Maps/MapsContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { Component } from 'react';
import MapsData from './index';

const MapsContext = React.createContext();

function MapsProvider({children}) {
return (
<MapsContext.Provider value={MapsData}>
{children}
</MapsContext.Provider>
);
}

function MapsConsumer({children}) {
return (
<MapsContext.Consumer>
{context => {
if (context === undefined) {
throw new Error('MapsConsumer must be used within a MapsProvider');
}

return children(context);
}}
</MapsContext.Consumer>
);
}

function useMapsData() {
const context = React.useContext(MapsContext);

if (context === undefined) {
throw new Error('useMapsData must be used within a MapsProvider');
}

return context;
}

function withMapsDataHandler(WrappedComponent) {
return (
class GetMapsData extends Component {
render() {
return (
<MapsContext.Consumer>
{context => {
if (context === undefined) {
throw new Error('MapsConsumer must be used within a MapsProvider');
}

return <WrappedComponent {...this.props} mapsDataHandler={context} />;
}}
</MapsContext.Consumer>
);
}
}
);
}

export default MapsProvider;
export { withMapsDataHandler, MapsConsumer, useMapsData, MapsContext };
19 changes: 19 additions & 0 deletions app/src/Backend/Provider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from "react";

import BcnProvider from './Bcn/BcnContext';
import MapsProvider from './Maps/MapsContext';
import ChartsProvider from './Charts/ChartsContext';

const BackendProvider = ({children}) => {
return (
<BcnProvider>
<MapsProvider>
<ChartsProvider>
{children}
</ChartsProvider>
</MapsProvider>
</BcnProvider>
);
};

export default BackendProvider;
57 changes: 29 additions & 28 deletions app/src/Widget/List.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import Paper from '@material-ui/core/Paper';
import MenuAddWidget from './MenuAddWidget';
import WidgetsTypes from './Widgets';

import MapData from '../Backend/Maps';
import ChartData from '../Backend/Charts';
import BcnData from '../Backend/Bcn';
import { withBcnDataHandler } from '../Backend/Bcn/BcnContext';
import { withMapsDataHandler } from '../Backend/Maps/MapsContext';
import { withChartsDataHandler } from '../Backend/Charts/ChartsContext';

import Throtle from '../Throtle';
import Slider from '../Slider';
import Loading from '../Loading';

import WidgetDataContextProvider from './DataContextProvider';
import WidgetDataContextProvider from './DataContextProvider';
import withPropHandler from './withPropHandler';

// GUID generator: used to create unique dtemporal IDs for widgets
Expand Down Expand Up @@ -134,29 +134,23 @@ class WidgetsList extends React.PureComponent {
// with excessive calls on mouse move
throtle = new Throtle();

// Map Data backend
// TODO: Handle errors
MapData = new MapData();

// Chart Data backend
// TODO: Handle errors
ChartData = new ChartData();

// BCN Data backend
// TODO: Handle errors
BcnData = new BcnData();

constructor(props) {
super(props);
// Generate initial list of unique IDs
if ('widgets' in props) {
this.updateIDs(props.widgets.length);
}

this.bcnData = new props.bcnDataHandler();
this.chartsData = new props.chartsDataHandler();
this.mapData = new props.mapsDataHandler();
}

// Fetch data once mounted
componentDidMount() {
this.MapData.days(
const { mapData, chartsData, bcnData } = this;

mapData.days(
days => {
// Are we on the last time serie element before update?
const isLast =
Expand Down Expand Up @@ -186,34 +180,35 @@ class WidgetsList extends React.PureComponent {

// Once data has been fetched, schedule next data update
// Mind the timer on unmount
this.MapData.scheduleNextUpdate();
mapData.scheduleNextUpdate();
});
this.ChartData.index(
chartsData.index(
chartsIndex => {

this.setState({ chartsIndex });

// Once data has been fetched, schedule next data update
// Mind the timer on unmount
this.ChartData.scheduleNextUpdate();
chartsData.scheduleNextUpdate();
});
this.BcnData.index(
bcnData.index(
bcnIndex => {

this.setState({ bcnIndex });

// Once data has been fetched, schedule next data update
// Mind the timer on unmount
this.BcnData.scheduleNextUpdate();
bcnData.scheduleNextUpdate();
});
}

// Cleanup side effects
componentWillUnmount() {
const { mapData, chartsData, bcnData } = this;

// Cancel next update timers
this.MapData.cancelUpdateSchedule();
this.ChartData.cancelUpdateSchedule();
this.BcnData.cancelUpdateSchedule();
bcnData.cancelUpdateSchedule();
chartsData.cancelUpdateSchedule();
mapData.cancelUpdateSchedule();

// Cancel possible throtle timer
this.throtle.clear();
Expand Down Expand Up @@ -355,12 +350,18 @@ const withShowMarkLabels = (Component) => {
// withPropHandler: Handle params from providers (route + localStorage) into props
// withStyles: Add `classes` prop for styling components
// withShowMarkLabels: Add `showMarkLabels` breakpoint to sho/hide Slider mark labels depending on sreen size
// withBcnDataHandler: Add `bcnDataHandler` prop to use bcn backend data
// withMapsDataHandler: Add `mapsDataHandler` prop to use maps backend data
// withChartsDataHandler: Add `chartsDataHandler` prop to use charts backend data
const WidgetsListWithPropHandler =
withPropHandler(
withStyles(useStyles)(
withShowMarkLabels(
WidgetsList
)));
withBcnDataHandler(
withMapsDataHandler(
withChartsDataHandler(
WidgetsList
))))));

// Manage some context providers details:
// - pathFilter: How to split `location` (Route `path` prop)
Expand Down
16 changes: 9 additions & 7 deletions app/src/Widget/Widgets/Bcn/EditDataset.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import TreeItem from '@material-ui/lab/TreeItem';

import BcnData from '../../../Backend/Bcn';
import { withBcnDataHandler } from '../../../Backend/Bcn/BcnContext';

// From: https://material-ui.com/components/tree-view/#rich-object

Expand Down Expand Up @@ -38,22 +38,24 @@ class RecursiveTreeView extends React.Component {
this.props.onChange(value);
}
}

componentWillMount = () => {
const bcnData = new BcnData(this.props.bcnIndex);
const {value} = this.props;
const { value, bcnIndex, bcnDataHandler } = this.props;

const bcnData = new bcnDataHandler(bcnIndex);

this.setState({
value,
breadcrumb: bcnData
.findBreadcrumb(null, this.props.value)
.findBreadcrumb(null, value)
.map(node => `${!('values' in node) ? 'DISABLED-' : ''}${node.code}`),
});
}

render = (props) => {
const { classes, bcnIndex, ...restProps } = this.props;
const { breadcrumb, value } = this.state;

return (
<TreeView
className={classes.root}
Expand All @@ -72,4 +74,4 @@ class RecursiveTreeView extends React.Component {
}
}

export default withStyles(styles)(RecursiveTreeView);
export default withBcnDataHandler(withStyles(styles)(RecursiveTreeView));
Loading