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",
|
||||
"notistack": "^3.0.1",
|
||||
"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",
|
||||
"react": "^18.3.1",
|
||||
"react-beautiful-dnd": "^13.1.1",
|
||||
|
|
@ -11967,7 +11967,7 @@
|
|||
},
|
||||
"node_modules/protobuf-ts": {
|
||||
"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": {
|
||||
"protobufjs": "^6.8.8"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
"mui-tel-input": "^7.0.0",
|
||||
"notistack": "^3.0.1",
|
||||
"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",
|
||||
"react": "^18.3.1",
|
||||
"react-beautiful-dnd": "^13.1.1",
|
||||
|
|
|
|||
|
|
@ -443,14 +443,24 @@ export default function BinCard(props: Props) {
|
|||
" L"
|
||||
);
|
||||
}
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bin.bushelsPerTonne() > 1) {
|
||||
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
||||
return (
|
||||
bin.grainTonnes().toLocaleString() +
|
||||
bin.grainInventory().toLocaleString() +
|
||||
" mT " +
|
||||
bin.fillPercent() +
|
||||
"%"
|
||||
);
|
||||
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||
return (
|
||||
bin.grainInventory().toLocaleString() +
|
||||
" t " +
|
||||
bin.fillPercent() +
|
||||
"%"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
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;
|
||||
diameter: string;
|
||||
grainBushels: string;
|
||||
grainTonnes: string;
|
||||
grainWeight: string;
|
||||
grainType: Option | null;
|
||||
grainUse: Option | null;
|
||||
grainSubtype: string;
|
||||
customTypeName: string;
|
||||
highTemp: number;
|
||||
lowTemp: number;
|
||||
bushelsPerTonne: string;
|
||||
tempTarget: number;
|
||||
}
|
||||
|
||||
|
|
@ -160,14 +159,13 @@ export default function BinSettings(props: Props) {
|
|||
hopperHeight: "",
|
||||
diameter: "",
|
||||
grainBushels: "",
|
||||
grainTonnes: "",
|
||||
grainWeight: "",
|
||||
grainType: null,
|
||||
grainUse: null,
|
||||
grainSubtype: "",
|
||||
customTypeName: "",
|
||||
highTemp: 20,
|
||||
lowTemp: 10,
|
||||
bushelsPerTonne: "",
|
||||
tempTarget: 15
|
||||
});
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
|
|
@ -194,6 +192,7 @@ export default function BinSettings(props: Props) {
|
|||
const [isCustomBin, setIsCustomBin] = useState(false);
|
||||
const [binModelOps, setBinModelOptions] = useState<Option[]>([]);
|
||||
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 [autoTopNode, setAutoTopNode] = useState(false);
|
||||
const [inventoryControl, setInventoryControl] = useState<pond.BinInventoryControl>(
|
||||
|
|
@ -232,14 +231,27 @@ export default function BinSettings(props: Props) {
|
|||
|
||||
if (initForm.inventory) {
|
||||
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
|
||||
if (!initForm.inventory.bushelsPerTonne) {
|
||||
initForm.inventory.bushelsPerTonne = GrainDescriber(
|
||||
//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
|
||||
const grain = GrainDescriber(
|
||||
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){
|
||||
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 (!initForm.inventory.targetTemperature || initForm.inventory.targetTemperature) {
|
||||
|
|
@ -290,6 +302,21 @@ export default function BinSettings(props: Props) {
|
|||
? initForm.inventory.grainBushels * 35.239
|
||||
: 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);
|
||||
setHighTempC(initForm.highTemp ?? 20);
|
||||
|
|
@ -299,9 +326,10 @@ export default function BinSettings(props: Props) {
|
|||
height: h,
|
||||
diameter: d,
|
||||
grainBushels: gb.toFixed(2),
|
||||
grainTonnes: initForm.inventory?.bushelsPerTonne
|
||||
? (gb / initForm.inventory.bushelsPerTonne).toFixed(2)
|
||||
: "",
|
||||
grainWeight: weight,
|
||||
// grainTons: initForm.inventory?.bushelsPerTon
|
||||
// ? (gb / initForm.inventory.bushelsPerTon).toFixed(2)
|
||||
// : "",
|
||||
grainType: initForm.inventory?.grainType
|
||||
? ToGrainOption(initForm.inventory.grainType)
|
||||
: null,
|
||||
|
|
@ -315,8 +343,7 @@ export default function BinSettings(props: Props) {
|
|||
tempTarget: target,
|
||||
hopperHeight: hopperHeight,
|
||||
topConeHeight: topconeHeight,
|
||||
sidewallHeight: sidewallHeight,
|
||||
bushelsPerTonne: initForm.inventory?.bushelsPerTonne.toString() ?? "0"
|
||||
sidewallHeight: sidewallHeight
|
||||
});
|
||||
setInMoistureString(initForm.inventory?.initialMoisture.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 inventory = form.inventory;
|
||||
const empty = inventory ? inventory.empty : false;
|
||||
const bushPerTonne = formExtension.bushelsPerTonne;
|
||||
const binQuantity = formExtension.grainBushels;
|
||||
const grainTonnes = formExtension.grainTonnes;
|
||||
const grainType = formExtension.grainType;
|
||||
const grainSubtype = formExtension.grainSubtype;
|
||||
const grainUse = formExtension.grainUse;
|
||||
|
|
@ -805,11 +923,11 @@ export default function BinSettings(props: Props) {
|
|||
pond.BinInventory.create({
|
||||
...form.inventory,
|
||||
grainType: pond.Grain.GRAIN_CUSTOM,
|
||||
bushelsPerTonne: 0
|
||||
bushelsPerTonne: 0,
|
||||
})
|
||||
);
|
||||
updateFormExtension("grainType", null);
|
||||
updateFormExtension("bushelsPerTonne", "");
|
||||
setBushelConversion(0)
|
||||
} else {
|
||||
setStorageType(pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN);
|
||||
updateForm(
|
||||
|
|
@ -859,7 +977,8 @@ export default function BinSettings(props: Props) {
|
|||
let storageType = parseFloat(value) as pond.BinStorage;
|
||||
setStorageType(storageType);
|
||||
if (storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
||||
formExtension.bushelsPerTonne = "";
|
||||
// formExtension.bushelsPerTonne = "";
|
||||
setBushelConversion(0)
|
||||
formExtension.grainBushels = (
|
||||
parseFloat(formExtension.grainBushels) * 35.239
|
||||
).toFixed(0);
|
||||
|
|
@ -1054,7 +1173,29 @@ export default function BinSettings(props: Props) {
|
|||
</React.Fragment>
|
||||
:
|
||||
<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>
|
||||
}
|
||||
</React.Fragment>
|
||||
|
|
@ -1073,11 +1214,21 @@ export default function BinSettings(props: Props) {
|
|||
pond.BinInventory.create({
|
||||
...form.inventory,
|
||||
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
|
||||
//and is reset whenever the user switches between custom or not
|
||||
let conversion = 0
|
||||
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);
|
||||
}}
|
||||
group
|
||||
|
|
@ -1106,7 +1257,8 @@ export default function BinSettings(props: Props) {
|
|||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_BUSHELS ||
|
||||
{inventoryAmount()}
|
||||
{/* {getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_BUSHELS ||
|
||||
storageType === pond.BinStorage.BIN_STORAGE_FERTILIZER ||
|
||||
formExtension.bushelsPerTonne === "0" ||
|
||||
formExtension.bushelsPerTonne === "" ? (
|
||||
|
|
@ -1163,7 +1315,7 @@ export default function BinSettings(props: Props) {
|
|||
) : (
|
||||
<TextField
|
||||
label="Amount"
|
||||
value={grainTonnes}
|
||||
value={grainWeight}
|
||||
type="number"
|
||||
onChange={event => {
|
||||
let newWeight = event.target.value;
|
||||
|
|
@ -1180,7 +1332,7 @@ export default function BinSettings(props: Props) {
|
|||
})
|
||||
);
|
||||
//updateFormExtension("grainBushels", newBushels.toString())
|
||||
updateFormExtension("grainTonnes", newWeight);
|
||||
updateFormExtension("grainWeight", newWeight);
|
||||
}
|
||||
}}
|
||||
fullWidth
|
||||
|
|
@ -1191,7 +1343,7 @@ export default function BinSettings(props: Props) {
|
|||
}}
|
||||
className={classes.bottomSpacing}
|
||||
/>
|
||||
)}
|
||||
)} */}
|
||||
{!isCustomInventory && (
|
||||
<SearchSelect
|
||||
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
|
||||
const approvalDialog = () => {
|
||||
// get the display information for the transaction
|
||||
const grainTransaction = selectedTransaction?.transaction.transaction?.grainTransaction ?? pond.GrainTransaction.create()
|
||||
const bushels = grainTransaction.bushels ?? 0
|
||||
const weight = bushels / grainTransaction.bushelsPerTonne
|
||||
//const weight = bushels / grainTransaction.bushelsPerTonne
|
||||
let graintype = grainTransaction.grainType ?? pond.Grain.GRAIN_INVALID
|
||||
const grainDisplay = graintype === pond.Grain.GRAIN_CUSTOM
|
||||
const grainTypeDisplay = graintype === pond.Grain.GRAIN_CUSTOM
|
||||
? grainTransaction.customGrain
|
||||
: GrainDescriber(grainTransaction.grainType).name
|
||||
|
||||
|
|
@ -215,7 +228,7 @@ export default function BinTransactions(props: Props){
|
|||
<DialogTitle>Accept Transaction</DialogTitle>
|
||||
<DialogContent>
|
||||
<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>
|
||||
{/*Object type selection*/}
|
||||
<Autocomplete
|
||||
|
|
@ -378,9 +391,9 @@ export default function BinTransactions(props: Props){
|
|||
// get the display information for the transaction
|
||||
const grainTransaction = t.transaction.transaction?.grainTransaction ?? pond.GrainTransaction.create()
|
||||
const bushels = grainTransaction.bushels ?? 0
|
||||
const weight = bushels / grainTransaction.bushelsPerTonne
|
||||
// const weight = bushels / grainTransaction.bushelsPerTonne
|
||||
let graintype = grainTransaction.grainType ?? pond.Grain.GRAIN_INVALID
|
||||
const grainDisplay = graintype === pond.Grain.GRAIN_CUSTOM
|
||||
const grainTypeDisplay = graintype === pond.Grain.GRAIN_CUSTOM
|
||||
? grainTransaction.customGrain
|
||||
: GrainDescriber(grainTransaction.grainType).name
|
||||
return (
|
||||
|
|
@ -394,7 +407,7 @@ export default function BinTransactions(props: Props){
|
|||
</Box>
|
||||
</Box>
|
||||
<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
|
||||
variant="contained"
|
||||
disabled={selectedMatch?.transaction.key === t.transaction.key}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import { round } from "lodash";
|
|||
import { Bin, Component, Device } from "models";
|
||||
import { GetComponentIcon } from "pbHelpers/ComponentType";
|
||||
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
||||
import { useMobile } from "hooks";
|
||||
import { useComponentAPI, useMobile } from "hooks";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { quack } from "protobuf-ts/quack";
|
||||
import { useGlobalState, useSnackbar } from "providers";
|
||||
|
|
@ -71,6 +71,7 @@ import { makeStyles } from "@mui/styles";
|
|||
import ButtonGroup from "common/ButtonGroup";
|
||||
import ModeChangeDialog from "./conditioning/modeChangeDialog";
|
||||
import CustomGrainSelector from "grain/CustomGrainSelector";
|
||||
import BinControllerDisplay from "./BinControllerDisplay";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
return ({
|
||||
|
|
@ -180,7 +181,7 @@ interface Props {
|
|||
bin: Bin;
|
||||
loading: boolean;
|
||||
components: Map<string, Component>;
|
||||
componentDevices?: Map<string, number>;
|
||||
componentDevices: Map<string, number>;
|
||||
devices: Device[];
|
||||
plenums?: Plenum[];
|
||||
ambient?: Ambient;
|
||||
|
|
@ -270,7 +271,7 @@ export default function BinVisualizer(props: Props) {
|
|||
const [storageType, setStorageType] = useState<pond.BinStorage>(
|
||||
pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN
|
||||
);
|
||||
const [bushPerTonne, setBushPerTonne] = useState("0");
|
||||
//const [bushPerTonne, setBushPerTonne] = useState("0");
|
||||
const [grainSubtype, setGrainSubtype] = useState("");
|
||||
|
||||
const [loadingTrend, setLoadingTrend] = useState(false);
|
||||
|
|
@ -289,6 +290,12 @@ export default function BinVisualizer(props: Props) {
|
|||
const [modeChangeInProgress, setModeChangeInProgress] = useState(false)
|
||||
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(() => {
|
||||
setModeTime(moment(bin.status.lastModeChange));
|
||||
}, [bin.status.lastModeChange]);
|
||||
|
|
@ -326,7 +333,7 @@ export default function BinVisualizer(props: Props) {
|
|||
setCustomTypeName(bin.settings.inventory.customTypeName);
|
||||
setGrainType(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());
|
||||
setNewBinMode(bin.settings.mode);
|
||||
setNewGrainSettings(bin.customGrain());
|
||||
|
|
@ -495,8 +502,10 @@ export default function BinVisualizer(props: Props) {
|
|||
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
||||
return Math.round(val * 35.239 * 100) / 100;
|
||||
} 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;
|
||||
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||
return Math.round((val / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
|
|
@ -511,17 +520,19 @@ export default function BinVisualizer(props: Props) {
|
|||
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
||||
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() + "%)";
|
||||
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||
return "t (" + bin.fillPercent() + "%)";
|
||||
} else {
|
||||
return " / " + capacity.toLocaleString() + " bu";
|
||||
}
|
||||
};
|
||||
|
||||
const grainErrorCheck = () => {
|
||||
if (isNaN(parseFloat(bushPerTonne))) return true;
|
||||
return false;
|
||||
};
|
||||
// const grainErrorCheck = () => {
|
||||
// if (isNaN(parseFloat(bushPerTonne))) return true;
|
||||
// return false;
|
||||
// };
|
||||
|
||||
const inventoryOverview = () => {
|
||||
const capacity = bin.settings.specs?.bushelCapacity ?? 0;
|
||||
|
|
@ -774,7 +785,7 @@ export default function BinVisualizer(props: Props) {
|
|||
setCustomTypeName(bin.settings.inventory.customTypeName);
|
||||
setGrainType(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())
|
||||
setGrainSubtype(bin.subtype());
|
||||
}
|
||||
|
|
@ -802,7 +813,7 @@ export default function BinVisualizer(props: Props) {
|
|||
checked={isCustomInventory}
|
||||
onChange={(_, checked) => {
|
||||
setIsCustomInventory(checked);
|
||||
setBushPerTonne("0");
|
||||
//setBushPerTonne("0");
|
||||
setGrainSubtype("");
|
||||
setCustomTypeName("");
|
||||
setGrainOption(ToGrainOption(pond.Grain.GRAIN_NONE));
|
||||
|
|
@ -834,7 +845,7 @@ export default function BinVisualizer(props: Props) {
|
|||
: pond.Grain.GRAIN_INVALID;
|
||||
setGrainOption(ToGrainOption(newGrainType));
|
||||
setGrainType(newGrainType);
|
||||
setBushPerTonne(GrainDescriber(newGrainType).bushelsPerTonne.toFixed(2));
|
||||
//setBushPerTonne(GrainDescriber(newGrainType).bushelsPerTonne.toFixed(2));
|
||||
}}
|
||||
group
|
||||
disabled={!canEdit}
|
||||
|
|
@ -897,7 +908,7 @@ export default function BinVisualizer(props: Props) {
|
|||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
disabled={grainErrorCheck()}
|
||||
// disabled={grainErrorCheck()}
|
||||
onClick={() => {
|
||||
updateBin();
|
||||
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();
|
||||
if (pendingDisplay) {
|
||||
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 (
|
||||
<Box display="flex" width={1} justifyContent="flex-end">
|
||||
<FullScreen handle={fullScreenHandler}>
|
||||
|
|
@ -1533,54 +1551,24 @@ export default function BinVisualizer(props: Props) {
|
|||
Controllers
|
||||
</Typography>
|
||||
<Box className={classes.displayBox}>
|
||||
{bin.status.fans.map(fan => (
|
||||
<Box className={classes.controllerDisplay} key={fan.key}>
|
||||
<Box display="flex">
|
||||
<AerationFanIcon />
|
||||
<Typography
|
||||
align="center"
|
||||
style={{
|
||||
paddingLeft: 5,
|
||||
fontSize: isMobile ? "0.85rem" : "1.0rem",
|
||||
fontWeight: 650
|
||||
}}>
|
||||
{fan.name}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
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>
|
||||
))}
|
||||
{bin.status.fans.map(fan => {
|
||||
let fanComp = components.get(fan.key)
|
||||
let device = componentDevices.get(fan.key)
|
||||
if(fanComp && device){
|
||||
return (
|
||||
<BinControllerDisplay key={fanComp.key()} component={fanComp} deviceID={device} currentState/>
|
||||
)
|
||||
}
|
||||
})}
|
||||
{bin.status.heaters.map(heater => {
|
||||
let heaterComp = components.get(heater.key)
|
||||
let device = componentDevices.get(heater.key)
|
||||
if(heaterComp && device){
|
||||
return (
|
||||
<BinControllerDisplay key={heaterComp.key()} component={heaterComp} deviceID={device} currentState={heater.state}/>
|
||||
)
|
||||
}
|
||||
})}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
|
|
@ -1987,9 +1975,10 @@ export default function BinVisualizer(props: Props) {
|
|||
//update all the grain stuff
|
||||
b.settings.inventory.grainType = grainType;
|
||||
b.settings.inventory.customTypeName = customTypeName;
|
||||
b.settings.inventory.bushelsPerTonne = isNaN(parseFloat(bushPerTonne))
|
||||
? 0
|
||||
: parseFloat(bushPerTonne);
|
||||
b.settings.inventory.bushelsPerTonne = GrainDescriber(grainType).bushelsPerTonne
|
||||
// b.settings.inventory.bushelsPerTonne = isNaN(parseFloat(bushPerTonne))
|
||||
// ? 0
|
||||
// : parseFloat(bushPerTonne);
|
||||
b.settings.inventory.grainSubtype = grainSubtype;
|
||||
b.settings.inventory.customGrain = newGrainSettings
|
||||
}
|
||||
|
|
@ -2010,7 +1999,6 @@ export default function BinVisualizer(props: Props) {
|
|||
}
|
||||
b.settings.mode = newBinMode;
|
||||
}
|
||||
console.log(b.settings)
|
||||
binAPI.updateBin(bin.key(), b.settings, as).then(resp => {
|
||||
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 hasInventory = binMetrics && binMetrics.grainInventory.length > 0;
|
||||
const useWeight = getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT;
|
||||
return (
|
||||
<Accordion
|
||||
className={classes.accordion}
|
||||
|
|
@ -695,17 +733,9 @@ export default function BinyardDisplay(props: Props) {
|
|||
<GridListTile key={key}>
|
||||
<BinUtilizationChart
|
||||
grain={inv.grainType}
|
||||
customUnit={useWeight ? " mT" : " bu"}
|
||||
bushelAmount={
|
||||
useWeight
|
||||
? inv.bushelAmount / GrainDescriber(inv.grainType).bushelsPerTonne
|
||||
: inv.bushelAmount
|
||||
}
|
||||
bushelCapacity={
|
||||
useWeight
|
||||
? inv.bushelCapacity / GrainDescriber(inv.grainType).bushelsPerTonne
|
||||
: inv.bushelCapacity
|
||||
}
|
||||
customUnit={grainUnitDisplay()}
|
||||
bushelAmount={supportedGrainDisplay(inv.grainType, inv.bushelAmount)}
|
||||
bushelCapacity={supportedGrainDisplay(inv.grainType, inv.bushelCapacity)}
|
||||
onClick={() => {
|
||||
setContentFilter(pond.Grain[inv.grainType]);
|
||||
loadMoreBins(pond.Grain[inv.grainType]);
|
||||
|
|
@ -724,11 +754,10 @@ export default function BinyardDisplay(props: Props) {
|
|||
amount = amount * 35.239;
|
||||
cap = cap * 35.239;
|
||||
unit = " L";
|
||||
}
|
||||
if (useWeight && inv.bushelsPerTonne > 1) {
|
||||
amount = amount / inv.bushelsPerTonne;
|
||||
cap = cap / inv.bushelsPerTonne;
|
||||
unit = " mT";
|
||||
}else{
|
||||
amount = customQuantityDisplay(inv, amount)
|
||||
cap = customQuantityDisplay(inv, cap)
|
||||
unit = grainUnitDisplay(inv)
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -69,9 +69,12 @@ export default function BinLevelOverTime(props: Props) {
|
|||
if (fertilizerBin && cap) {
|
||||
cap = cap * 35.239;
|
||||
}
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && cap) {
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && cap) {
|
||||
cap = cap / bin.bushelsPerTonne();
|
||||
}
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
||||
cap = cap / (bin.bushelsPerTonne()*0.907);
|
||||
}
|
||||
setCapacity(cap);
|
||||
binAPI
|
||||
.listHistoryBetween(bin.key(), 500, startDate.toISOString(), endDate.toISOString())
|
||||
|
|
@ -85,13 +88,18 @@ export default function BinLevelOverTime(props: Props) {
|
|||
if (hist.settings?.inventory) {
|
||||
let bushels = hist.settings.inventory.grainBushels ?? 0;
|
||||
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 = {
|
||||
timestamp: moment(hist.timestamp).valueOf(),
|
||||
value: fertilizerBin
|
||||
? Math.round(bushels * 35.239)
|
||||
: getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT
|
||||
? Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100
|
||||
: bushels
|
||||
: grainDisplay
|
||||
};
|
||||
data.push(newData);
|
||||
lastBushels = bushels;
|
||||
|
|
@ -112,12 +120,17 @@ export default function BinLevelOverTime(props: Props) {
|
|||
let currentTime = moment().valueOf();
|
||||
if (data.length === 0) {
|
||||
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({
|
||||
value: fertilizerBin
|
||||
? Math.round(bushels * 35.239)
|
||||
: getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT
|
||||
? Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100
|
||||
: bushels,
|
||||
: grainDisplay,
|
||||
timestamp: currentTime
|
||||
});
|
||||
}
|
||||
|
|
@ -143,9 +156,12 @@ export default function BinLevelOverTime(props: Props) {
|
|||
if (fertilizerBin && cap) {
|
||||
cap = cap * 35.239;
|
||||
}
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && cap) {
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && cap) {
|
||||
cap = cap / bin.bushelsPerTonne();
|
||||
}
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
||||
cap = cap / (bin.bushelsPerTonne()*0.907);
|
||||
}
|
||||
setCapacity(cap);
|
||||
let autoBarData: BarData[] = [];
|
||||
|
||||
|
|
@ -163,8 +179,15 @@ export default function BinLevelOverTime(props: Props) {
|
|||
m.values.forEach((val, i) => {
|
||||
if (val.values[0] && m.timestamps[i]) {
|
||||
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({
|
||||
value: val.values[0],
|
||||
value: grainDisplay,
|
||||
timestamp: moment(m.timestamps[i]).valueOf(),
|
||||
});
|
||||
lastBushels = val.values[0];
|
||||
|
|
@ -175,12 +198,17 @@ export default function BinLevelOverTime(props: Props) {
|
|||
if (autoBarData.length === 0) {
|
||||
let bushels = bin.bushels();
|
||||
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({
|
||||
value: fertilizerBin
|
||||
? Math.round(bushels * 35.239)
|
||||
: getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT
|
||||
? Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100
|
||||
: bushels,
|
||||
: grainDisplay,
|
||||
timestamp: currentTime
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ interface Props {
|
|||
* @default undefined
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
|
@ -97,7 +101,7 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
})
|
||||
|
||||
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 [currentToggle, setCurrentToggle] = useState<number[]>([])
|
||||
|
||||
|
|
@ -107,6 +111,8 @@ export default function ButtonGroup(props: Props){
|
|||
let toggled: number [] = [0]
|
||||
if(toggledButtons){
|
||||
toggled = toggledButtons
|
||||
} else if(defaultToggle){
|
||||
toggled = [defaultToggle]
|
||||
}
|
||||
setCurrentToggle(toggled)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,9 +92,14 @@ export default function ContractSettings(props: Props) {
|
|||
setContractValue(contract.settings.totalValue.toString());
|
||||
setCommodity(contract.settings.commodity);
|
||||
setContractDate(contract.settings.contractDate);
|
||||
setConversionValue(
|
||||
contract.settings.conversionValue > 0 ? contract.settings.conversionValue.toString() : "1"
|
||||
);
|
||||
let conv = 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());
|
||||
}
|
||||
}, [contract]);
|
||||
|
|
@ -102,12 +107,21 @@ export default function ContractSettings(props: Props) {
|
|||
useEffect(() => {
|
||||
switch (contractType) {
|
||||
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({
|
||||
sizeLabel: "Total Grain on Contract",
|
||||
commodityLabel: "Select Grain Type",
|
||||
conversionLabel: "Bushels Per Tonne",
|
||||
conversionLabel: conversionLabel,
|
||||
deliveryLabel: "Grain Delivered",
|
||||
adornment: getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT ? "mT" : "bu"
|
||||
adornment: adornment
|
||||
});
|
||||
break;
|
||||
default:
|
||||
|
|
@ -148,13 +162,22 @@ export default function ContractSettings(props: Props) {
|
|||
};
|
||||
|
||||
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))
|
||||
? 0
|
||||
: Math.round(Contract.toStoredUnit(parseFloat(deliveredAmount), contractType, conVal));
|
||||
const sizeVal = isNaN(parseFloat(contractSize))
|
||||
? 0
|
||||
: 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) {
|
||||
let settings: pond.ContractSettings = contract.settings;
|
||||
settings.commodity = commodity;
|
||||
|
|
@ -201,7 +224,6 @@ export default function ContractSettings(props: Props) {
|
|||
settings.type = contractType;
|
||||
settings.conversionValue = conVal;
|
||||
settings.contractDate = contractDate;
|
||||
|
||||
contractAPI
|
||||
.addContract(name, settings, as)
|
||||
.then(resp => {
|
||||
|
|
@ -490,7 +512,9 @@ export default function ContractSettings(props: Props) {
|
|||
InputLabelProps={{ shrink: true }}
|
||||
error={isNaN(parseFloat(conversionValue))}
|
||||
helperText={isNaN(parseFloat(conversionValue)) ? "Must be a valid number" : ""}
|
||||
onChange={e => setConversionValue(e.target.value)}
|
||||
onChange={e => {
|
||||
setConversionValue(e.target.value)
|
||||
}}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -27,11 +27,17 @@ export default function ContractTransactionGraph(props: Props) {
|
|||
if (transaction?.grainTransaction) {
|
||||
value = transaction.grainTransaction.bushels;
|
||||
if (
|
||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT &&
|
||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
||||
transaction.grainTransaction.bushelsPerTonne > 1
|
||||
) {
|
||||
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({
|
||||
timestamp: time.valueOf(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
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 DeviceTags from "device/DeviceTags";
|
||||
import VersionChip from "device/VersionChip";
|
||||
|
|
@ -233,6 +233,17 @@ export default function DeviceOverview(props: Props) {
|
|||
<StatusChip status="pending" />
|
||||
</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} />}
|
||||
</Grid>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -235,6 +235,12 @@ export default function DeviceSettings(props: Props) {
|
|||
setDeviceForm(updatedForm);
|
||||
};
|
||||
|
||||
const toggleBusRequired = (event: any) => {
|
||||
let updatedForm = Device.clone(deviceForm);
|
||||
updatedForm.settings.needsBusControl = event.target.checked;
|
||||
setDeviceForm(updatedForm);
|
||||
};
|
||||
|
||||
const toggleSleeps = (event: any) => {
|
||||
let updatedForm = Device.clone(deviceForm);
|
||||
let updatedSleeps = event.target.checked;
|
||||
|
|
@ -500,7 +506,8 @@ export default function DeviceSettings(props: Props) {
|
|||
</Grid>
|
||||
)}
|
||||
{user.hasAdmin() && (
|
||||
<Grid size={{ xs: 12, sm: 12 }}>
|
||||
<React.Fragment>
|
||||
<Grid size={{ xs: 12, sm: 6 }}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
|
|
@ -516,6 +523,23 @@ export default function DeviceSettings(props: Props) {
|
|||
labelPlacement="end"
|
||||
/>
|
||||
</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>
|
||||
</React.Fragment>
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ export default function FieldSettings(props: Props) {
|
|||
settings.grainSubtype = grainSubtype;
|
||||
settings.landLocation = landLocation;
|
||||
settings.acres = acres;
|
||||
settings.bushelsPerTonne = isNaN(parseFloat(bushelsPerTonne)) ? 1 : parseFloat(bushelsPerTonne);
|
||||
|
||||
fieldAPI
|
||||
.updateField(selectedField.key(), settings, undefined, as)
|
||||
|
|
@ -121,6 +122,7 @@ export default function FieldSettings(props: Props) {
|
|||
geo.shapes = borders;
|
||||
}
|
||||
settings.fieldGeoData = geo;
|
||||
settings.bushelsPerTonne = isNaN(parseFloat(bushelsPerTonne)) ? 1 : parseFloat(bushelsPerTonne);
|
||||
fieldAPI
|
||||
.addField(settings, as)
|
||||
.then(resp => {
|
||||
|
|
@ -226,6 +228,7 @@ export default function FieldSettings(props: Props) {
|
|||
if (option) {
|
||||
let grainType = pond.Grain[option.value as keyof typeof pond.Grain];
|
||||
setCropType(grainType);
|
||||
console.log("set bpt here")
|
||||
setBushelsPerTonne(GrainDescriber(grainType).bushelsPerTonne.toString());
|
||||
}
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -126,9 +126,24 @@ export default function GateDevice(props: Props) {
|
|||
}
|
||||
}, [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 !== "") {
|
||||
gateAPI
|
||||
//the promise for adding the pref to the new component
|
||||
promises.push(gateAPI
|
||||
.updatePrefs(
|
||||
gate.key,
|
||||
"component",
|
||||
|
|
@ -137,11 +152,17 @@ export default function GateDevice(props: Props) {
|
|||
[gate.key],
|
||||
["gate"],
|
||||
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(() => {
|
||||
|
|
@ -205,7 +226,7 @@ export default function GateDevice(props: Props) {
|
|||
style={{ fontSize: 8 }}
|
||||
onChange={e => {
|
||||
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);
|
||||
if (tempKey === key) {
|
||||
setTempKey("");
|
||||
|
|
@ -238,6 +259,7 @@ export default function GateDevice(props: Props) {
|
|||
style={{ fontSize: 8 }}
|
||||
onChange={e => {
|
||||
gateComponentUpdate(
|
||||
tempKey,
|
||||
e.target.value as string,
|
||||
pond.GateComponentType.GATE_COMPONENT_TYPE_TEMP
|
||||
);
|
||||
|
|
@ -273,6 +295,7 @@ export default function GateDevice(props: Props) {
|
|||
style={{ fontSize: 8 }}
|
||||
onChange={e => {
|
||||
gateComponentUpdate(
|
||||
pressureKey,
|
||||
e.target.value as string,
|
||||
pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
|
||||
);
|
||||
|
|
|
|||
|
|
@ -93,15 +93,14 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
compDevice.components.forEach(comp => {
|
||||
let component = Component.any(comp);
|
||||
//checks the address for the LED components to get the red and green LED's
|
||||
|
||||
if (component.locationString() === redAddr && component.subType() === 1) {
|
||||
setRedComponent(component);
|
||||
} else if (component.locationString() === greenAddr && component.subType() === 1) {
|
||||
setGreenComponent(component);
|
||||
} else if (component.type() === quack.ComponentType.COMPONENT_TYPE_PRESSURE_CABLE) {
|
||||
if (
|
||||
} else if (
|
||||
gate.preferences[component.key()] === pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
|
||||
) {
|
||||
console.log(component)
|
||||
setPressureComponent(component);
|
||||
setPressureSource(
|
||||
quack.ComponentID.create({
|
||||
|
|
@ -111,13 +110,13 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if(compDevice.device){
|
||||
setDevice(Device.create(compDevice.device))
|
||||
}
|
||||
}, [gate, densityTemp, user, compDevice]);
|
||||
}, [gate, densityTemp, user, compDevice, gate.preferences]);
|
||||
|
||||
const buttonDisabled = () => {
|
||||
if (greenComponent === undefined) return true
|
||||
|
|
@ -129,13 +128,13 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
|
||||
const createInteractions = async () => {
|
||||
//the interactions to be made
|
||||
|
||||
if (
|
||||
greenComponent !== undefined &&
|
||||
redComponent !== undefined &&
|
||||
pressureComponent !== undefined
|
||||
) {
|
||||
|
||||
//get the number of nodes in the pressure components
|
||||
let nodes = pressureComponent.numNodes()
|
||||
let lightInteractions: pond.InteractionSettings[] = []
|
||||
//making variables for the parameters of the interactions
|
||||
const redSink = quack.ComponentID.create({
|
||||
|
|
@ -163,19 +162,18 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
source: pressureSource,
|
||||
conditions: [
|
||||
pond.InteractionCondition.create({
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||
value: -highDelta,
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||
value: highDelta,
|
||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||
}),
|
||||
pond.InteractionCondition.create({
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||
value: -lowDelta,
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||
value: lowDelta,
|
||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||
})
|
||||
],
|
||||
nodeOne: 2,
|
||||
nodeTwo: 1,
|
||||
subtype: 18,
|
||||
nodeOne: nodes,
|
||||
subtype: nodes+1,
|
||||
schedule: lightSchedule,
|
||||
result: pond.InteractionResult.create({
|
||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
|
||||
|
|
@ -201,14 +199,13 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
source: pressureSource,
|
||||
conditions: [
|
||||
pond.InteractionCondition.create({
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||
value: -highDelta,
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||
value: highDelta,
|
||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||
})
|
||||
],
|
||||
nodeOne: 2,
|
||||
nodeTwo: 1,
|
||||
subtype: 18,
|
||||
nodeOne: nodes,
|
||||
subtype: nodes+1,
|
||||
schedule: lightSchedule,
|
||||
result: pond.InteractionResult.create({
|
||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||
|
|
@ -221,19 +218,18 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
source: pressureSource,
|
||||
conditions: [
|
||||
pond.InteractionCondition.create({
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||
value: -highDelta,
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||
value: highDelta,
|
||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||
}),
|
||||
pond.InteractionCondition.create({
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||
value: -lowDelta,
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||
value: lowDelta,
|
||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||
})
|
||||
],
|
||||
nodeOne: 2,
|
||||
nodeTwo: 1,
|
||||
subtype: 18,
|
||||
nodeOne: nodes,
|
||||
subtype: nodes+1,
|
||||
schedule: lightSchedule,
|
||||
result: pond.InteractionResult.create({
|
||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||
|
|
@ -246,19 +242,18 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
source: pressureSource,
|
||||
conditions: [
|
||||
pond.InteractionCondition.create({
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||
value: -lowDelta,
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||
value: lowDelta,
|
||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||
}),
|
||||
pond.InteractionCondition.create({
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||
value: -thresholdPascals,
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||
value: thresholdPascals,
|
||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||
}),
|
||||
],
|
||||
nodeOne: 2,
|
||||
nodeTwo: 1,
|
||||
subtype: 18,
|
||||
nodeOne: nodes,
|
||||
subtype: nodes+1,
|
||||
schedule: lightSchedule,
|
||||
result: pond.InteractionResult.create({
|
||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||
|
|
@ -276,7 +271,8 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||
}),
|
||||
],
|
||||
subtype: 1,
|
||||
nodeOne: nodes,
|
||||
subtype: nodes+1,
|
||||
schedule: lightSchedule,
|
||||
result: pond.InteractionResult.create({
|
||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_SET,
|
||||
|
|
@ -291,19 +287,18 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
source: pressureSource,
|
||||
conditions: [
|
||||
pond.InteractionCondition.create({
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||
value: -highDelta,
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||
value: highDelta,
|
||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||
}),
|
||||
pond.InteractionCondition.create({
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_LESS_THAN,
|
||||
value: -lowDelta,
|
||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||
value: lowDelta,
|
||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE
|
||||
})
|
||||
],
|
||||
nodeOne: 2,
|
||||
nodeTwo: 1,
|
||||
subtype: 18,
|
||||
nodeOne: nodes,
|
||||
subtype: nodes+1,
|
||||
schedule: lightSchedule,
|
||||
result: pond.InteractionResult.create({
|
||||
type: quack.InteractionResultType.INTERACTION_RESULT_TYPE_TOGGLE,
|
||||
|
|
@ -393,7 +388,6 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
color="primary"
|
||||
onClick={() => {
|
||||
//TODO: Once we figure out how to fix the backend to handle rapid addition/removal of interactions
|
||||
//removeCurrentInteractions();
|
||||
setAdding(true);
|
||||
interactionsAPI.clearInteractions(device.id(), [pressureSource]).then(resp => {
|
||||
createInteractions();
|
||||
|
|
@ -401,7 +395,8 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
console.error(err)
|
||||
})
|
||||
}}
|
||||
disabled={buttonDisabled()}>
|
||||
disabled={buttonDisabled()}
|
||||
>
|
||||
{adding ? "Adding Interaction" : "Create Interaction"}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import {MenuItem, TextField } from "@mui/material"
|
|||
import { cloneDeep } from "lodash"
|
||||
import { pond } from "protobuf-ts/pond"
|
||||
import React, { useEffect, useRef, useState } from "react"
|
||||
import { getGrainUnit } from "utils"
|
||||
|
||||
interface Props {
|
||||
grainSettings?: pond.GrainSettings
|
||||
|
|
@ -18,7 +19,7 @@ export default function CustomGrainForm(props: Props) {
|
|||
const [constantB, setConstantB] = useState("0")
|
||||
const [constantC, setConstantC] = 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)
|
||||
|
||||
useEffect(()=>{
|
||||
|
|
@ -30,12 +31,19 @@ export default function CustomGrainForm(props: Props) {
|
|||
setConstantB(grainSettings.b.toString())
|
||||
setConstantC(grainSettings.c.toString())
|
||||
setKgPerBushel(grainSettings.kgPerBushel.toString())
|
||||
setBushelsPerTonne(grainSettings.bushelsPerTonne.toString())
|
||||
setBushelConversion(grainSettings.bushelsPerTonne.toString())
|
||||
setNewGrainSettings(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 (group === "") return false
|
||||
if (isNaN(parseFloat(constA))) return false
|
||||
|
|
@ -64,7 +72,7 @@ export default function CustomGrainForm(props: Props) {
|
|||
setName(name)
|
||||
let settings = cloneDeep(newGrainSettings)
|
||||
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)
|
||||
}}/>
|
||||
<TextField
|
||||
|
|
@ -77,7 +85,7 @@ export default function CustomGrainForm(props: Props) {
|
|||
setGroup(group)
|
||||
let settings = cloneDeep(newGrainSettings)
|
||||
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)
|
||||
}}/>
|
||||
<TextField
|
||||
|
|
@ -91,7 +99,7 @@ export default function CustomGrainForm(props: Props) {
|
|||
setEquation(enumVal)
|
||||
let settings = cloneDeep(newGrainSettings)
|
||||
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)
|
||||
}}
|
||||
select>
|
||||
|
|
@ -121,7 +129,7 @@ export default function CustomGrainForm(props: Props) {
|
|||
onChange={(e) => {
|
||||
let val = e.target.value
|
||||
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)
|
||||
if(!isNaN(parseFloat(val))){
|
||||
settings.a = parseFloat(val)
|
||||
|
|
@ -139,7 +147,7 @@ export default function CustomGrainForm(props: Props) {
|
|||
onChange={(e) => {
|
||||
let val = e.target.value
|
||||
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)
|
||||
if(!isNaN(parseFloat(val))){
|
||||
settings.b = parseFloat(val)
|
||||
|
|
@ -157,7 +165,7 @@ export default function CustomGrainForm(props: Props) {
|
|||
onChange={(e) => {
|
||||
let val = e.target.value
|
||||
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)
|
||||
if(!isNaN(parseFloat(val))){
|
||||
settings.c = parseFloat(val)
|
||||
|
|
@ -175,7 +183,7 @@ export default function CustomGrainForm(props: Props) {
|
|||
onChange={(e) => {
|
||||
let val = e.target.value
|
||||
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)
|
||||
if(!isNaN(parseFloat(val))){
|
||||
settings.kgPerBushel = parseFloat(val)
|
||||
|
|
@ -187,20 +195,24 @@ export default function CustomGrainForm(props: Props) {
|
|||
sx={{marginBottom: 2}}
|
||||
fullWidth
|
||||
type="number"
|
||||
value={bushelsPerTonne}
|
||||
error={isNaN(parseFloat(bushelsPerTonne))}
|
||||
helperText={isNaN(parseFloat(bushelsPerTonne)) ? "Must be a valid number" : ""}
|
||||
value={bushelsConversion}
|
||||
error={isNaN(parseFloat(bushelsConversion))}
|
||||
helperText={isNaN(parseFloat(bushelsConversion)) ? "Must be a valid number" : ""}
|
||||
onChange={(e) => {
|
||||
let val = e.target.value
|
||||
setBushelsPerTonne(val)
|
||||
setBushelConversion(val)
|
||||
valid.current = validate(name, group, constantA, constantB, constantC, kgPerBushel, val)
|
||||
let settings = cloneDeep(newGrainSettings)
|
||||
if(!isNaN(parseFloat(val))){
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||
settings.bushelsPerTonne = parseFloat(val)/0.907
|
||||
}else{
|
||||
settings.bushelsPerTonne = parseFloat(val)
|
||||
}
|
||||
}
|
||||
settingsChanged(settings)
|
||||
}}
|
||||
label="Bushels per Tonne"/>
|
||||
label={"Bushels per " + (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE ? " Tonne" : "Ton")}/>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export interface GrainExtension {
|
|||
colour: string;
|
||||
weightConversionKg: number;
|
||||
bushelsPerTonne: number;
|
||||
bushelsPerTon: number; //NOTE: this is US tons (2000lB/t)
|
||||
}
|
||||
|
||||
const defaultSetTemp = 30.0;
|
||||
|
|
@ -45,7 +46,8 @@ const defaultGrain: GrainExtension = {
|
|||
targetMC: 15.0,
|
||||
colour: "#424242",
|
||||
weightConversionKg: 0,
|
||||
bushelsPerTonne: 0
|
||||
bushelsPerTonne: 0,
|
||||
bushelsPerTon: 0
|
||||
};
|
||||
|
||||
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,
|
||||
colour: "yellow",
|
||||
weightConversionKg: 0,
|
||||
bushelsPerTonne: 0
|
||||
bushelsPerTonne: 0,
|
||||
bushelsPerTon: 0
|
||||
}
|
||||
],
|
||||
[
|
||||
|
|
@ -81,7 +84,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
|||
img: BarleyImg,
|
||||
colour: "#27632a",
|
||||
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,
|
||||
colour: "#46b298",
|
||||
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: "#ffff00",
|
||||
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,
|
||||
colour: "#cddc39",
|
||||
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,
|
||||
colour: "#ffef62",
|
||||
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,
|
||||
colour: "#ffef62",
|
||||
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,
|
||||
colour: "#ffef62",
|
||||
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,
|
||||
colour: "#ffef62",
|
||||
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,
|
||||
colour: "#ffef62",
|
||||
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,
|
||||
colour: "#79955a",
|
||||
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,
|
||||
colour: "#79955a",
|
||||
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,
|
||||
colour: "#79955a",
|
||||
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,
|
||||
colour: "#b2a058",
|
||||
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,
|
||||
colour: "#7c9c99",
|
||||
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,
|
||||
colour: "#7c9c99",
|
||||
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,
|
||||
colour: "#7c9c99",
|
||||
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,
|
||||
colour: "#829baf",
|
||||
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,
|
||||
colour: "#7d6d99",
|
||||
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,
|
||||
colour: "#ffab40",
|
||||
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,
|
||||
colour: "#46b298",
|
||||
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,
|
||||
colour: "#46b298",
|
||||
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,
|
||||
colour: "#46b298",
|
||||
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,
|
||||
colour: "#6e6d19",
|
||||
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,
|
||||
colour: "#6e6d19",
|
||||
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,
|
||||
colour: "#ffe100",
|
||||
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,
|
||||
colour: "#cb5e3c",
|
||||
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,
|
||||
colour: "#cb5e3c",
|
||||
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,
|
||||
colour: "#cb5e3c",
|
||||
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,
|
||||
colour: "red",
|
||||
weightConversionKg: 27.2155,
|
||||
bushelsPerTonne: 36.744
|
||||
bushelsPerTonne: 36.744,
|
||||
bushelsPerTon: 33.33
|
||||
}
|
||||
],[
|
||||
pond.Grain.GRAIN_DRY_BEANS_BLACK,
|
||||
|
|
@ -572,7 +604,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
|||
targetMC: 15.0,
|
||||
colour: "grey",
|
||||
weightConversionKg: 27.2155,
|
||||
bushelsPerTonne: 36.744
|
||||
bushelsPerTonne: 36.744,
|
||||
bushelsPerTon: 33.33
|
||||
}
|
||||
],[
|
||||
pond.Grain.GRAIN_RYE_A,
|
||||
|
|
@ -587,7 +620,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
|||
targetMC: 15.0,
|
||||
colour: "grey",
|
||||
weightConversionKg: 25.4,
|
||||
bushelsPerTonne: 39.368
|
||||
bushelsPerTonne: 39.368,
|
||||
bushelsPerTon: 35.71
|
||||
}
|
||||
],[
|
||||
pond.Grain.GRAIN_RYE_B,
|
||||
|
|
@ -602,7 +636,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
|||
targetMC: 15.0,
|
||||
colour: "grey",
|
||||
weightConversionKg: 25.4,
|
||||
bushelsPerTonne: 39.368
|
||||
bushelsPerTonne: 39.368,
|
||||
bushelsPerTon: 35.71
|
||||
},
|
||||
],[
|
||||
pond.Grain.GRAIN_RYE_C,
|
||||
|
|
@ -617,7 +652,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
|||
targetMC: 15.0,
|
||||
colour: "grey",
|
||||
weightConversionKg: 25.4,
|
||||
bushelsPerTonne: 39.368
|
||||
bushelsPerTonne: 39.368,
|
||||
bushelsPerTon: 35.71
|
||||
},
|
||||
],[
|
||||
pond.Grain.GRAIN_RYE_D,
|
||||
|
|
@ -632,7 +668,8 @@ export const GrainExtensions: Map<pond.Grain, GrainExtension> = new Map([
|
|||
targetMC: 15.0,
|
||||
colour: "grey",
|
||||
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) => {
|
||||
let dest = selectedDestination;
|
||||
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
|
||||
if (source) {
|
||||
bpt = source.value.bushelsPerTonne();
|
||||
bPerTonne = source.value.bushelsPerTonne();
|
||||
} else if (dest) {
|
||||
bpt = dest.value.bushelsPerTonne();
|
||||
bPerTonne = dest.value.bushelsPerTonne();
|
||||
}
|
||||
|
||||
let newTransaction = pond.Transaction.create({
|
||||
|
|
@ -239,7 +240,7 @@ export default function GrainTransaction(props: Props) {
|
|||
grainTransaction: pond.GrainTransaction.create({
|
||||
bushels: finalVal,
|
||||
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 (
|
||||
<ResponsiveDialog
|
||||
open={open}
|
||||
|
|
@ -506,14 +518,14 @@ export default function GrainTransaction(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT ? "mT" : "bu"}
|
||||
{grainUnitDisplay()}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
onChange={e => {
|
||||
//if the user is viewing the grain in weight
|
||||
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)
|
||||
//use source of the conversion value if it was selected, otherwise use the destination
|
||||
if (!isNaN(parseFloat(e.target.value))) {
|
||||
|
|
@ -523,6 +535,18 @@ export default function GrainTransaction(props: Props) {
|
|||
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);
|
||||
setGrainChangeVal(grainVal);
|
||||
|
|
|
|||
|
|
@ -36,11 +36,14 @@ export default function GrainBagInventoryGraph(props: Props) {
|
|||
//let time = hist.timestamp;
|
||||
let val = hist.object.grainBagSettings.currentBushels ?? 0;
|
||||
if (
|
||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT &&
|
||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
||||
grainBag.bushelsPerTonne() > 1
|
||||
) {
|
||||
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) {
|
||||
lastBushels = val;
|
||||
barData.push({
|
||||
|
|
@ -51,13 +54,16 @@ export default function GrainBagInventoryGraph(props: Props) {
|
|||
}
|
||||
});
|
||||
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({
|
||||
timestamp: moment.now().valueOf(),
|
||||
value:
|
||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT &&
|
||||
grainBag.bushelsPerTonne() > 1
|
||||
? Math.round((grainBag.bushels() / grainBag.bushelsPerTonne()) * 100) / 100
|
||||
: grainBag.bushels()
|
||||
value: Math.round(val*100)/100
|
||||
});
|
||||
}
|
||||
setData(barData);
|
||||
|
|
@ -71,6 +77,17 @@ export default function GrainBagInventoryGraph(props: Props) {
|
|||
}
|
||||
}, [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 (
|
||||
<Card raised>
|
||||
<Box padding={2}>
|
||||
|
|
@ -87,11 +104,7 @@ export default function GrainBagInventoryGraph(props: Props) {
|
|||
}
|
||||
data={data}
|
||||
yMin={0}
|
||||
yMax={
|
||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT
|
||||
? grainBag.capacity() / grainBag.bushelsPerTonne()
|
||||
: grainBag.capacity()
|
||||
}
|
||||
yMax={maxYAxis()}
|
||||
customHeight={customHeight}
|
||||
useGradient
|
||||
labels
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export default function GrainBagSettings(props: Props) {
|
|||
const theme = useTheme();
|
||||
const [grainUpdate, setGrainUpdate] = useState(false);
|
||||
const [grainDiff, setGrainDiff] = useState(0);
|
||||
const [bushelsPerTonne, setBushelsPerTonne] = useState(0);
|
||||
const [bushelConversion, setBushelConversion] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (grainBag) {
|
||||
|
|
@ -84,8 +84,10 @@ export default function GrainBagSettings(props: Props) {
|
|||
: grainBag.settings.length
|
||||
);
|
||||
let grainVal = grainBag.bushels();
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT) {
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE) {
|
||||
grainVal = grainBag.bushels() / grainBag.bushelsPerTonne();
|
||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) {
|
||||
grainVal = grainBag.bushels() / (grainBag.bushelsPerTonne() * 0.907)
|
||||
}
|
||||
setGrainFill(grainVal.toFixed(2));
|
||||
setBagName(grainBag.name());
|
||||
|
|
@ -117,6 +119,10 @@ export default function GrainBagSettings(props: Props) {
|
|||
|
||||
const submit = () => {
|
||||
//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) {
|
||||
grainBag.title = bagName;
|
||||
grainBag.settings.initialMoisture = initialMoisture;
|
||||
|
|
@ -127,7 +133,7 @@ export default function GrainBagSettings(props: Props) {
|
|||
grainBag.settings.bushelCapacity = grainCapacity;
|
||||
grainBag.settings.grainSubtype = grainSubtype;
|
||||
grainBag.settings.fillDate = fillDate;
|
||||
grainBag.settings.bushelsPerTonne = bushelsPerTonne;
|
||||
grainBag.settings.bushelsPerTonne = tonneConversion;
|
||||
grainBag.settings.storageType = isCustom
|
||||
? pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN
|
||||
: pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN;
|
||||
|
|
@ -161,6 +167,7 @@ export default function GrainBagSettings(props: Props) {
|
|||
settings.currentBushels = grainBushels;
|
||||
settings.grainSubtype = grainSubtype;
|
||||
settings.fillDate = fillDate;
|
||||
settings.bushelsPerTonne = tonneConversion;
|
||||
settings.storageType = isCustom
|
||||
? pond.BinStorage.BIN_STORAGE_UNSUPPORTED_GRAIN
|
||||
: pond.BinStorage.BIN_STORAGE_SUPPORTED_GRAIN;
|
||||
|
|
@ -205,10 +212,10 @@ export default function GrainBagSettings(props: Props) {
|
|||
/>
|
||||
<TextField
|
||||
label="Bushels Per Tonne"
|
||||
value={bushelsPerTonne}
|
||||
value={bushelConversion}
|
||||
type="number"
|
||||
onChange={event => {
|
||||
setBushelsPerTonne(+event.target.value);
|
||||
setBushelConversion(+event.target.value);
|
||||
}}
|
||||
fullWidth
|
||||
className={classes.bottomSpacing}
|
||||
|
|
@ -227,7 +234,7 @@ export default function GrainBagSettings(props: Props) {
|
|||
? pond.Grain[option.value as keyof typeof pond.Grain]
|
||||
: pond.Grain.GRAIN_INVALID;
|
||||
setSupportedGrainType(newGrainType);
|
||||
setBushelsPerTonne(GrainDescriber(newGrainType).bushelsPerTonne);
|
||||
setBushelConversion(GrainDescriber(newGrainType).bushelsPerTonne);
|
||||
setSelectedGrainOp(option);
|
||||
}}
|
||||
group
|
||||
|
|
@ -246,6 +253,18 @@ export default function GrainBagSettings(props: Props) {
|
|||
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 (
|
||||
<React.Fragment>
|
||||
<GrainTransaction
|
||||
|
|
@ -389,30 +408,24 @@ export default function GrainBagSettings(props: Props) {
|
|||
className={classes.bottomSpacing}
|
||||
/>
|
||||
<TextField
|
||||
label={
|
||||
"Current " +
|
||||
(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bushelsPerTonne > 0
|
||||
? "Weight"
|
||||
: "Bushels")
|
||||
}
|
||||
label={"Current Inventory"}
|
||||
fullWidth
|
||||
type="number"
|
||||
variant="outlined"
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && bushelsPerTonne > 0
|
||||
? "mT"
|
||||
: "bu"}
|
||||
{grainUnitDisplay()}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
value={grainFill}
|
||||
onChange={e => {
|
||||
let bushelVal = +e.target.value;
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT) {
|
||||
//convert the number as a weight into the bushel value
|
||||
bushelVal = +e.target.value * (bushelsPerTonne > 0 ? bushelsPerTonne : 1);
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE || getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) {
|
||||
//convert the number as a weight into the bushel value, no changing or conversions necessary
|
||||
// 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) {
|
||||
bushelVal = grainCapacity;
|
||||
|
|
|
|||
|
|
@ -83,12 +83,19 @@ export default function GrainBagVisualizer(props: Props) {
|
|||
const grainOverlay = () => {
|
||||
let displayPending = pendingGrainAmount;
|
||||
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) {
|
||||
displayPending = Math.round((displayPending / 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 (
|
||||
<Box>
|
||||
{grainDiff !== undefined && grainDiff > 0 && (
|
||||
|
|
@ -141,7 +148,7 @@ export default function GrainBagVisualizer(props: Props) {
|
|||
};
|
||||
|
||||
const grainAmountDisplay = () => {
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && grainBag.bushelsPerTonne() > 1) {
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1) {
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<Typography variant="body2" style={{ fontWeight: "bold", marginRight: "4px" }}>
|
||||
|
|
@ -150,6 +157,15 @@ export default function GrainBagVisualizer(props: Props) {
|
|||
<Typography variant="body2">({grainBag.fillPercent()}%)</Typography>
|
||||
</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 {
|
||||
return (
|
||||
<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 { MarkerData } from "maps/mapMarkers/Markers";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { getGrainUnit } from "utils";
|
||||
import { stringToMaterialColour } from "utils/strings";
|
||||
import { or } from "utils/types";
|
||||
|
||||
|
|
@ -235,17 +236,14 @@ export class Bin {
|
|||
return bpt;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the weight in tonnes for the grain inventory provided the bushels per tonne is set
|
||||
* if it is not set it will divide by 1 effectively returning the bushels
|
||||
* @returns grain weight
|
||||
*/
|
||||
public grainTonnes(): number {
|
||||
let weight = 0;
|
||||
if (this.settings.inventory) {
|
||||
weight = this.settings.inventory.grainBushels / this.bushelsPerTonne();
|
||||
public grainInventory(): number {
|
||||
let grain = this.bushels()
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.bushelsPerTonne() > 1){
|
||||
grain = this.bushels() / this.bushelsPerTonne()
|
||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.bushelsPerTonne() > 1){
|
||||
grain = this.bushels() / (this.bushelsPerTonne() * 0.907)
|
||||
}
|
||||
return Math.round(weight * 100) / 100;
|
||||
return Math.round(grain*100)/100
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,7 +29,13 @@ export class Contract {
|
|||
|
||||
private measurementUnit(): string {
|
||||
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 "";
|
||||
}
|
||||
|
|
@ -202,9 +208,12 @@ export class Contract {
|
|||
let size = this.settings.size;
|
||||
switch (this.settings.type) {
|
||||
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();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
@ -213,26 +222,33 @@ export class Contract {
|
|||
let del = this.settings.delivered;
|
||||
switch (this.settings.type) {
|
||||
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();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static toStoredUnit(
|
||||
secondaryUnitVal: number,
|
||||
contractType: pond.ContractType,
|
||||
conversionValue: number
|
||||
): number {
|
||||
let storedunitVal = secondaryUnitVal;
|
||||
let storedUnitVal = secondaryUnitVal;
|
||||
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:
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && conversionValue > 1) {
|
||||
storedunitVal = secondaryUnitVal * conversionValue;
|
||||
if ((getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE || getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) && conversionValue > 1) {
|
||||
storedUnitVal = secondaryUnitVal * conversionValue;
|
||||
}
|
||||
}
|
||||
return storedunitVal;
|
||||
return storedUnitVal;
|
||||
}
|
||||
|
||||
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 hasInventory = binMetrics && binMetrics.grainInventory.length > 0;
|
||||
const useWeight = getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT;
|
||||
return (
|
||||
<Accordion
|
||||
className={classes.accordion}
|
||||
|
|
@ -972,17 +1010,9 @@ export default function Bins(props: Props) {
|
|||
<ImageListItem key={key}>
|
||||
<BinUtilizationChart
|
||||
grain={inv.grainType}
|
||||
customUnit={useWeight ? " mT" : " bu"}
|
||||
bushelAmount={
|
||||
useWeight
|
||||
? inv.bushelAmount / GrainDescriber(inv.grainType).bushelsPerTonne
|
||||
: inv.bushelAmount
|
||||
}
|
||||
bushelCapacity={
|
||||
useWeight
|
||||
? inv.bushelCapacity / GrainDescriber(inv.grainType).bushelsPerTonne
|
||||
: inv.bushelCapacity
|
||||
}
|
||||
customUnit={grainUnitDisplay()}
|
||||
bushelAmount={supportedGrainDisplay(inv.grainType, inv.bushelAmount)}
|
||||
bushelCapacity={supportedGrainDisplay(inv.grainType, inv.bushelCapacity)}
|
||||
onClick={() => {
|
||||
setContentFilter(pond.Grain[inv.grainType]);
|
||||
loadMoreBins(pond.Grain[inv.grainType]);
|
||||
|
|
@ -1001,11 +1031,10 @@ export default function Bins(props: Props) {
|
|||
amount = amount * 35.239;
|
||||
cap = cap * 35.239;
|
||||
unit = " L";
|
||||
}
|
||||
if (useWeight && inv.bushelsPerTonne > 1) {
|
||||
amount = amount / inv.bushelsPerTonne;
|
||||
cap = cap / inv.bushelsPerTonne;
|
||||
unit = " mT";
|
||||
} else {
|
||||
amount = customQuantityDisplay(inv, amount)
|
||||
cap = customQuantityDisplay(inv, cap)
|
||||
unit = grainUnitDisplay(inv);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { useDeviceAPI, useGlobalState, useSnackbar } from "providers";
|
|||
import { useEffect, useState } from "react";
|
||||
import { useLocation, useParams } from "react-router-dom";
|
||||
import PageContainer from "./PageContainer";
|
||||
import { useMobile } from "hooks";
|
||||
import { useHTTP, useMobile } from "hooks";
|
||||
import LoadingScreen from "app/LoadingScreen";
|
||||
import SmartBreadcrumb from "common/SmartBreadcrumb";
|
||||
import DeviceActions from "device/DeviceActions";
|
||||
|
|
@ -21,6 +21,7 @@ import { or } from "utils";
|
|||
import ComponentDiagnostics from "component/ComponentDiagnostics";
|
||||
import DeviceWizard from "device/DeviceWizard";
|
||||
import DeviceScannedComponents from "device/autoDetect/DeviceScannedComponents";
|
||||
import { useWebSocket } from "hooks/useWebSocket";
|
||||
|
||||
export interface DevicePageData {
|
||||
device: Device;
|
||||
|
|
@ -65,6 +66,8 @@ export default function DevicePage() {
|
|||
|
||||
// const [devicePageData, setDevicePageData] = useState(pond.GetDevicePageDataResponse.create())
|
||||
|
||||
const { token } = useHTTP();
|
||||
|
||||
const loadDevice = () => {
|
||||
if (loading) return
|
||||
if (state?.devicePageData) {
|
||||
|
|
@ -165,6 +168,65 @@ export default function DevicePage() {
|
|||
.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 = () => {
|
||||
deviceAPI.listFoundComponents(parseInt(deviceID))
|
||||
.then(resp => {
|
||||
|
|
|
|||
|
|
@ -168,7 +168,8 @@ export default function SignupCallback () {
|
|||
variant="outlined"
|
||||
InputLabelProps={{ shrink: true }}>
|
||||
<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>
|
||||
</Grid2>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ export default function GrainBag(props: Props) {
|
|||
}
|
||||
console.log
|
||||
userAPI.getUser(user.id(), { key: key, kind: kind } as Scope).then(resp => {
|
||||
console.log(resp)
|
||||
setPermissions(resp.permissions);
|
||||
});
|
||||
}, [as, bagID, userAPI, user]);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ interface IHTTPContext {
|
|||
) => Promise<AxiosResponse<T>>;
|
||||
del: <T>(url: string, spreadOptions?: AxiosRequestConfig) => Promise<AxiosResponse<T>>;
|
||||
options: (demo?: boolean) => AxiosRequestConfig;
|
||||
token: string;
|
||||
}
|
||||
|
||||
interface Props extends PropsWithChildren<any>{
|
||||
|
|
@ -104,7 +105,8 @@ export default function HTTPProvider(props: Props) {
|
|||
put,
|
||||
post,
|
||||
del,
|
||||
options: defaultOptions
|
||||
options: defaultOptions,
|
||||
token
|
||||
}}>
|
||||
{/* <BillingProvider> */}
|
||||
<PondProvider>
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ export default function GrainBagProvider(props: PropsWithChildren<Props>) {
|
|||
(end && "&end=" + end)
|
||||
)
|
||||
if (view) {
|
||||
url = url + "?as=" + view
|
||||
url = url + "&as=" + view
|
||||
}
|
||||
return get<pond.ListGrainBagHistoryResponse>(url);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -336,9 +336,9 @@ export function getWhitelabel(): WhiteLabel {
|
|||
if (window.location.origin.includes("bxt-dev")) {
|
||||
return BXT_WHITE_LABEL;
|
||||
}
|
||||
// if (window.location.origin.includes("localhost")) {
|
||||
// return STAGING_WHITELABEL;
|
||||
// }
|
||||
if (window.location.origin.includes("localhost")) {
|
||||
return STREAMLINE_WHITE_LABEL;
|
||||
}
|
||||
if (window.location.origin.includes("staging") || import.meta.env.VITE_LOCAL_STAGING=='true') {
|
||||
return STAGING_WHITELABEL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,17 @@ interface Props {
|
|||
|
||||
export default function TransactionDataDisplay(props: 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 = () => {
|
||||
let transactionData = transaction.transaction.transaction;
|
||||
|
|
@ -27,9 +38,7 @@ export default function TransactionDataDisplay(props: Props) {
|
|||
</Typography>
|
||||
<Typography>Variant: {gt.subtype}</Typography>
|
||||
<Typography>
|
||||
{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_WEIGHT && gt.bushelsPerTonne > 1
|
||||
? "Weight: " + gt.bushels / gt.bushelsPerTonne + " mT"
|
||||
: "Bushels: " + gt.bushels}
|
||||
{grainDisplay(gt)}
|
||||
</Typography>
|
||||
<Typography>Message: {gt.message}</Typography>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -455,8 +455,11 @@ export default function UserSettings(props: Props) {
|
|||
case 1:
|
||||
grainUnit = pond.GrainUnit.GRAIN_UNIT_BUSHELS;
|
||||
break;
|
||||
case 2:
|
||||
grainUnit = pond.GrainUnit.GRAIN_UNIT_WEIGHT;
|
||||
case 3:
|
||||
grainUnit = pond.GrainUnit.GRAIN_UNIT_TONNE;
|
||||
break;
|
||||
case 4:
|
||||
grainUnit = pond.GrainUnit.GRAIN_UNIT_TON;
|
||||
break;
|
||||
default:
|
||||
grainUnit = pond.GrainUnit.GRAIN_UNIT_UNKNOWN;
|
||||
|
|
@ -540,7 +543,8 @@ export default function UserSettings(props: Props) {
|
|||
variant="outlined"
|
||||
InputLabelProps={{ shrink: true }}>
|
||||
<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>
|
||||
</Grid2>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -55,13 +55,33 @@ export function setDistanceUnit(unit: pond.DistanceUnit) {
|
|||
}
|
||||
|
||||
export function getGrainUnit(): pond.GrainUnit {
|
||||
return localStorage.getItem("grainUnit") === "mT"
|
||||
? pond.GrainUnit.GRAIN_UNIT_WEIGHT
|
||||
: pond.GrainUnit.GRAIN_UNIT_BUSHELS;
|
||||
switch(localStorage.getItem("grainUnit")){
|
||||
case "mT":
|
||||
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) {
|
||||
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) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue