bin card, no svg yet

This commit is contained in:
Carter 2025-03-10 16:35:19 -06:00
parent a0eabf50c6
commit 7edba7e25b
4 changed files with 848 additions and 153 deletions

525
src/bin/BinCardV2.tsx Normal file
View file

@ -0,0 +1,525 @@
import {
Box,
Card,
darken,
Grid,
IconButton,
Theme,
Typography,
} from "@mui/material";
import HumidityIcon from "component/HumidityIcon";
import TemperatureIcon from "component/TemperatureIcon";
import GrainDescriber from "grain/GrainDescriber";
import { cloneDeep } from "lodash";
import { Bin } from "models";
import { GrainCable } from "models/GrainCable";
import moment from "moment";
import { pond } from "protobuf-ts/pond";
import { useGlobalState } from "providers";
import React, { useEffect, useState } from "react";
import { celsiusToFahrenheit, getGrainUnit, or } from "utils";
//import { useHistory } from "react-router";
//import BinModeDot from "./BinModeDot";
// import BinSVGV2 from "./BinSVGV2";
import { avg } from "utils";
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
import { quack } from "protobuf-ts/quack";
import AerationFanIcon from "products/AgIcons/AerationFanIcon";
import ObjectHeaterIcon from "products/Construction/ObjectHeaterIcon";
import { CheckCircle, Warning } from "@mui/icons-material";
import { makeStyles } from "@mui/styles";
const useStyles = makeStyles((theme: Theme) => {
return ({
displayBox: {
background: darken(theme.palette.background.default, 0.05),
borderRadius: 5,
marginRight: -30, //negative margin to extend the box behind the bin svg
paddingRight: 30, //padding to offset the text and ignore the extension
marginTop: 5
}
});
});
interface Props {
bin: Bin;
duplicateBin: (bin: Bin) => void;
dupHovered: (hovered: boolean) => void;
valDisplay?: "high" | "low" | "average";
}
interface GrainDetails {
temp: number;
humid: number;
emc: number | undefined;
}
export default function BinCard(props: Props) {
const { bin, valDisplay } = props;
const [cables, setCables] = useState<GrainCable[]>();
//const [modeDetails, setModeDetails] = useState("");
const [lidarPercentage, setLidarPercentage] = useState<number | undefined>();
const [lidarBushels, setLidarBushels] = useState<number | undefined>();
const [{ user }] = useGlobalState();
const classes = useStyles();
const [average, setAverage] = useState<GrainDetails>();
const [coldNode, setColdNode] = useState<GrainDetails>();
const [hotNode, setHotNode] = useState<GrainDetails>();
const [mostMissed, setMostMissed] = useState(0);
const warningThreshold = 6;
const tempColour = describeMeasurement(
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE
).colour();
const humColour = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_PERCENT).colour();
const emcColour = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_GRAIN_EMC).colour();
useEffect(() => {
let newGrainCables: GrainCable[] = [];
if (bin.status.grainCables === undefined) return;
let mostMissedReadings = 0;
let allTemps: number[] = [];
let allHums: number[] = [];
let allMoistures: number[] = [];
let coldestNode: GrainDetails | undefined;
let hottestNode: GrainDetails | undefined;
let now = moment();
bin.status.grainCables.forEach(cable => {
let c: GrainCable = new GrainCable();
//flip the cables so that for display node 1 is at the bottom
let cableTemps = cloneDeep(cable.celcius);
let cableHums = cloneDeep(cable.relativeHumidity);
let cableEMC = cloneDeep(cable.moisture);
c.temperatures = cableTemps.reverse();
c.humidities = cableHums.reverse();
c.grainMoistures = cableEMC.reverse();
c.topNode = cable.topNode;
newGrainCables.push(c);
//determine the averages for temp/RH/EMC for the bin using all of the cables
let temps = cloneDeep(cable.celcius);
let hums = cloneDeep(cable.relativeHumidity);
let moistures = cloneDeep(cable.moisture);
const spliceEnd = cable.topNode > 0 ? cable.topNode : temps.length;
let grainTemps = temps.splice(0, spliceEnd);
let grainHums = hums.splice(0, spliceEnd);
let grainEMCs = moistures.splice(0, spliceEnd);
allTemps.push(...grainTemps);
allHums.push(...grainHums);
allMoistures.push(...grainEMCs);
//set the hottest and coldest nodes
if (coldestNode === undefined || Math.min(...grainTemps) < coldestNode.temp) {
let lowTempIndex =
grainTemps.indexOf(Math.min(...grainTemps)) === -1
? 0
: grainTemps.indexOf(Math.min(...grainTemps));
coldestNode = {
temp: grainTemps[lowTempIndex],
humid: grainHums[lowTempIndex],
emc: grainEMCs[lowTempIndex]
};
}
if (hottestNode === undefined || Math.max(...grainTemps) > hottestNode.temp) {
let highTempIndex =
grainTemps.indexOf(Math.max(...grainTemps)) === -1
? 0
: grainTemps.indexOf(Math.max(...grainTemps));
hottestNode = {
temp: grainTemps[highTempIndex],
humid: grainHums[highTempIndex],
emc: grainEMCs[highTempIndex]
};
}
let lastRead = moment(cable.lastRead);
let elapsedMS = now.diff(lastRead);
if (elapsedMS > cable.measurementInterval) {
let missedReadings = Math.floor(elapsedMS / cable.measurementInterval);
if (missedReadings > mostMissedReadings) {
mostMissedReadings = missedReadings;
}
}
});
setCables(newGrainCables);
setMostMissed(mostMissedReadings);
setColdNode(coldestNode);
setHotNode(hottestNode);
setAverage({
temp: avg(allTemps),
humid: avg(allHums),
emc: avg(allMoistures)
});
let cm = 0;
if (bin.status.distance && bin.status.distance > 0) {
//note that no conversions are happening as the unit measurement model is not being used so the value will be in cm
cm = bin.status.distance;
let height = or(bin.settings.specs?.heightCm, 0);
let ratio = 1 - cm / height;
let capacity = or(bin.settings.specs?.bushelCapacity, 0);
let lidarEstimate = Math.round(capacity * ratio);
setLidarBushels(lidarEstimate);
setLidarPercentage(Math.round((lidarEstimate / capacity) * 100));
}
}, [bin]);
// useEffect(() => {
// let now = moment();
// let duration = moment.duration(moment(bin.status.lastModeChange).diff(now));
// let days = duration.asDays();
// days = Math.abs(days);
// duration.subtract(moment.duration(days, "days"));
// let hours = duration.hours();
// hours = Math.abs(hours);
// if (days > 50 && bin.settings.mode === pond.BinMode.BIN_MODE_DRYING) {
// setModeDetails("Calculating...");
// } else if (bin.settings.mode === pond.BinMode.BIN_MODE_NONE) {
// setModeDetails("No Mode");
// } else {
// setModeDetails(Math.floor(days) + "d " + hours + "h");
// }
// }, [bin]);
const typeDisplay = () => {
let grainType = bin.settings.inventory?.grainType ?? pond.Grain.GRAIN_NONE;
if (bin.storage() === pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN) {
return (
<Box>
<Typography variant="subtitle2" style={{ fontSize: "0.7rem", fontWeight: 700 }}>
{GrainDescriber(grainType).name}
</Typography>
{/* <Typography variant="subtitle2" style={{ fontSize: "0.7rem", fontWeight: 700 }}>
{bin.settings.inventory?.grainSubtype}
</Typography> */}
</Box>
);
}
return (
<Box>
<Typography variant="subtitle2" style={{ fontSize: "0.7rem", fontWeight: 700 }}>
{bin.settings.inventory?.customTypeName}
</Typography>
</Box>
);
};
const tempDisplay = () => {
let display = "--";
let val;
switch (valDisplay) {
case "average":
val = average?.temp;
break;
case "low":
val = coldNode?.temp;
break;
case "high":
val = hotNode?.temp;
break;
}
if (val !== undefined && !isNaN(val)) {
if (user.settings.temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
val = celsiusToFahrenheit(val);
}
display = val.toFixed(2);
}
return (
<Typography
align="center"
noWrap
style={{ fontSize: "0.85rem", fontWeight: 650, color: tempColour }}>
{display +
(user.settings.temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_CELSIUS
? "°C"
: "°F")}
</Typography>
);
};
const percentDisplay = () => {
let display = "--";
let val;
let useEMC = false;
switch (valDisplay) {
case "average":
if (average?.emc) {
useEMC = true;
val = average.emc;
} else {
val = average?.humid;
}
break;
case "low":
if (coldNode?.emc) {
useEMC = true;
val = coldNode.emc;
} else {
val = coldNode?.humid;
}
break;
case "high":
if (hotNode?.emc) {
useEMC = true;
val = hotNode.emc;
} else {
val = hotNode?.humid;
}
break;
}
if (val !== undefined && !isNaN(val)) {
display = val.toFixed(2);
}
return (
<Typography
align="center"
noWrap
style={{ fontSize: "0.85rem", fontWeight: 650, color: useEMC ? emcColour : humColour }}>
{display}%
</Typography>
);
};
const cableBox = () => {
return (
<Box className={classes.displayBox}>
<Grid container alignContent="center" alignItems="center" direction="row">
<Grid item xs={3}>
<TemperatureIcon heightWidth={20} />
</Grid>
<Grid item xs={9}>
<Box>
{tempDisplay()}
<Typography
align="center"
color="textSecondary"
noWrap
style={{ fontSize: "0.5rem" }}>
{valDisplay === "high" ? "High" : valDisplay === "low" ? "Low" : "Average"}
</Typography>
</Box>
</Grid>
<Grid item xs={3} style={{ paddingLeft: 5 }}>
<HumidityIcon height={20} />
</Grid>
<Grid item xs={9}>
<Box>
{percentDisplay()}
<Typography
align="center"
color="textSecondary"
noWrap
style={{ fontSize: "0.5rem" }}>
{valDisplay === "high" ? "High" : valDisplay === "low" ? "Low" : "Average"}
</Typography>
</Box>
</Grid>
</Grid>
</Box>
);
};
const fanBox = (controller: pond.BinFan) => {
return (
<Box className={classes.displayBox} key={controller.key}>
<Grid container direction="row" alignItems="center" alignContent="center">
<Grid item xs={3} style={{ paddingLeft: 5, paddingTop: 5 }}>
<AerationFanIcon size={18} />
</Grid>
<Grid item xs={9}>
<Box>
<Typography
align="center"
noWrap
style={{
fontSize: "0.7rem",
fontWeight: 650,
color: controller.state ? "green" : "orange"
}}>
{controller.state ? "ON" : "OFF"}
</Typography>
</Box>
</Grid>
</Grid>
</Box>
);
};
const heaterBox = (controller: pond.BinHeater) => {
return (
<Box className={classes.displayBox} key={controller.key}>
<Grid container direction="row" alignItems="center" alignContent="center">
<Grid item xs={3} style={{ paddingLeft: 5, paddingTop: 3 }}>
{/* <ObjectHeaterIcon height={18} width={18} /> */}
<ObjectHeaterIcon />
</Grid>
<Grid item xs={9}>
<Box>
<Typography
align="center"
noWrap
style={{
fontSize: "0.7rem",
fontWeight: 650,
color: controller.state ? "green" : "orange"
}}>
{controller.state ? "ON" : "OFF"}
</Typography>
</Box>
</Grid>
</Grid>
</Box>
);
};
const binGraphic = () => {
return (
<Box display="flex" justifyContent="center" paddingTop={0}>
<Box padding={0} style={{ flex: 1, textAlign: "left", flexDirection: "column" }}>
{typeDisplay()}
{cableBox()}
{bin.status.fans.map(controller => fanBox(controller))}
{bin.status.heaters.map(controller => heaterBox(controller))}
</Box>
<Box style={{ flex: 1, textAlign: "center", flexDirection: "column" }}>
{/* <BinSVGV2
cableEstimate={bin.settings.autoGrainNode}
height={160}
binShape={bin.settings.specs?.shape}
fillPercentage={bin.fillPercent()}
lidarEstimate={lidarPercentage}
cables={cables}
highTemp={bin.settings.highTemp}
lowTemp={bin.settings.lowTemp}
hottestNodeTemp={valDisplay === "high" ? hotNode?.temp : undefined}
coldestNodeTemp={valDisplay === "low" ? coldNode?.temp : undefined}
inventoryControl={bin.inventoryControl()}
/> */}
hi
</Box>
</Box>
);
};
const inventoryDisplay = (current: number, capacity: number) => {
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
return (
Math.round(current * 35.239).toLocaleString() +
"/" +
Math.round(capacity * 35.239).toLocaleString() +
(lidarBushels ? "(" + Math.round(lidarBushels * 35.239).toLocaleString() + " est)" : "") +
" L"
);
}
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bin.bushelsPerTonne() > 1) {
return (
bin.grainTonnes().toLocaleString() +
(lidarBushels
? "(" + Math.round(lidarBushels / bin.bushelsPerTonne()).toLocaleString() + " est)"
: "") +
" mT " +
bin.fillPercent() +
"%"
);
}
return (
current.toLocaleString() +
"/" +
capacity.toLocaleString() +
(lidarBushels ? "(" + lidarBushels.toLocaleString() + " est)" : "") +
" bu"
);
};
const componentStateBanner = () => {
const hasCables = bin.status.grainCables.length > 0;
return (
<Box display="flex" justifyContent="space-between">
{hasCables ? (
<React.Fragment>
<Typography style={{ fontSize: 15, fontWeight: 650 }}>
{mostMissed < 3 ? "Active" : mostMissed <= warningThreshold ? "Missing" : "Inactive"}
</Typography>
{mostMissed < 3 ? (
<CheckCircle style={{ color: "green" }} />
) : mostMissed <= warningThreshold ? (
<Warning style={{ color: "yellow" }} />
) : (
<Warning style={{ color: "red" }} />
)}
</React.Fragment>
) : (
<Typography style={{ fontSize: 15, fontWeight: 650 }}>Unmonitored</Typography>
)}
</Box>
);
};
const info = () => {
const inv = bin.settings.inventory;
let bushelAmount = inv?.grainBushels;
let bushelCapacity = bin.settings.specs?.bushelCapacity;
const empty =
!inv || inv.empty || !bushelCapacity || bushelCapacity <= 0 || inv.grainBushels <= 0;
return (
<Box width={1} marginTop={0}>
<Typography align="center" color="textSecondary" noWrap style={{ fontSize: "0.65rem" }}>
{empty || !bushelAmount || !bushelCapacity
? "empty"
: inventoryDisplay(bushelAmount, bushelCapacity)}
</Typography>
</Box>
);
};
return (
<Card>
{user.hasFeature("admin") && (
<IconButton
style={{
height: 35,
width: 35,
position: "absolute",
zIndex: 2,
right: 1,
top: 1
}}
onClick={e => props.duplicateBin(bin)}
onMouseEnter={() => props.dupHovered(true)}
onMouseLeave={() => props.dupHovered(false)}>
+
</IconButton>
)}
{/* <Box position="absolute" top={4} right={4}>
<BinModeDot mode={bin.settings.mode} />
</Box> */}
<Box padding={1}>
<Typography
align="left"
variant="body1"
color="textPrimary"
noWrap
style={{ fontSize: "0.8rem", fontWeight: 700 }}>
{bin.name()}
</Typography>
{binGraphic()}
{info()}
{componentStateBanner()}
</Box>
{/* <Box style={{position: "absolute", right:5, bottom: 1}}>
<Warning />
</Box> */}
</Card>
);
}

152
src/bin/BinsList.tsx Normal file
View file

@ -0,0 +1,152 @@
import {
Box,
Button,
Grid2 as Grid,
Theme,
Typography
} from "@mui/material";
import { Bin } from "models";
import React, { useRef, useState } from "react";
// import ScrollMenu from "react-horizontal-scroll-menu";
// import { useHistory } from "react-router";
import { ArrowForward, ArrowBack } from "@mui/icons-material";
import { useMobile } from "hooks";
import BinCardV2 from "./BinCardV2";
import { makeStyles } from "@mui/styles";
import { useNavigate } from "react-router-dom";
interface Props {
bins: Bin[];
duplicateBin: (bin: Bin) => void;
title?: string;
gridView?: boolean;
loadMore?: (newTranslation: number) => void;
startingTranslate: number;
valDisplay?: "high" | "low" | "average";
}
const useStyles = makeStyles((theme: Theme) => {
return ({
gridListTile: {
position: "relative",
minHeight: "184px",
height: "auto !important",
//width: "184px",
padding: 2
},
hidden: {
visibility: "hidden"
}
})
});
export default function BinsList(props: Props) {
const { bins, duplicateBin, title, gridView, loadMore, startingTranslate, valDisplay } = props;
const classes = useStyles();
// const history = useHistory();
const navigate = useNavigate()
const isMobile = useMobile();
const [duplicate, setDuplicate] = useState(false);
const scrollRef = useRef<any>(null);
const goToBin = (i: number) => {
let path = "/bins/" + bins[i].key();
navigate(path, { state: {bin: bins[i]} });
};
// const scroll = () => {
// return (
// <ScrollMenu
// wheel={false}
// ref={scrollRef}
// alignCenter={false}
// inertiaScrolling
// translate={startingTranslate}
// hideArrows
// hideSingleArrow
// arrowDisabledClass={classes.hidden}
// onUpdate={params => {
// if (scrollRef.current.state) {
// if (scrollRef.current.getOffsetAtEnd() === params.translate && loadMore) {
// loadMore(params.translate);
// }
// }
// }}
// onSelect={e => {
// if (!duplicate) {
// goToBin(e as number);
// }
// }}
// arrowLeft={
// <Button style={{ height: 184, display: isMobile ? "none" : "block" }}>
// <ArrowBack />
// </Button>
// }
// arrowRight={
// <Button style={{ height: 184, display: isMobile ? "none" : "block" }}>
// <ArrowForward />
// </Button>
// }
// data={bins.map((b, i) => (
// <Box key={i} className={classes.gridListTile}>
// <BinCardV2
// bin={b}
// duplicateBin={duplicateBin}
// dupHovered={setDuplicate}
// valDisplay={valDisplay}
// />
// </Box>
// ))}
// />
// );
// };
const grid = () => {
return (
<Grid container direction="row">
{bins.map((b, i) =>
isMobile ? (
<Grid
size={{
xs: 6,
sm: 4,
md: 3,
lg: 2,
}}
key={i}
className={classes.gridListTile}
onClick={() => goToBin(i)}>
<BinCardV2
bin={b}
duplicateBin={duplicateBin}
dupHovered={setDuplicate}
valDisplay={valDisplay}
/>
</Grid>
) : (
<Box
key={i}
style={{ width: "184px" }}
className={classes.gridListTile}
onClick={() => goToBin(i)}>
<BinCardV2
bin={b}
duplicateBin={duplicateBin}
dupHovered={setDuplicate}
valDisplay={valDisplay}
/>
</Box>
)
)}
</Grid>
);
};
return (
<React.Fragment>
{title && <Typography>{title}</Typography>}
{/* {gridView ? grid() : scroll()} */}
{grid()}
</React.Fragment>
);
}

View file

@ -1,27 +1,29 @@
import { Box, Button, Grid } from "@material-ui/core";
import { getTableIcons } from "common/ResponsiveTable";
import { Box, Button, Grid2 as Grid } from "@mui/material";
// import { getTableIcons } from "common/ResponsiveTable";
import SearchBar from "common/SearchBar";
import SearchSelect, { Option } from "common/SearchSelect";
import MaterialTable, { MTableToolbar } from "material-table";
import { Bin, BinYard, Field } from "models";
import { Gate } from "models/Gate";
import { GrainBag } from "models/GrainBag";
import { ObjectHeater } from "models/ObjectHeater";
// import MaterialTable, { MTableToolbar } from "material-table";
// import { Bin, BinYard, Field } from "models";
import { Bin } from "models";
// import { Gate } from "models/Gate";
// import { GrainBag } from "models/GrainBag";
// import { ObjectHeater } from "models/ObjectHeater";
import ObjectDescriber, { SearchableObjects } from "objects/ObjectDescriber";
import { pond } from "protobuf-ts/pond";
import {
useBinAPI,
useBinYardAPI,
useFieldAPI,
// useFieldAPI,
useGateAPI,
useGlobalState,
useGrainBagAPI,
useObjectHeaterAPI
// useGrainBagAPI,
// useObjectHeaterAPI
} from "providers";
import React, { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import TeamSearch from "teams/TeamSearch";
import BulkBinSettings from "./bulkEditForms/bulkBinSettings";
import BulkGrainBagSettings from "./bulkEditForms/bulkGrainBagSettings";
import ResponsiveTable from "common/ResponsiveTable";
//import BulkGateSettings from "./bulkEditForms/bulkGateSettings";
interface customButton {
@ -58,12 +60,13 @@ export default function ObjectTable(props: Props) {
//the api's to load all the objects available to look at in this table
const binAPI = useBinAPI();
const binyardAPI = useBinYardAPI();
const fieldAPI = useFieldAPI();
// const fieldAPI = useFieldAPI();
const gateAPI = useGateAPI();
const grainBagAPI = useGrainBagAPI();
const heaterAPI = useObjectHeaterAPI();
// const grainBagAPI = useGrainBagAPI();
// const heaterAPI = useObjectHeaterAPI();
const load = useCallback(() => {
console.log("Hello!")
if (tableLoading) return;
/**
* switch case to use the correct api to load the object that was selected.
@ -78,6 +81,7 @@ export default function ObjectTable(props: Props) {
if (currentType !== pond.ObjectType.OBJECT_TYPE_UNKNOWN) {
setTableLoading(true);
}
console.log("Hello!")
switch (currentType) {
case pond.ObjectType.OBJECT_TYPE_BIN:
binAPI
@ -97,98 +101,98 @@ export default function ObjectTable(props: Props) {
setTableLoading(false);
});
break;
case pond.ObjectType.OBJECT_TYPE_BINYARD:
binyardAPI
.listBinYards(
pageSize,
pageSize * tablePage,
currentDirection,
currentOrder,
search,
undefined,
selectedUser
)
.then(resp => {
setTableData(resp.data.yard.map(b => BinYard.create(b)));
setObjectTotal(resp.data.total);
setTableLoading(false);
});
break;
case pond.ObjectType.OBJECT_TYPE_FIELD:
fieldAPI
.listFields(
pageSize,
pageSize * tablePage,
currentDirection,
currentOrder,
search,
selectedUser
)
.then(resp => {
setTableData(resp.data.fields.map(f => Field.create(f)));
setObjectTotal(resp.data.total);
setTableLoading(false);
});
break;
case pond.ObjectType.OBJECT_TYPE_GATE:
gateAPI
.listGates(
pageSize,
pageSize * tablePage,
currentDirection,
currentOrder,
search,
undefined,
undefined,
undefined,
isNumerical,
selectedUser
)
.then(resp => {
setTableData(resp.data.gates.map(g => Gate.create(g)));
setObjectTotal(resp.data.total);
setTableLoading(false);
});
break;
case pond.ObjectType.OBJECT_TYPE_GRAIN_BAG:
grainBagAPI
.listGrainBags(
pageSize,
pageSize * tablePage,
currentDirection,
currentOrder,
search,
undefined,
undefined,
isNumerical,
selectedUser
)
.then(resp => {
setTableData(resp.data.grainBags.map(gb => GrainBag.create(gb)));
setObjectTotal(resp.data.total);
setTableLoading(false);
});
break;
case pond.ObjectType.OBJECT_TYPE_HEATER:
heaterAPI
.listObjectHeaters(
pageSize,
pageSize * tablePage,
currentDirection,
currentOrder,
search,
undefined,
selectedUser,
undefined,
undefined,
isNumerical
)
.then(resp => {
setTableData(resp.data.heaters.map(h => ObjectHeater.create(h)));
setObjectTotal(resp.data.total);
setTableLoading(false);
});
break;
// case pond.ObjectType.OBJECT_TYPE_BINYARD:
// binyardAPI
// .listBinYards(
// pageSize,
// pageSize * tablePage,
// currentDirection,
// currentOrder,
// search,
// undefined,
// selectedUser
// )
// .then(resp => {
// setTableData(resp.data.yard.map(b => BinYard.create(b)));
// setObjectTotal(resp.data.total);
// setTableLoading(false);
// });
// break;
// case pond.ObjectType.OBJECT_TYPE_FIELD:
// fieldAPI
// .listFields(
// pageSize,
// pageSize * tablePage,
// currentDirection,
// currentOrder,
// search,
// selectedUser
// )
// .then(resp => {
// setTableData(resp.data.fields.map(f => Field.create(f)));
// setObjectTotal(resp.data.total);
// setTableLoading(false);
// });
// break;
// case pond.ObjectType.OBJECT_TYPE_GATE:
// gateAPI
// .listGates(
// pageSize,
// pageSize * tablePage,
// currentDirection,
// currentOrder,
// search,
// undefined,
// undefined,
// undefined,
// isNumerical,
// selectedUser
// )
// .then(resp => {
// setTableData(resp.data.gates.map(g => Gate.create(g)));
// setObjectTotal(resp.data.total);
// setTableLoading(false);
// });
// break;
// case pond.ObjectType.OBJECT_TYPE_GRAIN_BAG:
// grainBagAPI
// .listGrainBags(
// pageSize,
// pageSize * tablePage,
// currentDirection,
// currentOrder,
// search,
// undefined,
// undefined,
// isNumerical,
// selectedUser
// )
// .then(resp => {
// setTableData(resp.data.grainBags.map(gb => GrainBag.create(gb)));
// setObjectTotal(resp.data.total);
// setTableLoading(false);
// });
// break;
// case pond.ObjectType.OBJECT_TYPE_HEATER:
// heaterAPI
// .listObjectHeaters(
// pageSize,
// pageSize * tablePage,
// currentDirection,
// currentOrder,
// search,
// undefined,
// selectedUser,
// undefined,
// undefined,
// isNumerical
// )
// .then(resp => {
// setTableData(resp.data.heaters.map(h => ObjectHeater.create(h)));
// setObjectTotal(resp.data.total);
// setTableLoading(false);
// });
// break;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
@ -202,10 +206,10 @@ export default function ObjectTable(props: Props) {
currentSearchText,
binAPI,
binyardAPI,
fieldAPI,
// fieldAPI,
gateAPI,
grainBagAPI,
heaterAPI
// grainBagAPI,
// heaterAPI
]);
useEffect(() => {
@ -232,14 +236,15 @@ export default function ObjectTable(props: Props) {
);
case pond.ObjectType.OBJECT_TYPE_GRAIN_BAG:
return (
<BulkGrainBagSettings
selectedBags={selectedObjects as GrainBag[]}
refreshCallback={reLoad => {
if (reLoad) {
load();
}
}}
/>
// <BulkGrainBagSettings
// selectedBags={selectedObjects as GrainBag[]}
// refreshCallback={reLoad => {
// if (reLoad) {
// load();
// }
// }}
// />
null
);
default:
}
@ -259,7 +264,7 @@ export default function ObjectTable(props: Props) {
{customButtons &&
selectedObjects.length > 0 &&
customButtons.map((button, i) => (
<Grid item xs={3} key={i}>
<Grid size={{ xs: 3 }} key={i}>
<Button
style={{ width: "100%" }}
variant="contained"
@ -274,11 +279,17 @@ export default function ObjectTable(props: Props) {
);
};
const handleRowsPerPageChange = (event: any) => {
const newRowsPerPage = parseInt(event.target.value, 10); // Get selected value
setPageSize(newRowsPerPage);
setTablePage(0)
}
return (
<Box padding={2}>
{showControls && (
<Grid container direction="row" spacing={2} style={{ padding: 10 }}>
<Grid item>
<Grid>
<SearchSelect
style={{ width: 200 }}
label="From"
@ -295,7 +306,7 @@ export default function ObjectTable(props: Props) {
}}
/>
</Grid>
<Grid item style={{ width: 300 }}>
<Grid style={{ width: 300 }}>
<TeamSearch
label="User/Team"
loadUsers
@ -308,7 +319,15 @@ export default function ObjectTable(props: Props) {
</Grid>
)}
<MaterialTable
<ResponsiveTable
rows={tableData}
total={objectTotal}
pageSize={pageSize}
page={tablePage}
setPage={setTablePage}
handleRowsPerPageChange={handleRowsPerPageChange}
/>
{/* <MaterialTable
isLoading={tableLoading}
key="objectList"
title={ObjectDescriber(currentType).name}
@ -354,13 +373,13 @@ export default function ObjectTable(props: Props) {
onSelectionChange={(data, rowData) => {
setSelectedObjects(data);
}}
// actions={[
// {
// tooltip: "Update Selected Objects",
// icon: "edit",
// onClick: (evt, data) => {console.log(data)}
// }
// ]}
actions={[
{
tooltip: "Update Selected Objects",
icon: "edit",
onClick: (evt, data) => {console.log(data)}
}
]}
onChangeRowsPerPage={pageSize => {
setPageSize(pageSize);
}}
@ -372,7 +391,7 @@ export default function ObjectTable(props: Props) {
</React.Fragment>
)
}}
/>
/> */}
</Box>
);
}

View file

@ -45,7 +45,7 @@ import {
// import AddBinFab from "bin/AddBinFab";
// import BinsFansStatusTable from "bin/BinFansStatusTable";
// import BinSettings from "bin/BinSettings";
// import BinsList from "bin/BinsList";
import BinsList from "bin/BinsList";
// import BinYard from "bin/BinYard";
import BinInventoryChart, { GrainAmount } from "charts/BinInventoryChart";
import BinUtilizationChart from "charts/BinUtilizationChart";
@ -72,7 +72,7 @@ import React, { SetStateAction, useCallback, useEffect, useState } from "react";
import { getGrainUnit, stringToMaterialColour } from "utils";
//import InfiniteScroll from "react-infinite-scroller";
import PageContainer from "./PageContainer";
// import ObjectTable from "objects/ObjectTable";
import ObjectTable from "objects/ObjectTable";
import ResponsiveDialog from "common/ResponsiveDialog";
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
import { green, yellow } from "@mui/material/colors";
@ -584,25 +584,24 @@ export default function Bins(props: Props) {
if (binView === "list") {
return (
// <ObjectTable
// startingObject={pond.ObjectType.OBJECT_TYPE_BIN}
// preLoadedData={paginatedBins.bins}
// rowClickFunction={data => {
// let bin = data as Bin;
// let path = "/bins/" + bin.key();
// navigate(path, { state: { bin: bin }});
// }}
// customButtons={[
// {
// label: "Set High Temp Notifications",
// function: objects => {
// setAlertBins(objects as Bin[]);
// setOpenAddAlerts(true);
// }
// }
// ]}
// />
null
<ObjectTable
startingObject={pond.ObjectType.OBJECT_TYPE_BIN}
preLoadedData={paginatedBins.bins}
rowClickFunction={data => {
let bin = data as Bin;
let path = "/bins/" + bin.key();
navigate(path, { state: { bin: bin }});
}}
customButtons={[
{
label: "Set High Temp Notifications",
function: objects => {
setAlertBins(objects as Bin[]);
setOpenAddAlerts(true);
}
}
]}
/>
);
}
@ -615,7 +614,7 @@ export default function Bins(props: Props) {
<Divider />
</Grid>
<Grid item xs={12}>
{/*<BinsList
<BinsList
valDisplay={cardValDisplay}
gridView={binView === "grid"}
bins={grainBins}
@ -628,7 +627,7 @@ export default function Bins(props: Props) {
setScrollTranslations({ ...scrollTranslations, bins: newTranslation });
}
}}
/>*/}
/>
</Grid>
</React.Fragment>
)}