From 13c15ec1954d3bfb4efe20f5d067b59fab537274 Mon Sep 17 00:00:00 2001 From: csawatzky Date: Wed, 3 Jun 2026 12:36:08 -0600 Subject: [PATCH] finished hooking up the inventory adjustment slider when using manual control on the bin page --- src/bin/BinTableExpanded.tsx | 18 ++-- src/bin/binSummary/BinSummary.tsx | 134 ++++++++++++++++++++++++++---- src/bin/binTableView.tsx | 3 +- src/grain/GrainTransaction.tsx | 4 +- src/models/Bin.ts | 35 ++++++++ src/pages/BinV2.tsx | 1 + 6 files changed, 169 insertions(+), 26 deletions(-) diff --git a/src/bin/BinTableExpanded.tsx b/src/bin/BinTableExpanded.tsx index 5f180eb..cf1def6 100644 --- a/src/bin/BinTableExpanded.tsx +++ b/src/bin/BinTableExpanded.tsx @@ -207,16 +207,16 @@ export default function BinTableExpanded(props: Props) { {user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "+20 °F" : "+10 °C"} above target - - {cables.map((cable, i) => ( - - - {cable.name} - - {cableTable(cable)} + + {cables.map((cable, i) => ( + + + {cable.name} + + {cableTable(cable)} + + ))} - ))} - ) } \ No newline at end of file diff --git a/src/bin/binSummary/BinSummary.tsx b/src/bin/binSummary/BinSummary.tsx index 7519e53..d637c05 100644 --- a/src/bin/binSummary/BinSummary.tsx +++ b/src/bin/binSummary/BinSummary.tsx @@ -1,4 +1,4 @@ -import { Box, Card, DialogContent, DialogTitle, Grid2, IconButton, LinearProgress, Switch, Typography } from "@mui/material"; +import { Box, Card, DialogContent, DialogTitle, Grid2, IconButton, LinearProgress, Slider, Switch, Tooltip, Typography } from "@mui/material"; import { useMobile } from "hooks"; import { Bin, Component, Device } from "models"; import Bin3dVisualizer from "./components/bin3dVisualizer"; @@ -13,9 +13,12 @@ import BinDetails from "./components/binDetails"; import { Plenum } from "models/Plenum"; import BinSensorsDisplay from "../binSensorsDisplay"; import ResponsiveDialog from "common/ResponsiveDialog"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import SearchSelect from "common/SearchSelect"; import ChangeGrainDialog from "grain/ChangeGrainDialog"; +import { useGlobalState } from "providers"; +import GrainTransaction from "grain/GrainTransaction"; +import { cloneDeep } from "lodash"; interface Props { bin: Bin @@ -32,13 +35,33 @@ interface Props { React.SetStateAction | undefined> >; updateBinCallback?: (bin: Bin) => void + setBin?: React.Dispatch>; } export default function BinSummary(props: Props){ - const {bin, devices, fans, heaters, permissions, componentDevices, componentMap, binPrefs, updateBinCallback, cables = [], plenums = [], setPreferences} = props + const {bin, devices, fans, heaters, permissions, componentDevices, componentMap, binPrefs, updateBinCallback, cables = [], plenums = [], setPreferences, setBin} = props //const [currentDevice, setCurrentDevice] = useState(undefined) const isMobile = useMobile() const [openGrainDialog, setOpenGrainDialog] = useState(false) + const [manualFillPercent, setManualFillPercent] = useState(0) + const [manualBushels, setManualBushels] = useState(0) + const [{user}] = useGlobalState() + const fillCapRef = useRef(null); + const [fillCapWidth, setFillCapWidth] = useState(undefined); + const [openNewTransaction, setOpenNewTransaction] = useState(false) + + useEffect(() => { + if (fillCapRef.current) { + // measure the max possible string width once + fillCapRef.current.textContent = `${bin.grainCapacity(user)}/${bin.grainCapacity(user)}`; + setFillCapWidth(fillCapRef.current.offsetWidth); + } + }, [bin, user]); + + useEffect(()=>{ + setManualFillPercent(bin.fillPercent()) + setManualBushels(bin.bushels()) + },[bin]) // useEffect(() => { // if(devices.length > 0){ @@ -76,6 +99,18 @@ export default function BinSummary(props: Props){ ) } + const currentFill = () => { + if(bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_MANUAL){ + if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){ + return Math.round((manualBushels / bin.bushelsPerTonne())*10)/10 + }else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){ + return Math.round((manualBushels / (bin.bushelsPerTonne() * 0.907))*10)/10 + } + return Math.round(manualBushels) + } + return bin.grainInventory(user) + } + const inventorySummary = () => { return ( @@ -111,14 +146,58 @@ export default function BinSummary(props: Props){ {/* Bin Fill */} - + Bin Fill - - {bin.binFillCap()} + {/* hidden measuring span, renders off-screen */} + + + {currentFill()}/{bin.grainCapacity(user)} + {bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_MANUAL ? + { + setOpenNewTransaction(true) + }} + onChange={(_, val) => { + let fillPercent = val as number + setManualFillPercent(fillPercent) + let newBushels = (fillPercent/100) * bin.bushelCapacity() + setManualBushels(newBushels) + //this does casue the 3d bin to fill as you drag it but it throws off the transaction and the reset if you cancel + // let clone = cloneDeep(bin) + // let inventory = clone.settings.inventory ?? pond.BinInventory.create() + // inventory.grainBushels = newBushels + // if(setBin){ + // setBin(clone) + // } + }} + min={0} + max={100} + sx={{ + flexGrow: 1, + color: "#4caf50", + "& .MuiSlider-thumb": { + width: 16, + height: 16, + }, + "& .MuiSlider-rail": { + backgroundColor: "rgba(255,255,255,0.1)", + }, + }} + /> + : + } + + {bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_MANUAL ? manualFillPercent : bin.fillPercent()}% + @@ -141,15 +224,17 @@ export default function BinSummary(props: Props){ Last Updated - - - - - {moment(bin.status.timestamp).fromNow()} - + + + + + + {moment(bin.status.timestamp).fromNow()} + + + {activity(bin.status.timestamp)} - {activity(bin.status.timestamp)} - + @@ -158,6 +243,27 @@ export default function BinSummary(props: Props){ return ( + { + //this resets all of the state variables used + setOpenNewTransaction(false); + if(!confirmed){ + setManualBushels(bin.bushels()) + setManualFillPercent(bin.fillPercent()) + }else{ + let clone = cloneDeep(bin) + let inventory = clone.settings.inventory ?? pond.BinInventory.create() + inventory.grainBushels = manualBushels + if(setBin){ + setBin(clone) + } + } + + }} + /> setOpenGrainDialog(false)} permissions={permissions} updateBin={updateBinCallback}/> {inventorySummary()} diff --git a/src/bin/binTableView.tsx b/src/bin/binTableView.tsx index 0c9958d..242f82a 100644 --- a/src/bin/binTableView.tsx +++ b/src/bin/binTableView.tsx @@ -300,7 +300,8 @@ export default function BinTableView(props: Props) { }}> Show All Cables - + diff --git a/src/grain/GrainTransaction.tsx b/src/grain/GrainTransaction.tsx index c6b2cfe..d7395e5 100644 --- a/src/grain/GrainTransaction.tsx +++ b/src/grain/GrainTransaction.tsx @@ -37,7 +37,7 @@ interface Props { asDestination?: boolean; restrictMatching?: boolean; open: boolean; - close: () => void; + close: (confirmed?: boolean) => void; callback?: (newTransaction?: pond.Transaction) => void; allowAttachmentUploads?: boolean; } @@ -82,7 +82,7 @@ export default function GrainTransaction(props: Props) { const [filePermission, setFilePermission] = useState(false); const closeDialogs = (confirmed: boolean, newTransaction?: pond.Transaction) => { - close(); + close(confirmed); setGrainChangeVal("0"); setGrainEntry("0"); setIsObject(""); diff --git a/src/models/Bin.ts b/src/models/Bin.ts index a3e46f4..6f67212 100644 --- a/src/models/Bin.ts +++ b/src/models/Bin.ts @@ -162,6 +162,11 @@ export class Bin { return colour; } + /** + * this function returns the number of bushels in the bin, if using the automatic lidar or libracart to control inventory it will use the bushels in status + * otherwise will use the bushels in the inventory found in settings + * @returns (number) the current bushels in the bin + */ public bushels(): number { let control = this.settings.inventory?.inventoryControl; let bushels = this.settings.inventory?.grainBushels || 0 @@ -172,6 +177,14 @@ export class Bin { return bushels } + /** + * this function returns the bushelCapacity in the bins specs as it is stored or 0 if the specs are undefined + * @returns (number) the capacity of the bin in bushels + */ + public bushelCapacity(): number { + return this.settings.specs?.bushelCapacity ?? 0 + } + public fillPercent(): number { let fill = 0; if (this.settings.inventory && this.settings.specs) { @@ -281,6 +294,12 @@ export class Bin { return bpt; } + /** + * this function returns a bins stored inventory in the unit of the passed in user, + * it can return it in bushels, US tons, or metric Tonnes + * @param user the user object + * @returns (number) bins current stored inventory + */ public grainInventory(user: User): number { let grain = this.bushels() if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.bushelsPerTonne() > 1){ @@ -291,6 +310,22 @@ export class Bin { return Math.round(grain*100)/100 } + /** + * this function returns a bins capacity in the unit of the passed in user, + * it can return it in bushels, US tons, or metric Tonnes + * @param user the user object + * @returns (number) bins max capacity + */ + public grainCapacity(user: User): number { + let capacity = this.bushelCapacity() + if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.bushelsPerTonne() > 1){ + capacity = capacity / this.bushelsPerTonne() + }else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.bushelsPerTonne() > 1){ + capacity = capacity / (this.bushelsPerTonne() * 0.907) + } + return Math.round(capacity*100)/100 + } + /** * gets the enum value for the inventory control in the bins inventory */ diff --git a/src/pages/BinV2.tsx b/src/pages/BinV2.tsx index 819dfda..25699e5 100644 --- a/src/pages/BinV2.tsx +++ b/src/pages/BinV2.tsx @@ -553,6 +553,7 @@ export default function BinV2(){ openSnack("Bin has Been Updated") }) }} + setBin={setBin} /> {/* render drawers */} {noteDrawer()}