Merge branch 'analog_pressure_component' into dev_environment
1
.env
|
|
@ -14,6 +14,7 @@ VITE_AUTH0_ADAPTIVE_CONSTRUCTION_CLIENT_ID=32rABabJzXRvJiWivTmeKFgwFiqh4ok7
|
||||||
VITE_AUTH0_AEROGROW_CLIENT_ID=KHl9ooUt1nia1RYw5n224dyggCXdbsSd
|
VITE_AUTH0_AEROGROW_CLIENT_ID=KHl9ooUt1nia1RYw5n224dyggCXdbsSd
|
||||||
VITE_AUTH0_MIVENT_CLIENT_ID=VNALE7RW6l3dY5uYcxgwElZV0lcT25Fg
|
VITE_AUTH0_MIVENT_CLIENT_ID=VNALE7RW6l3dY5uYcxgwElZV0lcT25Fg
|
||||||
VITE_AUTH0_OMNIAIR_CLIENT_ID=IblmarD8wFafiD6doxTmOHQ6Bx3L9wWl
|
VITE_AUTH0_OMNIAIR_CLIENT_ID=IblmarD8wFafiD6doxTmOHQ6Bx3L9wWl
|
||||||
|
VITE_AUTH0_INTELLIFARMS_CLIENT_ID=RYtuAyOcB4DSaaqJMLDMf3pV8SFY9PdY
|
||||||
|
|
||||||
#Branding (Default theme)
|
#Branding (Default theme)
|
||||||
VITE_APP_WEBSITE_TITLE="Adaptive Dashboard"
|
VITE_APP_WEBSITE_TITLE="Adaptive Dashboard"
|
||||||
|
|
|
||||||
29
README.md
|
|
@ -18,31 +18,36 @@ Steps to add a new white label
|
||||||
- add a `CNAME` record pointing their custom subdomain (ex: dashboard.example.com) to brandxtech.ca
|
- add a `CNAME` record pointing their custom subdomain (ex: dashboard.example.com) to brandxtech.ca
|
||||||
- add a login button on their website point to `/login` of their custom subdomain (ex: dashboard.example.com/login)
|
- add a login button on their website point to `/login` of their custom subdomain (ex: dashboard.example.com/login)
|
||||||
|
|
||||||
|
It is recommended to start with the Auth0 stage once everything from the client has been recieved as things like the client ID will be needed in other stages
|
||||||
|
|
||||||
<!-- frontend steps -->
|
<!-- frontend steps -->
|
||||||
2. Create a PWA folder in `public` that is named after the client and generate PWA assets using [this](https://realfavicongenerator.net/) website (use the company logo but you might need to use a custom favicon depending on the result)
|
Frontend Steps
|
||||||
|
1. Create a PWA folder in `public` that is named after the client and generate PWA assets using [this](https://realfavicongenerator.net/) website (use the company logo but you might need to use a custom favicon depending on the result)
|
||||||
|
|
||||||
- https://maskable.app/ also create a maskable icon for PWA
|
- https://maskable.app/ also create a maskable icon for PWA
|
||||||
- create a 512x512 png as well for PWA
|
- create a 512x512 png as well for PWA
|
||||||
|
|
||||||
3. Create a white-label branding folder in `src/assets/whitelabels` and create a `darkLogo.png` and `lightLogo.png` from the client's logo
|
2. Create a white-label branding folder in `src/assets/whitelabels` and create a `darkLogo.png` and `lightLogo.png` from the client's logo
|
||||||
4. In `src/services/whiteLabel.ts`, add a new `Whitelabel` instance with the required fields and add its hostname mapping to the `whitelabels` map (it is very similar to step one but had some constraints when dealing with the `public` folder)
|
3. In `src/services/whiteLabel.ts`, add a new `Whitelabel` instance with the required fields and add its hostname mapping to the `whitelabels` map
|
||||||
5. If there are any pages specific to the whitelabel be sure to update the side and bottom navigator
|
4. If there are any pages specific to the whitelabel be sure to update the side and bottom navigator
|
||||||
|
|
||||||
<!-- backend steps -->
|
<!-- backend steps -->
|
||||||
6. In `dynamic-config.prod.yml`, add a router entry for the new whitelabel
|
Backend Steps
|
||||||
7. In `pond/http/server.go`, add the sub-domain to the `allowedOrigins`
|
1. In `dynamic-config.prod.yml`, add a router entry for the new whitelabel
|
||||||
8. In `pond/whitelabel.go`, add an entry for the new white label
|
2. In `pond/http/server.go`, add the sub-domain to the `allowedOrigins`
|
||||||
|
3. In `pond/whitelabel.go`, add an entry for the new white label
|
||||||
|
|
||||||
7. Create a new `Auth0` application for the client
|
<!-- Auth steps -->
|
||||||
|
Auth0 Steps
|
||||||
|
1. Create a new Single Page App on Auth0 using React as the tech
|
||||||
|
2. Once you have the client ID add it to your .env file in the frontend
|
||||||
|
3. Adjust settings accordingly in the new application
|
||||||
- use a image bucket like [postimg](https://postimages.org/) to store their company logo and favicon
|
- use a image bucket like [postimg](https://postimages.org/) to store their company logo and favicon
|
||||||
- add a whitelabel logo
|
- add a whitelabel logo
|
||||||
- allow necessary `origins`, `callback URLs`, and `CORS domains` to the application settings (see the default application as a guideline)
|
- allow necessary `origins`, `callback URLs`, and `CORS domains` to the application settings (see other applications/whitelabels as a guideline)
|
||||||
- customize the Universal Login page to handle the new whitelabel
|
- customize the Universal Login page to handle the new whitelabel
|
||||||
- check if the client ID matches this client's Auth0 application
|
- check if the client ID matches this client's Auth0 application
|
||||||
- change the Universal Login theme using white-label colours and images stored in a bucket (ex: [postimg](https://postimages.org/))
|
- change the Universal Login theme using white-label colours and images stored in a bucket (ex: [postimg](https://postimages.org/))
|
||||||
8. Enable the white-label sub-domain for CORS in the backend
|
|
||||||
|
|
||||||
- in [http.go](https://gitlab.com/brandx/backend/blob/master/pond/http.go), add the white-label sub-domain to the `AllowedOrigins` list
|
|
||||||
|
|
||||||
## Expanding the ESLint configuration
|
## Expanding the ESLint configuration
|
||||||
|
|
||||||
|
|
|
||||||
4
package-lock.json
generated
|
|
@ -43,7 +43,7 @@
|
||||||
"mui-tel-input": "^7.0.0",
|
"mui-tel-input": "^7.0.0",
|
||||||
"notistack": "^3.0.1",
|
"notistack": "^3.0.1",
|
||||||
"openweathermap-ts": "^1.2.10",
|
"openweathermap-ts": "^1.2.10",
|
||||||
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging",
|
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#dev",
|
||||||
"query-string": "^9.2.1",
|
"query-string": "^9.2.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-beautiful-dnd": "^13.1.1",
|
"react-beautiful-dnd": "^13.1.1",
|
||||||
|
|
@ -11205,7 +11205,7 @@
|
||||||
},
|
},
|
||||||
"node_modules/protobuf-ts": {
|
"node_modules/protobuf-ts": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#9c0f668d4a56b8216dd71a44c3110a818aaf3541",
|
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#b44f5fa7183d9565e9fd9e7a9ac756114401ddfd",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"protobufjs": "^6.8.8"
|
"protobufjs": "^6.8.8"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
public/Intellifarms/IFND-2023-Logo-White.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
public/Intellifarms/IFND-2023-Logo.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
public/Intellifarms/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/Intellifarms/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
public/Intellifarms/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
9
public/Intellifarms/browserconfig.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<browserconfig>
|
||||||
|
<msapplication>
|
||||||
|
<tile>
|
||||||
|
<square150x150logo src="/mstile-150x150.png"/>
|
||||||
|
<TileColor>#ffffff</TileColor>
|
||||||
|
</tile>
|
||||||
|
</msapplication>
|
||||||
|
</browserconfig>
|
||||||
BIN
public/Intellifarms/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 712 B |
BIN
public/Intellifarms/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
public/Intellifarms/favicon-48x48.png
Normal file
|
After Width: | Height: | Size: 3 KiB |
BIN
public/Intellifarms/favicon.ico
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
19
public/Intellifarms/manifest.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "Intellifarms",
|
||||||
|
"short_name": "Intellifarms",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/android-chrome-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/android-chrome-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"theme_color": "#ffffff",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"display": "standalone"
|
||||||
|
}
|
||||||
BIN
public/Intellifarms/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
3
public/Intellifarms/safari-pinned-tab.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
|
<image href="Intellifarms_Icon.png" height="512" width="512"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 134 B |
BIN
src/assets/whitelabels/Intellifarms/IFND-2023-Logo-White.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
src/assets/whitelabels/Intellifarms/IFND-2023-Logo.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
|
|
@ -57,6 +57,8 @@ interface Props {
|
||||||
components?: Map<string, Component>;
|
components?: Map<string, Component>;
|
||||||
setComponents?: React.Dispatch<React.SetStateAction<Map<string, Component>>>;
|
setComponents?: React.Dispatch<React.SetStateAction<Map<string, Component>>>;
|
||||||
updateBinStatus?: (componentKeys: string[], removed?: boolean) => void;
|
updateBinStatus?: (componentKeys: string[], removed?: boolean) => void;
|
||||||
|
componentDevices?: Map<string, number>
|
||||||
|
setComponentDevices?: React.Dispatch<React.SetStateAction<Map<string, number>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OpenState {
|
interface OpenState {
|
||||||
|
|
@ -77,7 +79,9 @@ export default function BinActions(props: Props) {
|
||||||
refreshCallback,
|
refreshCallback,
|
||||||
userID,
|
userID,
|
||||||
components,
|
components,
|
||||||
|
componentDevices,
|
||||||
setComponents,
|
setComponents,
|
||||||
|
setComponentDevices,
|
||||||
updateBinStatus
|
updateBinStatus
|
||||||
} = props;
|
} = props;
|
||||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
|
||||||
|
|
@ -245,7 +249,9 @@ export default function BinActions(props: Props) {
|
||||||
open={openState.sensors}
|
open={openState.sensors}
|
||||||
userID={userID}
|
userID={userID}
|
||||||
components={components}
|
components={components}
|
||||||
|
componentDevices={componentDevices}
|
||||||
setComponents={setComponents}
|
setComponents={setComponents}
|
||||||
|
setComponentDevices={setComponentDevices}
|
||||||
updateBinStatus={updateBinStatus}
|
updateBinStatus={updateBinStatus}
|
||||||
onClose={refresh => {
|
onClose={refresh => {
|
||||||
if (refresh === true) {
|
if (refresh === true) {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import moment from "moment";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useGlobalState } from "providers";
|
import { useGlobalState } from "providers";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { celsiusToFahrenheit, getGrainUnit, or } from "utils";
|
import { celsiusToFahrenheit, or } from "utils";
|
||||||
//import { useHistory } from "react-router";
|
//import { useHistory } from "react-router";
|
||||||
//import BinModeDot from "./BinModeDot";
|
//import BinModeDot from "./BinModeDot";
|
||||||
import BinSVGV2 from "./BinSVGV2";
|
import BinSVGV2 from "./BinSVGV2";
|
||||||
|
|
@ -444,16 +444,16 @@ export default function BinCard(props: Props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
||||||
return (
|
return (
|
||||||
bin.grainInventory().toLocaleString() +
|
bin.grainInventory(user).toLocaleString() +
|
||||||
" mT " +
|
" mT " +
|
||||||
bin.fillPercent() +
|
bin.fillPercent() +
|
||||||
"%"
|
"%"
|
||||||
);
|
);
|
||||||
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
} else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||||
return (
|
return (
|
||||||
bin.grainInventory().toLocaleString() +
|
bin.grainInventory(user).toLocaleString() +
|
||||||
" t " +
|
" t " +
|
||||||
bin.fillPercent() +
|
bin.fillPercent() +
|
||||||
"%"
|
"%"
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,9 @@ const useStyles = makeStyles((theme: Theme) => {
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
components?: Map<string, Component>;
|
components?: Map<string, Component>;
|
||||||
|
componentDevices?: Map<string, number>;
|
||||||
setComponents?: React.Dispatch<React.SetStateAction<Map<string, Component>>>;
|
setComponents?: React.Dispatch<React.SetStateAction<Map<string, Component>>>;
|
||||||
|
setComponentDevices?: React.Dispatch<React.SetStateAction<Map<string, number>>>;
|
||||||
bin: string;
|
bin: string;
|
||||||
binGrain: pond.Grain;
|
binGrain: pond.Grain;
|
||||||
updateBinStatus?: (componentKeys: string[], removed?: boolean) => void;
|
updateBinStatus?: (componentKeys: string[], removed?: boolean) => void;
|
||||||
|
|
@ -84,7 +86,7 @@ interface Option {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function BinComponents(props: Props) {
|
export default function BinComponents(props: Props) {
|
||||||
const { components, bin, setComponents, updateBinStatus, binGrain } = props;
|
const { components, componentDevices, bin, setComponents, setComponentDevices, updateBinStatus, binGrain } = props;
|
||||||
const [{as}] = useGlobalState();
|
const [{as}] = useGlobalState();
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const binAPI = useBinAPI();
|
const binAPI = useBinAPI();
|
||||||
|
|
@ -208,20 +210,54 @@ export default function BinComponents(props: Props) {
|
||||||
// }
|
// }
|
||||||
// }, [selectedDevice, componentAPI, deviceComponents, snackbar]);
|
// }, [selectedDevice, componentAPI, deviceComponents, snackbar]);
|
||||||
|
|
||||||
const removeComponent = (component: string) => {
|
const removeComponent = (component: string, device?: number) => {
|
||||||
binAPI.removeComponent(bin, component, as).then(() => {
|
console.log(device)
|
||||||
|
binAPI.removeComponent(bin, component, device, as).then(() => {
|
||||||
|
|
||||||
if (components && setComponents) {
|
if (components && setComponents) {
|
||||||
if (components.delete(component)) {
|
if (components.delete(component)) {
|
||||||
let newComponents = new Map(components);
|
let newComponents = new Map(components);
|
||||||
setComponents(newComponents);
|
setComponents(newComponents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(componentDevices && setComponentDevices) {
|
||||||
|
if (componentDevices.delete(component)) {
|
||||||
|
let newComponentDevices = new Map(componentDevices);
|
||||||
|
setComponentDevices(newComponentDevices);
|
||||||
|
}
|
||||||
|
}
|
||||||
snackbar.info("Component removed from bin");
|
snackbar.info("Component removed from bin");
|
||||||
});
|
});
|
||||||
setComponentToRemove(undefined);
|
setComponentToRemove(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeComponentConfirmation = () => {
|
const removeComponentConfirmation = (last?: boolean) => {
|
||||||
|
let lastComponent = false;
|
||||||
|
let devId: number | undefined;
|
||||||
|
if(last){
|
||||||
|
lastComponent = last
|
||||||
|
}else{
|
||||||
|
if (componentDevices && componentToRemove) {
|
||||||
|
const id = componentDevices.get(componentToRemove.key());
|
||||||
|
|
||||||
|
if (id !== undefined) {
|
||||||
|
devId = id
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
for (const val of componentDevices.values()) {
|
||||||
|
if (val === devId) {
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count > 1) {
|
||||||
|
break; // stop early once we know it's not the last
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastComponent = count === 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<ResponsiveDialog
|
<ResponsiveDialog
|
||||||
fullScreen={false}
|
fullScreen={false}
|
||||||
|
|
@ -229,19 +265,37 @@ export default function BinComponents(props: Props) {
|
||||||
onClose={() => setComponentToRemove(undefined)}>
|
onClose={() => setComponentToRemove(undefined)}>
|
||||||
<DialogTitle>Remove {componentToRemove?.name()}?</DialogTitle>
|
<DialogTitle>Remove {componentToRemove?.name()}?</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText>
|
{lastComponent ?
|
||||||
This will remove {componentToRemove?.name()} from this bin. If you don't have direct
|
<DialogContentText>
|
||||||
access to this component or the device it is attached to, you will not be able to add it
|
This component {componentToRemove?.name()} is the last component from its device. You can choose to remove only the component itself or the device along with it.
|
||||||
back.
|
Leaving the device may have unexpected results if the device will continue to be used and it is recommended to remove it if the device is being moved to a new bin.
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
|
:
|
||||||
|
<DialogContentText>
|
||||||
|
This will remove {componentToRemove?.name()} from this bin. If you don't have direct
|
||||||
|
access to this component or the device it is attached to, you will not be able to add it
|
||||||
|
back.
|
||||||
|
</DialogContentText>
|
||||||
|
}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={() => setComponentToRemove(undefined)} color="primary">
|
<Button onClick={() => setComponentToRemove(undefined)} color="primary">
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
|
{lastComponent
|
||||||
|
?
|
||||||
|
<React.Fragment>
|
||||||
|
<Button onClick={() => removeComponent(componentToRemove!.key())} color="primary">
|
||||||
|
Remove Component
|
||||||
|
</Button>
|
||||||
|
<Button onClick={() => removeComponent(componentToRemove!.key(), devId)} color="primary">
|
||||||
|
Remove Component And Device
|
||||||
|
</Button>
|
||||||
|
</React.Fragment> :
|
||||||
<Button onClick={() => removeComponent(componentToRemove!.key())} color="primary">
|
<Button onClick={() => removeComponent(componentToRemove!.key())} color="primary">
|
||||||
Remove
|
Remove
|
||||||
</Button>
|
</Button>
|
||||||
|
}
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</ResponsiveDialog>
|
</ResponsiveDialog>
|
||||||
);
|
);
|
||||||
|
|
@ -256,7 +310,7 @@ export default function BinComponents(props: Props) {
|
||||||
<DialogTitle>Remove All Components?</DialogTitle>
|
<DialogTitle>Remove All Components?</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText>
|
<DialogContentText>
|
||||||
This will remove All attached components from this bin. If you don't have direct access
|
This will remove All attached components and devices from this bin. If you don't have direct access
|
||||||
to these components or the devices they are attached to, you will not be able to add
|
to these components or the devices they are attached to, you will not be able to add
|
||||||
them back.
|
them back.
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
|
|
@ -320,6 +374,12 @@ export default function BinComponents(props: Props) {
|
||||||
setComponents(newComponents);
|
setComponents(newComponents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(componentDevices && setComponentDevices) {
|
||||||
|
if (componentDevices.set(component.key(), device)) {
|
||||||
|
let newComponentDevices = new Map(componentDevices);
|
||||||
|
setComponentDevices(newComponentDevices);
|
||||||
|
}
|
||||||
|
}
|
||||||
//if a grain cable was added to the bin update the components grain type to match the bin
|
//if a grain cable was added to the bin update the components grain type to match the bin
|
||||||
if (preferences.type === pond.BinComponent.BIN_COMPONENT_GRAIN_CABLE) {
|
if (preferences.type === pond.BinComponent.BIN_COMPONENT_GRAIN_CABLE) {
|
||||||
let settings = component.settings;
|
let settings = component.settings;
|
||||||
|
|
@ -338,15 +398,40 @@ export default function BinComponents(props: Props) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
binAPI.removeComponent(bin, component.key(), as).then(resp => {
|
let lastComponent = false;
|
||||||
if (components && setComponents) {
|
if (componentDevices) {
|
||||||
|
console.log(componentDevices)
|
||||||
|
let count = 0;
|
||||||
|
for (const val of componentDevices.values()) {
|
||||||
|
if (val === device) {
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (count > 1) {
|
||||||
|
break; // stop early once we know it's not the last
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastComponent = count === 1;
|
||||||
|
}
|
||||||
|
if(lastComponent){
|
||||||
|
setComponentToRemove(component)
|
||||||
|
}else{
|
||||||
|
binAPI.removeComponent(bin, component.key(), undefined, as).then(resp => {
|
||||||
|
if (components && setComponents) {
|
||||||
if (components.delete(component.key())) {
|
if (components.delete(component.key())) {
|
||||||
let newComponents = new Map(components);
|
let newComponents = new Map(components);
|
||||||
setComponents(newComponents);
|
setComponents(newComponents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(componentDevices && setComponentDevices) {
|
||||||
|
if (componentDevices.delete(component.key())) {
|
||||||
|
let newComponentDevices = new Map(componentDevices);
|
||||||
|
setComponentDevices(newComponentDevices);
|
||||||
|
}
|
||||||
|
}
|
||||||
snackbar.info("Component removed from bin");
|
snackbar.info("Component removed from bin");
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -567,7 +652,10 @@ export default function BinComponents(props: Props) {
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText inset={cIcon === undefined}>{component.name()}</ListItemText>
|
<ListItemText inset={cIcon === undefined}>{component.name()}</ListItemText>
|
||||||
<ListItemSecondaryAction>
|
<ListItemSecondaryAction>
|
||||||
<IconButton onClick={() => setComponentToRemove(component)}>
|
<IconButton onClick={() => {
|
||||||
|
setComponentToRemove(component)
|
||||||
|
|
||||||
|
}}>
|
||||||
<Remove />
|
<Remove />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</ListItemSecondaryAction>
|
</ListItemSecondaryAction>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
||||||
import { pond, quack } from "protobuf-ts/pond";
|
import { pond, quack } from "protobuf-ts/pond";
|
||||||
import { useGlobalState, useInteractionsAPI, useSnackbar } from "providers";
|
import { useGlobalState, useInteractionsAPI, useSnackbar } from "providers";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { avg, fahrenheitToCelsius, getTemperatureUnit } from "utils";
|
import { avg, fahrenheitToCelsius } from "utils";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import { Mark } from "@mui/material/Slider/useSlider.types";
|
import { Mark } from "@mui/material/Slider/useSlider.types";
|
||||||
|
|
||||||
|
|
@ -103,7 +103,7 @@ export default function BinConditioningInteraction(props: Props) {
|
||||||
let sliderVals: Map<quack.MeasurementType, number> = new Map();
|
let sliderVals: Map<quack.MeasurementType, number> = new Map();
|
||||||
let sliderMarks: Map<quack.MeasurementType, number> = new Map();
|
let sliderMarks: Map<quack.MeasurementType, number> = new Map();
|
||||||
passedInteraction.conditions().forEach(condition => {
|
passedInteraction.conditions().forEach(condition => {
|
||||||
let describer = describeMeasurement(condition.measurementType, source.type());
|
let describer = describeMeasurement(condition.measurementType, source.type(), undefined, undefined, user);
|
||||||
//NOTE: toDisplay will convert the temp value to fahrenheit
|
//NOTE: toDisplay will convert the temp value to fahrenheit
|
||||||
sliderVals.set(condition.measurementType, describer.toDisplay(condition.value));
|
sliderVals.set(condition.measurementType, describer.toDisplay(condition.value));
|
||||||
});
|
});
|
||||||
|
|
@ -131,7 +131,7 @@ export default function BinConditioningInteraction(props: Props) {
|
||||||
temp &&
|
temp &&
|
||||||
hum
|
hum
|
||||||
) {
|
) {
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
//the emc calc needs the temp to be in celsius
|
//the emc calc needs the temp to be in celsius
|
||||||
temp = fahrenheitToCelsius(temp);
|
temp = fahrenheitToCelsius(temp);
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +139,7 @@ export default function BinConditioningInteraction(props: Props) {
|
||||||
setBaseEMC(emc === hum ? undefined : emc);
|
setBaseEMC(emc === hum ? undefined : emc);
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [sliderVals, grain]);
|
}, [sliderVals, grain, user]);
|
||||||
|
|
||||||
const updateInteraction = () => {
|
const updateInteraction = () => {
|
||||||
interactionAPI
|
interactionAPI
|
||||||
|
|
@ -173,17 +173,17 @@ export default function BinConditioningInteraction(props: Props) {
|
||||||
return (
|
return (
|
||||||
<Grid container>
|
<Grid container>
|
||||||
{interaction.conditions().map((condition, i) => {
|
{interaction.conditions().map((condition, i) => {
|
||||||
let describer = describeMeasurement(condition.measurementType, source?.type());
|
let describer = describeMeasurement(condition.measurementType, source?.type(), source.subType(), undefined, user);
|
||||||
let labelTail = "";
|
let labelTail = describer.unit();
|
||||||
let marks: Mark[] = [];
|
let marks: Mark[] = [];
|
||||||
|
|
||||||
if (condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE) {
|
// if (condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE) {
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
// if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
labelTail = "°F";
|
// labelTail = "°F";
|
||||||
} else {
|
// } else {
|
||||||
labelTail = "°C";
|
// labelTail = "°C";
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if (condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT) {
|
if (condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT) {
|
||||||
labelTail = "%";
|
labelTail = "%";
|
||||||
}
|
}
|
||||||
|
|
@ -198,7 +198,7 @@ export default function BinConditioningInteraction(props: Props) {
|
||||||
return (
|
return (
|
||||||
<Grid key={i} container item xs={12} alignContent="center" alignItems="center">
|
<Grid key={i} container item xs={12} alignContent="center" alignItems="center">
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
{interactionConditionText(source, condition, false)}
|
{interactionConditionText(source, condition, false, user)}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12} style={{ marginBottom: 20 }}>
|
<Grid item xs={12} style={{ marginBottom: 20 }}>
|
||||||
<Slider
|
<Slider
|
||||||
|
|
@ -220,7 +220,7 @@ export default function BinConditioningInteraction(props: Props) {
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE
|
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||||
) {
|
) {
|
||||||
return value.toFixed(1) + "°F";
|
return value.toFixed(1) + "°F";
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import SearchSelect, { Option } from "common/SearchSelect";
|
||||||
import { useMobile } from "hooks";
|
import { useMobile } from "hooks";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { getDistanceUnit } from "utils";
|
import { useGlobalState } from "providers";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
optionsChanged: (binOptions: jsonBin[]) => void;
|
optionsChanged: (binOptions: jsonBin[]) => void;
|
||||||
|
|
@ -13,6 +13,7 @@ interface Props {
|
||||||
|
|
||||||
export default function BinSelector(props: Props) {
|
export default function BinSelector(props: Props) {
|
||||||
const { optionsChanged, vertical } = props;
|
const { optionsChanged, vertical } = props;
|
||||||
|
const [{user}] = useGlobalState();
|
||||||
const isMobile = useMobile();
|
const isMobile = useMobile();
|
||||||
const [manufacturerOptions, SetManufacturerOptions] = useState<Option[]>([]);
|
const [manufacturerOptions, SetManufacturerOptions] = useState<Option[]>([]);
|
||||||
const [manufacturer, SetManufacturer] = useState<Option | null>(null);
|
const [manufacturer, SetManufacturer] = useState<Option | null>(null);
|
||||||
|
|
@ -126,7 +127,7 @@ export default function BinSelector(props: Props) {
|
||||||
}}
|
}}
|
||||||
label={
|
label={
|
||||||
"Minimum Diameter " +
|
"Minimum Diameter " +
|
||||||
(getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)")
|
(user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)")
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -143,7 +144,7 @@ export default function BinSelector(props: Props) {
|
||||||
}}
|
}}
|
||||||
label={
|
label={
|
||||||
"Maximum Diameter " +
|
"Maximum Diameter " +
|
||||||
(getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)")
|
(user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)")
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,9 @@ interface Props {
|
||||||
coords?: { longitude: number; latitude: number };
|
coords?: { longitude: number; latitude: number };
|
||||||
binYards?: pond.BinYardSettings[];
|
binYards?: pond.BinYardSettings[];
|
||||||
components?: Map<string, Component>;
|
components?: Map<string, Component>;
|
||||||
|
componentDevices?: Map<string, number>
|
||||||
setComponents?: React.Dispatch<React.SetStateAction<Map<string, Component>>>;
|
setComponents?: React.Dispatch<React.SetStateAction<Map<string, Component>>>;
|
||||||
|
setComponentDevices?: React.Dispatch<React.SetStateAction<Map<string, number>>>;
|
||||||
updateBinStatus?: (componentKeys: string[], removed?: boolean) => void;
|
updateBinStatus?: (componentKeys: string[], removed?: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,7 +45,9 @@ export default function BinSensors(props: Props) {
|
||||||
mode,
|
mode,
|
||||||
openedBinYard,
|
openedBinYard,
|
||||||
components,
|
components,
|
||||||
|
componentDevices,
|
||||||
setComponents,
|
setComponents,
|
||||||
|
setComponentDevices,
|
||||||
updateBinStatus
|
updateBinStatus
|
||||||
} = props;
|
} = props;
|
||||||
const [initialized, setInitialized] = useState(false);
|
const [initialized, setInitialized] = useState(false);
|
||||||
|
|
@ -93,7 +97,9 @@ export default function BinSensors(props: Props) {
|
||||||
<Box padding={1}>
|
<Box padding={1}>
|
||||||
<BinComponents
|
<BinComponents
|
||||||
components={components ? components : undefined}
|
components={components ? components : undefined}
|
||||||
|
componentDevices={componentDevices}
|
||||||
setComponents={setComponents}
|
setComponents={setComponents}
|
||||||
|
setComponentDevices={setComponentDevices}
|
||||||
bin={bin.key()}
|
bin={bin.key()}
|
||||||
binGrain={bin.grain()}
|
binGrain={bin.grain()}
|
||||||
updateBinStatus={updateBinStatus}
|
updateBinStatus={updateBinStatus}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ import { pond } from "protobuf-ts/pond";
|
||||||
import { useBinAPI, useBinYardAPI, useGlobalState, useLibraCartProxyAPI } from "providers";
|
import { useBinAPI, useBinYardAPI, useGlobalState, useLibraCartProxyAPI } from "providers";
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
// import { useHistory } from "react-router";
|
// import { useHistory } from "react-router";
|
||||||
import { getDistanceUnit, or, getTemperatureUnit, getGrainUnit } from "utils";
|
import { or } from "utils";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import BinSelector from "./BinSelector";
|
import BinSelector from "./BinSelector";
|
||||||
|
|
@ -240,16 +240,16 @@ export default function BinSettings(props: Props) {
|
||||||
initForm.inventory.bushelsPerTonne = grain.bushelsPerTonne;
|
initForm.inventory.bushelsPerTonne = grain.bushelsPerTonne;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
setBushelConversion(initForm.inventory.bushelsPerTonne)
|
setBushelConversion(initForm.inventory.bushelsPerTonne)
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
setBushelConversion(initForm.inventory.bushelsPerTonne * 0.907)
|
setBushelConversion(initForm.inventory.bushelsPerTonne * 0.907)
|
||||||
}
|
}
|
||||||
if (initForm.inventory.customGrain){
|
if (initForm.inventory.customGrain){
|
||||||
setCustomGrain(initForm.inventory.customGrain)
|
setCustomGrain(initForm.inventory.customGrain)
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
setBushelConversion(initForm.inventory.customGrain.bushelsPerTonne)
|
setBushelConversion(initForm.inventory.customGrain.bushelsPerTonne)
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
setBushelConversion(initForm.inventory.customGrain.bushelsPerTonne * 0.907)
|
setBushelConversion(initForm.inventory.customGrain.bushelsPerTonne * 0.907)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +269,7 @@ export default function BinSettings(props: Props) {
|
||||||
let sidewallHeight = "";
|
let sidewallHeight = "";
|
||||||
let hopperHeight = "";
|
let hopperHeight = "";
|
||||||
if (initForm.specs) {
|
if (initForm.specs) {
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
h = (initForm.specs.heightCm * 0.0328).toFixed(2);
|
h = (initForm.specs.heightCm * 0.0328).toFixed(2);
|
||||||
d = (initForm.specs.diameterCm * 0.0328).toFixed(2);
|
d = (initForm.specs.diameterCm * 0.0328).toFixed(2);
|
||||||
if (initForm.specs.advancedDimensions) {
|
if (initForm.specs.advancedDimensions) {
|
||||||
|
|
@ -290,7 +290,7 @@ export default function BinSettings(props: Props) {
|
||||||
let high = initForm.highTemp ?? 20;
|
let high = initForm.highTemp ?? 20;
|
||||||
let low = initForm.lowTemp ?? 10;
|
let low = initForm.lowTemp ?? 10;
|
||||||
let target = initForm.inventory?.targetTemperature ?? 15;
|
let target = initForm.inventory?.targetTemperature ?? 15;
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
high = parseFloat((high * 1.8 + 32).toFixed(2));
|
high = parseFloat((high * 1.8 + 32).toFixed(2));
|
||||||
low = parseFloat((low * 1.8 + 32).toFixed(2));
|
low = parseFloat((low * 1.8 + 32).toFixed(2));
|
||||||
target = parseFloat((target * 1.8 + 32).toFixed(2));
|
target = parseFloat((target * 1.8 + 32).toFixed(2));
|
||||||
|
|
@ -304,15 +304,15 @@ export default function BinSettings(props: Props) {
|
||||||
: initForm.inventory?.grainBushels ?? 0;
|
: initForm.inventory?.grainBushels ?? 0;
|
||||||
let weight = ""
|
let weight = ""
|
||||||
if(initForm.inventory){
|
if(initForm.inventory){
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
weight = (gb/initForm.inventory.bushelsPerTonne).toFixed(2)
|
weight = (gb/initForm.inventory.bushelsPerTonne).toFixed(2)
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
weight = (gb/(initForm.inventory.bushelsPerTonne * 0.907)).toFixed(2)
|
weight = (gb/(initForm.inventory.bushelsPerTonne * 0.907)).toFixed(2)
|
||||||
}
|
}
|
||||||
if(initForm.inventory.customGrain){
|
if(initForm.inventory.customGrain){
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
weight = (gb/initForm.inventory.customGrain.bushelsPerTonne).toFixed(2)
|
weight = (gb/initForm.inventory.customGrain.bushelsPerTonne).toFixed(2)
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
weight = (gb/(initForm.inventory.customGrain.bushelsPerTonne * 0.907)).toFixed(2)
|
weight = (gb/(initForm.inventory.customGrain.bushelsPerTonne * 0.907)).toFixed(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -350,7 +350,7 @@ export default function BinSettings(props: Props) {
|
||||||
setMoistureTargetDeviation(initForm.inventory?.moistureTargetDeviation.toString() ?? "0");
|
setMoistureTargetDeviation(initForm.inventory?.moistureTargetDeviation.toString() ?? "0");
|
||||||
setAutoFillThreshold(initForm.inventory?.autoThreshold ?? 5)
|
setAutoFillThreshold(initForm.inventory?.autoThreshold ?? 5)
|
||||||
let dropDistance = initForm.inventory?.lidarDropCm ?? 0
|
let dropDistance = initForm.inventory?.lidarDropCm ?? 0
|
||||||
if(getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET){
|
if(user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET){
|
||||||
dropDistance = Math.round((dropDistance/30.48)*100)/100
|
dropDistance = Math.round((dropDistance/30.48)*100)/100
|
||||||
}
|
}
|
||||||
setLidarDropDistance(dropDistance)
|
setLidarDropDistance(dropDistance)
|
||||||
|
|
@ -364,7 +364,7 @@ export default function BinSettings(props: Props) {
|
||||||
} else {
|
} else {
|
||||||
setInitialized(false);
|
setInitialized(false);
|
||||||
}
|
}
|
||||||
}, [bin, open, mode, openedBinYard]);
|
}, [bin, open, mode, openedBinYard, user]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (mode === "remove") {
|
if (mode === "remove") {
|
||||||
|
|
@ -475,7 +475,7 @@ export default function BinSettings(props: Props) {
|
||||||
if (form.inventory) {
|
if (form.inventory) {
|
||||||
form.inventory.inventoryControl = inventoryControl
|
form.inventory.inventoryControl = inventoryControl
|
||||||
form.inventory.autoThreshold = autoFillThreshold
|
form.inventory.autoThreshold = autoFillThreshold
|
||||||
form.inventory.lidarDropCm = getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? lidarDropDistance * 30.48 : lidarDropDistance
|
form.inventory.lidarDropCm = user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? lidarDropDistance * 30.48 : lidarDropDistance
|
||||||
if(form.inventory.grainType !== pond.Grain.GRAIN_CUSTOM){
|
if(form.inventory.grainType !== pond.Grain.GRAIN_CUSTOM){
|
||||||
form.inventory.customGrain = undefined
|
form.inventory.customGrain = undefined
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -529,7 +529,7 @@ export default function BinSettings(props: Props) {
|
||||||
form.inventory.inventoryControl = inventoryControl
|
form.inventory.inventoryControl = inventoryControl
|
||||||
form.inventory.autoThreshold = autoFillThreshold
|
form.inventory.autoThreshold = autoFillThreshold
|
||||||
//if the users preferences are in feet convert the distance to cm otherwise it was entered as cm so use that
|
//if the users preferences are in feet convert the distance to cm otherwise it was entered as cm so use that
|
||||||
form.inventory.lidarDropCm = getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? lidarDropDistance * 30.48 : lidarDropDistance
|
form.inventory.lidarDropCm = user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? lidarDropDistance * 30.48 : lidarDropDistance
|
||||||
if(form.inventory.grainType !== pond.Grain.GRAIN_CUSTOM){
|
if(form.inventory.grainType !== pond.Grain.GRAIN_CUSTOM){
|
||||||
form.inventory.customGrain = undefined
|
form.inventory.customGrain = undefined
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -804,7 +804,7 @@ export default function BinSettings(props: Props) {
|
||||||
const binQuantity = formExtension.grainBushels;
|
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
|
//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 !== "")){
|
if(storageType !== pond.BinStorage.BIN_STORAGE_FERTILIZER && ((user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE || user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) && bushelConversion !== 0 && grainWeight !== "")){
|
||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
label="Amount"
|
label="Amount"
|
||||||
|
|
@ -830,7 +830,7 @@ export default function BinSettings(props: Props) {
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
disabled={!canEdit}
|
disabled={!canEdit}
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: <InputAdornment position="end">{getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE ? "mT" : "t"}</InputAdornment>
|
endAdornment: <InputAdornment position="end">{user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE ? "mT" : "t"}</InputAdornment>
|
||||||
}}
|
}}
|
||||||
className={classes.bottomSpacing}
|
className={classes.bottomSpacing}
|
||||||
/>
|
/>
|
||||||
|
|
@ -1099,7 +1099,7 @@ export default function BinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "ft" : "cm"}
|
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "ft" : "cm"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -1179,9 +1179,9 @@ export default function BinSettings(props: Props) {
|
||||||
setCustomGrain(newGrainSettings)
|
setCustomGrain(newGrainSettings)
|
||||||
let conversion = 0
|
let conversion = 0
|
||||||
|
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
conversion = newGrainSettings.bushelsPerTonne
|
conversion = newGrainSettings.bushelsPerTonne
|
||||||
}else if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
}else if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
conversion = newGrainSettings.bushelsPerTonne * 0.907
|
conversion = newGrainSettings.bushelsPerTonne * 0.907
|
||||||
}
|
}
|
||||||
updateForm(
|
updateForm(
|
||||||
|
|
@ -1218,9 +1218,9 @@ export default function BinSettings(props: Props) {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
let conversion = 0
|
let conversion = 0
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
conversion = GrainDescriber(newGrainType).bushelsPerTonne
|
conversion = GrainDescriber(newGrainType).bushelsPerTonne
|
||||||
}else if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
}else if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
conversion = GrainDescriber(newGrainType).bushelsPerTon
|
conversion = GrainDescriber(newGrainType).bushelsPerTon
|
||||||
}
|
}
|
||||||
setBushelConversion(conversion)
|
setBushelConversion(conversion)
|
||||||
|
|
@ -1435,7 +1435,7 @@ export default function BinSettings(props: Props) {
|
||||||
let sH = sidewallHeight;
|
let sH = sidewallHeight;
|
||||||
let hH = hopperHeight ?? 0;
|
let hH = hopperHeight ?? 0;
|
||||||
let d = diameter;
|
let d = diameter;
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
tcH = tcH * 3.281;
|
tcH = tcH * 3.281;
|
||||||
sH = sH * 3.281;
|
sH = sH * 3.281;
|
||||||
hH = hH * 3.281;
|
hH = hH * 3.281;
|
||||||
|
|
@ -1463,7 +1463,7 @@ export default function BinSettings(props: Props) {
|
||||||
let hopperHeight = formExtension.hopperHeight;
|
let hopperHeight = formExtension.hopperHeight;
|
||||||
let diameter = formExtension.diameter;
|
let diameter = formExtension.diameter;
|
||||||
|
|
||||||
// if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
// if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
// diameterM = (Number(diameterM) * 3.28084).toFixed(2);
|
// diameterM = (Number(diameterM) * 3.28084).toFixed(2);
|
||||||
// heightM = (Number(heightM) * 3.28084).toFixed(2);
|
// heightM = (Number(heightM) * 3.28084).toFixed(2);
|
||||||
// }
|
// }
|
||||||
|
|
@ -1552,7 +1552,7 @@ export default function BinSettings(props: Props) {
|
||||||
let d = diameter;
|
let d = diameter;
|
||||||
let valueM = value;
|
let valueM = value;
|
||||||
let dM = diameter;
|
let dM = diameter;
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
valueM = (Number(value) * 0.3048).toFixed(2);
|
valueM = (Number(value) * 0.3048).toFixed(2);
|
||||||
dM = (Number(d) * 0.3048).toFixed(2);
|
dM = (Number(d) * 0.3048).toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
@ -1577,7 +1577,7 @@ export default function BinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -1637,7 +1637,7 @@ export default function BinSettings(props: Props) {
|
||||||
let value = event?.target.value;
|
let value = event?.target.value;
|
||||||
let valueM = value;
|
let valueM = value;
|
||||||
setModelID(0);
|
setModelID(0);
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
valueM = (Number(value) * 0.3048).toFixed(2);
|
valueM = (Number(value) * 0.3048).toFixed(2);
|
||||||
}
|
}
|
||||||
let coneCM =
|
let coneCM =
|
||||||
|
|
@ -1674,7 +1674,7 @@ export default function BinSettings(props: Props) {
|
||||||
|
|
||||||
//need to get the total height in cm
|
//need to get the total height in cm
|
||||||
let totalHeightCM = s + t + h; //the total height in the users units
|
let totalHeightCM = s + t + h; //the total height in the users units
|
||||||
if(getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET){
|
if(user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET){
|
||||||
totalHeightCM = totalHeightCM * 30.48 //convert from feet to cm
|
totalHeightCM = totalHeightCM * 30.48 //convert from feet to cm
|
||||||
}else{
|
}else{
|
||||||
totalHeightCM = totalHeightCM * 100 //convert from m to cm
|
totalHeightCM = totalHeightCM * 100 //convert from m to cm
|
||||||
|
|
@ -1698,7 +1698,7 @@ export default function BinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||||
? "m"
|
? "m"
|
||||||
: "ft"}
|
: "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -1725,7 +1725,7 @@ export default function BinSettings(props: Props) {
|
||||||
//calculate the new cone height for the roof angle
|
//calculate the new cone height for the roof angle
|
||||||
let coneCM = TriangleOppositeLength(d / 2, angle ?? 0);
|
let coneCM = TriangleOppositeLength(d / 2, angle ?? 0);
|
||||||
let newConeHeight =
|
let newConeHeight =
|
||||||
getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET
|
user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||||
? (coneCM / 30.48).toFixed(2)
|
? (coneCM / 30.48).toFixed(2)
|
||||||
: (coneCM / 100).toFixed(2);
|
: (coneCM / 100).toFixed(2);
|
||||||
|
|
||||||
|
|
@ -1749,7 +1749,7 @@ export default function BinSettings(props: Props) {
|
||||||
|
|
||||||
//need to get the total height in cm
|
//need to get the total height in cm
|
||||||
let totalHeightCM = s + t + h; //the total height in the users units
|
let totalHeightCM = s + t + h; //the total height in the users units
|
||||||
if(getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET){
|
if(user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET){
|
||||||
totalHeightCM = totalHeightCM * 30.48 //convert from feet to cm
|
totalHeightCM = totalHeightCM * 30.48 //convert from feet to cm
|
||||||
}else{
|
}else{
|
||||||
totalHeightCM = totalHeightCM * 100 //convert from m to cm
|
totalHeightCM = totalHeightCM * 100 //convert from m to cm
|
||||||
|
|
@ -1786,7 +1786,7 @@ export default function BinSettings(props: Props) {
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
let value = event?.target.value;
|
let value = event?.target.value;
|
||||||
let valueM = value;
|
let valueM = value;
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
valueM = (Number(value) * 0.3048).toFixed(2);
|
valueM = (Number(value) * 0.3048).toFixed(2);
|
||||||
}
|
}
|
||||||
let ext = cloneDeep(formExtension);
|
let ext = cloneDeep(formExtension);
|
||||||
|
|
@ -1811,7 +1811,7 @@ export default function BinSettings(props: Props) {
|
||||||
|
|
||||||
//need to get the total height in cm
|
//need to get the total height in cm
|
||||||
let totalHeightCM = s + t + h; //the total height in the users units
|
let totalHeightCM = s + t + h; //the total height in the users units
|
||||||
if(getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET){
|
if(user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET){
|
||||||
totalHeightCM = totalHeightCM * 30.48 //convert from feet to cm
|
totalHeightCM = totalHeightCM * 30.48 //convert from feet to cm
|
||||||
}else{
|
}else{
|
||||||
totalHeightCM = totalHeightCM * 100 //convert from m to cm
|
totalHeightCM = totalHeightCM * 100 //convert from m to cm
|
||||||
|
|
@ -1838,7 +1838,7 @@ export default function BinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||||
? "m"
|
? "m"
|
||||||
: "ft"}
|
: "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -1868,7 +1868,7 @@ export default function BinSettings(props: Props) {
|
||||||
let coneCM = TriangleOppositeLength(d / 2, angle ?? 0);
|
let coneCM = TriangleOppositeLength(d / 2, angle ?? 0);
|
||||||
|
|
||||||
let newHopperHeight =
|
let newHopperHeight =
|
||||||
getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET
|
user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||||
? (coneCM / 30.48).toFixed(2)
|
? (coneCM / 30.48).toFixed(2)
|
||||||
: (coneCM / 100).toFixed(2);
|
: (coneCM / 100).toFixed(2);
|
||||||
|
|
||||||
|
|
@ -1926,7 +1926,7 @@ export default function BinSettings(props: Props) {
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
let value = event?.target.value;
|
let value = event?.target.value;
|
||||||
let valueM = value;
|
let valueM = value;
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
valueM = (Number(value) * 0.3048).toFixed(2);
|
valueM = (Number(value) * 0.3048).toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1982,7 +1982,7 @@ export default function BinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||||
? "m"
|
? "m"
|
||||||
: "ft"}
|
: "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -2009,7 +2009,7 @@ export default function BinSettings(props: Props) {
|
||||||
let h = height;
|
let h = height;
|
||||||
let valueM = value;
|
let valueM = value;
|
||||||
let hM = height;
|
let hM = height;
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
valueM = (Number(value) * 0.3048).toFixed(2);
|
valueM = (Number(value) * 0.3048).toFixed(2);
|
||||||
hM = (Number(h) * 0.3048).toFixed(2);
|
hM = (Number(h) * 0.3048).toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
@ -2063,7 +2063,7 @@ export default function BinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -2253,7 +2253,7 @@ export default function BinSettings(props: Props) {
|
||||||
let userHopperHeight = hopperHeight;
|
let userHopperHeight = hopperHeight;
|
||||||
let userDiameter = jsonBin.Diameter;
|
let userDiameter = jsonBin.Diameter;
|
||||||
//since the jsone data is in feet just check if we need to make it in meters
|
//since the jsone data is in feet just check if we need to make it in meters
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
userHeight = userHeight / 3.281;
|
userHeight = userHeight / 3.281;
|
||||||
userDiameter = userDiameter / 3.281;
|
userDiameter = userDiameter / 3.281;
|
||||||
userTopCone = userTopCone / 3.281;
|
userTopCone = userTopCone / 3.281;
|
||||||
|
|
@ -2308,7 +2308,7 @@ export default function BinSettings(props: Props) {
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
let value = event?.target.value;
|
let value = event?.target.value;
|
||||||
let valueC = value;
|
let valueC = value;
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
valueC = ((Number(value) - 32) * (5 / 9)).toFixed(2);
|
valueC = ((Number(value) - 32) * (5 / 9)).toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2320,7 +2320,7 @@ export default function BinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||||
? "F"
|
? "F"
|
||||||
: "C"}
|
: "C"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -2348,7 +2348,7 @@ export default function BinSettings(props: Props) {
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
let value = event?.target.value;
|
let value = event?.target.value;
|
||||||
let valueC = value;
|
let valueC = value;
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
valueC = ((Number(value) - 32) * (5 / 9)).toFixed(2);
|
valueC = ((Number(value) - 32) * (5 / 9)).toFixed(2);
|
||||||
}
|
}
|
||||||
setLowTempC(+valueC);
|
setLowTempC(+valueC);
|
||||||
|
|
@ -2357,7 +2357,7 @@ export default function BinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||||
? "F"
|
? "F"
|
||||||
: "C"}
|
: "C"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -2383,7 +2383,7 @@ export default function BinSettings(props: Props) {
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
let value = event?.target.value;
|
let value = event?.target.value;
|
||||||
let valueC = value;
|
let valueC = value;
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
valueC = ((Number(value) - 32) * (5 / 9)).toFixed(2);
|
valueC = ((Number(value) - 32) * (5 / 9)).toFixed(2);
|
||||||
}
|
}
|
||||||
setHighTempC(+valueC);
|
setHighTempC(+valueC);
|
||||||
|
|
@ -2392,7 +2392,7 @@ export default function BinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||||
? "F"
|
? "F"
|
||||||
: "C"}
|
: "C"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import Co2Icon from "products/CommonIcons/co2Icon";
|
||||||
import { pond, quack } from "protobuf-ts/pond";
|
import { pond, quack } from "protobuf-ts/pond";
|
||||||
import { useBinAPI, useGlobalState, useSnackbar } from "providers";
|
import { useBinAPI, useGlobalState, useSnackbar } from "providers";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { avg, getTemperatureUnit } from "utils";
|
import { avg } from "utils";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import { Mark } from "@mui/material/Slider/useSlider.types";
|
import { Mark } from "@mui/material/Slider/useSlider.types";
|
||||||
import { CO2 } from "models/CO2";
|
import { CO2 } from "models/CO2";
|
||||||
|
|
@ -134,7 +134,7 @@ export default function BinStorageConditions(props: Props) {
|
||||||
const binAPI = useBinAPI();
|
const binAPI = useBinAPI();
|
||||||
const { openSnack } = useSnackbar();
|
const { openSnack } = useSnackbar();
|
||||||
const { bin, headspaceCO2, cables } = props;
|
const { bin, headspaceCO2, cables } = props;
|
||||||
const [{as}] = useGlobalState()
|
const [{as, user}] = useGlobalState()
|
||||||
const [sliderTemps, setSliderTemps] = useState<number[]>([-40, 40]);
|
const [sliderTemps, setSliderTemps] = useState<number[]>([-40, 40]);
|
||||||
//boolean that if a cable is missing its filled to display an icon or something to let the user know not all of the cables have their fill set
|
//boolean that if a cable is missing its filled to display an icon or something to let the user know not all of the cables have their fill set
|
||||||
const [missingTopNodeWarning, setMissingTopNodeWarning] = useState(false);
|
const [missingTopNodeWarning, setMissingTopNodeWarning] = useState(false);
|
||||||
|
|
@ -233,7 +233,7 @@ export default function BinStorageConditions(props: Props) {
|
||||||
}
|
}
|
||||||
setTempTargets(tempCounts);
|
setTempTargets(tempCounts);
|
||||||
let tempVal = bin.settings.inventory?.targetTemperature ?? 0;
|
let tempVal = bin.settings.inventory?.targetTemperature ?? 0;
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
tempVal = tempVal * 1.8 + 32;
|
tempVal = tempVal * 1.8 + 32;
|
||||||
}
|
}
|
||||||
setTargetTemp(tempVal.toFixed(1));
|
setTargetTemp(tempVal.toFixed(1));
|
||||||
|
|
@ -244,7 +244,7 @@ export default function BinStorageConditions(props: Props) {
|
||||||
setEmcTargets(emcCounts);
|
setEmcTargets(emcCounts);
|
||||||
setTargetEMC(bin.settings.inventory?.targetMoisture.toFixed(1) ?? "");
|
setTargetEMC(bin.settings.inventory?.targetMoisture.toFixed(1) ?? "");
|
||||||
setEmcDeviation(bin.settings.inventory?.moistureTargetDeviation.toFixed(1) ?? "");
|
setEmcDeviation(bin.settings.inventory?.moistureTargetDeviation.toFixed(1) ?? "");
|
||||||
}, [bin, cables]);
|
}, [bin, cables, user]);
|
||||||
|
|
||||||
//useEffect that watches for changes in the target emc and deviation to update the targets
|
//useEffect that watches for changes in the target emc and deviation to update the targets
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -301,7 +301,7 @@ export default function BinStorageConditions(props: Props) {
|
||||||
settings.highTemp = sliderTemps[1];
|
settings.highTemp = sliderTemps[1];
|
||||||
if (settings.inventory) {
|
if (settings.inventory) {
|
||||||
let tempVal = parseFloat(targetTemp);
|
let tempVal = parseFloat(targetTemp);
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
tempVal = Math.fround(((tempVal - 32) * 5) / 9);
|
tempVal = Math.fround(((tempVal - 32) * 5) / 9);
|
||||||
}
|
}
|
||||||
settings.inventory.targetTemperature = tempVal;
|
settings.inventory.targetTemperature = tempVal;
|
||||||
|
|
@ -376,14 +376,14 @@ export default function BinStorageConditions(props: Props) {
|
||||||
let mark: Mark[] = [];
|
let mark: Mark[] = [];
|
||||||
if (averageTemp) {
|
if (averageTemp) {
|
||||||
let temp = averageTemp;
|
let temp = averageTemp;
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
temp = temp * 1.8 + 32;
|
temp = temp * 1.8 + 32;
|
||||||
}
|
}
|
||||||
mark = [
|
mark = [
|
||||||
{
|
{
|
||||||
label: customMark(
|
label: customMark(
|
||||||
temp.toFixed(1) +
|
temp.toFixed(1) +
|
||||||
(getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
(user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||||
? "°F"
|
? "°F"
|
||||||
: "°C"),
|
: "°C"),
|
||||||
"AVG"
|
"AVG"
|
||||||
|
|
@ -422,7 +422,7 @@ export default function BinStorageConditions(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||||
? "°F"
|
? "°F"
|
||||||
: "°C"}
|
: "°C"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -451,7 +451,7 @@ export default function BinStorageConditions(props: Props) {
|
||||||
max={sliderEdge}
|
max={sliderEdge}
|
||||||
valueLabelDisplay="on"
|
valueLabelDisplay="on"
|
||||||
valueLabelFormat={value => {
|
valueLabelFormat={value => {
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
return ((value * 9) / 5 + 32).toFixed(1) + "°F";
|
return ((value * 9) / 5 + 32).toFixed(1) + "°F";
|
||||||
}
|
}
|
||||||
return value.toFixed(1) + "°C";
|
return value.toFixed(1) + "°C";
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,10 @@ import { Transaction } from "models/Transaction";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import ObjectDescriber from "objects/ObjectDescriber";
|
import ObjectDescriber from "objects/ObjectDescriber";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useBinAPI, useContractAPI, useFieldAPI, useGrainBagAPI, useSnackbar, useTransactionAPI } from "providers";
|
import { useBinAPI, useContractAPI, useFieldAPI, useGlobalState, useGrainBagAPI, useSnackbar, useTransactionAPI } from "providers";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import TransactionDataDisplay from "transactions/transactionDataDisplay";
|
import TransactionDataDisplay from "transactions/transactionDataDisplay";
|
||||||
import { getGrainUnit } from "utils";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
bin: Bin
|
bin: Bin
|
||||||
|
|
@ -26,6 +25,7 @@ export default function BinTransactions(props: Props){
|
||||||
const { bin, permissions, refresh } = props
|
const { bin, permissions, refresh } = props
|
||||||
const [state, setState] = useState<pond.TransactionState>(pond.TransactionState.TRANSACTION_STATE_APPROVAL_REQUIRED)
|
const [state, setState] = useState<pond.TransactionState>(pond.TransactionState.TRANSACTION_STATE_APPROVAL_REQUIRED)
|
||||||
const transactionAPI = useTransactionAPI()
|
const transactionAPI = useTransactionAPI()
|
||||||
|
const [{user}] = useGlobalState()
|
||||||
const binAPI = useBinAPI()
|
const binAPI = useBinAPI()
|
||||||
const grainBagAPI = useGrainBagAPI()
|
const grainBagAPI = useGrainBagAPI()
|
||||||
const fieldAPI = useFieldAPI()
|
const fieldAPI = useFieldAPI()
|
||||||
|
|
@ -103,7 +103,7 @@ export default function BinTransactions(props: Props){
|
||||||
const loadContracts = useCallback(()=>{
|
const loadContracts = useCallback(()=>{
|
||||||
contractAPI.listContracts(0,0, "asc", "name").then(resp => {
|
contractAPI.listContracts(0,0, "asc", "name").then(resp => {
|
||||||
setContractOptions(resp.data.contracts.map(c => {
|
setContractOptions(resp.data.contracts.map(c => {
|
||||||
let contract = Contract.create(c)
|
let contract = Contract.create(c, user)
|
||||||
return {label: contract.name(), value: contract.key(), group: contract.grainName()}
|
return {label: contract.name(), value: contract.key(), group: contract.grainName()}
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
|
@ -198,11 +198,11 @@ export default function BinTransactions(props: Props){
|
||||||
|
|
||||||
const grainQuantityDisplay = (bushels: number) => {
|
const grainQuantityDisplay = (bushels: number) => {
|
||||||
const grainTransaction = selectedTransaction?.transaction.transaction?.grainTransaction ?? pond.GrainTransaction.create()
|
const grainTransaction = selectedTransaction?.transaction.transaction?.grainTransaction ?? pond.GrainTransaction.create()
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainTransaction.bushelsPerTonne > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainTransaction.bushelsPerTonne > 1){
|
||||||
let tonneWeight = bushels / grainTransaction.bushelsPerTonne
|
let tonneWeight = bushels / grainTransaction.bushelsPerTonne
|
||||||
return tonneWeight + " mT"
|
return tonneWeight + " mT"
|
||||||
}
|
}
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainTransaction.bushelsPerTonne > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainTransaction.bushelsPerTonne > 1){
|
||||||
let tonneWeight = bushels / (grainTransaction.bushelsPerTonne * 0.907)
|
let tonneWeight = bushels / (grainTransaction.bushelsPerTonne * 0.907)
|
||||||
return tonneWeight + " t"
|
return tonneWeight + " t"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ import { FullScreen, useFullScreenHandle } from "react-full-screen";
|
||||||
import moment, { Moment } from "moment";
|
import moment, { Moment } from "moment";
|
||||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||||
import { getThemeType } from "theme";
|
import { getThemeType } from "theme";
|
||||||
import { getGrainUnit, getTemperatureUnit, or } from "utils";
|
import { or } from "utils";
|
||||||
import { useBinAPI } from "providers/pond/binAPI";
|
import { useBinAPI } from "providers/pond/binAPI";
|
||||||
import BindaptIcon from "products/Bindapt/BindaptIcon";
|
import BindaptIcon from "products/Bindapt/BindaptIcon";
|
||||||
import {
|
import {
|
||||||
|
|
@ -498,9 +498,9 @@ export default function BinVisualizer(props: Props) {
|
||||||
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
||||||
return Math.round(val * 35.239 * 100) / 100;
|
return Math.round(val * 35.239 * 100) / 100;
|
||||||
} else {
|
} else {
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
||||||
return Math.round((val / bin.bushelsPerTonne()) * 100) / 100;
|
return Math.round((val / bin.bushelsPerTonne()) * 100) / 100;
|
||||||
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
} else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||||
return Math.round((val / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
return Math.round((val / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -516,9 +516,9 @@ export default function BinVisualizer(props: Props) {
|
||||||
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
||||||
return " / " + capacity.toLocaleString() + " L";
|
return " / " + capacity.toLocaleString() + " L";
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
||||||
return "mT (" + bin.fillPercent() + "%)";
|
return "mT (" + bin.fillPercent() + "%)";
|
||||||
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
} else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||||
return "t (" + bin.fillPercent() + "%)";
|
return "t (" + bin.fillPercent() + "%)";
|
||||||
} else {
|
} else {
|
||||||
return " / " + capacity.toLocaleString() + " bu";
|
return " / " + capacity.toLocaleString() + " bu";
|
||||||
|
|
@ -605,7 +605,7 @@ export default function BinVisualizer(props: Props) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (valC) {
|
if (valC) {
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
temp = CtoF(valC).toFixed(1) + "°F";
|
temp = CtoF(valC).toFixed(1) + "°F";
|
||||||
} else {
|
} else {
|
||||||
temp = valC.toFixed(1) + "°C";
|
temp = valC.toFixed(1) + "°C";
|
||||||
|
|
@ -705,7 +705,7 @@ export default function BinVisualizer(props: Props) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (valC) {
|
if (valC) {
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
temp = Math.abs(valC * 1.8).toFixed(1) + "°F"; //since this is a measurement of change a change in 1 degrre celsius is equivalent to 1.8 fahrenheit
|
temp = Math.abs(valC * 1.8).toFixed(1) + "°F"; //since this is a measurement of change a change in 1 degrre celsius is equivalent to 1.8 fahrenheit
|
||||||
} else {
|
} else {
|
||||||
temp = Math.abs(valC).toFixed(1) + "°C";
|
temp = Math.abs(valC).toFixed(1) + "°C";
|
||||||
|
|
@ -1328,14 +1328,14 @@ export default function BinVisualizer(props: Props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
||||||
diffDisplay = diffDisplay / bin.bushelsPerTonne();
|
diffDisplay = diffDisplay / bin.bushelsPerTonne();
|
||||||
if (pendingDisplay) {
|
if (pendingDisplay) {
|
||||||
pendingDisplay = pendingDisplay / bin.bushelsPerTonne();
|
pendingDisplay = pendingDisplay / bin.bushelsPerTonne();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||||
diffDisplay = diffDisplay / (bin.bushelsPerTonne()*0.907);
|
diffDisplay = diffDisplay / (bin.bushelsPerTonne()*0.907);
|
||||||
if (pendingDisplay) {
|
if (pendingDisplay) {
|
||||||
pendingDisplay = pendingDisplay / (bin.bushelsPerTonne()*0.907);
|
pendingDisplay = pendingDisplay / (bin.bushelsPerTonne()*0.907);
|
||||||
|
|
@ -1539,7 +1539,7 @@ export default function BinVisualizer(props: Props) {
|
||||||
<InfoOutlined />
|
<InfoOutlined />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
) : (
|
) : (
|
||||||
<IconButton size="small" onClick={fullScreenHandler.enter}>
|
<IconButton size="small" onClick={() => {fullScreenHandler.enter()}}>
|
||||||
<FullscreenIcon />
|
<FullscreenIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
|
|
@ -1676,7 +1676,7 @@ export default function BinVisualizer(props: Props) {
|
||||||
fontWeight: 650,
|
fontWeight: 650,
|
||||||
color: tempColour
|
color: tempColour
|
||||||
}}>
|
}}>
|
||||||
{ambient?.getTempString(getTemperatureUnit())}
|
{ambient?.getTempString(user.tempUnit())}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Box display="flex" marginY={1}>
|
<Box display="flex" marginY={1}>
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ import { Bin } from "models";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useBinAPI, useGlobalState } from "providers";
|
import { useBinAPI, useGlobalState } from "providers";
|
||||||
import React, { useEffect, useState, useCallback, SetStateAction } from "react";
|
import React, { useEffect, useState, useCallback, SetStateAction } from "react";
|
||||||
import { getGrainUnit, stringToMaterialColour } from "utils";
|
import { stringToMaterialColour } from "utils";
|
||||||
//import BinsFansStatusTable from "./BinFansStatusTable";
|
//import BinsFansStatusTable from "./BinFansStatusTable";
|
||||||
import BinsList from "./BinsList";
|
import BinsList from "./BinsList";
|
||||||
|
|
||||||
|
|
@ -95,7 +95,7 @@ export default function BinyardDisplay(props: Props) {
|
||||||
const isMobile = useMobile();
|
const isMobile = useMobile();
|
||||||
const [carouselIndex, setCarouselIndex] = useState(0);
|
const [carouselIndex, setCarouselIndex] = useState(0);
|
||||||
const [binMenuAnchorEl, setBinMenuAnchorEl] = useState<Element | null>(null);
|
const [binMenuAnchorEl, setBinMenuAnchorEl] = useState<Element | null>(null);
|
||||||
const [{ as }] = useGlobalState();
|
const [{ as, user }] = useGlobalState();
|
||||||
const maxBins = 40;
|
const maxBins = 40;
|
||||||
const [binsLoading, setBinsLoading] = useState(false);
|
const [binsLoading, setBinsLoading] = useState(false);
|
||||||
const [expandTotal, setExpandTotal] = useState(false);
|
const [expandTotal, setExpandTotal] = useState(false);
|
||||||
|
|
@ -658,7 +658,7 @@ export default function BinyardDisplay(props: Props) {
|
||||||
return " bu";
|
return " bu";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (getGrainUnit()) {
|
switch (user.grainUnit()) {
|
||||||
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
||||||
return " mT";
|
return " mT";
|
||||||
case pond.GrainUnit.GRAIN_UNIT_TON:
|
case pond.GrainUnit.GRAIN_UNIT_TON:
|
||||||
|
|
@ -671,9 +671,9 @@ export default function BinyardDisplay(props: Props) {
|
||||||
const customQuantityDisplay = (customInventory: pond.CustomInventory, bushels: number) => {
|
const customQuantityDisplay = (customInventory: pond.CustomInventory, bushels: number) => {
|
||||||
let amount = bushels
|
let amount = bushels
|
||||||
if(customInventory.bushelsPerTonne > 1){
|
if(customInventory.bushelsPerTonne > 1){
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
amount = bushels/customInventory.bushelsPerTonne
|
amount = bushels/customInventory.bushelsPerTonne
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
amount = bushels/(customInventory.bushelsPerTonne*0.907)
|
amount = bushels/(customInventory.bushelsPerTonne*0.907)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -683,9 +683,9 @@ export default function BinyardDisplay(props: Props) {
|
||||||
const supportedGrainDisplay = (grain: pond.Grain, bushels: number) => {
|
const supportedGrainDisplay = (grain: pond.Grain, bushels: number) => {
|
||||||
const describer = GrainDescriber(grain)
|
const describer = GrainDescriber(grain)
|
||||||
let amount = bushels
|
let amount = bushels
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
amount = bushels/describer.bushelsPerTonne
|
amount = bushels/describer.bushelsPerTonne
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
amount = bushels/describer.bushelsPerTon
|
amount = bushels/describer.bushelsPerTon
|
||||||
}
|
}
|
||||||
return Math.round(amount*100)/100
|
return Math.round(amount*100)/100
|
||||||
|
|
|
||||||
|
|
@ -87,9 +87,24 @@ export default function GrainNodeInteractions(props: Props) {
|
||||||
const [nodeHum, setNodeHum] = useState<number>();
|
const [nodeHum, setNodeHum] = useState<number>();
|
||||||
const [nodeMoist, setNodeMoist] = useState<number | undefined>();
|
const [nodeMoist, setNodeMoist] = useState<number | undefined>();
|
||||||
const [{ user, as }] = useGlobalState();
|
const [{ user, as }] = useGlobalState();
|
||||||
const tempDescriber = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE);
|
const tempDescriber = describeMeasurement(
|
||||||
const humDescriber = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_PERCENT);
|
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
||||||
const moistureDescriber = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_GRAIN_EMC);
|
quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
user);
|
||||||
|
const humDescriber = describeMeasurement(
|
||||||
|
quack.MeasurementType.MEASUREMENT_TYPE_PERCENT,
|
||||||
|
quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
user);
|
||||||
|
const moistureDescriber = describeMeasurement(
|
||||||
|
quack.MeasurementType.MEASUREMENT_TYPE_GRAIN_EMC,
|
||||||
|
quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
user);
|
||||||
const [topNode, setTopNode] = useState(false);
|
const [topNode, setTopNode] = useState(false);
|
||||||
const [excluded, setExcluded] = useState(false);
|
const [excluded, setExcluded] = useState(false);
|
||||||
const componentAPI = useComponentAPI();
|
const componentAPI = useComponentAPI();
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import { sameComponentID } from "pbHelpers/Component";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { lowerCase } from "lodash";
|
import { lowerCase } from "lodash";
|
||||||
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
||||||
import { fahrenheitToCelsius, getTemperatureUnit } from "utils";
|
|
||||||
import { GetGrainExtensionMap } from "grain";
|
import { GetGrainExtensionMap } from "grain";
|
||||||
import { PromiseProgress, Stage, Step as PromiseStep } from "common/PromiseProgress";
|
import { PromiseProgress, Stage, Step as PromiseStep } from "common/PromiseProgress";
|
||||||
|
|
||||||
|
|
@ -76,7 +75,7 @@ export default function ModeChangeDialog(props: Props){
|
||||||
changeOutdoorHumidity,
|
changeOutdoorHumidity,
|
||||||
presets
|
presets
|
||||||
} = props
|
} = props
|
||||||
const [{as}] = useGlobalState()
|
const [{as, user}] = useGlobalState()
|
||||||
const [componentSets, setComponentSets] = useState<ComponentSet[]>([])
|
const [componentSets, setComponentSets] = useState<ComponentSet[]>([])
|
||||||
const interactionAPI = useInteractionsAPI()
|
const interactionAPI = useInteractionsAPI()
|
||||||
const componentAPI = useComponentAPI();
|
const componentAPI = useComponentAPI();
|
||||||
|
|
@ -289,20 +288,24 @@ if (!selectedDevice) return;
|
||||||
describeMeasurement(
|
describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_PERCENT,
|
quack.MeasurementType.MEASUREMENT_TYPE_PERCENT,
|
||||||
sensor.settings.type,
|
sensor.settings.type,
|
||||||
sensor.settings.subtype
|
sensor.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toStored(hum)
|
).toStored(hum)
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
conditions.push(humidityCondition);
|
conditions.push(humidityCondition);
|
||||||
|
|
||||||
//since the measurement describers function to stored does a conversion into celsius if the users pref is fahrenheit for temperature we need to convert the preset value into fahrenheit
|
//since the measurement describers function to stored does a conversion into celsius if the users pref is fahrenheit for temperature we need to convert the preset value into fahrenheit
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
temp = Math.round((temp * (9 / 5) + 32) * 100) / 100;
|
temp = Math.round((temp * (9 / 5) + 32) * 100) / 100;
|
||||||
}
|
}
|
||||||
let tempVal = describeMeasurement(
|
let tempVal = describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
||||||
sensor.settings.type,
|
sensor.settings.type,
|
||||||
sensor.settings.subtype
|
sensor.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toStored(temp);
|
).toStored(temp);
|
||||||
|
|
||||||
let tempCondition = pond.InteractionCondition.create({
|
let tempCondition = pond.InteractionCondition.create({
|
||||||
|
|
@ -386,19 +389,23 @@ if (!selectedDevice) return;
|
||||||
value: describeMeasurement(
|
value: describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_PERCENT,
|
quack.MeasurementType.MEASUREMENT_TYPE_PERCENT,
|
||||||
sensor.settings.type,
|
sensor.settings.type,
|
||||||
sensor.settings.subtype
|
sensor.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toStored(humidityPreset)
|
).toStored(humidityPreset)
|
||||||
});
|
});
|
||||||
conditions.push(fanConditionOne);
|
conditions.push(fanConditionOne);
|
||||||
|
|
||||||
//since the measurement describers function toStored does a conversion into celsius for temperature if the users pref is fahrenheit we need to convert the preset value into fahrenheit
|
//since the measurement describers function toStored does a conversion into celsius for temperature if the users pref is fahrenheit we need to convert the preset value into fahrenheit
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
tempPreset = Math.round((tempPreset * (9 / 5) + 32) * 100) / 100;
|
tempPreset = Math.round((tempPreset * (9 / 5) + 32) * 100) / 100;
|
||||||
}
|
}
|
||||||
let tempVal = describeMeasurement(
|
let tempVal = describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
||||||
sensor.settings.type,
|
sensor.settings.type,
|
||||||
sensor.settings.subtype
|
sensor.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toStored(tempPreset);
|
).toStored(tempPreset);
|
||||||
|
|
||||||
let fanConditionTwo = pond.InteractionCondition.create({
|
let fanConditionTwo = pond.InteractionCondition.create({
|
||||||
|
|
@ -631,7 +638,7 @@ if (!selectedDevice) return;
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||||
? "°F"
|
? "°F"
|
||||||
: "℃"}
|
: "℃"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
|
||||||
|
|
@ -346,14 +346,14 @@ export default function BinComponentGraph(props: Props) {
|
||||||
? measurements?.map(um =>
|
? measurements?.map(um =>
|
||||||
areaGraph(
|
areaGraph(
|
||||||
um,
|
um,
|
||||||
describeMeasurement(um.type, component.type(), component.subType()),
|
describeMeasurement(um.type, component.type(), component.subType(), undefined, user),
|
||||||
component.settings.smoothingAverages
|
component.settings.smoothingAverages
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
: measurements?.map(um =>
|
: measurements?.map(um =>
|
||||||
lineGraph(
|
lineGraph(
|
||||||
um,
|
um,
|
||||||
describeMeasurement(um.type, component.type(), component.subType()),
|
describeMeasurement(um.type, component.type(), component.subType(), undefined, user),
|
||||||
component.settings.smoothingAverages
|
component.settings.smoothingAverages
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import { pond } from "protobuf-ts/pond";
|
||||||
import { useBinAPI, useGlobalState } from "providers";
|
import { useBinAPI, useGlobalState } from "providers";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { Legend } from "recharts";
|
import { Legend } from "recharts";
|
||||||
import { getGrainUnit } from "utils";
|
|
||||||
import BinLevelAreaGraph from "./BinLevelAreaGraph";
|
import BinLevelAreaGraph from "./BinLevelAreaGraph";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -32,7 +31,7 @@ interface InventoryAt {
|
||||||
export default function BinLevelOverTime(props: Props) {
|
export default function BinLevelOverTime(props: Props) {
|
||||||
const { bin, fertilizerBin, colour, startDate, endDate, customHeight } = props;
|
const { bin, fertilizerBin, colour, startDate, endDate, customHeight } = props;
|
||||||
const binAPI = useBinAPI();
|
const binAPI = useBinAPI();
|
||||||
const [{as}] = useGlobalState();
|
const [{as, user}] = useGlobalState();
|
||||||
const [inventoryData, setInventoryData] = useState<InventoryAt[]>([]);
|
const [inventoryData, setInventoryData] = useState<InventoryAt[]>([]);
|
||||||
const [dataLoading, setDataLoading] = useState(false);
|
const [dataLoading, setDataLoading] = useState(false);
|
||||||
const [capacity, setCapacity] = useState<number | undefined>();
|
const [capacity, setCapacity] = useState<number | undefined>();
|
||||||
|
|
@ -69,10 +68,10 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
if (fertilizerBin && cap) {
|
if (fertilizerBin && cap) {
|
||||||
cap = cap * 35.239;
|
cap = cap * 35.239;
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && cap) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && cap) {
|
||||||
cap = cap / bin.bushelsPerTonne();
|
cap = cap / bin.bushelsPerTonne();
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
||||||
cap = cap / (bin.bushelsPerTonne()*0.907);
|
cap = cap / (bin.bushelsPerTonne()*0.907);
|
||||||
}
|
}
|
||||||
setCapacity(cap);
|
setCapacity(cap);
|
||||||
|
|
@ -89,10 +88,10 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
let bushels = hist.settings.inventory.grainBushels ?? 0;
|
let bushels = hist.settings.inventory.grainBushels ?? 0;
|
||||||
if (bushels !== lastBushels) {
|
if (bushels !== lastBushels) {
|
||||||
let grainDisplay = bushels
|
let grainDisplay = bushels
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
||||||
grainDisplay = Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100;
|
grainDisplay = Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100;
|
||||||
}
|
}
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
||||||
grainDisplay = Math.round((bushels / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
grainDisplay = Math.round((bushels / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||||
}
|
}
|
||||||
let newData: InventoryAt = {
|
let newData: InventoryAt = {
|
||||||
|
|
@ -121,10 +120,10 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
let bushels = bin.bushels();
|
let bushels = bin.bushels();
|
||||||
let grainDisplay = bushels
|
let grainDisplay = bushels
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
||||||
grainDisplay = Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100;
|
grainDisplay = Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100;
|
||||||
}
|
}
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
||||||
grainDisplay = Math.round((bushels / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
grainDisplay = Math.round((bushels / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||||
}
|
}
|
||||||
data.push({
|
data.push({
|
||||||
|
|
@ -156,10 +155,10 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
if (fertilizerBin && cap) {
|
if (fertilizerBin && cap) {
|
||||||
cap = cap * 35.239;
|
cap = cap * 35.239;
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && cap) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && cap) {
|
||||||
cap = cap / bin.bushelsPerTonne();
|
cap = cap / bin.bushelsPerTonne();
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
||||||
cap = cap / (bin.bushelsPerTonne()*0.907);
|
cap = cap / (bin.bushelsPerTonne()*0.907);
|
||||||
}
|
}
|
||||||
setCapacity(cap);
|
setCapacity(cap);
|
||||||
|
|
@ -180,10 +179,10 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
if (val.values[0] && m.timestamps[i]) {
|
if (val.values[0] && m.timestamps[i]) {
|
||||||
if (lastBushels !== val.values[0]) {
|
if (lastBushels !== val.values[0]) {
|
||||||
let grainDisplay = val.values[0]
|
let grainDisplay = val.values[0]
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
||||||
grainDisplay = Math.round((grainDisplay / bin.bushelsPerTonne()) * 100) / 100;
|
grainDisplay = Math.round((grainDisplay / bin.bushelsPerTonne()) * 100) / 100;
|
||||||
}
|
}
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
||||||
grainDisplay = Math.round((grainDisplay / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
grainDisplay = Math.round((grainDisplay / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||||
}
|
}
|
||||||
autoBarData.push({
|
autoBarData.push({
|
||||||
|
|
@ -199,10 +198,10 @@ export default function BinLevelOverTime(props: Props) {
|
||||||
let bushels = bin.bushels();
|
let bushels = bin.bushels();
|
||||||
let currentTime = moment().valueOf();
|
let currentTime = moment().valueOf();
|
||||||
let grainDisplay = bushels
|
let grainDisplay = bushels
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
||||||
grainDisplay = Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100;
|
grainDisplay = Math.round((bushels / bin.bushelsPerTonne()) * 100) / 100;
|
||||||
}
|
}
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
||||||
grainDisplay = Math.round((bushels / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
grainDisplay = Math.round((bushels / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||||
}
|
}
|
||||||
autoBarData.push({
|
autoBarData.push({
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { colors } from "@mui/material";
|
||||||
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { distanceConversion } from "utils";
|
import { distanceConversion } from "utils";
|
||||||
|
import { useGlobalState } from "providers";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
bin: jsonBin;
|
bin: jsonBin;
|
||||||
|
|
@ -22,6 +23,8 @@ export default function SideView(props: Props) {
|
||||||
const dimensionFontSize = 7;
|
const dimensionFontSize = 7;
|
||||||
const gapSize = svgViewBoxSize * 0.05;
|
const gapSize = svgViewBoxSize * 0.05;
|
||||||
const { bin } = props;
|
const { bin } = props;
|
||||||
|
const [{ user }] = useGlobalState();
|
||||||
|
const distanceUnit = user.distanceUnit();
|
||||||
const [scale, setScale] = useState(0); //the scale to multiply the bin dimension by in order to determine how long to draw the line
|
const [scale, setScale] = useState(0); //the scale to multiply the bin dimension by in order to determine how long to draw the line
|
||||||
const [hopperHeight, setHopperHeight] = useState(0);
|
const [hopperHeight, setHopperHeight] = useState(0);
|
||||||
const [roofHeight, setRoofHeight] = useState(0);
|
const [roofHeight, setRoofHeight] = useState(0);
|
||||||
|
|
@ -194,7 +197,7 @@ export default function SideView(props: Props) {
|
||||||
"bottomText",
|
"bottomText",
|
||||||
svgViewBoxSize / 2,
|
svgViewBoxSize / 2,
|
||||||
y2,
|
y2,
|
||||||
distanceConversion(bin.Diameter).toFixed(1)
|
distanceConversion(bin.Diameter, distanceUnit).toFixed(1)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -231,7 +234,7 @@ export default function SideView(props: Props) {
|
||||||
let y2 = (roofHeight + bin.Sidewall) * scale;
|
let y2 = (roofHeight + bin.Sidewall) * scale;
|
||||||
|
|
||||||
d.push(
|
d.push(
|
||||||
dimensionText("sidewallText", x2, midpoint, distanceConversion(bin.Sidewall).toFixed(1))
|
dimensionText("sidewallText", x2, midpoint, distanceConversion(bin.Sidewall, distanceUnit).toFixed(1))
|
||||||
);
|
);
|
||||||
d.push(
|
d.push(
|
||||||
dimensionPath(
|
dimensionPath(
|
||||||
|
|
@ -270,7 +273,7 @@ export default function SideView(props: Props) {
|
||||||
"peakText",
|
"peakText",
|
||||||
xText,
|
xText,
|
||||||
midpoint,
|
midpoint,
|
||||||
distanceConversion(bin.Sidewall + roofHeight).toFixed(1)
|
distanceConversion(bin.Sidewall + roofHeight, distanceUnit).toFixed(1)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
d.push(
|
d.push(
|
||||||
|
|
@ -313,7 +316,7 @@ export default function SideView(props: Props) {
|
||||||
"totalText",
|
"totalText",
|
||||||
x2,
|
x2,
|
||||||
midpoint,
|
midpoint,
|
||||||
distanceConversion(roofHeight + bin.Sidewall + hopperHeight).toFixed(1)
|
distanceConversion(roofHeight + bin.Sidewall + hopperHeight, distanceUnit).toFixed(1)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
d.push(
|
d.push(
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import {
|
||||||
//import MaterialTable from "material-table";
|
//import MaterialTable from "material-table";
|
||||||
//import { getTableIcons } from "common/ResponsiveTable";
|
//import { getTableIcons } from "common/ResponsiveTable";
|
||||||
import CableDisplay from "./cableDisplay";
|
import CableDisplay from "./cableDisplay";
|
||||||
import { distanceConversion, getDistanceUnit } from "utils";
|
import { distanceConversion } from "utils";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import CableQuote from "./cableQuote";
|
import CableQuote from "./cableQuote";
|
||||||
import { useMobile } from "hooks";
|
import { useMobile } from "hooks";
|
||||||
|
|
@ -33,6 +33,7 @@ import {
|
||||||
} from "common/TrigFunctions";
|
} from "common/TrigFunctions";
|
||||||
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
|
import { useGlobalState } from "providers";
|
||||||
|
|
||||||
const useStyles = makeStyles(() => ({
|
const useStyles = makeStyles(() => ({
|
||||||
sliderThumb: {
|
sliderThumb: {
|
||||||
|
|
@ -56,6 +57,7 @@ export default function CableEstimator() {
|
||||||
//the conversion constant to convert cubic feet to bushels
|
//the conversion constant to convert cubic feet to bushels
|
||||||
const conversionConstantFT = 0.7786;
|
const conversionConstantFT = 0.7786;
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
const [{ user }] = useGlobalState();
|
||||||
const [binOptions, setBinOptions] = useState<jsonBin[]>([]);
|
const [binOptions, setBinOptions] = useState<jsonBin[]>([]);
|
||||||
const [displayedRows, setDisplayedRows] = useState<jsonBin[]>([]);
|
const [displayedRows, setDisplayedRows] = useState<jsonBin[]>([]);
|
||||||
const [tablePage, setTablePage] = useState(0)
|
const [tablePage, setTablePage] = useState(0)
|
||||||
|
|
@ -67,21 +69,21 @@ export default function CableEstimator() {
|
||||||
const [quoteOpen, setQuoteOpen] = useState(false);
|
const [quoteOpen, setQuoteOpen] = useState(false);
|
||||||
const [useCustomBin, setUseCustomBin] = useState(false);
|
const [useCustomBin, setUseCustomBin] = useState(false);
|
||||||
const [diameterFormEntry, setDiameterFormEntry] = useState(
|
const [diameterFormEntry, setDiameterFormEntry] = useState(
|
||||||
getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "9.1" : "30"
|
user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "9.1" : "30"
|
||||||
);
|
);
|
||||||
//const [capacityFormEntry, setCapacityFormEntry] = useState("0");
|
//const [capacityFormEntry, setCapacityFormEntry] = useState("0");
|
||||||
const [ringsFormEntry, setRingsFormEntry] = useState("0");
|
const [ringsFormEntry, setRingsFormEntry] = useState("0");
|
||||||
const [ringHeightFormEntry, setRingHeightFormEntry] = useState("0");
|
const [ringHeightFormEntry, setRingHeightFormEntry] = useState("0");
|
||||||
const [ringHeightFt, setRingHeightFt] = useState(0);
|
const [ringHeightFt, setRingHeightFt] = useState(0);
|
||||||
const [sidewallFormEntry, setSidewallFormEntry] = useState(
|
const [sidewallFormEntry, setSidewallFormEntry] = useState(
|
||||||
getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "7" : "23"
|
user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "7" : "23"
|
||||||
);
|
);
|
||||||
const [peakFormEntry, setPeakFormEntry] = useState(
|
const [peakFormEntry, setPeakFormEntry] = useState(
|
||||||
getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "9.1" : "30"
|
user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "9.1" : "30"
|
||||||
);
|
);
|
||||||
//const [eaveToPeakFormEntry, setEaveToPeakFormEntry] = useState("0");
|
//const [eaveToPeakFormEntry, setEaveToPeakFormEntry] = useState("0");
|
||||||
const [roofAngleFormEntry, setRoofAngleFormEntry] = useState(
|
const [roofAngleFormEntry, setRoofAngleFormEntry] = useState(
|
||||||
getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "7.6" : "25"
|
user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "7.6" : "25"
|
||||||
);
|
);
|
||||||
const [hopperAngleFormEntry, setHopperAngleFormEntry] = useState("0");
|
const [hopperAngleFormEntry, setHopperAngleFormEntry] = useState("0");
|
||||||
const nodeSpacing = 4;
|
const nodeSpacing = 4;
|
||||||
|
|
@ -129,24 +131,40 @@ export default function CableEstimator() {
|
||||||
render: (row: jsonBin) => <Box padding={2}>{row.HopperAngle}</Box>
|
render: (row: jsonBin) => <Box padding={2}>{row.HopperAngle}</Box>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Diameter " + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
title: "Diameter " + (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
||||||
sortKey: "Diameter",
|
sortKey: "Diameter",
|
||||||
render: (row: jsonBin) => <Box padding={2}>{distanceConversion(row.Diameter).toFixed(2)}</Box>
|
render: (row: jsonBin) => (
|
||||||
|
<Box padding={2}>
|
||||||
|
{distanceConversion(row.Diameter, user.distanceUnit()).toFixed(2)}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Sidewall" + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
title: "Sidewall" + (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
||||||
sortKey: "Sidewall",
|
sortKey: "Sidewall",
|
||||||
render: (row: jsonBin) => <Box padding={2}>{distanceConversion(row.Sidewall).toFixed(2)}</Box>
|
render: (row: jsonBin) => (
|
||||||
|
<Box padding={2}>
|
||||||
|
{distanceConversion(row.Sidewall, user.distanceUnit()).toFixed(2)}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Peak Height" + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
title: "Peak Height" + (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
||||||
sortKey: "Peak",
|
sortKey: "Peak",
|
||||||
render: (row: jsonBin) => <Box padding={2}>{distanceConversion(row.Peak).toFixed(2)}</Box>
|
render: (row: jsonBin) => (
|
||||||
|
<Box padding={2}>
|
||||||
|
{distanceConversion(row.Peak, user.distanceUnit()).toFixed(2)}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Eave To Peak" + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
title: "Eave To Peak" + (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
||||||
sortKey: "EaveToPeak",
|
sortKey: "EaveToPeak",
|
||||||
render: (row: jsonBin) => <Box padding={2}>{distanceConversion(row.EaveToPeak).toFixed(2)}</Box>
|
render: (row: jsonBin) => (
|
||||||
|
<Box padding={2}>
|
||||||
|
{distanceConversion(row.EaveToPeak, user.distanceUnit()).toFixed(2)}
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Roof Angle",
|
title: "Roof Angle",
|
||||||
|
|
@ -545,7 +563,7 @@ export default function CableEstimator() {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -554,7 +572,7 @@ export default function CableEstimator() {
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
setDiameterFormEntry(e.target.value);
|
setDiameterFormEntry(e.target.value);
|
||||||
let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
|
let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
val = val * 3.281;
|
val = val * 3.281;
|
||||||
}
|
}
|
||||||
//when the diameter is changed use the current peak height to adjust the roof angle
|
//when the diameter is changed use the current peak height to adjust the roof angle
|
||||||
|
|
@ -577,7 +595,7 @@ export default function CableEstimator() {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -589,7 +607,7 @@ export default function CableEstimator() {
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
setPeakFormEntry(e.target.value);
|
setPeakFormEntry(e.target.value);
|
||||||
let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
|
let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
val = val * 3.281;
|
val = val * 3.281;
|
||||||
}
|
}
|
||||||
//when the peak height is changed use the diameter to calculate the roof angle
|
//when the peak height is changed use the diameter to calculate the roof angle
|
||||||
|
|
@ -621,7 +639,7 @@ export default function CableEstimator() {
|
||||||
//use the new number of rings and ring height to get the sidewall height
|
//use the new number of rings and ring height to get the sidewall height
|
||||||
let sidewallFt = val * ringHeightFt;
|
let sidewallFt = val * ringHeightFt;
|
||||||
bin.Sidewall = sidewallFt;
|
bin.Sidewall = sidewallFt;
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
setSidewallFormEntry((sidewallFt / 3.281).toString());
|
setSidewallFormEntry((sidewallFt / 3.281).toString());
|
||||||
} else {
|
} else {
|
||||||
setSidewallFormEntry(sidewallFt.toString());
|
setSidewallFormEntry(sidewallFt.toString());
|
||||||
|
|
@ -650,7 +668,7 @@ export default function CableEstimator() {
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
setRingHeightFormEntry(e.target.value);
|
setRingHeightFormEntry(e.target.value);
|
||||||
let inVal = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
|
let inVal = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
|
||||||
// if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
// if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
// val = val * 3.281;
|
// val = val * 3.281;
|
||||||
// }
|
// }
|
||||||
let ringFt = inVal / 12;
|
let ringFt = inVal / 12;
|
||||||
|
|
@ -659,7 +677,7 @@ export default function CableEstimator() {
|
||||||
let bin = cloneDeep(customBin);
|
let bin = cloneDeep(customBin);
|
||||||
let sidewallFt = bin.Rings * ringFt;
|
let sidewallFt = bin.Rings * ringFt;
|
||||||
bin.Sidewall = sidewallFt;
|
bin.Sidewall = sidewallFt;
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
setSidewallFormEntry((sidewallFt / 3.281).toString());
|
setSidewallFormEntry((sidewallFt / 3.281).toString());
|
||||||
} else {
|
} else {
|
||||||
setSidewallFormEntry(sidewallFt.toString());
|
setSidewallFormEntry(sidewallFt.toString());
|
||||||
|
|
@ -683,7 +701,7 @@ export default function CableEstimator() {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -694,7 +712,7 @@ export default function CableEstimator() {
|
||||||
setSidewallFormEntry(e.target.value);
|
setSidewallFormEntry(e.target.value);
|
||||||
let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
|
let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
|
||||||
//if the value entered is meters convert it to feet for the bin
|
//if the value entered is meters convert it to feet for the bin
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
val = val * 3.281;
|
val = val * 3.281;
|
||||||
}
|
}
|
||||||
let bin = cloneDeep(customBin);
|
let bin = cloneDeep(customBin);
|
||||||
|
|
@ -733,7 +751,7 @@ export default function CableEstimator() {
|
||||||
let coneHeight = calcConeHeight(bin.Diameter / 2, bin.RoofAngle);
|
let coneHeight = calcConeHeight(bin.Diameter / 2, bin.RoofAngle);
|
||||||
bin.Peak = bin.Sidewall + coneHeight; //assign it as feet
|
bin.Peak = bin.Sidewall + coneHeight; //assign it as feet
|
||||||
let peakHeightDisplay = bin.Sidewall + coneHeight;
|
let peakHeightDisplay = bin.Sidewall + coneHeight;
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
peakHeightDisplay = peakHeightDisplay / 3.281;
|
peakHeightDisplay = peakHeightDisplay / 3.281;
|
||||||
}
|
}
|
||||||
setPeakFormEntry(peakHeightDisplay.toFixed(1));
|
setPeakFormEntry(peakHeightDisplay.toFixed(1));
|
||||||
|
|
@ -762,7 +780,7 @@ export default function CableEstimator() {
|
||||||
let coneHeight = calcConeHeight(bin.Diameter / 2, bin.RoofAngle);
|
let coneHeight = calcConeHeight(bin.Diameter / 2, bin.RoofAngle);
|
||||||
bin.Peak = bin.Sidewall + coneHeight;
|
bin.Peak = bin.Sidewall + coneHeight;
|
||||||
let peakHeightDisplay = bin.Sidewall + coneHeight;
|
let peakHeightDisplay = bin.Sidewall + coneHeight;
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
peakHeightDisplay = peakHeightDisplay / 3.281;
|
peakHeightDisplay = peakHeightDisplay / 3.281;
|
||||||
}
|
}
|
||||||
setPeakFormEntry(peakHeightDisplay.toFixed(1));
|
setPeakFormEntry(peakHeightDisplay.toFixed(1));
|
||||||
|
|
@ -887,7 +905,7 @@ export default function CableEstimator() {
|
||||||
setEaveToPeakFormEntry(e.target.value);
|
setEaveToPeakFormEntry(e.target.value);
|
||||||
let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
|
let val = isNaN(parseFloat(e.target.value)) ? 0 : parseFloat(e.target.value);
|
||||||
//if the value entered is meters convert it to feet for the bin
|
//if the value entered is meters convert it to feet for the bin
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
val = val * 3.281;
|
val = val * 3.281;
|
||||||
}
|
}
|
||||||
let bin = cloneDeep(customBin);
|
let bin = cloneDeep(customBin);
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||||
//import { getTableIcons } from "common/ResponsiveTable";
|
//import { getTableIcons } from "common/ResponsiveTable";
|
||||||
//import MaterialTable from "material-table";
|
//import MaterialTable from "material-table";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useEffect } from "react";
|
import { distanceConversion } from "utils";
|
||||||
import { distanceConversion, getDistanceUnit } from "utils";
|
import { useGlobalState } from "providers";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
bin: jsonBin;
|
bin: jsonBin;
|
||||||
|
|
@ -13,6 +13,7 @@ interface Props {
|
||||||
|
|
||||||
export default function CableMounting(props: Props) {
|
export default function CableMounting(props: Props) {
|
||||||
const { bin } = props;
|
const { bin } = props;
|
||||||
|
const [{ user }] = useGlobalState();
|
||||||
// const [tablePage, setTablePage] = useState(0)
|
// const [tablePage, setTablePage] = useState(0)
|
||||||
// const [pageSize, setPageSize] = useState(10)
|
// const [pageSize, setPageSize] = useState(10)
|
||||||
|
|
||||||
|
|
@ -26,15 +27,19 @@ export default function CableMounting(props: Props) {
|
||||||
render: (row: CableSum) => <Box padding={2}>{row.Orbit === 0 ? "Center" : row.Orbit}</Box>
|
render: (row: CableSum) => <Box padding={2}>{row.Orbit === 0 ? "Center" : row.Orbit}</Box>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "From Center " + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
title: "From Center " + (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
||||||
render: (row: CableSum) => (
|
render: (row: CableSum) => (
|
||||||
<Box padding={2}>{distanceConversion(row.DistanceFromCenter).toFixed(2)}</Box>
|
<Box padding={2}>
|
||||||
|
{distanceConversion(row.DistanceFromCenter, user.distanceUnit()).toFixed(2)}
|
||||||
|
</Box>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Along Roof" + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
title: "Along Roof" + (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
||||||
render: (row: CableSum) => (
|
render: (row: CableSum) => (
|
||||||
<Box padding={2}>{distanceConversion(roofDist(row.DistanceFromCenter)).toFixed(2)}</Box>
|
<Box padding={2}>
|
||||||
|
{distanceConversion(roofDist(row.DistanceFromCenter), user.distanceUnit()).toFixed(2)}
|
||||||
|
</Box>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import ResponsiveDialog from "common/ResponsiveDialog";
|
||||||
import { useMobile } from "hooks";
|
import { useMobile } from "hooks";
|
||||||
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||||
import PdfContent from "./pdfComponents/pdfContent";
|
import PdfContent from "./pdfComponents/pdfContent";
|
||||||
|
import { useGlobalState } from "providers";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
bin: jsonBin;
|
bin: jsonBin;
|
||||||
|
|
@ -14,6 +15,7 @@ interface Props {
|
||||||
|
|
||||||
export default function CableQuote(props: Props) {
|
export default function CableQuote(props: Props) {
|
||||||
const { open, close, bin } = props;
|
const { open, close, bin } = props;
|
||||||
|
const [{user}] = useGlobalState();
|
||||||
const isMobil = useMobile();
|
const isMobil = useMobile();
|
||||||
const pdfStyle = StyleSheet.create({
|
const pdfStyle = StyleSheet.create({
|
||||||
viewerDesktop: {
|
viewerDesktop: {
|
||||||
|
|
@ -27,7 +29,11 @@ export default function CableQuote(props: Props) {
|
||||||
});
|
});
|
||||||
|
|
||||||
const pdfDoc = () => {
|
const pdfDoc = () => {
|
||||||
return <AgPDFTemplate content={<PdfContent bin={bin} />} />;
|
return (
|
||||||
|
<AgPDFTemplate
|
||||||
|
content={<PdfContent bin={bin} distanceUnit={user.distanceUnit()} />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ import { Box, Typography } from "@mui/material";
|
||||||
//import MaterialTable from "material-table";
|
//import MaterialTable from "material-table";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { distanceConversion, getDistanceUnit } from "utils";
|
import { distanceConversion } from "utils";
|
||||||
|
import { useGlobalState } from "providers";
|
||||||
import { Cable, jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
import { Cable, jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||||
|
|
@ -15,17 +16,19 @@ interface Props {
|
||||||
|
|
||||||
export default function CableTable(props: Props) {
|
export default function CableTable(props: Props) {
|
||||||
const { bin, /*cablesChanged*/ } = props;
|
const { bin, /*cablesChanged*/ } = props;
|
||||||
|
const [{ user }] = useGlobalState();
|
||||||
//const nodeSpacing = 4; //space between the nodes in feet
|
//const nodeSpacing = 4; //space between the nodes in feet
|
||||||
|
|
||||||
const [cableData, setCableData] = useState(bin.Cables);
|
const [cableData, setCableData] = useState(bin.Cables);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let convertedCables: Cable[] = cloneDeep(bin.Cables);
|
let convertedCables: Cable[] = cloneDeep(bin.Cables);
|
||||||
|
const du = user.distanceUnit();
|
||||||
convertedCables.forEach(cable => {
|
convertedCables.forEach(cable => {
|
||||||
cable.Length = Math.round(distanceConversion(cable.Length) * 100) / 100;
|
cable.Length = Math.round(distanceConversion(cable.Length, du) * 100) / 100;
|
||||||
});
|
});
|
||||||
setCableData(convertedCables);
|
setCableData(convertedCables);
|
||||||
}, [bin]);
|
}, [bin, user]);
|
||||||
|
|
||||||
// const table = () => {
|
// const table = () => {
|
||||||
// return (
|
// return (
|
||||||
|
|
@ -116,7 +119,7 @@ export default function CableTable(props: Props) {
|
||||||
render: (row) => <Box padding={2}>{row.Count}</Box>
|
render: (row) => <Box padding={2}>{row.Count}</Box>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Length" + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
title: "Length" + (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"),
|
||||||
render: (row) => <Box padding={2}>{row.Length}</Box>
|
render: (row) => <Box padding={2}>{row.Length}</Box>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { getDistanceUnit } from "utils";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
borderColour: string;
|
borderColour: string;
|
||||||
|
distanceUnit: pond.DistanceUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CableTableHeader(props: Props) {
|
export default function CableTableHeader(props: Props) {
|
||||||
|
|
@ -35,7 +35,8 @@ export default function CableTableHeader(props: Props) {
|
||||||
<Text style={styles.cell}>Type</Text>
|
<Text style={styles.cell}>Type</Text>
|
||||||
<Text style={styles.cell}>Qty</Text>
|
<Text style={styles.cell}>Qty</Text>
|
||||||
<Text style={styles.cell}>
|
<Text style={styles.cell}>
|
||||||
Length {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"}
|
Length{" "}
|
||||||
|
{props.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.endCell}>Nodes</Text>
|
<Text style={styles.endCell}>Nodes</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,12 @@ import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
||||||
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { distanceConversion } from "utils";
|
import { distanceConversion } from "utils";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
bin: jsonBin;
|
bin: jsonBin;
|
||||||
borderColour: string;
|
borderColour: string;
|
||||||
|
distanceUnit: pond.DistanceUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CableTableRow(props: Props) {
|
export default function CableTableRow(props: Props) {
|
||||||
|
|
@ -48,7 +50,9 @@ export default function CableTableRow(props: Props) {
|
||||||
<Text style={styles.cell}>{cable.Orbit === 0 ? "Center" : cable.Orbit}</Text>
|
<Text style={styles.cell}>{cable.Orbit === 0 ? "Center" : cable.Orbit}</Text>
|
||||||
<Text style={styles.cell}>{cable.Type === 2 ? "Moisture" : "Temperature"}</Text>
|
<Text style={styles.cell}>{cable.Type === 2 ? "Moisture" : "Temperature"}</Text>
|
||||||
<Text style={styles.cell}>{cable.Count}</Text>
|
<Text style={styles.cell}>{cable.Count}</Text>
|
||||||
<Text style={styles.cell}>{distanceConversion(cable.Length).toFixed(2)}</Text>
|
<Text style={styles.cell}>
|
||||||
|
{distanceConversion(cable.Length, props.distanceUnit).toFixed(2)}
|
||||||
|
</Text>
|
||||||
<Text style={styles.endCell}>{cable.Nodes}</Text>
|
<Text style={styles.endCell}>{cable.Nodes}</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { getDistanceUnit } from "utils";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
borderColour: string;
|
borderColour: string;
|
||||||
|
distanceUnit: pond.DistanceUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MountingTableHeader(props: Props) {
|
export default function MountingTableHeader(props: Props) {
|
||||||
|
|
@ -43,10 +43,12 @@ export default function MountingTableHeader(props: Props) {
|
||||||
<View style={styles.view}>
|
<View style={styles.view}>
|
||||||
<Text style={styles.orbit}>Orbit</Text>
|
<Text style={styles.orbit}>Orbit</Text>
|
||||||
<Text style={styles.centerDist}>
|
<Text style={styles.centerDist}>
|
||||||
Radius {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"}
|
Radius{" "}
|
||||||
|
{props.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.roofDist}>
|
<Text style={styles.roofDist}>
|
||||||
Along Roof {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"}
|
Along Roof{" "}
|
||||||
|
{props.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.bracket}>Bracket</Text>
|
<Text style={styles.bracket}>Bracket</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,12 @@ import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
||||||
import { getBracket, jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
import { getBracket, jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { distanceConversion } from "utils";
|
import { distanceConversion } from "utils";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
bin: jsonBin;
|
bin: jsonBin;
|
||||||
borderColour: string;
|
borderColour: string;
|
||||||
|
distanceUnit: pond.DistanceUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MountingTableRow(props: Props) {
|
export default function MountingTableRow(props: Props) {
|
||||||
|
|
@ -65,10 +67,10 @@ export default function MountingTableRow(props: Props) {
|
||||||
key={i}>
|
key={i}>
|
||||||
<Text style={styles.orbit}>{orbit.Orbit === 0 ? "C" : orbit.Orbit}</Text>
|
<Text style={styles.orbit}>{orbit.Orbit === 0 ? "C" : orbit.Orbit}</Text>
|
||||||
<Text style={styles.centerDist}>
|
<Text style={styles.centerDist}>
|
||||||
{distanceConversion(orbit.DistanceFromCenter).toFixed(2)}
|
{distanceConversion(orbit.DistanceFromCenter, props.distanceUnit).toFixed(2)}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.roofDist}>
|
<Text style={styles.roofDist}>
|
||||||
{distanceConversion(roofDist(orbit.DistanceFromCenter)).toFixed(2)}
|
{distanceConversion(roofDist(orbit.DistanceFromCenter), props.distanceUnit).toFixed(2)}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.bracket}>
|
<Text style={styles.bracket}>
|
||||||
{bracketType}
|
{bracketType}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
||||||
import { colors } from "@mui/material";
|
import { colors } from "@mui/material";
|
||||||
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
import CableTableHeader from "./cableTable/cableTableHeader";
|
import CableTableHeader from "./cableTable/cableTableHeader";
|
||||||
import CableTableRow from "./cableTable/cableTableRow";
|
import CableTableRow from "./cableTable/cableTableRow";
|
||||||
import PDFSideView from "./pdfSVG/pdfSideView";
|
import PDFSideView from "./pdfSVG/pdfSideView";
|
||||||
|
|
@ -10,9 +11,11 @@ import MountingTableRow from "./mountingTable/mountingTableRows";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
bin: jsonBin;
|
bin: jsonBin;
|
||||||
|
distanceUnit: pond.DistanceUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PdfContent(props: Props) {
|
export default function PdfContent(props: Props) {
|
||||||
|
const { distanceUnit } = props;
|
||||||
const tableBorderColour = colors.grey[800];
|
const tableBorderColour = colors.grey[800];
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
|
@ -53,7 +56,7 @@ export default function PdfContent(props: Props) {
|
||||||
</View>
|
</View>
|
||||||
<View style={{ height: 280, flexDirection: "row" }}>
|
<View style={{ height: 280, flexDirection: "row" }}>
|
||||||
<View style={{ width: 260 }}>
|
<View style={{ width: 260 }}>
|
||||||
<PDFSideView bin={props.bin} />
|
<PDFSideView bin={props.bin} distanceUnit={distanceUnit} />
|
||||||
</View>
|
</View>
|
||||||
<View style={{ width: 260 }}>
|
<View style={{ width: 260 }}>
|
||||||
<View style={{ height: 195 }}>
|
<View style={{ height: 195 }}>
|
||||||
|
|
@ -63,8 +66,12 @@ export default function PdfContent(props: Props) {
|
||||||
<Text style={{ fontFamily: "Helvetica-Bold", marginBottom: 5 }}>Install Guide</Text>
|
<Text style={{ fontFamily: "Helvetica-Bold", marginBottom: 5 }}>Install Guide</Text>
|
||||||
<View
|
<View
|
||||||
style={{ borderColor: tableBorderColour, borderWidth: 1, flexDirection: "column" }}>
|
style={{ borderColor: tableBorderColour, borderWidth: 1, flexDirection: "column" }}>
|
||||||
<MountingTableHeader borderColour={tableBorderColour} />
|
<MountingTableHeader borderColour={tableBorderColour} distanceUnit={distanceUnit} />
|
||||||
<MountingTableRow borderColour={tableBorderColour} bin={props.bin} />
|
<MountingTableRow
|
||||||
|
borderColour={tableBorderColour}
|
||||||
|
bin={props.bin}
|
||||||
|
distanceUnit={distanceUnit}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
@ -73,8 +80,12 @@ export default function PdfContent(props: Props) {
|
||||||
Recommended Cables
|
Recommended Cables
|
||||||
</Text>
|
</Text>
|
||||||
<View style={styles.cableTable}>
|
<View style={styles.cableTable}>
|
||||||
<CableTableHeader borderColour={tableBorderColour} />
|
<CableTableHeader borderColour={tableBorderColour} distanceUnit={distanceUnit} />
|
||||||
<CableTableRow bin={props.bin} borderColour={tableBorderColour} />
|
<CableTableRow
|
||||||
|
bin={props.bin}
|
||||||
|
borderColour={tableBorderColour}
|
||||||
|
distanceUnit={distanceUnit}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
import { colors } from "@mui/material";
|
import { colors } from "@mui/material";
|
||||||
import { Circle, Line, Path, Svg, Text } from "@react-pdf/renderer";
|
import { Circle, Line, Path, Svg, Text } from "@react-pdf/renderer";
|
||||||
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { distanceConversion } from "utils";
|
import { distanceConversion } from "utils";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
bin: jsonBin;
|
bin: jsonBin;
|
||||||
|
distanceUnit: pond.DistanceUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface svgPoint {
|
interface svgPoint {
|
||||||
|
|
@ -22,7 +24,7 @@ export default function PDFSideView(props: Props) {
|
||||||
const nodeSpacing = 4; //space in feet between the nodes
|
const nodeSpacing = 4; //space in feet between the nodes
|
||||||
const dimensionFontSize = 18;
|
const dimensionFontSize = 18;
|
||||||
const gapSize = svgViewBoxSize * 0.05;
|
const gapSize = svgViewBoxSize * 0.05;
|
||||||
const { bin } = props;
|
const { bin, distanceUnit } = props;
|
||||||
const [scale, setScale] = useState(0); //the scale to multiply the bin dimension by in order to determine how long to draw the line
|
const [scale, setScale] = useState(0); //the scale to multiply the bin dimension by in order to determine how long to draw the line
|
||||||
const [hopperHeight, setHopperHeight] = useState(0);
|
const [hopperHeight, setHopperHeight] = useState(0);
|
||||||
const [roofHeight, setRoofHeight] = useState(0);
|
const [roofHeight, setRoofHeight] = useState(0);
|
||||||
|
|
@ -194,7 +196,7 @@ export default function PDFSideView(props: Props) {
|
||||||
"bottomText",
|
"bottomText",
|
||||||
svgViewBoxSize / 2,
|
svgViewBoxSize / 2,
|
||||||
y2,
|
y2,
|
||||||
distanceConversion(bin.Diameter).toFixed(1)
|
distanceConversion(bin.Diameter, distanceUnit).toFixed(1)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -231,7 +233,12 @@ export default function PDFSideView(props: Props) {
|
||||||
let y2 = (roofHeight + bin.Sidewall) * scale;
|
let y2 = (roofHeight + bin.Sidewall) * scale;
|
||||||
|
|
||||||
d.push(
|
d.push(
|
||||||
dimensionText("sidewallText", x2, midpoint, distanceConversion(bin.Sidewall).toFixed(1))
|
dimensionText(
|
||||||
|
"sidewallText",
|
||||||
|
x2,
|
||||||
|
midpoint,
|
||||||
|
distanceConversion(bin.Sidewall, distanceUnit).toFixed(1)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
d.push(
|
d.push(
|
||||||
dimensionPath(
|
dimensionPath(
|
||||||
|
|
@ -270,7 +277,7 @@ export default function PDFSideView(props: Props) {
|
||||||
"peakText",
|
"peakText",
|
||||||
xText,
|
xText,
|
||||||
midpoint,
|
midpoint,
|
||||||
distanceConversion(bin.Sidewall + roofHeight).toFixed(1)
|
distanceConversion(bin.Sidewall + roofHeight, distanceUnit).toFixed(1)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
d.push(
|
d.push(
|
||||||
|
|
@ -313,7 +320,7 @@ export default function PDFSideView(props: Props) {
|
||||||
"totalText",
|
"totalText",
|
||||||
x2,
|
x2,
|
||||||
midpoint,
|
midpoint,
|
||||||
distanceConversion(roofHeight + bin.Sidewall + hopperHeight).toFixed(1)
|
distanceConversion(roofHeight + bin.Sidewall + hopperHeight, distanceUnit).toFixed(1)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
d.push(
|
d.push(
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ export default function MeasurementsChart(props: Props) {
|
||||||
const [currentMax, setCurrentMax] = useState<number | string>("dataMax");
|
const [currentMax, setCurrentMax] = useState<number | string>("dataMax");
|
||||||
const [newChart, setNewChart] = useState(false);
|
const [newChart, setNewChart] = useState(false);
|
||||||
const [xDomain, setXDomain] = useState<string[] | number[]>(["dataMin", "dataMax"]);
|
const [xDomain, setXDomain] = useState<string[] | number[]>(["dataMin", "dataMax"]);
|
||||||
const [{ showErrors }, dispatch] = useGlobalState();
|
const [{ showErrors, user }, dispatch] = useGlobalState();
|
||||||
const isMobile = useMobile();
|
const isMobile = useMobile();
|
||||||
// const [zoomStart, setZoomStart] = useState<Moment>();
|
// const [zoomStart, setZoomStart] = useState<Moment>();
|
||||||
// const [zoomEnd, setZoomEnd] = useState<Moment>();
|
// const [zoomEnd, setZoomEnd] = useState<Moment>();
|
||||||
|
|
@ -123,7 +123,7 @@ export default function MeasurementsChart(props: Props) {
|
||||||
if (filters?.selectedInteractions?.includes(interaction.key())) {
|
if (filters?.selectedInteractions?.includes(interaction.key())) {
|
||||||
interaction.settings.conditions.forEach((condition, j) => {
|
interaction.settings.conditions.forEach((condition, j) => {
|
||||||
if (condition.measurementType === measurementType) {
|
if (condition.measurementType === measurementType) {
|
||||||
let describer = describeMeasurement(condition.measurementType);
|
let describer = describeMeasurement(condition.measurementType, undefined, undefined, undefined, user);
|
||||||
selectedInteractions.push(
|
selectedInteractions.push(
|
||||||
<ReferenceLine
|
<ReferenceLine
|
||||||
key={interaction.key() + ":condition" + j}
|
key={interaction.key() + ":condition" + j}
|
||||||
|
|
@ -197,7 +197,9 @@ export default function MeasurementsChart(props: Props) {
|
||||||
let describer = describeMeasurement(
|
let describer = describeMeasurement(
|
||||||
m.type,
|
m.type,
|
||||||
component.settings.type,
|
component.settings.type,
|
||||||
component.settings.subtype
|
component.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
);
|
);
|
||||||
let min: string | number = "dataMin";
|
let min: string | number = "dataMin";
|
||||||
let max: string | number = "dataMax";
|
let max: string | number = "dataMax";
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,12 @@ interface Props {
|
||||||
multiGraphZoom?: (domain: number[] | string[]) => void;
|
multiGraphZoom?: (domain: number[] | string[]) => void;
|
||||||
colourAboveZero?: ColourData
|
colourAboveZero?: ColourData
|
||||||
colourBelowZero?: ColourData
|
colourBelowZero?: ColourData
|
||||||
|
minY?: string | number
|
||||||
|
maxY?: string | number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SingleSetAreaChart(props: Props) {
|
export default function SingleSetAreaChart(props: Props) {
|
||||||
const { data, maxRef, minRef, newXDomain, multiGraphZoom, yAxisLabel, colourAboveZero, colourBelowZero, tooltipLabel, tooltipUnit } = props;
|
const { data, maxRef, minRef, newXDomain, multiGraphZoom, yAxisLabel, colourAboveZero, colourBelowZero, tooltipLabel, tooltipUnit, minY, maxY } = props;
|
||||||
const [xDomain, setXDomain] = useState<string[] | number[]>(["dataMin", "dataMax"]);
|
const [xDomain, setXDomain] = useState<string[] | number[]>(["dataMin", "dataMax"]);
|
||||||
const [refLeft, setRefLeft] = useState<number | undefined>();
|
const [refLeft, setRefLeft] = useState<number | undefined>();
|
||||||
const [refRight, setRefRight] = useState<number | undefined>();
|
const [refRight, setRefRight] = useState<number | undefined>();
|
||||||
|
|
@ -152,7 +154,8 @@ export default function SingleSetAreaChart(props: Props) {
|
||||||
/>
|
/>
|
||||||
<YAxis
|
<YAxis
|
||||||
type="number"
|
type="number"
|
||||||
domain={["auto", "auto"]}
|
allowDataOverflow
|
||||||
|
domain={[minY ?? "auto", maxY ?? "auto"]}
|
||||||
label={{
|
label={{
|
||||||
value: yAxisLabel,
|
value: yAxisLabel,
|
||||||
position: "insideLeft",
|
position: "insideLeft",
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,11 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
localStorage.setItem(filterKey, JSON.stringify(filterList));
|
localStorage.setItem(filterKey, JSON.stringify(filterList));
|
||||||
}, [filterList])
|
}, [filterList])
|
||||||
|
|
||||||
|
const headerColSpan =
|
||||||
|
(columns?.length ?? ((rows?.[0] && Object.keys(rows[0]).length) || 0)) +
|
||||||
|
(rowSelect ? 1 : 0) +
|
||||||
|
(renderGutter ? 1 : 0);
|
||||||
|
|
||||||
const openColumnMenu = (event: any) => {
|
const openColumnMenu = (event: any) => {
|
||||||
setColumnAnchor(event.currentTarget);
|
setColumnAnchor(event.currentTarget);
|
||||||
// setUserMenuIsOpen(true);
|
// setUserMenuIsOpen(true);
|
||||||
|
|
@ -614,7 +619,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
||||||
<TableHead className={stickyHeader ? classes.stickyHeader : undefined}>
|
<TableHead className={stickyHeader ? classes.stickyHeader : undefined}>
|
||||||
{customElement &&
|
{customElement &&
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={10000} sx={{ border: "none" }}>
|
<TableCell colSpan={headerColSpan} sx={{ border: "none" }}>
|
||||||
{customElement}
|
{customElement}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ import { bestUnit, milliToX } from "common/time/duration";
|
||||||
import { useGlobalState } from "providers";
|
import { useGlobalState } from "providers";
|
||||||
import { green, red } from "@mui/material/colors";
|
import { green, red } from "@mui/material/colors";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import { getDistanceUnit } from "utils";
|
|
||||||
import { GrainOptions } from "grain";
|
import { GrainOptions } from "grain";
|
||||||
import CompModes from "component/ComponentMode.json";
|
import CompModes from "component/ComponentMode.json";
|
||||||
import FanPicker from "fans/fanPicker";
|
import FanPicker from "fans/fanPicker";
|
||||||
|
|
@ -146,7 +145,9 @@ export default function ComponentForm(props: Props) {
|
||||||
let describer = describeMeasurement(
|
let describer = describeMeasurement(
|
||||||
primaryMeasurement(formComponent.settings.type),
|
primaryMeasurement(formComponent.settings.type),
|
||||||
formComponent.settings.type,
|
formComponent.settings.type,
|
||||||
formComponent.settings.subtype
|
formComponent.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
);
|
);
|
||||||
let offset = describer.toDisplay(formComponent.settings.calibrationOffset);
|
let offset = describer.toDisplay(formComponent.settings.calibrationOffset);
|
||||||
let formCoefficients: string[] = [];
|
let formCoefficients: string[] = [];
|
||||||
|
|
@ -177,11 +178,11 @@ export default function ComponentForm(props: Props) {
|
||||||
let width = formComponent.settings.containerDimensions?.widthCm ?? 0;
|
let width = formComponent.settings.containerDimensions?.widthCm ?? 0;
|
||||||
let height = formComponent.settings.containerDimensions?.heightCm ?? 0;
|
let height = formComponent.settings.containerDimensions?.heightCm ?? 0;
|
||||||
|
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
length = length / 100;
|
length = length / 100;
|
||||||
width = width / 100;
|
width = width / 100;
|
||||||
height = height / 100;
|
height = height / 100;
|
||||||
} else if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
} else if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
length = length / 30.48;
|
length = length / 30.48;
|
||||||
width = width / 30.48;
|
width = width / 30.48;
|
||||||
height = height / 30.48;
|
height = height / 30.48;
|
||||||
|
|
@ -189,9 +190,9 @@ export default function ComponentForm(props: Props) {
|
||||||
|
|
||||||
let sensorDistance = formComponent.settings.sensorDistanceCm ?? 0;
|
let sensorDistance = formComponent.settings.sensorDistanceCm ?? 0;
|
||||||
|
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
sensorDistance = sensorDistance / 100;
|
sensorDistance = sensorDistance / 100;
|
||||||
} else if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
} else if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
sensorDistance = sensorDistance / 30.48;
|
sensorDistance = sensorDistance / 30.48;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -481,7 +482,9 @@ export default function ComponentForm(props: Props) {
|
||||||
f.component.settings.calibrationOffset = describeMeasurement(
|
f.component.settings.calibrationOffset = describeMeasurement(
|
||||||
primaryMeasurement(f.component.settings.type),
|
primaryMeasurement(f.component.settings.type),
|
||||||
f.component.settings.type,
|
f.component.settings.type,
|
||||||
f.component.settings.subtype
|
f.component.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toStored(+event.target.value);
|
).toStored(+event.target.value);
|
||||||
}
|
}
|
||||||
setForm(f);
|
setForm(f);
|
||||||
|
|
@ -494,7 +497,9 @@ export default function ComponentForm(props: Props) {
|
||||||
f.component.settings.calibrations[index].calibrationOffset = describeMeasurement(
|
f.component.settings.calibrations[index].calibrationOffset = describeMeasurement(
|
||||||
primaryMeasurement(f.component.settings.type),
|
primaryMeasurement(f.component.settings.type),
|
||||||
f.component.settings.type,
|
f.component.settings.type,
|
||||||
f.component.settings.subtype
|
f.component.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toStored(+event.target.value);
|
).toStored(+event.target.value);
|
||||||
}
|
}
|
||||||
setForm(f);
|
setForm(f);
|
||||||
|
|
@ -520,9 +525,9 @@ export default function ComponentForm(props: Props) {
|
||||||
if (!isNaN(Number(event.target.value))) {
|
if (!isNaN(Number(event.target.value))) {
|
||||||
let dimensions = f.component.settings.containerDimensions;
|
let dimensions = f.component.settings.containerDimensions;
|
||||||
let value = Number(event.target.value);
|
let value = Number(event.target.value);
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
value = value * 100;
|
value = value * 100;
|
||||||
} else if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
} else if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
value = value * 30.48;
|
value = value * 30.48;
|
||||||
}
|
}
|
||||||
if (dimensions !== undefined && dimensions !== null) {
|
if (dimensions !== undefined && dimensions !== null) {
|
||||||
|
|
@ -549,9 +554,9 @@ export default function ComponentForm(props: Props) {
|
||||||
if (!isNaN(Number(event.target.value))) {
|
if (!isNaN(Number(event.target.value))) {
|
||||||
let dimensions = f.component.settings.containerDimensions;
|
let dimensions = f.component.settings.containerDimensions;
|
||||||
let value = Number(event.target.value);
|
let value = Number(event.target.value);
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
value = value * 100;
|
value = value * 100;
|
||||||
} else if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
} else if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
value = value * 30.48;
|
value = value * 30.48;
|
||||||
}
|
}
|
||||||
if (dimensions !== undefined && dimensions !== null) {
|
if (dimensions !== undefined && dimensions !== null) {
|
||||||
|
|
@ -578,9 +583,9 @@ export default function ComponentForm(props: Props) {
|
||||||
if (!isNaN(Number(event.target.value))) {
|
if (!isNaN(Number(event.target.value))) {
|
||||||
let dimensions = f.component.settings.containerDimensions;
|
let dimensions = f.component.settings.containerDimensions;
|
||||||
let value = Number(event.target.value);
|
let value = Number(event.target.value);
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
value = value * 100;
|
value = value * 100;
|
||||||
} else if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
} else if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
value = value * 30.48;
|
value = value * 30.48;
|
||||||
}
|
}
|
||||||
if (dimensions !== undefined && dimensions !== null) {
|
if (dimensions !== undefined && dimensions !== null) {
|
||||||
|
|
@ -606,9 +611,9 @@ export default function ComponentForm(props: Props) {
|
||||||
f.sensorDistance = event.target.value;
|
f.sensorDistance = event.target.value;
|
||||||
if (!isNaN(Number(event.target.value))) {
|
if (!isNaN(Number(event.target.value))) {
|
||||||
let value = Number(event.target.value);
|
let value = Number(event.target.value);
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
value = value * 100;
|
value = value * 100;
|
||||||
} else if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
} else if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
value = value * 30.48;
|
value = value * 30.48;
|
||||||
}
|
}
|
||||||
f.component.settings.sensorDistanceCm = value;
|
f.component.settings.sensorDistanceCm = value;
|
||||||
|
|
@ -732,7 +737,9 @@ export default function ComponentForm(props: Props) {
|
||||||
{describeMeasurement(
|
{describeMeasurement(
|
||||||
primaryMeasurement(component.settings.type),
|
primaryMeasurement(component.settings.type),
|
||||||
component.settings.type,
|
component.settings.type,
|
||||||
component.settings.subtype
|
component.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).unit()}
|
).unit()}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
|
|
@ -824,7 +831,7 @@ export default function ComponentForm(props: Props) {
|
||||||
|
|
||||||
const describeSource = (measurementType: quack.MeasurementType): MeasurementDescriber => {
|
const describeSource = (measurementType: quack.MeasurementType): MeasurementDescriber => {
|
||||||
const { component } = form;
|
const { component } = form;
|
||||||
return describeMeasurement(measurementType, component.type(), component.subType());
|
return describeMeasurement(measurementType, component.type(), component.subType(), undefined, user);
|
||||||
};
|
};
|
||||||
|
|
||||||
const availableMeasurementTypes = (type: quack.ComponentType): quack.MeasurementType[] => {
|
const availableMeasurementTypes = (type: quack.ComponentType): quack.MeasurementType[] => {
|
||||||
|
|
@ -1252,7 +1259,7 @@ export default function ComponentForm(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||||
? "m"
|
? "m"
|
||||||
: "ft"}
|
: "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -1276,7 +1283,7 @@ export default function ComponentForm(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||||
? "m"
|
? "m"
|
||||||
: "ft"}
|
: "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -1300,7 +1307,7 @@ export default function ComponentForm(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||||
? "m"
|
? "m"
|
||||||
: "ft"}
|
: "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -1328,7 +1335,7 @@ export default function ComponentForm(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,7 @@ class ExportDataSettings extends React.Component<Props, State> {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
formatMeasurements(measurements: Array<pond.Measurement>): Promise<Array<any>> {
|
formatMeasurements(measurements: Array<pond.Measurement>): Promise<Array<any>> {
|
||||||
const { device, component } = this.props;
|
const { device, component, user } = this.props;
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
if (!measurements) reject("Invalid measurements");
|
if (!measurements) reject("Invalid measurements");
|
||||||
|
|
@ -237,7 +237,9 @@ class ExportDataSettings extends React.Component<Props, State> {
|
||||||
let unit = describeMeasurement(
|
let unit = describeMeasurement(
|
||||||
componentMeasurement.measurementType,
|
componentMeasurement.measurementType,
|
||||||
component.settings.type,
|
component.settings.type,
|
||||||
component.settings.subtype
|
component.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).unit();
|
).unit();
|
||||||
let key = componentMeasurement.label + " (" + unit + ")";
|
let key = componentMeasurement.label + " (" + unit + ")";
|
||||||
row[key] = componentMeasurement.extract(measurement.measurement);
|
row[key] = componentMeasurement.extract(measurement.measurement);
|
||||||
|
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
import { Box, Card, Typography, useTheme } from "@mui/material";
|
|
||||||
import GrainDescriber from "grain/GrainDescriber";
|
|
||||||
import { Contract } from "models/Contract";
|
|
||||||
import { Label, Pie, PieChart, ResponsiveContainer, Text } from "recharts";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
contract: Contract;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ContractVisualizer(props: Props) {
|
|
||||||
const { contract } = props;
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card style={{ height: "100%", padding: 10 }}>
|
|
||||||
<Box height={"15%"}>
|
|
||||||
<Typography style={{ fontWeight: 650, fontSize: 20 }}>
|
|
||||||
{GrainDescriber(contract.grain()).name}
|
|
||||||
</Typography>
|
|
||||||
<Typography style={{ fontWeight: 650, fontSize: 15 }}>
|
|
||||||
{contract.deliveredInPreferredUnit().toFixed(2)}/
|
|
||||||
{contract.sizeInPreferredUnit().toFixed(2)} {contract.unit}
|
|
||||||
</Typography>
|
|
||||||
</Box>
|
|
||||||
<ResponsiveContainer height={"85%"}>
|
|
||||||
<PieChart>
|
|
||||||
{/* <Legend
|
|
||||||
verticalAlign="bottom"
|
|
||||||
content={() => (
|
|
||||||
<Box textAlign="center" marginY={0.5}>
|
|
||||||
<Chip label={contract.commodityLabel()} />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
/> */}
|
|
||||||
<Pie
|
|
||||||
outerRadius={"100%"}
|
|
||||||
innerRadius="70%"
|
|
||||||
stroke="transparent"
|
|
||||||
data={[
|
|
||||||
{
|
|
||||||
name: "",
|
|
||||||
value: contract.settings.delivered,
|
|
||||||
fill: contract.colour
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "",
|
|
||||||
value: contract.settings.size - contract.settings.delivered
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
dataKey="value"
|
|
||||||
cx="50%"
|
|
||||||
cy="50%">
|
|
||||||
<Label
|
|
||||||
position="center"
|
|
||||||
fill={theme.palette.text.secondary}
|
|
||||||
fontSize={"2rem"}
|
|
||||||
fontWeight={650}
|
|
||||||
content={props => {
|
|
||||||
const { cx, cy } = props.viewBox as any;
|
|
||||||
return (
|
|
||||||
<g>
|
|
||||||
<Text
|
|
||||||
x={cx}
|
|
||||||
y={cy}
|
|
||||||
dy={-15}
|
|
||||||
textAnchor="middle"
|
|
||||||
verticalAnchor="middle"
|
|
||||||
fill={props.fill}
|
|
||||||
fontWeight={props.fontWeight}
|
|
||||||
fontSize={props.fontSize}>
|
|
||||||
{((contract.settings.delivered / contract.settings.size) * 100).toFixed(1) +
|
|
||||||
"%"}
|
|
||||||
</Text>
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Label
|
|
||||||
position="center"
|
|
||||||
fill={theme.palette.text.secondary}
|
|
||||||
fontSize={"1.5rem"}
|
|
||||||
fontWeight={650}
|
|
||||||
content={props => {
|
|
||||||
const { cx, cy } = props.viewBox as any;
|
|
||||||
return (
|
|
||||||
<g>
|
|
||||||
<Text
|
|
||||||
x={cx}
|
|
||||||
y={cy}
|
|
||||||
dy={15}
|
|
||||||
textAnchor="middle"
|
|
||||||
verticalAnchor="middle"
|
|
||||||
fill={props.fill}
|
|
||||||
fontWeight={props.fontWeight}
|
|
||||||
fontSize={props.fontSize}>
|
|
||||||
Delivered
|
|
||||||
</Text>
|
|
||||||
</g>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Pie>
|
|
||||||
</PieChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -60,7 +60,7 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
export default function ContractsList(props: Props) {
|
export default function ContractsList(props: Props) {
|
||||||
const { contracts, contractPermissions, updateList } = props;
|
const { contracts, contractPermissions, updateList } = props;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [{as}] = useGlobalState();
|
const [{as, user}] = useGlobalState();
|
||||||
//will need map for contracts that have supported grain types
|
//will need map for contracts that have supported grain types
|
||||||
const [supportedTypes, setSupportedTypes] = useState<Map<pond.Grain, Contract[]>>(new Map());
|
const [supportedTypes, setSupportedTypes] = useState<Map<pond.Grain, Contract[]>>(new Map());
|
||||||
//will need need map for custom contracts
|
//will need need map for custom contracts
|
||||||
|
|
@ -173,16 +173,16 @@ export default function ContractsList(props: Props) {
|
||||||
<TableCell>{contract.name()}</TableCell>
|
<TableCell>{contract.name()}</TableCell>
|
||||||
<TableCell>{contract.settings.contractDate}</TableCell>
|
<TableCell>{contract.settings.contractDate}</TableCell>
|
||||||
<TableCell>{contract.settings.deliveryWindow?.endDate}</TableCell>
|
<TableCell>{contract.settings.deliveryWindow?.endDate}</TableCell>
|
||||||
<TableCell>{contract.sizeInPreferredUnit() + " " + contract.unit}</TableCell>
|
<TableCell>{contract.sizeInPreferredUnit(user) + " " + contract.unit}</TableCell>
|
||||||
<TableCell>{contract.deliveredInPreferredUnit() + " " + contract.unit}</TableCell>
|
<TableCell>{contract.deliveredInPreferredUnit(user) + " " + contract.unit}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{/* <progress value={contract.settings.delivered} max={contract.settings.size} style={{height: 10}}/> */}
|
{/* <progress value={contract.settings.delivered} max={contract.settings.size} style={{height: 10}}/> */}
|
||||||
<CustomProgressBar colour={colors.blue[500]} completed={fillPercent} />
|
<CustomProgressBar colour={colors.blue[500]} completed={fillPercent} />
|
||||||
{/* {((contract.settings.delivered/contract.settings.size)*100).toFixed(1) + "%"} */}
|
{/* {((contract.settings.delivered/contract.settings.size)*100).toFixed(1) + "%"} */}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{contract.sizeInPreferredUnit() -
|
{contract.sizeInPreferredUnit(user) -
|
||||||
contract.deliveredInPreferredUnit() +
|
contract.deliveredInPreferredUnit(user) +
|
||||||
" " +
|
" " +
|
||||||
contract.unit}
|
contract.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ import moment from "moment";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useGlobalState, useTaskAPI, useContractAPI, useSnackbar } from "providers";
|
import { useGlobalState, useTaskAPI, useContractAPI, useSnackbar } from "providers";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { getGrainUnit } from "utils";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
|
@ -45,7 +44,7 @@ export default function ContractSettings(props: Props) {
|
||||||
const { open, close, contract } = props;
|
const { open, close, contract } = props;
|
||||||
const contractAPI = useContractAPI();
|
const contractAPI = useContractAPI();
|
||||||
const [name, setName] = useState("");
|
const [name, setName] = useState("");
|
||||||
const [{as}] = useGlobalState();
|
const [{as, user}] = useGlobalState();
|
||||||
const [contractID, setContractID] = useState(""); //id
|
const [contractID, setContractID] = useState(""); //id
|
||||||
const [holder, setHolder] = useState(""); //holder
|
const [holder, setHolder] = useState(""); //holder
|
||||||
const [deliveryStart, setDeliveryStart] = useState(moment().format("YYYY-MM-DD")); //deliverystart
|
const [deliveryStart, setDeliveryStart] = useState(moment().format("YYYY-MM-DD")); //deliverystart
|
||||||
|
|
@ -72,7 +71,6 @@ export default function ContractSettings(props: Props) {
|
||||||
adornment: ""
|
adornment: ""
|
||||||
});
|
});
|
||||||
const taskAPI = useTaskAPI();
|
const taskAPI = useTaskAPI();
|
||||||
const [{ user }] = useGlobalState();
|
|
||||||
|
|
||||||
const closeSettings = () => {
|
const closeSettings = () => {
|
||||||
close();
|
close();
|
||||||
|
|
@ -87,32 +85,32 @@ export default function ContractSettings(props: Props) {
|
||||||
setDeliveryEnd(contract.settings.deliveryWindow?.endDate ?? "");
|
setDeliveryEnd(contract.settings.deliveryWindow?.endDate ?? "");
|
||||||
setContractType(contract.settings.type);
|
setContractType(contract.settings.type);
|
||||||
setCustomCommodity(contract.settings.customCommodity);
|
setCustomCommodity(contract.settings.customCommodity);
|
||||||
setContractSize(contract.sizeInPreferredUnit().toFixed(2));
|
setContractSize(contract.sizeInPreferredUnit(user).toFixed(2));
|
||||||
setDeliveredAmount(contract.deliveredInPreferredUnit().toFixed(2));
|
setDeliveredAmount(contract.deliveredInPreferredUnit(user).toFixed(2));
|
||||||
setContractValue(contract.settings.totalValue.toString());
|
setContractValue(contract.settings.totalValue.toString());
|
||||||
setCommodity(contract.settings.commodity);
|
setCommodity(contract.settings.commodity);
|
||||||
setContractDate(contract.settings.contractDate);
|
setContractDate(contract.settings.contractDate);
|
||||||
let conv = 1
|
let conv = 1
|
||||||
if(contract.settings.conversionValue > 1){
|
if(contract.settings.conversionValue > 1){
|
||||||
conv = contract.settings.conversionValue
|
conv = contract.settings.conversionValue
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
conv = conv * 0.907
|
conv = conv * 0.907
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setConversionValue(conv.toFixed(2));
|
setConversionValue(conv.toFixed(2));
|
||||||
setUseCustom(contract.isCustom());
|
setUseCustom(contract.isCustom());
|
||||||
}
|
}
|
||||||
}, [contract]);
|
}, [contract, user]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
switch (contractType) {
|
switch (contractType) {
|
||||||
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
||||||
let conversionLabel = "Bushels Per Tonne"
|
let conversionLabel = "Bushels Per Tonne"
|
||||||
let adornment = "bu"
|
let adornment = "bu"
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
adornment = "mT"
|
adornment = "mT"
|
||||||
}
|
}
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
conversionLabel = "Bushels Per Ton"
|
conversionLabel = "Bushels Per Ton"
|
||||||
adornment = "t"
|
adornment = "t"
|
||||||
}
|
}
|
||||||
|
|
@ -167,14 +165,14 @@ export default function ContractSettings(props: Props) {
|
||||||
//we will assume that both of those entries are using the same unit ie both US ton or both metric tonne
|
//we will assume that both of those entries are using the same unit ie both US ton or both metric tonne
|
||||||
const deliveredVal = isNaN(parseFloat(deliveredAmount))
|
const deliveredVal = isNaN(parseFloat(deliveredAmount))
|
||||||
? 0
|
? 0
|
||||||
: Math.round(Contract.toStoredUnit(parseFloat(deliveredAmount), contractType, conVal));
|
: Math.round(Contract.toStoredUnit(parseFloat(deliveredAmount), contractType, conVal, user));
|
||||||
const sizeVal = isNaN(parseFloat(contractSize))
|
const sizeVal = isNaN(parseFloat(contractSize))
|
||||||
? 0
|
? 0
|
||||||
: Math.round(Contract.toStoredUnit(parseFloat(contractSize), contractType, conVal));
|
: Math.round(Contract.toStoredUnit(parseFloat(contractSize), contractType, conVal, user));
|
||||||
|
|
||||||
//then after the conversion to bushels change the conversion value to metric to be stored in the contract
|
//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(contractType === pond.ContractType.CONTRACT_TYPE_GRAIN){
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
conVal = conVal / 0.907 //convert the ton they entered to mT to be stored in the contracts conversion value
|
conVal = conVal / 0.907 //convert the ton they entered to mT to be stored in the contracts conversion value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import { Transaction } from "models/Transaction";
|
||||||
import BarGraph, { BarData } from "charts/BarGraph";
|
import BarGraph, { BarData } from "charts/BarGraph";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import moment, { Moment } from "moment";
|
import moment, { Moment } from "moment";
|
||||||
import { getGrainUnit } from "utils";
|
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
import { useGlobalState } from "providers";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
contract: Contract;
|
contract: Contract;
|
||||||
|
|
@ -14,6 +14,7 @@ interface Props {
|
||||||
|
|
||||||
export default function ContractTransactionGraph(props: Props) {
|
export default function ContractTransactionGraph(props: Props) {
|
||||||
const { contract, transactions } = props;
|
const { contract, transactions } = props;
|
||||||
|
const [{ user }] = useGlobalState();
|
||||||
const [data, setData] = useState<BarData[]>([]);
|
const [data, setData] = useState<BarData[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -27,13 +28,13 @@ export default function ContractTransactionGraph(props: Props) {
|
||||||
if (transaction?.grainTransaction) {
|
if (transaction?.grainTransaction) {
|
||||||
value = transaction.grainTransaction.bushels;
|
value = transaction.grainTransaction.bushels;
|
||||||
if (
|
if (
|
||||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
||||||
transaction.grainTransaction.bushelsPerTonne > 1
|
transaction.grainTransaction.bushelsPerTonne > 1
|
||||||
) {
|
) {
|
||||||
value = value / transaction.grainTransaction.bushelsPerTonne;
|
value = value / transaction.grainTransaction.bushelsPerTonne;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON &&
|
user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON &&
|
||||||
transaction.grainTransaction.bushelsPerTonne > 1
|
transaction.grainTransaction.bushelsPerTonne > 1
|
||||||
) {
|
) {
|
||||||
value = value / (transaction.grainTransaction.bushelsPerTonne * 0.907);
|
value = value / (transaction.grainTransaction.bushelsPerTonne * 0.907);
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,7 @@ export default function ContractTransactionTable(props: Props) {
|
||||||
<DialogTitle>Select Files to Upload</DialogTitle>
|
<DialogTitle>Select Files to Upload</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<FileUploader
|
<FileUploader
|
||||||
|
hasFilePermission={permissions.includes(pond.Permission.PERMISSION_FILE_MANAGEMENT)}
|
||||||
keys={[contract.key(), selectedTransaction.transaction.key]}
|
keys={[contract.key(), selectedTransaction.transaction.key]}
|
||||||
types={["contract", "transaction"]}
|
types={["contract", "transaction"]}
|
||||||
toAttach={{
|
toAttach={{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { Box, Card, Typography, useTheme } from "@mui/material";
|
import { Box, Card, Typography, useTheme } from "@mui/material";
|
||||||
import GrainDescriber from "grain/GrainDescriber";
|
import GrainDescriber from "grain/GrainDescriber";
|
||||||
import { Contract } from "models/Contract";
|
import { Contract } from "models/Contract";
|
||||||
|
import { useGlobalState } from "providers";
|
||||||
import { Label, Pie, PieChart, ResponsiveContainer, Text } from "recharts";
|
import { Label, Pie, PieChart, ResponsiveContainer, Text } from "recharts";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -9,6 +10,7 @@ interface Props {
|
||||||
|
|
||||||
export default function ContractVisualizer(props: Props) {
|
export default function ContractVisualizer(props: Props) {
|
||||||
const { contract } = props;
|
const { contract } = props;
|
||||||
|
const [{ user }] = useGlobalState();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -18,8 +20,8 @@ export default function ContractVisualizer(props: Props) {
|
||||||
{GrainDescriber(contract.grain()).name}
|
{GrainDescriber(contract.grain()).name}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography style={{ fontWeight: 650, fontSize: 15 }}>
|
<Typography style={{ fontWeight: 650, fontSize: 15 }}>
|
||||||
{contract.deliveredInPreferredUnit().toFixed(2)}/
|
{contract.deliveredInPreferredUnit(user).toFixed(2)}/
|
||||||
{contract.sizeInPreferredUnit().toFixed(2)} {contract.unit}
|
{contract.sizeInPreferredUnit(user).toFixed(2)} {contract.unit}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<ResponsiveContainer height={"85%"}>
|
<ResponsiveContainer height={"85%"}>
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@ import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
||||||
import { pond, quack } from "protobuf-ts/pond";
|
import { pond, quack } from "protobuf-ts/pond";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import CableTopNodeSummary from "bin/CableTopNodeSummary";
|
import CableTopNodeSummary from "bin/CableTopNodeSummary";
|
||||||
import { getTemperatureUnit } from "utils";
|
|
||||||
import { DevicePreset } from "models/DevicePreset";
|
import { DevicePreset } from "models/DevicePreset";
|
||||||
import { Ambient } from "models/Ambient";
|
import { Ambient } from "models/Ambient";
|
||||||
import { useGlobalState } from "providers";
|
import { useGlobalState } from "providers";
|
||||||
|
|
@ -182,7 +181,7 @@ export default function DevicePresets(props: DevicePresetsProps) {
|
||||||
const [heaters, setHeaters] = useState<Controller[]>([]);
|
const [heaters, setHeaters] = useState<Controller[]>([]);
|
||||||
const [fans, setFans] = useState<Component[]>([]);
|
const [fans, setFans] = useState<Component[]>([]);
|
||||||
//const [subscribeBinToAutoTopNode, setSubscribeBinToAutoTopNode] = useState(false);
|
//const [subscribeBinToAutoTopNode, setSubscribeBinToAutoTopNode] = useState(false);
|
||||||
const [{as}] = useGlobalState();
|
const [{as, user}] = useGlobalState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (deviceComponents.get(deviceIndex.toString())) return;
|
if (deviceComponents.get(deviceIndex.toString())) return;
|
||||||
|
|
@ -439,19 +438,23 @@ export default function DevicePresets(props: DevicePresetsProps) {
|
||||||
value: describeMeasurement(
|
value: describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_PERCENT,
|
quack.MeasurementType.MEASUREMENT_TYPE_PERCENT,
|
||||||
plenum.settings.type,
|
plenum.settings.type,
|
||||||
plenum.settings.subtype
|
plenum.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toStored(humidityPreset)
|
).toStored(humidityPreset)
|
||||||
});
|
});
|
||||||
conditions.push(fanConditionOne);
|
conditions.push(fanConditionOne);
|
||||||
|
|
||||||
//since the measurement describers function toStored does a conversion into celsius for temperature if the users pref is fahrenheit we need to convert the preset value into fahrenheit
|
//since the measurement describers function toStored does a conversion into celsius for temperature if the users pref is fahrenheit we need to convert the preset value into fahrenheit
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
tempPreset = Math.round((tempPreset * (9 / 5) + 32) * 100) / 100;
|
tempPreset = Math.round((tempPreset * (9 / 5) + 32) * 100) / 100;
|
||||||
}
|
}
|
||||||
let tempVal = describeMeasurement(
|
let tempVal = describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
||||||
plenum.settings.type,
|
plenum.settings.type,
|
||||||
plenum.settings.subtype
|
plenum.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toStored(tempPreset);
|
).toStored(tempPreset);
|
||||||
|
|
||||||
let fanConditionTwo = pond.InteractionCondition.create({
|
let fanConditionTwo = pond.InteractionCondition.create({
|
||||||
|
|
@ -533,7 +536,9 @@ export default function DevicePresets(props: DevicePresetsProps) {
|
||||||
describeMeasurement(
|
describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_PERCENT,
|
quack.MeasurementType.MEASUREMENT_TYPE_PERCENT,
|
||||||
plenum.settings.type,
|
plenum.settings.type,
|
||||||
plenum.settings.subtype
|
plenum.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toStored(hum)
|
).toStored(hum)
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
@ -541,13 +546,15 @@ export default function DevicePresets(props: DevicePresetsProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//since the measurement describers function to stored does a conversion into celsius if the users pref is fahrenheit for temperature we need to convert the preset value into fahrenheit
|
//since the measurement describers function to stored does a conversion into celsius if the users pref is fahrenheit for temperature we need to convert the preset value into fahrenheit
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
temp = Math.round((temp * (9 / 5) + 32) * 100) / 100;
|
temp = Math.round((temp * (9 / 5) + 32) * 100) / 100;
|
||||||
}
|
}
|
||||||
let tempVal = describeMeasurement(
|
let tempVal = describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
||||||
plenum.settings.type,
|
plenum.settings.type,
|
||||||
plenum.settings.subtype
|
plenum.settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toStored(temp);
|
).toStored(temp);
|
||||||
|
|
||||||
let tempCondition = pond.InteractionCondition.create({
|
let tempCondition = pond.InteractionCondition.create({
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,9 @@ import { cloneDeep } from "lodash";
|
||||||
import { DevicePreset } from "models/DevicePreset";
|
import { DevicePreset } from "models/DevicePreset";
|
||||||
import { ObjectTypeString } from "objects/ObjectDescriber";
|
import { ObjectTypeString } from "objects/ObjectDescriber";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useSnackbar } from "providers";
|
import { useGlobalState, useSnackbar } from "providers";
|
||||||
import { useDevicePresetAPI } from "providers/pond/devicePresetAPI";
|
import { useDevicePresetAPI } from "providers/pond/devicePresetAPI";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { getTemperatureUnit } from "utils";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
preset: DevicePreset;
|
preset: DevicePreset;
|
||||||
|
|
@ -54,6 +53,7 @@ export default function DevicePresetCard(props: Props) {
|
||||||
const [humString, setHumString] = useState("0");
|
const [humString, setHumString] = useState("0");
|
||||||
const [hum, setHum] = useState(0);
|
const [hum, setHum] = useState(0);
|
||||||
const isMobile = useMobile();
|
const isMobile = useMobile();
|
||||||
|
const [{user}] = useGlobalState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPresetName(preset.name);
|
setPresetName(preset.name);
|
||||||
|
|
@ -63,11 +63,11 @@ export default function DevicePresetCard(props: Props) {
|
||||||
setHum(preset.settings.humidity);
|
setHum(preset.settings.humidity);
|
||||||
setHumString(preset.settings.humidity.toString());
|
setHumString(preset.settings.humidity.toString());
|
||||||
let displayTemp = preset.settings.temperature.toString();
|
let displayTemp = preset.settings.temperature.toString();
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
displayTemp = ((preset.settings.temperature * 9) / 5 + 32).toFixed();
|
displayTemp = ((preset.settings.temperature * 9) / 5 + 32).toFixed();
|
||||||
}
|
}
|
||||||
setTempString(displayTemp);
|
setTempString(displayTemp);
|
||||||
}, [preset]);
|
}, [preset, user]);
|
||||||
|
|
||||||
const saveNewPreset = () => {
|
const saveNewPreset = () => {
|
||||||
let typestring;
|
let typestring;
|
||||||
|
|
@ -296,7 +296,7 @@ export default function DevicePresetCard(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||||
? "°F"
|
? "°F"
|
||||||
: "°C"}
|
: "°C"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -307,7 +307,7 @@ export default function DevicePresetCard(props: Props) {
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
if (!isNaN(+e.target.value)) {
|
if (!isNaN(+e.target.value)) {
|
||||||
let temp = +e.target.value;
|
let temp = +e.target.value;
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
temp = Math.round((((temp - 32) * 5) / 9) * 10) / 10;
|
temp = Math.round((((temp - 32) * 5) / 9) * 10) / 10;
|
||||||
}
|
}
|
||||||
setTempC(temp);
|
setTempC(temp);
|
||||||
|
|
@ -324,7 +324,7 @@ export default function DevicePresetCard(props: Props) {
|
||||||
max={40}
|
max={40}
|
||||||
valueLabelDisplay="auto"
|
valueLabelDisplay="auto"
|
||||||
valueLabelFormat={value => {
|
valueLabelFormat={value => {
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
return ((value * 9) / 5 + 32).toFixed() + "°F";
|
return ((value * 9) / 5 + 32).toFixed() + "°F";
|
||||||
}
|
}
|
||||||
return value.toFixed() + "°C";
|
return value.toFixed() + "°C";
|
||||||
|
|
@ -350,7 +350,7 @@ export default function DevicePresetCard(props: Props) {
|
||||||
max={40}
|
max={40}
|
||||||
valueLabelDisplay="auto"
|
valueLabelDisplay="auto"
|
||||||
valueLabelFormat={value => {
|
valueLabelFormat={value => {
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
return ((value * 9) / 5 + 32).toFixed() + "°F";
|
return ((value * 9) / 5 + 32).toFixed() + "°F";
|
||||||
}
|
}
|
||||||
return value.toFixed() + "°C";
|
return value.toFixed() + "°C";
|
||||||
|
|
@ -371,7 +371,7 @@ export default function DevicePresetCard(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||||
? "°F"
|
? "°F"
|
||||||
: "°C"}
|
: "°C"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -382,7 +382,7 @@ export default function DevicePresetCard(props: Props) {
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
if (!isNaN(+e.target.value)) {
|
if (!isNaN(+e.target.value)) {
|
||||||
let temp = +e.target.value;
|
let temp = +e.target.value;
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
temp = Math.round((((temp - 32) * 5) / 9) * 10) / 10;
|
temp = Math.round((((temp - 32) * 5) / 9) * 10) / 10;
|
||||||
}
|
}
|
||||||
setTempC(temp);
|
setTempC(temp);
|
||||||
|
|
|
||||||
173
src/field/FieldTaskList.tsx
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
import { Fab, Theme } from "@mui/material"
|
||||||
|
import { Task } from "models"
|
||||||
|
import { useGlobalState, useTaskAPI } from "providers"
|
||||||
|
import React, { useCallback, useEffect, useState } from "react"
|
||||||
|
import TaskDrawer from "tasks/TaskDrawer"
|
||||||
|
import TaskList from "tasks/TaskList"
|
||||||
|
import TaskSettings from "tasks/TaskSettings"
|
||||||
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
|
import { makeStyles } from "@mui/styles";
|
||||||
|
import { openSnackbar } from "providers/Snackbar"
|
||||||
|
import { cloneDeep } from "lodash"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
field: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme: Theme) => {
|
||||||
|
return ({
|
||||||
|
active: {
|
||||||
|
color: theme.palette.getContrastText(theme.palette.secondary.main),
|
||||||
|
backgroundColor: theme.palette.secondary.main,
|
||||||
|
width: theme.spacing(5),
|
||||||
|
height: theme.spacing(5),
|
||||||
|
border: 0,
|
||||||
|
"&:hover": {
|
||||||
|
backgroundColor: theme.palette.secondary.main
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fab: {
|
||||||
|
zIndex: 20,
|
||||||
|
background: theme.palette.primary.main,
|
||||||
|
"&:hover": {
|
||||||
|
background: theme.palette.primary.main
|
||||||
|
},
|
||||||
|
"&:focus": {
|
||||||
|
background: theme.palette.primary.main
|
||||||
|
},
|
||||||
|
position: "absolute",
|
||||||
|
bottom: theme.spacing(8), //for mobile navigator
|
||||||
|
right: theme.spacing(2),
|
||||||
|
[theme.breakpoints.up("sm")]: {
|
||||||
|
bottom: theme.spacing(2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
overlayFab: {
|
||||||
|
zIndex: 20,
|
||||||
|
background: theme.palette.primary.main,
|
||||||
|
"&:hover": {
|
||||||
|
background: theme.palette.primary.main
|
||||||
|
},
|
||||||
|
"&:focus": {
|
||||||
|
background: theme.palette.primary.main
|
||||||
|
},
|
||||||
|
position: "fixed",
|
||||||
|
bottom: theme.spacing(8), //for mobile navigator
|
||||||
|
right: theme.spacing(2),
|
||||||
|
[theme.breakpoints.up("sm")]: {
|
||||||
|
bottom: theme.spacing(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function FieldTaskList(props: Props) {
|
||||||
|
const { field } = props
|
||||||
|
const [{ as }] = useGlobalState()
|
||||||
|
const taskAPI = useTaskAPI()
|
||||||
|
const classes = useStyles()
|
||||||
|
const [selectedTask, setSelectedTask] = useState<Task | undefined>(undefined)
|
||||||
|
const [openTaskDrawer, setOpenTaskDrawer] = useState(false)
|
||||||
|
const [opentaskSettings, setOpenTaskSettings] = useState(false)
|
||||||
|
const [taskMap, setTaskMap] = useState<Map<string, Task>>(new Map())
|
||||||
|
|
||||||
|
//load the tasks
|
||||||
|
const loadTasks = useCallback(() => {
|
||||||
|
console.log("loading tasks")
|
||||||
|
taskAPI.listTasks(50, 0, "asc", "start", undefined, undefined, undefined, undefined, undefined, [field], ["field"]).then(resp => {
|
||||||
|
if(resp.data.tasks){
|
||||||
|
let newMap: Map<string,Task> = new Map()
|
||||||
|
resp.data.tasks.forEach(task => {
|
||||||
|
newMap.set(task.key, Task.create(task))
|
||||||
|
})
|
||||||
|
setTaskMap(newMap)
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
|
||||||
|
})
|
||||||
|
},[as, field])
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
loadTasks()
|
||||||
|
},[loadTasks])
|
||||||
|
|
||||||
|
const deleteTask = (task: Task) => {
|
||||||
|
taskAPI.removeTask(task.key).then(resp => {
|
||||||
|
openSnackbar("success", "Task has been removed")
|
||||||
|
loadTasks()
|
||||||
|
}).catch(err => {
|
||||||
|
openSnackbar("error", "There was a problem removing the task")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const markComplete = (task: Task) => {
|
||||||
|
let settings = cloneDeep(task.settings)
|
||||||
|
settings.complete = !task.settings.complete
|
||||||
|
taskAPI.updateTask(task.key, settings).then(resp => {
|
||||||
|
openSnackbar("success", "Task has been updated")
|
||||||
|
loadTasks()
|
||||||
|
}).catch(err => {
|
||||||
|
openSnackbar("error", "There was a problem updating the task")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//return the task list
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{selectedTask &&
|
||||||
|
<TaskDrawer
|
||||||
|
task={selectedTask}
|
||||||
|
open={openTaskDrawer}
|
||||||
|
deleteTask={deleteTask}
|
||||||
|
completeTask={markComplete}
|
||||||
|
closeCallback={(refresh) => {
|
||||||
|
setOpenTaskDrawer(false)
|
||||||
|
setSelectedTask(undefined)
|
||||||
|
if (refresh) {
|
||||||
|
loadTasks()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
keys={[field]}
|
||||||
|
types={["field"]}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
<TaskList
|
||||||
|
deleteTask={deleteTask}
|
||||||
|
markComplete={markComplete}
|
||||||
|
openTask={id => {
|
||||||
|
let task = taskMap.get(id)
|
||||||
|
if(task){
|
||||||
|
setSelectedTask(task)
|
||||||
|
setOpenTaskDrawer(true)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
tasks={Array.from(taskMap.values())}
|
||||||
|
reLoad={() => {
|
||||||
|
loadTasks()
|
||||||
|
}}
|
||||||
|
keys={[field]}
|
||||||
|
types={["field"]}
|
||||||
|
/>
|
||||||
|
<TaskSettings
|
||||||
|
open={opentaskSettings}
|
||||||
|
onClose={(reload) => {
|
||||||
|
setOpenTaskSettings(false)
|
||||||
|
if(reload){
|
||||||
|
loadTasks()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
keys={[field]}
|
||||||
|
types={["field"]}
|
||||||
|
task={selectedTask}
|
||||||
|
/>
|
||||||
|
<Fab
|
||||||
|
onClick={() => {setOpenTaskSettings(true)}}
|
||||||
|
aria-label="Create Task"
|
||||||
|
className={classes.overlayFab}
|
||||||
|
size={"medium"}>
|
||||||
|
<AddIcon />
|
||||||
|
</Fab>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,6 @@ import { pond } from "protobuf-ts/pond"
|
||||||
import { quack } from "protobuf-ts/quack"
|
import { quack } from "protobuf-ts/quack"
|
||||||
import { useGlobalState } from "providers"
|
import { useGlobalState } from "providers"
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { getTemperatureUnit } from "utils"
|
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -190,7 +189,7 @@ export default function GateDeltaTempGraph(props: Props){
|
||||||
<span>
|
<span>
|
||||||
{"Delta Temp: "}
|
{"Delta Temp: "}
|
||||||
<span style={{ color: recent.value > 0 ? warmingColour : coolingColour, fontWeight: 500 }}>
|
<span style={{ color: recent.value > 0 ? warmingColour : coolingColour, fontWeight: 500 }}>
|
||||||
{recent.value.toFixed(2) + (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C")}
|
{recent.value.toFixed(2) + (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C")}
|
||||||
</span>
|
</span>
|
||||||
<br />
|
<br />
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -211,10 +210,12 @@ export default function GateDeltaTempGraph(props: Props){
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<SingleSetAreaChart
|
<SingleSetAreaChart
|
||||||
data={data}
|
data={data}
|
||||||
|
minY={-40} //-40C is the same as -40F
|
||||||
|
maxY={(user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? 104 : 40)}
|
||||||
tooltipLabel="Delta Temp"
|
tooltipLabel="Delta Temp"
|
||||||
tooltipUnit={getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C"}
|
tooltipUnit={user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C"}
|
||||||
yAxisLabel={"Delta T" + (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C")}
|
yAxisLabel={"Delta T" + (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C")}
|
||||||
colourAboveZero={{colour: warmingColour, label: "Heating"}}
|
colourAboveZero={{colour: warmingColour, label: "Heating"}}
|
||||||
colourBelowZero={{colour: coolingColour, label: "Cooling"}}/>
|
colourBelowZero={{colour: coolingColour, label: "Cooling"}}/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ import moment from "moment";
|
||||||
import { pond, quack } from "protobuf-ts/pond";
|
import { pond, quack } from "protobuf-ts/pond";
|
||||||
import { useGlobalState, useInteractionsAPI, useSnackbar } from "providers";
|
import { useGlobalState, useInteractionsAPI, useSnackbar } from "providers";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { getPressureUnit } from "utils";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
close: (canceled: boolean) => void;
|
close: (canceled: boolean) => void;
|
||||||
|
|
@ -100,7 +98,6 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
} else if (
|
} else if (
|
||||||
gate.preferences[component.key()] === pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
|
gate.preferences[component.key()] === pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE
|
||||||
) {
|
) {
|
||||||
console.log(component)
|
|
||||||
setPressureComponent(component);
|
setPressureComponent(component);
|
||||||
setPressureSource(
|
setPressureSource(
|
||||||
quack.ComponentID.create({
|
quack.ComponentID.create({
|
||||||
|
|
@ -186,9 +183,9 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
//need to make sure the redthreshold is in pascals
|
//need to make sure the redthreshold is in pascals
|
||||||
let thresholdPascals = 0
|
let thresholdPascals = 0
|
||||||
if(!isNaN(parseFloat(redThreshold))){
|
if(!isNaN(parseFloat(redThreshold))){
|
||||||
if(getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_KILOPASCALS){
|
if(user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_KILOPASCALS){
|
||||||
thresholdPascals = parseFloat(redThreshold)*1000
|
thresholdPascals = parseFloat(redThreshold)*1000
|
||||||
}else if (getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER){
|
}else if (user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER){
|
||||||
thresholdPascals = parseFloat(redThreshold)*249
|
thresholdPascals = parseFloat(redThreshold)*249
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -346,8 +343,8 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
when the difference between the pressures falls within this range and vice versa:
|
when the difference between the pressures falls within this range and vice versa:
|
||||||
</Typography>
|
</Typography>
|
||||||
<br />
|
<br />
|
||||||
<Typography>Upper Limit: {getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? (highDelta/249.089).toFixed(2) + " iwg" : highDelta/1000 + " kPa"}</Typography>
|
<Typography>Upper Limit: {user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? (highDelta/249.089).toFixed(2) + " iwg" : highDelta/1000 + " kPa"}</Typography>
|
||||||
<Typography>Lower Limit: {getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? (lowDelta/249.089).toFixed(2) + " iwg" : lowDelta/1000 + " kPa"}</Typography>
|
<Typography>Lower Limit: {user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? (lowDelta/249.089).toFixed(2) + " iwg" : lowDelta/1000 + " kPa"}</Typography>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<Typography>If you would like to have the interactions set in such a way that if the average pressure falls below a given value set the use off condition and set the value to use</Typography>
|
<Typography>If you would like to have the interactions set in such a way that if the average pressure falls below a given value set the use off condition and set the value to use</Typography>
|
||||||
|
|
@ -372,7 +369,7 @@ export default function GateDeviceInteraction(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? "iwg" : "kPa"}
|
{user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? "iwg" : "kPa"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -282,13 +282,13 @@ export default function GateGraphs(props: Props) {
|
||||||
if (um.values[0] && um.values[0].values.length > 1) {
|
if (um.values[0] && um.values[0].values.length > 1) {
|
||||||
return areaGraph(
|
return areaGraph(
|
||||||
um,
|
um,
|
||||||
describeMeasurement(um.type, component.type(), component.subType()),
|
describeMeasurement(um.type, component.type(), component.subType(), undefined, user),
|
||||||
component.settings.smoothingAverages
|
component.settings.smoothingAverages
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return lineGraph(
|
return lineGraph(
|
||||||
um,
|
um,
|
||||||
describeMeasurement(um.type, component.type(), component.subType()),
|
describeMeasurement(um.type, component.type(), component.subType(), undefined, user),
|
||||||
component.settings.smoothingAverages
|
component.settings.smoothingAverages
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import moment from "moment";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { UnitMeasurement } from "models/UnitMeasurement";
|
import { UnitMeasurement } from "models/UnitMeasurement";
|
||||||
import { quack } from "protobuf-ts/quack";
|
import { quack } from "protobuf-ts/quack";
|
||||||
import { getTemperatureUnit } from "utils";
|
|
||||||
import { teal } from "@mui/material/colors";
|
import { teal } from "@mui/material/colors";
|
||||||
import { react } from "@babel/types";
|
import { react } from "@babel/types";
|
||||||
import { getDeviceStateHelper } from "pbHelpers/DeviceState";
|
import { getDeviceStateHelper } from "pbHelpers/DeviceState";
|
||||||
|
|
@ -229,7 +228,7 @@ export default function GateList(props: Props) {
|
||||||
})
|
})
|
||||||
if(ambientTemp && outletTemp){
|
if(ambientTemp && outletTemp){
|
||||||
let deltaTemp = outletTemp - ambientTemp
|
let deltaTemp = outletTemp - ambientTemp
|
||||||
display = deltaTemp.toFixed(2) + (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "°F" : "°C")
|
display = deltaTemp.toFixed(2) + (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "°F" : "°C")
|
||||||
}else{
|
}else{
|
||||||
display = "Sensor Missing"
|
display = "Sensor Missing"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,7 @@ import {MenuItem, TextField } from "@mui/material"
|
||||||
import { cloneDeep } from "lodash"
|
import { cloneDeep } from "lodash"
|
||||||
import { pond } from "protobuf-ts/pond"
|
import { pond } from "protobuf-ts/pond"
|
||||||
import React, { useEffect, useRef, useState } from "react"
|
import React, { useEffect, useRef, useState } from "react"
|
||||||
import { getGrainUnit } from "utils"
|
import { useGlobalState } from "providers";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
grainSettings?: pond.GrainSettings
|
grainSettings?: pond.GrainSettings
|
||||||
onGrainSettingsChange: (settings: pond.GrainSettings, formValid: boolean) => void
|
onGrainSettingsChange: (settings: pond.GrainSettings, formValid: boolean) => void
|
||||||
|
|
@ -11,6 +10,7 @@ interface Props {
|
||||||
|
|
||||||
export default function CustomGrainForm(props: Props) {
|
export default function CustomGrainForm(props: Props) {
|
||||||
const {grainSettings, onGrainSettingsChange} = props
|
const {grainSettings, onGrainSettingsChange} = props
|
||||||
|
const [{ user }] = useGlobalState();
|
||||||
const [newGrainSettings, setNewGrainSettings] = useState(pond.GrainSettings.create())
|
const [newGrainSettings, setNewGrainSettings] = useState(pond.GrainSettings.create())
|
||||||
const [name, setName] = useState("")
|
const [name, setName] = useState("")
|
||||||
const [group, setGroup] = useState("")
|
const [group, setGroup] = useState("")
|
||||||
|
|
@ -204,7 +204,7 @@ export default function CustomGrainForm(props: Props) {
|
||||||
valid.current = validate(name, group, constantA, constantB, constantC, kgPerBushel, val)
|
valid.current = validate(name, group, constantA, constantB, constantC, kgPerBushel, val)
|
||||||
let settings = cloneDeep(newGrainSettings)
|
let settings = cloneDeep(newGrainSettings)
|
||||||
if(!isNaN(parseFloat(val))){
|
if(!isNaN(parseFloat(val))){
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
settings.bushelsPerTonne = parseFloat(val)/0.907
|
settings.bushelsPerTonne = parseFloat(val)/0.907
|
||||||
}else{
|
}else{
|
||||||
settings.bushelsPerTonne = parseFloat(val)
|
settings.bushelsPerTonne = parseFloat(val)
|
||||||
|
|
@ -212,7 +212,7 @@ export default function CustomGrainForm(props: Props) {
|
||||||
}
|
}
|
||||||
settingsChanged(settings)
|
settingsChanged(settings)
|
||||||
}}
|
}}
|
||||||
label={"Bushels per " + (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE ? " Tonne" : "Ton")}/>
|
label={"Bushels per " + (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE ? " Tonne" : "Ton")}/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ import {
|
||||||
useTransactionAPI
|
useTransactionAPI
|
||||||
} from "providers";
|
} from "providers";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { getGrainUnit } from "utils";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
mainObject: Bin | GrainBag | Field | Contract;
|
mainObject: Bin | GrainBag | Field | Contract;
|
||||||
|
|
@ -451,7 +450,7 @@ export default function GrainTransaction(props: Props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const grainUnitDisplay = () => {
|
const grainUnitDisplay = () => {
|
||||||
switch (getGrainUnit()){
|
switch (user.grainUnit()){
|
||||||
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
||||||
return "mT"
|
return "mT"
|
||||||
case pond.GrainUnit.GRAIN_UNIT_TON:
|
case pond.GrainUnit.GRAIN_UNIT_TON:
|
||||||
|
|
@ -525,7 +524,7 @@ export default function GrainTransaction(props: Props) {
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
//if the user is viewing the grain in weight
|
//if the user is viewing the grain in weight
|
||||||
let grainVal = e.target.value;
|
let grainVal = e.target.value;
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE) {
|
||||||
//need to convert what the user input (weight) into what is actually stored (bushels)
|
//need to convert what the user input (weight) into what is actually stored (bushels)
|
||||||
//use source of the conversion value if it was selected, otherwise use the destination
|
//use source of the conversion value if it was selected, otherwise use the destination
|
||||||
if (!isNaN(parseFloat(e.target.value))) {
|
if (!isNaN(parseFloat(e.target.value))) {
|
||||||
|
|
@ -535,7 +534,7 @@ export default function GrainTransaction(props: Props) {
|
||||||
grainVal = (+grainVal * selectedDestination.value.bushelsPerTonne()).toFixed(2);
|
grainVal = (+grainVal * selectedDestination.value.bushelsPerTonne()).toFixed(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) {
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) {
|
||||||
if (!isNaN(parseFloat(e.target.value))) {
|
if (!isNaN(parseFloat(e.target.value))) {
|
||||||
if (selectedSource) {
|
if (selectedSource) {
|
||||||
if(selectedSource.value.bushelsPerTonne){
|
if(selectedSource.value.bushelsPerTonne){
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import moment, { Moment } from "moment";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useGlobalState, useGrainBagAPI, useSnackbar } from "providers";
|
import { useGlobalState, useGrainBagAPI, useSnackbar } from "providers";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { getGrainUnit } from "utils";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
grainBag: GrainBag;
|
grainBag: GrainBag;
|
||||||
|
|
@ -21,7 +20,7 @@ export default function GrainBagInventoryGraph(props: Props) {
|
||||||
const [data, setData] = useState<BarData[]>([]);
|
const [data, setData] = useState<BarData[]>([]);
|
||||||
const [loadingData, setLoadingData] = useState<boolean>(false);
|
const [loadingData, setLoadingData] = useState<boolean>(false);
|
||||||
const { openSnack } = useSnackbar();
|
const { openSnack } = useSnackbar();
|
||||||
const [{as}] = useGlobalState();
|
const [{as, user}] = useGlobalState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (grainBag.key() && !loadingData) {
|
if (grainBag.key() && !loadingData) {
|
||||||
|
|
@ -36,12 +35,12 @@ export default function GrainBagInventoryGraph(props: Props) {
|
||||||
//let time = hist.timestamp;
|
//let time = hist.timestamp;
|
||||||
let val = hist.object.grainBagSettings.currentBushels ?? 0;
|
let val = hist.object.grainBagSettings.currentBushels ?? 0;
|
||||||
if (
|
if (
|
||||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
||||||
grainBag.bushelsPerTonne() > 1
|
grainBag.bushelsPerTonne() > 1
|
||||||
) {
|
) {
|
||||||
val = Math.round((val / grainBag.bushelsPerTonne()) * 100) / 100;
|
val = Math.round((val / grainBag.bushelsPerTonne()) * 100) / 100;
|
||||||
}
|
}
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1){
|
||||||
val = Math.round((val / (grainBag.bushelsPerTonne() * 0.907)) * 100) / 100;
|
val = Math.round((val / (grainBag.bushelsPerTonne() * 0.907)) * 100) / 100;
|
||||||
}
|
}
|
||||||
if (val !== lastBushels) {
|
if (val !== lastBushels) {
|
||||||
|
|
@ -55,10 +54,10 @@ export default function GrainBagInventoryGraph(props: Props) {
|
||||||
});
|
});
|
||||||
if (barData.length === 0) {
|
if (barData.length === 0) {
|
||||||
let val = grainBag.bushels()
|
let val = grainBag.bushels()
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1){
|
||||||
val = grainBag.bushels() / grainBag.bushelsPerTonne()
|
val = grainBag.bushels() / grainBag.bushelsPerTonne()
|
||||||
}
|
}
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1){
|
||||||
val = grainBag.bushels() / (grainBag.bushelsPerTonne() * 0.907)
|
val = grainBag.bushels() / (grainBag.bushelsPerTonne() * 0.907)
|
||||||
}
|
}
|
||||||
barData.push({
|
barData.push({
|
||||||
|
|
@ -79,10 +78,10 @@ export default function GrainBagInventoryGraph(props: Props) {
|
||||||
|
|
||||||
const maxYAxis = () => {
|
const maxYAxis = () => {
|
||||||
let val = grainBag.capacity()
|
let val = grainBag.capacity()
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
val = Math.round((val / grainBag.bushelsPerTonne()) * 100) / 100;
|
val = Math.round((val / grainBag.bushelsPerTonne()) * 100) / 100;
|
||||||
}
|
}
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1){
|
||||||
val = Math.round((val / (grainBag.bushelsPerTonne() * 0.907)) * 100) / 100;
|
val = Math.round((val / (grainBag.bushelsPerTonne() * 0.907)) * 100) / 100;
|
||||||
}
|
}
|
||||||
return val
|
return val
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import { pond } from "protobuf-ts/pond";
|
||||||
import { useGlobalState, useGrainBagAPI, useSnackbar } from "providers";
|
import { useGlobalState, useGrainBagAPI, useSnackbar } from "providers";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { getGrainUnit } from "utils";
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => {
|
const useStyles = makeStyles((theme: Theme) => {
|
||||||
return ({
|
return ({
|
||||||
|
|
@ -84,9 +83,9 @@ export default function GrainBagSettings(props: Props) {
|
||||||
: grainBag.settings.length
|
: grainBag.settings.length
|
||||||
);
|
);
|
||||||
let grainVal = grainBag.bushels();
|
let grainVal = grainBag.bushels();
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE) {
|
||||||
grainVal = grainBag.bushels() / grainBag.bushelsPerTonne();
|
grainVal = grainBag.bushels() / grainBag.bushelsPerTonne();
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) {
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) {
|
||||||
grainVal = grainBag.bushels() / (grainBag.bushelsPerTonne() * 0.907)
|
grainVal = grainBag.bushels() / (grainBag.bushelsPerTonne() * 0.907)
|
||||||
}
|
}
|
||||||
setGrainFill(grainVal.toFixed(2));
|
setGrainFill(grainVal.toFixed(2));
|
||||||
|
|
@ -120,7 +119,7 @@ export default function GrainBagSettings(props: Props) {
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
//if a bag was passed in do an update
|
//if a bag was passed in do an update
|
||||||
let tonneConversion = bushelConversion
|
let tonneConversion = bushelConversion
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
tonneConversion = bushelConversion / 0.907
|
tonneConversion = bushelConversion / 0.907
|
||||||
}
|
}
|
||||||
if (grainBag) {
|
if (grainBag) {
|
||||||
|
|
@ -255,9 +254,9 @@ export default function GrainBagSettings(props: Props) {
|
||||||
|
|
||||||
const grainUnitDisplay = () => {
|
const grainUnitDisplay = () => {
|
||||||
if(bushelConversion > 1){
|
if(bushelConversion > 1){
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
return "mT"
|
return "mT"
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
return "t"
|
return "t"
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -422,7 +421,7 @@ export default function GrainBagSettings(props: Props) {
|
||||||
value={grainFill}
|
value={grainFill}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
let bushelVal = +e.target.value;
|
let bushelVal = +e.target.value;
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE || getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE || user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) {
|
||||||
//convert the number as a weight into the bushel value, no changing or conversions necessary
|
//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)
|
// since these are both user entered fields and should be the same unit (ton or tonne)
|
||||||
bushelVal = +e.target.value * (bushelConversion > 0 ? bushelConversion : 1);
|
bushelVal = +e.target.value * (bushelConversion > 0 ? bushelConversion : 1);
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ import moment from "moment";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { getThemeType } from "theme";
|
import { getThemeType } from "theme";
|
||||||
import { getGrainUnit } from "utils";
|
|
||||||
import GrainBagSVG from "./grainBagSVG";
|
import GrainBagSVG from "./grainBagSVG";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
|
import { useGlobalState } from "providers";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
grainBag: GrainBag;
|
grainBag: GrainBag;
|
||||||
|
|
@ -68,6 +68,7 @@ export default function GrainBagVisualizer(props: Props) {
|
||||||
const [grainDiff, setGrainDiff] = useState<number | undefined>();
|
const [grainDiff, setGrainDiff] = useState<number | undefined>();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [openTransaction, setOpenTransaction] = useState(false);
|
const [openTransaction, setOpenTransaction] = useState(false);
|
||||||
|
const [{ user }] = useGlobalState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFillLevel((grainBag.bushels() / grainBag.capacity()) * 100);
|
setFillLevel((grainBag.bushels() / grainBag.capacity()) * 100);
|
||||||
|
|
@ -83,13 +84,13 @@ export default function GrainBagVisualizer(props: Props) {
|
||||||
const grainOverlay = () => {
|
const grainOverlay = () => {
|
||||||
let displayPending = pendingGrainAmount;
|
let displayPending = pendingGrainAmount;
|
||||||
let displayDiff = grainDiff;
|
let displayDiff = grainDiff;
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1) {
|
||||||
if (displayPending && displayDiff) {
|
if (displayPending && displayDiff) {
|
||||||
displayPending = Math.round((displayPending / grainBag.bushelsPerTonne()) * 100) / 100;
|
displayPending = Math.round((displayPending / grainBag.bushelsPerTonne()) * 100) / 100;
|
||||||
displayDiff = Math.round((displayDiff / grainBag.bushelsPerTonne()) * 100) / 100;
|
displayDiff = Math.round((displayDiff / grainBag.bushelsPerTonne()) * 100) / 100;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1) {
|
||||||
if (displayPending && displayDiff) {
|
if (displayPending && displayDiff) {
|
||||||
displayPending = Math.round((displayPending / (grainBag.bushelsPerTonne() * 0.907)) * 100) / 100;
|
displayPending = Math.round((displayPending / (grainBag.bushelsPerTonne() * 0.907)) * 100) / 100;
|
||||||
displayDiff = Math.round((displayDiff / (grainBag.bushelsPerTonne()* 0.907)) * 100) / 100;
|
displayDiff = Math.round((displayDiff / (grainBag.bushelsPerTonne()* 0.907)) * 100) / 100;
|
||||||
|
|
@ -148,7 +149,7 @@ export default function GrainBagVisualizer(props: Props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const grainAmountDisplay = () => {
|
const grainAmountDisplay = () => {
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||||
<Typography variant="body2" style={{ fontWeight: "bold", marginRight: "4px" }}>
|
<Typography variant="body2" style={{ fontWeight: "bold", marginRight: "4px" }}>
|
||||||
|
|
@ -157,7 +158,7 @@ export default function GrainBagVisualizer(props: Props) {
|
||||||
<Typography variant="body2">({grainBag.fillPercent()}%)</Typography>
|
<Typography variant="body2">({grainBag.fillPercent()}%)</Typography>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1) {
|
} else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||||
<Typography variant="body2" style={{ fontWeight: "bold", marginRight: "4px" }}>
|
<Typography variant="body2" style={{ fontWeight: "bold", marginRight: "4px" }}>
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,9 @@ export default function InteractionSettings(props: Props) {
|
||||||
let value = describeMeasurement(
|
let value = describeMeasurement(
|
||||||
condition.measurementType,
|
condition.measurementType,
|
||||||
or(initialComponent, Component.create()).settings.type,
|
or(initialComponent, Component.create()).settings.type,
|
||||||
or(initialComponent, Component.create()).settings.subtype
|
or(initialComponent, Component.create()).settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toDisplay(condition.value);
|
).toDisplay(condition.value);
|
||||||
rawConditionValues.push(value.toString());
|
rawConditionValues.push(value.toString());
|
||||||
});
|
});
|
||||||
|
|
@ -425,7 +427,7 @@ export default function InteractionSettings(props: Props) {
|
||||||
mappedComponents.get(componentIDToString(interaction.settings.source)),
|
mappedComponents.get(componentIDToString(interaction.settings.source)),
|
||||||
Component.create()
|
Component.create()
|
||||||
);
|
);
|
||||||
return describeMeasurement(measurementType, source.settings.type, source.settings.subtype);
|
return describeMeasurement(measurementType, source.settings.type, source.settings.subtype, undefined, user);
|
||||||
};
|
};
|
||||||
|
|
||||||
const describeSink = (): MeasurementDescriber => {
|
const describeSink = (): MeasurementDescriber => {
|
||||||
|
|
@ -433,7 +435,9 @@ export default function InteractionSettings(props: Props) {
|
||||||
return describeMeasurement(
|
return describeMeasurement(
|
||||||
Measurement.boolean,
|
Measurement.boolean,
|
||||||
or(sink, Component.create()).settings.type,
|
or(sink, Component.create()).settings.type,
|
||||||
or(sink, Component.create()).settings.subtype
|
or(sink, Component.create()).settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -861,7 +865,7 @@ export default function InteractionSettings(props: Props) {
|
||||||
const conditionGroup = (index: number) => {
|
const conditionGroup = (index: number) => {
|
||||||
if (index >= numConditions) return;
|
if (index >= numConditions) return;
|
||||||
let measurementType = interaction.settings.conditions[index].measurementType;
|
let measurementType = interaction.settings.conditions[index].measurementType;
|
||||||
let source = describeSource(measurementType);
|
let source = describeSource(measurementType, );
|
||||||
let isBoolean = isBooleanValue(index);
|
let isBoolean = isBooleanValue(index);
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={index}>
|
<React.Fragment key={index}>
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ interface Props {
|
||||||
|
|
||||||
export default function InteractionsOverview(props: Props) {
|
export default function InteractionsOverview(props: Props) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const [{as}] = useGlobalState();
|
const [{as, user}] = useGlobalState();
|
||||||
const interactionsAPI = useInteractionsAPI();
|
const interactionsAPI = useInteractionsAPI();
|
||||||
const { success, error } = useSnackbar();
|
const { success, error } = useSnackbar();
|
||||||
const { device, component, components, permissions, refreshCallback } = props;
|
const { device, component, components, permissions, refreshCallback } = props;
|
||||||
|
|
@ -118,12 +118,12 @@ export default function InteractionsOverview(props: Props) {
|
||||||
if (!conditions) return items;
|
if (!conditions) return items;
|
||||||
conditions.forEach((condition: pond.IInteractionCondition, conditionIndex: number) => {
|
conditions.forEach((condition: pond.IInteractionCondition, conditionIndex: number) => {
|
||||||
let measurementType = condition.measurementType;
|
let measurementType = condition.measurementType;
|
||||||
let measurement = describeMeasurement(condition.measurementType, sourceType, sourceSubtype);
|
let measurement = describeMeasurement(condition.measurementType, sourceType, sourceSubtype, undefined, user);
|
||||||
items.push(
|
items.push(
|
||||||
<Grid container size={{ sm: 12 }} key={conditionIndex} alignItems="center">
|
<Grid container size={{ sm: 12 }} key={conditionIndex} alignItems="center">
|
||||||
<Grid size={{ xs: 12, sm: 6 }}>
|
<Grid size={{ xs: 12, sm: 6 }}>
|
||||||
<Typography variant="caption" gutterBottom>
|
<Typography variant="caption" gutterBottom>
|
||||||
{interactionConditionText(source, condition, conditionIndex > 0)}
|
{interactionConditionText(source, condition, conditionIndex > 0, user)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid size={{ xs: 12, sm: 6 }}>
|
<Grid size={{ xs: 12, sm: 6 }}>
|
||||||
|
|
@ -185,7 +185,7 @@ export default function InteractionsOverview(props: Props) {
|
||||||
let condition = conditions[conditionIndex];
|
let condition = conditions[conditionIndex];
|
||||||
let sourceType = source && source.settings.type;
|
let sourceType = source && source.settings.type;
|
||||||
let sourceSubtype = source && source.settings.subtype;
|
let sourceSubtype = source && source.settings.subtype;
|
||||||
let describer = describeMeasurement(condition.measurementType, sourceType, sourceSubtype);
|
let describer = describeMeasurement(condition.measurementType, sourceType, sourceSubtype, undefined, user);
|
||||||
condition.value = describer.toStored(value);
|
condition.value = describer.toStored(value);
|
||||||
updatedDirtyInteractions.set(interactionIndex, true);
|
updatedDirtyInteractions.set(interactionIndex, true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ import { FeatureCollection, Feature } from "geojson";
|
||||||
import DrawController from "./mapControllers/drawController";
|
import DrawController from "./mapControllers/drawController";
|
||||||
//import { Geometry } from "geojson";
|
//import { Geometry } from "geojson";
|
||||||
import Map, { MapRef, Marker, MarkerDragEvent } from "react-map-gl/mapbox";
|
import Map, { MapRef, Marker, MarkerDragEvent } from "react-map-gl/mapbox";
|
||||||
import { getDistanceUnit } from "utils";
|
|
||||||
import { MapMouseEvent } from "mapbox-gl";
|
import { MapMouseEvent } from "mapbox-gl";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import { Result } from "@mapbox/mapbox-gl-geocoder";
|
import { Result } from "@mapbox/mapbox-gl-geocoder";
|
||||||
|
|
@ -499,7 +498,7 @@ export default function MapBase(props: Props) {
|
||||||
lineWidth: 5,
|
lineWidth: 5,
|
||||||
origin: pond.DataOrigin.DATA_ORIGIN_ADAPTIVE,
|
origin: pond.DataOrigin.DATA_ORIGIN_ADAPTIVE,
|
||||||
totalDist:
|
totalDist:
|
||||||
getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||||
? (data.totalDistanceKm * 1000).toFixed(2)
|
? (data.totalDistanceKm * 1000).toFixed(2)
|
||||||
: (data.totalDistanceKm * 3280.8398950131).toFixed(2)
|
: (data.totalDistanceKm * 3280.8398950131).toFixed(2)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ import DisplayDrawer from "common/DisplayDrawer";
|
||||||
import HarvestPlanDisplay from "harvestPlan/HarvestPlanDisplay";
|
import HarvestPlanDisplay from "harvestPlan/HarvestPlanDisplay";
|
||||||
import { Field, fieldScope, HarvestPlan, teamScope } from "models";
|
import { Field, fieldScope, HarvestPlan, teamScope } from "models";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import TaskViewer from "tasks/TaskViewer";
|
|
||||||
import Weather from "weather/weather";
|
import Weather from "weather/weather";
|
||||||
import { getThemeType } from "theme";
|
import { getThemeType } from "theme";
|
||||||
import GrainDescriber from "grain/GrainDescriber";
|
import GrainDescriber from "grain/GrainDescriber";
|
||||||
|
|
@ -24,6 +23,7 @@ import { useMobile } from "hooks";
|
||||||
import { useGlobalState, useHarvestPlanAPI, useUserAPI } from "providers";
|
import { useGlobalState, useHarvestPlanAPI, useUserAPI } from "providers";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import FieldActions from "field/FieldActions";
|
import FieldActions from "field/FieldActions";
|
||||||
|
import FieldTaskList from "field/FieldTaskList";
|
||||||
|
|
||||||
interface TabPanelProps {
|
interface TabPanelProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
|
@ -218,7 +218,7 @@ export default function FieldDrawer(props: Props) {
|
||||||
TabIndicatorProps={{ style: { background: "rgba(255,255,0,255)" } }}>
|
TabIndicatorProps={{ style: { background: "rgba(255,255,0,255)" } }}>
|
||||||
<Tab label="Field Overview" />
|
<Tab label="Field Overview" />
|
||||||
<Tab label="Weather" />
|
<Tab label="Weather" />
|
||||||
<Tab label="Field Activities" />
|
<Tab label="Field Tasks" />
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<TabPanelMine value={value} index={0}>
|
<TabPanelMine value={value} index={0}>
|
||||||
<Box paddingLeft={2} paddingRight={2} paddingBottom={5}>
|
<Box paddingLeft={2} paddingRight={2} paddingBottom={5}>
|
||||||
|
|
@ -273,7 +273,7 @@ export default function FieldDrawer(props: Props) {
|
||||||
<Weather longitude={field.center().longitude} latitude={field.center().latitude} />
|
<Weather longitude={field.center().longitude} latitude={field.center().latitude} />
|
||||||
</TabPanelMine>
|
</TabPanelMine>
|
||||||
<TabPanelMine value={value} index={2}>
|
<TabPanelMine value={value} index={2}>
|
||||||
<TaskViewer drawerView objectKey={field.key()} loadKeys={taskLoadKeys} overlayButton />
|
<FieldTaskList field={field.key()}/>
|
||||||
</TabPanelMine>
|
</TabPanelMine>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import GrainDescriber from "grain/GrainDescriber";
|
import GrainDescriber from "grain/GrainDescriber";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import { MarkerData } from "maps/mapMarkers/Markers";
|
import { MarkerData } from "maps/mapMarkers/Markers";
|
||||||
|
import { User } from "models";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { getGrainUnit } from "utils";
|
|
||||||
import { stringToMaterialColour } from "utils/strings";
|
import { stringToMaterialColour } from "utils/strings";
|
||||||
import { or } from "utils/types";
|
import { or } from "utils/types";
|
||||||
|
|
||||||
|
|
@ -236,11 +236,11 @@ export class Bin {
|
||||||
return bpt;
|
return bpt;
|
||||||
}
|
}
|
||||||
|
|
||||||
public grainInventory(): number {
|
public grainInventory(user: User): number {
|
||||||
let grain = this.bushels()
|
let grain = this.bushels()
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.bushelsPerTonne() > 1){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.bushelsPerTonne() > 1){
|
||||||
grain = this.bushels() / this.bushelsPerTonne()
|
grain = this.bushels() / this.bushelsPerTonne()
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.bushelsPerTonne() > 1){
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.bushelsPerTonne() > 1){
|
||||||
grain = this.bushels() / (this.bushelsPerTonne() * 0.907)
|
grain = this.bushels() / (this.bushelsPerTonne() * 0.907)
|
||||||
}
|
}
|
||||||
return Math.round(grain*100)/100
|
return Math.round(grain*100)/100
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ import { quack } from "protobuf-ts/pond";
|
||||||
import { or } from "utils/types";
|
import { or } from "utils/types";
|
||||||
import { clone, cloneDeep } from "lodash";
|
import { clone, cloneDeep } from "lodash";
|
||||||
import { Component } from "models";
|
import { Component } from "models";
|
||||||
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
|
||||||
import { extractGrainCable } from "pbHelpers/ComponentTypes";
|
|
||||||
|
|
||||||
export class CO2 {
|
export class CO2 {
|
||||||
public settings: pond.ComponentSettings = pond.ComponentSettings.create();
|
public settings: pond.ComponentSettings = pond.ComponentSettings.create();
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ import { Option } from "common/SearchSelect";
|
||||||
import { GrainOptions, ToGrainOption } from "grain";
|
import { GrainOptions, ToGrainOption } from "grain";
|
||||||
import GrainDescriber from "grain/GrainDescriber";
|
import GrainDescriber from "grain/GrainDescriber";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
|
import { User } from "models";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { getGrainUnit, stringToMaterialColour } from "utils";
|
import { stringToMaterialColour } from "utils";
|
||||||
import { or } from "utils/types";
|
import { or } from "utils/types";
|
||||||
|
|
||||||
export class Contract {
|
export class Contract {
|
||||||
|
|
@ -14,26 +15,28 @@ export class Contract {
|
||||||
public label: string = "";
|
public label: string = "";
|
||||||
private objKey: string = "";
|
private objKey: string = "";
|
||||||
|
|
||||||
public static create(pb?: pond.Contract): Contract {
|
public static create(pb?: pond.Contract, user?: User): Contract {
|
||||||
let my = new Contract();
|
let my = new Contract();
|
||||||
if (pb) {
|
if (pb) {
|
||||||
my.settings = pond.ContractSettings.fromObject(cloneDeep(or(pb.settings, {})));
|
my.settings = pond.ContractSettings.fromObject(cloneDeep(or(pb.settings, {})));
|
||||||
my.title = pb.name;
|
my.title = pb.name;
|
||||||
my.objKey = pb.key;
|
my.objKey = pb.key;
|
||||||
my.unit = my.measurementUnit();
|
my.unit = my.measurementUnit(user);
|
||||||
my.colour = my.commodityColour();
|
my.colour = my.commodityColour();
|
||||||
my.label = my.commodityLabel();
|
my.label = my.commodityLabel();
|
||||||
}
|
}
|
||||||
return my;
|
return my;
|
||||||
}
|
}
|
||||||
|
|
||||||
private measurementUnit(): string {
|
private measurementUnit(user?: User): string {
|
||||||
if (this.settings.type === pond.ContractType.CONTRACT_TYPE_GRAIN) {
|
if (this.settings.type === pond.ContractType.CONTRACT_TYPE_GRAIN) {
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1){
|
if( user ){
|
||||||
return "mT"
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1){
|
||||||
}
|
return "mT"
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.conversionValue() > 1){
|
}
|
||||||
return "t"
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.conversionValue() > 1){
|
||||||
|
return "t"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return "bu";
|
return "bu";
|
||||||
}
|
}
|
||||||
|
|
@ -63,21 +66,22 @@ export class Contract {
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static clone(other?: Contract): Contract {
|
public static clone(other?: Contract, user?: User): Contract {
|
||||||
if (other) {
|
if (other) {
|
||||||
return Contract.create(
|
return Contract.create(
|
||||||
pond.Contract.fromObject({
|
pond.Contract.fromObject({
|
||||||
title: other.title,
|
title: other.title,
|
||||||
key: other.objKey,
|
key: other.objKey,
|
||||||
settings: cloneDeep(other.settings)
|
settings: cloneDeep(other.settings)
|
||||||
})
|
}),
|
||||||
|
user
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Contract.create();
|
return Contract.create(undefined, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static any(data: any): Contract {
|
public static any(data: any, user?: User): Contract {
|
||||||
return Contract.create(pond.Contract.fromObject(cloneDeep(data)));
|
return Contract.create(pond.Contract.fromObject(cloneDeep(data)), user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public key(): string {
|
public key(): string {
|
||||||
|
|
@ -204,28 +208,28 @@ export class Contract {
|
||||||
return this.conversionValue();
|
return this.conversionValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public sizeInPreferredUnit(): number {
|
public sizeInPreferredUnit(user: User): number {
|
||||||
let size = this.settings.size;
|
let size = this.settings.size;
|
||||||
switch (this.settings.type) {
|
switch (this.settings.type) {
|
||||||
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1) {
|
||||||
size = size / this.conversionValue();
|
size = size / this.conversionValue();
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.conversionValue() > 1){
|
if (user.grainUnit() === 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
|
size = size / (this.conversionValue() * 0.907); //the conversion for grain will be stored in metric tonnes, this will convert it to US tons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Math.round(size * 100) / 100;
|
return Math.round(size * 100) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
public deliveredInPreferredUnit(): number {
|
public deliveredInPreferredUnit(user: User): number {
|
||||||
let del = this.settings.delivered;
|
let del = this.settings.delivered;
|
||||||
switch (this.settings.type) {
|
switch (this.settings.type) {
|
||||||
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1) {
|
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1) {
|
||||||
del = del / this.conversionValue();
|
del = del / this.conversionValue();
|
||||||
}
|
}
|
||||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.conversionValue() > 1){
|
if (user.grainUnit() === 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
|
del = del / (this.conversionValue() * 0.907); //the conversion for grain will be stored in metric tonnes, this will convert it to US tons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -237,14 +241,15 @@ export class Contract {
|
||||||
public static toStoredUnit(
|
public static toStoredUnit(
|
||||||
secondaryUnitVal: number,
|
secondaryUnitVal: number,
|
||||||
contractType: pond.ContractType,
|
contractType: pond.ContractType,
|
||||||
conversionValue: number
|
conversionValue: number,
|
||||||
|
user: User
|
||||||
): number {
|
): number {
|
||||||
let storedUnitVal = secondaryUnitVal;
|
let storedUnitVal = secondaryUnitVal;
|
||||||
switch (contractType) {
|
switch (contractType) {
|
||||||
//use the value and conversion they entered directly, it is safe to assume they are both the same unit (ton vs tonne) so dont need to convert anything
|
//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
|
//before converting to bushels
|
||||||
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
||||||
if ((getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE || getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) && conversionValue > 1) {
|
if ((user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE || user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) && conversionValue > 1) {
|
||||||
storedUnitVal = secondaryUnitVal * conversionValue;
|
storedUnitVal = secondaryUnitVal * conversionValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ export class UnitMeasurement {
|
||||||
public static create(pb?: pond.UnitMeasurementsForComponent, user?: User): UnitMeasurement {
|
public static create(pb?: pond.UnitMeasurementsForComponent, user?: User): UnitMeasurement {
|
||||||
let my = new UnitMeasurement();
|
let my = new UnitMeasurement();
|
||||||
if (pb) {
|
if (pb) {
|
||||||
let describer = describeMeasurement(pb.type, pb.componentType);
|
let describer = describeMeasurement(pb.type, pb.componentType, undefined, undefined, user);
|
||||||
let values = pb.values;
|
let values = pb.values;
|
||||||
if (user) {
|
if (user) {
|
||||||
values = unitConversion(pb.values, pb.type, user);
|
values = unitConversion(pb.values, pb.type, user);
|
||||||
|
|
|
||||||
|
|
@ -101,4 +101,20 @@ export class User {
|
||||||
}
|
}
|
||||||
return this.settings.features.includes(flag);
|
return this.settings.features.includes(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public tempUnit(): pond.TemperatureUnit {
|
||||||
|
return this.settings.temperatureUnit
|
||||||
|
}
|
||||||
|
|
||||||
|
public pressureUnit(): pond.PressureUnit {
|
||||||
|
return this.settings.pressureUnit
|
||||||
|
}
|
||||||
|
|
||||||
|
public distanceUnit(): pond.DistanceUnit {
|
||||||
|
return this.settings.distanceUnit
|
||||||
|
}
|
||||||
|
|
||||||
|
public grainUnit(): pond.GrainUnit {
|
||||||
|
return this.settings.grainUnit
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import BinsIcon from "products/Bindapt/BinsIcon";
|
||||||
import { useGlobalState } from "providers";
|
import { useGlobalState } from "providers";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { useNavigate, useLocation } from "react-router-dom";
|
import { useNavigate, useLocation } from "react-router-dom";
|
||||||
import { IsAdaptiveAgriculture, isBXT, IsMiVent, IsAdCon, IsOmniAir, IsMiPCA } from "services/whiteLabel";
|
import { IsAdaptiveAgriculture, isBXT, IsMiVent, IsAdCon, IsOmniAir, IsMiPCA, IsIntellifarms } from "services/whiteLabel";
|
||||||
import FieldsIcon from "products/AgIcons/FieldsIcon";
|
import FieldsIcon from "products/AgIcons/FieldsIcon";
|
||||||
import NexusSTIcon from "products/Construction/NexusSTIcon";
|
import NexusSTIcon from "products/Construction/NexusSTIcon";
|
||||||
import OmniAirDeviceIcon from "products/AviationIcons/OmniAirDeviceIcon";
|
import OmniAirDeviceIcon from "products/AviationIcons/OmniAirDeviceIcon";
|
||||||
|
|
@ -36,7 +36,8 @@ export default function BottomNavigator(props: Props) {
|
||||||
const { isAuthenticated } = useAuth0();
|
const { isAuthenticated } = useAuth0();
|
||||||
const [{ user }] = useGlobalState();
|
const [{ user }] = useGlobalState();
|
||||||
const [route, setRoute] = useState(sideIsOpen ? "side" : "");
|
const [route, setRoute] = useState(sideIsOpen ? "side" : "");
|
||||||
const isAdaptive = IsAdaptiveAgriculture();
|
const isAg = IsAdaptiveAgriculture();
|
||||||
|
const isIntel = IsIntellifarms();
|
||||||
const isMiVent = IsMiVent();
|
const isMiVent = IsMiVent();
|
||||||
const isAdCon = IsAdCon();
|
const isAdCon = IsAdCon();
|
||||||
const isOmni = IsOmniAir();
|
const isOmni = IsOmniAir();
|
||||||
|
|
@ -45,7 +46,7 @@ export default function BottomNavigator(props: Props) {
|
||||||
const reRoute = useCallback(
|
const reRoute = useCallback(
|
||||||
(path: string) => {
|
(path: string) => {
|
||||||
if (path === "") {
|
if (path === "") {
|
||||||
if (isAdaptive) {
|
if (isAg || isIntel) {
|
||||||
return "bins";
|
return "bins";
|
||||||
}
|
}
|
||||||
if (isMiVent) {
|
if (isMiVent) {
|
||||||
|
|
@ -74,7 +75,7 @@ export default function BottomNavigator(props: Props) {
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
},
|
},
|
||||||
[isAdaptive, isMiVent]
|
[isAg, isMiVent, isIntel]
|
||||||
);
|
);
|
||||||
|
|
||||||
const autoDetectRoute = useCallback(() => {
|
const autoDetectRoute = useCallback(() => {
|
||||||
|
|
@ -105,10 +106,10 @@ export default function BottomNavigator(props: Props) {
|
||||||
const authenticatedNavigation = () => {
|
const authenticatedNavigation = () => {
|
||||||
return (
|
return (
|
||||||
<BottomNavigation value={route} onChange={(_, newValue) => handleRouteChange(newValue)}>
|
<BottomNavigation value={route} onChange={(_, newValue) => handleRouteChange(newValue)}>
|
||||||
{isAdaptive && (
|
{isAg || isIntel && (
|
||||||
<BottomNavigationAction label="Farm" icon={<FieldsIcon type={getType()} />} value="visualFarm" />
|
<BottomNavigationAction label="Farm" icon={<FieldsIcon type={getType()} />} value="visualFarm" />
|
||||||
)}
|
)}
|
||||||
{isAdaptive && (
|
{isAg || isIntel && (
|
||||||
<BottomNavigationAction label="Bins" icon={<BinsIcon type={getType()} />} value="bins" />
|
<BottomNavigationAction label="Bins" icon={<BinsIcon type={getType()} />} value="bins" />
|
||||||
)}
|
)}
|
||||||
{isAdCon && (
|
{isAdCon && (
|
||||||
|
|
@ -136,7 +137,7 @@ export default function BottomNavigator(props: Props) {
|
||||||
<BottomNavigationAction
|
<BottomNavigationAction
|
||||||
label="Devices"
|
label="Devices"
|
||||||
icon={
|
icon={
|
||||||
isAdaptive ? (
|
(isAg || isIntel) ? (
|
||||||
<BindaptIcon type={getType()} />
|
<BindaptIcon type={getType()} />
|
||||||
) : isAdCon ? (
|
) : isAdCon ? (
|
||||||
<NexusSTIcon type={getType()} />
|
<NexusSTIcon type={getType()} />
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import {
|
||||||
IsAdaptiveAgriculture,
|
IsAdaptiveAgriculture,
|
||||||
// hasTutorialPlaylist,
|
// hasTutorialPlaylist,
|
||||||
IsAdCon,
|
IsAdCon,
|
||||||
|
IsIntellifarms,
|
||||||
IsMiPCA,
|
IsMiPCA,
|
||||||
// isBXT,
|
// isBXT,
|
||||||
IsMiVent,
|
IsMiVent,
|
||||||
|
|
@ -165,14 +166,15 @@ export default function SideNavigator(props: Props) {
|
||||||
|
|
||||||
const authenticatedSideMenu = () => {
|
const authenticatedSideMenu = () => {
|
||||||
const isMiVent = IsMiVent();
|
const isMiVent = IsMiVent();
|
||||||
const isAg = IsAdaptiveAgriculture()
|
const isAg = IsAdaptiveAgriculture()
|
||||||
|
const isIntel = IsIntellifarms()
|
||||||
const isStreamline = IsStreamline()
|
const isStreamline = IsStreamline()
|
||||||
const isOmni = IsOmniAir()
|
const isOmni = IsOmniAir()
|
||||||
const isMiPCA = IsMiPCA()
|
const isMiPCA = IsMiPCA()
|
||||||
const isAdCon = IsAdCon()
|
const isAdCon = IsAdCon()
|
||||||
return (
|
return (
|
||||||
<List className={classes.list} component="nav">
|
<List className={classes.list} component="nav">
|
||||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||||
<Tooltip title="Visual Farm" placement="right">
|
<Tooltip title="Visual Farm" placement="right">
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
id="tour-visual-farm"
|
id="tour-visual-farm"
|
||||||
|
|
@ -214,7 +216,7 @@ export default function SideNavigator(props: Props) {
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||||
<Tooltip title="Contracts" placement="right">
|
<Tooltip title="Contracts" placement="right">
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
id="tour-contracts"
|
id="tour-contracts"
|
||||||
|
|
@ -228,7 +230,7 @@ export default function SideNavigator(props: Props) {
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||||
<Tooltip title="Bins" placement="right">
|
<Tooltip title="Bins" placement="right">
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
id="tour-bins"
|
id="tour-bins"
|
||||||
|
|
@ -270,7 +272,7 @@ export default function SideNavigator(props: Props) {
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||||
<Tooltip title="Transactions" placement="right">
|
<Tooltip title="Transactions" placement="right">
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
id="tour-transactions"
|
id="tour-transactions"
|
||||||
|
|
@ -362,7 +364,7 @@ export default function SideNavigator(props: Props) {
|
||||||
{open && <ListItemText primary="Users" />}
|
{open && <ListItemText primary="Users" />}
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||||
<Tooltip title="My Fields" placement="right">
|
<Tooltip title="My Fields" placement="right">
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
id="tour-field-list"
|
id="tour-field-list"
|
||||||
|
|
@ -376,7 +378,7 @@ export default function SideNavigator(props: Props) {
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{(isAg || isStreamline || user.hasFeature("admin")) && (
|
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) && (
|
||||||
<Tooltip title="Grain Types" placement="right">
|
<Tooltip title="Grain Types" placement="right">
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
id="tour-grain-types"
|
id="tour-grain-types"
|
||||||
|
|
@ -460,7 +462,7 @@ export default function SideNavigator(props: Props) {
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
{(isAg || isStreamline || user.hasFeature("admin")) &&
|
{(isAg || isIntel || isStreamline || user.hasFeature("admin")) &&
|
||||||
<Tooltip title="Marketplace" placement="right">
|
<Tooltip title="Marketplace" placement="right">
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
id="tour-marketplace"
|
id="tour-marketplace"
|
||||||
|
|
|
||||||
|
|
@ -216,12 +216,16 @@ export default function ObjectHeaterCharts(props: Props) {
|
||||||
let tempDescriber = describeMeasurement(
|
let tempDescriber = describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
||||||
tempComponent.type(),
|
tempComponent.type(),
|
||||||
tempComponent.subType()
|
tempComponent.subType(),
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
);
|
);
|
||||||
let heaterDescriber = describeMeasurement(
|
let heaterDescriber = describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN,
|
quack.MeasurementType.MEASUREMENT_TYPE_BOOLEAN,
|
||||||
heaterComponent.type(),
|
heaterComponent.type(),
|
||||||
heaterComponent.subType()
|
heaterComponent.subType(),
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
);
|
);
|
||||||
let tempData: LineData[] = [];
|
let tempData: LineData[] = [];
|
||||||
heaterTemps.forEach(ht => {
|
heaterTemps.forEach(ht => {
|
||||||
|
|
@ -588,7 +592,9 @@ export default function ObjectHeaterCharts(props: Props) {
|
||||||
describer={describeMeasurement(
|
describer={describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
||||||
tempHum.type(),
|
tempHum.type(),
|
||||||
tempHum.subType()
|
tempHum.subType(),
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
)}
|
)}
|
||||||
lineData={ambientTemps}
|
lineData={ambientTemps}
|
||||||
numLines={1}
|
numLines={1}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,11 @@ import { Column } from "common/ResponsiveTable";
|
||||||
import { Option } from "common/SearchSelect";
|
import { Option } from "common/SearchSelect";
|
||||||
import GrainDescriber from "grain/GrainDescriber";
|
import GrainDescriber from "grain/GrainDescriber";
|
||||||
//import { Column } from "material-table";
|
//import { Column } from "material-table";
|
||||||
import { Bin, BinYard, Field } from "models";
|
import { Bin, BinYard, Field, User } from "models";
|
||||||
//import { Gate } from "models/Gate";
|
//import { Gate } from "models/Gate";
|
||||||
import { GrainBag } from "models/GrainBag";
|
import { GrainBag } from "models/GrainBag";
|
||||||
//import { ObjectHeater } from "models/ObjectHeater";
|
//import { ObjectHeater } from "models/ObjectHeater";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { getDistanceUnit, getTemperatureUnit } from "utils";
|
|
||||||
|
|
||||||
interface Sort {
|
interface Sort {
|
||||||
order: string; //what to send to the backend list to sort by
|
order: string; //what to send to the backend list to sort by
|
||||||
numerical: boolean; //whether to use a numerical or text sort
|
numerical: boolean; //whether to use a numerical or text sort
|
||||||
|
|
@ -20,6 +18,8 @@ export interface ObjectExtension {
|
||||||
isTransactionObject: boolean;
|
isTransactionObject: boolean;
|
||||||
//this will define the columns to be used for the object in a material table
|
//this will define the columns to be used for the object in a material table
|
||||||
tableColumns: Column<any>[];
|
tableColumns: Column<any>[];
|
||||||
|
// Optional factory so columns can depend on the active user settings (units, formatting, etc.)
|
||||||
|
getTableColumns?: (user?: User) => Column<any>[];
|
||||||
//this map will match the title of the column to what the backend needs to perform the ordering
|
//this map will match the title of the column to what the backend needs to perform the ordering
|
||||||
tableSort: Map<string, Sort>;
|
tableSort: Map<string, Sort>;
|
||||||
}
|
}
|
||||||
|
|
@ -32,6 +32,202 @@ const defaultObject: ObjectExtension = {
|
||||||
tableSort: new Map()
|
tableSort: new Map()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const binColumns = (user?: User): Column<any>[] => {
|
||||||
|
const temperatureUnit =
|
||||||
|
user?.tempUnit() ?? pond.TemperatureUnit.TEMPERATURE_UNIT_CELSIUS;
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: "Name",
|
||||||
|
cellStyle: {padding: "16px"},
|
||||||
|
render: row => {
|
||||||
|
return (<div>{row.settings.name}</div>);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Grain",
|
||||||
|
cellStyle: {padding: "16px"},
|
||||||
|
render: row => {
|
||||||
|
let grain = row.settings.inventory?.grainType;
|
||||||
|
if (grain) {
|
||||||
|
return GrainDescriber(grain).name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Bin Height",
|
||||||
|
cellStyle: {padding: "16px"},
|
||||||
|
render: row => {
|
||||||
|
let d = row.settings.specs?.heightCm;
|
||||||
|
if (d) {
|
||||||
|
if (
|
||||||
|
(user?.distanceUnit() ?? pond.DistanceUnit.DISTANCE_UNIT_FEET) ===
|
||||||
|
pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||||
|
) {
|
||||||
|
return (d / 100).toFixed(2) + " m";
|
||||||
|
} else {
|
||||||
|
return (d / 30.48).toFixed(2) + " ft";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Bin Diameter",
|
||||||
|
cellStyle: {padding: "16px"},
|
||||||
|
render: row => {
|
||||||
|
let d = row.settings.specs?.diameterCm;
|
||||||
|
if (d) {
|
||||||
|
if (
|
||||||
|
(user?.distanceUnit() ?? pond.DistanceUnit.DISTANCE_UNIT_FEET) ===
|
||||||
|
pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||||
|
) {
|
||||||
|
return (d / 100).toFixed(2) + " m";
|
||||||
|
} else {
|
||||||
|
return (d / 30.48).toFixed(2) + " ft";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Custom Grain Name",
|
||||||
|
cellStyle: {padding: "16px"},
|
||||||
|
render: row => {
|
||||||
|
return row.settings.inventory?.customTypeName;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Grain Variant",
|
||||||
|
cellStyle: {padding: "16px"},
|
||||||
|
render: row => {
|
||||||
|
return row.settings.inventory?.grainSubtype;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Grain Bushels",
|
||||||
|
cellStyle: {padding: "16px"},
|
||||||
|
render: row => {
|
||||||
|
return (<div>{row.settings.inventory ? isNaN(row.settings.inventory.grainBushels) ? 0 : row.settings.inventory.grainBushels : 0}</div>);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Grain Capacity",
|
||||||
|
cellStyle: {padding: "16px"},
|
||||||
|
render: row => {
|
||||||
|
return row.settings.specs?.bushelCapacity;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "High Temp Warning",
|
||||||
|
cellStyle: {padding: "16px"},
|
||||||
|
render: row => {
|
||||||
|
let t = row.settings.highTemp;
|
||||||
|
if (t) {
|
||||||
|
if (temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
|
return (t * 1.8 + 32).toFixed(2) + " °F";
|
||||||
|
}
|
||||||
|
return t.toFixed(2) + " °C";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Low Temp Warning",
|
||||||
|
cellStyle: {padding: "16px"},
|
||||||
|
render: row => {
|
||||||
|
let t = row.settings.lowTemp;
|
||||||
|
if (t) {
|
||||||
|
if (temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
|
return (t * 1.8 + 32).toFixed(2) + " °F";
|
||||||
|
}
|
||||||
|
return t.toFixed(2) + " °C";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
] as Column<Bin>[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const grainBagColumns = (user?: User): Column<GrainBag>[] => {
|
||||||
|
const distanceUnit =
|
||||||
|
user?.distanceUnit() ?? pond.DistanceUnit.DISTANCE_UNIT_FEET;
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: "Name",
|
||||||
|
render: row => {
|
||||||
|
if (row.title) {
|
||||||
|
return (<div>{row.title.toString()}</div>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Length",
|
||||||
|
render: row => {
|
||||||
|
if (row.settings.length) {
|
||||||
|
if (distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
|
return row.settings.length.toFixed(2) + " m";
|
||||||
|
} else {
|
||||||
|
return (row.settings.length * 3.281).toFixed(2) + " ft";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Diameter",
|
||||||
|
render: row => {
|
||||||
|
if (row.settings.diameter) {
|
||||||
|
if (distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
|
return row.settings.diameter.toFixed(2) + " m";
|
||||||
|
} else {
|
||||||
|
return (row.settings.diameter * 3.281).toFixed(2) + " ft";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Grain",
|
||||||
|
render: row => {
|
||||||
|
if (row.settings.supportedGrain) {
|
||||||
|
return GrainDescriber(row.settings.supportedGrain).name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Custom Grain",
|
||||||
|
render: row => {
|
||||||
|
return row.settings.customGrain;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Grain Variant",
|
||||||
|
render: row => {
|
||||||
|
return row.settings.grainSubtype;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Capacity",
|
||||||
|
render: row => {
|
||||||
|
return row.settings.bushelCapacity + " bu";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Bushels",
|
||||||
|
render: row => {
|
||||||
|
return row.settings.currentBushels + " bu";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Fill Date",
|
||||||
|
render: row => {
|
||||||
|
return row.settings.fillDate;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Initial Moisture",
|
||||||
|
render: row => {
|
||||||
|
return row.settings.initialMoisture + "%";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
] as Column<GrainBag>[];
|
||||||
|
};
|
||||||
|
|
||||||
export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
|
export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
|
||||||
[pond.ObjectType.OBJECT_TYPE_UNKNOWN, defaultObject],
|
[pond.ObjectType.OBJECT_TYPE_UNKNOWN, defaultObject],
|
||||||
[
|
[
|
||||||
|
|
@ -50,109 +246,8 @@ export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
|
||||||
name: "Bin",
|
name: "Bin",
|
||||||
inventoryGroup: "grain",
|
inventoryGroup: "grain",
|
||||||
isTransactionObject: true,
|
isTransactionObject: true,
|
||||||
tableColumns: [
|
tableColumns: binColumns(),
|
||||||
{
|
getTableColumns: (user?: User) => binColumns(user),
|
||||||
title: "Name",
|
|
||||||
cellStyle: {padding: "16px"},
|
|
||||||
render: row => {
|
|
||||||
return (<div>{row.settings.name}</div>);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Grain",
|
|
||||||
cellStyle: {padding: "16px"},
|
|
||||||
render: row => {
|
|
||||||
let grain = row.settings.inventory?.grainType;
|
|
||||||
if (grain) {
|
|
||||||
return GrainDescriber(grain).name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Bin Height",
|
|
||||||
cellStyle: {padding: "16px"},
|
|
||||||
render: row => {
|
|
||||||
let d = row.settings.specs?.heightCm;
|
|
||||||
if (d) {
|
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
|
||||||
return (d / 100).toFixed(2) + " m";
|
|
||||||
} else {
|
|
||||||
return (d / 30.48).toFixed(2) + " ft";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Bin Diameter",
|
|
||||||
cellStyle: {padding: "16px"},
|
|
||||||
render: row => {
|
|
||||||
let d = row.settings.specs?.diameterCm;
|
|
||||||
if (d) {
|
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
|
||||||
return (d / 100).toFixed(2) + " m";
|
|
||||||
} else {
|
|
||||||
return (d / 30.48).toFixed(2) + " ft";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Custom Grain Name",
|
|
||||||
cellStyle: {padding: "16px"},
|
|
||||||
render: row => {
|
|
||||||
return row.settings.inventory?.customTypeName;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Grain Variant",
|
|
||||||
cellStyle: {padding: "16px"},
|
|
||||||
render: row => {
|
|
||||||
return row.settings.inventory?.grainSubtype;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Grain Bushels",
|
|
||||||
cellStyle: {padding: "16px"},
|
|
||||||
render: row => {
|
|
||||||
return (<div>{row.settings.inventory ? isNaN(row.settings.inventory.grainBushels) ? 0 : row.settings.inventory.grainBushels : 0}</div>);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Grain Capacity",
|
|
||||||
cellStyle: {padding: "16px"},
|
|
||||||
render: row => {
|
|
||||||
return row.settings.specs?.bushelCapacity;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "High Temp Warning",
|
|
||||||
cellStyle: {padding: "16px"},
|
|
||||||
render: row => {
|
|
||||||
let t = row.settings.highTemp;
|
|
||||||
if (t) {
|
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
|
||||||
return (t * 1.8 + 32).toFixed(2) + " °F";
|
|
||||||
} else {
|
|
||||||
return t.toFixed(2) + " °C";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Low Temp Warning",
|
|
||||||
cellStyle: {padding: "16px"},
|
|
||||||
render: row => {
|
|
||||||
let t = row.settings.lowTemp;
|
|
||||||
if (t) {
|
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
|
||||||
return (t * 1.8 + 32).toFixed(2) + " °F";
|
|
||||||
} else {
|
|
||||||
return t.toFixed(2) + " °C";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
] as Column<Bin>[],
|
|
||||||
tableSort: new Map([
|
tableSort: new Map([
|
||||||
["Name", { order: "name", numerical: false }],
|
["Name", { order: "name", numerical: false }],
|
||||||
["Grain", { order: "inventory.grainType", numerical: false }],
|
["Grain", { order: "inventory.grainType", numerical: false }],
|
||||||
|
|
@ -395,84 +490,8 @@ export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
|
||||||
name: "Grainbag",
|
name: "Grainbag",
|
||||||
inventoryGroup: "grain",
|
inventoryGroup: "grain",
|
||||||
isTransactionObject: true,
|
isTransactionObject: true,
|
||||||
tableColumns: [
|
tableColumns: grainBagColumns(),
|
||||||
{
|
getTableColumns: (user?: User) => grainBagColumns(user),
|
||||||
title: "Name",
|
|
||||||
render: row => {
|
|
||||||
if (row.title) {
|
|
||||||
return (<div>{row.title.toString()}</div>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Length",
|
|
||||||
render: row => {
|
|
||||||
if (row.settings.length) {
|
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
|
||||||
return row.settings.length.toFixed(2) + " m";
|
|
||||||
} else {
|
|
||||||
return (row.settings.length * 3.281).toFixed(2) + " ft";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Diameter",
|
|
||||||
render: row => {
|
|
||||||
if (row.settings.diameter) {
|
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
|
||||||
return row.settings.diameter.toFixed(2) + " m";
|
|
||||||
} else {
|
|
||||||
return (row.settings.diameter * 3.281).toFixed(2) + " ft";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Grain",
|
|
||||||
render: row => {
|
|
||||||
if (row.settings.supportedGrain) {
|
|
||||||
return GrainDescriber(row.settings.supportedGrain).name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Custom Grain",
|
|
||||||
render: row => {
|
|
||||||
return row.settings.customGrain;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Grain Variant",
|
|
||||||
render: row => {
|
|
||||||
return row.settings.grainSubtype;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Capacity",
|
|
||||||
render: row => {
|
|
||||||
return row.settings.bushelCapacity + " bu";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Bushels",
|
|
||||||
render: row => {
|
|
||||||
return row.settings.currentBushels + " bu";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Fill Date",
|
|
||||||
render: row => {
|
|
||||||
return row.settings.fillDate;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Initial Moisture",
|
|
||||||
render: row => {
|
|
||||||
return row.settings.initialMoisture + "%";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
] as Column<GrainBag>[],
|
|
||||||
tableSort: new Map([
|
tableSort: new Map([
|
||||||
["Name", { order: "name", numerical: false }],
|
["Name", { order: "name", numerical: false }],
|
||||||
["Length", { order: "length", numerical: true }],
|
["Length", { order: "length", numerical: true }],
|
||||||
|
|
@ -708,8 +727,7 @@ export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export default function ObjectDescriber(type: pond.ObjectType): ObjectExtension {
|
export default function ObjectDescriber(type: pond.ObjectType): ObjectExtension {
|
||||||
let describer = ObjectExtensions.get(type);
|
return ObjectExtensions.get(type) ?? defaultObject;
|
||||||
return describer ? describer : defaultObject;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -745,7 +763,8 @@ export function SearchableObjects(): Option[] {
|
||||||
Object.values(pond.ObjectType).forEach(obj => {
|
Object.values(pond.ObjectType).forEach(obj => {
|
||||||
if (typeof obj !== "string") {
|
if (typeof obj !== "string") {
|
||||||
let ext = ObjectDescriber(obj);
|
let ext = ObjectDescriber(obj);
|
||||||
if (ext.tableColumns.length > 0) {
|
const columns = ext.getTableColumns ? ext.getTableColumns() : ext.tableColumns;
|
||||||
|
if (columns.length > 0) {
|
||||||
options.push({
|
options.push({
|
||||||
label: ext.name,
|
label: ext.name,
|
||||||
value: obj
|
value: obj
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { Box, Button, Grid2 as Grid } from "@mui/material";
|
import { Box, Button, Grid2 as Grid } from "@mui/material";
|
||||||
// import { getTableIcons } from "common/ResponsiveTable";
|
// import { getTableIcons } from "common/ResponsiveTable";
|
||||||
import SearchBar from "common/SearchBar";
|
|
||||||
import SearchSelect, { Option } from "common/SearchSelect";
|
import SearchSelect, { Option } from "common/SearchSelect";
|
||||||
// import MaterialTable, { MTableToolbar } from "material-table";
|
// import MaterialTable, { MTableToolbar } from "material-table";
|
||||||
// import { Bin, BinYard, Field } from "models";
|
// import { Bin, BinYard, Field } from "models";
|
||||||
|
|
@ -22,9 +21,8 @@ import {
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import TeamSearch from "teams/TeamSearch";
|
import TeamSearch from "teams/TeamSearch";
|
||||||
import BulkBinSettings from "./bulkEditForms/bulkBinSettings";
|
import BulkBinSettings from "./bulkEditForms/bulkBinSettings";
|
||||||
import BulkGrainBagSettings from "./bulkEditForms/bulkGrainBagSettings";
|
|
||||||
import ResponsiveTable from "common/ResponsiveTable";
|
import ResponsiveTable from "common/ResponsiveTable";
|
||||||
import { cloneDeep, indexOf } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
//import BulkGateSettings from "./bulkEditForms/bulkGateSettings";
|
//import BulkGateSettings from "./bulkEditForms/bulkGateSettings";
|
||||||
|
|
||||||
interface customButton {
|
interface customButton {
|
||||||
|
|
@ -61,6 +59,9 @@ export default function ObjectTable(props: Props) {
|
||||||
const [selectedUser, setSelectedUser] = useState<string>(as ?? user.id());
|
const [selectedUser, setSelectedUser] = useState<string>(as ?? user.id());
|
||||||
const [selectedPageRows, setSelectedPageRows] = useState<Map<number, number[]>>(new Map())//key is the page value is an array of row indexes for that page
|
const [selectedPageRows, setSelectedPageRows] = useState<Map<number, number[]>>(new Map())//key is the page value is an array of row indexes for that page
|
||||||
const [tableLoading, setTableLoading] = useState(false);
|
const [tableLoading, setTableLoading] = useState(false);
|
||||||
|
|
||||||
|
const objectExtension = ObjectDescriber(currentType);
|
||||||
|
const columns = objectExtension.getTableColumns ? objectExtension.getTableColumns(user) : objectExtension.tableColumns;
|
||||||
//the api's to load all the objects available to look at in this table
|
//the api's to load all the objects available to look at in this table
|
||||||
const binAPI = useBinAPI();
|
const binAPI = useBinAPI();
|
||||||
const binyardAPI = useBinYardAPI();
|
const binyardAPI = useBinYardAPI();
|
||||||
|
|
@ -366,7 +367,7 @@ export default function ObjectTable(props: Props) {
|
||||||
|
|
||||||
<ResponsiveTable
|
<ResponsiveTable
|
||||||
rows={tableData}
|
rows={tableData}
|
||||||
columns={ObjectDescriber(currentType).tableColumns}
|
columns={columns}
|
||||||
onRowClick={rowClickFunction}
|
onRowClick={rowClickFunction}
|
||||||
total={objectTotal}
|
total={objectTotal}
|
||||||
pageSize={pageSize}
|
pageSize={pageSize}
|
||||||
|
|
@ -383,7 +384,7 @@ export default function ObjectTable(props: Props) {
|
||||||
key="objectList"
|
key="objectList"
|
||||||
title={ObjectDescriber(currentType).name}
|
title={ObjectDescriber(currentType).name}
|
||||||
icons={getTableIcons()}
|
icons={getTableIcons()}
|
||||||
columns={ObjectDescriber(currentType).tableColumns}
|
columns={ObjectDescriber(currentType, user).tableColumns}
|
||||||
data={tableData}
|
data={tableData}
|
||||||
page={tablePage}
|
page={tablePage}
|
||||||
totalCount={objectTotal}
|
totalCount={objectTotal}
|
||||||
|
|
@ -399,10 +400,10 @@ export default function ObjectTable(props: Props) {
|
||||||
}}
|
}}
|
||||||
onOrderChange={(by, direction) => {
|
onOrderChange={(by, direction) => {
|
||||||
if (by !== -1) {
|
if (by !== -1) {
|
||||||
let colName = ObjectDescriber(currentType).tableColumns[by].title?.toString();
|
let colName = ObjectDescriber(currentType, user).tableColumns[by].title?.toString();
|
||||||
let order;
|
let order;
|
||||||
if (colName) {
|
if (colName) {
|
||||||
order = ObjectDescriber(currentType).tableSort.get(colName);
|
order = ObjectDescriber(currentType, user).tableSort.get(colName);
|
||||||
setCurrentOrder(order?.order);
|
setCurrentOrder(order?.order);
|
||||||
setCurrentDirection(direction);
|
setCurrentDirection(direction);
|
||||||
setIsNumerical(order?.numerical);
|
setIsNumerical(order?.numerical);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { GrainOptions } from "grain";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useBinAPI, useGlobalState, useSnackbar } from "providers";
|
import { useBinAPI, useGlobalState, useSnackbar } from "providers";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { fahrenheitToCelsius, getDistanceUnit, getTemperatureUnit } from "utils";
|
import { fahrenheitToCelsius } from "utils";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
selectedBins: pond.Bin[];
|
selectedBins: pond.Bin[];
|
||||||
|
|
@ -19,7 +19,7 @@ export default function BulkBinSettings(props: Props) {
|
||||||
const gridItemWidth = 3;
|
const gridItemWidth = 3;
|
||||||
// bin settings variables
|
// bin settings variables
|
||||||
const [name, setName] = useState<string | undefined>();
|
const [name, setName] = useState<string | undefined>();
|
||||||
const [{as}] = useGlobalState();
|
const [{as, user}] = useGlobalState();
|
||||||
const [grainType, setGrainType] = useState<pond.Grain | undefined>();
|
const [grainType, setGrainType] = useState<pond.Grain | undefined>();
|
||||||
const [grainOption, setGrainOption] = useState<Option | null>();
|
const [grainOption, setGrainOption] = useState<Option | null>();
|
||||||
const [height, setHeight] = useState<number | undefined>();
|
const [height, setHeight] = useState<number | undefined>();
|
||||||
|
|
@ -32,10 +32,10 @@ export default function BulkBinSettings(props: Props) {
|
||||||
const [lowTemp, setLowTemp] = useState<number | undefined>();
|
const [lowTemp, setLowTemp] = useState<number | undefined>();
|
||||||
|
|
||||||
const convertedDistance = (enteredDistance: number) => {
|
const convertedDistance = (enteredDistance: number) => {
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||||
return enteredDistance * 100;
|
return enteredDistance * 100;
|
||||||
}
|
}
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
return enteredDistance * 30.48;
|
return enteredDistance * 30.48;
|
||||||
}
|
}
|
||||||
return enteredDistance;
|
return enteredDistance;
|
||||||
|
|
@ -43,7 +43,7 @@ export default function BulkBinSettings(props: Props) {
|
||||||
|
|
||||||
const convertedTemp = (enteredTemp: number) => {
|
const convertedTemp = (enteredTemp: number) => {
|
||||||
let t = enteredTemp;
|
let t = enteredTemp;
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
t = fahrenheitToCelsius(enteredTemp);
|
t = fahrenheitToCelsius(enteredTemp);
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
|
|
@ -168,7 +168,7 @@ export default function BulkBinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -186,7 +186,7 @@ export default function BulkBinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
|
@ -204,7 +204,7 @@ export default function BulkBinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||||
? "°F"
|
? "°F"
|
||||||
: "°C"}
|
: "°C"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
@ -224,7 +224,7 @@ export default function BulkBinSettings(props: Props) {
|
||||||
InputProps={{
|
InputProps={{
|
||||||
endAdornment: (
|
endAdornment: (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||||
? "°F"
|
? "°F"
|
||||||
: "°C"}
|
: "°C"}
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import { GrainBag } from "models/GrainBag";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { useGlobalState, useGrainBagAPI, useSnackbar } from "providers";
|
import { useGlobalState, useGrainBagAPI, useSnackbar } from "providers";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { getDistanceUnit } from "utils";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
selectedBags: GrainBag[];
|
selectedBags: GrainBag[];
|
||||||
|
|
@ -28,10 +27,10 @@ export default function BulkGrainBagSettings(props: Props) {
|
||||||
const [bushels, setBushels] = useState<number | undefined>();
|
const [bushels, setBushels] = useState<number | undefined>();
|
||||||
const [fillDate, setFillDate] = useState<string | undefined>();
|
const [fillDate, setFillDate] = useState<string | undefined>();
|
||||||
const [initialMoisture, setInitialMoisture] = useState<number | undefined>();
|
const [initialMoisture, setInitialMoisture] = useState<number | undefined>();
|
||||||
const [{as}] = useGlobalState();
|
const [{ as, user }] = useGlobalState();
|
||||||
|
|
||||||
const convertedDistance = (enteredDistance: number) => {
|
const convertedDistance = (enteredDistance: number) => {
|
||||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
return enteredDistance / 3.281;
|
return enteredDistance / 3.281;
|
||||||
}
|
}
|
||||||
return enteredDistance;
|
return enteredDistance;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { pond, quack } from "protobuf-ts/pond";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import NewObjectInteraction from "./NewObjectInteraction";
|
import NewObjectInteraction from "./NewObjectInteraction";
|
||||||
import { Option } from "common/SearchSelect";
|
import { Option } from "common/SearchSelect";
|
||||||
|
import { useGlobalState } from "providers";
|
||||||
|
|
||||||
export interface Alert {
|
export interface Alert {
|
||||||
conditions: pond.InteractionCondition[];
|
conditions: pond.InteractionCondition[];
|
||||||
|
|
@ -20,10 +21,11 @@ interface Props {
|
||||||
|
|
||||||
export default function Alerts(props: Props){
|
export default function Alerts(props: Props){
|
||||||
const {alerts, addNew, permissions} = props
|
const {alerts, addNew, permissions} = props
|
||||||
|
const [{user}] = useGlobalState();
|
||||||
// const [openNewAlert, setOpenNewAlert] = useState(false)
|
// const [openNewAlert, setOpenNewAlert] = useState(false)
|
||||||
|
|
||||||
const readableCondition = (condition: pond.InteractionCondition) => {
|
const readableCondition = (condition: pond.InteractionCondition) => {
|
||||||
let describer = describeMeasurement(condition.measurementType);
|
let describer = describeMeasurement(condition.measurementType, undefined, undefined, undefined, user);
|
||||||
let type = describer.label();
|
let type = describer.label();
|
||||||
let comparison =
|
let comparison =
|
||||||
condition.comparison === quack.RelationalOperator.RELATIONAL_OPERATOR_EQUAL_TO
|
condition.comparison === quack.RelationalOperator.RELATIONAL_OPERATOR_EQUAL_TO
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { Component, Device, Interaction } from "models";
|
||||||
import { interactionResultText } from "pbHelpers/Interaction";
|
import { interactionResultText } from "pbHelpers/Interaction";
|
||||||
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
||||||
import { pond, quack } from "protobuf-ts/pond";
|
import { pond, quack } from "protobuf-ts/pond";
|
||||||
|
import { useGlobalState } from "providers";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
export interface Control {
|
export interface Control {
|
||||||
|
|
@ -23,6 +24,7 @@ interface Props {
|
||||||
|
|
||||||
export default function Controls(props: Props){
|
export default function Controls(props: Props){
|
||||||
const { devices, controls, addNew, permissions } = props
|
const { devices, controls, addNew, permissions } = props
|
||||||
|
const [{user}] = useGlobalState();
|
||||||
const [deviceControls, setDeviceControls] = useState<Map<number, Control[]>>(new Map())
|
const [deviceControls, setDeviceControls] = useState<Map<number, Control[]>>(new Map())
|
||||||
const [openDeviceMenu, setOpenDeviceMenu] = useState(false)
|
const [openDeviceMenu, setOpenDeviceMenu] = useState(false)
|
||||||
const [anchor, setAnchor] = useState<null | HTMLElement>(null)
|
const [anchor, setAnchor] = useState<null | HTMLElement>(null)
|
||||||
|
|
@ -45,7 +47,7 @@ export default function Controls(props: Props){
|
||||||
let conditions: string = ""
|
let conditions: string = ""
|
||||||
let firstSource = control.sourceComponents[0]
|
let firstSource = control.sourceComponents[0]
|
||||||
control.conditions.forEach((condition, index) => {
|
control.conditions.forEach((condition, index) => {
|
||||||
let describer = describeMeasurement(condition.measurementType, firstSource.type(), firstSource.subType());
|
let describer = describeMeasurement(condition.measurementType, firstSource.type(), firstSource.subType(), undefined, user);
|
||||||
let type = describer.label();
|
let type = describer.label();
|
||||||
let comparison =
|
let comparison =
|
||||||
condition.comparison === quack.RelationalOperator.RELATIONAL_OPERATOR_EQUAL_TO
|
condition.comparison === quack.RelationalOperator.RELATIONAL_OPERATOR_EQUAL_TO
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ const useStyles = makeStyles((theme: Theme) => {
|
||||||
export default function NewObjectInteraction(props: Props){
|
export default function NewObjectInteraction(props: Props){
|
||||||
const { open, onClose, device, linkedComponents, componentDevices } = props
|
const { open, onClose, device, linkedComponents, componentDevices } = props
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const [{ as }] = useGlobalState();
|
const [{ as, user }] = useGlobalState();
|
||||||
const {openSnack} = useSnackbar();
|
const {openSnack} = useSnackbar();
|
||||||
const interactionsAPI = useInteractionsAPI();
|
const interactionsAPI = useInteractionsAPI();
|
||||||
const [newAlertComponentType, setNewAlertComponentType] = useState<quack.ComponentType>(
|
const [newAlertComponentType, setNewAlertComponentType] = useState<quack.ComponentType>(
|
||||||
|
|
@ -249,7 +249,7 @@ export default function NewObjectInteraction(props: Props){
|
||||||
const measurementTypeMenuItems = () => {
|
const measurementTypeMenuItems = () => {
|
||||||
return availableMeasurementTypes(newAlertComponentType).map(measurementType => (
|
return availableMeasurementTypes(newAlertComponentType).map(measurementType => (
|
||||||
<MenuItem key={measurementType} value={measurementType}>
|
<MenuItem key={measurementType} value={measurementType}>
|
||||||
{describeMeasurement(measurementType).label()}
|
{describeMeasurement(measurementType, undefined, undefined, undefined, user).label()}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
@ -531,7 +531,9 @@ export default function NewObjectInteraction(props: Props){
|
||||||
return describeMeasurement(
|
return describeMeasurement(
|
||||||
Measurement.boolean,
|
Measurement.boolean,
|
||||||
or(sink, Component.create()).settings.type,
|
or(sink, Component.create()).settings.type,
|
||||||
or(sink, Component.create()).settings.subtype
|
or(sink, Component.create()).settings.subtype,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ export default function Bin(props: Props) {
|
||||||
resp.data.devices.forEach((dev: any) => {
|
resp.data.devices.forEach((dev: any) => {
|
||||||
let device = Device.create(dev);
|
let device = Device.create(dev);
|
||||||
if (attachedDevIds.includes(device.id())) {
|
if (attachedDevIds.includes(device.id())) {
|
||||||
devs.push(Device.create(dev));
|
devs.push(device);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setDevices(devs);
|
setDevices(devs);
|
||||||
|
|
@ -512,7 +512,7 @@ export default function Bin(props: Props) {
|
||||||
if (showTasks()) {
|
if (showTasks()) {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<TaskViewer drawerView objectKey={binID} loadKeys={[binID]} />
|
<TaskViewer drawerView keys={[binID]} types={["bin"]} overlayButton />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -674,6 +674,8 @@ export default function Bin(props: Props) {
|
||||||
userID={user.id()}
|
userID={user.id()}
|
||||||
components={components}
|
components={components}
|
||||||
setComponents={setComponents}
|
setComponents={setComponents}
|
||||||
|
componentDevices={componentDevices}
|
||||||
|
setComponentDevices={setComponentDevices}
|
||||||
updateBinStatus={updateStatus}
|
updateBinStatus={updateStatus}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -1156,7 +1158,7 @@ export default function Bin(props: Props) {
|
||||||
<IconButton style={{ width: 50 }} onClick={() => setTaskDrawer(false)}>
|
<IconButton style={{ width: 50 }} onClick={() => setTaskDrawer(false)}>
|
||||||
<Close />
|
<Close />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<TaskViewer drawerView objectKey={binID} loadKeys={[binID]} />
|
<TaskViewer drawerView keys={[binID]} types={["bin"]} overlayButton />
|
||||||
</Box>
|
</Box>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ import {
|
||||||
} from "providers";
|
} from "providers";
|
||||||
import React, { SetStateAction, useCallback, useEffect, useState } from "react";
|
import React, { SetStateAction, useCallback, useEffect, useState } from "react";
|
||||||
// import { getThemeType } from "theme";
|
// import { getThemeType } from "theme";
|
||||||
import { getGrainUnit, stringToMaterialColour } from "utils";
|
import { stringToMaterialColour } from "utils";
|
||||||
//import InfiniteScroll from "react-infinite-scroller";
|
//import InfiniteScroll from "react-infinite-scroller";
|
||||||
import PageContainer from "./PageContainer";
|
import PageContainer from "./PageContainer";
|
||||||
import ObjectTable from "objects/ObjectTable";
|
import ObjectTable from "objects/ObjectTable";
|
||||||
|
|
@ -569,7 +569,11 @@ export default function Bins(props: Props) {
|
||||||
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
measurementType: quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
||||||
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
comparison: quack.RelationalOperator.RELATIONAL_OPERATOR_GREATER_THAN,
|
||||||
value: describeMeasurement(
|
value: describeMeasurement(
|
||||||
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE
|
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
user
|
||||||
).toStored(bin.settings.highTemp)
|
).toStored(bin.settings.highTemp)
|
||||||
}),
|
}),
|
||||||
componentLocation: quack.ComponentID.create({
|
componentLocation: quack.ComponentID.create({
|
||||||
|
|
@ -934,7 +938,7 @@ export default function Bins(props: Props) {
|
||||||
return " bu";
|
return " bu";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (getGrainUnit()) {
|
switch (user.grainUnit()) {
|
||||||
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
||||||
return " mT";
|
return " mT";
|
||||||
case pond.GrainUnit.GRAIN_UNIT_TON:
|
case pond.GrainUnit.GRAIN_UNIT_TON:
|
||||||
|
|
@ -947,9 +951,9 @@ export default function Bins(props: Props) {
|
||||||
const customQuantityDisplay = (customInventory: pond.CustomInventory, bushels: number) => {
|
const customQuantityDisplay = (customInventory: pond.CustomInventory, bushels: number) => {
|
||||||
let amount = bushels
|
let amount = bushels
|
||||||
if(customInventory.bushelsPerTonne > 1){
|
if(customInventory.bushelsPerTonne > 1){
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
amount = bushels/customInventory.bushelsPerTonne
|
amount = bushels/customInventory.bushelsPerTonne
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
amount = bushels/(customInventory.bushelsPerTonne*0.907)
|
amount = bushels/(customInventory.bushelsPerTonne*0.907)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -959,9 +963,9 @@ export default function Bins(props: Props) {
|
||||||
const supportedGrainDisplay = (grain: pond.Grain, bushels: number) => {
|
const supportedGrainDisplay = (grain: pond.Grain, bushels: number) => {
|
||||||
const describer = GrainDescriber(grain)
|
const describer = GrainDescriber(grain)
|
||||||
let amount = bushels
|
let amount = bushels
|
||||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||||
amount = bushels/describer.bushelsPerTonne
|
amount = bushels/describer.bushelsPerTonne
|
||||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||||
amount = bushels/describer.bushelsPerTon
|
amount = bushels/describer.bushelsPerTon
|
||||||
}
|
}
|
||||||
return Math.round(amount*100)/100
|
return Math.round(amount*100)/100
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import PageContainer from "./PageContainer";
|
||||||
|
|
||||||
export default function Contracts() {
|
export default function Contracts() {
|
||||||
const [openSettings, setOpenSettings] = useState(false);
|
const [openSettings, setOpenSettings] = useState(false);
|
||||||
const [{ as }] = useGlobalState()
|
const [{ as, user }] = useGlobalState()
|
||||||
const contractAPI = useContractAPI();
|
const contractAPI = useContractAPI();
|
||||||
const [contracts, setContracts] = useState<Contract[]>([]);
|
const [contracts, setContracts] = useState<Contract[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
@ -42,7 +42,7 @@ export default function Contracts() {
|
||||||
let contractPermissions: Map<string, pond.Permission[]> = new Map();
|
let contractPermissions: Map<string, pond.Permission[]> = new Map();
|
||||||
if (resp.data.contracts){
|
if (resp.data.contracts){
|
||||||
resp.data.contracts.forEach(contract => {
|
resp.data.contracts.forEach(contract => {
|
||||||
let c = Contract.create(contract);
|
let c = Contract.create(contract, user);
|
||||||
contracts.push(c);
|
contracts.push(c);
|
||||||
let p = pond.EvaluatePermissionsResponse.fromObject(
|
let p = pond.EvaluatePermissionsResponse.fromObject(
|
||||||
resp.data.contractPermissions[c.key()]
|
resp.data.contractPermissions[c.key()]
|
||||||
|
|
@ -56,7 +56,7 @@ export default function Contracts() {
|
||||||
})
|
})
|
||||||
.catch(err => {});
|
.catch(err => {});
|
||||||
}
|
}
|
||||||
}, [contractAPI, year, as]); // eslint-disable-line react-hooks/exhaustive-deps
|
}, [contractAPI, year, as, user]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ import Grid from '@mui/material/Grid2';
|
||||||
import { Component, Device, Interaction, User } from "models";
|
import { Component, Device, Interaction, User } from "models";
|
||||||
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
||||||
import { useDeviceAPI, useGlobalState, useSnackbar } from "providers";
|
import { useDeviceAPI, useGlobalState, useSnackbar } from "providers";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useDeviceStatusStreams } from "hooks/useDeviceStatusStreams";
|
||||||
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { useLocation, useParams } from "react-router-dom";
|
import { useLocation, useParams } from "react-router-dom";
|
||||||
import PageContainer from "./PageContainer";
|
import PageContainer from "./PageContainer";
|
||||||
import { useHTTP, useMobile } from "hooks";
|
import { useHTTP, useMobile } from "hooks";
|
||||||
|
|
@ -23,6 +24,25 @@ import DeviceWizard from "device/DeviceWizard";
|
||||||
import DeviceScannedComponents from "device/autoDetect/DeviceScannedComponents";
|
import DeviceScannedComponents from "device/autoDetect/DeviceScannedComponents";
|
||||||
import { useWebSocket } from "hooks/useWebSocket";
|
import { useWebSocket } from "hooks/useWebSocket";
|
||||||
|
|
||||||
|
type TimestampedReading = { timestamp?: string };
|
||||||
|
|
||||||
|
function getTimestampMillis(timestamp?: string): number | undefined {
|
||||||
|
if (!timestamp) return undefined;
|
||||||
|
const parsed = Date.parse(timestamp);
|
||||||
|
return Number.isNaN(parsed) ? undefined : parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickNewestReading<T extends TimestampedReading>(
|
||||||
|
current: T | null | undefined,
|
||||||
|
incoming: T | null | undefined
|
||||||
|
): T | null | undefined {
|
||||||
|
const currentTs = getTimestampMillis(current?.timestamp);
|
||||||
|
const incomingTs = getTimestampMillis(incoming?.timestamp);
|
||||||
|
if (incomingTs === undefined) return current ?? incoming;
|
||||||
|
if (currentTs === undefined) return incoming ?? current;
|
||||||
|
return incomingTs >= currentTs ? incoming : current;
|
||||||
|
}
|
||||||
|
|
||||||
export interface DevicePageData {
|
export interface DevicePageData {
|
||||||
device: Device;
|
device: Device;
|
||||||
components: Component[];
|
components: Component[];
|
||||||
|
|
@ -76,6 +96,55 @@ export default function DevicePage() {
|
||||||
? as
|
? as
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const liveStatusDeviceIds = useMemo(
|
||||||
|
() => (deviceID ? [deviceID] : []),
|
||||||
|
[deviceID]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleLiveDeviceStatus = useCallback(
|
||||||
|
(streamDeviceId: string, status: pond.DeviceStatus) => {
|
||||||
|
setDevice((prev) => {
|
||||||
|
if (prev.id().toString() !== streamDeviceId) return prev;
|
||||||
|
const updated = Device.clone(prev);
|
||||||
|
const incomingStatus = pond.DeviceStatus.fromObject(status);
|
||||||
|
const currentStatus = prev.status ?? pond.DeviceStatus.create();
|
||||||
|
|
||||||
|
incomingStatus.plenum = pickNewestReading(currentStatus.plenum, incomingStatus.plenum);
|
||||||
|
incomingStatus.sen5x = pickNewestReading(currentStatus.sen5x, incomingStatus.sen5x);
|
||||||
|
incomingStatus.co = pickNewestReading(currentStatus.co, incomingStatus.co);
|
||||||
|
incomingStatus.co2 = pickNewestReading(currentStatus.co2, incomingStatus.co2);
|
||||||
|
incomingStatus.no2 = pickNewestReading(currentStatus.no2, incomingStatus.no2);
|
||||||
|
incomingStatus.o2 = pickNewestReading(currentStatus.o2, incomingStatus.o2);
|
||||||
|
incomingStatus.lel = pickNewestReading(currentStatus.lel, incomingStatus.lel);
|
||||||
|
incomingStatus.h2s = pickNewestReading(currentStatus.h2s, incomingStatus.h2s);
|
||||||
|
|
||||||
|
const currentLastActive = getTimestampMillis(currentStatus.lastActive);
|
||||||
|
const incomingLastActive = getTimestampMillis(incomingStatus.lastActive);
|
||||||
|
if (
|
||||||
|
currentLastActive !== undefined &&
|
||||||
|
incomingLastActive !== undefined &&
|
||||||
|
incomingLastActive < currentLastActive
|
||||||
|
) {
|
||||||
|
incomingStatus.lastActive = currentStatus.lastActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
updated.status = incomingStatus;
|
||||||
|
return updated;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
useDeviceStatusStreams({
|
||||||
|
deviceIds: liveStatusDeviceIds,
|
||||||
|
onStatusUpdate: handleLiveDeviceStatus,
|
||||||
|
token,
|
||||||
|
keys: liveContextKeys,
|
||||||
|
types: liveContextTypes,
|
||||||
|
as: liveAs,
|
||||||
|
enabled: Boolean(deviceID && token),
|
||||||
|
});
|
||||||
|
|
||||||
const loadDevice = () => {
|
const loadDevice = () => {
|
||||||
if (loading) return
|
if (loading) return
|
||||||
if (state?.devicePageData) {
|
if (state?.devicePageData) {
|
||||||
|
|
@ -212,35 +281,6 @@ export default function DevicePage() {
|
||||||
enabled: !!deviceID,
|
enabled: !!deviceID,
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Real-time device updates (optional) ---
|
|
||||||
// Updates device-level info (name, status, lastActive, etc.)
|
|
||||||
useWebSocket<Device | null>({
|
|
||||||
path: `/v1/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);
|
|
||||||
},
|
|
||||||
keys: liveContextKeys,
|
|
||||||
types: liveContextTypes,
|
|
||||||
as: liveAs,
|
|
||||||
token,
|
|
||||||
enabled: !!deviceID,
|
|
||||||
});
|
|
||||||
|
|
||||||
const loadPortScan = () => {
|
const loadPortScan = () => {
|
||||||
deviceAPI.listFoundComponents(parseInt(deviceID))
|
deviceAPI.listFoundComponents(parseInt(deviceID))
|
||||||
.then(resp => {
|
.then(resp => {
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,12 @@ import { Settings } from "@mui/icons-material";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import FieldMinimap from "field/Fieldminimap";
|
import FieldMinimap from "field/Fieldminimap";
|
||||||
import Weather from "weather/weather";
|
import Weather from "weather/weather";
|
||||||
import TaskViewer from "tasks/TaskViewer";
|
|
||||||
import HarvestPlanDisplay from "harvestPlan/HarvestPlanDisplay";
|
import HarvestPlanDisplay from "harvestPlan/HarvestPlanDisplay";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import HarvestPlanTable from "harvestPlan/HarvestPlanTable";
|
import HarvestPlanTable from "harvestPlan/HarvestPlanTable";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
import FieldSettings from "field/FieldSettings";
|
import FieldSettings from "field/FieldSettings";
|
||||||
|
import FieldTaskList from "field/FieldTaskList";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) => {
|
const useStyles = makeStyles((theme: Theme) => {
|
||||||
return ({
|
return ({
|
||||||
|
|
@ -185,12 +185,9 @@ export default function FieldPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const tasks = () => {
|
const tasks = () => {
|
||||||
let taskLoadKeys: string[] = [];
|
return (
|
||||||
if (!planLoading) {
|
<FieldTaskList field={field.key()}/>
|
||||||
field.key() !== "" && taskLoadKeys.push(field.key());
|
)
|
||||||
//hPlan.key() !== "" && taskLoadKeys.push(hPlan.key());
|
|
||||||
}
|
|
||||||
return (<TaskViewer drawerView objectKey={field.key()} loadKeys={taskLoadKeys} overlayButton={isMobile}/>)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const desktopView = () => {
|
const desktopView = () => {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { Gate as IGate } from "models/Gate";
|
||||||
//import { Redirect, useHistory, useRouteMatch } from "react-router";
|
//import { Redirect, useHistory, useRouteMatch } from "react-router";
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import PageContainer from "./PageContainer";
|
import PageContainer from "./PageContainer";
|
||||||
import { useGlobalState, useGateAPI, useUserAPI } from "providers";
|
import { useGlobalState, useGateAPI } from "providers";
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
ButtonBase,
|
ButtonBase,
|
||||||
|
|
@ -20,7 +20,7 @@ import {
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import DeviceLinkDrawer from "common/DeviceLinkDrawer";
|
import DeviceLinkDrawer from "common/DeviceLinkDrawer";
|
||||||
import { Component, Device, Scope } from "models";
|
import { Component, Device } from "models";
|
||||||
import GateActions from "gate/GateActions";
|
import GateActions from "gate/GateActions";
|
||||||
import GateDevice from "gate/GateDevice";
|
import GateDevice from "gate/GateDevice";
|
||||||
import ObjectControls from "common/ObjectControls";
|
import ObjectControls from "common/ObjectControls";
|
||||||
|
|
@ -28,7 +28,7 @@ import { Link } from "@mui/icons-material";
|
||||||
import Chat from "chat/Chat";
|
import Chat from "chat/Chat";
|
||||||
import PlaneIcon from "products/AviationIcons/PlaneIcon";
|
import PlaneIcon from "products/AviationIcons/PlaneIcon";
|
||||||
import NotesIcon from "@mui/icons-material/Notes";
|
import NotesIcon from "@mui/icons-material/Notes";
|
||||||
import { useMobile, useSnackbar, useThemeType } from "hooks";
|
import { useMobile, usePermissionAPI, useSnackbar, useThemeType } from "hooks";
|
||||||
import { clone } from "lodash";
|
import { clone } from "lodash";
|
||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
import { makeStyles } from "@mui/styles";
|
import { makeStyles } from "@mui/styles";
|
||||||
|
|
@ -90,7 +90,7 @@ export default function Gate(props: Props) {
|
||||||
const gateID = gateKey ?? useParams<{ gateKey: string }>()?.gateKey ?? "";
|
const gateID = gateKey ?? useParams<{ gateKey: string }>()?.gateKey ?? "";
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const gateAPI = useGateAPI();
|
const gateAPI = useGateAPI();
|
||||||
const userAPI = useUserAPI();
|
const permissionAPI = usePermissionAPI();
|
||||||
const [gate, setGate] = useState<IGate>(IGate.create());
|
const [gate, setGate] = useState<IGate>(IGate.create());
|
||||||
const [devices, setDevices] = useState<Map<string, pond.ComprehensiveDevice>>(
|
const [devices, setDevices] = useState<Map<string, pond.ComprehensiveDevice>>(
|
||||||
new Map<string, pond.ComprehensiveDevice>()
|
new Map<string, pond.ComprehensiveDevice>()
|
||||||
|
|
@ -115,16 +115,10 @@ export default function Gate(props: Props) {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let key = gateID;
|
permissionAPI.getPermissions(user.id(), [gateID], ["gate"]).then(resp => {
|
||||||
let kind = "gate";
|
setPermissions(pond.EvaluatePermissionsResponse.fromObject(resp.data).permissions)
|
||||||
if (as) {
|
})
|
||||||
key = as;
|
}, [as, gateID, permissionAPI, user]);
|
||||||
kind = "team";
|
|
||||||
}
|
|
||||||
userAPI.getUser(user.id(), { key: key, kind: kind } as Scope).then(resp => {
|
|
||||||
setPermissions(resp.permissions);
|
|
||||||
});
|
|
||||||
}, [as, gateID, userAPI, user]);
|
|
||||||
|
|
||||||
const loadGate = useCallback(() => {
|
const loadGate = useCallback(() => {
|
||||||
let id = gateID;
|
let id = gateID;
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ import TemperatureIcon from "component/TemperatureIcon";
|
||||||
import FuelIcon from "products/CommonIcons/fuelIcon";
|
import FuelIcon from "products/CommonIcons/fuelIcon";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import Warning from "@mui/icons-material/Warning";
|
import Warning from "@mui/icons-material/Warning";
|
||||||
import { getTemperatureUnit } from "utils";
|
|
||||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
|
|
@ -286,7 +285,7 @@ export default function Heater() {
|
||||||
|
|
||||||
const tempUnit = () => {
|
const tempUnit = () => {
|
||||||
let unit = "°C";
|
let unit = "°C";
|
||||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||||
unit = "°F";
|
unit = "°F";
|
||||||
}
|
}
|
||||||
return unit;
|
return unit;
|
||||||
|
|
|
||||||
|
|
@ -247,6 +247,7 @@ export default function TeamPage() {
|
||||||
closeDialogCallback={() => setUserDialog(false)}
|
closeDialogCallback={() => setUserDialog(false)}
|
||||||
refreshCallback={() => {}}
|
refreshCallback={() => {}}
|
||||||
useImitation={false}
|
useImitation={false}
|
||||||
|
shareLabel="Add Team Member +"
|
||||||
/>
|
/>
|
||||||
<Grid2 container spacing={1}>
|
<Grid2 container spacing={1}>
|
||||||
<Grid2 size={{ xs: 12, sm: 4 }}>
|
<Grid2 size={{ xs: 12, sm: 4 }}>
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ import {
|
||||||
Voltage,
|
Voltage,
|
||||||
VPD,
|
VPD,
|
||||||
Weight,
|
Weight,
|
||||||
CapacitorCable
|
CapacitorCable,
|
||||||
|
AnalogPressure
|
||||||
} from "pbHelpers/ComponentTypes";
|
} from "pbHelpers/ComponentTypes";
|
||||||
//import { multilineGrainCableData } from "pbHelpers/ComponentTypes/GrainCable";
|
//import { multilineGrainCableData } from "pbHelpers/ComponentTypes/GrainCable";
|
||||||
//import { multilineCapCableData } from "./ComponentTypes/CapacitorCable";
|
//import { multilineCapCableData } from "./ComponentTypes/CapacitorCable";
|
||||||
|
|
@ -98,7 +99,8 @@ const COMPONENT_TYPE_MAP = new Map<quack.ComponentType, Function>([
|
||||||
[quack.ComponentType.COMPONENT_TYPE_VIBRATION_CHAIN, VibrationCable],
|
[quack.ComponentType.COMPONENT_TYPE_VIBRATION_CHAIN, VibrationCable],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE, dragerGasDongle],
|
[quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE, dragerGasDongle],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, Airflow],
|
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, Airflow],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_TEMP_HUMIDITY, TempHumidity]
|
[quack.ComponentType.COMPONENT_TYPE_TEMP_HUMIDITY, TempHumidity],
|
||||||
|
[quack.ComponentType.COMPONENT_TYPE_ANALOG_PRESSURE, AnalogPressure]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export interface Subtype {
|
export interface Subtype {
|
||||||
|
|
@ -238,16 +240,16 @@ export function unitMeasurementSummary(
|
||||||
): Summary {
|
): Summary {
|
||||||
let vals: string[] = [];
|
let vals: string[] = [];
|
||||||
convertedMeasurement.values.forEach(val => {
|
convertedMeasurement.values.forEach(val => {
|
||||||
vals.push(val + describer.unit());
|
vals.push(val + convertedMeasurement.unit);
|
||||||
});
|
});
|
||||||
let v = vals.join(", ");
|
let v = vals.join(", ");
|
||||||
if (describer.enumerations().length > 0) {
|
if (describer.enumerations().length > 0) {
|
||||||
v = describer.enumerations()[parseFloat(vals[0])];
|
v = describer.enumerations()[parseFloat(vals[0])];
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
colour: describer.colour(),
|
colour: convertedMeasurement.colour,
|
||||||
label: describer.label(),
|
label: convertedMeasurement.label,
|
||||||
type: describer.type(),
|
type: convertedMeasurement.type,
|
||||||
value: v,
|
value: v,
|
||||||
error: convertedMeasurement.error
|
error: convertedMeasurement.error
|
||||||
};
|
};
|
||||||
|
|
@ -260,6 +262,8 @@ export function unitMeasurementSummaries(
|
||||||
): Summary[] {
|
): Summary[] {
|
||||||
let summaries: Summary[] = [];
|
let summaries: Summary[] = [];
|
||||||
measurements.measurementsFor.forEach(measurement => {
|
measurements.measurementsFor.forEach(measurement => {
|
||||||
|
//the only reason the user doesnt need to be passed in here is because it is only used for enumerations,
|
||||||
|
//things like the unit and colour are in the measurement itself at this point
|
||||||
let describer = describeMeasurement(measurement.type, compType, subtype);
|
let describer = describeMeasurement(measurement.type, compType, subtype);
|
||||||
summaries.push(unitMeasurementSummary(measurement, describer));
|
summaries.push(unitMeasurementSummary(measurement, describer));
|
||||||
});
|
});
|
||||||
|
|
@ -532,6 +536,7 @@ export function simpleLineChartData(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
console.log(lineData)
|
||||||
return lineData;
|
return lineData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -947,6 +952,15 @@ function getOverlayAreas(
|
||||||
return overlayAreas;
|
return overlayAreas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this function adds lines to victory graphs for interactions on the component
|
||||||
|
* DEPRECATED: we now use Recharts for our graphs
|
||||||
|
* @param componentType
|
||||||
|
* @param subtype
|
||||||
|
* @param interactionCondition
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
function createInteractionLine(
|
function createInteractionLine(
|
||||||
componentType: quack.ComponentType,
|
componentType: quack.ComponentType,
|
||||||
subtype: number,
|
subtype: number,
|
||||||
|
|
|
||||||
88
src/pbHelpers/ComponentTypes/AnalogPressure.ts
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
import {
|
||||||
|
ComponentTypeExtension,
|
||||||
|
Summary,
|
||||||
|
Subtype,
|
||||||
|
simpleMeasurements,
|
||||||
|
simpleSummaries,
|
||||||
|
unitMeasurementSummaries,
|
||||||
|
AreaChartData,
|
||||||
|
GraphFilters,
|
||||||
|
simpleAreaChartData,
|
||||||
|
LineChartData,
|
||||||
|
simpleLineChartData
|
||||||
|
} from "pbHelpers/ComponentType";
|
||||||
|
import PressureDarkIcon from "assets/components/pressureDark.png";
|
||||||
|
import PressureLightIcon from "assets/components/pressureLight.png";
|
||||||
|
import { quack } from "protobuf-ts/quack";
|
||||||
|
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
||||||
|
import { convertedUnitMeasurement } from "models/UnitMeasurement";
|
||||||
|
import { pond } from "protobuf-ts/pond";
|
||||||
|
|
||||||
|
export function AnalogPressure(subtype: number = 0): ComponentTypeExtension {
|
||||||
|
let pressure = describeMeasurement(
|
||||||
|
quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE,
|
||||||
|
quack.ComponentType.COMPONENT_TYPE_ANALOG_PRESSURE,
|
||||||
|
subtype
|
||||||
|
);
|
||||||
|
let voltage = describeMeasurement(
|
||||||
|
quack.MeasurementType.MEASUREMENT_TYPE_VOLTAGE,
|
||||||
|
quack.ComponentType.COMPONENT_TYPE_ANALOG_PRESSURE,
|
||||||
|
subtype
|
||||||
|
)
|
||||||
|
let addressTypes = [quack.AddressType.ADDRESS_TYPE_I2C];
|
||||||
|
return {
|
||||||
|
type: quack.ComponentType.COMPONENT_TYPE_PRESSURE,
|
||||||
|
subtypes: [
|
||||||
|
{
|
||||||
|
key: quack.AnalogPressureSubtype.ANALOG_PRESSURE_SUBTYPE_PMC21,
|
||||||
|
value: "ANALOG_PRESSURE_SUBTYPE_PMC21",
|
||||||
|
friendlyName: "PMC 21"
|
||||||
|
} as Subtype
|
||||||
|
],
|
||||||
|
friendlyName: "Analog Pressure",
|
||||||
|
description: "Measures the atmospheric pressure or absolute pressure",
|
||||||
|
isController: false,
|
||||||
|
isSource: true,
|
||||||
|
isCalibratable: true,
|
||||||
|
hasFan: true,
|
||||||
|
addressTypes: addressTypes,
|
||||||
|
interactionResultTypes: [],
|
||||||
|
states: [],
|
||||||
|
measurements: simpleMeasurements(pressure, voltage),
|
||||||
|
measurementSummary: async function(measurement: quack.Measurement): Promise<Array<Summary>> {
|
||||||
|
return simpleSummaries(measurement, pressure);
|
||||||
|
},
|
||||||
|
unitMeasurementSummary: (
|
||||||
|
measurements: convertedUnitMeasurement,
|
||||||
|
): Summary[] => {
|
||||||
|
return unitMeasurementSummaries(
|
||||||
|
measurements,
|
||||||
|
quack.ComponentType.COMPONENT_TYPE_PRESSURE,
|
||||||
|
subtype,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
areaChartData: (
|
||||||
|
measurement: pond.UnitMeasurementsForComponent,
|
||||||
|
smoothingAverages?: number,
|
||||||
|
filters?: GraphFilters
|
||||||
|
): AreaChartData => {
|
||||||
|
return simpleAreaChartData(measurement, smoothingAverages, filters);
|
||||||
|
},
|
||||||
|
lineChartData: (
|
||||||
|
measurement: pond.UnitMeasurementsForComponent,
|
||||||
|
smoothingAverages?: number,
|
||||||
|
filters?: GraphFilters
|
||||||
|
): LineChartData => {
|
||||||
|
return simpleLineChartData(
|
||||||
|
quack.ComponentType.COMPONENT_TYPE_PRESSURE,
|
||||||
|
measurement,
|
||||||
|
smoothingAverages,
|
||||||
|
filters
|
||||||
|
);
|
||||||
|
},
|
||||||
|
minMeasurementPeriodMs: 1000,
|
||||||
|
icon: (theme?: "light" | "dark"): string | undefined => {
|
||||||
|
return theme === "light" ? PressureDarkIcon : PressureLightIcon;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -29,3 +29,4 @@ export * from "./Voltage";
|
||||||
export * from "./VPD";
|
export * from "./VPD";
|
||||||
export * from "./Weight";
|
export * from "./Weight";
|
||||||
export * from "./CapacitorCable";
|
export * from "./CapacitorCable";
|
||||||
|
export * from "./AnalogPressure";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Interaction, Component } from "models";
|
import { Interaction, Component, User } from "models";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { quack } from "protobuf-ts/quack";
|
import { quack } from "protobuf-ts/quack";
|
||||||
import { or, notNull } from "utils/types";
|
import { or, notNull } from "utils/types";
|
||||||
|
|
@ -172,7 +172,8 @@ export const interactionResultText = (interaction: Interaction, sink?: Component
|
||||||
export const interactionConditionText = (
|
export const interactionConditionText = (
|
||||||
source: Component | undefined,
|
source: Component | undefined,
|
||||||
condition: pond.IInteractionCondition,
|
condition: pond.IInteractionCondition,
|
||||||
and: boolean
|
and: boolean,
|
||||||
|
user?: User
|
||||||
) => {
|
) => {
|
||||||
let comparison = "is exactly";
|
let comparison = "is exactly";
|
||||||
switch (condition.comparison) {
|
switch (condition.comparison) {
|
||||||
|
|
@ -189,7 +190,7 @@ export const interactionConditionText = (
|
||||||
if (!condition.measurementType) return "Unknown " + comparison + " " + condition.value;
|
if (!condition.measurementType) return "Unknown " + comparison + " " + condition.value;
|
||||||
let sourceType = source && source.settings.type;
|
let sourceType = source && source.settings.type;
|
||||||
let sourceSubtype = source && source.settings.subtype;
|
let sourceSubtype = source && source.settings.subtype;
|
||||||
let measurement = describeMeasurement(condition.measurementType, sourceType, sourceSubtype);
|
let measurement = describeMeasurement(condition.measurementType, sourceType, sourceSubtype, undefined, user);
|
||||||
return (
|
return (
|
||||||
(and ? "and " : "") +
|
(and ? "and " : "") +
|
||||||
measurement.label() +
|
measurement.label() +
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,13 @@ import {
|
||||||
yellow
|
yellow
|
||||||
} from "@mui/material/colors";
|
} from "@mui/material/colors";
|
||||||
import { GraphType } from "common/Graph";
|
import { GraphType } from "common/Graph";
|
||||||
|
import { User } from "models";
|
||||||
import { IsCardController } from "products/DeviceProduct";
|
import { IsCardController } from "products/DeviceProduct";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import { quack } from "protobuf-ts/quack";
|
import { quack } from "protobuf-ts/quack";
|
||||||
import { getTextSecondary } from "theme/text";
|
import { getTextSecondary } from "theme/text";
|
||||||
// import { getTextSecondary } from "theme";
|
// import { getTextSecondary } from "theme";
|
||||||
import { getDistanceUnit, getPressureUnit, getTemperatureUnit, roundTo } from "utils";
|
import { roundTo } from "utils";
|
||||||
import { extract } from "utils/types";
|
import { extract } from "utils/types";
|
||||||
|
|
||||||
interface Enumeration {
|
interface Enumeration {
|
||||||
|
|
@ -64,7 +65,8 @@ export class MeasurementDescriber {
|
||||||
measurementType: quack.MeasurementType,
|
measurementType: quack.MeasurementType,
|
||||||
componentType: quack.ComponentType,
|
componentType: quack.ComponentType,
|
||||||
componentSubtype: number,
|
componentSubtype: number,
|
||||||
product?: pond.DeviceProduct
|
product?: pond.DeviceProduct,
|
||||||
|
user?: User
|
||||||
) {
|
) {
|
||||||
this.measurementType = measurementType;
|
this.measurementType = measurementType;
|
||||||
this.details = {
|
this.details = {
|
||||||
|
|
@ -87,7 +89,7 @@ export class MeasurementDescriber {
|
||||||
case quack.MeasurementType.MEASUREMENT_TYPE_INVALID:
|
case quack.MeasurementType.MEASUREMENT_TYPE_INVALID:
|
||||||
break;
|
break;
|
||||||
case quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE:
|
case quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE:
|
||||||
let temperatureUnit = getTemperatureUnit();
|
let temperatureUnit = user?.tempUnit() ?? pond.TemperatureUnit.TEMPERATURE_UNIT_CELSIUS;
|
||||||
let isFahrenheit = temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT;
|
let isFahrenheit = temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT;
|
||||||
this.details.label = "Temperature";
|
this.details.label = "Temperature";
|
||||||
this.details.unit = isFahrenheit ? "°F" : "°C";
|
this.details.unit = isFahrenheit ? "°F" : "°C";
|
||||||
|
|
@ -233,7 +235,8 @@ export class MeasurementDescriber {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE:
|
case quack.MeasurementType.MEASUREMENT_TYPE_PRESSURE:
|
||||||
let pressureUnit = getPressureUnit();
|
let pressureUnit =
|
||||||
|
user?.pressureUnit() ?? pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER;
|
||||||
let isIWG = pressureUnit === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER;
|
let isIWG = pressureUnit === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER;
|
||||||
this.details.label = "Pressure";
|
this.details.label = "Pressure";
|
||||||
this.details.unit = isIWG ? "iwg" : "kPa";
|
this.details.unit = isIWG ? "iwg" : "kPa";
|
||||||
|
|
@ -437,7 +440,8 @@ export class MeasurementDescriber {
|
||||||
this.details.max = 100000;
|
this.details.max = 100000;
|
||||||
break;
|
break;
|
||||||
case quack.MeasurementType.MEASUREMENT_TYPE_DISTANCE_CM:
|
case quack.MeasurementType.MEASUREMENT_TYPE_DISTANCE_CM:
|
||||||
let distanceUnit = getDistanceUnit();
|
let distanceUnit =
|
||||||
|
user?.distanceUnit() ?? pond.DistanceUnit.DISTANCE_UNIT_FEET;
|
||||||
this.details.label = "Distance";
|
this.details.label = "Distance";
|
||||||
this.details.unit = "cm";
|
this.details.unit = "cm";
|
||||||
if (distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
if (distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||||
|
|
@ -451,7 +455,8 @@ export class MeasurementDescriber {
|
||||||
this.details.max = 100000;
|
this.details.max = 100000;
|
||||||
break;
|
break;
|
||||||
case quack.MeasurementType.MEASUREMENT_TYPE_SPEED:
|
case quack.MeasurementType.MEASUREMENT_TYPE_SPEED:
|
||||||
let speedUnit = getDistanceUnit()
|
let speedUnit =
|
||||||
|
user?.distanceUnit() ?? pond.DistanceUnit.DISTANCE_UNIT_FEET;
|
||||||
this.details.label = "Speed";
|
this.details.label = "Speed";
|
||||||
this.details.unit = speedUnit === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m/s" : "ft/m"; //yes this is meters per second and feet per minute
|
this.details.unit = speedUnit === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m/s" : "ft/m"; //yes this is meters per second and feet per minute
|
||||||
this.details.colour = green["500"];
|
this.details.colour = green["500"];
|
||||||
|
|
@ -689,11 +694,12 @@ export function describeMeasurement(
|
||||||
componentType: quack.ComponentType | null | undefined = quack.ComponentType
|
componentType: quack.ComponentType | null | undefined = quack.ComponentType
|
||||||
.COMPONENT_TYPE_INVALID,
|
.COMPONENT_TYPE_INVALID,
|
||||||
componentSubtype: number = 0,
|
componentSubtype: number = 0,
|
||||||
product?: pond.DeviceProduct
|
product?: pond.DeviceProduct,
|
||||||
|
user?: User
|
||||||
): MeasurementDescriber {
|
): MeasurementDescriber {
|
||||||
measurementType = measurementType
|
measurementType = measurementType
|
||||||
? measurementType
|
? measurementType
|
||||||
: quack.MeasurementType.MEASUREMENT_TYPE_INVALID;
|
: quack.MeasurementType.MEASUREMENT_TYPE_INVALID;
|
||||||
componentType = componentType ? componentType : quack.ComponentType.COMPONENT_TYPE_INVALID;
|
componentType = componentType ? componentType : quack.ComponentType.COMPONENT_TYPE_INVALID;
|
||||||
return new MeasurementDescriber(measurementType, componentType, componentSubtype, product);
|
return new MeasurementDescriber(measurementType, componentType, componentSubtype, product, user);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ const MiVentV1Pins: ConfigurablePin[] = [
|
||||||
{ address: 1024, label: "C2" }
|
{ address: 1024, label: "C2" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
//no longer in development so if you are adding new component types DO NOT add the I2C address here because the firmware of the device will not support it
|
||||||
export const MiVentV1Availability: DeviceAvailabilityMap = new Map<
|
export const MiVentV1Availability: DeviceAvailabilityMap = new Map<
|
||||||
quack.AddressType,
|
quack.AddressType,
|
||||||
DevicePositions
|
DevicePositions
|
||||||
|
|
@ -53,7 +54,8 @@ export const MiVentV2Availability: DeviceAvailabilityMap = new Map<
|
||||||
[quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]],
|
[quack.ComponentType.COMPONENT_TYPE_DHT, [0x40]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]],
|
[quack.ComponentType.COMPONENT_TYPE_SEN5X, [0x69]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x6c]],
|
[quack.ComponentType.COMPONENT_TYPE_AIRFLOW, [0x6c]],
|
||||||
[quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE, [0x6d]]
|
[quack.ComponentType.COMPONENT_TYPE_DRAGER_GAS_DONGLE, [0x6d]],
|
||||||
|
[quack.ComponentType.COMPONENT_TYPE_ANALOG_PRESSURE, [0x6e]]
|
||||||
|
|
||||||
])
|
])
|
||||||
],
|
],
|
||||||
|
|
|
||||||