Merge branch 'staging_environment'
This commit is contained in:
commit
596599cd2b
36 changed files with 1195 additions and 337 deletions
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -43,7 +43,7 @@
|
||||||
"mui-tel-input": "^7.0.0",
|
"mui-tel-input": "^7.0.0",
|
||||||
"notistack": "^3.0.1",
|
"notistack": "^3.0.1",
|
||||||
"openweathermap-ts": "^1.2.10",
|
"openweathermap-ts": "^1.2.10",
|
||||||
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#master",
|
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging",
|
||||||
"query-string": "^9.2.1",
|
"query-string": "^9.2.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
|
|
@ -11967,7 +11967,7 @@
|
||||||
},
|
},
|
||||||
"node_modules/protobuf-ts": {
|
"node_modules/protobuf-ts": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#ab9e8d4fd38f9af7802398403d38fddda5eb01da",
|
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#1c00e059fe16126e85c50581786b7510759920d7",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"protobufjs": "^6.8.8"
|
"protobufjs": "^6.8.8"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
"mui-tel-input": "^7.0.0",
|
"mui-tel-input": "^7.0.0",
|
||||||
"notistack": "^3.0.1",
|
"notistack": "^3.0.1",
|
||||||
"openweathermap-ts": "^1.2.10",
|
"openweathermap-ts": "^1.2.10",
|
||||||
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#master",
|
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging",
|
||||||
"query-string": "^9.2.1",
|
"query-string": "^9.2.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
|
|
|
||||||
|
|
@ -443,14 +443,24 @@ export default function BinCard(props: Props) {
|
||||||
" L"
|
" L"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bin.bushelsPerTonne() > 1) {
|
|
||||||
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
||||||
return (
|
return (
|
||||||
bin.grainTonnes().toLocaleString() +
|
bin.grainInventory().toLocaleString() +
|
||||||
" mT " +
|
" mT " +
|
||||||
bin.fillPercent() +
|
bin.fillPercent() +
|
||||||
"%"
|
"%"
|
||||||
);
|
);
|
||||||
|
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||||
|
return (
|
||||||
|
bin.grainInventory().toLocaleString() +
|
||||||
|
" t " +
|
||||||
|
bin.fillPercent() +
|
||||||
|
"%"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
current.toLocaleString() +
|
current.toLocaleString() +
|
||||||
"/" +
|
"/" +
|
||||||
|
|
|
||||||
168
src/bin/BinControllerDisplay.tsx
Normal file
168
src/bin/BinControllerDisplay.tsx
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
import { Component } from "models"
|
||||||
|
import React, { useEffect, useState } from "react"
|
||||||
|
import { makeStyles } from "@mui/styles";
|
||||||
|
import { Box, Button, DialogActions, DialogContent, DialogTitle, Typography } from "@mui/material";
|
||||||
|
import AerationFanIcon from "products/AgIcons/AerationFanIcon";
|
||||||
|
import { quack } from "protobuf-ts/quack";
|
||||||
|
import { useComponentAPI, useMobile, useSnackbar } from "hooks";
|
||||||
|
import ButtonGroup from "common/ButtonGroup";
|
||||||
|
import ObjectHeaterIcon from "products/Construction/ObjectHeaterIcon";
|
||||||
|
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||||
|
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
deviceID: number
|
||||||
|
component: Component
|
||||||
|
currentState?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles(() => {
|
||||||
|
return ({
|
||||||
|
controllerDisplay: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
paddingLeft: 5,
|
||||||
|
paddingRight: 5
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function BinControllerDisplay(props: Props) {
|
||||||
|
const {component, deviceID, currentState} = props
|
||||||
|
const [controllerState, setControllerState] = useState(0)
|
||||||
|
const [openDialog, setOpenDialog] = useState(false)
|
||||||
|
const [newOutputState, setNewOutputState] = useState(0)
|
||||||
|
const {openSnack} = useSnackbar()
|
||||||
|
const componentAPI = useComponentAPI()
|
||||||
|
const isMobile = useMobile()
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
setControllerState(component.settings.defaultOutputState)
|
||||||
|
},[component])
|
||||||
|
|
||||||
|
|
||||||
|
const controllerIcon = () => {
|
||||||
|
if(component.subType() === quack.BooleanOutputSubtype.BOOLEAN_OUTPUT_SUBTYPE_HEATER){
|
||||||
|
return <ObjectHeaterIcon />
|
||||||
|
}else{
|
||||||
|
return <AerationFanIcon />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setController = () => {
|
||||||
|
let newSettings = component.settings
|
||||||
|
newSettings.defaultOutputState = newOutputState
|
||||||
|
componentAPI.update(deviceID, newSettings).then(resp => {
|
||||||
|
openSnack("Updated controllers output state")
|
||||||
|
setControllerState(newOutputState)
|
||||||
|
}).catch(err => {
|
||||||
|
openSnack("There was a problem updating the controller")
|
||||||
|
}).finally(() => {
|
||||||
|
setOpenDialog(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const controllerDialog = () => {
|
||||||
|
return (
|
||||||
|
<ResponsiveDialog open={openDialog} onClose={() => {setOpenDialog(false)}}>
|
||||||
|
<DialogTitle>Set Controller State</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
This Action will change the output state of the controller
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={()=>{setOpenDialog(false)}}>Cancel</Button>
|
||||||
|
<Button onClick={()=>{setController()}} variant="contained" color="primary">Confirm</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</ResponsiveDialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const componentOn = () => {
|
||||||
|
if(currentState){
|
||||||
|
return currentState
|
||||||
|
}else{
|
||||||
|
let state = false
|
||||||
|
component.status.lastGoodMeasurement.forEach(um => {
|
||||||
|
if(um.type === quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN){
|
||||||
|
if(um.values.length > 0){
|
||||||
|
let readings = um.values
|
||||||
|
if(readings[readings.length-1].values.length > 0){
|
||||||
|
let nodes = readings[readings.length-1].values
|
||||||
|
if (nodes[nodes.length -1] === 1){
|
||||||
|
state = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{controllerDialog()}
|
||||||
|
<Box className={classes.controllerDisplay} key={component.key()} marginTop={1} marginBottom={1}>
|
||||||
|
<Box display="flex" marginY="auto">
|
||||||
|
<Box margin="auto">
|
||||||
|
{controllerIcon()}
|
||||||
|
</Box>
|
||||||
|
<Typography
|
||||||
|
align="center"
|
||||||
|
style={{
|
||||||
|
marginBottom: "auto",
|
||||||
|
marginTop: "auto",
|
||||||
|
paddingLeft: 5,
|
||||||
|
fontSize: isMobile ? "0.85rem" : "1.0rem",
|
||||||
|
fontWeight: 650
|
||||||
|
}}>
|
||||||
|
{component.name()}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
<Box display="flex">
|
||||||
|
<ButtonGroup
|
||||||
|
buttons={[
|
||||||
|
{
|
||||||
|
title: "Auto",
|
||||||
|
function: () => {
|
||||||
|
setNewOutputState(0)
|
||||||
|
setOpenDialog(true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "On",
|
||||||
|
function: () => {
|
||||||
|
setNewOutputState(1)
|
||||||
|
setOpenDialog(true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Off",
|
||||||
|
function: () => {
|
||||||
|
setNewOutputState(2)
|
||||||
|
setOpenDialog(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
toggledButtons={[controllerState]}
|
||||||
|
toggle
|
||||||
|
/>
|
||||||
|
<Typography
|
||||||
|
style={{
|
||||||
|
minWidth: 30,
|
||||||
|
marginLeft: "10px",
|
||||||
|
marginBottom: "auto",
|
||||||
|
marginTop: "auto",
|
||||||
|
fontSize: isMobile ? "0.85rem" : "1.0rem",
|
||||||
|
fontWeight: 650,
|
||||||
|
color: componentOn() ? "green" : "orange"
|
||||||
|
}}>
|
||||||
|
{componentOn() ? "ON" : "OFF"}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -126,14 +126,13 @@ interface BinFormExtension {
|
||||||
hopperHeight: string;
|
hopperHeight: string;
|
||||||
diameter: string;
|
diameter: string;
|
||||||
grainBushels: string;
|
grainBushels: string;
|
||||||
grainTonnes: string;
|
grainWeight: string;
|
||||||
grainType: Option | null;
|
grainType: Option | null;
|
||||||
grainUse: Option | null;
|
grainUse: Option | null;
|
||||||
grainSubtype: string;
|
grainSubtype: string;
|
||||||
customTypeName: string;
|
customTypeName: string;
|
||||||
highTemp: number;
|
highTemp: number;
|
||||||
lowTemp: number;
|
lowTemp: number;
|
||||||
bushelsPerTonne: string;
|
|
||||||
tempTarget: number;
|
tempTarget: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,14 +159,13 @@ export default function BinSettings(props: Props) {
|
||||||
hopperHeight: "",
|
hopperHeight: "",
|
||||||
diameter: "",
|
diameter: "",
|
||||||
grainBushels: "",
|
grainBushels: "",
|
||||||
grainTonnes: "",
|
grainWeight: "",
|
||||||
grainType: null,
|
grainType: null,
|
||||||
grainUse: null,
|
grainUse: null,
|
||||||
grainSubtype: "",
|
grainSubtype: "",
|
||||||
customTypeName: "",
|
customTypeName: "",
|
||||||
highTemp: 20,
|
highTemp: 20,
|
||||||
lowTemp: 10,
|
lowTemp: 10,
|
||||||
bushelsPerTonne: "",
|
|
||||||
tempTarget: 15
|
tempTarget: 15
|
||||||
});
|
});
|
||||||
const [initialized, setInitialized] = useState(false);
|
const [initialized, setInitialized] = useState(false);
|
||||||
|
|
@ -194,6 +192,7 @@ export default function BinSettings(props: Props) {
|
||||||
const [isCustomBin, setIsCustomBin] = useState(false);
|
const [isCustomBin, setIsCustomBin] = useState(false);
|
||||||
const [binModelOps, setBinModelOptions] = useState<Option[]>([]);
|
const [binModelOps, setBinModelOptions] = useState<Option[]>([]);
|
||||||
const [selectedBinModel, setSelectedBinModel] = useState<Option | null>(null);
|
const [selectedBinModel, setSelectedBinModel] = useState<Option | null>(null);
|
||||||
|
const [bushelConversion, setBushelConversion] = useState(0) //the number used to convert the bushels to either tonne or ton based on user preference
|
||||||
const [modelID, setModelID] = useState(0);
|
const [modelID, setModelID] = useState(0);
|
||||||
const [autoTopNode, setAutoTopNode] = useState(false);
|
const [autoTopNode, setAutoTopNode] = useState(false);
|
||||||
const [inventoryControl, setInventoryControl] = useState<pond.BinInventoryControl>(
|
const [inventoryControl, setInventoryControl] = useState<pond.BinInventoryControl>(
|
||||||
|
|
@ -232,14 +231,27 @@ export default function BinSettings(props: Props) {
|
||||||
|
|
||||||
if (initForm.inventory) {
|
if (initForm.inventory) {
|
||||||
setInventoryControl(initForm.inventory.inventoryControl);
|
setInventoryControl(initForm.inventory.inventoryControl);
|
||||||
//make sure bushels per tonne is set so bins that don't have it in the settings yet can still do it before they get updated properly
|
//make sure bushels per ton/ne is set so bins that don't have it in the settings yet can still do it before they get updated properly
|
||||||
if (!initForm.inventory.bushelsPerTonne) {
|
const grain = GrainDescriber(
|
||||||
initForm.inventory.bushelsPerTonne = GrainDescriber(
|
|
||||||
initForm.inventory.grainType
|
initForm.inventory.grainType
|
||||||
).bushelsPerTonne;
|
)
|
||||||
|
|
||||||
|
if (!initForm.inventory.bushelsPerTonne) {
|
||||||
|
initForm.inventory.bushelsPerTonne = grain.bushelsPerTonne;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
setBushelConversion(initForm.inventory.bushelsPerTonne)
|
||||||
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
setBushelConversion(initForm.inventory.bushelsPerTonne * 0.907)
|
||||||
}
|
}
|
||||||
if (initForm.inventory.customGrain){
|
if (initForm.inventory.customGrain){
|
||||||
setCustomGrain(initForm.inventory.customGrain)
|
setCustomGrain(initForm.inventory.customGrain)
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
setBushelConversion(initForm.inventory.customGrain.bushelsPerTonne)
|
||||||
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
setBushelConversion(initForm.inventory.customGrain.bushelsPerTonne * 0.907)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//if the target temp is not set (older bins) make it the midpoint of the high and low temps assuming they are set otherwise make it 15
|
//if the target temp is not set (older bins) make it the midpoint of the high and low temps assuming they are set otherwise make it 15
|
||||||
if (!initForm.inventory.targetTemperature || initForm.inventory.targetTemperature) {
|
if (!initForm.inventory.targetTemperature || initForm.inventory.targetTemperature) {
|
||||||
|
|
@ -290,6 +302,21 @@ export default function BinSettings(props: Props) {
|
||||||
? initForm.inventory.grainBushels * 35.239
|
? initForm.inventory.grainBushels * 35.239
|
||||||
: 0
|
: 0
|
||||||
: initForm.inventory?.grainBushels ?? 0;
|
: initForm.inventory?.grainBushels ?? 0;
|
||||||
|
let weight = ""
|
||||||
|
if(initForm.inventory){
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
weight = (gb/initForm.inventory.bushelsPerTonne).toFixed(2)
|
||||||
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
weight = (gb/(initForm.inventory.bushelsPerTonne * 0.907)).toFixed(2)
|
||||||
|
}
|
||||||
|
if(initForm.inventory.customGrain){
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
weight = (gb/initForm.inventory.customGrain.bushelsPerTonne).toFixed(2)
|
||||||
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
weight = (gb/(initForm.inventory.customGrain.bushelsPerTonne * 0.907)).toFixed(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setForm(initForm);
|
setForm(initForm);
|
||||||
setHighTempC(initForm.highTemp ?? 20);
|
setHighTempC(initForm.highTemp ?? 20);
|
||||||
|
|
@ -299,9 +326,10 @@ export default function BinSettings(props: Props) {
|
||||||
height: h,
|
height: h,
|
||||||
diameter: d,
|
diameter: d,
|
||||||
grainBushels: gb.toFixed(2),
|
grainBushels: gb.toFixed(2),
|
||||||
grainTonnes: initForm.inventory?.bushelsPerTonne
|
grainWeight: weight,
|
||||||
? (gb / initForm.inventory.bushelsPerTonne).toFixed(2)
|
// grainTons: initForm.inventory?.bushelsPerTon
|
||||||
: "",
|
// ? (gb / initForm.inventory.bushelsPerTon).toFixed(2)
|
||||||
|
// : "",
|
||||||
grainType: initForm.inventory?.grainType
|
grainType: initForm.inventory?.grainType
|
||||||
? ToGrainOption(initForm.inventory.grainType)
|
? ToGrainOption(initForm.inventory.grainType)
|
||||||
: null,
|
: null,
|
||||||
|
|
@ -315,8 +343,7 @@ export default function BinSettings(props: Props) {
|
||||||
tempTarget: target,
|
tempTarget: target,
|
||||||
hopperHeight: hopperHeight,
|
hopperHeight: hopperHeight,
|
||||||
topConeHeight: topconeHeight,
|
topConeHeight: topconeHeight,
|
||||||
sidewallHeight: sidewallHeight,
|
sidewallHeight: sidewallHeight
|
||||||
bushelsPerTonne: initForm.inventory?.bushelsPerTonne.toString() ?? "0"
|
|
||||||
});
|
});
|
||||||
setInMoistureString(initForm.inventory?.initialMoisture.toString() ?? "0");
|
setInMoistureString(initForm.inventory?.initialMoisture.toString() ?? "0");
|
||||||
setTMoistureString(initForm.inventory?.targetMoisture.toString() ?? "0");
|
setTMoistureString(initForm.inventory?.targetMoisture.toString() ?? "0");
|
||||||
|
|
@ -771,12 +798,103 @@ export default function BinSettings(props: Props) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const inventoryAmount = () => {
|
||||||
|
const grainWeight = formExtension.grainWeight;
|
||||||
|
const binQuantity = formExtension.grainBushels;
|
||||||
|
|
||||||
|
//as long as the storage type is not fertilizer it is some sort of grain, whether it is supported or custom is not important in this instance so we do not need to check for unknown
|
||||||
|
if(storageType !== pond.BinStorage.BIN_STORAGE_FERTILIZER && ((getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE || getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) && bushelConversion !== 0 && grainWeight !== "")){
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
label="Amount"
|
||||||
|
value={grainWeight}
|
||||||
|
type="number"
|
||||||
|
onChange={event => {
|
||||||
|
let newWeight = event.target.value;
|
||||||
|
//get the bushel amount
|
||||||
|
if (!isNaN(+newWeight)) {
|
||||||
|
let newBushels = Math.round(+newWeight * bushelConversion * 100) / 100;
|
||||||
|
updateForm(
|
||||||
|
"inventory",
|
||||||
|
pond.BinInventory.create({
|
||||||
|
...form.inventory,
|
||||||
|
grainBushels: newBushels
|
||||||
|
})
|
||||||
|
);
|
||||||
|
//updateFormExtension("grainBushels", newBushels.toString())
|
||||||
|
updateFormExtension("grainWeight", newWeight);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
disabled={!canEdit}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: <InputAdornment position="end">{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE ? "mT" : "t"}</InputAdornment>
|
||||||
|
}}
|
||||||
|
className={classes.bottomSpacing}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}else{
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
label="Amount"
|
||||||
|
value={binQuantity}
|
||||||
|
type="number"
|
||||||
|
onChange={event => {
|
||||||
|
let capacity =
|
||||||
|
bin?.settings.storage === pond.BinStorage.BIN_STORAGE_FERTILIZER
|
||||||
|
? +inputCapacity * 35.239
|
||||||
|
: inputCapacity;
|
||||||
|
let value = event?.target.value;
|
||||||
|
let v =
|
||||||
|
value === ""
|
||||||
|
? 0
|
||||||
|
: isNaN(parseFloat(value))
|
||||||
|
? 0
|
||||||
|
: parseFloat(value) >= +capacity
|
||||||
|
? +capacity
|
||||||
|
: parseFloat(value) <= 0
|
||||||
|
? 0
|
||||||
|
: parseFloat(value);
|
||||||
|
if (bin?.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER && v) {
|
||||||
|
v = v / 35.239;
|
||||||
|
}
|
||||||
|
//setNewGrainQuantity(v);
|
||||||
|
updateForm(
|
||||||
|
"inventory",
|
||||||
|
pond.BinInventory.create({
|
||||||
|
...form.inventory,
|
||||||
|
grainBushels: v
|
||||||
|
})
|
||||||
|
);
|
||||||
|
updateFormExtension("grainBushels", value);
|
||||||
|
}}
|
||||||
|
InputProps={{
|
||||||
|
endAdornment: (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
{storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER
|
||||||
|
? "Litres"
|
||||||
|
: "Bushels"}
|
||||||
|
</InputAdornment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
fullWidth
|
||||||
|
variant="outlined"
|
||||||
|
disabled={
|
||||||
|
!canEdit ||
|
||||||
|
inventoryControl === pond.BinInventoryControl.BIN_INVENTORY_CONTROL_AUTOMATIC
|
||||||
|
}
|
||||||
|
className={classes.bottomSpacing}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const inventoryForm = () => {
|
const inventoryForm = () => {
|
||||||
const inventory = form.inventory;
|
const inventory = form.inventory;
|
||||||
const empty = inventory ? inventory.empty : false;
|
const empty = inventory ? inventory.empty : false;
|
||||||
const bushPerTonne = formExtension.bushelsPerTonne;
|
|
||||||
const binQuantity = formExtension.grainBushels;
|
const binQuantity = formExtension.grainBushels;
|
||||||
const grainTonnes = formExtension.grainTonnes;
|
|
||||||
const grainType = formExtension.grainType;
|
const grainType = formExtension.grainType;
|
||||||
const grainSubtype = formExtension.grainSubtype;
|
const grainSubtype = formExtension.grainSubtype;
|
||||||
const grainUse = formExtension.grainUse;
|
const grainUse = formExtension.grainUse;
|
||||||
|
|
@ -805,11 +923,11 @@ export default function BinSettings(props: Props) {
|
||||||
pond.BinInventory.create({
|
pond.BinInventory.create({
|
||||||
...form.inventory,
|
...form.inventory,
|
||||||
grainType: pond.Grain.GRAIN_CUSTOM,
|
grainType: pond.Grain.GRAIN_CUSTOM,
|
||||||
bushelsPerTonne: 0
|
bushelsPerTonne: 0,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
updateFormExtension("grainType", null);
|
updateFormExtension("grainType", null);
|
||||||
updateFormExtension("bushelsPerTonne", "");
|
setBushelConversion(0)
|
||||||
} else {
|
} else {
|
||||||
setStorageType(pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN);
|
setStorageType(pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN);
|
||||||
updateForm(
|
updateForm(
|
||||||
|
|
@ -859,7 +977,8 @@ export default function BinSettings(props: Props) {
|
||||||
let storageType = parseFloat(value) as pond.BinStorage;
|
let storageType = parseFloat(value) as pond.BinStorage;
|
||||||
setStorageType(storageType);
|
setStorageType(storageType);
|
||||||
if (storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
if (storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
||||||
formExtension.bushelsPerTonne = "";
|
// formExtension.bushelsPerTonne = "";
|
||||||
|
setBushelConversion(0)
|
||||||
formExtension.grainBushels = (
|
formExtension.grainBushels = (
|
||||||
parseFloat(formExtension.grainBushels) * 35.239
|
parseFloat(formExtension.grainBushels) * 35.239
|
||||||
).toFixed(0);
|
).toFixed(0);
|
||||||
|
|
@ -1054,7 +1173,29 @@ export default function BinSettings(props: Props) {
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
:
|
:
|
||||||
<Box sx={{border: "1px solid white", borderRadius: 2, padding: 2, marginBottom: 2}}>
|
<Box sx={{border: "1px solid white", borderRadius: 2, padding: 2, marginBottom: 2}}>
|
||||||
<CustomGrainSelector initialGrain={customGrain} onGrainSettingsChange={(newGrainSettings) => {setCustomGrain(newGrainSettings)}}/>
|
<CustomGrainSelector
|
||||||
|
initialGrain={customGrain}
|
||||||
|
onGrainSettingsChange={(newGrainSettings) => {
|
||||||
|
setCustomGrain(newGrainSettings)
|
||||||
|
let conversion = 0
|
||||||
|
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
conversion = newGrainSettings.bushelsPerTonne
|
||||||
|
}else if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
conversion = newGrainSettings.bushelsPerTonne * 0.907
|
||||||
|
}
|
||||||
|
updateForm(
|
||||||
|
"inventory",
|
||||||
|
pond.BinInventory.create({
|
||||||
|
...form.inventory,
|
||||||
|
bushelsPerTonne: newGrainSettings.bushelsPerTonne,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
setBushelConversion(conversion)
|
||||||
|
if(conversion !== 0 && !isNaN(+binQuantity)){
|
||||||
|
updateFormExtension("grainWeight", (+binQuantity/conversion).toFixed(2))
|
||||||
|
}
|
||||||
|
}}/>
|
||||||
</Box>
|
</Box>
|
||||||
}
|
}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
@ -1073,11 +1214,21 @@ export default function BinSettings(props: Props) {
|
||||||
pond.BinInventory.create({
|
pond.BinInventory.create({
|
||||||
...form.inventory,
|
...form.inventory,
|
||||||
grainType: newGrainType,
|
grainType: newGrainType,
|
||||||
bushelsPerTonne: GrainDescriber(newGrainType).bushelsPerTonne
|
bushelsPerTonne: GrainDescriber(newGrainType).bushelsPerTonne,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
//doesn't need to update the form extension to display the bushels per tonne as it is not changeable for the supported grain
|
let conversion = 0
|
||||||
//and is reset whenever the user switches between custom or not
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
conversion = GrainDescriber(newGrainType).bushelsPerTonne
|
||||||
|
}else if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
conversion = GrainDescriber(newGrainType).bushelsPerTon
|
||||||
|
}
|
||||||
|
setBushelConversion(conversion)
|
||||||
|
if(conversion !== 0 && !isNaN(+binQuantity)){
|
||||||
|
//updateFormExtension("grainWeight", (+binQuantity/conversion).toFixed(2))
|
||||||
|
let newWeight = (+binQuantity/conversion).toFixed(2)
|
||||||
|
formExtension.grainWeight = newWeight
|
||||||
|
}
|
||||||
updateFormExtension("grainType", option);
|
updateFormExtension("grainType", option);
|
||||||
}}
|
}}
|
||||||
group
|
group
|
||||||
|
|
@ -1106,7 +1257,8 @@ export default function BinSettings(props: Props) {
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_BUSHELS ||
|
{inventoryAmount()}
|
||||||
|
{/* {getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_BUSHELS ||
|
||||||
storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER ||
|
storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER ||
|
||||||
formExtension.bushelsPerTonne === "0" ||
|
formExtension.bushelsPerTonne === "0" ||
|
||||||
formExtension.bushelsPerTonne === "" ? (
|
formExtension.bushelsPerTonne === "" ? (
|
||||||
|
|
@ -1163,7 +1315,7 @@ export default function BinSettings(props: Props) {
|
||||||
) : (
|
) : (
|
||||||
<TextField
|
<TextField
|
||||||
label="Amount"
|
label="Amount"
|
||||||
value={grainTonnes}
|
value={grainWeight}
|
||||||
type="number"
|
type="number"
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
let newWeight = event.target.value;
|
let newWeight = event.target.value;
|
||||||
|
|
@ -1180,7 +1332,7 @@ export default function BinSettings(props: Props) {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
//updateFormExtension("grainBushels", newBushels.toString())
|
//updateFormExtension("grainBushels", newBushels.toString())
|
||||||
updateFormExtension("grainTonnes", newWeight);
|
updateFormExtension("grainWeight", newWeight);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|
@ -1191,7 +1343,7 @@ export default function BinSettings(props: Props) {
|
||||||
}}
|
}}
|
||||||
className={classes.bottomSpacing}
|
className={classes.bottomSpacing}
|
||||||
/>
|
/>
|
||||||
)}
|
)} */}
|
||||||
{!isCustomInventory && (
|
{!isCustomInventory && (
|
||||||
<SearchSelect
|
<SearchSelect
|
||||||
label="Use"
|
label="Use"
|
||||||
|
|
|
||||||
|
|
@ -196,14 +196,27 @@ export default function BinTransactions(props: Props){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const grainQuantityDisplay = (bushels: number) => {
|
||||||
|
const grainTransaction = selectedTransaction?.transaction.transaction?.grainTransaction ?? pond.GrainTransaction.create()
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainTransaction.bushelsPerTonne > 1){
|
||||||
|
let tonneWeight = bushels / grainTransaction.bushelsPerTonne
|
||||||
|
return tonneWeight + " mT"
|
||||||
|
}
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainTransaction.bushelsPerTonne > 1){
|
||||||
|
let tonneWeight = bushels / (grainTransaction.bushelsPerTonne * 0.907)
|
||||||
|
return tonneWeight + " t"
|
||||||
|
}
|
||||||
|
return bushels + " bushels"
|
||||||
|
}
|
||||||
|
|
||||||
// dialog for approving a transaction
|
// dialog for approving a transaction
|
||||||
const approvalDialog = () => {
|
const approvalDialog = () => {
|
||||||
// get the display information for the transaction
|
// get the display information for the transaction
|
||||||
const grainTransaction = selectedTransaction?.transaction.transaction?.grainTransaction ?? pond.GrainTransaction.create()
|
const grainTransaction = selectedTransaction?.transaction.transaction?.grainTransaction ?? pond.GrainTransaction.create()
|
||||||
const bushels = grainTransaction.bushels ?? 0
|
const bushels = grainTransaction.bushels ?? 0
|
||||||
const weight = bushels / grainTransaction.bushelsPerTonne
|
//const weight = bushels / grainTransaction.bushelsPerTonne
|
||||||
let graintype = grainTransaction.grainType ?? pond.Grain.GRAIN_INVALID
|
let graintype = grainTransaction.grainType ?? pond.Grain.GRAIN_INVALID
|
||||||
const grainDisplay = graintype === pond.Grain.GRAIN_CUSTOM
|
const grainTypeDisplay = graintype === pond.Grain.GRAIN_CUSTOM
|
||||||
? grainTransaction.customGrain
|
? grainTransaction.customGrain
|
||||||
: GrainDescriber(grainTransaction.grainType).name
|
: GrainDescriber(grainTransaction.grainType).name
|
||||||
|
|
||||||
|
|
@ -215,7 +228,7 @@ export default function BinTransactions(props: Props){
|
||||||
<DialogTitle>Accept Transaction</DialogTitle>
|
<DialogTitle>Accept Transaction</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<Box>
|
<Box>
|
||||||
<Typography>{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT ? weight + " mT" : bushels + " bushels"} of {grainTransaction.subtype} {grainDisplay} moved</Typography>
|
<Typography>{grainQuantityDisplay(bushels)} of {grainTransaction.subtype} {grainTypeDisplay} moved</Typography>
|
||||||
<Typography margin={1} fontWeight={650}>From:</Typography>
|
<Typography margin={1} fontWeight={650}>From:</Typography>
|
||||||
{/*Object type selection*/}
|
{/*Object type selection*/}
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
|
|
@ -378,9 +391,9 @@ export default function BinTransactions(props: Props){
|
||||||
// get the display information for the transaction
|
// get the display information for the transaction
|
||||||
const grainTransaction = t.transaction.transaction?.grainTransaction ?? pond.GrainTransaction.create()
|
const grainTransaction = t.transaction.transaction?.grainTransaction ?? pond.GrainTransaction.create()
|
||||||
const bushels = grainTransaction.bushels ?? 0
|
const bushels = grainTransaction.bushels ?? 0
|
||||||
const weight = bushels / grainTransaction.bushelsPerTonne
|
// const weight = bushels / grainTransaction.bushelsPerTonne
|
||||||
let graintype = grainTransaction.grainType ?? pond.Grain.GRAIN_INVALID
|
let graintype = grainTransaction.grainType ?? pond.Grain.GRAIN_INVALID
|
||||||
const grainDisplay = graintype === pond.Grain.GRAIN_CUSTOM
|
const grainTypeDisplay = graintype === pond.Grain.GRAIN_CUSTOM
|
||||||
? grainTransaction.customGrain
|
? grainTransaction.customGrain
|
||||||
: GrainDescriber(grainTransaction.grainType).name
|
: GrainDescriber(grainTransaction.grainType).name
|
||||||
return (
|
return (
|
||||||
|
|
@ -394,7 +407,7 @@ export default function BinTransactions(props: Props){
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box display="flex" justifyContent="space-between">
|
<Box display="flex" justifyContent="space-between">
|
||||||
<Typography sx={{margin: "auto", marginLeft: 0}}>{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT ? weight + " mT" : bushels + " bushels"} of {grainTransaction.subtype} {grainDisplay} moved</Typography>
|
<Typography sx={{margin: "auto", marginLeft: 0}}>{grainQuantityDisplay(bushels)} of {grainTransaction.subtype} {grainTypeDisplay} moved</Typography>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
disabled={selectedMatch?.transaction.key === t.transaction.key}
|
disabled={selectedMatch?.transaction.key === t.transaction.key}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import { round } from "lodash";
|
||||||
import { Bin, Component, Device } from "models";
|
import { Bin, Component, Device } from "models";
|
||||||
import { GetComponentIcon } from "pbHelpers/ComponentType";
|
import { GetComponentIcon } from "pbHelpers/ComponentType";
|
||||||
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
||||||
import { useMobile } from "hooks";
|
import { useComponentAPI, useMobile } from "hooks";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { quack } from "protobuf-ts/quack";
|
import { quack } from "protobuf-ts/quack";
|
||||||
import { useGlobalState, useSnackbar } from "providers";
|
import { useGlobalState, useSnackbar } from "providers";
|
||||||
|
|
@ -71,6 +71,7 @@ import { makeStyles } from "@mui/styles";
|
||||||
import ButtonGroup from "common/ButtonGroup";
|
import ButtonGroup from "common/ButtonGroup";
|
||||||
import ModeChangeDialog from "./conditioning/modeChangeDialog";
|
import ModeChangeDialog from "./conditioning/modeChangeDialog";
|
||||||
import CustomGrainSelector from "grain/CustomGrainSelector";
|
import CustomGrainSelector from "grain/CustomGrainSelector";
|
||||||
|
import BinControllerDisplay from "./BinControllerDisplay";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => {
|
const useStyles = makeStyles((theme: Theme) => {
|
||||||
return ({
|
return ({
|
||||||
|
|
@ -180,7 +181,7 @@ interface Props {
|
||||||
bin: Bin;
|
bin: Bin;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
components: Map<string, Component>;
|
components: Map<string, Component>;
|
||||||
componentDevices?: Map<string, number>;
|
componentDevices: Map<string, number>;
|
||||||
devices: Device[];
|
devices: Device[];
|
||||||
plenums?: Plenum[];
|
plenums?: Plenum[];
|
||||||
ambient?: Ambient;
|
ambient?: Ambient;
|
||||||
|
|
@ -270,7 +271,7 @@ export default function BinVisualizer(props: Props) {
|
||||||
const [storageType, setStorageType] = useState<pond.BinStorage>(
|
const [storageType, setStorageType] = useState<pond.BinStorage>(
|
||||||
pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN
|
pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN
|
||||||
);
|
);
|
||||||
const [bushPerTonne, setBushPerTonne] = useState("0");
|
//const [bushPerTonne, setBushPerTonne] = useState("0");
|
||||||
const [grainSubtype, setGrainSubtype] = useState("");
|
const [grainSubtype, setGrainSubtype] = useState("");
|
||||||
|
|
||||||
const [loadingTrend, setLoadingTrend] = useState(false);
|
const [loadingTrend, setLoadingTrend] = useState(false);
|
||||||
|
|
@ -289,6 +290,12 @@ export default function BinVisualizer(props: Props) {
|
||||||
const [modeChangeInProgress, setModeChangeInProgress] = useState(false)
|
const [modeChangeInProgress, setModeChangeInProgress] = useState(false)
|
||||||
const [newGrainSettings, setNewGrainSettings] = useState<pond.GrainSettings>()
|
const [newGrainSettings, setNewGrainSettings] = useState<pond.GrainSettings>()
|
||||||
|
|
||||||
|
const componentAPI = useComponentAPI()
|
||||||
|
const [openControllerDIalog, setOpenControllerDialog] = useState(false)
|
||||||
|
const [controllerOutputStates, setControllerOutputStates] = useState<Map<string, number>>(new Map<string, number>())
|
||||||
|
const [selectedController, setSelectedController] = useState<Component>()
|
||||||
|
const [newOutputState, setNewOutputState] = useState()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setModeTime(moment(bin.status.lastModeChange));
|
setModeTime(moment(bin.status.lastModeChange));
|
||||||
}, [bin.status.lastModeChange]);
|
}, [bin.status.lastModeChange]);
|
||||||
|
|
@ -326,7 +333,7 @@ export default function BinVisualizer(props: Props) {
|
||||||
setCustomTypeName(bin.settings.inventory.customTypeName);
|
setCustomTypeName(bin.settings.inventory.customTypeName);
|
||||||
setGrainType(bin.settings.inventory.grainType);
|
setGrainType(bin.settings.inventory.grainType);
|
||||||
setGrainOption(ToGrainOption(bin.settings.inventory.grainType));
|
setGrainOption(ToGrainOption(bin.settings.inventory.grainType));
|
||||||
setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2));
|
//setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2));
|
||||||
setGrainSubtype(bin.subtype());
|
setGrainSubtype(bin.subtype());
|
||||||
setNewBinMode(bin.settings.mode);
|
setNewBinMode(bin.settings.mode);
|
||||||
setNewGrainSettings(bin.customGrain());
|
setNewGrainSettings(bin.customGrain());
|
||||||
|
|
@ -495,8 +502,10 @@ export default function BinVisualizer(props: Props) {
|
||||||
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
||||||
return Math.round(val * 35.239 * 100) / 100;
|
return Math.round(val * 35.239 * 100) / 100;
|
||||||
} else {
|
} else {
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bin.bushelsPerTonne() > 1) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
||||||
return Math.round((val / bin.bushelsPerTonne()) * 100) / 100;
|
return Math.round((val / bin.bushelsPerTonne()) * 100) / 100;
|
||||||
|
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||||
|
return Math.round((val / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
|
|
@ -511,17 +520,19 @@ export default function BinVisualizer(props: Props) {
|
||||||
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
||||||
return " / " + capacity.toLocaleString() + " L";
|
return " / " + capacity.toLocaleString() + " L";
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bin.bushelsPerTonne() > 1) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
||||||
return "mT (" + bin.fillPercent() + "%)";
|
return "mT (" + bin.fillPercent() + "%)";
|
||||||
|
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||||
|
return "t (" + bin.fillPercent() + "%)";
|
||||||
} else {
|
} else {
|
||||||
return " / " + capacity.toLocaleString() + " bu";
|
return " / " + capacity.toLocaleString() + " bu";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const grainErrorCheck = () => {
|
// const grainErrorCheck = () => {
|
||||||
if (isNaN(parseFloat(bushPerTonne))) return true;
|
// if (isNaN(parseFloat(bushPerTonne))) return true;
|
||||||
return false;
|
// return false;
|
||||||
};
|
// };
|
||||||
|
|
||||||
const inventoryOverview = () => {
|
const inventoryOverview = () => {
|
||||||
const capacity = bin.settings.specs?.bushelCapacity ?? 0;
|
const capacity = bin.settings.specs?.bushelCapacity ?? 0;
|
||||||
|
|
@ -774,7 +785,7 @@ export default function BinVisualizer(props: Props) {
|
||||||
setCustomTypeName(bin.settings.inventory.customTypeName);
|
setCustomTypeName(bin.settings.inventory.customTypeName);
|
||||||
setGrainType(bin.settings.inventory.grainType);
|
setGrainType(bin.settings.inventory.grainType);
|
||||||
setGrainOption(ToGrainOption(bin.settings.inventory.grainType));
|
setGrainOption(ToGrainOption(bin.settings.inventory.grainType));
|
||||||
setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2));
|
//setBushPerTonne(bin.settings.inventory.bushelsPerTonne.toFixed(2));
|
||||||
setNewGrainSettings(bin.customGrain())
|
setNewGrainSettings(bin.customGrain())
|
||||||
setGrainSubtype(bin.subtype());
|
setGrainSubtype(bin.subtype());
|
||||||
}
|
}
|
||||||
|
|
@ -802,7 +813,7 @@ export default function BinVisualizer(props: Props) {
|
||||||
checked={isCustomInventory}
|
checked={isCustomInventory}
|
||||||
onChange={(_, checked) => {
|
onChange={(_, checked) => {
|
||||||
setIsCustomInventory(checked);
|
setIsCustomInventory(checked);
|
||||||
setBushPerTonne("0");
|
//setBushPerTonne("0");
|
||||||
setGrainSubtype("");
|
setGrainSubtype("");
|
||||||
setCustomTypeName("");
|
setCustomTypeName("");
|
||||||
setGrainOption(ToGrainOption(pond.Grain.GRAIN_NONE));
|
setGrainOption(ToGrainOption(pond.Grain.GRAIN_NONE));
|
||||||
|
|
@ -834,7 +845,7 @@ export default function BinVisualizer(props: Props) {
|
||||||
: pond.Grain.GRAIN_INVALID;
|
: pond.Grain.GRAIN_INVALID;
|
||||||
setGrainOption(ToGrainOption(newGrainType));
|
setGrainOption(ToGrainOption(newGrainType));
|
||||||
setGrainType(newGrainType);
|
setGrainType(newGrainType);
|
||||||
setBushPerTonne(GrainDescriber(newGrainType).bushelsPerTonne.toFixed(2));
|
//setBushPerTonne(GrainDescriber(newGrainType).bushelsPerTonne.toFixed(2));
|
||||||
}}
|
}}
|
||||||
group
|
group
|
||||||
disabled={!canEdit}
|
disabled={!canEdit}
|
||||||
|
|
@ -897,7 +908,7 @@ export default function BinVisualizer(props: Props) {
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={grainErrorCheck()}
|
// disabled={grainErrorCheck()}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
updateBin();
|
updateBin();
|
||||||
setGrainChangeDialog(false);
|
setGrainChangeDialog(false);
|
||||||
|
|
@ -1321,13 +1332,20 @@ export default function BinVisualizer(props: Props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bin.bushelsPerTonne() > 1) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
||||||
diffDisplay = diffDisplay / bin.bushelsPerTonne();
|
diffDisplay = diffDisplay / bin.bushelsPerTonne();
|
||||||
if (pendingDisplay) {
|
if (pendingDisplay) {
|
||||||
pendingDisplay = pendingDisplay / bin.bushelsPerTonne();
|
pendingDisplay = pendingDisplay / bin.bushelsPerTonne();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||||
|
diffDisplay = diffDisplay / (bin.bushelsPerTonne()*0.907);
|
||||||
|
if (pendingDisplay) {
|
||||||
|
pendingDisplay = pendingDisplay / (bin.bushelsPerTonne()*0.907);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box display="flex" width={1} justifyContent="flex-end">
|
<Box display="flex" width={1} justifyContent="flex-end">
|
||||||
<FullScreen handle={fullScreenHandler}>
|
<FullScreen handle={fullScreenHandler}>
|
||||||
|
|
@ -1533,54 +1551,24 @@ export default function BinVisualizer(props: Props) {
|
||||||
Controllers
|
Controllers
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box className={classes.displayBox}>
|
<Box className={classes.displayBox}>
|
||||||
{bin.status.fans.map(fan => (
|
{bin.status.fans.map(fan => {
|
||||||
<Box className={classes.controllerDisplay} key={fan.key}>
|
let fanComp = components.get(fan.key)
|
||||||
<Box display="flex">
|
let device = componentDevices.get(fan.key)
|
||||||
<AerationFanIcon />
|
if(fanComp && device){
|
||||||
<Typography
|
return (
|
||||||
align="center"
|
<BinControllerDisplay key={fanComp.key()} component={fanComp} deviceID={device} currentState/>
|
||||||
style={{
|
)
|
||||||
paddingLeft: 5,
|
}
|
||||||
fontSize: isMobile ? "0.85rem" : "1.0rem",
|
})}
|
||||||
fontWeight: 650
|
{bin.status.heaters.map(heater => {
|
||||||
}}>
|
let heaterComp = components.get(heater.key)
|
||||||
{fan.name}
|
let device = componentDevices.get(heater.key)
|
||||||
</Typography>
|
if(heaterComp && device){
|
||||||
</Box>
|
return (
|
||||||
<Typography
|
<BinControllerDisplay key={heaterComp.key()} component={heaterComp} deviceID={device} currentState={heater.state}/>
|
||||||
style={{
|
)
|
||||||
fontSize: isMobile ? "0.85rem" : "1.0rem",
|
}
|
||||||
fontWeight: 650,
|
})}
|
||||||
color: fan.state ? "green" : "orange"
|
|
||||||
}}>
|
|
||||||
{fan.state ? "ON" : "OFF"}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
))}
|
|
||||||
{bin.status.heaters.map(heater => (
|
|
||||||
<Box className={classes.controllerDisplay} key={heater.key}>
|
|
||||||
<Box display="flex">
|
|
||||||
<ObjectHeaterIcon />
|
|
||||||
<Typography
|
|
||||||
align="center"
|
|
||||||
style={{
|
|
||||||
paddingLeft: 5,
|
|
||||||
fontSize: isMobile ? "0.85rem" : "1.0rem",
|
|
||||||
fontWeight: 650
|
|
||||||
}}>
|
|
||||||
{heater.name}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<Typography
|
|
||||||
style={{
|
|
||||||
fontSize: isMobile ? "0.85rem" : "1.0rem",
|
|
||||||
fontWeight: 650,
|
|
||||||
color: heater.state ? "green" : "orange"
|
|
||||||
}}>
|
|
||||||
{heater.state ? "ON" : "OFF"}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
))}
|
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
@ -1987,9 +1975,10 @@ export default function BinVisualizer(props: Props) {
|
||||||
//update all the grain stuff
|
//update all the grain stuff
|
||||||
b.settings.inventory.grainType = grainType;
|
b.settings.inventory.grainType = grainType;
|
||||||
b.settings.inventory.customTypeName = customTypeName;
|
b.settings.inventory.customTypeName = customTypeName;
|
||||||
b.settings.inventory.bushelsPerTonne = isNaN(parseFloat(bushPerTonne))
|
b.settings.inventory.bushelsPerTonne = GrainDescriber(grainType).bushelsPerTonne
|
||||||
? 0
|
// b.settings.inventory.bushelsPerTonne = isNaN(parseFloat(bushPerTonne))
|
||||||
: parseFloat(bushPerTonne);
|
// ? 0
|
||||||
|
// : parseFloat(bushPerTonne);
|
||||||
b.settings.inventory.grainSubtype = grainSubtype;
|
b.settings.inventory.grainSubtype = grainSubtype;
|
||||||
b.settings.inventory.customGrain = newGrainSettings
|
b.settings.inventory.customGrain = newGrainSettings
|
||||||
}
|
}
|
||||||
|
|
@ -2010,7 +1999,6 @@ export default function BinVisualizer(props: Props) {
|
||||||
}
|
}
|
||||||
b.settings.mode = newBinMode;
|
b.settings.mode = newBinMode;
|
||||||
}
|
}
|
||||||
console.log(b.settings)
|
|
||||||
binAPI.updateBin(bin.key(), b.settings, as).then(resp => {
|
binAPI.updateBin(bin.key(), b.settings, as).then(resp => {
|
||||||
refresh();
|
refresh();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -652,9 +652,47 @@ export default function BinyardDisplay(props: Props) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const grainUnitDisplay = (custom?: pond.CustomInventory) => {
|
||||||
|
// If custom and not convertible, always bushels
|
||||||
|
if (custom && custom.bushelsPerTonne <= 1) {
|
||||||
|
return " bu";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (getGrainUnit()) {
|
||||||
|
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
||||||
|
return " mT";
|
||||||
|
case pond.GrainUnit.GRAIN_UNIT_TON:
|
||||||
|
return " t";
|
||||||
|
default:
|
||||||
|
return " bu";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const customQuantityDisplay = (customInventory: pond.CustomInventory, bushels: number) => {
|
||||||
|
let amount = bushels
|
||||||
|
if(customInventory.bushelsPerTonne > 1){
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
amount = bushels/customInventory.bushelsPerTonne
|
||||||
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
amount = bushels/(customInventory.bushelsPerTonne*0.907)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.round(amount*100)/100
|
||||||
|
}
|
||||||
|
|
||||||
|
const supportedGrainDisplay = (grain: pond.Grain, bushels: number) => {
|
||||||
|
const describer = GrainDescriber(grain)
|
||||||
|
let amount = bushels
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
amount = bushels/describer.bushelsPerTonne
|
||||||
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
amount = bushels/describer.bushelsPerTon
|
||||||
|
}
|
||||||
|
return Math.round(amount*100)/100
|
||||||
|
}
|
||||||
|
|
||||||
const binUtilizationList = () => {
|
const binUtilizationList = () => {
|
||||||
const hasInventory = binMetrics && binMetrics.grainInventory.length > 0;
|
const hasInventory = binMetrics && binMetrics.grainInventory.length > 0;
|
||||||
const useWeight = getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT;
|
|
||||||
return (
|
return (
|
||||||
<Accordion
|
<Accordion
|
||||||
className={classes.accordion}
|
className={classes.accordion}
|
||||||
|
|
@ -695,17 +733,9 @@ export default function BinyardDisplay(props: Props) {
|
||||||
<GridListTile key={key}>
|
<GridListTile key={key}>
|
||||||
<BinUtilizationChart
|
<BinUtilizationChart
|
||||||
grain={inv.grainType}
|
grain={inv.grainType}
|
||||||
customUnit={useWeight ? " mT" : " bu"}
|
customUnit={grainUnitDisplay()}
|
||||||
bushelAmount={
|
bushelAmount={supportedGrainDisplay(inv.grainType, inv.bushelAmount)}
|
||||||
useWeight
|
bushelCapacity={supportedGrainDisplay(inv.grainType, inv.bushelCapacity)}
|
||||||
? inv.bushelAmount / GrainDescriber(inv.grainType).bushelsPerTonne
|
|
||||||
: inv.bushelAmount
|
|
||||||
}
|
|
||||||
bushelCapacity={
|
|
||||||
useWeight
|
|
||||||
? inv.bushelCapacity / GrainDescriber(inv.grainType).bushelsPerTonne
|
|
||||||
: inv.bushelCapacity
|
|
||||||
}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setContentFilter(pond.Grain[inv.grainType]);
|
setContentFilter(pond.Grain[inv.grainType]);
|
||||||
loadMoreBins(pond.Grain[inv.grainType]);
|
loadMoreBins(pond.Grain[inv.grainType]);
|
||||||
|
|
@ -724,11 +754,10 @@ export default function BinyardDisplay(props: Props) {
|
||||||
amount = amount * 35.239;
|
amount = amount * 35.239;
|
||||||
cap = cap * 35.239;
|
cap = cap * 35.239;
|
||||||
unit = " L";
|
unit = " L";
|
||||||
}
|
}else{
|
||||||
if (useWeight && inv.bushelsPerTonne > 1) {
|
amount = customQuantityDisplay(inv, amount)
|
||||||
amount = amount / inv.bushelsPerTonne;
|
cap = customQuantityDisplay(inv, cap)
|
||||||
cap = cap / inv.bushelsPerTonne;
|
unit = grainUnitDisplay(inv)
|
||||||
unit = " mT";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -69,9 +69,12 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
if (fertilizerBin && cap) {
|
if (fertilizerBin && cap) {
|
||||||
cap = cap * 35.239;
|
cap = cap * 35.239;
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && cap) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && cap) {
|
||||||
cap = cap / bin.bushelsPerTonne();
|
cap = cap / bin.bushelsPerTonne();
|
||||||
}
|
}
|
||||||
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
||||||
|
cap = cap / (bin.bushelsPerTonne()*0.907);
|
||||||
|
}
|
||||||
setCapacity(cap);
|
setCapacity(cap);
|
||||||
binAPI
|
binAPI
|
||||||
.listHistoryBetween(bin.key(), 500, startDate.toISOString(), endDate.toISOString())
|
.listHistoryBetween(bin.key(), 500, startDate.toISOString(), endDate.toISOString())
|
||||||
|
|
@ -85,13 +88,18 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
if (hist.settings?.inventory) {
|
if (hist.settings?.inventory) {
|
||||||
let bushels = hist.settings.inventory.grainBushels ?? 0;
|
let bushels = hist.settings.inventory.grainBushels ?? 0;
|
||||||
if (bushels !== lastBushels) {
|
if (bushels !== lastBushels) {
|
||||||
|
let grainDisplay = bushels
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
||||||
|
grainDisplay = Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100;
|
||||||
|
}
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
||||||
|
grainDisplay = Math.round((bushels / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||||
|
}
|
||||||
let newData: InventoryAt = {
|
let newData: InventoryAt = {
|
||||||
timestamp: moment(hist.timestamp).valueOf(),
|
timestamp: moment(hist.timestamp).valueOf(),
|
||||||
value: fertilizerBin
|
value: fertilizerBin
|
||||||
? Math.round(bushels * 35.239)
|
? Math.round(bushels * 35.239)
|
||||||
: getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT
|
: grainDisplay
|
||||||
? Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100
|
|
||||||
: bushels
|
|
||||||
};
|
};
|
||||||
data.push(newData);
|
data.push(newData);
|
||||||
lastBushels = bushels;
|
lastBushels = bushels;
|
||||||
|
|
@ -112,12 +120,17 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
let currentTime = moment().valueOf();
|
let currentTime = moment().valueOf();
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
let bushels = bin.bushels();
|
let bushels = bin.bushels();
|
||||||
|
let grainDisplay = bushels
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
||||||
|
grainDisplay = Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100;
|
||||||
|
}
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
||||||
|
grainDisplay = Math.round((bushels / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||||
|
}
|
||||||
data.push({
|
data.push({
|
||||||
value: fertilizerBin
|
value: fertilizerBin
|
||||||
? Math.round(bushels * 35.239)
|
? Math.round(bushels * 35.239)
|
||||||
: getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT
|
: grainDisplay,
|
||||||
? Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100
|
|
||||||
: bushels,
|
|
||||||
timestamp: currentTime
|
timestamp: currentTime
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -143,9 +156,12 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
if (fertilizerBin && cap) {
|
if (fertilizerBin && cap) {
|
||||||
cap = cap * 35.239;
|
cap = cap * 35.239;
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && cap) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && cap) {
|
||||||
cap = cap / bin.bushelsPerTonne();
|
cap = cap / bin.bushelsPerTonne();
|
||||||
}
|
}
|
||||||
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
||||||
|
cap = cap / (bin.bushelsPerTonne()*0.907);
|
||||||
|
}
|
||||||
setCapacity(cap);
|
setCapacity(cap);
|
||||||
let autoBarData: BarData[] = [];
|
let autoBarData: BarData[] = [];
|
||||||
|
|
||||||
|
|
@ -163,8 +179,15 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
m.values.forEach((val, i) => {
|
m.values.forEach((val, i) => {
|
||||||
if (val.values[0] && m.timestamps[i]) {
|
if (val.values[0] && m.timestamps[i]) {
|
||||||
if (lastBushels !== val.values[0]) {
|
if (lastBushels !== val.values[0]) {
|
||||||
|
let grainDisplay = val.values[0]
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
||||||
|
grainDisplay = Math.round((grainDisplay / bin.bushelsPerTonne()) * 100) / 100;
|
||||||
|
}
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
||||||
|
grainDisplay = Math.round((grainDisplay / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||||
|
}
|
||||||
autoBarData.push({
|
autoBarData.push({
|
||||||
value: val.values[0],
|
value: grainDisplay,
|
||||||
timestamp: moment(m.timestamps[i]).valueOf(),
|
timestamp: moment(m.timestamps[i]).valueOf(),
|
||||||
});
|
});
|
||||||
lastBushels = val.values[0];
|
lastBushels = val.values[0];
|
||||||
|
|
@ -175,12 +198,17 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
if (autoBarData.length === 0) {
|
if (autoBarData.length === 0) {
|
||||||
let bushels = bin.bushels();
|
let bushels = bin.bushels();
|
||||||
let currentTime = moment().valueOf();
|
let currentTime = moment().valueOf();
|
||||||
|
let grainDisplay = bushels
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
||||||
|
grainDisplay = Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100;
|
||||||
|
}
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
||||||
|
grainDisplay = Math.round((bushels / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||||
|
}
|
||||||
autoBarData.push({
|
autoBarData.push({
|
||||||
value: fertilizerBin
|
value: fertilizerBin
|
||||||
? Math.round(bushels * 35.239)
|
? Math.round(bushels * 35.239)
|
||||||
: getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT
|
: grainDisplay,
|
||||||
? Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100
|
|
||||||
: bushels,
|
|
||||||
timestamp: currentTime
|
timestamp: currentTime
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,10 @@ interface Props {
|
||||||
* @default undefined
|
* @default undefined
|
||||||
*/
|
*/
|
||||||
toggledButtons?: number[]
|
toggledButtons?: number[]
|
||||||
|
/**
|
||||||
|
* This can be used to set which button starts toggled by default, and from there it will be controlled internally, toggledButtons will override this
|
||||||
|
*/
|
||||||
|
defaultToggle?: number
|
||||||
/**
|
/**
|
||||||
* Numerical value for the size of the text for buttons that dont use the icon
|
* Numerical value for the size of the text for buttons that dont use the icon
|
||||||
*/
|
*/
|
||||||
|
|
@ -97,7 +101,7 @@ const useStyles = makeStyles((theme: Theme) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function ButtonGroup(props: Props){
|
export default function ButtonGroup(props: Props){
|
||||||
const { buttons, toggle, toggledButtons, multiToggle, textSize, disableAll } = props
|
const { buttons, toggle, toggledButtons, defaultToggle, multiToggle, textSize, disableAll } = props
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const [currentToggle, setCurrentToggle] = useState<number[]>([])
|
const [currentToggle, setCurrentToggle] = useState<number[]>([])
|
||||||
|
|
||||||
|
|
@ -107,6 +111,8 @@ export default function ButtonGroup(props: Props){
|
||||||
let toggled: number [] = [0]
|
let toggled: number [] = [0]
|
||||||
if(toggledButtons){
|
if(toggledButtons){
|
||||||
toggled = toggledButtons
|
toggled = toggledButtons
|
||||||
|
} else if(defaultToggle){
|
||||||
|
toggled = [defaultToggle]
|
||||||
}
|
}
|
||||||
setCurrentToggle(toggled)
|
setCurrentToggle(toggled)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,9 +92,14 @@ export default function ContractSettings(props: Props) {
|
||||||
setContractValue(contract.settings.totalValue.toString());
|
setContractValue(contract.settings.totalValue.toString());
|
||||||
setCommodity(contract.settings.commodity);
|
setCommodity(contract.settings.commodity);
|
||||||
setContractDate(contract.settings.contractDate);
|
setContractDate(contract.settings.contractDate);
|
||||||
setConversionValue(
|
let conv = 1
|
||||||
contract.settings.conversionValue > 0 ? contract.settings.conversionValue.toString() : "1"
|
if(contract.settings.conversionValue > 1){
|
||||||
);
|
conv = contract.settings.conversionValue
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
conv = conv * 0.907
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setConversionValue(conv.toFixed(2));
|
||||||
setUseCustom(contract.isCustom());
|
setUseCustom(contract.isCustom());
|
||||||
}
|
}
|
||||||
}, [contract]);
|
}, [contract]);
|
||||||
|
|
@ -102,12 +107,21 @@ export default function ContractSettings(props: Props) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
switch (contractType) {
|
switch (contractType) {
|
||||||
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
||||||
|
let conversionLabel = "Bushels Per Tonne"
|
||||||
|
let adornment = "bu"
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
adornment = "mT"
|
||||||
|
}
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
conversionLabel = "Bushels Per Ton"
|
||||||
|
adornment = "t"
|
||||||
|
}
|
||||||
setLabels({
|
setLabels({
|
||||||
sizeLabel: "Total Grain on Contract",
|
sizeLabel: "Total Grain on Contract",
|
||||||
commodityLabel: "Select Grain Type",
|
commodityLabel: "Select Grain Type",
|
||||||
conversionLabel: "Bushels Per Tonne",
|
conversionLabel: conversionLabel,
|
||||||
deliveryLabel: "Grain Delivered",
|
deliveryLabel: "Grain Delivered",
|
||||||
adornment: getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT ? "mT" : "bu"
|
adornment: adornment
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -148,13 +162,22 @@ export default function ContractSettings(props: Props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
const conVal = isNaN(parseFloat(conversionValue)) ? 1 : parseFloat(conversionValue);
|
let conVal = isNaN(parseFloat(conversionValue)) ? 1 : parseFloat(conversionValue);
|
||||||
|
//the toStoredUnit will convert what they entered for amount and size using the conversion that they entered
|
||||||
|
//we will assume that both of those entries are using the same unit ie both US ton or both metric tonne
|
||||||
const deliveredVal = isNaN(parseFloat(deliveredAmount))
|
const deliveredVal = isNaN(parseFloat(deliveredAmount))
|
||||||
? 0
|
? 0
|
||||||
: Math.round(Contract.toStoredUnit(parseFloat(deliveredAmount), contractType, conVal));
|
: Math.round(Contract.toStoredUnit(parseFloat(deliveredAmount), contractType, conVal));
|
||||||
const sizeVal = isNaN(parseFloat(contractSize))
|
const sizeVal = isNaN(parseFloat(contractSize))
|
||||||
? 0
|
? 0
|
||||||
: Math.round(Contract.toStoredUnit(parseFloat(contractSize), contractType, conVal));
|
: Math.round(Contract.toStoredUnit(parseFloat(contractSize), contractType, conVal));
|
||||||
|
|
||||||
|
//then after the conversion to bushels change the conversion value to metric to be stored in the contract
|
||||||
|
if(contractType === pond.ContractType.CONTRACT_TYPE_GRAIN){
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
conVal = conVal / 0.907 //convert the ton they entered to mT to be stored in the contracts conversion value
|
||||||
|
}
|
||||||
|
}
|
||||||
if (contract) {
|
if (contract) {
|
||||||
let settings: pond.ContractSettings = contract.settings;
|
let settings: pond.ContractSettings = contract.settings;
|
||||||
settings.commodity = commodity;
|
settings.commodity = commodity;
|
||||||
|
|
@ -201,7 +224,6 @@ export default function ContractSettings(props: Props) {
|
||||||
settings.type = contractType;
|
settings.type = contractType;
|
||||||
settings.conversionValue = conVal;
|
settings.conversionValue = conVal;
|
||||||
settings.contractDate = contractDate;
|
settings.contractDate = contractDate;
|
||||||
|
|
||||||
contractAPI
|
contractAPI
|
||||||
.addContract(name, settings, as)
|
.addContract(name, settings, as)
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
|
|
@ -490,7 +512,9 @@ export default function ContractSettings(props: Props) {
|
||||||
InputLabelProps={{ shrink: true }}
|
InputLabelProps={{ shrink: true }}
|
||||||
error={isNaN(parseFloat(conversionValue))}
|
error={isNaN(parseFloat(conversionValue))}
|
||||||
helperText={isNaN(parseFloat(conversionValue)) ? "Must be a valid number" : ""}
|
helperText={isNaN(parseFloat(conversionValue)) ? "Must be a valid number" : ""}
|
||||||
onChange={e => setConversionValue(e.target.value)}
|
onChange={e => {
|
||||||
|
setConversionValue(e.target.value)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,17 @@ export default function ContractTransactionGraph(props: Props) {
|
||||||
if (transaction?.grainTransaction) {
|
if (transaction?.grainTransaction) {
|
||||||
value = transaction.grainTransaction.bushels;
|
value = transaction.grainTransaction.bushels;
|
||||||
if (
|
if (
|
||||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT &&
|
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
||||||
transaction.grainTransaction.bushelsPerTonne > 1
|
transaction.grainTransaction.bushelsPerTonne > 1
|
||||||
) {
|
) {
|
||||||
value = value / transaction.grainTransaction.bushelsPerTonne;
|
value = value / transaction.grainTransaction.bushelsPerTonne;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON &&
|
||||||
|
transaction.grainTransaction.bushelsPerTonne > 1
|
||||||
|
) {
|
||||||
|
value = value / (transaction.grainTransaction.bushelsPerTonne * 0.907);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
d.push({
|
d.push({
|
||||||
timestamp: time.valueOf(),
|
timestamp: time.valueOf(),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Chip, Grid2 as Grid, Theme, Tooltip, Skeleton } from "@mui/material";
|
import { Chip, Grid2 as Grid, Theme, Tooltip, Skeleton } from "@mui/material";
|
||||||
import { DataUsage, SimCard, Launch } from "@mui/icons-material";
|
import { DataUsage, SimCard, Launch, DeviceHub } from "@mui/icons-material";
|
||||||
import StatusChip from "common/StatusChip";
|
import StatusChip from "common/StatusChip";
|
||||||
import DeviceTags from "device/DeviceTags";
|
import DeviceTags from "device/DeviceTags";
|
||||||
import VersionChip from "device/VersionChip";
|
import VersionChip from "device/VersionChip";
|
||||||
|
|
@ -233,6 +233,17 @@ export default function DeviceOverview(props: Props) {
|
||||||
<StatusChip status="pending" />
|
<StatusChip status="pending" />
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
|
{device.settings.needsBusControl && (
|
||||||
|
<Grid>
|
||||||
|
<Tooltip title="Device needs the Bus Control component to power the I2C port">
|
||||||
|
<Chip
|
||||||
|
variant="outlined"
|
||||||
|
label={"I2C Bus"}
|
||||||
|
icon={<DeviceHub />}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
{<DeviceTags device={device} disableAdd={disableAddTag} />}
|
{<DeviceTags device={device} disableAdd={disableAddTag} />}
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,12 @@ export default function DeviceSettings(props: Props) {
|
||||||
setDeviceForm(updatedForm);
|
setDeviceForm(updatedForm);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleBusRequired = (event: any) => {
|
||||||
|
let updatedForm = Device.clone(deviceForm);
|
||||||
|
updatedForm.settings.needsBusControl = event.target.checked;
|
||||||
|
setDeviceForm(updatedForm);
|
||||||
|
};
|
||||||
|
|
||||||
const toggleSleeps = (event: any) => {
|
const toggleSleeps = (event: any) => {
|
||||||
let updatedForm = Device.clone(deviceForm);
|
let updatedForm = Device.clone(deviceForm);
|
||||||
let updatedSleeps = event.target.checked;
|
let updatedSleeps = event.target.checked;
|
||||||
|
|
@ -500,7 +506,8 @@ export default function DeviceSettings(props: Props) {
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
{user.hasAdmin() && (
|
{user.hasAdmin() && (
|
||||||
<Grid size={{ xs: 12, sm: 12 }}>
|
<React.Fragment>
|
||||||
|
<Grid size={{ xs: 12, sm: 6 }}>
|
||||||
<FormControlLabel
|
<FormControlLabel
|
||||||
control={
|
control={
|
||||||
<Switch
|
<Switch
|
||||||
|
|
@ -516,6 +523,23 @@ export default function DeviceSettings(props: Props) {
|
||||||
labelPlacement="end"
|
labelPlacement="end"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid size={{ xs: 12, sm: 6 }}>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
checked={deviceForm.settings.needsBusControl}
|
||||||
|
onChange={toggleBusRequired}
|
||||||
|
name="needsI2CBus"
|
||||||
|
aria-label="needsI2CBus"
|
||||||
|
color="secondary"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
disabled={!canEdit}
|
||||||
|
label="I2C Bus Required"
|
||||||
|
labelPlacement="end"
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ export default function FieldSettings(props: Props) {
|
||||||
settings.grainSubtype = grainSubtype;
|
settings.grainSubtype = grainSubtype;
|
||||||
settings.landLocation = landLocation;
|
settings.landLocation = landLocation;
|
||||||
settings.acres = acres;
|
settings.acres = acres;
|
||||||
|
settings.bushelsPerTonne = isNaN(parseFloat(bushelsPerTonne)) ? 1 : parseFloat(bushelsPerTonne);
|
||||||
|
|
||||||
fieldAPI
|
fieldAPI
|
||||||
.updateField(selectedField.key(), settings, undefined, as)
|
.updateField(selectedField.key(), settings, undefined, as)
|
||||||
|
|
@ -121,6 +122,7 @@ export default function FieldSettings(props: Props) {
|
||||||
geo.shapes = borders;
|
geo.shapes = borders;
|
||||||
}
|
}
|
||||||
settings.fieldGeoData = geo;
|
settings.fieldGeoData = geo;
|
||||||
|
settings.bushelsPerTonne = isNaN(parseFloat(bushelsPerTonne)) ? 1 : parseFloat(bushelsPerTonne);
|
||||||
fieldAPI
|
fieldAPI
|
||||||
.addField(settings, as)
|
.addField(settings, as)
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
|
|
@ -226,6 +228,7 @@ export default function FieldSettings(props: Props) {
|
||||||
if (option) {
|
if (option) {
|
||||||
let grainType = pond.Grain[option.value as keyof typeof pond.Grain];
|
let grainType = pond.Grain[option.value as keyof typeof pond.Grain];
|
||||||
setCropType(grainType);
|
setCropType(grainType);
|
||||||
|
console.log("set bpt here")
|
||||||
setBushelsPerTonne(GrainDescriber(grainType).bushelsPerTonne.toString());
|
setBushelsPerTonne(GrainDescriber(grainType).bushelsPerTonne.toString());
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -126,9 +126,24 @@ export default function GateDevice(props: Props) {
|
||||||
}
|
}
|
||||||
}, [comprehensiveDevice, gate, linkedCompList, user]);
|
}, [comprehensiveDevice, gate, linkedCompList, user]);
|
||||||
|
|
||||||
const gateComponentUpdate = (componentKey: string, gateCompType: pond.GateComponentType) => {
|
const gateComponentUpdate = (oldKey: string, componentKey: string, gateCompType: pond.GateComponentType) => {
|
||||||
|
let promises: any[] = []
|
||||||
|
if (oldKey !== "") {
|
||||||
|
//the promise for removing the pref from the old component
|
||||||
|
promises.push(gateAPI
|
||||||
|
.updatePrefs(
|
||||||
|
gate.key,
|
||||||
|
"component",
|
||||||
|
device.id() + ":" + oldKey,
|
||||||
|
pond.GateComponentType.GATE_COMPONENT_TYPE_UNKNOWN,
|
||||||
|
[gate.key],
|
||||||
|
["gate"],
|
||||||
|
as
|
||||||
|
))
|
||||||
|
}
|
||||||
if (componentKey !== "") {
|
if (componentKey !== "") {
|
||||||
gateAPI
|
//the promise for adding the pref to the new component
|
||||||
|
promises.push(gateAPI
|
||||||
.updatePrefs(
|
.updatePrefs(
|
||||||
gate.key,
|
gate.key,
|
||||||
"component",
|
"component",
|
||||||
|
|
@ -137,11 +152,17 @@ export default function GateDevice(props: Props) {
|
||||||
[gate.key],
|
[gate.key],
|
||||||
["gate"],
|
["gate"],
|
||||||
as
|
as
|
||||||
)
|
))
|
||||||
.then(resp => {
|
|
||||||
openSnack("Component Prefence Updated");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
Promise.all(promises).then(resp => {
|
||||||
|
openSnack("Component Prefence Updated");
|
||||||
|
let clone = cloneDeep(gate.preferences)
|
||||||
|
clone[oldKey] = pond.GateComponentType.GATE_COMPONENT_TYPE_UNKNOWN
|
||||||
|
clone[componentKey] = gateCompType
|
||||||
|
gate.preferences = clone
|
||||||
|
|
||||||
|
}).catch(
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -205,7 +226,7 @@ export default function GateDevice(props: Props) {
|
||||||
style={{ fontSize: 8 }}
|
style={{ fontSize: 8 }}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
var key = e.target.value as string;
|
var key = e.target.value as string;
|
||||||
gateComponentUpdate(key, pond.GateComponentType.GATE_COMPONENT_TYPE_AMBIENT);
|
gateComponentUpdate(ambientKey, key, pond.GateComponentType.GATE_COMPONENT_TYPE_AMBIENT);
|
||||||
setAmbientKey(key);
|
setAmbientKey(key);
|
||||||
if (tempKey === key) {
|
if (tempKey === key) {
|
||||||
setTempKey("");
|
setTempKey("");
|
||||||
|
|
@ -238,6 +259,7 @@ export default function GateDevice(props: Props) {
|
||||||
style={{ fontSize: 8 }}
|
style={{ fontSize: 8 }}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
gateComponentUpdate(
|
gateComponentUpdate(
|
||||||
|
tempKey,
|
||||||
e.target.value as string,
|
e.target.value as string,
|
||||||
pond.GateComponentType.GATE_COMPONENT_TYPE_TEMP
|
pond.GateComponentType.GATE_COMPONENT_TYPE_TEMP
|
||||||
);
|
);
|
||||||
|
|
@ -273,6 +295,7 @@ export default function GateDevice(props: Props) {
|
||||||
style={{ fontSize: 8 }}
|
style={{ fontSize: 8 }}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
gateComponentUpdate(
|
gateComponentUpdate(
|
||||||
|
pressureKey,
|
||||||
e.target.value as string,
|
e.target.value as string,
|
||||||
pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
|
pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -93,15 +93,14 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
compDevice.components.forEach(comp => {
|
compDevice.components.forEach(comp => {
|
||||||
let component = Component.any(comp);
|
let component = Component.any(comp);
|
||||||
//checks the address for the LED components to get the red and green LED's
|
//checks the address for the LED components to get the red and green LED's
|
||||||
|
|
||||||
if (component.locationString() === redAddr && component.subType() === 1) {
|
if (component.locationString() === redAddr && component.subType() === 1) {
|
||||||
setRedComponent(component);
|
setRedComponent(component);
|
||||||
} else if (component.locationString() === greenAddr && component.subType() === 1) {
|
} else if (component.locationString() === greenAddr && component.subType() === 1) {
|
||||||
setGreenComponent(component);
|
setGreenComponent(component);
|
||||||
} else if (component.type() === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE) {
|
} else if (
|
||||||
if (
|
|
||||||
gate.preferences[component.key()] === pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
|
gate.preferences[component.key()] === pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
|
||||||
) {
|
) {
|
||||||
|
console.log(component)
|
||||||
setPressureComponent(component);
|
setPressureComponent(component);
|
||||||
setPressureSource(
|
setPressureSource(
|
||||||
quack.ComponentID.create({
|
quack.ComponentID.create({
|
||||||
|
|
@ -111,13 +110,13 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if(compDevice.device){
|
if(compDevice.device){
|
||||||
setDevice(Device.create(compDevice.device))
|
setDevice(Device.create(compDevice.device))
|
||||||
}
|
}
|
||||||
}, [gate, densityTemp, user, compDevice]);
|
}, [gate, densityTemp, user, compDevice, gate.preferences]);
|
||||||
|
|
||||||
const buttonDisabled = () => {
|
const buttonDisabled = () => {
|
||||||
if (greenComponent === undefined) return true
|
if (greenComponent === undefined) return true
|
||||||
|
|
@ -129,13 +128,13 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
|
|
||||||
const createInteractions = async () => {
|
const createInteractions = async () => {
|
||||||
//the interactions to be made
|
//the interactions to be made
|
||||||
|
|
||||||
if (
|
if (
|
||||||
greenComponent !== undefined &&
|
greenComponent !== undefined &&
|
||||||
redComponent !== undefined &&
|
redComponent !== undefined &&
|
||||||
pressureComponent !== undefined
|
pressureComponent !== undefined
|
||||||
) {
|
) {
|
||||||
|
//get the number of nodes in the pressure components
|
||||||
|
let nodes = pressureComponent.numNodes()
|
||||||
let lightInteractions: pond.InteractionSettings[] = []
|
let lightInteractions: pond.InteractionSettings[] = []
|
||||||
//making variables for the parameters of the interactions
|
//making variables for the parameters of the interactions
|
||||||
const redSink = quack.ComponentID.create({
|
const redSink = quack.ComponentID.create({
|
||||||
|
|
@ -163,19 +162,18 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
source: pressureSource,
|
source: pressureSource,
|
||||||
conditions: [
|
conditions: [
|
||||||
pond.InteractionCondition.create({
|
pond.InteractionCondition.create({
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||||
value: -highDelta,
|
value: highDelta,
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
}),
|
}),
|
||||||
pond.InteractionCondition.create({
|
pond.InteractionCondition.create({
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||||
value: -lowDelta,
|
value: lowDelta,
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
nodeOne: 2,
|
nodeOne: nodes,
|
||||||
nodeTwo: 1,
|
subtype: nodes+1,
|
||||||
subtype: 18,
|
|
||||||
schedule: lightSchedule,
|
schedule: lightSchedule,
|
||||||
result: pond.InteractionResult.create({
|
result: pond.InteractionResult.create({
|
||||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
|
||||||
|
|
@ -201,14 +199,13 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
source: pressureSource,
|
source: pressureSource,
|
||||||
conditions: [
|
conditions: [
|
||||||
pond.InteractionCondition.create({
|
pond.InteractionCondition.create({
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||||
value: -highDelta,
|
value: highDelta,
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
nodeOne: 2,
|
nodeOne: nodes,
|
||||||
nodeTwo: 1,
|
subtype: nodes+1,
|
||||||
subtype: 18,
|
|
||||||
schedule: lightSchedule,
|
schedule: lightSchedule,
|
||||||
result: pond.InteractionResult.create({
|
result: pond.InteractionResult.create({
|
||||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||||
|
|
@ -221,19 +218,18 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
source: pressureSource,
|
source: pressureSource,
|
||||||
conditions: [
|
conditions: [
|
||||||
pond.InteractionCondition.create({
|
pond.InteractionCondition.create({
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||||
value: -highDelta,
|
value: highDelta,
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
}),
|
}),
|
||||||
pond.InteractionCondition.create({
|
pond.InteractionCondition.create({
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||||
value: -lowDelta,
|
value: lowDelta,
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
nodeOne: 2,
|
nodeOne: nodes,
|
||||||
nodeTwo: 1,
|
subtype: nodes+1,
|
||||||
subtype: 18,
|
|
||||||
schedule: lightSchedule,
|
schedule: lightSchedule,
|
||||||
result: pond.InteractionResult.create({
|
result: pond.InteractionResult.create({
|
||||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||||
|
|
@ -246,19 +242,18 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
source: pressureSource,
|
source: pressureSource,
|
||||||
conditions: [
|
conditions: [
|
||||||
pond.InteractionCondition.create({
|
pond.InteractionCondition.create({
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||||
value: -lowDelta,
|
value: lowDelta,
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
}),
|
}),
|
||||||
pond.InteractionCondition.create({
|
pond.InteractionCondition.create({
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||||
value: -thresholdPascals,
|
value: thresholdPascals,
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
nodeOne: 2,
|
nodeOne: nodes,
|
||||||
nodeTwo: 1,
|
subtype: nodes+1,
|
||||||
subtype: 18,
|
|
||||||
schedule: lightSchedule,
|
schedule: lightSchedule,
|
||||||
result: pond.InteractionResult.create({
|
result: pond.InteractionResult.create({
|
||||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||||
|
|
@ -276,7 +271,8 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
subtype: 1,
|
nodeOne: nodes,
|
||||||
|
subtype: nodes+1,
|
||||||
schedule: lightSchedule,
|
schedule: lightSchedule,
|
||||||
result: pond.InteractionResult.create({
|
result: pond.InteractionResult.create({
|
||||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||||
|
|
@ -291,19 +287,18 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
source: pressureSource,
|
source: pressureSource,
|
||||||
conditions: [
|
conditions: [
|
||||||
pond.InteractionCondition.create({
|
pond.InteractionCondition.create({
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||||
value: -highDelta,
|
value: highDelta,
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
}),
|
}),
|
||||||
pond.InteractionCondition.create({
|
pond.InteractionCondition.create({
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||||
value: -lowDelta,
|
value: lowDelta,
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
nodeOne: 2,
|
nodeOne: nodes,
|
||||||
nodeTwo: 1,
|
subtype: nodes+1,
|
||||||
subtype: 18,
|
|
||||||
schedule: lightSchedule,
|
schedule: lightSchedule,
|
||||||
result: pond.InteractionResult.create({
|
result: pond.InteractionResult.create({
|
||||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
|
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
|
||||||
|
|
@ -393,7 +388,6 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
//TODO: Once we figure out how to fix the backend to handle rapid addition/removal of interactions
|
//TODO: Once we figure out how to fix the backend to handle rapid addition/removal of interactions
|
||||||
//removeCurrentInteractions();
|
|
||||||
setAdding(true);
|
setAdding(true);
|
||||||
interactionsAPI.clearInteractions(device.id(), [pressureSource]).then(resp => {
|
interactionsAPI.clearInteractions(device.id(), [pressureSource]).then(resp => {
|
||||||
createInteractions();
|
createInteractions();
|
||||||
|
|
@ -401,7 +395,8 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
disabled={buttonDisabled()}>
|
disabled={buttonDisabled()}
|
||||||
|
>
|
||||||
{adding ? "Adding Interaction" : "Create Interaction"}
|
{adding ? "Adding Interaction" : "Create Interaction"}
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import {MenuItem, TextField } from "@mui/material"
|
||||||
import { cloneDeep } from "lodash"
|
import { cloneDeep } from "lodash"
|
||||||
import { pond } from "protobuf-ts/pond"
|
import { pond } from "protobuf-ts/pond"
|
||||||
import React, { useEffect, useRef, useState } from "react"
|
import React, { useEffect, useRef, useState } from "react"
|
||||||
|
import { getGrainUnit } from "utils"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
grainSettings?: pond.GrainSettings
|
grainSettings?: pond.GrainSettings
|
||||||
|
|
@ -18,7 +19,7 @@ export default function CustomGrainForm(props: Props) {
|
||||||
const [constantB, setConstantB] = useState("0")
|
const [constantB, setConstantB] = useState("0")
|
||||||
const [constantC, setConstantC] = useState("0")
|
const [constantC, setConstantC] = useState("0")
|
||||||
const [kgPerBushel, setKgPerBushel] = useState("0")
|
const [kgPerBushel, setKgPerBushel] = useState("0")
|
||||||
const [bushelsPerTonne, setBushelsPerTonne] = useState("0")
|
const [bushelsConversion, setBushelConversion] = useState("0")//this is either per tonne or per US ton depending on user preferences
|
||||||
const valid = useRef(false)
|
const valid = useRef(false)
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
|
|
@ -30,12 +31,19 @@ export default function CustomGrainForm(props: Props) {
|
||||||
setConstantB(grainSettings.b.toString())
|
setConstantB(grainSettings.b.toString())
|
||||||
setConstantC(grainSettings.c.toString())
|
setConstantC(grainSettings.c.toString())
|
||||||
setKgPerBushel(grainSettings.kgPerBushel.toString())
|
setKgPerBushel(grainSettings.kgPerBushel.toString())
|
||||||
setBushelsPerTonne(grainSettings.bushelsPerTonne.toString())
|
setBushelConversion(grainSettings.bushelsPerTonne.toString())
|
||||||
setNewGrainSettings(grainSettings)
|
setNewGrainSettings(grainSettings)
|
||||||
}
|
}
|
||||||
},[grainSettings])
|
},[grainSettings])
|
||||||
|
|
||||||
const validate = (name: string, group: string, constA: string, constB: string, constC: string, kgPerBushel: string, bushelsPerTonne: string) => {
|
const validate = (
|
||||||
|
name: string,
|
||||||
|
group: string,
|
||||||
|
constA: string,
|
||||||
|
constB: string,
|
||||||
|
constC: string,
|
||||||
|
kgPerBushel: string,
|
||||||
|
bushelsPerTonne: string) => {
|
||||||
if (name === "") return false
|
if (name === "") return false
|
||||||
if (group === "") return false
|
if (group === "") return false
|
||||||
if (isNaN(parseFloat(constA))) return false
|
if (isNaN(parseFloat(constA))) return false
|
||||||
|
|
@ -64,7 +72,7 @@ export default function CustomGrainForm(props: Props) {
|
||||||
setName(name)
|
setName(name)
|
||||||
let settings = cloneDeep(newGrainSettings)
|
let settings = cloneDeep(newGrainSettings)
|
||||||
settings.name = name
|
settings.name = name
|
||||||
valid.current = validate(name, group, constantA, constantB, constantC, kgPerBushel, bushelsPerTonne)
|
valid.current = validate(name, group, constantA, constantB, constantC, kgPerBushel, bushelsConversion)
|
||||||
settingsChanged(settings)
|
settingsChanged(settings)
|
||||||
}}/>
|
}}/>
|
||||||
<TextField
|
<TextField
|
||||||
|
|
@ -77,7 +85,7 @@ export default function CustomGrainForm(props: Props) {
|
||||||
setGroup(group)
|
setGroup(group)
|
||||||
let settings = cloneDeep(newGrainSettings)
|
let settings = cloneDeep(newGrainSettings)
|
||||||
settings.group = group
|
settings.group = group
|
||||||
valid.current = validate(name, group, constantA, constantB, constantC, kgPerBushel, bushelsPerTonne)
|
valid.current = validate(name, group, constantA, constantB, constantC, kgPerBushel, bushelsConversion)
|
||||||
settingsChanged(settings)
|
settingsChanged(settings)
|
||||||
}}/>
|
}}/>
|
||||||
<TextField
|
<TextField
|
||||||
|
|
@ -91,7 +99,7 @@ export default function CustomGrainForm(props: Props) {
|
||||||
setEquation(enumVal)
|
setEquation(enumVal)
|
||||||
let settings = cloneDeep(newGrainSettings)
|
let settings = cloneDeep(newGrainSettings)
|
||||||
settings.equation = enumVal
|
settings.equation = enumVal
|
||||||
valid.current = validate(name, group, constantA, constantB, constantC, kgPerBushel, bushelsPerTonne)
|
valid.current = validate(name, group, constantA, constantB, constantC, kgPerBushel, bushelsConversion)
|
||||||
settingsChanged(settings)
|
settingsChanged(settings)
|
||||||
}}
|
}}
|
||||||
select>
|
select>
|
||||||
|
|
@ -121,7 +129,7 @@ export default function CustomGrainForm(props: Props) {
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
let val = e.target.value
|
let val = e.target.value
|
||||||
setConstantA(val)
|
setConstantA(val)
|
||||||
valid.current = validate(name, group, val, constantB, constantC, kgPerBushel, bushelsPerTonne)
|
valid.current = validate(name, group, val, constantB, constantC, kgPerBushel, bushelsConversion)
|
||||||
let settings = cloneDeep(newGrainSettings)
|
let settings = cloneDeep(newGrainSettings)
|
||||||
if(!isNaN(parseFloat(val))){
|
if(!isNaN(parseFloat(val))){
|
||||||
settings.a = parseFloat(val)
|
settings.a = parseFloat(val)
|
||||||
|
|
@ -139,7 +147,7 @@ export default function CustomGrainForm(props: Props) {
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
let val = e.target.value
|
let val = e.target.value
|
||||||
setConstantB(val)
|
setConstantB(val)
|
||||||
valid.current = validate(name, group, constantA, val, constantC, kgPerBushel, bushelsPerTonne)
|
valid.current = validate(name, group, constantA, val, constantC, kgPerBushel, bushelsConversion)
|
||||||
let settings = cloneDeep(newGrainSettings)
|
let settings = cloneDeep(newGrainSettings)
|
||||||
if(!isNaN(parseFloat(val))){
|
if(!isNaN(parseFloat(val))){
|
||||||
settings.b = parseFloat(val)
|
settings.b = parseFloat(val)
|
||||||
|
|
@ -157,7 +165,7 @@ export default function CustomGrainForm(props: Props) {
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
let val = e.target.value
|
let val = e.target.value
|
||||||
setConstantC(val)
|
setConstantC(val)
|
||||||
valid.current = validate(name, group, constantA, constantB, val, kgPerBushel, bushelsPerTonne)
|
valid.current = validate(name, group, constantA, constantB, val, kgPerBushel, bushelsConversion)
|
||||||
let settings = cloneDeep(newGrainSettings)
|
let settings = cloneDeep(newGrainSettings)
|
||||||
if(!isNaN(parseFloat(val))){
|
if(!isNaN(parseFloat(val))){
|
||||||
settings.c = parseFloat(val)
|
settings.c = parseFloat(val)
|
||||||
|
|
@ -175,7 +183,7 @@ export default function CustomGrainForm(props: Props) {
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
let val = e.target.value
|
let val = e.target.value
|
||||||
setKgPerBushel(val)
|
setKgPerBushel(val)
|
||||||
valid.current = validate(name, group, constantA, constantB, constantC, val, bushelsPerTonne)
|
valid.current = validate(name, group, constantA, constantB, constantC, val, bushelsConversion)
|
||||||
let settings = cloneDeep(newGrainSettings)
|
let settings = cloneDeep(newGrainSettings)
|
||||||
if(!isNaN(parseFloat(val))){
|
if(!isNaN(parseFloat(val))){
|
||||||
settings.kgPerBushel = parseFloat(val)
|
settings.kgPerBushel = parseFloat(val)
|
||||||
|
|
@ -187,20 +195,24 @@ export default function CustomGrainForm(props: Props) {
|
||||||
sx={{marginBottom: 2}}
|
sx={{marginBottom: 2}}
|
||||||
fullWidth
|
fullWidth
|
||||||
type="number"
|
type="number"
|
||||||
value={bushelsPerTonne}
|
value={bushelsConversion}
|
||||||
error={isNaN(parseFloat(bushelsPerTonne))}
|
error={isNaN(parseFloat(bushelsConversion))}
|
||||||
helperText={isNaN(parseFloat(bushelsPerTonne)) ? "Must be a valid number" : ""}
|
helperText={isNaN(parseFloat(bushelsConversion)) ? "Must be a valid number" : ""}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
let val = e.target.value
|
let val = e.target.value
|
||||||
setBushelsPerTonne(val)
|
setBushelConversion(val)
|
||||||
valid.current = validate(name, group, constantA, constantB, constantC, kgPerBushel, val)
|
valid.current = validate(name, group, constantA, constantB, constantC, kgPerBushel, val)
|
||||||
let settings = cloneDeep(newGrainSettings)
|
let settings = cloneDeep(newGrainSettings)
|
||||||
if(!isNaN(parseFloat(val))){
|
if(!isNaN(parseFloat(val))){
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
settings.bushelsPerTonne = parseFloat(val)/0.907
|
||||||
|
}else{
|
||||||
settings.bushelsPerTonne = parseFloat(val)
|
settings.bushelsPerTonne = parseFloat(val)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
settingsChanged(settings)
|
settingsChanged(settings)
|
||||||
}}
|
}}
|
||||||
label="Bushels per Tonne"/>
|
label={"Bushels per " + (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE ? " Tonne" : "Ton")}/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ export interface GrainExtension {
|
||||||
colour: string;
|
colour: string;
|
||||||
weightConversionKg: number;
|
weightConversionKg: number;
|
||||||
bushelsPerTonne: number;
|
bushelsPerTonne: number;
|
||||||
|
bushelsPerTon: number; //NOTE: this is US tons (2000lB/t)
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultSetTemp = 30.0;
|
const defaultSetTemp = 30.0;
|
||||||
|
|
@ -45,7 +46,8 @@ const defaultGrain: GrainExtension = {
|
||||||
targetMC: 15.0,
|
targetMC: 15.0,
|
||||||
colour: "#424242",
|
colour: "#424242",
|
||||||
weightConversionKg: 0,
|
weightConversionKg: 0,
|
||||||
bushelsPerTonne: 0
|
bushelsPerTonne: 0,
|
||||||
|
bushelsPerTon: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
|
|
@ -64,7 +66,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
targetMC: 15.0,
|
targetMC: 15.0,
|
||||||
colour: "yellow",
|
colour: "yellow",
|
||||||
weightConversionKg: 0,
|
weightConversionKg: 0,
|
||||||
bushelsPerTonne: 0
|
bushelsPerTonne: 0,
|
||||||
|
bushelsPerTon: 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -81,7 +84,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: BarleyImg,
|
img: BarleyImg,
|
||||||
colour: "#27632a",
|
colour: "#27632a",
|
||||||
weightConversionKg: 21.772657171369,
|
weightConversionKg: 21.772657171369,
|
||||||
bushelsPerTonne: 45.93
|
bushelsPerTonne: 45.93,
|
||||||
|
bushelsPerTon: 41.66
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -98,7 +102,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
targetMC: 16.1,
|
targetMC: 16.1,
|
||||||
colour: "#46b298",
|
colour: "#46b298",
|
||||||
weightConversionKg: 1,
|
weightConversionKg: 1,
|
||||||
bushelsPerTonne: 45.93
|
bushelsPerTonne: 45.93,
|
||||||
|
bushelsPerTon: 50.63
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -116,7 +121,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
// colour: "#cddc39",
|
// colour: "#cddc39",
|
||||||
colour: "#ffff00",
|
colour: "#ffff00",
|
||||||
weightConversionKg: 22.67961461,
|
weightConversionKg: 22.67961461,
|
||||||
bushelsPerTonne: 44.092
|
bushelsPerTonne: 44.092,
|
||||||
|
bushelsPerTon: 39.99
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -133,7 +139,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: CanolaImg,
|
img: CanolaImg,
|
||||||
colour: "#cddc39",
|
colour: "#cddc39",
|
||||||
weightConversionKg: 27.215537532,
|
weightConversionKg: 27.215537532,
|
||||||
bushelsPerTonne: 44.092
|
bushelsPerTonne: 44.092,
|
||||||
|
bushelsPerTon: 39.9
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -150,7 +157,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: CornImg,
|
img: CornImg,
|
||||||
colour: "#ffef62",
|
colour: "#ffef62",
|
||||||
weightConversionKg: 25.4014333665971,
|
weightConversionKg: 25.4014333665971,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -167,7 +175,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: CornImg,
|
img: CornImg,
|
||||||
colour: "#ffef62",
|
colour: "#ffef62",
|
||||||
weightConversionKg: 25.4014333665971,
|
weightConversionKg: 25.4014333665971,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -184,7 +193,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: CornImg,
|
img: CornImg,
|
||||||
colour: "#ffef62",
|
colour: "#ffef62",
|
||||||
weightConversionKg: 25.4014333665971,
|
weightConversionKg: 25.4014333665971,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -201,7 +211,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: CornImg,
|
img: CornImg,
|
||||||
colour: "#ffef62",
|
colour: "#ffef62",
|
||||||
weightConversionKg: 25.4014333665971,
|
weightConversionKg: 25.4014333665971,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -218,7 +229,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: CornImg,
|
img: CornImg,
|
||||||
colour: "#ffef62",
|
colour: "#ffef62",
|
||||||
weightConversionKg: 25.4014333665971,
|
weightConversionKg: 25.4014333665971,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -235,7 +247,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: OatImg,
|
img: OatImg,
|
||||||
colour: "#79955a",
|
colour: "#79955a",
|
||||||
weightConversionKg: 15.4222988297197,
|
weightConversionKg: 15.4222988297197,
|
||||||
bushelsPerTonne: 64.842
|
bushelsPerTonne: 64.842,
|
||||||
|
bushelsPerTon: 58.81
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -252,7 +265,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: OatImg,
|
img: OatImg,
|
||||||
colour: "#79955a",
|
colour: "#79955a",
|
||||||
weightConversionKg: 15.4222988297197,
|
weightConversionKg: 15.4222988297197,
|
||||||
bushelsPerTonne: 64.842
|
bushelsPerTonne: 64.842,
|
||||||
|
bushelsPerTon: 58.81
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -269,7 +283,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: OatImg,
|
img: OatImg,
|
||||||
colour: "#79955a",
|
colour: "#79955a",
|
||||||
weightConversionKg: 15.4222988297197,
|
weightConversionKg: 15.4222988297197,
|
||||||
bushelsPerTonne: 64.842
|
bushelsPerTonne: 64.842,
|
||||||
|
bushelsPerTon: 58.81
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -286,7 +301,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: PeanutImg,
|
img: PeanutImg,
|
||||||
colour: "#b2a058",
|
colour: "#b2a058",
|
||||||
weightConversionKg: 23.3124,
|
weightConversionKg: 23.3124,
|
||||||
bushelsPerTonne: 105.263
|
bushelsPerTonne: 105.263,
|
||||||
|
bushelsPerTon: 95.47
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -303,7 +319,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: RiceImg,
|
img: RiceImg,
|
||||||
colour: "#7c9c99",
|
colour: "#7c9c99",
|
||||||
weightConversionKg: 28.439,
|
weightConversionKg: 28.439,
|
||||||
bushelsPerTonne: 49.02
|
bushelsPerTonne: 49.02,
|
||||||
|
bushelsPerTon: 44.46
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -320,7 +337,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: RiceImg,
|
img: RiceImg,
|
||||||
colour: "#7c9c99",
|
colour: "#7c9c99",
|
||||||
weightConversionKg: 29.979,
|
weightConversionKg: 29.979,
|
||||||
bushelsPerTonne: 49.02
|
bushelsPerTonne: 49.02,
|
||||||
|
bushelsPerTon: 44.46
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -337,7 +355,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: RiceImg,
|
img: RiceImg,
|
||||||
colour: "#7c9c99",
|
colour: "#7c9c99",
|
||||||
weightConversionKg: 30.744,
|
weightConversionKg: 30.744,
|
||||||
bushelsPerTonne: 49.02
|
bushelsPerTonne: 49.02,
|
||||||
|
bushelsPerTon: 44.46
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -354,7 +373,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: SorghumImg,
|
img: SorghumImg,
|
||||||
colour: "#829baf",
|
colour: "#829baf",
|
||||||
weightConversionKg: 25.4014333665971,
|
weightConversionKg: 25.4014333665971,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -371,7 +391,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: SoybeanImg,
|
img: SoybeanImg,
|
||||||
colour: "#7d6d99",
|
colour: "#7d6d99",
|
||||||
weightConversionKg: 27.2158214642112,
|
weightConversionKg: 27.2158214642112,
|
||||||
bushelsPerTonne: 36.744
|
bushelsPerTonne: 36.744,
|
||||||
|
bushelsPerTon: 33.33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -388,7 +409,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: SunflowerImg,
|
img: SunflowerImg,
|
||||||
colour: "#ffab40",
|
colour: "#ffab40",
|
||||||
weightConversionKg: 13.6079107321056,
|
weightConversionKg: 13.6079107321056,
|
||||||
bushelsPerTonne: 73.487
|
bushelsPerTonne: 73.487,
|
||||||
|
bushelsPerTon: 66.65
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -405,7 +427,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: WheatImg,
|
img: WheatImg,
|
||||||
colour: "#46b298",
|
colour: "#46b298",
|
||||||
weightConversionKg: 27.2158214642112,
|
weightConversionKg: 27.2158214642112,
|
||||||
bushelsPerTonne: 36.744
|
bushelsPerTonne: 36.744,
|
||||||
|
bushelsPerTon: 33.33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -422,7 +445,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: WheatImg,
|
img: WheatImg,
|
||||||
colour: "#46b298",
|
colour: "#46b298",
|
||||||
weightConversionKg: 27.2158214642112,
|
weightConversionKg: 27.2158214642112,
|
||||||
bushelsPerTonne: 36.744
|
bushelsPerTonne: 36.744,
|
||||||
|
bushelsPerTon: 33.33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -439,7 +463,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: WheatImg,
|
img: WheatImg,
|
||||||
colour: "#46b298",
|
colour: "#46b298",
|
||||||
weightConversionKg: 27.2158214642112,
|
weightConversionKg: 27.2158214642112,
|
||||||
bushelsPerTonne: 36.744
|
bushelsPerTonne: 36.744,
|
||||||
|
bushelsPerTon: 33.33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -456,7 +481,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: FlaxImg,
|
img: FlaxImg,
|
||||||
colour: "#6e6d19",
|
colour: "#6e6d19",
|
||||||
weightConversionKg: 25.4014333665971,
|
weightConversionKg: 25.4014333665971,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -473,7 +499,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: FlaxImg,
|
img: FlaxImg,
|
||||||
colour: "#6e6d19",
|
colour: "#6e6d19",
|
||||||
weightConversionKg: 25.4014333665971,
|
weightConversionKg: 25.4014333665971,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -490,7 +517,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: PeaImg,
|
img: PeaImg,
|
||||||
colour: "#ffe100",
|
colour: "#ffe100",
|
||||||
weightConversionKg: 27.2158214642112,
|
weightConversionKg: 27.2158214642112,
|
||||||
bushelsPerTonne: 36.744
|
bushelsPerTonne: 36.744,
|
||||||
|
bushelsPerTon: 33.33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -507,7 +535,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: LentilImg,
|
img: LentilImg,
|
||||||
colour: "#cb5e3c",
|
colour: "#cb5e3c",
|
||||||
weightConversionKg: 27.2158214642112,
|
weightConversionKg: 27.2158214642112,
|
||||||
bushelsPerTonne: 36.744
|
bushelsPerTonne: 36.744,
|
||||||
|
bushelsPerTon: 33.33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -524,7 +553,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: LentilImg,
|
img: LentilImg,
|
||||||
colour: "#cb5e3c",
|
colour: "#cb5e3c",
|
||||||
weightConversionKg: 27.2158214642112,
|
weightConversionKg: 27.2158214642112,
|
||||||
bushelsPerTonne: 36.744
|
bushelsPerTonne: 36.744,
|
||||||
|
bushelsPerTon: 33.33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -541,7 +571,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
img: LentilImg,
|
img: LentilImg,
|
||||||
colour: "#cb5e3c",
|
colour: "#cb5e3c",
|
||||||
weightConversionKg: 27.2158214642112,
|
weightConversionKg: 27.2158214642112,
|
||||||
bushelsPerTonne: 36.744
|
bushelsPerTonne: 36.744,
|
||||||
|
bushelsPerTon: 33.33
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|
@ -557,7 +588,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
targetMC: 15.0,
|
targetMC: 15.0,
|
||||||
colour: "red",
|
colour: "red",
|
||||||
weightConversionKg: 27.2155,
|
weightConversionKg: 27.2155,
|
||||||
bushelsPerTonne: 36.744
|
bushelsPerTonne: 36.744,
|
||||||
|
bushelsPerTon: 33.33
|
||||||
}
|
}
|
||||||
],[
|
],[
|
||||||
pond.Grain.GRAIN_DRY_BEANS_BLACK,
|
pond.Grain.GRAIN_DRY_BEANS_BLACK,
|
||||||
|
|
@ -572,7 +604,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
targetMC: 15.0,
|
targetMC: 15.0,
|
||||||
colour: "grey",
|
colour: "grey",
|
||||||
weightConversionKg: 27.2155,
|
weightConversionKg: 27.2155,
|
||||||
bushelsPerTonne: 36.744
|
bushelsPerTonne: 36.744,
|
||||||
|
bushelsPerTon: 33.33
|
||||||
}
|
}
|
||||||
],[
|
],[
|
||||||
pond.Grain.GRAIN_RYE_A,
|
pond.Grain.GRAIN_RYE_A,
|
||||||
|
|
@ -587,7 +620,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
targetMC: 15.0,
|
targetMC: 15.0,
|
||||||
colour: "grey",
|
colour: "grey",
|
||||||
weightConversionKg: 25.4,
|
weightConversionKg: 25.4,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
}
|
}
|
||||||
],[
|
],[
|
||||||
pond.Grain.GRAIN_RYE_B,
|
pond.Grain.GRAIN_RYE_B,
|
||||||
|
|
@ -602,7 +636,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
targetMC: 15.0,
|
targetMC: 15.0,
|
||||||
colour: "grey",
|
colour: "grey",
|
||||||
weightConversionKg: 25.4,
|
weightConversionKg: 25.4,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
},
|
},
|
||||||
],[
|
],[
|
||||||
pond.Grain.GRAIN_RYE_C,
|
pond.Grain.GRAIN_RYE_C,
|
||||||
|
|
@ -617,7 +652,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
targetMC: 15.0,
|
targetMC: 15.0,
|
||||||
colour: "grey",
|
colour: "grey",
|
||||||
weightConversionKg: 25.4,
|
weightConversionKg: 25.4,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
},
|
},
|
||||||
],[
|
],[
|
||||||
pond.Grain.GRAIN_RYE_D,
|
pond.Grain.GRAIN_RYE_D,
|
||||||
|
|
@ -632,7 +668,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
||||||
targetMC: 15.0,
|
targetMC: 15.0,
|
||||||
colour: "grey",
|
colour: "grey",
|
||||||
weightConversionKg: 25.4,
|
weightConversionKg: 25.4,
|
||||||
bushelsPerTonne: 39.368
|
bushelsPerTonne: 39.368,
|
||||||
|
bushelsPerTon: 35.71
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -225,12 +225,13 @@ export default function GrainTransaction(props: Props) {
|
||||||
const createTransaction = (finalVal: number) => {
|
const createTransaction = (finalVal: number) => {
|
||||||
let dest = selectedDestination;
|
let dest = selectedDestination;
|
||||||
let source = selectedSource;
|
let source = selectedSource;
|
||||||
let bpt = 1;
|
let bPerTonne = 1;
|
||||||
|
let bPerTon = 1;
|
||||||
//use the sources bushel per tonne if one was selected otherwise use the destination
|
//use the sources bushel per tonne if one was selected otherwise use the destination
|
||||||
if (source) {
|
if (source) {
|
||||||
bpt = source.value.bushelsPerTonne();
|
bPerTonne = source.value.bushelsPerTonne();
|
||||||
} else if (dest) {
|
} else if (dest) {
|
||||||
bpt = dest.value.bushelsPerTonne();
|
bPerTonne = dest.value.bushelsPerTonne();
|
||||||
}
|
}
|
||||||
|
|
||||||
let newTransaction = pond.Transaction.create({
|
let newTransaction = pond.Transaction.create({
|
||||||
|
|
@ -239,7 +240,7 @@ export default function GrainTransaction(props: Props) {
|
||||||
grainTransaction: pond.GrainTransaction.create({
|
grainTransaction: pond.GrainTransaction.create({
|
||||||
bushels: finalVal,
|
bushels: finalVal,
|
||||||
message: grainMessage,
|
message: grainMessage,
|
||||||
bushelsPerTonne: bpt
|
bushelsPerTonne: bPerTonne,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
@ -449,6 +450,17 @@ export default function GrainTransaction(props: Props) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const grainUnitDisplay = () => {
|
||||||
|
switch (getGrainUnit()){
|
||||||
|
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
||||||
|
return "mT"
|
||||||
|
case pond.GrainUnit.GRAIN_UNIT_TON:
|
||||||
|
return "t"
|
||||||
|
default:
|
||||||
|
return "bu"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResponsiveDialog
|
<ResponsiveDialog
|
||||||
open={open}
|
open={open}
|
||||||
|
|
@ -506,14 +518,14 @@ export default function GrainTransaction(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT ? "mT" : "bu"}
|
{grainUnitDisplay()}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
//if the user is viewing the grain in weight
|
//if the user is viewing the grain in weight
|
||||||
let grainVal = e.target.value;
|
let grainVal = e.target.value;
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE) {
|
||||||
//need to convert what the user input (weight) into what is actually stored (bushels)
|
//need to convert what the user input (weight) into what is actually stored (bushels)
|
||||||
//use source of the conversion value if it was selected, otherwise use the destination
|
//use source of the conversion value if it was selected, otherwise use the destination
|
||||||
if (!isNaN(parseFloat(e.target.value))) {
|
if (!isNaN(parseFloat(e.target.value))) {
|
||||||
|
|
@ -523,6 +535,18 @@ export default function GrainTransaction(props: Props) {
|
||||||
grainVal = (+grainVal * selectedDestination.value.bushelsPerTonne()).toFixed(2);
|
grainVal = (+grainVal * selectedDestination.value.bushelsPerTonne()).toFixed(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) {
|
||||||
|
if (!isNaN(parseFloat(e.target.value))) {
|
||||||
|
if (selectedSource) {
|
||||||
|
if(selectedSource.value.bushelsPerTonne){
|
||||||
|
grainVal = (+grainVal * (selectedSource.value.bushelsPerTonne() * 0.907)).toFixed(2);
|
||||||
|
}
|
||||||
|
} else if (selectedDestination) {
|
||||||
|
if(selectedDestination.value.bushelsPerTonne){
|
||||||
|
grainVal = (+grainVal * (selectedDestination.value.bushelsPerTonne() * 0.907)).toFixed(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setGrainEntry(e.target.value);
|
setGrainEntry(e.target.value);
|
||||||
setGrainChangeVal(grainVal);
|
setGrainChangeVal(grainVal);
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,14 @@ export default function GrainBagInventoryGraph(props: Props) {
|
||||||
//let time = hist.timestamp;
|
//let time = hist.timestamp;
|
||||||
let val = hist.object.grainBagSettings.currentBushels ?? 0;
|
let val = hist.object.grainBagSettings.currentBushels ?? 0;
|
||||||
if (
|
if (
|
||||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT &&
|
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
||||||
grainBag.bushelsPerTonne() > 1
|
grainBag.bushelsPerTonne() > 1
|
||||||
) {
|
) {
|
||||||
val = Math.round((val / grainBag.bushelsPerTonne()) * 100) / 100;
|
val = Math.round((val / grainBag.bushelsPerTonne()) * 100) / 100;
|
||||||
}
|
}
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1){
|
||||||
|
val = Math.round((val / (grainBag.bushelsPerTonne() * 0.907)) * 100) / 100;
|
||||||
|
}
|
||||||
if (val !== lastBushels) {
|
if (val !== lastBushels) {
|
||||||
lastBushels = val;
|
lastBushels = val;
|
||||||
barData.push({
|
barData.push({
|
||||||
|
|
@ -51,13 +54,16 @@ export default function GrainBagInventoryGraph(props: Props) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (barData.length === 0) {
|
if (barData.length === 0) {
|
||||||
|
let val = grainBag.bushels()
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1){
|
||||||
|
val = grainBag.bushels() / grainBag.bushelsPerTonne()
|
||||||
|
}
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1){
|
||||||
|
val = grainBag.bushels() / (grainBag.bushelsPerTonne() * 0.907)
|
||||||
|
}
|
||||||
barData.push({
|
barData.push({
|
||||||
timestamp: moment.now().valueOf(),
|
timestamp: moment.now().valueOf(),
|
||||||
value:
|
value: Math.round(val*100)/100
|
||||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT &&
|
|
||||||
grainBag.bushelsPerTonne() > 1
|
|
||||||
? Math.round((grainBag.bushels() / grainBag.bushelsPerTonne()) * 100) / 100
|
|
||||||
: grainBag.bushels()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setData(barData);
|
setData(barData);
|
||||||
|
|
@ -71,6 +77,17 @@ export default function GrainBagInventoryGraph(props: Props) {
|
||||||
}
|
}
|
||||||
}, [grainBagAPI, grainBag, startDate, endDate, openSnack]); //eslint-disable-line react-hooks/exhaustive-deps
|
}, [grainBagAPI, grainBag, startDate, endDate, openSnack]); //eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
|
const maxYAxis = () => {
|
||||||
|
let val = grainBag.capacity()
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
val = Math.round((val / grainBag.bushelsPerTonne()) * 100) / 100;
|
||||||
|
}
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1){
|
||||||
|
val = Math.round((val / (grainBag.bushelsPerTonne() * 0.907)) * 100) / 100;
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card raised>
|
<Card raised>
|
||||||
<Box padding={2}>
|
<Box padding={2}>
|
||||||
|
|
@ -87,11 +104,7 @@ export default function GrainBagInventoryGraph(props: Props) {
|
||||||
}
|
}
|
||||||
data={data}
|
data={data}
|
||||||
yMin={0}
|
yMin={0}
|
||||||
yMax={
|
yMax={maxYAxis()}
|
||||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT
|
|
||||||
? grainBag.capacity() / grainBag.bushelsPerTonne()
|
|
||||||
: grainBag.capacity()
|
|
||||||
}
|
|
||||||
customHeight={customHeight}
|
customHeight={customHeight}
|
||||||
useGradient
|
useGradient
|
||||||
labels
|
labels
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ export default function GrainBagSettings(props: Props) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [grainUpdate, setGrainUpdate] = useState(false);
|
const [grainUpdate, setGrainUpdate] = useState(false);
|
||||||
const [grainDiff, setGrainDiff] = useState(0);
|
const [grainDiff, setGrainDiff] = useState(0);
|
||||||
const [bushelsPerTonne, setBushelsPerTonne] = useState(0);
|
const [bushelConversion, setBushelConversion] = useState(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (grainBag) {
|
if (grainBag) {
|
||||||
|
|
@ -84,8 +84,10 @@ export default function GrainBagSettings(props: Props) {
|
||||||
: grainBag.settings.length
|
: grainBag.settings.length
|
||||||
);
|
);
|
||||||
let grainVal = grainBag.bushels();
|
let grainVal = grainBag.bushels();
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE) {
|
||||||
grainVal = grainBag.bushels() / grainBag.bushelsPerTonne();
|
grainVal = grainBag.bushels() / grainBag.bushelsPerTonne();
|
||||||
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) {
|
||||||
|
grainVal = grainBag.bushels() / (grainBag.bushelsPerTonne() * 0.907)
|
||||||
}
|
}
|
||||||
setGrainFill(grainVal.toFixed(2));
|
setGrainFill(grainVal.toFixed(2));
|
||||||
setBagName(grainBag.name());
|
setBagName(grainBag.name());
|
||||||
|
|
@ -117,6 +119,10 @@ export default function GrainBagSettings(props: Props) {
|
||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
//if a bag was passed in do an update
|
//if a bag was passed in do an update
|
||||||
|
let tonneConversion = bushelConversion
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
tonneConversion = bushelConversion / 0.907
|
||||||
|
}
|
||||||
if (grainBag) {
|
if (grainBag) {
|
||||||
grainBag.title = bagName;
|
grainBag.title = bagName;
|
||||||
grainBag.settings.initialMoisture = initialMoisture;
|
grainBag.settings.initialMoisture = initialMoisture;
|
||||||
|
|
@ -127,7 +133,7 @@ export default function GrainBagSettings(props: Props) {
|
||||||
grainBag.settings.bushelCapacity = grainCapacity;
|
grainBag.settings.bushelCapacity = grainCapacity;
|
||||||
grainBag.settings.grainSubtype = grainSubtype;
|
grainBag.settings.grainSubtype = grainSubtype;
|
||||||
grainBag.settings.fillDate = fillDate;
|
grainBag.settings.fillDate = fillDate;
|
||||||
grainBag.settings.bushelsPerTonne = bushelsPerTonne;
|
grainBag.settings.bushelsPerTonne = tonneConversion;
|
||||||
grainBag.settings.storageType = isCustom
|
grainBag.settings.storageType = isCustom
|
||||||
? pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN
|
? pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN
|
||||||
: pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN;
|
: pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN;
|
||||||
|
|
@ -161,6 +167,7 @@ export default function GrainBagSettings(props: Props) {
|
||||||
settings.currentBushels = grainBushels;
|
settings.currentBushels = grainBushels;
|
||||||
settings.grainSubtype = grainSubtype;
|
settings.grainSubtype = grainSubtype;
|
||||||
settings.fillDate = fillDate;
|
settings.fillDate = fillDate;
|
||||||
|
settings.bushelsPerTonne = tonneConversion;
|
||||||
settings.storageType = isCustom
|
settings.storageType = isCustom
|
||||||
? pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN
|
? pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN
|
||||||
: pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN;
|
: pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN;
|
||||||
|
|
@ -205,10 +212,10 @@ export default function GrainBagSettings(props: Props) {
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label="Bushels Per Tonne"
|
label="Bushels Per Tonne"
|
||||||
value={bushelsPerTonne}
|
value={bushelConversion}
|
||||||
type="number"
|
type="number"
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
setBushelsPerTonne(+event.target.value);
|
setBushelConversion(+event.target.value);
|
||||||
}}
|
}}
|
||||||
fullWidth
|
fullWidth
|
||||||
className={classes.bottomSpacing}
|
className={classes.bottomSpacing}
|
||||||
|
|
@ -227,7 +234,7 @@ export default function GrainBagSettings(props: Props) {
|
||||||
? pond.Grain[option.value as keyof typeof pond.Grain]
|
? pond.Grain[option.value as keyof typeof pond.Grain]
|
||||||
: pond.Grain.GRAIN_INVALID;
|
: pond.Grain.GRAIN_INVALID;
|
||||||
setSupportedGrainType(newGrainType);
|
setSupportedGrainType(newGrainType);
|
||||||
setBushelsPerTonne(GrainDescriber(newGrainType).bushelsPerTonne);
|
setBushelConversion(GrainDescriber(newGrainType).bushelsPerTonne);
|
||||||
setSelectedGrainOp(option);
|
setSelectedGrainOp(option);
|
||||||
}}
|
}}
|
||||||
group
|
group
|
||||||
|
|
@ -246,6 +253,18 @@ export default function GrainBagSettings(props: Props) {
|
||||||
return invalid;
|
return invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const grainUnitDisplay = () => {
|
||||||
|
if(bushelConversion > 1){
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
return "mT"
|
||||||
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
return "t"
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
return "bu"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<GrainTransaction
|
<GrainTransaction
|
||||||
|
|
@ -389,30 +408,24 @@ export default function GrainBagSettings(props: Props) {
|
||||||
className={classes.bottomSpacing}
|
className={classes.bottomSpacing}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label={
|
label={"Current Inventory"}
|
||||||
"Current " +
|
|
||||||
(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bushelsPerTonne > 0
|
|
||||||
? "Weight"
|
|
||||||
: "Bushels")
|
|
||||||
}
|
|
||||||
fullWidth
|
fullWidth
|
||||||
type="number"
|
type="number"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bushelsPerTonne > 0
|
{grainUnitDisplay()}
|
||||||
? "mT"
|
|
||||||
: "bu"}
|
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
value={grainFill}
|
value={grainFill}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
let bushelVal = +e.target.value;
|
let bushelVal = +e.target.value;
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE || getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) {
|
||||||
//convert the number as a weight into the bushel value
|
//convert the number as a weight into the bushel value, no changing or conversions necessary
|
||||||
bushelVal = +e.target.value * (bushelsPerTonne > 0 ? bushelsPerTonne : 1);
|
// since these are both user entered fields and should be the same unit (ton or tonne)
|
||||||
|
bushelVal = +e.target.value * (bushelConversion > 0 ? bushelConversion : 1);
|
||||||
}
|
}
|
||||||
if (bushelVal > grainCapacity) {
|
if (bushelVal > grainCapacity) {
|
||||||
bushelVal = grainCapacity;
|
bushelVal = grainCapacity;
|
||||||
|
|
|
||||||
|
|
@ -83,12 +83,19 @@ export default function GrainBagVisualizer(props: Props) {
|
||||||
const grainOverlay = () => {
|
const grainOverlay = () => {
|
||||||
let displayPending = pendingGrainAmount;
|
let displayPending = pendingGrainAmount;
|
||||||
let displayDiff = grainDiff;
|
let displayDiff = grainDiff;
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && grainBag.bushelsPerTonne() > 1) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1) {
|
||||||
if (displayPending && displayDiff) {
|
if (displayPending && displayDiff) {
|
||||||
displayPending = Math.round((displayPending / grainBag.bushelsPerTonne()) * 100) / 100;
|
displayPending = Math.round((displayPending / grainBag.bushelsPerTonne()) * 100) / 100;
|
||||||
displayDiff = Math.round((displayDiff / grainBag.bushelsPerTonne()) * 100) / 100;
|
displayDiff = Math.round((displayDiff / grainBag.bushelsPerTonne()) * 100) / 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1) {
|
||||||
|
if (displayPending && displayDiff) {
|
||||||
|
displayPending = Math.round((displayPending / (grainBag.bushelsPerTonne() * 0.907)) * 100) / 100;
|
||||||
|
displayDiff = Math.round((displayDiff / (grainBag.bushelsPerTonne()* 0.907)) * 100) / 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
{grainDiff !== undefined && grainDiff > 0 && (
|
{grainDiff !== undefined && grainDiff > 0 && (
|
||||||
|
|
@ -141,7 +148,7 @@ export default function GrainBagVisualizer(props: Props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const grainAmountDisplay = () => {
|
const grainAmountDisplay = () => {
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && grainBag.bushelsPerTonne() > 1) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||||
<Typography variant="body2" style={{ fontWeight: "bold", marginRight: "4px" }}>
|
<Typography variant="body2" style={{ fontWeight: "bold", marginRight: "4px" }}>
|
||||||
|
|
@ -150,6 +157,15 @@ export default function GrainBagVisualizer(props: Props) {
|
||||||
<Typography variant="body2">({grainBag.fillPercent()}%)</Typography>
|
<Typography variant="body2">({grainBag.fillPercent()}%)</Typography>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1) {
|
||||||
|
return (
|
||||||
|
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||||
|
<Typography variant="body2" style={{ fontWeight: "bold", marginRight: "4px" }}>
|
||||||
|
{(grainBag.bushels() / (grainBag.bushelsPerTonne()*0.907)).toFixed(2) + " t"}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2">({grainBag.fillPercent()}%)</Typography>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||||
|
|
|
||||||
123
src/hooks/useWebSocket.ts
Normal file
123
src/hooks/useWebSocket.ts
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
import { useEffect, useRef, useCallback } from "react";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives the WebSocket base URL from VITE_APP_API_URL.
|
||||||
|
* e.g. "https://api.brandxtech.ca" -> "wss://api.brandxtech.ca"
|
||||||
|
* Falls back to current page host for local dev.
|
||||||
|
*/
|
||||||
|
function getWsBaseUrl(): string {
|
||||||
|
const apiUrl = import.meta.env.VITE_APP_API_URL;
|
||||||
|
if (apiUrl) {
|
||||||
|
return apiUrl.replace(/^http/, "ws");
|
||||||
|
}
|
||||||
|
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||||
|
return `${protocol}//${window.location.host}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UseWebSocketOptions<T> {
|
||||||
|
/** The API path, e.g. "/v1/live/devices/123/components" */
|
||||||
|
path: string;
|
||||||
|
/** Transform the raw MessageEvent into your domain type */
|
||||||
|
parse: (event: MessageEvent) => T;
|
||||||
|
/** Called whenever a new parsed message arrives */
|
||||||
|
onMessage: (data: T) => void;
|
||||||
|
/** Auth token passed as ?token= query param */
|
||||||
|
token?: string;
|
||||||
|
/** Minimum seconds between updates, passed as ?rate= to the backend */
|
||||||
|
rate?: number;
|
||||||
|
/** Whether the connection should be active. Default true. */
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* useWebSocket manages a WebSocket connection with automatic reconnection.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* useWebSocket({
|
||||||
|
* path: `/v1/live/devices/${deviceID}/components`,
|
||||||
|
* parse: (e) => Component.any(JSON.parse(e.data)),
|
||||||
|
* onMessage: (component) => handleUpdate(component),
|
||||||
|
* token: authToken,
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useWebSocket<T>(options: UseWebSocketOptions<T>) {
|
||||||
|
const { path, parse, onMessage, token, rate = 0, enabled = true } = options;
|
||||||
|
|
||||||
|
// Keep latest callbacks in refs so reconnects don't use stale closures
|
||||||
|
const onMessageRef = useRef(onMessage);
|
||||||
|
onMessageRef.current = onMessage;
|
||||||
|
const parseRef = useRef(parse);
|
||||||
|
parseRef.current = parse;
|
||||||
|
|
||||||
|
const wsRef = useRef<WebSocket | null>(null);
|
||||||
|
const reconnectTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
|
||||||
|
const retriesRef = useRef(0);
|
||||||
|
|
||||||
|
const connect = useCallback(() => {
|
||||||
|
if (!token) return;
|
||||||
|
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.set("token", token);
|
||||||
|
if (rate > 0) params.set("rate", rate.toString());
|
||||||
|
|
||||||
|
const url = `${getWsBaseUrl()}${path}?${params.toString()}`;
|
||||||
|
const ws = new WebSocket(url);
|
||||||
|
wsRef.current = ws;
|
||||||
|
|
||||||
|
ws.onopen = () => {
|
||||||
|
console.debug(`[ws] connected: ${path}`);
|
||||||
|
retriesRef.current = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
try {
|
||||||
|
const parsed = parseRef.current(event);
|
||||||
|
onMessageRef.current(parsed);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(`[ws] parse error on ${path}:`, err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = (err) => {
|
||||||
|
console.warn(`[ws] error on ${path}:`, err);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = (event) => {
|
||||||
|
console.debug(`[ws] closed: ${path} (code: ${event.code})`);
|
||||||
|
wsRef.current = null;
|
||||||
|
|
||||||
|
// Don't reconnect on clean close or auth rejection
|
||||||
|
if (event.code === 1000 || event.code === 4001 || event.code === 4003) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exponential backoff: 1s, 2s, 4s, 8s, ... capped at 30s
|
||||||
|
const delay = Math.min(1000 * Math.pow(2, retriesRef.current), 30000);
|
||||||
|
retriesRef.current += 1;
|
||||||
|
console.debug(`[ws] reconnecting in ${delay}ms...`);
|
||||||
|
reconnectTimeoutRef.current = setTimeout(connect, delay);
|
||||||
|
};
|
||||||
|
}, [path, token, rate]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!enabled || !token) {
|
||||||
|
if (wsRef.current) {
|
||||||
|
wsRef.current.close(1000, "disabled");
|
||||||
|
wsRef.current = null;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (reconnectTimeoutRef.current) {
|
||||||
|
clearTimeout(reconnectTimeoutRef.current);
|
||||||
|
}
|
||||||
|
if (wsRef.current) {
|
||||||
|
wsRef.current.close(1000, "cleanup");
|
||||||
|
wsRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [connect, enabled, token]);
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import GrainDescriber from "grain/GrainDescriber";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import { MarkerData } from "maps/mapMarkers/Markers";
|
import { MarkerData } from "maps/mapMarkers/Markers";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
import { getGrainUnit } from "utils";
|
||||||
import { stringToMaterialColour } from "utils/strings";
|
import { stringToMaterialColour } from "utils/strings";
|
||||||
import { or } from "utils/types";
|
import { or } from "utils/types";
|
||||||
|
|
||||||
|
|
@ -235,17 +236,14 @@ export class Bin {
|
||||||
return bpt;
|
return bpt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public grainInventory(): number {
|
||||||
* gets the weight in tonnes for the grain inventory provided the bushels per tonne is set
|
let grain = this.bushels()
|
||||||
* if it is not set it will divide by 1 effectively returning the bushels
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.bushelsPerTonne() > 1){
|
||||||
* @returns grain weight
|
grain = this.bushels() / this.bushelsPerTonne()
|
||||||
*/
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.bushelsPerTonne() > 1){
|
||||||
public grainTonnes(): number {
|
grain = this.bushels() / (this.bushelsPerTonne() * 0.907)
|
||||||
let weight = 0;
|
|
||||||
if (this.settings.inventory) {
|
|
||||||
weight = this.settings.inventory.grainBushels / this.bushelsPerTonne();
|
|
||||||
}
|
}
|
||||||
return Math.round(weight * 100) / 100;
|
return Math.round(grain*100)/100
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,13 @@ export class Contract {
|
||||||
|
|
||||||
private measurementUnit(): string {
|
private measurementUnit(): string {
|
||||||
if (this.settings.type === pond.ContractType.CONTRACT_TYPE_GRAIN) {
|
if (this.settings.type === pond.ContractType.CONTRACT_TYPE_GRAIN) {
|
||||||
return getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT ? "mT" : "bu";
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1){
|
||||||
|
return "mT"
|
||||||
|
}
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.conversionValue() > 1){
|
||||||
|
return "t"
|
||||||
|
}
|
||||||
|
return "bu";
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
@ -202,9 +208,12 @@ export class Contract {
|
||||||
let size = this.settings.size;
|
let size = this.settings.size;
|
||||||
switch (this.settings.type) {
|
switch (this.settings.type) {
|
||||||
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && this.conversionValue() > 1) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1) {
|
||||||
size = size / this.conversionValue();
|
size = size / this.conversionValue();
|
||||||
}
|
}
|
||||||
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.conversionValue() > 1){
|
||||||
|
size = size / (this.conversionValue() * 0.907); //the conversion for grain will be stored in metric tonnes, this will convert it to US tons
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Math.round(size * 100) / 100;
|
return Math.round(size * 100) / 100;
|
||||||
}
|
}
|
||||||
|
|
@ -213,26 +222,33 @@ export class Contract {
|
||||||
let del = this.settings.delivered;
|
let del = this.settings.delivered;
|
||||||
switch (this.settings.type) {
|
switch (this.settings.type) {
|
||||||
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && this.conversionValue() > 1) {
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1) {
|
||||||
del = del / this.conversionValue();
|
del = del / this.conversionValue();
|
||||||
}
|
}
|
||||||
|
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.conversionValue() > 1){
|
||||||
|
del = del / (this.conversionValue() * 0.907); //the conversion for grain will be stored in metric tonnes, this will convert it to US tons
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return Math.round(del * 100) / 100;
|
return Math.round(del * 100) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static toStoredUnit(
|
public static toStoredUnit(
|
||||||
secondaryUnitVal: number,
|
secondaryUnitVal: number,
|
||||||
contractType: pond.ContractType,
|
contractType: pond.ContractType,
|
||||||
conversionValue: number
|
conversionValue: number
|
||||||
): number {
|
): number {
|
||||||
let storedunitVal = secondaryUnitVal;
|
let storedUnitVal = secondaryUnitVal;
|
||||||
switch (contractType) {
|
switch (contractType) {
|
||||||
|
//use the value and conversion they entered directly, it is safe to assume they are both the same unit (ton vs tonne) so dont need to convert anything
|
||||||
|
//before converting to bushels
|
||||||
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && conversionValue > 1) {
|
if ((getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE || getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) && conversionValue > 1) {
|
||||||
storedunitVal = secondaryUnitVal * conversionValue;
|
storedUnitVal = secondaryUnitVal * conversionValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return storedunitVal;
|
return storedUnitVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public grainName(): string {
|
public grainName(): string {
|
||||||
|
|
|
||||||
|
|
@ -928,9 +928,47 @@ export default function Bins(props: Props) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const grainUnitDisplay = (custom?: pond.CustomInventory) => {
|
||||||
|
// If custom and not convertible, always bushels
|
||||||
|
if (custom && custom.bushelsPerTonne <= 1) {
|
||||||
|
return " bu";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (getGrainUnit()) {
|
||||||
|
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
||||||
|
return " mT";
|
||||||
|
case pond.GrainUnit.GRAIN_UNIT_TON:
|
||||||
|
return " t";
|
||||||
|
default:
|
||||||
|
return " bu";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const customQuantityDisplay = (customInventory: pond.CustomInventory, bushels: number) => {
|
||||||
|
let amount = bushels
|
||||||
|
if(customInventory.bushelsPerTonne > 1){
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
amount = bushels/customInventory.bushelsPerTonne
|
||||||
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
amount = bushels/(customInventory.bushelsPerTonne*0.907)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Math.round(amount*100)/100
|
||||||
|
}
|
||||||
|
|
||||||
|
const supportedGrainDisplay = (grain: pond.Grain, bushels: number) => {
|
||||||
|
const describer = GrainDescriber(grain)
|
||||||
|
let amount = bushels
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
|
amount = bushels/describer.bushelsPerTonne
|
||||||
|
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
|
amount = bushels/describer.bushelsPerTon
|
||||||
|
}
|
||||||
|
return Math.round(amount*100)/100
|
||||||
|
}
|
||||||
|
|
||||||
const binUtilizationList = () => {
|
const binUtilizationList = () => {
|
||||||
const hasInventory = binMetrics && binMetrics.grainInventory.length > 0;
|
const hasInventory = binMetrics && binMetrics.grainInventory.length > 0;
|
||||||
const useWeight = getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT;
|
|
||||||
return (
|
return (
|
||||||
<Accordion
|
<Accordion
|
||||||
className={classes.accordion}
|
className={classes.accordion}
|
||||||
|
|
@ -972,17 +1010,9 @@ export default function Bins(props: Props) {
|
||||||
<ImageListItem key={key}>
|
<ImageListItem key={key}>
|
||||||
<BinUtilizationChart
|
<BinUtilizationChart
|
||||||
grain={inv.grainType}
|
grain={inv.grainType}
|
||||||
customUnit={useWeight ? " mT" : " bu"}
|
customUnit={grainUnitDisplay()}
|
||||||
bushelAmount={
|
bushelAmount={supportedGrainDisplay(inv.grainType, inv.bushelAmount)}
|
||||||
useWeight
|
bushelCapacity={supportedGrainDisplay(inv.grainType, inv.bushelCapacity)}
|
||||||
? inv.bushelAmount / GrainDescriber(inv.grainType).bushelsPerTonne
|
|
||||||
: inv.bushelAmount
|
|
||||||
}
|
|
||||||
bushelCapacity={
|
|
||||||
useWeight
|
|
||||||
? inv.bushelCapacity / GrainDescriber(inv.grainType).bushelsPerTonne
|
|
||||||
: inv.bushelCapacity
|
|
||||||
}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setContentFilter(pond.Grain[inv.grainType]);
|
setContentFilter(pond.Grain[inv.grainType]);
|
||||||
loadMoreBins(pond.Grain[inv.grainType]);
|
loadMoreBins(pond.Grain[inv.grainType]);
|
||||||
|
|
@ -1001,11 +1031,10 @@ export default function Bins(props: Props) {
|
||||||
amount = amount * 35.239;
|
amount = amount * 35.239;
|
||||||
cap = cap * 35.239;
|
cap = cap * 35.239;
|
||||||
unit = " L";
|
unit = " L";
|
||||||
}
|
} else {
|
||||||
if (useWeight && inv.bushelsPerTonne > 1) {
|
amount = customQuantityDisplay(inv, amount)
|
||||||
amount = amount / inv.bushelsPerTonne;
|
cap = customQuantityDisplay(inv, cap)
|
||||||
cap = cap / inv.bushelsPerTonne;
|
unit = grainUnitDisplay(inv);
|
||||||
unit = " mT";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { useDeviceAPI, useGlobalState, useSnackbar } from "providers";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useLocation, useParams } from "react-router-dom";
|
import { useLocation, useParams } from "react-router-dom";
|
||||||
import PageContainer from "./PageContainer";
|
import PageContainer from "./PageContainer";
|
||||||
import { useMobile } from "hooks";
|
import { useHTTP, useMobile } from "hooks";
|
||||||
import LoadingScreen from "app/LoadingScreen";
|
import LoadingScreen from "app/LoadingScreen";
|
||||||
import SmartBreadcrumb from "common/SmartBreadcrumb";
|
import SmartBreadcrumb from "common/SmartBreadcrumb";
|
||||||
import DeviceActions from "device/DeviceActions";
|
import DeviceActions from "device/DeviceActions";
|
||||||
|
|
@ -21,6 +21,7 @@ import { or } from "utils";
|
||||||
import ComponentDiagnostics from "component/ComponentDiagnostics";
|
import ComponentDiagnostics from "component/ComponentDiagnostics";
|
||||||
import DeviceWizard from "device/DeviceWizard";
|
import DeviceWizard from "device/DeviceWizard";
|
||||||
import DeviceScannedComponents from "device/autoDetect/DeviceScannedComponents";
|
import DeviceScannedComponents from "device/autoDetect/DeviceScannedComponents";
|
||||||
|
import { useWebSocket } from "hooks/useWebSocket";
|
||||||
|
|
||||||
export interface DevicePageData {
|
export interface DevicePageData {
|
||||||
device: Device;
|
device: Device;
|
||||||
|
|
@ -65,6 +66,8 @@ export default function DevicePage() {
|
||||||
|
|
||||||
// const [devicePageData, setDevicePageData] = useState(pond.GetDevicePageDataResponse.create())
|
// const [devicePageData, setDevicePageData] = useState(pond.GetDevicePageDataResponse.create())
|
||||||
|
|
||||||
|
const { token } = useHTTP();
|
||||||
|
|
||||||
const loadDevice = () => {
|
const loadDevice = () => {
|
||||||
if (loading) return
|
if (loading) return
|
||||||
if (state?.devicePageData) {
|
if (state?.devicePageData) {
|
||||||
|
|
@ -165,6 +168,65 @@ export default function DevicePage() {
|
||||||
.finally(() => setLoading(false));
|
.finally(() => setLoading(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Real-time component updates ---
|
||||||
|
// Streams all component changes for this device.
|
||||||
|
// When the backend receives a new reading and updates a component,
|
||||||
|
// this fires and updates the component in state without a page refresh.
|
||||||
|
useWebSocket<{ key: string; component: Component } | null>({
|
||||||
|
path: `/live/devices/${deviceID}/components`,
|
||||||
|
parse: (e) => {
|
||||||
|
try {
|
||||||
|
const raw = JSON.parse(e.data);
|
||||||
|
const comp = Component.any(raw);
|
||||||
|
if (!comp?.settings) {
|
||||||
|
console.warn("[ws] received component without settings:", raw);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return { key: comp.key(), component: comp };
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("[ws] failed to parse component:", err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMessage: (data) => {
|
||||||
|
if (!data) return;
|
||||||
|
const { key, component } = data;
|
||||||
|
setComponents((prev) => {
|
||||||
|
const updated = new Map(prev);
|
||||||
|
updated.set(key, component);
|
||||||
|
return updated;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
token,
|
||||||
|
enabled: !!deviceID,
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Real-time device updates (optional) ---
|
||||||
|
// Updates device-level info (name, status, lastActive, etc.)
|
||||||
|
useWebSocket<Device | null>({
|
||||||
|
path: `/live/devices/${deviceID}`,
|
||||||
|
parse: (e) => {
|
||||||
|
try {
|
||||||
|
const raw = JSON.parse(e.data);
|
||||||
|
const dev = Device.any(raw);
|
||||||
|
if (!dev?.settings) {
|
||||||
|
console.warn("[ws] received device without settings:", raw);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return dev;
|
||||||
|
} catch (err) {
|
||||||
|
console.warn("[ws] failed to parse device:", err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onMessage: (updatedDevice) => {
|
||||||
|
if (!updatedDevice) return;
|
||||||
|
setDevice(updatedDevice);
|
||||||
|
},
|
||||||
|
token,
|
||||||
|
enabled: !!deviceID,
|
||||||
|
});
|
||||||
|
|
||||||
const loadPortScan = () => {
|
const loadPortScan = () => {
|
||||||
deviceAPI.listFoundComponents(parseInt(deviceID))
|
deviceAPI.listFoundComponents(parseInt(deviceID))
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,8 @@ export default function SignupCallback () {
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
InputLabelProps={{ shrink: true }}>
|
InputLabelProps={{ shrink: true }}>
|
||||||
<MenuItem value={pond.GrainUnit.GRAIN_UNIT_BUSHELS}>Bushels (bu)</MenuItem>
|
<MenuItem value={pond.GrainUnit.GRAIN_UNIT_BUSHELS}>Bushels (bu)</MenuItem>
|
||||||
<MenuItem value={pond.GrainUnit.GRAIN_UNIT_WEIGHT}>Tonnes (mT)</MenuItem>
|
<MenuItem value={pond.GrainUnit.GRAIN_UNIT_TONNE}>Tonnes (mT)</MenuItem>
|
||||||
|
<MenuItem value={pond.GrainUnit.GRAIN_UNIT_TON}>US Tons (t)</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ export default function GrainBag(props: Props) {
|
||||||
}
|
}
|
||||||
console.log
|
console.log
|
||||||
userAPI.getUser(user.id(), { key: key, kind: kind } as Scope).then(resp => {
|
userAPI.getUser(user.id(), { key: key, kind: kind } as Scope).then(resp => {
|
||||||
console.log(resp)
|
|
||||||
setPermissions(resp.permissions);
|
setPermissions(resp.permissions);
|
||||||
});
|
});
|
||||||
}, [as, bagID, userAPI, user]);
|
}, [as, bagID, userAPI, user]);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ interface IHTTPContext {
|
||||||
) => Promise<AxiosResponse<T>>;
|
) => Promise<AxiosResponse<T>>;
|
||||||
del: <T>(url: string, spreadOptions?: AxiosRequestConfig) => Promise<AxiosResponse<T>>;
|
del: <T>(url: string, spreadOptions?: AxiosRequestConfig) => Promise<AxiosResponse<T>>;
|
||||||
options: (demo?: boolean) => AxiosRequestConfig;
|
options: (demo?: boolean) => AxiosRequestConfig;
|
||||||
|
token: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props extends PropsWithChildren<any>{
|
interface Props extends PropsWithChildren<any>{
|
||||||
|
|
@ -104,7 +105,8 @@ export default function HTTPProvider(props: Props) {
|
||||||
put,
|
put,
|
||||||
post,
|
post,
|
||||||
del,
|
del,
|
||||||
options: defaultOptions
|
options: defaultOptions,
|
||||||
|
token
|
||||||
}}>
|
}}>
|
||||||
{/* <BillingProvider> */}
|
{/* <BillingProvider> */}
|
||||||
<PondProvider>
|
<PondProvider>
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ export default function GrainBagProvider(props: PropsWithChildren<Props>) {
|
||||||
(end && "&end=" + end)
|
(end && "&end=" + end)
|
||||||
)
|
)
|
||||||
if (view) {
|
if (view) {
|
||||||
url = url + "?as=" + view
|
url = url + "&as=" + view
|
||||||
}
|
}
|
||||||
return get<pond.ListGrainBagHistoryResponse>(url);
|
return get<pond.ListGrainBagHistoryResponse>(url);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -336,9 +336,9 @@ export function getWhitelabel(): WhiteLabel {
|
||||||
if (window.location.origin.includes("bxt-dev")) {
|
if (window.location.origin.includes("bxt-dev")) {
|
||||||
return BXT_WHITE_LABEL;
|
return BXT_WHITE_LABEL;
|
||||||
}
|
}
|
||||||
// if (window.location.origin.includes("localhost")) {
|
if (window.location.origin.includes("localhost")) {
|
||||||
// return STAGING_WHITELABEL;
|
return STREAMLINE_WHITE_LABEL;
|
||||||
// }
|
}
|
||||||
if (window.location.origin.includes("staging") || import.meta.env.VITE_LOCAL_STAGING=='true') {
|
if (window.location.origin.includes("staging") || import.meta.env.VITE_LOCAL_STAGING=='true') {
|
||||||
return STAGING_WHITELABEL;
|
return STAGING_WHITELABEL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,17 @@ interface Props {
|
||||||
|
|
||||||
export default function TransactionDataDisplay(props: Props) {
|
export default function TransactionDataDisplay(props: Props) {
|
||||||
const { transaction } = props;
|
const { transaction } = props;
|
||||||
|
console.log(transaction)
|
||||||
|
|
||||||
|
const grainDisplay = (gt: pond.GrainTransaction) => {
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && gt.bushelsPerTonne > 1){
|
||||||
|
return "Weight: " + Math.round(gt.bushels / gt.bushelsPerTonne*100)/100 + " mT"
|
||||||
|
}
|
||||||
|
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && gt.bushelsPerTonne > 1){
|
||||||
|
return "Weight: " + Math.round(gt.bushels / (gt.bushelsPerTonne*0.907)*100)/100 + " t"
|
||||||
|
}
|
||||||
|
return "Bushels: " + gt.bushels
|
||||||
|
}
|
||||||
|
|
||||||
const display = () => {
|
const display = () => {
|
||||||
let transactionData = transaction.transaction.transaction;
|
let transactionData = transaction.transaction.transaction;
|
||||||
|
|
@ -27,9 +38,7 @@ export default function TransactionDataDisplay(props: Props) {
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>Variant: {gt.subtype}</Typography>
|
<Typography>Variant: {gt.subtype}</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && gt.bushelsPerTonne > 1
|
{grainDisplay(gt)}
|
||||||
? "Weight: " + gt.bushels / gt.bushelsPerTonne + " mT"
|
|
||||||
: "Bushels: " + gt.bushels}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography>Message: {gt.message}</Typography>
|
<Typography>Message: {gt.message}</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -455,8 +455,11 @@ export default function UserSettings(props: Props) {
|
||||||
case 1:
|
case 1:
|
||||||
grainUnit = pond.GrainUnit.GRAIN_UNIT_BUSHELS;
|
grainUnit = pond.GrainUnit.GRAIN_UNIT_BUSHELS;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 3:
|
||||||
grainUnit = pond.GrainUnit.GRAIN_UNIT_WEIGHT;
|
grainUnit = pond.GrainUnit.GRAIN_UNIT_TONNE;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
grainUnit = pond.GrainUnit.GRAIN_UNIT_TON;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
grainUnit = pond.GrainUnit.GRAIN_UNIT_UNKNOWN;
|
grainUnit = pond.GrainUnit.GRAIN_UNIT_UNKNOWN;
|
||||||
|
|
@ -540,7 +543,8 @@ export default function UserSettings(props: Props) {
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
InputLabelProps={{ shrink: true }}>
|
InputLabelProps={{ shrink: true }}>
|
||||||
<MenuItem value={pond.GrainUnit.GRAIN_UNIT_BUSHELS}>Bushels (bu)</MenuItem>
|
<MenuItem value={pond.GrainUnit.GRAIN_UNIT_BUSHELS}>Bushels (bu)</MenuItem>
|
||||||
<MenuItem value={pond.GrainUnit.GRAIN_UNIT_WEIGHT}>Tonnes (mT)</MenuItem>
|
<MenuItem value={pond.GrainUnit.GRAIN_UNIT_TONNE}>Tonnes (mT)</MenuItem>
|
||||||
|
<MenuItem value={pond.GrainUnit.GRAIN_UNIT_TON}>US Tons (t)</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -55,13 +55,33 @@ export function setDistanceUnit(unit: pond.DistanceUnit) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getGrainUnit(): pond.GrainUnit {
|
export function getGrainUnit(): pond.GrainUnit {
|
||||||
return localStorage.getItem("grainUnit") === "mT"
|
switch(localStorage.getItem("grainUnit")){
|
||||||
? pond.GrainUnit.GRAIN_UNIT_WEIGHT
|
case "mT":
|
||||||
: pond.GrainUnit.GRAIN_UNIT_BUSHELS;
|
return pond.GrainUnit.GRAIN_UNIT_TONNE
|
||||||
|
case "t":
|
||||||
|
return pond.GrainUnit.GRAIN_UNIT_TON
|
||||||
|
default:
|
||||||
|
return pond.GrainUnit.GRAIN_UNIT_BUSHELS
|
||||||
|
}
|
||||||
|
|
||||||
|
// return localStorage.getItem("grainUnit") === "mT"
|
||||||
|
// ? pond.GrainUnit.GRAIN_UNIT_WEIGHT
|
||||||
|
// : pond.GrainUnit.GRAIN_UNIT_BUSHELS;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setGrainUnit(unit: pond.GrainUnit) {
|
export function setGrainUnit(unit: pond.GrainUnit) {
|
||||||
localStorage.setItem("grainUnit", unit === pond.GrainUnit.GRAIN_UNIT_WEIGHT ? "mT" : "bu");
|
switch(unit){
|
||||||
|
case pond.GrainUnit.GRAIN_UNIT_WEIGHT:
|
||||||
|
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
||||||
|
localStorage.setItem("grainUnit", "mT")
|
||||||
|
break;
|
||||||
|
case pond.GrainUnit.GRAIN_UNIT_TON:
|
||||||
|
localStorage.setItem("grainUnit", "t")
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
localStorage.setItem("grainUnit", "bu")
|
||||||
|
}
|
||||||
|
// localStorage.setItem("grainUnit", unit === pond.GrainUnit.GRAIN_UNIT_WEIGHT ? "mT" : "bu");
|
||||||
}
|
}
|
||||||
|
|
||||||
export const distanceConversion = (val: number) => {
|
export const distanceConversion = (val: number) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue