Created
April 27, 2020 15:55
-
-
Save DWboutin/03e60c46ec8b31a83d26fdef76ec7d10 to your computer and use it in GitHub Desktop.
React-DND
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { connect } from 'react-redux'; | |
import { Responsive, WidthProvider } from 'react-grid-layout'; | |
import { changeLayout, changeCurrentBreakpoint, changeWidgetOptions } from '../../actions/dashboard-actions'; | |
import { fetch as fetchLayouts, create as createLayout } from '../../actions/layouts-actions'; | |
import { fetch as fetchChartTypes } from '../../actions/chart-types-actions'; | |
import { | |
fetch as fetchWidgets, | |
create as createWidget, | |
update as updateWidget, | |
updateMany as updateManyWidgets, | |
remove as removeWidget | |
} from '../../actions/widgets-actions'; | |
import { toggleDigitalControl, historyFetch} from '../../actions/devices-actions'; | |
import DropZone from '../../wrapper/DropZone'; | |
import WidgetCard from '../reusables/WidgetCard'; | |
import WidgetDigitalControl from '../reusables/WidgetDigitalControl'; | |
import WidgetDigitalSensor from '../reusables/WidgetDigitalSensor'; | |
import WidgetAnalogSensor from '../reusables/WidgetAnalogSensor'; | |
import AnalogSensorForm from '../reusables/WidgetOptionsForm/AnalogSensorForm'; | |
import DigitalSensorForm from '../reusables/WidgetOptionsForm/DigitalSensorForm'; | |
import DigitalControlForm from '../reusables/WidgetOptionsForm/DigitalControlForm'; | |
import StyledDialog from '../reusables/StyledDialog'; | |
import SocketsHandler from '../../utils/socketsHandler'; | |
import { createWidgetKey, getWidgetLayouts } from '../../utils/helpers'; | |
import '../../assets/scss/components/section/WidgetGrid.scss'; | |
const ResponsiveReactGridLayout = WidthProvider(Responsive); | |
class WidgetGrid extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
compactType: 'vertical', | |
mounted: true, | |
dialogIsOpen: false, | |
dialogWidgetProps: null, | |
layouts: null, | |
isModified: false, | |
deviceHistoryFetch: [], | |
}; | |
this.socketHandler = null; | |
this.deviceHistoryIdsFetching = []; // to store device id to fetch history only one time | |
this.handleDropItem = this.handleDropItem.bind(this); | |
this.onBreakpointChange = this.onBreakpointChange.bind(this); | |
this.onLayoutChange = this.onLayoutChange.bind(this); | |
this.getWidgetsKeysLengthForKey = this.getWidgetsKeysLengthForKey.bind(this); | |
this.handleDialogOpen = this.handleDialogOpen.bind(this); | |
this.handleDialogClose = this.handleDialogClose.bind(this); | |
this.handleClearDialogWidgetProps = this.handleClearDialogWidgetProps.bind(this); | |
this.handleWidgetOptionsFormSubmit = this.handleWidgetOptionsFormSubmit.bind(this); | |
this.onLayoutModification = this.onLayoutModification.bind(this); | |
this.handleDigitalControlToggle = this.handleDigitalControlToggle.bind(this); | |
this.handleWidgetRemove = this.handleWidgetRemove.bind(this); | |
this.handleDeviceHistoryFetch = this.handleDeviceHistoryFetch.bind(this); | |
} | |
componentDidMount() { | |
const { getLayouts, createLayout, getWidgets, getChartTypes } = this.props; | |
this.socketHandler = new SocketsHandler(); | |
this.socketHandler.listen(); | |
getLayouts().then((layoutList) => { | |
if (layoutList.length <= 0) { | |
createLayout({ | |
name: 'default', | |
}).then(getLayouts()); | |
} | |
}); | |
getWidgets(); | |
getChartTypes(); | |
function iframeResize() { | |
// What's the page height? | |
var height = document.body.scrollHeight; | |
parent.postMessage(height, "*"); | |
} | |
iframeResize(); | |
} | |
onBreakpointChange(breakpoint) { | |
const { changeCurrentBreakpoint } = this.props; | |
changeCurrentBreakpoint(breakpoint); | |
} | |
onLayoutChange(layout, layouts) { | |
const { changeLayout } = this.props; | |
this.setState({ | |
layouts, | |
}); | |
changeLayout(layouts); | |
if (this.state.isModified) { | |
this.updateWidgetLayouts(); | |
} | |
} | |
onLayoutModification() { | |
this.setState({ | |
isModified: true, | |
}); | |
} | |
updateWidgetLayouts() { | |
const { updateManyWidgets, getWidgets } = this.props; | |
const objectsLayouts = {}; | |
const layouts = this.state.layouts; | |
Object.keys(layouts).forEach((size) => { | |
layouts[size].forEach((layout) => { | |
const widgetKey = (typeof layout.i !== 'string') ? 'widget-id-' + layout.i : layout.i; | |
const currentObj = objectsLayouts[widgetKey]; | |
if (typeof currentObj === 'undefined') { | |
objectsLayouts[widgetKey] = {}; | |
} | |
layout.i = widgetKey; | |
objectsLayouts[widgetKey][size] = layout; | |
}); | |
}); | |
updateManyWidgets(objectsLayouts).then(() => { | |
this.setState({ | |
isModified: false, | |
}); | |
getWidgets(); | |
}); | |
} | |
getWidgetsKeysLengthForKey(key) { | |
const { widgets } = this.props; | |
const keys = []; | |
Object.keys(widgets).forEach((widgetKey) => { | |
if (widgetKey.indexOf(key) !== -1) { | |
keys.push(widgetKey); | |
} | |
}); | |
return keys.length; | |
} | |
handleDropItem(droppedProps) { | |
const { createWidget, activeLayout, layoutsList, getWidgets, currentBreakpoint } = this.props; | |
const widgetLayout = {}; | |
widgetLayout[currentBreakpoint] = { | |
...droppedProps.widget.grid, | |
i: `widget-id-${droppedProps.widget.id}`, | |
}; | |
createWidget(droppedProps.widget, layoutsList[activeLayout].id, widgetLayout) | |
.then(() => { | |
// refresh widget list | |
getWidgets() | |
}); | |
} | |
handleDialogOpen(widgetProps) { | |
this.setState({ | |
dialogIsOpen: true, | |
dialogWidgetProps: widgetProps, | |
}); | |
} | |
handleDialogClose() { | |
this.setState({ | |
dialogIsOpen: false, | |
}); | |
} | |
handleClearDialogWidgetProps() { | |
this.setState({ | |
dialogWidgetProps: null, | |
}); | |
} | |
handleWidgetOptionsFormSubmit(values) { | |
const { updateWidget, getWidgets } = this.props; | |
const widgetId = values.widget_id; | |
delete values.widget_id; | |
updateWidget(widgetId, values) | |
.then(() => getWidgets()) | |
.then(() => { | |
this.handleDialogClose(); | |
}); | |
} | |
handleWidgetRemove() { | |
const { deleteWidget, getWidgets } = this.props; | |
const { dialogWidgetProps } = this.state; | |
deleteWidget(dialogWidgetProps.id) | |
.then(() => getWidgets()) | |
.then(() => { | |
this.handleDialogClose(); | |
}); | |
} | |
handleDigitalControlToggle(objectId) { | |
const { toggleDigitalControlDevice } = this.props; | |
toggleDigitalControlDevice(objectId); | |
} | |
handleDeviceHistoryFetch(objectId, dateStart, dateEnd) { | |
const { getDeviceHistory, devicesHistory } = this.props; | |
if (this.deviceHistoryIdsFetching.indexOf(objectId) === -1 && Object.keys(devicesHistory).indexOf(objectId) === -1) { | |
this.deviceHistoryIdsFetching.push(objectId); | |
return getDeviceHistory(objectId, dateStart, dateEnd); | |
} else { | |
return false; | |
} | |
} | |
render() { | |
const { widgets, layouts, cols, breakpoints, rowHeight, currentBreakpoint, devices, devicesHistory } = this.props; | |
const { dialogIsOpen, dialogWidgetProps } = this.state; | |
return ( | |
<DropZone id="widget-grid" accepts={['device']} onDrop={this.handleDropItem}> | |
<ResponsiveReactGridLayout | |
id="widget-grid" | |
breakpoints={breakpoints} | |
layouts={layouts} | |
cols={cols} | |
rowHeight={rowHeight} | |
onBreakpointChange={this.onBreakpointChange} | |
onLayoutChange={this.onLayoutChange} | |
measureBeforeMount | |
useCSSTransforms={this.state.mounted} | |
compactType={this.state.compactType} | |
preventCollision={!this.state.compactType} | |
onDragStop={this.onLayoutModification} | |
onResizeStop={this.onLayoutModification} | |
> | |
{widgets.map(widget => ( | |
<div key={`widget-id-${widget.id}`} data-grid={widget.layout[currentBreakpoint]}> | |
{(devices[widget.object_id] && devices[widget.object_id].is_digital_control) && ( | |
<WidgetDigitalControl | |
{...widget} | |
device={devices[widget.object_id]} | |
deviceHistory={devicesHistory[widget.object_id]} | |
socketHandler={this.socketHandler} | |
widgetKey={widget['random-generated-hash-id']} | |
handleDialogOpen={this.handleDialogOpen} | |
handleDigitalControlToggle={this.handleDigitalControlToggle} | |
handleDeviceHistoryFetch={this.handleDeviceHistoryFetch} | |
/> | |
)} | |
{(devices[widget.object_id] && devices[widget.object_id].is_digital_sensor) && ( | |
<WidgetDigitalSensor | |
{...widget} | |
device={devices[widget.object_id]} | |
deviceHistory={devicesHistory[widget.object_id]} | |
socketHandler={this.socketHandler} | |
widgetKey={widget['random-generated-hash-id']} | |
handleDialogOpen={this.handleDialogOpen} | |
handleDeviceHistoryFetch={this.handleDeviceHistoryFetch} | |
/> | |
)} | |
{(devices[widget.object_id] && devices[widget.object_id].is_analog_sensor) && ( | |
<WidgetAnalogSensor | |
{...widget} | |
device={devices[widget.object_id]} | |
deviceHistory={devicesHistory[widget.object_id]} | |
socketHandler={this.socketHandler} | |
widgetKey={widget['random-generated-hash-id']} | |
handleDialogOpen={this.handleDialogOpen} | |
handleDeviceHistoryFetch={this.handleDeviceHistoryFetch} | |
/> | |
)} | |
</div> | |
))} | |
</ResponsiveReactGridLayout> | |
<StyledDialog | |
isOpen={(dialogIsOpen && dialogWidgetProps !== null)} | |
iconClasses="far fa-cog" | |
title={(dialogWidgetProps !== null) ? dialogWidgetProps.name : ''} | |
handleDialogClose={this.handleDialogClose} | |
handleClearDialogWidgetProps={this.handleClearDialogWidgetProps} | |
color={(dialogWidgetProps !== null && dialogWidgetProps.color) ? dialogWidgetProps.color : ''} | |
> | |
{(dialogIsOpen && dialogWidgetProps !== null && dialogWidgetProps.device.is_digital_control) && ( | |
<DigitalControlForm | |
widgetProps={dialogWidgetProps} | |
onSubmit={this.handleWidgetOptionsFormSubmit} | |
handleDialogClose={this.handleDialogClose} | |
onWidgetRemove={this.handleWidgetRemove} | |
/> | |
)} | |
{(dialogIsOpen && dialogWidgetProps !== null && dialogWidgetProps.device.is_digital_sensor) && ( | |
<DigitalSensorForm | |
widgetProps={dialogWidgetProps} | |
onSubmit={this.handleWidgetOptionsFormSubmit} | |
handleDialogClose={this.handleDialogClose} | |
onWidgetRemove={this.handleWidgetRemove} | |
/> | |
)} | |
{(dialogIsOpen && dialogWidgetProps !== null && dialogWidgetProps.device.is_analog_sensor) && ( | |
<AnalogSensorForm | |
widgetProps={dialogWidgetProps} | |
onSubmit={this.handleWidgetOptionsFormSubmit} | |
handleDialogClose={this.handleDialogClose} | |
onWidgetRemove={this.handleWidgetRemove} | |
/> | |
)} | |
</StyledDialog> | |
</DropZone> | |
); | |
} | |
} | |
WidgetGrid.propTypes = {}; | |
WidgetGrid.defaultProps = { | |
className: 'layout', | |
rowHeight: 30, | |
cols: { | |
xlg: 12, | |
lg: 12, | |
md: 10, | |
sm: 6, | |
xs: 4, | |
}, | |
breakpoints: { | |
xlg: 1920, | |
lg: 1280, | |
md: 960, | |
sm: 600, | |
xs: 0, | |
}, | |
initialLayout: [], | |
}; | |
export const mapStateToProps = (state, props) => ({ | |
locale: state.application.locale, | |
widgets: state.widgets.list, | |
layouts: state.layouts.layout, | |
devices: state.devices.list, | |
devicesHistory: state.devices.history, | |
activeLayout: state.layouts.activeLayout, | |
layoutsList: state.layouts.list, | |
currentBreakpoint: state.dashboard.currentBreakpoint, | |
}); | |
export const mapDispatchToProps = dispatch => ({ | |
getChartTypes: () => dispatch(fetchChartTypes()), | |
getLayouts: () => dispatch(fetchLayouts()), | |
getDeviceHistory: (objectId, dateStart, dateEnd) => dispatch(historyFetch(objectId, dateStart, dateEnd)), | |
createLayout: (layout) => dispatch(createLayout(layout)), | |
getWidgets: (widgetKey, widget) => dispatch(fetchWidgets()), | |
addWidget: (widgetKey, widget) => dispatch(addWidget(widgetKey, widget)), | |
createWidget: (widget, layoutId, widgetLayout) => dispatch(createWidget(widget, layoutId, widgetLayout)), | |
updateWidget: (widgetId, widgetData) => dispatch(updateWidget(widgetId, widgetData)), | |
deleteWidget: (widgetId) => dispatch(removeWidget(widgetId)), | |
changeCurrentBreakpoint: (breakpoint) => dispatch(changeCurrentBreakpoint(breakpoint)), | |
changeLayout: (layouts) => dispatch(changeLayout(layouts)), | |
updateManyWidgets: (widgets) => dispatch(updateManyWidgets(widgets)), | |
toggleDigitalControlDevice: (objectId) => dispatch(toggleDigitalControl(objectId)) | |
}); | |
export default connect(mapStateToProps, mapDispatchToProps)(WidgetGrid); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment