finished hooking up the inventory adjustment slider when using manual control on the bin page

This commit is contained in:
csawatzky 2026-06-03 12:36:08 -06:00
parent b8a49197cb
commit 13c15ec195
6 changed files with 169 additions and 26 deletions

View file

@ -207,16 +207,16 @@ export default function BinTableExpanded(props: Props) {
<Typography sx={{fontWeight: 600, fontSize: 10}}>{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "+20 °F" : "+10 °C"} above target</Typography>
</Box>
</Box>
<Box sx={{ display: "flex", flexDirection: "row", overflowX: "auto", gap: 2}}>
{cables.map((cable, i) => (
<Box key={i} sx={{ flexShrink: 0 }}>
<Typography className={classes.headerCellStyle} sx={{ textAlign: "center" }}>
{cable.name}
</Typography>
{cableTable(cable)}
<Box sx={{ display: "flex", flexDirection: "row", overflowX: "auto", gap: 2, paddingBottom: 2}}>
{cables.map((cable, i) => (
<Box key={i} sx={{ flexShrink: 0 }}>
<Typography className={classes.headerCellStyle} sx={{ textAlign: "center" }}>
{cable.name}
</Typography>
{cableTable(cable)}
</Box>
))}
</Box>
))}
</Box>
</Box>
)
}

View file

@ -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<Map<string, pond.BinComponentPreferences> | undefined>
>;
updateBinCallback?: (bin: Bin) => void
setBin?: React.Dispatch<React.SetStateAction<Bin>>;
}
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<Device | undefined>(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<HTMLSpanElement>(null);
const [fillCapWidth, setFillCapWidth] = useState<number | undefined>(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 (
<Card raised sx={{ marginBottom: 2 }}>
@ -111,14 +146,58 @@ export default function BinSummary(props: Props){
</Box>
{/* Bin Fill */}
<Box sx={{ flexGrow: 1, maxWidth: 400, mx: 4 }}>
<Box sx={{ flexGrow: 1, maxWidth: 450, mx: 4 }}>
<Typography variant="caption" sx={{ color: grey[500] }}>
Bin Fill
</Typography>
<Box display="flex" alignItems="center" gap={1} sx={{ mt: 0.5 }}>
<Typography variant="body2" noWrap>
{bin.binFillCap()}
{/* hidden measuring span, renders off-screen */}
<span
ref={fillCapRef}
style={{
position: "absolute",
visibility: "hidden",
whiteSpace: "nowrap",
fontSize: "0.875rem", // match body2
}}
/>
<Typography variant="body2" noWrap sx={{ width: fillCapWidth, flexShrink: 0 }}>
{currentFill()}/{bin.grainCapacity(user)}
</Typography>
{bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_MANUAL ?
<Slider
value={manualFillPercent}
onChangeCommitted={() => {
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)",
},
}}
/>
:
<LinearProgress
variant="determinate"
value={bin.fillPercent()}
@ -133,6 +212,10 @@ export default function BinSummary(props: Props){
},
}}
/>
}
<Typography variant="body2" noWrap sx={{ width: 100 }}>
{bin.inventoryControl() === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_MANUAL ? manualFillPercent : bin.fillPercent()}%
</Typography>
</Box>
</Box>
@ -141,15 +224,17 @@ export default function BinSummary(props: Props){
<Typography variant="caption" sx={{ color: grey[500] }}>
Last Updated
</Typography>
<Box display="flex" alignItems="center" gap={2} sx={{ mt: 0.5 }}>
<Box display="flex" alignItems="center" gap={1}>
<AccessTime sx={{ fontSize: 16, color: grey[400] }} />
<Typography variant="body2" sx={{ color: grey[300] }}>
{moment(bin.status.timestamp).fromNow()}
</Typography>
<Tooltip title="Bin Status will update whenever its settings change or a device with a connected sensor checks in">
<Box display="flex" alignItems="center" gap={2} sx={{ mt: 0.5 }}>
<Box display="flex" alignItems="center" gap={1}>
<AccessTime sx={{ fontSize: 16, color: grey[400] }} />
<Typography variant="body2" sx={{ color: grey[300] }}>
{moment(bin.status.timestamp).fromNow()}
</Typography>
</Box>
{activity(bin.status.timestamp)}
</Box>
{activity(bin.status.timestamp)}
</Box>
</Tooltip>
</Box>
</Box>
</Card>
@ -158,6 +243,27 @@ export default function BinSummary(props: Props){
return (
<Box padding={2}>
<GrainTransaction
open={openNewTransaction}
mainObject={bin}
grainAdjustment={manualBushels - bin.bushels()}
close={(confirmed) => {
//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)
}
}
}}
/>
<ChangeGrainDialog bin={bin} open={openGrainDialog} closeDialog={()=>setOpenGrainDialog(false)} permissions={permissions} updateBin={updateBinCallback}/>
{inventorySummary()}
<Grid2 container spacing={2}>

View file

@ -300,7 +300,8 @@ export default function BinTableView(props: Props) {
}}>
Show All Cables
</Button>
<Tooltip title="testing">
<Tooltip title="This table shows the bins levels using nodes that are in the grain averaged together. Data comes from the bins status.
Use the button to see all of the cables individually.">
<Info />
</Tooltip>
</Box>