diff --git a/src/bin/graphs/BinLevelOverTime.tsx b/src/bin/graphs/BinLevelOverTime.tsx index cefb99e..8aabf93 100644 --- a/src/bin/graphs/BinLevelOverTime.tsx +++ b/src/bin/graphs/BinLevelOverTime.tsx @@ -13,7 +13,7 @@ import { Bin } from "models"; import moment, { Moment } from "moment"; import { pond, quack } from "protobuf-ts/pond"; import { useBinAPI, useGlobalState } from "providers"; -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { Legend } from "recharts"; import { getGrainUnit } from "utils"; @@ -31,24 +31,13 @@ export default function BinLevelOverTime(props: Props) { const { bin, fertilizerBin, colour, startDate, endDate, customHeight } = props; const binAPI = useBinAPI(); const [{as}] = useGlobalState(); - const [showCable, setShowCable] = useState(false); - const [manualData, setManualData] = useState([]); - const [cableData, setCableData] = useState([]); + const [data, setData] = useState([]); const [modeAreas, setModeAreas] = useState([]); - // const defaultDateRange = GetDefaultDateRange(); - // const [startDate, setStartDate] = useState(defaultDateRange.start); - // const [endDate, setEndDate] = useState(defaultDateRange.end); const [dataLoading, setDataLoading] = useState(false); - const [cableDataLoading, setCableDataLoading] = useState(false); const [capacity, setCapacity] = useState(); - - // const updateDateRange = (newStartDate: any, newEndDate: any) => { - // let range = GetDefaultDateRange(); - // range.start = newStartDate; - // range.end = newEndDate; - // setStartDate(newStartDate); - // setEndDate(newEndDate); - // }; + + const [modeData, setModeData] = useState([]); + const [histDataLoading, setHistDataLoading] = useState(false); const getFill = (mode: pond.BinMode) => { let fill = ""; @@ -72,8 +61,8 @@ export default function BinLevelOverTime(props: Props) { return fill; }; - useEffect(() => { - if (dataLoading || bin.key() === "") return; + //loads the data from the bin history table + const loadHistoryData = useCallback(() => { setDataLoading(true); let cap = bin.settings.specs?.bushelCapacity; if (fertilizerBin && cap) { @@ -146,48 +135,125 @@ export default function BinLevelOverTime(props: Props) { fill: getFill(bin.settings.mode) }); } - setManualData(data); + setData(data); setModeAreas(modeAreas); }) .finally(() => { setDataLoading(false); }); - }, [binAPI, bin, startDate, endDate, fertilizerBin]); // eslint-disable-line react-hooks/exhaustive-deps + },[startDate, endDate, bin, fertilizerBin]) - useEffect(() => { - if (cableDataLoading || bin.key() === "") return; - setCableDataLoading(true); + //loads the data from the measuremnts table as a unit measurement + const loadMeasurementData = useCallback(() => { + setDataLoading(true); + let cap = bin.settings.specs?.bushelCapacity; + if (fertilizerBin && cap) { + cap = cap * 35.239; + } + if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && cap) { + cap = cap / bin.bushelsPerTonne(); + } + setCapacity(cap); + let autoBarData: BarData[] = []; + + //load the measurment data to build the bushel bars binAPI - .listBinMeasurements(bin.key(), startDate, endDate, 500, 0, "asc", undefined, undefined, undefined, undefined, as) + .listBinMeasurements(bin.key(), startDate, endDate, 500, 0, "asc") .then(resp => { + let lastBushels = -1; + resp.data.measurements.forEach(objMeasurement => { //set the bushel cable measurements let m = pond.UnitMeasurementsForObject.fromObject(objMeasurement); - if (m.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_BUSHEL_CABLE) { - let cableBarData: BarData[] = []; - let lastBushels = -1; - //val will be an array of only a single number since this is not a measurement that involves nodes - m.values.forEach((val, i) => { - if (val.values[0] && m.timestamps[i]) { - if (lastBushels !== val.values[0]) { - cableBarData.push({ - value: val.values[0], - timestamp: moment(m.timestamps[i]).valueOf() - }); - lastBushels = val.values[0]; - } + //val will be an array of only a single number since this is not a measurement that involves nodes + m.values.forEach((val, i) => { + if (val.values[0] && m.timestamps[i]) { + if (lastBushels !== val.values[0]) { + autoBarData.push({ + value: val.values[0], + timestamp: moment(m.timestamps[i]).valueOf(), + }); + lastBushels = val.values[0]; } - }); - setCableData(cableBarData); - } + } + }); }); + if (autoBarData.length === 0) { + let bushels = bin.settings.inventory?.grainBushels ?? 0; + let currentTime = moment().valueOf(); + autoBarData.push({ + value: fertilizerBin + ? Math.round(bushels * 35.239) + : getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT + ? Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100 + : bushels, + timestamp: currentTime + }); + } + setData(autoBarData); }) .catch(err => {}) .finally(() => { - setCableDataLoading(false); + setDataLoading(false); }); - }, [binAPI, bin, startDate, endDate, fertilizerBin, as]); // eslint-disable-line react-hooks/exhaustive-deps + },[startDate, endDate, bin, fertilizerBin]) + + const modeDataFromHistory = useCallback(()=>{ + if (histDataLoading) return; + setHistDataLoading(true) + binAPI + .listHistoryBetween(bin.key(), 500, startDate.toISOString(), endDate.toISOString()) + .then(resp => { + //loop through the history finding all the times the bin mode changed + let currentMode: pond.BinMode | undefined = undefined + let modeData: BarData[] = [] + resp.data.history.forEach(hist => { + let histBin = Bin.create() + histBin.settings = hist.settings ?? pond.BinSettings.create() + if(hist.settings && currentMode !== hist.settings.mode){ + currentMode = hist.settings.mode + modeData.push({ + timestamp: moment(hist.timestamp).valueOf(), + value: 1, + fill: getFill(currentMode) + }) + } + }) + setModeData(modeData) + }) + .catch(err => { + + }) + .finally(()=>{ + setHistDataLoading(false) + }) + },[bin, startDate, endDate]) + + + useEffect(() => { + //dont call a load function if loading is already in progress + if (dataLoading || bin.key() === "") return; + //check what is controlling the bin inventory + let control = bin.inventoryControl() + //for automatic lidar and cables get the data from measurements as an object measurement + if(control === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC_LIDAR || + control === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC + ){ + //load the measurement data for the bar graph + loadMeasurementData() + //load the data for the storage mode changes + modeDataFromHistory() + + //for manual and hybrid (lidar or in the future, cables) get the data from bin_history + }else if(control === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_MANUAL || + control === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_HYBRID_LIDAR || + control === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_UNKNOWN + ){ + loadHistoryData() + } + + },[bin, loadMeasurementData, loadHistoryData]) const legend = () => { return ( @@ -203,15 +269,16 @@ export default function BinLevelOverTime(props: Props) { ); }; - const manualChart = () => { + const inventoryChart = () => { return ( 0 ? legend() : undefined} labelColour="white" labels useGradient @@ -219,62 +286,28 @@ export default function BinLevelOverTime(props: Props) { ); }; - const cableChart = () => { - if (cableData.length === 0) { - return ( - - - No cable estimates for selected time frame - - - ); - } + const autoBinModeChart = () => { return ( - - ); - }; + ) + } return ( - - - - Grain Levels Over Time - - - - { - setShowCable(checked); - }} - color="primary" - /> - } - label="Cable Estimates" - /> - - - - {dataLoading ? : showCable ? cableChart() : manualChart()} + + Grain Levels Over Time + + {dataLoading ? : inventoryChart()} + {/* when using auto will need to make a new chart just for the bin modes since the auto inventory comes from another place */} + {(bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC_LIDAR || + bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC) && autoBinModeChart()} ); } diff --git a/src/charts/BarGraph.tsx b/src/charts/BarGraph.tsx index 8e0ab82..f8bd48e 100644 --- a/src/charts/BarGraph.tsx +++ b/src/charts/BarGraph.tsx @@ -15,6 +15,7 @@ import { export interface BarData { timestamp: number; value: number; + fill?: string; } export interface RefArea { @@ -36,8 +37,9 @@ export interface AxisLabel { interface Props { data: BarData[]; - barColour: string; + barColour?: string; refAreas?: RefArea[]; + hideYAxis?: boolean; yMin?: number; yMax?: number; graphLegend?: JSX.Element; @@ -60,6 +62,7 @@ export default function BarGraph(props: Props) { data, barColour, refAreas, + hideYAxis, yMin, yMax, graphLegend, @@ -103,6 +106,7 @@ export default function BarGraph(props: Props) { {graphLegend}