Merge branch 'staging_environment' into get_permissions_fix
This commit is contained in:
commit
777089e8c4
65 changed files with 1144 additions and 1773 deletions
3
.env
3
.env
|
|
@ -20,3 +20,6 @@ VITE_APP_WEBSITE_TITLE="Adaptive Dashboard"
|
|||
VITE_APP_PRIMARY_COLOUR=blue
|
||||
VITE_APP_SECONDARY_COLOUR=blueGrey
|
||||
VITE_APP_SIGNATURE_COLOUR="#323232"
|
||||
|
||||
# Live device/component WebSocket streams (must match string "true" in code)
|
||||
VITE_ENABLE_WEBSOCKETS=true
|
||||
|
|
|
|||
762
package-lock.json
generated
762
package-lock.json
generated
|
|
@ -1922,278 +1922,6 @@
|
|||
"integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
|
||||
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
|
||||
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
|
||||
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
|
||||
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
|
||||
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
|
||||
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
|
||||
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
|
||||
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
|
||||
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
|
||||
|
|
@ -2211,159 +1939,6 @@
|
|||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openharmony-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
|
||||
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
|
||||
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
|
||||
|
|
@ -3742,244 +3317,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
|
||||
"integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
|
||||
"integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
|
||||
"integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
|
||||
"integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
|
||||
|
|
@ -4008,90 +3345,6 @@
|
|||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openbsd-x64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
|
||||
"integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
|
||||
"integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
|
||||
"integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.59.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
|
||||
"integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@sentry-internal/browser-utils": {
|
||||
"version": "8.55.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.55.0.tgz",
|
||||
|
|
@ -9370,21 +8623,6 @@
|
|||
"integrity": "sha512-hlq4+BU0hlPmwsFjwGGzZ+OZ9N/wq9Ljg/sq3pX+2CD7hrJsX9tJgWWK/wiNTFM212CLHWhicOoqwXyZGGetJg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import moment from "moment";
|
|||
import { pond } from "protobuf-ts/pond";
|
||||
import { useGlobalState } from "providers";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { celsiusToFahrenheit, getGrainUnit, or } from "utils";
|
||||
import { celsiusToFahrenheit, or } from "utils";
|
||||
//import { useHistory } from "react-router";
|
||||
//import BinModeDot from "./BinModeDot";
|
||||
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 (
|
||||
bin.grainInventory().toLocaleString() +
|
||||
bin.grainInventory(user).toLocaleString() +
|
||||
" 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 (
|
||||
bin.grainInventory().toLocaleString() +
|
||||
bin.grainInventory(user).toLocaleString() +
|
||||
" t " +
|
||||
bin.fillPercent() +
|
||||
"%"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
|||
import { pond, quack } from "protobuf-ts/pond";
|
||||
import { useGlobalState, useInteractionsAPI, useSnackbar } from "providers";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { avg, fahrenheitToCelsius, getTemperatureUnit } from "utils";
|
||||
import { avg, fahrenheitToCelsius } from "utils";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { Mark } from "@mui/material/Slider/useSlider.types";
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ export default function BinConditioningInteraction(props: Props) {
|
|||
temp &&
|
||||
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
|
||||
temp = fahrenheitToCelsius(temp);
|
||||
}
|
||||
|
|
@ -139,7 +139,7 @@ export default function BinConditioningInteraction(props: Props) {
|
|||
setBaseEMC(emc === hum ? undefined : emc);
|
||||
|
||||
}
|
||||
}, [sliderVals, grain]);
|
||||
}, [sliderVals, grain, user]);
|
||||
|
||||
const updateInteraction = () => {
|
||||
interactionAPI
|
||||
|
|
@ -178,7 +178,7 @@ export default function BinConditioningInteraction(props: Props) {
|
|||
let marks: Mark[] = [];
|
||||
|
||||
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";
|
||||
} else {
|
||||
labelTail = "°C";
|
||||
|
|
@ -220,7 +220,7 @@ export default function BinConditioningInteraction(props: Props) {
|
|||
quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE
|
||||
) {
|
||||
if (
|
||||
getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
) {
|
||||
return value.toFixed(1) + "°F";
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import SearchSelect, { Option } from "common/SearchSelect";
|
|||
import { useMobile } from "hooks";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { getDistanceUnit } from "utils";
|
||||
import { useGlobalState } from "providers";
|
||||
|
||||
interface Props {
|
||||
optionsChanged: (binOptions: jsonBin[]) => void;
|
||||
|
|
@ -13,6 +13,7 @@ interface Props {
|
|||
|
||||
export default function BinSelector(props: Props) {
|
||||
const { optionsChanged, vertical } = props;
|
||||
const [{user}] = useGlobalState();
|
||||
const isMobile = useMobile();
|
||||
const [manufacturerOptions, SetManufacturerOptions] = useState<Option[]>([]);
|
||||
const [manufacturer, SetManufacturer] = useState<Option | null>(null);
|
||||
|
|
@ -126,7 +127,7 @@ export default function BinSelector(props: Props) {
|
|||
}}
|
||||
label={
|
||||
"Minimum Diameter " +
|
||||
(getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)")
|
||||
(user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)")
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
|
@ -143,7 +144,7 @@ export default function BinSelector(props: Props) {
|
|||
}}
|
||||
label={
|
||||
"Maximum Diameter " +
|
||||
(getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)")
|
||||
(user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)")
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ import { pond } from "protobuf-ts/pond";
|
|||
import { useBinAPI, useBinYardAPI, useGlobalState, useLibraCartProxyAPI } from "providers";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
// import { useHistory } from "react-router";
|
||||
import { getDistanceUnit, or, getTemperatureUnit, getGrainUnit } from "utils";
|
||||
import { or } from "utils";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import BinSelector from "./BinSelector";
|
||||
|
|
@ -240,16 +240,16 @@ export default function BinSettings(props: Props) {
|
|||
initForm.inventory.bushelsPerTonne = grain.bushelsPerTonne;
|
||||
}
|
||||
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
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)
|
||||
}
|
||||
if (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)
|
||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||
setBushelConversion(initForm.inventory.customGrain.bushelsPerTonne * 0.907)
|
||||
}
|
||||
}
|
||||
|
|
@ -269,7 +269,7 @@ export default function BinSettings(props: Props) {
|
|||
let sidewallHeight = "";
|
||||
let hopperHeight = "";
|
||||
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);
|
||||
d = (initForm.specs.diameterCm * 0.0328).toFixed(2);
|
||||
if (initForm.specs.advancedDimensions) {
|
||||
|
|
@ -290,7 +290,7 @@ export default function BinSettings(props: Props) {
|
|||
let high = initForm.highTemp ?? 20;
|
||||
let low = initForm.lowTemp ?? 10;
|
||||
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));
|
||||
low = parseFloat((low * 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;
|
||||
let weight = ""
|
||||
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)
|
||||
}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)
|
||||
}
|
||||
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)
|
||||
}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)
|
||||
}
|
||||
}
|
||||
|
|
@ -350,7 +350,7 @@ export default function BinSettings(props: Props) {
|
|||
setMoistureTargetDeviation(initForm.inventory?.moistureTargetDeviation.toString() ?? "0");
|
||||
setAutoFillThreshold(initForm.inventory?.autoThreshold ?? 5)
|
||||
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
|
||||
}
|
||||
setLidarDropDistance(dropDistance)
|
||||
|
|
@ -364,7 +364,7 @@ export default function BinSettings(props: Props) {
|
|||
} else {
|
||||
setInitialized(false);
|
||||
}
|
||||
}, [bin, open, mode, openedBinYard]);
|
||||
}, [bin, open, mode, openedBinYard, user]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mode === "remove") {
|
||||
|
|
@ -475,7 +475,7 @@ export default function BinSettings(props: Props) {
|
|||
if (form.inventory) {
|
||||
form.inventory.inventoryControl = inventoryControl
|
||||
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){
|
||||
form.inventory.customGrain = undefined
|
||||
}else{
|
||||
|
|
@ -529,7 +529,7 @@ export default function BinSettings(props: Props) {
|
|||
form.inventory.inventoryControl = inventoryControl
|
||||
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
|
||||
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){
|
||||
form.inventory.customGrain = undefined
|
||||
}else{
|
||||
|
|
@ -804,7 +804,7 @@ export default function BinSettings(props: Props) {
|
|||
const binQuantity = formExtension.grainBushels;
|
||||
|
||||
//as long as the storage type is not fertilizer it is some sort of grain, whether it is supported or custom is not important in this instance so we do not need to check for unknown
|
||||
if(storageType !== pond.BinStorage.BIN_STORAGE_FERTILIZER && ((getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE || getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON) && bushelConversion !== 0 && grainWeight !== "")){
|
||||
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 (
|
||||
<TextField
|
||||
label="Amount"
|
||||
|
|
@ -830,7 +830,7 @@ export default function BinSettings(props: Props) {
|
|||
variant="outlined"
|
||||
disabled={!canEdit}
|
||||
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}
|
||||
/>
|
||||
|
|
@ -1099,7 +1099,7 @@ export default function BinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "ft" : "cm"}
|
||||
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "ft" : "cm"}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
|
|
@ -1179,9 +1179,9 @@ export default function BinSettings(props: Props) {
|
|||
setCustomGrain(newGrainSettings)
|
||||
let conversion = 0
|
||||
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
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
|
||||
}
|
||||
updateForm(
|
||||
|
|
@ -1218,9 +1218,9 @@ export default function BinSettings(props: Props) {
|
|||
})
|
||||
);
|
||||
let conversion = 0
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
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
|
||||
}
|
||||
setBushelConversion(conversion)
|
||||
|
|
@ -1435,7 +1435,7 @@ export default function BinSettings(props: Props) {
|
|||
let sH = sidewallHeight;
|
||||
let hH = hopperHeight ?? 0;
|
||||
let d = diameter;
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
tcH = tcH * 3.281;
|
||||
sH = sH * 3.281;
|
||||
hH = hH * 3.281;
|
||||
|
|
@ -1463,7 +1463,7 @@ export default function BinSettings(props: Props) {
|
|||
let hopperHeight = formExtension.hopperHeight;
|
||||
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);
|
||||
// heightM = (Number(heightM) * 3.28084).toFixed(2);
|
||||
// }
|
||||
|
|
@ -1552,7 +1552,7 @@ export default function BinSettings(props: Props) {
|
|||
let d = diameter;
|
||||
let valueM = value;
|
||||
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);
|
||||
dM = (Number(d) * 0.3048).toFixed(2);
|
||||
}
|
||||
|
|
@ -1577,7 +1577,7 @@ export default function BinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
|
|
@ -1637,7 +1637,7 @@ export default function BinSettings(props: Props) {
|
|||
let value = event?.target.value;
|
||||
let valueM = value;
|
||||
setModelID(0);
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
valueM = (Number(value) * 0.3048).toFixed(2);
|
||||
}
|
||||
let coneCM =
|
||||
|
|
@ -1674,7 +1674,7 @@ export default function BinSettings(props: Props) {
|
|||
|
||||
//need to get the total height in cm
|
||||
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
|
||||
}else{
|
||||
totalHeightCM = totalHeightCM * 100 //convert from m to cm
|
||||
|
|
@ -1698,7 +1698,7 @@ export default function BinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||
? "m"
|
||||
: "ft"}
|
||||
</InputAdornment>
|
||||
|
|
@ -1725,7 +1725,7 @@ export default function BinSettings(props: Props) {
|
|||
//calculate the new cone height for the roof angle
|
||||
let coneCM = TriangleOppositeLength(d / 2, angle ?? 0);
|
||||
let newConeHeight =
|
||||
getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||
user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||
? (coneCM / 30.48).toFixed(2)
|
||||
: (coneCM / 100).toFixed(2);
|
||||
|
||||
|
|
@ -1749,7 +1749,7 @@ export default function BinSettings(props: Props) {
|
|||
|
||||
//need to get the total height in cm
|
||||
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
|
||||
}else{
|
||||
totalHeightCM = totalHeightCM * 100 //convert from m to cm
|
||||
|
|
@ -1786,7 +1786,7 @@ export default function BinSettings(props: Props) {
|
|||
onChange={event => {
|
||||
let value = event?.target.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);
|
||||
}
|
||||
let ext = cloneDeep(formExtension);
|
||||
|
|
@ -1811,7 +1811,7 @@ export default function BinSettings(props: Props) {
|
|||
|
||||
//need to get the total height in cm
|
||||
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
|
||||
}else{
|
||||
totalHeightCM = totalHeightCM * 100 //convert from m to cm
|
||||
|
|
@ -1838,7 +1838,7 @@ export default function BinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||
? "m"
|
||||
: "ft"}
|
||||
</InputAdornment>
|
||||
|
|
@ -1868,7 +1868,7 @@ export default function BinSettings(props: Props) {
|
|||
let coneCM = TriangleOppositeLength(d / 2, angle ?? 0);
|
||||
|
||||
let newHopperHeight =
|
||||
getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||
user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||
? (coneCM / 30.48).toFixed(2)
|
||||
: (coneCM / 100).toFixed(2);
|
||||
|
||||
|
|
@ -1926,7 +1926,7 @@ export default function BinSettings(props: Props) {
|
|||
onChange={event => {
|
||||
let value = event?.target.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);
|
||||
}
|
||||
|
||||
|
|
@ -1982,7 +1982,7 @@ export default function BinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET
|
||||
? "m"
|
||||
: "ft"}
|
||||
</InputAdornment>
|
||||
|
|
@ -2009,7 +2009,7 @@ export default function BinSettings(props: Props) {
|
|||
let h = height;
|
||||
let valueM = value;
|
||||
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);
|
||||
hM = (Number(h) * 0.3048).toFixed(2);
|
||||
}
|
||||
|
|
@ -2063,7 +2063,7 @@ export default function BinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
|
|
@ -2253,7 +2253,7 @@ export default function BinSettings(props: Props) {
|
|||
let userHopperHeight = hopperHeight;
|
||||
let userDiameter = jsonBin.Diameter;
|
||||
//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;
|
||||
userDiameter = userDiameter / 3.281;
|
||||
userTopCone = userTopCone / 3.281;
|
||||
|
|
@ -2308,7 +2308,7 @@ export default function BinSettings(props: Props) {
|
|||
onChange={event => {
|
||||
let value = event?.target.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);
|
||||
}
|
||||
|
||||
|
|
@ -2320,7 +2320,7 @@ export default function BinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
? "F"
|
||||
: "C"}
|
||||
</InputAdornment>
|
||||
|
|
@ -2348,7 +2348,7 @@ export default function BinSettings(props: Props) {
|
|||
onChange={event => {
|
||||
let value = event?.target.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);
|
||||
}
|
||||
setLowTempC(+valueC);
|
||||
|
|
@ -2357,7 +2357,7 @@ export default function BinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
? "F"
|
||||
: "C"}
|
||||
</InputAdornment>
|
||||
|
|
@ -2383,7 +2383,7 @@ export default function BinSettings(props: Props) {
|
|||
onChange={event => {
|
||||
let value = event?.target.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);
|
||||
}
|
||||
setHighTempC(+valueC);
|
||||
|
|
@ -2392,7 +2392,7 @@ export default function BinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
? "F"
|
||||
: "C"}
|
||||
</InputAdornment>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import Co2Icon from "products/CommonIcons/co2Icon";
|
|||
import { pond, quack } from "protobuf-ts/pond";
|
||||
import { useBinAPI, useGlobalState, useSnackbar } from "providers";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { avg, getTemperatureUnit } from "utils";
|
||||
import { avg } from "utils";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { Mark } from "@mui/material/Slider/useSlider.types";
|
||||
import { CO2 } from "models/CO2";
|
||||
|
|
@ -134,7 +134,7 @@ export default function BinStorageConditions(props: Props) {
|
|||
const binAPI = useBinAPI();
|
||||
const { openSnack } = useSnackbar();
|
||||
const { bin, headspaceCO2, cables } = props;
|
||||
const [{as}] = useGlobalState()
|
||||
const [{as, user}] = useGlobalState()
|
||||
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
|
||||
const [missingTopNodeWarning, setMissingTopNodeWarning] = useState(false);
|
||||
|
|
@ -233,7 +233,7 @@ export default function BinStorageConditions(props: Props) {
|
|||
}
|
||||
setTempTargets(tempCounts);
|
||||
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;
|
||||
}
|
||||
setTargetTemp(tempVal.toFixed(1));
|
||||
|
|
@ -244,7 +244,7 @@ export default function BinStorageConditions(props: Props) {
|
|||
setEmcTargets(emcCounts);
|
||||
setTargetEMC(bin.settings.inventory?.targetMoisture.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(() => {
|
||||
|
|
@ -301,7 +301,7 @@ export default function BinStorageConditions(props: Props) {
|
|||
settings.highTemp = sliderTemps[1];
|
||||
if (settings.inventory) {
|
||||
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);
|
||||
}
|
||||
settings.inventory.targetTemperature = tempVal;
|
||||
|
|
@ -376,14 +376,14 @@ export default function BinStorageConditions(props: Props) {
|
|||
let mark: Mark[] = [];
|
||||
if (averageTemp) {
|
||||
let temp = averageTemp;
|
||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
temp = temp * 1.8 + 32;
|
||||
}
|
||||
mark = [
|
||||
{
|
||||
label: customMark(
|
||||
temp.toFixed(1) +
|
||||
(getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
(user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
? "°F"
|
||||
: "°C"),
|
||||
"AVG"
|
||||
|
|
@ -422,7 +422,7 @@ export default function BinStorageConditions(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
? "°F"
|
||||
: "°C"}
|
||||
</InputAdornment>
|
||||
|
|
@ -451,7 +451,7 @@ export default function BinStorageConditions(props: Props) {
|
|||
max={sliderEdge}
|
||||
valueLabelDisplay="on"
|
||||
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.toFixed(1) + "°C";
|
||||
|
|
|
|||
|
|
@ -10,11 +10,10 @@ import { Transaction } from "models/Transaction";
|
|||
import moment from "moment";
|
||||
import ObjectDescriber from "objects/ObjectDescriber";
|
||||
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 { useCallback, useEffect, useState } from "react";
|
||||
import TransactionDataDisplay from "transactions/transactionDataDisplay";
|
||||
import { getGrainUnit } from "utils";
|
||||
|
||||
interface Props {
|
||||
bin: Bin
|
||||
|
|
@ -26,6 +25,7 @@ export default function BinTransactions(props: Props){
|
|||
const { bin, permissions, refresh } = props
|
||||
const [state, setState] = useState<pond.TransactionState>(pond.TransactionState.TRANSACTION_STATE_APPROVAL_REQUIRED)
|
||||
const transactionAPI = useTransactionAPI()
|
||||
const [{user}] = useGlobalState()
|
||||
const binAPI = useBinAPI()
|
||||
const grainBagAPI = useGrainBagAPI()
|
||||
const fieldAPI = useFieldAPI()
|
||||
|
|
@ -103,7 +103,7 @@ export default function BinTransactions(props: Props){
|
|||
const loadContracts = useCallback(()=>{
|
||||
contractAPI.listContracts(0,0, "asc", "name").then(resp => {
|
||||
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()}
|
||||
}))
|
||||
})
|
||||
|
|
@ -198,11 +198,11 @@ export default function BinTransactions(props: Props){
|
|||
|
||||
const grainQuantityDisplay = (bushels: number) => {
|
||||
const grainTransaction = selectedTransaction?.transaction.transaction?.grainTransaction ?? pond.GrainTransaction.create()
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainTransaction.bushelsPerTonne > 1){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainTransaction.bushelsPerTonne > 1){
|
||||
let tonneWeight = bushels / grainTransaction.bushelsPerTonne
|
||||
return tonneWeight + " mT"
|
||||
}
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainTransaction.bushelsPerTonne > 1){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainTransaction.bushelsPerTonne > 1){
|
||||
let tonneWeight = bushels / (grainTransaction.bushelsPerTonne * 0.907)
|
||||
return tonneWeight + " t"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ import { FullScreen, useFullScreenHandle } from "react-full-screen";
|
|||
import moment, { Moment } from "moment";
|
||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||
import { getThemeType } from "theme";
|
||||
import { getGrainUnit, getTemperatureUnit, or } from "utils";
|
||||
import { or } from "utils";
|
||||
import { useBinAPI } from "providers/pond/binAPI";
|
||||
import BindaptIcon from "products/Bindapt/BindaptIcon";
|
||||
import {
|
||||
|
|
@ -498,9 +498,9 @@ export default function BinVisualizer(props: Props) {
|
|||
if (bin.storage() === pond.BinStorage.BIN_STORAGE_FERTILIZER) {
|
||||
return Math.round(val * 35.239 * 100) / 100;
|
||||
} else {
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
||||
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1) {
|
||||
return Math.round((val / bin.bushelsPerTonne()) * 100) / 100;
|
||||
} else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||
} else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1) {
|
||||
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) {
|
||||
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() + "%)";
|
||||
} 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() + "%)";
|
||||
} else {
|
||||
return " / " + capacity.toLocaleString() + " bu";
|
||||
|
|
@ -605,7 +605,7 @@ export default function BinVisualizer(props: Props) {
|
|||
break;
|
||||
}
|
||||
if (valC) {
|
||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
temp = CtoF(valC).toFixed(1) + "°F";
|
||||
} else {
|
||||
temp = valC.toFixed(1) + "°C";
|
||||
|
|
@ -705,7 +705,7 @@ export default function BinVisualizer(props: Props) {
|
|||
break;
|
||||
}
|
||||
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
|
||||
} else {
|
||||
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();
|
||||
if (pendingDisplay) {
|
||||
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);
|
||||
if (pendingDisplay) {
|
||||
pendingDisplay = pendingDisplay / (bin.bushelsPerTonne()*0.907);
|
||||
|
|
@ -1676,7 +1676,7 @@ export default function BinVisualizer(props: Props) {
|
|||
fontWeight: 650,
|
||||
color: tempColour
|
||||
}}>
|
||||
{ambient?.getTempString(getTemperatureUnit())}
|
||||
{ambient?.getTempString(user.tempUnit())}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box display="flex" marginY={1}>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import { Bin } from "models";
|
|||
import { pond } from "protobuf-ts/pond";
|
||||
import { useBinAPI, useGlobalState } from "providers";
|
||||
import React, { useEffect, useState, useCallback, SetStateAction } from "react";
|
||||
import { getGrainUnit, stringToMaterialColour } from "utils";
|
||||
import { stringToMaterialColour } from "utils";
|
||||
//import BinsFansStatusTable from "./BinFansStatusTable";
|
||||
import BinsList from "./BinsList";
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ export default function BinyardDisplay(props: Props) {
|
|||
const isMobile = useMobile();
|
||||
const [carouselIndex, setCarouselIndex] = useState(0);
|
||||
const [binMenuAnchorEl, setBinMenuAnchorEl] = useState<Element | null>(null);
|
||||
const [{ as }] = useGlobalState();
|
||||
const [{ as, user }] = useGlobalState();
|
||||
const maxBins = 40;
|
||||
const [binsLoading, setBinsLoading] = useState(false);
|
||||
const [expandTotal, setExpandTotal] = useState(false);
|
||||
|
|
@ -658,7 +658,7 @@ export default function BinyardDisplay(props: Props) {
|
|||
return " bu";
|
||||
}
|
||||
|
||||
switch (getGrainUnit()) {
|
||||
switch (user.grainUnit()) {
|
||||
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
||||
return " mT";
|
||||
case pond.GrainUnit.GRAIN_UNIT_TON:
|
||||
|
|
@ -671,9 +671,9 @@ export default function BinyardDisplay(props: Props) {
|
|||
const customQuantityDisplay = (customInventory: pond.CustomInventory, bushels: number) => {
|
||||
let amount = bushels
|
||||
if(customInventory.bushelsPerTonne > 1){
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -683,9 +683,9 @@ export default function BinyardDisplay(props: Props) {
|
|||
const supportedGrainDisplay = (grain: pond.Grain, bushels: number) => {
|
||||
const describer = GrainDescriber(grain)
|
||||
let amount = bushels
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
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
|
||||
}
|
||||
return Math.round(amount*100)/100
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import { sameComponentID } from "pbHelpers/Component";
|
|||
import moment from "moment";
|
||||
import { lowerCase } from "lodash";
|
||||
import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
||||
import { fahrenheitToCelsius, getTemperatureUnit } from "utils";
|
||||
import { GetGrainExtensionMap } from "grain";
|
||||
import { PromiseProgress, Stage, Step as PromiseStep } from "common/PromiseProgress";
|
||||
|
||||
|
|
@ -76,7 +75,7 @@ export default function ModeChangeDialog(props: Props){
|
|||
changeOutdoorHumidity,
|
||||
presets
|
||||
} = props
|
||||
const [{as}] = useGlobalState()
|
||||
const [{as, user}] = useGlobalState()
|
||||
const [componentSets, setComponentSets] = useState<ComponentSet[]>([])
|
||||
const interactionAPI = useInteractionsAPI()
|
||||
const componentAPI = useComponentAPI();
|
||||
|
|
@ -296,7 +295,7 @@ if (!selectedDevice) return;
|
|||
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
|
||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
temp = Math.round((temp * (9 / 5) + 32) * 100) / 100;
|
||||
}
|
||||
let tempVal = describeMeasurement(
|
||||
|
|
@ -392,7 +391,7 @@ if (!selectedDevice) return;
|
|||
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
|
||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
tempPreset = Math.round((tempPreset * (9 / 5) + 32) * 100) / 100;
|
||||
}
|
||||
let tempVal = describeMeasurement(
|
||||
|
|
@ -631,7 +630,7 @@ if (!selectedDevice) return;
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
? "°F"
|
||||
: "℃"}
|
||||
</InputAdornment>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import { pond } from "protobuf-ts/pond";
|
|||
import { useBinAPI, useGlobalState } from "providers";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Legend } from "recharts";
|
||||
import { getGrainUnit } from "utils";
|
||||
import BinLevelAreaGraph from "./BinLevelAreaGraph";
|
||||
|
||||
interface Props {
|
||||
|
|
@ -32,7 +31,7 @@ interface InventoryAt {
|
|||
export default function BinLevelOverTime(props: Props) {
|
||||
const { bin, fertilizerBin, colour, startDate, endDate, customHeight } = props;
|
||||
const binAPI = useBinAPI();
|
||||
const [{as}] = useGlobalState();
|
||||
const [{as, user}] = useGlobalState();
|
||||
const [inventoryData, setInventoryData] = useState<InventoryAt[]>([]);
|
||||
const [dataLoading, setDataLoading] = useState(false);
|
||||
const [capacity, setCapacity] = useState<number | undefined>();
|
||||
|
|
@ -69,10 +68,10 @@ export default function BinLevelOverTime(props: Props) {
|
|||
if (fertilizerBin && cap) {
|
||||
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();
|
||||
}
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
||||
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
||||
cap = cap / (bin.bushelsPerTonne()*0.907);
|
||||
}
|
||||
setCapacity(cap);
|
||||
|
|
@ -89,10 +88,10 @@ export default function BinLevelOverTime(props: Props) {
|
|||
let bushels = hist.settings.inventory.grainBushels ?? 0;
|
||||
if (bushels !== lastBushels) {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
let newData: InventoryAt = {
|
||||
|
|
@ -121,10 +120,10 @@ export default function BinLevelOverTime(props: Props) {
|
|||
if (data.length === 0) {
|
||||
let bushels = bin.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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
data.push({
|
||||
|
|
@ -156,10 +155,10 @@ export default function BinLevelOverTime(props: Props) {
|
|||
if (fertilizerBin && cap) {
|
||||
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();
|
||||
}
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
||||
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && cap) {
|
||||
cap = cap / (bin.bushelsPerTonne()*0.907);
|
||||
}
|
||||
setCapacity(cap);
|
||||
|
|
@ -180,10 +179,10 @@ export default function BinLevelOverTime(props: Props) {
|
|||
if (val.values[0] && m.timestamps[i]) {
|
||||
if (lastBushels !== val.values[0]) {
|
||||
let grainDisplay = val.values[0]
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && bin.bushelsPerTonne() > 1){
|
||||
grainDisplay = Math.round((grainDisplay / bin.bushelsPerTonne()) * 100) / 100;
|
||||
}
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && bin.bushelsPerTonne() > 1){
|
||||
grainDisplay = Math.round((grainDisplay / (bin.bushelsPerTonne()*0.907)) * 100) / 100;
|
||||
}
|
||||
autoBarData.push({
|
||||
|
|
@ -199,10 +198,10 @@ export default function BinLevelOverTime(props: Props) {
|
|||
let bushels = bin.bushels();
|
||||
let currentTime = moment().valueOf();
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
autoBarData.push({
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { colors } from "@mui/material";
|
|||
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||
import { useEffect, useState } from "react";
|
||||
import { distanceConversion } from "utils";
|
||||
import { useGlobalState } from "providers";
|
||||
|
||||
interface Props {
|
||||
bin: jsonBin;
|
||||
|
|
@ -22,6 +23,8 @@ export default function SideView(props: Props) {
|
|||
const dimensionFontSize = 7;
|
||||
const gapSize = svgViewBoxSize * 0.05;
|
||||
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 [hopperHeight, setHopperHeight] = useState(0);
|
||||
const [roofHeight, setRoofHeight] = useState(0);
|
||||
|
|
@ -194,7 +197,7 @@ export default function SideView(props: Props) {
|
|||
"bottomText",
|
||||
svgViewBoxSize / 2,
|
||||
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;
|
||||
|
||||
d.push(
|
||||
dimensionText("sidewallText", x2, midpoint, distanceConversion(bin.Sidewall).toFixed(1))
|
||||
dimensionText("sidewallText", x2, midpoint, distanceConversion(bin.Sidewall, distanceUnit).toFixed(1))
|
||||
);
|
||||
d.push(
|
||||
dimensionPath(
|
||||
|
|
@ -270,7 +273,7 @@ export default function SideView(props: Props) {
|
|||
"peakText",
|
||||
xText,
|
||||
midpoint,
|
||||
distanceConversion(bin.Sidewall + roofHeight).toFixed(1)
|
||||
distanceConversion(bin.Sidewall + roofHeight, distanceUnit).toFixed(1)
|
||||
)
|
||||
);
|
||||
d.push(
|
||||
|
|
@ -313,7 +316,7 @@ export default function SideView(props: Props) {
|
|||
"totalText",
|
||||
x2,
|
||||
midpoint,
|
||||
distanceConversion(roofHeight + bin.Sidewall + hopperHeight).toFixed(1)
|
||||
distanceConversion(roofHeight + bin.Sidewall + hopperHeight, distanceUnit).toFixed(1)
|
||||
)
|
||||
);
|
||||
d.push(
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import {
|
|||
//import MaterialTable from "material-table";
|
||||
//import { getTableIcons } from "common/ResponsiveTable";
|
||||
import CableDisplay from "./cableDisplay";
|
||||
import { distanceConversion, getDistanceUnit } from "utils";
|
||||
import { distanceConversion } from "utils";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import CableQuote from "./cableQuote";
|
||||
import { useMobile } from "hooks";
|
||||
|
|
@ -33,6 +33,7 @@ import {
|
|||
} from "common/TrigFunctions";
|
||||
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { useGlobalState } from "providers";
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
sliderThumb: {
|
||||
|
|
@ -56,6 +57,7 @@ export default function CableEstimator() {
|
|||
//the conversion constant to convert cubic feet to bushels
|
||||
const conversionConstantFT = 0.7786;
|
||||
const classes = useStyles();
|
||||
const [{ user }] = useGlobalState();
|
||||
const [binOptions, setBinOptions] = useState<jsonBin[]>([]);
|
||||
const [displayedRows, setDisplayedRows] = useState<jsonBin[]>([]);
|
||||
const [tablePage, setTablePage] = useState(0)
|
||||
|
|
@ -67,21 +69,21 @@ export default function CableEstimator() {
|
|||
const [quoteOpen, setQuoteOpen] = useState(false);
|
||||
const [useCustomBin, setUseCustomBin] = useState(false);
|
||||
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 [ringsFormEntry, setRingsFormEntry] = useState("0");
|
||||
const [ringHeightFormEntry, setRingHeightFormEntry] = useState("0");
|
||||
const [ringHeightFt, setRingHeightFt] = useState(0);
|
||||
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(
|
||||
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 [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 nodeSpacing = 4;
|
||||
|
|
@ -129,24 +131,40 @@ export default function CableEstimator() {
|
|||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
|
|
@ -545,7 +563,7 @@ export default function CableEstimator() {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
|
|
@ -554,7 +572,7 @@ export default function CableEstimator() {
|
|||
onChange={e => {
|
||||
setDiameterFormEntry(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;
|
||||
}
|
||||
//when the diameter is changed use the current peak height to adjust the roof angle
|
||||
|
|
@ -577,7 +595,7 @@ export default function CableEstimator() {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
|
|
@ -589,7 +607,7 @@ export default function CableEstimator() {
|
|||
onChange={e => {
|
||||
setPeakFormEntry(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;
|
||||
}
|
||||
//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
|
||||
let sidewallFt = val * ringHeightFt;
|
||||
bin.Sidewall = sidewallFt;
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
setSidewallFormEntry((sidewallFt / 3.281).toString());
|
||||
} else {
|
||||
setSidewallFormEntry(sidewallFt.toString());
|
||||
|
|
@ -650,7 +668,7 @@ export default function CableEstimator() {
|
|||
onChange={e => {
|
||||
setRingHeightFormEntry(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;
|
||||
// }
|
||||
let ringFt = inVal / 12;
|
||||
|
|
@ -659,7 +677,7 @@ export default function CableEstimator() {
|
|||
let bin = cloneDeep(customBin);
|
||||
let sidewallFt = bin.Rings * ringFt;
|
||||
bin.Sidewall = sidewallFt;
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
setSidewallFormEntry((sidewallFt / 3.281).toString());
|
||||
} else {
|
||||
setSidewallFormEntry(sidewallFt.toString());
|
||||
|
|
@ -683,7 +701,7 @@ export default function CableEstimator() {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
|
|
@ -694,7 +712,7 @@ export default function CableEstimator() {
|
|||
setSidewallFormEntry(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 (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
val = val * 3.281;
|
||||
}
|
||||
let bin = cloneDeep(customBin);
|
||||
|
|
@ -733,7 +751,7 @@ export default function CableEstimator() {
|
|||
let coneHeight = calcConeHeight(bin.Diameter / 2, bin.RoofAngle);
|
||||
bin.Peak = bin.Sidewall + coneHeight; //assign it as feet
|
||||
let peakHeightDisplay = bin.Sidewall + coneHeight;
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
peakHeightDisplay = peakHeightDisplay / 3.281;
|
||||
}
|
||||
setPeakFormEntry(peakHeightDisplay.toFixed(1));
|
||||
|
|
@ -762,7 +780,7 @@ export default function CableEstimator() {
|
|||
let coneHeight = calcConeHeight(bin.Diameter / 2, bin.RoofAngle);
|
||||
bin.Peak = 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;
|
||||
}
|
||||
setPeakFormEntry(peakHeightDisplay.toFixed(1));
|
||||
|
|
@ -887,7 +905,7 @@ export default function CableEstimator() {
|
|||
setEaveToPeakFormEntry(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 (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
val = val * 3.281;
|
||||
}
|
||||
let bin = cloneDeep(customBin);
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
|||
//import { getTableIcons } from "common/ResponsiveTable";
|
||||
//import MaterialTable from "material-table";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useEffect } from "react";
|
||||
import { distanceConversion, getDistanceUnit } from "utils";
|
||||
import { distanceConversion } from "utils";
|
||||
import { useGlobalState } from "providers";
|
||||
|
||||
interface Props {
|
||||
bin: jsonBin;
|
||||
|
|
@ -13,6 +13,7 @@ interface Props {
|
|||
|
||||
export default function CableMounting(props: Props) {
|
||||
const { bin } = props;
|
||||
const [{ user }] = useGlobalState();
|
||||
// const [tablePage, setTablePage] = useState(0)
|
||||
// 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>
|
||||
},
|
||||
{
|
||||
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) => (
|
||||
<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) => (
|
||||
<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 { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||
import PdfContent from "./pdfComponents/pdfContent";
|
||||
import { useGlobalState } from "providers";
|
||||
|
||||
interface Props {
|
||||
bin: jsonBin;
|
||||
|
|
@ -14,6 +15,7 @@ interface Props {
|
|||
|
||||
export default function CableQuote(props: Props) {
|
||||
const { open, close, bin } = props;
|
||||
const [{user}] = useGlobalState();
|
||||
const isMobil = useMobile();
|
||||
const pdfStyle = StyleSheet.create({
|
||||
viewerDesktop: {
|
||||
|
|
@ -27,7 +29,11 @@ export default function CableQuote(props: Props) {
|
|||
});
|
||||
|
||||
const pdfDoc = () => {
|
||||
return <AgPDFTemplate content={<PdfContent bin={bin} />} />;
|
||||
return (
|
||||
<AgPDFTemplate
|
||||
content={<PdfContent bin={bin} distanceUnit={user.distanceUnit()} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ import { Box, Typography } from "@mui/material";
|
|||
//import MaterialTable from "material-table";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
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 { cloneDeep } from "lodash";
|
||||
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||
|
|
@ -15,17 +16,19 @@ interface Props {
|
|||
|
||||
export default function CableTable(props: Props) {
|
||||
const { bin, /*cablesChanged*/ } = props;
|
||||
const [{ user }] = useGlobalState();
|
||||
//const nodeSpacing = 4; //space between the nodes in feet
|
||||
|
||||
const [cableData, setCableData] = useState(bin.Cables);
|
||||
|
||||
useEffect(() => {
|
||||
let convertedCables: Cable[] = cloneDeep(bin.Cables);
|
||||
const du = user.distanceUnit();
|
||||
convertedCables.forEach(cable => {
|
||||
cable.Length = Math.round(distanceConversion(cable.Length) * 100) / 100;
|
||||
cable.Length = Math.round(distanceConversion(cable.Length, du) * 100) / 100;
|
||||
});
|
||||
setCableData(convertedCables);
|
||||
}, [bin]);
|
||||
}, [bin, user]);
|
||||
|
||||
// const table = () => {
|
||||
// return (
|
||||
|
|
@ -116,7 +119,7 @@ export default function CableTable(props: Props) {
|
|||
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>
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { getDistanceUnit } from "utils";
|
||||
|
||||
interface Props {
|
||||
borderColour: string;
|
||||
distanceUnit: pond.DistanceUnit;
|
||||
}
|
||||
|
||||
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}>Qty</Text>
|
||||
<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 style={styles.endCell}>Nodes</Text>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
|||
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||
import React from "react";
|
||||
import { distanceConversion } from "utils";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
|
||||
interface Props {
|
||||
bin: jsonBin;
|
||||
borderColour: string;
|
||||
distanceUnit: pond.DistanceUnit;
|
||||
}
|
||||
|
||||
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.Type === 2 ? "Moisture" : "Temperature"}</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>
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { getDistanceUnit } from "utils";
|
||||
|
||||
interface Props {
|
||||
borderColour: string;
|
||||
distanceUnit: pond.DistanceUnit;
|
||||
}
|
||||
|
||||
export default function MountingTableHeader(props: Props) {
|
||||
|
|
@ -43,10 +43,12 @@ export default function MountingTableHeader(props: Props) {
|
|||
<View style={styles.view}>
|
||||
<Text style={styles.orbit}>Orbit</Text>
|
||||
<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 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 style={styles.bracket}>Bracket</Text>
|
||||
</View>
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
|||
import { getBracket, jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||
import React from "react";
|
||||
import { distanceConversion } from "utils";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
|
||||
interface Props {
|
||||
bin: jsonBin;
|
||||
borderColour: string;
|
||||
distanceUnit: pond.DistanceUnit;
|
||||
}
|
||||
|
||||
export default function MountingTableRow(props: Props) {
|
||||
|
|
@ -65,10 +67,10 @@ export default function MountingTableRow(props: Props) {
|
|||
key={i}>
|
||||
<Text style={styles.orbit}>{orbit.Orbit === 0 ? "C" : orbit.Orbit}</Text>
|
||||
<Text style={styles.centerDist}>
|
||||
{distanceConversion(orbit.DistanceFromCenter).toFixed(2)}
|
||||
{distanceConversion(orbit.DistanceFromCenter, props.distanceUnit).toFixed(2)}
|
||||
</Text>
|
||||
<Text style={styles.roofDist}>
|
||||
{distanceConversion(roofDist(orbit.DistanceFromCenter)).toFixed(2)}
|
||||
{distanceConversion(roofDist(orbit.DistanceFromCenter), props.distanceUnit).toFixed(2)}
|
||||
</Text>
|
||||
<Text style={styles.bracket}>
|
||||
{bracketType}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { StyleSheet, Text, View } from "@react-pdf/renderer";
|
||||
import { colors } from "@mui/material";
|
||||
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import CableTableHeader from "./cableTable/cableTableHeader";
|
||||
import CableTableRow from "./cableTable/cableTableRow";
|
||||
import PDFSideView from "./pdfSVG/pdfSideView";
|
||||
|
|
@ -10,9 +11,11 @@ import MountingTableRow from "./mountingTable/mountingTableRows";
|
|||
|
||||
interface Props {
|
||||
bin: jsonBin;
|
||||
distanceUnit: pond.DistanceUnit;
|
||||
}
|
||||
|
||||
export default function PdfContent(props: Props) {
|
||||
const { distanceUnit } = props;
|
||||
const tableBorderColour = colors.grey[800];
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
|
@ -53,7 +56,7 @@ export default function PdfContent(props: Props) {
|
|||
</View>
|
||||
<View style={{ height: 280, flexDirection: "row" }}>
|
||||
<View style={{ width: 260 }}>
|
||||
<PDFSideView bin={props.bin} />
|
||||
<PDFSideView bin={props.bin} distanceUnit={distanceUnit} />
|
||||
</View>
|
||||
<View style={{ width: 260 }}>
|
||||
<View style={{ height: 195 }}>
|
||||
|
|
@ -63,8 +66,12 @@ export default function PdfContent(props: Props) {
|
|||
<Text style={{ fontFamily: "Helvetica-Bold", marginBottom: 5 }}>Install Guide</Text>
|
||||
<View
|
||||
style={{ borderColor: tableBorderColour, borderWidth: 1, flexDirection: "column" }}>
|
||||
<MountingTableHeader borderColour={tableBorderColour} />
|
||||
<MountingTableRow borderColour={tableBorderColour} bin={props.bin} />
|
||||
<MountingTableHeader borderColour={tableBorderColour} distanceUnit={distanceUnit} />
|
||||
<MountingTableRow
|
||||
borderColour={tableBorderColour}
|
||||
bin={props.bin}
|
||||
distanceUnit={distanceUnit}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
|
@ -73,8 +80,12 @@ export default function PdfContent(props: Props) {
|
|||
Recommended Cables
|
||||
</Text>
|
||||
<View style={styles.cableTable}>
|
||||
<CableTableHeader borderColour={tableBorderColour} />
|
||||
<CableTableRow bin={props.bin} borderColour={tableBorderColour} />
|
||||
<CableTableHeader borderColour={tableBorderColour} distanceUnit={distanceUnit} />
|
||||
<CableTableRow
|
||||
bin={props.bin}
|
||||
borderColour={tableBorderColour}
|
||||
distanceUnit={distanceUnit}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
import { colors } from "@mui/material";
|
||||
import { Circle, Line, Path, Svg, Text } from "@react-pdf/renderer";
|
||||
import { jsonBin } from "common/DataImports/BinCables/BinCableImporter";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useEffect, useState } from "react";
|
||||
import { distanceConversion } from "utils";
|
||||
|
||||
interface Props {
|
||||
bin: jsonBin;
|
||||
distanceUnit: pond.DistanceUnit;
|
||||
}
|
||||
|
||||
interface svgPoint {
|
||||
|
|
@ -22,7 +24,7 @@ export default function PDFSideView(props: Props) {
|
|||
const nodeSpacing = 4; //space in feet between the nodes
|
||||
const dimensionFontSize = 18;
|
||||
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 [hopperHeight, setHopperHeight] = useState(0);
|
||||
const [roofHeight, setRoofHeight] = useState(0);
|
||||
|
|
@ -194,7 +196,7 @@ export default function PDFSideView(props: Props) {
|
|||
"bottomText",
|
||||
svgViewBoxSize / 2,
|
||||
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;
|
||||
|
||||
d.push(
|
||||
dimensionText("sidewallText", x2, midpoint, distanceConversion(bin.Sidewall).toFixed(1))
|
||||
dimensionText(
|
||||
"sidewallText",
|
||||
x2,
|
||||
midpoint,
|
||||
distanceConversion(bin.Sidewall, distanceUnit).toFixed(1)
|
||||
)
|
||||
);
|
||||
d.push(
|
||||
dimensionPath(
|
||||
|
|
@ -270,7 +277,7 @@ export default function PDFSideView(props: Props) {
|
|||
"peakText",
|
||||
xText,
|
||||
midpoint,
|
||||
distanceConversion(bin.Sidewall + roofHeight).toFixed(1)
|
||||
distanceConversion(bin.Sidewall + roofHeight, distanceUnit).toFixed(1)
|
||||
)
|
||||
);
|
||||
d.push(
|
||||
|
|
@ -313,7 +320,7 @@ export default function PDFSideView(props: Props) {
|
|||
"totalText",
|
||||
x2,
|
||||
midpoint,
|
||||
distanceConversion(roofHeight + bin.Sidewall + hopperHeight).toFixed(1)
|
||||
distanceConversion(roofHeight + bin.Sidewall + hopperHeight, distanceUnit).toFixed(1)
|
||||
)
|
||||
);
|
||||
d.push(
|
||||
|
|
|
|||
|
|
@ -1,57 +1,79 @@
|
|||
import { Box, BoxProps, Theme } from "@mui/material";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import classNames from "classnames";
|
||||
import { forwardRef, ReactNode } from "react";
|
||||
import { forwardRef, ReactNode, useCallback, useState } from "react";
|
||||
|
||||
const useStyles = makeStyles((_theme: Theme) => ({
|
||||
pulseWrapper: {
|
||||
position: 'relative',
|
||||
display: 'block', // Changed to block to respect Box margins
|
||||
width: 'fit-content', // Shrinks to child width
|
||||
'&::after': {
|
||||
content: '""',
|
||||
display: 'block',
|
||||
width: 'fit-content',
|
||||
isolation: 'isolate',
|
||||
overflow: 'visible',
|
||||
},
|
||||
pulseRing: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
border: '2px solid var(--pulse-color)',
|
||||
borderRadius: 'inherit', // Should inherit from Box
|
||||
animation: '$pulse 1.75s infinite ease-in-out',
|
||||
borderRadius: 'inherit',
|
||||
pointerEvents: 'none',
|
||||
boxSizing: 'border-box',
|
||||
transition: "border-color 0.35s ease-in-out",
|
||||
},
|
||||
zIndex: -1,
|
||||
animation: '$pulse 4.4s infinite ease-in-out',
|
||||
},
|
||||
'@keyframes pulse': {
|
||||
from: {
|
||||
transform: "scale(1)",
|
||||
opacity: 1
|
||||
},
|
||||
to: {
|
||||
transform: "scale(1.25)",
|
||||
opacity: 0
|
||||
}
|
||||
/* Start behind box, then expand out and fade */
|
||||
/* pulse, pause, pulse, pause - CONSISTENT: both pauses equal, both pulses equal */
|
||||
/* Pulse 1 (0-42%) - gradual fade in to soften the start */
|
||||
'0%': { boxShadow: '0 0 0 -2px var(--pulse-color)', opacity: 1 },
|
||||
'40%': { boxShadow: '0 0 0 14px var(--pulse-color)', opacity: 0 },
|
||||
'42%': { boxShadow: '0 0 0 -2px var(--pulse-color)', opacity: 0 },
|
||||
/* Pause 1 (42-50%) */
|
||||
'50%': { boxShadow: '0 0 0 -2px var(--pulse-color)', opacity: 0 },
|
||||
/* Pulse 2 (50-92%) */
|
||||
'52%': { boxShadow: '0 0 0 -2px var(--pulse-color)', opacity: 1 },
|
||||
'90%': { boxShadow: '0 0 0 14px var(--pulse-color)', opacity: 0 },
|
||||
'92%': { boxShadow: '0 0 0 -2px var(--pulse-color)', opacity: 0 },
|
||||
/* Pause 2 (92-100%) - same length as Pause 1, color change at iteration */
|
||||
'100%': { boxShadow: '0 0 0 -2px var(--pulse-color)', opacity: 0 },
|
||||
},
|
||||
}));
|
||||
|
||||
interface Props extends BoxProps {
|
||||
color: string;
|
||||
colors?: string[];
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const PulseBox = forwardRef<HTMLDivElement, Props>((props, ref) => {
|
||||
const { color, children, className, ...boxProps } = props;
|
||||
const { color, colors: colorsProp, children, className, ...boxProps } = props;
|
||||
const classes = useStyles()
|
||||
|
||||
const colors = colorsProp && colorsProp.length > 0 ? colorsProp : [color];
|
||||
const [colorIndex, setColorIndex] = useState(0);
|
||||
const displayColor = colors[colorIndex % colors.length] ?? color;
|
||||
|
||||
const onAnimationIteration = useCallback(() => {
|
||||
if (colors.length > 1) {
|
||||
setColorIndex((i) => (i + 1) % colors.length);
|
||||
}
|
||||
}, [colors.length]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
ref={ref}
|
||||
{...boxProps}
|
||||
className={classNames([classes.pulseWrapper, className])}
|
||||
style={{ '--pulse-color': color } as React.CSSProperties}
|
||||
style={{ '--pulse-color': displayColor } as React.CSSProperties}
|
||||
>
|
||||
<span
|
||||
className={classes.pulseRing}
|
||||
aria-hidden
|
||||
onAnimationIteration={onAnimationIteration}
|
||||
/>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
},
|
||||
tableContainer: {
|
||||
width: "100%",
|
||||
maxWidth: "100%",
|
||||
overflow: "hidden",
|
||||
minWidth: 0,
|
||||
},
|
||||
title: {
|
||||
|
|
@ -28,13 +26,12 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
marginTop: theme.spacing(-2),
|
||||
},
|
||||
titleComp: {
|
||||
padding: theme.spacing(1),
|
||||
marginLeft: theme.spacing(-1)
|
||||
padding: theme.spacing(1, 1, 0, 1.5),
|
||||
},
|
||||
subtitleComp: {
|
||||
padding: theme.spacing(1),
|
||||
marginTop: theme.spacing(-2),
|
||||
marginLeft: theme.spacing(-1),
|
||||
padding: theme.spacing(0, 1, 0.5, 1.5),
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
titleContainer: {
|
||||
border: "none",
|
||||
|
|
@ -42,6 +39,8 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
searchContainer: {
|
||||
border: "none",
|
||||
textAlign: "right",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
mobileTitleBox: {
|
||||
margin: theme.spacing(1),
|
||||
|
|
@ -118,8 +117,9 @@ function ResizableHeaderTitle<T>(props: {
|
|||
: {}),
|
||||
}}
|
||||
>
|
||||
<Box component="span" sx={{ whiteSpace: "nowrap" }}>
|
||||
{column.title} {showOrderIcon(column)}
|
||||
<Box component="span" sx={{ whiteSpace: "nowrap", display: "inline-flex", alignItems: "center" }}>
|
||||
<Box component="span">{column.title}</Box>
|
||||
{showOrderIcon(column)}
|
||||
</Box>
|
||||
</Grid2>
|
||||
);
|
||||
|
|
@ -235,6 +235,11 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
localStorage.setItem(filterKey, JSON.stringify(filterList));
|
||||
}, [filterList])
|
||||
|
||||
const headerColSpan =
|
||||
(columns?.length ?? ((rows?.[0] && Object.keys(rows[0]).length) || 0)) +
|
||||
(rowSelect ? 1 : 0) +
|
||||
(renderGutter ? 1 : 0);
|
||||
|
||||
const openColumnMenu = (event: any) => {
|
||||
setColumnAnchor(event.currentTarget);
|
||||
// setUserMenuIsOpen(true);
|
||||
|
|
@ -491,9 +496,17 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
const sortKey = column.sortKey ? column.sortKey : column.title.toLowerCase()
|
||||
if (sortKey === orderBy) {
|
||||
if (order === "asc") {
|
||||
return <ArrowDownward fontSize="small" sx={{ marginLeft: 1 }} />
|
||||
return (
|
||||
<Box component="span" sx={{ ml: 0.5, display: "inline-flex", alignItems: "center" }}>
|
||||
<ArrowDownward fontSize="small" />
|
||||
</Box>
|
||||
)
|
||||
} else {
|
||||
return <ArrowUpward fontSize="small" sx={{ marginLeft: 1 }} />
|
||||
return (
|
||||
<Box component="span" sx={{ ml: 0.5, display: "inline-flex", alignItems: "center" }}>
|
||||
<ArrowUpward fontSize="small" />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
@ -536,15 +549,13 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
const clampedWidth = Math.max(MIN_COLUMN_WIDTH, newWidthForIndex)
|
||||
const actualDelta = newWidths[index] - clampedWidth
|
||||
newWidths[index] = clampedWidth
|
||||
newWidths.every((width, j) => {
|
||||
if (j <= index || width === 0) return true
|
||||
else if (newWidths[j] !== undefined) {
|
||||
newWidths[j] = newWidths[j] + actualDelta
|
||||
return false
|
||||
}
|
||||
})
|
||||
setRowWidths(newWidths)
|
||||
|
||||
if (actualDelta > 0) {
|
||||
// Shrinking current column – give space to next column
|
||||
newWidths[index + 1] = (newWidths[index + 1] ?? 0) + actualDelta
|
||||
}
|
||||
// When growing (actualDelta < 0): never shrink adjacent columns – table grows to accommodate
|
||||
setRowWidths(newWidths)
|
||||
}
|
||||
|
||||
const MIN_COLUMN_WIDTH = 24;
|
||||
|
|
@ -553,14 +564,17 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
<Box className={classes.tableContainer} component={Paper}>
|
||||
{(title || setSearchText) && (
|
||||
<Box>
|
||||
<Grid2 container justifyContent="space-between" alignItems="center" sx={{ padding: 1 }}>
|
||||
<Grid2
|
||||
container
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
sx={{ px: 1.5, pt: 1, pb: 0.5 }}
|
||||
>
|
||||
<Grid2>
|
||||
<Box sx={{ marginTop: -1 }}>
|
||||
{renderTitle()}
|
||||
{renderSubtitle()}
|
||||
</Box>
|
||||
</Grid2>
|
||||
<Grid2 size={{ xs: "grow" }} sx={{ minWidth: 0, display: "flex", justifyContent: "flex-end" }}>
|
||||
<Grid2 size={{ xs: "grow" }} sx={{ minWidth: 0, display: "flex", justifyContent: "flex-end", mt: -1 }}>
|
||||
<Grid2 container alignItems="center" spacing={1} wrap="nowrap">
|
||||
<Grid2>
|
||||
{actions && actions}
|
||||
|
|
@ -588,11 +602,24 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
</Box>
|
||||
)}
|
||||
<TableContainer sx={{ overflowX: "auto", paddingBottom: 1 }}>
|
||||
<Table>
|
||||
<Table
|
||||
sx={{
|
||||
tableLayout: "fixed",
|
||||
width: columns && rowWidths.length > 0
|
||||
? (() => {
|
||||
const colsWidth = columns.reduce(
|
||||
(sum, c, i) => sum + (filterList.includes(c.title) || c.hidden ? 0 : (rowWidths[i] ?? 0)),
|
||||
0
|
||||
) + (rowSelect ? 48 : 0) + (renderGutter ? 48 : 0)
|
||||
return colsWidth > 0 ? `max(${colsWidth}px, 100%)` : "100%"
|
||||
})()
|
||||
: "100%",
|
||||
}}
|
||||
>
|
||||
<TableHead className={stickyHeader ? classes.stickyHeader : undefined}>
|
||||
{customElement &&
|
||||
<TableRow>
|
||||
<TableCell colSpan={10000} sx={{ border: "none" }}>
|
||||
<TableCell colSpan={headerColSpan} sx={{ border: "none" }}>
|
||||
{customElement}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { Device } from "models";
|
|||
import PulseBox from "./PulseBox";
|
||||
import RelativeTimestamp from "./RelativeTimestamp";
|
||||
import { or } from "utils";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
device: Device;
|
||||
|
|
@ -23,71 +22,47 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
marginRight: "auto",
|
||||
margin: theme.spacing(1),
|
||||
width: theme.spacing(16),
|
||||
height: theme.spacing(11),
|
||||
minHeight: theme.spacing(11),
|
||||
},
|
||||
readingsWrapper: {
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
minHeight: theme.spacing(10),
|
||||
},
|
||||
carouselContainer: {
|
||||
position: 'relative',
|
||||
height: '40px',
|
||||
overflow: 'hidden',
|
||||
position: "relative",
|
||||
height: "40px",
|
||||
overflow: "hidden",
|
||||
textAlign: "center",
|
||||
},
|
||||
carouselItem: {
|
||||
opacity: 0,
|
||||
transform: 'translateX(100%)',
|
||||
transition: 'opacity 0.5s ease, transform 0.5s ease',
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
transform: "translateX(100%)",
|
||||
transition: "opacity 0.5s ease, transform 0.5s ease",
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
overflow: "hidden",
|
||||
// height: '100%',
|
||||
},
|
||||
active: {
|
||||
opacity: 1,
|
||||
transform: 'translateX(0)',
|
||||
transform: "translateX(0)",
|
||||
},
|
||||
inactive: {
|
||||
transform: 'translateX(-100%)',
|
||||
transform: "translateX(-100%)",
|
||||
},
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
export default function StatusDust(props: Props) {
|
||||
const { device, showTimestamp } = props;
|
||||
const classes = useStyles()
|
||||
const classes = useStyles();
|
||||
|
||||
const colors = or(device.status.sen5x?.overlays.map(overlay => overlay.color), []);
|
||||
const messages = or(device.status.sen5x?.overlays.map(overlay => overlay.message), []);
|
||||
|
||||
const [color, setColor] = useState(colors.length > 0 ? colors[0] : "");
|
||||
const [, setColorIndex] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setColorIndex(prevIndex => {
|
||||
const newIndex = prevIndex >= colors.length - 1 ? 0 : prevIndex + 1;
|
||||
setColor(colors[newIndex]); // Use the new index here
|
||||
return newIndex;
|
||||
});
|
||||
}, 7500);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
// const [currentIndex, setCurrentIndex] = useState(0);
|
||||
|
||||
// Auto-cycle through measurements every 3 seconds
|
||||
// useEffect(() => {
|
||||
// const interval = setInterval(() => {
|
||||
// setCurrentIndex((prevIndex) => (prevIndex + 1) % 2);
|
||||
// }, 3000); // Adjust timing as needed (3000ms = 3s)
|
||||
|
||||
// return () => clearInterval(interval); // Cleanup on unmount
|
||||
// }, []);
|
||||
const colors = or(device.status.sen5x?.overlays.map((overlay) => overlay.color), []);
|
||||
const messages = or(device.status.sen5x?.overlays.map((overlay) => overlay.message), []);
|
||||
|
||||
const tooltip = () => {
|
||||
if (messages.length === 0) return null
|
||||
if (messages.length < 2) return (
|
||||
messages[0]
|
||||
)
|
||||
if (messages.length === 0) return null;
|
||||
if (messages.length < 2) return messages[0];
|
||||
return (
|
||||
<Grid2 container direction={"column"}>
|
||||
<Grid2 container direction="row">
|
||||
|
|
@ -100,10 +75,10 @@ export default function StatusDust(props: Props) {
|
|||
<Grid2 key={"tooltip-overly-message-" + message} container direction="row" alignItems={"center"}>
|
||||
<Box
|
||||
sx={{
|
||||
width: 10, // Size of the square
|
||||
width: 10,
|
||||
height: 10,
|
||||
backgroundColor: colors[index], // Passed color prop
|
||||
borderRadius: 1, // Optional: slight rounding, remove for sharp square
|
||||
backgroundColor: colors[index],
|
||||
borderRadius: 1,
|
||||
border: "1px solid black",
|
||||
}}
|
||||
/>
|
||||
|
|
@ -111,22 +86,20 @@ export default function StatusDust(props: Props) {
|
|||
{message}
|
||||
</Typography>
|
||||
</Grid2>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</Grid2>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
function compareTimestamps(timestamp1: string, timestamp2: string): number {
|
||||
const date1 = new Date(timestamp1);
|
||||
const date2 = new Date(timestamp2);
|
||||
|
||||
// Check if dates are valid
|
||||
if (isNaN(date1.getTime()) || isNaN(date2.getTime())) {
|
||||
throw new Error("Invalid RFC3339 timestamp format");
|
||||
}
|
||||
|
||||
// Compare using getTime() for millisecond precision
|
||||
return date1.getTime() - date2.getTime();
|
||||
}
|
||||
|
||||
|
|
@ -134,47 +107,49 @@ export default function StatusDust(props: Props) {
|
|||
const now = new Date();
|
||||
const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
||||
if (compareTimestamps(device.status.sen5x?.timestamp, oneDayAgo.toISOString()) < 0) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip title={tooltip()}>
|
||||
<PulseBox color={color} className={classes.box} >
|
||||
<Grid2 container direction="column" >
|
||||
<Grid2 container direction="column"
|
||||
className={`${classes.carouselItem} ${classes.active }`}
|
||||
>
|
||||
<PulseBox color={colors[0] ?? ""} colors={colors} className={classes.box}>
|
||||
<Grid2 container direction="column" spacing={0.25}>
|
||||
<Grid2 className={classes.readingsWrapper}>
|
||||
<Grid2 container direction="column" className={`${classes.carouselItem} ${classes.active}`}>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: green[300]}}>
|
||||
<Typography variant="body2" style={{ color: green[300] }}>
|
||||
{"<1um:"} {device.status.sen5x?.dust1ug.toFixed(1)}ug/m3
|
||||
</Typography>
|
||||
</Grid2>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: green[400]}}>
|
||||
<Typography variant="body2" style={{ color: green[400] }}>
|
||||
{"<2.5um:"} {device.status.sen5x?.dust2ug.toFixed(1)}ug/m3
|
||||
</Typography>
|
||||
</Grid2>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: green[500]}}>
|
||||
{"<4um: "}{device.status.sen5x?.dust4ug.toFixed(1)}ug/m3
|
||||
<Typography variant="body2" style={{ color: green[500] }}>
|
||||
{"<4um: "}
|
||||
{device.status.sen5x?.dust4ug.toFixed(1)}ug/m3
|
||||
</Typography>
|
||||
</Grid2>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: green[600]}}>
|
||||
{"<10um: "}{device.status.sen5x?.dust10ug.toFixed(1)}ug/m3
|
||||
<Typography variant="body2" style={{ color: green[600] }}>
|
||||
{"<10um: "}
|
||||
{device.status.sen5x?.dust10ug.toFixed(1)}ug/m3
|
||||
</Typography>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
{showTimestamp && device.status.sen5x?.timestamp && (
|
||||
<Grid2>
|
||||
<Grid2 sx={{ pt: 0.25 }}>
|
||||
<RelativeTimestamp timestamp={device.status.sen5x.timestamp} />
|
||||
</Grid2>
|
||||
)}
|
||||
</Grid2>
|
||||
</PulseBox>
|
||||
</Tooltip>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
@ -85,23 +85,8 @@ export default function StatusGas(props: Props) {
|
|||
messages = or(device.status[gasType]?.overlays?.map(overlay => overlay.message), []);
|
||||
}
|
||||
|
||||
const [color, setColor] = useState(colors.length > 0 ? colors[0] : "");
|
||||
const [, setColorIndex] = useState(0)
|
||||
|
||||
const gasTypes: ("o2" | "no2" | "co2" | "co" | "lel" | "h2s")[] = ["o2", "no2", "co2", "co", "lel", "h2s"]
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setColorIndex(prevIndex => {
|
||||
const newIndex = prevIndex >= colors.length - 1 ? 0 : prevIndex + 1;
|
||||
setColor(colors[newIndex]); // Use the new index here
|
||||
return newIndex;
|
||||
});
|
||||
}, 7500);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
|
||||
// Auto-cycle through measurements every 5 seconds
|
||||
|
|
@ -183,7 +168,7 @@ export default function StatusGas(props: Props) {
|
|||
}
|
||||
return (
|
||||
<Tooltip title={tooltip()}>
|
||||
<PulseBox color={color} className={gasType === "all" ? classes.boxTall : classes.box}>
|
||||
<PulseBox color={colors[0] ?? ""} colors={colors} className={gasType === "all" ? classes.boxTall : classes.box}>
|
||||
<Grid2 container direction="column" >
|
||||
{ gasType === "all" &&
|
||||
<Typography variant="body2">
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { Device } from "models";
|
|||
import PulseBox from "./PulseBox";
|
||||
import RelativeTimestamp from "./RelativeTimestamp";
|
||||
import { or } from "utils";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface Props {
|
||||
device: Device;
|
||||
|
|
@ -33,21 +32,6 @@ export default function StatusPlenum(props: Props) {
|
|||
const colors = or(device.status.plenum?.overlays.map(overlay => overlay.color), []);
|
||||
const messages = or(device.status.plenum?.overlays.map(overlay => overlay.message), []);
|
||||
|
||||
const [color, setColor] = useState(colors.length > 0 ? colors[0] : "");
|
||||
const [, setColorIndex] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setColorIndex(prevIndex => {
|
||||
const newIndex = prevIndex >= colors.length - 1 ? 0 : prevIndex + 1;
|
||||
setColor(colors[newIndex]); // Use the new index here
|
||||
return newIndex;
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
const tooltip = () => {
|
||||
if (messages.length === 0) return null
|
||||
if (messages.length < 2) return (
|
||||
|
|
@ -107,7 +91,7 @@ export default function StatusPlenum(props: Props) {
|
|||
|
||||
return (
|
||||
<Tooltip title={tooltip()}>
|
||||
<PulseBox color={color} className={classes.box} >
|
||||
<PulseBox color={colors[0] ?? ""} colors={colors} className={classes.box} >
|
||||
<Grid2 container direction="column" >
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: orange[700]}}>
|
||||
|
|
|
|||
|
|
@ -24,75 +24,61 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
marginRight: "auto",
|
||||
margin: theme.spacing(1),
|
||||
width: theme.spacing(16),
|
||||
height: theme.spacing(11),
|
||||
minHeight: theme.spacing(11),
|
||||
},
|
||||
/** Reserves vertical space so absolute carousel slides do not overlap the timestamp below. */
|
||||
readingsWrapper: {
|
||||
position: "relative",
|
||||
width: "100%",
|
||||
minHeight: theme.spacing(10),
|
||||
},
|
||||
carouselContainer: {
|
||||
position: 'relative',
|
||||
height: '40px',
|
||||
overflow: 'hidden',
|
||||
position: "relative",
|
||||
height: "40px",
|
||||
overflow: "hidden",
|
||||
textAlign: "center",
|
||||
},
|
||||
carouselItem: {
|
||||
opacity: 0,
|
||||
transform: 'translateX(100%)',
|
||||
transition: 'opacity 0.5s ease, transform 0.5s ease',
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
transform: "translateX(100%)",
|
||||
transition: "opacity 0.5s ease, transform 0.5s ease",
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
overflow: "hidden",
|
||||
// height: '100%',
|
||||
},
|
||||
active: {
|
||||
opacity: 1,
|
||||
transform: 'translateX(0)',
|
||||
transform: "translateX(0)",
|
||||
},
|
||||
inactive: {
|
||||
transform: 'translateX(-100%)',
|
||||
transform: "translateX(-100%)",
|
||||
},
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
export default function StatusSen5x(props: Props) {
|
||||
const { device, noDust, showTimestamp } = props;
|
||||
const classes = useStyles()
|
||||
// console.log(noDust)
|
||||
const colors = or(device.status.sen5x?.overlays.map(overlay => overlay.color), []);
|
||||
const messages = or(device.status.sen5x?.overlays.map(overlay => overlay.message), []);
|
||||
|
||||
const [color, setColor] = useState(colors.length > 0 ? colors[0] : "");
|
||||
const [, setColorIndex] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setColorIndex(prevIndex => {
|
||||
const newIndex = prevIndex >= colors.length - 1 ? 0 : prevIndex + 1;
|
||||
setColor(colors[newIndex]); // Use the new index here
|
||||
return newIndex;
|
||||
});
|
||||
}, 7500);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
const classes = useStyles();
|
||||
const colors = or(device.status.sen5x?.overlays.map((overlay) => overlay.color), []);
|
||||
const messages = or(device.status.sen5x?.overlays.map((overlay) => overlay.message), []);
|
||||
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
|
||||
// Auto-cycle through measurements every 5 seconds
|
||||
useEffect(() => {
|
||||
if (noDust) {
|
||||
setCurrentIndex(0)
|
||||
return
|
||||
setCurrentIndex(0);
|
||||
return;
|
||||
}
|
||||
const interval = setInterval(() => {
|
||||
if (!noDust) setCurrentIndex((prevIndex) => (prevIndex + 1) % 2);
|
||||
}, 5000);
|
||||
|
||||
return () => clearInterval(interval); // Cleanup on unmount
|
||||
return () => clearInterval(interval);
|
||||
}, [noDust]);
|
||||
|
||||
const tooltip = () => {
|
||||
if (messages.length === 0) return null
|
||||
if (messages.length < 2) return (
|
||||
messages[0]
|
||||
)
|
||||
if (messages.length === 0) return null;
|
||||
if (messages.length < 2) return messages[0];
|
||||
return (
|
||||
<Grid2 container direction={"column"}>
|
||||
<Grid2 container direction="row">
|
||||
|
|
@ -105,10 +91,10 @@ export default function StatusSen5x(props: Props) {
|
|||
<Grid2 key={"tooltip-overly-message-" + message} container direction="row" alignItems={"center"}>
|
||||
<Box
|
||||
sx={{
|
||||
width: 10, // Size of the square
|
||||
width: 10,
|
||||
height: 10,
|
||||
backgroundColor: colors[index], // Passed color prop
|
||||
borderRadius: 1, // Optional: slight rounding, remove for sharp square
|
||||
backgroundColor: colors[index],
|
||||
borderRadius: 1,
|
||||
border: "1px solid black",
|
||||
}}
|
||||
/>
|
||||
|
|
@ -116,22 +102,20 @@ export default function StatusSen5x(props: Props) {
|
|||
{message}
|
||||
</Typography>
|
||||
</Grid2>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</Grid2>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
function compareTimestamps(timestamp1: string, timestamp2: string): number {
|
||||
const date1 = new Date(timestamp1);
|
||||
const date2 = new Date(timestamp2);
|
||||
|
||||
// Check if dates are valid
|
||||
if (isNaN(date1.getTime()) || isNaN(date2.getTime())) {
|
||||
throw new Error("Invalid RFC3339 timestamp format");
|
||||
}
|
||||
|
||||
// Compare using getTime() for millisecond precision
|
||||
return date1.getTime() - date2.getTime();
|
||||
}
|
||||
|
||||
|
|
@ -139,76 +123,82 @@ export default function StatusSen5x(props: Props) {
|
|||
const now = new Date();
|
||||
const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
||||
if (compareTimestamps(device.status.sen5x?.timestamp, oneDayAgo.toISOString()) < 0) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip title={tooltip()}>
|
||||
<PulseBox color={color} className={classes.box} >
|
||||
<Grid2 container direction="column" >
|
||||
<Grid2 container direction="column"
|
||||
className={`${classes.carouselItem} ${
|
||||
0 === currentIndex ? classes.active : classes.inactive
|
||||
}`}
|
||||
<PulseBox color={colors[0] ?? ""} colors={colors} className={classes.box}>
|
||||
<Grid2 container direction="column" spacing={0.25}>
|
||||
<Grid2 className={classes.readingsWrapper}>
|
||||
<Grid2
|
||||
container
|
||||
direction="column"
|
||||
className={`${classes.carouselItem} ${0 === currentIndex ? classes.active : classes.inactive}`}
|
||||
>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: orange[700]}}>
|
||||
<Typography variant="body2" style={{ color: orange[700] }}>
|
||||
Temp: {device.status.sen5x?.temperature.toFixed(1)}°C
|
||||
</Typography>
|
||||
</Grid2>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: blue[700]}}>
|
||||
<Typography variant="body2" style={{ color: blue[700] }}>
|
||||
Humidity: {device.status.sen5x?.humidity.toFixed(1)}%
|
||||
</Typography>
|
||||
</Grid2>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: blue[300]}}>
|
||||
<Typography variant="body2" style={{ color: blue[300] }}>
|
||||
Voc: {device.status.sen5x?.voc.toFixed(1)}%
|
||||
</Typography>
|
||||
</Grid2>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: blue[400]}}>
|
||||
<Typography variant="body2" style={{ color: blue[400] }}>
|
||||
Nox: {device.status.sen5x?.nox.toFixed(1)}%
|
||||
</Typography>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
|
||||
{!noDust && <Grid2 container direction="column"
|
||||
className={`${classes.carouselItem} ${
|
||||
1 === currentIndex ? classes.active : classes.inactive
|
||||
}`}
|
||||
{!noDust && (
|
||||
<Grid2
|
||||
container
|
||||
direction="column"
|
||||
className={`${classes.carouselItem} ${1 === currentIndex ? classes.active : classes.inactive}`}
|
||||
>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: green[300]}}>
|
||||
<Typography variant="body2" style={{ color: green[300] }}>
|
||||
{"<1um:"} {device.status.sen5x?.dust1ug.toFixed(1)}ug/m3
|
||||
</Typography>
|
||||
</Grid2>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: green[400]}}>
|
||||
<Typography variant="body2" style={{ color: green[400] }}>
|
||||
{"<2.5um:"} {device.status.sen5x?.dust2ug.toFixed(1)}ug/m3
|
||||
</Typography>
|
||||
</Grid2>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: green[500]}}>
|
||||
{"<4um: "}{device.status.sen5x?.dust4ug.toFixed(1)}ug/m3
|
||||
<Typography variant="body2" style={{ color: green[500] }}>
|
||||
{"<4um: "}
|
||||
{device.status.sen5x?.dust4ug.toFixed(1)}ug/m3
|
||||
</Typography>
|
||||
</Grid2>
|
||||
<Grid2>
|
||||
<Typography variant="body2" style={{ color: green[600]}}>
|
||||
{"<10um: "}{device.status.sen5x?.dust10ug.toFixed(1)}ug/m3
|
||||
<Typography variant="body2" style={{ color: green[600] }}>
|
||||
{"<10um: "}
|
||||
{device.status.sen5x?.dust10ug.toFixed(1)}ug/m3
|
||||
</Typography>
|
||||
</Grid2>
|
||||
</Grid2>}
|
||||
</Grid2>
|
||||
)}
|
||||
</Grid2>
|
||||
{showTimestamp && device.status.sen5x?.timestamp && (
|
||||
<Grid2>
|
||||
<Grid2 sx={{ pt: 0.25 }}>
|
||||
<RelativeTimestamp timestamp={device.status.sen5x.timestamp} />
|
||||
</Grid2>
|
||||
)}
|
||||
</Grid2>
|
||||
</PulseBox>
|
||||
</Tooltip>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
@ -44,7 +44,6 @@ import { bestUnit, milliToX } from "common/time/duration";
|
|||
import { useGlobalState } from "providers";
|
||||
import { green, red } from "@mui/material/colors";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { getDistanceUnit } from "utils";
|
||||
import { GrainOptions } from "grain";
|
||||
import CompModes from "component/ComponentMode.json";
|
||||
import FanPicker from "fans/fanPicker";
|
||||
|
|
@ -177,11 +176,11 @@ export default function ComponentForm(props: Props) {
|
|||
let width = formComponent.settings.containerDimensions?.widthCm ?? 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;
|
||||
width = width / 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;
|
||||
width = width / 30.48;
|
||||
height = height / 30.48;
|
||||
|
|
@ -189,9 +188,9 @@ export default function ComponentForm(props: Props) {
|
|||
|
||||
let sensorDistance = formComponent.settings.sensorDistanceCm ?? 0;
|
||||
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
sensorDistance = sensorDistance / 100;
|
||||
} else if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
} else if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
sensorDistance = sensorDistance / 30.48;
|
||||
}
|
||||
|
||||
|
|
@ -520,9 +519,9 @@ export default function ComponentForm(props: Props) {
|
|||
if (!isNaN(Number(event.target.value))) {
|
||||
let dimensions = f.component.settings.containerDimensions;
|
||||
let value = Number(event.target.value);
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
value = value * 100;
|
||||
} else if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
} else if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
value = value * 30.48;
|
||||
}
|
||||
if (dimensions !== undefined && dimensions !== null) {
|
||||
|
|
@ -549,9 +548,9 @@ export default function ComponentForm(props: Props) {
|
|||
if (!isNaN(Number(event.target.value))) {
|
||||
let dimensions = f.component.settings.containerDimensions;
|
||||
let value = Number(event.target.value);
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
value = value * 100;
|
||||
} else if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
} else if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
value = value * 30.48;
|
||||
}
|
||||
if (dimensions !== undefined && dimensions !== null) {
|
||||
|
|
@ -578,9 +577,9 @@ export default function ComponentForm(props: Props) {
|
|||
if (!isNaN(Number(event.target.value))) {
|
||||
let dimensions = f.component.settings.containerDimensions;
|
||||
let value = Number(event.target.value);
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
value = value * 100;
|
||||
} else if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
} else if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
value = value * 30.48;
|
||||
}
|
||||
if (dimensions !== undefined && dimensions !== null) {
|
||||
|
|
@ -606,9 +605,9 @@ export default function ComponentForm(props: Props) {
|
|||
f.sensorDistance = event.target.value;
|
||||
if (!isNaN(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;
|
||||
} else if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
} else if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
value = value * 30.48;
|
||||
}
|
||||
f.component.settings.sensorDistanceCm = value;
|
||||
|
|
@ -1252,7 +1251,7 @@ export default function ComponentForm(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||
? "m"
|
||||
: "ft"}
|
||||
</InputAdornment>
|
||||
|
|
@ -1276,7 +1275,7 @@ export default function ComponentForm(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||
? "m"
|
||||
: "ft"}
|
||||
</InputAdornment>
|
||||
|
|
@ -1300,7 +1299,7 @@ export default function ComponentForm(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||
? "m"
|
||||
: "ft"}
|
||||
</InputAdornment>
|
||||
|
|
@ -1328,7 +1327,7 @@ export default function ComponentForm(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||
{user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
const { contracts, contractPermissions, updateList } = props;
|
||||
const theme = useTheme();
|
||||
const [{as}] = useGlobalState();
|
||||
const [{as, user}] = useGlobalState();
|
||||
//will need map for contracts that have supported grain types
|
||||
const [supportedTypes, setSupportedTypes] = useState<Map<pond.Grain, Contract[]>>(new Map());
|
||||
//will need need map for custom contracts
|
||||
|
|
@ -173,16 +173,16 @@ export default function ContractsList(props: Props) {
|
|||
<TableCell>{contract.name()}</TableCell>
|
||||
<TableCell>{contract.settings.contractDate}</TableCell>
|
||||
<TableCell>{contract.settings.deliveryWindow?.endDate}</TableCell>
|
||||
<TableCell>{contract.sizeInPreferredUnit() + " " + contract.unit}</TableCell>
|
||||
<TableCell>{contract.deliveredInPreferredUnit() + " " + contract.unit}</TableCell>
|
||||
<TableCell>{contract.sizeInPreferredUnit(user) + " " + contract.unit}</TableCell>
|
||||
<TableCell>{contract.deliveredInPreferredUnit(user) + " " + contract.unit}</TableCell>
|
||||
<TableCell>
|
||||
{/* <progress value={contract.settings.delivered} max={contract.settings.size} style={{height: 10}}/> */}
|
||||
<CustomProgressBar colour={colors.blue[500]} completed={fillPercent} />
|
||||
{/* {((contract.settings.delivered/contract.settings.size)*100).toFixed(1) + "%"} */}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{contract.sizeInPreferredUnit() -
|
||||
contract.deliveredInPreferredUnit() +
|
||||
{contract.sizeInPreferredUnit(user) -
|
||||
contract.deliveredInPreferredUnit(user) +
|
||||
" " +
|
||||
contract.unit}
|
||||
</TableCell>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import moment from "moment";
|
|||
import { pond } from "protobuf-ts/pond";
|
||||
import { useGlobalState, useTaskAPI, useContractAPI, useSnackbar } from "providers";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { getGrainUnit } from "utils";
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
|
|
@ -45,7 +44,7 @@ export default function ContractSettings(props: Props) {
|
|||
const { open, close, contract } = props;
|
||||
const contractAPI = useContractAPI();
|
||||
const [name, setName] = useState("");
|
||||
const [{as}] = useGlobalState();
|
||||
const [{as, user}] = useGlobalState();
|
||||
const [contractID, setContractID] = useState(""); //id
|
||||
const [holder, setHolder] = useState(""); //holder
|
||||
const [deliveryStart, setDeliveryStart] = useState(moment().format("YYYY-MM-DD")); //deliverystart
|
||||
|
|
@ -72,7 +71,6 @@ export default function ContractSettings(props: Props) {
|
|||
adornment: ""
|
||||
});
|
||||
const taskAPI = useTaskAPI();
|
||||
const [{ user }] = useGlobalState();
|
||||
|
||||
const closeSettings = () => {
|
||||
close();
|
||||
|
|
@ -87,32 +85,32 @@ export default function ContractSettings(props: Props) {
|
|||
setDeliveryEnd(contract.settings.deliveryWindow?.endDate ?? "");
|
||||
setContractType(contract.settings.type);
|
||||
setCustomCommodity(contract.settings.customCommodity);
|
||||
setContractSize(contract.sizeInPreferredUnit().toFixed(2));
|
||||
setDeliveredAmount(contract.deliveredInPreferredUnit().toFixed(2));
|
||||
setContractSize(contract.sizeInPreferredUnit(user).toFixed(2));
|
||||
setDeliveredAmount(contract.deliveredInPreferredUnit(user).toFixed(2));
|
||||
setContractValue(contract.settings.totalValue.toString());
|
||||
setCommodity(contract.settings.commodity);
|
||||
setContractDate(contract.settings.contractDate);
|
||||
let conv = 1
|
||||
if(contract.settings.conversionValue > 1){
|
||||
conv = contract.settings.conversionValue
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||
conv = conv * 0.907
|
||||
}
|
||||
}
|
||||
setConversionValue(conv.toFixed(2));
|
||||
setUseCustom(contract.isCustom());
|
||||
}
|
||||
}, [contract]);
|
||||
}, [contract, user]);
|
||||
|
||||
useEffect(() => {
|
||||
switch (contractType) {
|
||||
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
||||
let conversionLabel = "Bushels Per Tonne"
|
||||
let adornment = "bu"
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
adornment = "mT"
|
||||
}
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||
conversionLabel = "Bushels Per Ton"
|
||||
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
|
||||
const deliveredVal = isNaN(parseFloat(deliveredAmount))
|
||||
? 0
|
||||
: Math.round(Contract.toStoredUnit(parseFloat(deliveredAmount), contractType, conVal));
|
||||
: Math.round(Contract.toStoredUnit(parseFloat(deliveredAmount), contractType, conVal, user));
|
||||
const sizeVal = isNaN(parseFloat(contractSize))
|
||||
? 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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import { Transaction } from "models/Transaction";
|
|||
import BarGraph, { BarData } from "charts/BarGraph";
|
||||
import { useEffect, useState } from "react";
|
||||
import moment, { Moment } from "moment";
|
||||
import { getGrainUnit } from "utils";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useGlobalState } from "providers";
|
||||
|
||||
interface Props {
|
||||
contract: Contract;
|
||||
|
|
@ -14,6 +14,7 @@ interface Props {
|
|||
|
||||
export default function ContractTransactionGraph(props: Props) {
|
||||
const { contract, transactions } = props;
|
||||
const [{ user }] = useGlobalState();
|
||||
const [data, setData] = useState<BarData[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -27,13 +28,13 @@ export default function ContractTransactionGraph(props: Props) {
|
|||
if (transaction?.grainTransaction) {
|
||||
value = transaction.grainTransaction.bushels;
|
||||
if (
|
||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
||||
user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
||||
transaction.grainTransaction.bushelsPerTonne > 1
|
||||
) {
|
||||
value = value / transaction.grainTransaction.bushelsPerTonne;
|
||||
}
|
||||
if (
|
||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON &&
|
||||
user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON &&
|
||||
transaction.grainTransaction.bushelsPerTonne > 1
|
||||
) {
|
||||
value = value / (transaction.grainTransaction.bushelsPerTonne * 0.907);
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ export default function ContractTransactionTable(props: Props) {
|
|||
<DialogTitle>Select Files to Upload</DialogTitle>
|
||||
<DialogContent>
|
||||
<FileUploader
|
||||
hasFilePermission={permissions.includes(pond.Permission.PERMISSION_FILE_MANAGEMENT)}
|
||||
keys={[contract.key(), selectedTransaction.transaction.key]}
|
||||
types={["contract", "transaction"]}
|
||||
toAttach={{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Box, Card, Typography, useTheme } from "@mui/material";
|
||||
import GrainDescriber from "grain/GrainDescriber";
|
||||
import { Contract } from "models/Contract";
|
||||
import { useGlobalState } from "providers";
|
||||
import { Label, Pie, PieChart, ResponsiveContainer, Text } from "recharts";
|
||||
|
||||
interface Props {
|
||||
|
|
@ -9,6 +10,7 @@ interface Props {
|
|||
|
||||
export default function ContractVisualizer(props: Props) {
|
||||
const { contract } = props;
|
||||
const [{ user }] = useGlobalState();
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
|
|
@ -18,8 +20,8 @@ export default function ContractVisualizer(props: Props) {
|
|||
{GrainDescriber(contract.grain()).name}
|
||||
</Typography>
|
||||
<Typography style={{ fontWeight: 650, fontSize: 15 }}>
|
||||
{contract.deliveredInPreferredUnit().toFixed(2)}/
|
||||
{contract.sizeInPreferredUnit().toFixed(2)} {contract.unit}
|
||||
{contract.deliveredInPreferredUnit(user).toFixed(2)}/
|
||||
{contract.sizeInPreferredUnit(user).toFixed(2)} {contract.unit}
|
||||
</Typography>
|
||||
</Box>
|
||||
<ResponsiveContainer height={"85%"}>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import { describeMeasurement } from "pbHelpers/MeasurementDescriber";
|
|||
import { pond, quack } from "protobuf-ts/pond";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import CableTopNodeSummary from "bin/CableTopNodeSummary";
|
||||
import { getTemperatureUnit } from "utils";
|
||||
import { DevicePreset } from "models/DevicePreset";
|
||||
import { Ambient } from "models/Ambient";
|
||||
import { useGlobalState } from "providers";
|
||||
|
|
@ -182,7 +181,7 @@ export default function DevicePresets(props: DevicePresetsProps) {
|
|||
const [heaters, setHeaters] = useState<Controller[]>([]);
|
||||
const [fans, setFans] = useState<Component[]>([]);
|
||||
//const [subscribeBinToAutoTopNode, setSubscribeBinToAutoTopNode] = useState(false);
|
||||
const [{as}] = useGlobalState();
|
||||
const [{as, user}] = useGlobalState();
|
||||
|
||||
useEffect(() => {
|
||||
if (deviceComponents.get(deviceIndex.toString())) return;
|
||||
|
|
@ -445,7 +444,7 @@ export default function DevicePresets(props: DevicePresetsProps) {
|
|||
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
|
||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
tempPreset = Math.round((tempPreset * (9 / 5) + 32) * 100) / 100;
|
||||
}
|
||||
let tempVal = describeMeasurement(
|
||||
|
|
@ -541,7 +540,7 @@ 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
|
||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
temp = Math.round((temp * (9 / 5) + 32) * 100) / 100;
|
||||
}
|
||||
let tempVal = describeMeasurement(
|
||||
|
|
|
|||
|
|
@ -18,10 +18,9 @@ import { cloneDeep } from "lodash";
|
|||
import { DevicePreset } from "models/DevicePreset";
|
||||
import { ObjectTypeString } from "objects/ObjectDescriber";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useSnackbar } from "providers";
|
||||
import { useGlobalState, useSnackbar } from "providers";
|
||||
import { useDevicePresetAPI } from "providers/pond/devicePresetAPI";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { getTemperatureUnit } from "utils";
|
||||
|
||||
interface Props {
|
||||
preset: DevicePreset;
|
||||
|
|
@ -54,6 +53,7 @@ export default function DevicePresetCard(props: Props) {
|
|||
const [humString, setHumString] = useState("0");
|
||||
const [hum, setHum] = useState(0);
|
||||
const isMobile = useMobile();
|
||||
const [{user}] = useGlobalState();
|
||||
|
||||
useEffect(() => {
|
||||
setPresetName(preset.name);
|
||||
|
|
@ -63,11 +63,11 @@ export default function DevicePresetCard(props: Props) {
|
|||
setHum(preset.settings.humidity);
|
||||
setHumString(preset.settings.humidity.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();
|
||||
}
|
||||
setTempString(displayTemp);
|
||||
}, [preset]);
|
||||
}, [preset, user]);
|
||||
|
||||
const saveNewPreset = () => {
|
||||
let typestring;
|
||||
|
|
@ -296,7 +296,7 @@ export default function DevicePresetCard(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
? "°F"
|
||||
: "°C"}
|
||||
</InputAdornment>
|
||||
|
|
@ -307,7 +307,7 @@ export default function DevicePresetCard(props: Props) {
|
|||
onChange={e => {
|
||||
if (!isNaN(+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;
|
||||
}
|
||||
setTempC(temp);
|
||||
|
|
@ -324,7 +324,7 @@ export default function DevicePresetCard(props: Props) {
|
|||
max={40}
|
||||
valueLabelDisplay="auto"
|
||||
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.toFixed() + "°C";
|
||||
|
|
@ -350,7 +350,7 @@ export default function DevicePresetCard(props: Props) {
|
|||
max={40}
|
||||
valueLabelDisplay="auto"
|
||||
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.toFixed() + "°C";
|
||||
|
|
@ -371,7 +371,7 @@ export default function DevicePresetCard(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
? "°F"
|
||||
: "°C"}
|
||||
</InputAdornment>
|
||||
|
|
@ -382,7 +382,7 @@ export default function DevicePresetCard(props: Props) {
|
|||
onChange={e => {
|
||||
if (!isNaN(+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;
|
||||
}
|
||||
setTempC(temp);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import { pond } from "protobuf-ts/pond"
|
|||
import { quack } from "protobuf-ts/quack"
|
||||
import { useGlobalState } from "providers"
|
||||
import { useEffect, useState } from "react"
|
||||
import { getTemperatureUnit } from "utils"
|
||||
|
||||
|
||||
interface Props {
|
||||
|
|
@ -104,28 +103,25 @@ export default function GateDeltaTempGraph(props: Props){
|
|||
*/
|
||||
useEffect(()=>{
|
||||
//get the measurements for the temp component
|
||||
componentAPI.listUnitMeasurements(
|
||||
componentAPI.sampleUnitMeasurements(
|
||||
deviceID,
|
||||
tempComponent.key(),
|
||||
start.toISOString(),
|
||||
end.toISOString(),
|
||||
300,
|
||||
0,
|
||||
"timestamp",
|
||||
500
|
||||
).then(resp => {
|
||||
console.log(resp)
|
||||
if(resp.data.measurements){
|
||||
let tempCompMeasurements = resp.data.measurements.map(um => UnitMeasurement.any(um, user));
|
||||
//if there is an ambient component, then treat the temp component like a single sensor and not a chain, and use the ambient measurements as the inlet
|
||||
if(ambient){
|
||||
//need to then load the measurements for the ambient component
|
||||
componentAPI.listUnitMeasurements(
|
||||
componentAPI.sampleUnitMeasurements(
|
||||
deviceID,
|
||||
ambient.key(),
|
||||
start.toISOString(),
|
||||
end.toISOString(),
|
||||
300,
|
||||
0,
|
||||
"timestamp",
|
||||
500
|
||||
).then(resp => {
|
||||
let ambientMeasurements = resp.data.measurements.map(um => UnitMeasurement.any(um, user));
|
||||
//now loop through each of them to 'combine' them into a single array
|
||||
|
|
@ -193,7 +189,7 @@ export default function GateDeltaTempGraph(props: Props){
|
|||
<span>
|
||||
{"Delta Temp: "}
|
||||
<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>
|
||||
<br />
|
||||
</span>
|
||||
|
|
@ -216,8 +212,8 @@ export default function GateDeltaTempGraph(props: Props){
|
|||
<SingleSetAreaChart
|
||||
data={data}
|
||||
tooltipLabel="Delta Temp"
|
||||
tooltipUnit={getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C"}
|
||||
yAxisLabel={"Delta T" + (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C")}
|
||||
tooltipUnit={user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C"}
|
||||
yAxisLabel={"Delta T" + (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? " °F" : " °C")}
|
||||
colourAboveZero={{colour: warmingColour, label: "Heating"}}
|
||||
colourBelowZero={{colour: coolingColour, label: "Cooling"}}/>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ import moment from "moment";
|
|||
import { pond, quack } from "protobuf-ts/pond";
|
||||
import { useGlobalState, useInteractionsAPI, useSnackbar } from "providers";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { getPressureUnit } from "utils";
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
close: (canceled: boolean) => void;
|
||||
|
|
@ -185,9 +183,9 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
//need to make sure the redthreshold is in pascals
|
||||
let thresholdPascals = 0
|
||||
if(!isNaN(parseFloat(redThreshold))){
|
||||
if(getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_KILOPASCALS){
|
||||
if(user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_KILOPASCALS){
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -345,8 +343,8 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
when the difference between the pressures falls within this range and vice versa:
|
||||
</Typography>
|
||||
<br />
|
||||
<Typography>Upper Limit: {getPressureUnit() === 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>Upper Limit: {user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? (highDelta/249.089).toFixed(2) + " iwg" : highDelta/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 />
|
||||
|
||||
<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>
|
||||
|
|
@ -371,7 +369,7 @@ export default function GateDeviceInteraction(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<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>
|
||||
)
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import moment from "moment";
|
|||
import { pond } from "protobuf-ts/pond";
|
||||
import { UnitMeasurement } from "models/UnitMeasurement";
|
||||
import { quack } from "protobuf-ts/quack";
|
||||
import { getTemperatureUnit } from "utils";
|
||||
import { teal } from "@mui/material/colors";
|
||||
import { react } from "@babel/types";
|
||||
import { getDeviceStateHelper } from "pbHelpers/DeviceState";
|
||||
|
|
@ -229,7 +228,7 @@ export default function GateList(props: Props) {
|
|||
})
|
||||
if(ambientTemp && outletTemp){
|
||||
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{
|
||||
display = "Sensor Missing"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import {MenuItem, TextField } from "@mui/material"
|
|||
import { cloneDeep } from "lodash"
|
||||
import { pond } from "protobuf-ts/pond"
|
||||
import React, { useEffect, useRef, useState } from "react"
|
||||
import { getGrainUnit } from "utils"
|
||||
|
||||
import { useGlobalState } from "providers";
|
||||
interface Props {
|
||||
grainSettings?: pond.GrainSettings
|
||||
onGrainSettingsChange: (settings: pond.GrainSettings, formValid: boolean) => void
|
||||
|
|
@ -11,6 +10,7 @@ interface Props {
|
|||
|
||||
export default function CustomGrainForm(props: Props) {
|
||||
const {grainSettings, onGrainSettingsChange} = props
|
||||
const [{ user }] = useGlobalState();
|
||||
const [newGrainSettings, setNewGrainSettings] = useState(pond.GrainSettings.create())
|
||||
const [name, setName] = 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)
|
||||
let settings = cloneDeep(newGrainSettings)
|
||||
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
|
||||
}else{
|
||||
settings.bushelsPerTonne = parseFloat(val)
|
||||
|
|
@ -212,7 +212,7 @@ export default function CustomGrainForm(props: Props) {
|
|||
}
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import {
|
|||
useTransactionAPI
|
||||
} from "providers";
|
||||
import { useState, useEffect } from "react";
|
||||
import { getGrainUnit } from "utils";
|
||||
|
||||
interface Props {
|
||||
mainObject: Bin | GrainBag | Field | Contract;
|
||||
|
|
@ -451,7 +450,7 @@ export default function GrainTransaction(props: Props) {
|
|||
};
|
||||
|
||||
const grainUnitDisplay = () => {
|
||||
switch (getGrainUnit()){
|
||||
switch (user.grainUnit()){
|
||||
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
||||
return "mT"
|
||||
case pond.GrainUnit.GRAIN_UNIT_TON:
|
||||
|
|
@ -525,7 +524,7 @@ export default function GrainTransaction(props: Props) {
|
|||
onChange={e => {
|
||||
//if the user is viewing the grain in weight
|
||||
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)
|
||||
//use source of the conversion value if it was selected, otherwise use the destination
|
||||
if (!isNaN(parseFloat(e.target.value))) {
|
||||
|
|
@ -535,7 +534,7 @@ export default function GrainTransaction(props: Props) {
|
|||
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 (selectedSource) {
|
||||
if(selectedSource.value.bushelsPerTonne){
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import moment, { Moment } from "moment";
|
|||
import { pond } from "protobuf-ts/pond";
|
||||
import { useGlobalState, useGrainBagAPI, useSnackbar } from "providers";
|
||||
import { useEffect, useState } from "react";
|
||||
import { getGrainUnit } from "utils";
|
||||
|
||||
interface Props {
|
||||
grainBag: GrainBag;
|
||||
|
|
@ -21,7 +20,7 @@ export default function GrainBagInventoryGraph(props: Props) {
|
|||
const [data, setData] = useState<BarData[]>([]);
|
||||
const [loadingData, setLoadingData] = useState<boolean>(false);
|
||||
const { openSnack } = useSnackbar();
|
||||
const [{as}] = useGlobalState();
|
||||
const [{as, user}] = useGlobalState();
|
||||
|
||||
useEffect(() => {
|
||||
if (grainBag.key() && !loadingData) {
|
||||
|
|
@ -36,12 +35,12 @@ export default function GrainBagInventoryGraph(props: Props) {
|
|||
//let time = hist.timestamp;
|
||||
let val = hist.object.grainBagSettings.currentBushels ?? 0;
|
||||
if (
|
||||
getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
||||
user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE &&
|
||||
grainBag.bushelsPerTonne() > 1
|
||||
) {
|
||||
val = Math.round((val / grainBag.bushelsPerTonne()) * 100) / 100;
|
||||
}
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1){
|
||||
val = Math.round((val / (grainBag.bushelsPerTonne() * 0.907)) * 100) / 100;
|
||||
}
|
||||
if (val !== lastBushels) {
|
||||
|
|
@ -55,10 +54,10 @@ export default function GrainBagInventoryGraph(props: Props) {
|
|||
});
|
||||
if (barData.length === 0) {
|
||||
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()
|
||||
}
|
||||
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)
|
||||
}
|
||||
barData.push({
|
||||
|
|
@ -79,10 +78,10 @@ export default function GrainBagInventoryGraph(props: Props) {
|
|||
|
||||
const maxYAxis = () => {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
return val
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import { pond } from "protobuf-ts/pond";
|
|||
import { useGlobalState, useGrainBagAPI, useSnackbar } from "providers";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { getGrainUnit } from "utils";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
return ({
|
||||
|
|
@ -84,9 +83,9 @@ export default function GrainBagSettings(props: Props) {
|
|||
: grainBag.settings.length
|
||||
);
|
||||
let grainVal = grainBag.bushels();
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE) {
|
||||
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE) {
|
||||
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)
|
||||
}
|
||||
setGrainFill(grainVal.toFixed(2));
|
||||
|
|
@ -120,7 +119,7 @@ export default function GrainBagSettings(props: Props) {
|
|||
const submit = () => {
|
||||
//if a bag was passed in do an update
|
||||
let tonneConversion = bushelConversion
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||
tonneConversion = bushelConversion / 0.907
|
||||
}
|
||||
if (grainBag) {
|
||||
|
|
@ -255,9 +254,9 @@ export default function GrainBagSettings(props: Props) {
|
|||
|
||||
const grainUnitDisplay = () => {
|
||||
if(bushelConversion > 1){
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
return "mT"
|
||||
}else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||
}else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON){
|
||||
return "t"
|
||||
}
|
||||
}else{
|
||||
|
|
@ -422,7 +421,7 @@ export default function GrainBagSettings(props: Props) {
|
|||
value={grainFill}
|
||||
onChange={e => {
|
||||
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
|
||||
// since these are both user entered fields and should be the same unit (ton or tonne)
|
||||
bushelVal = +e.target.value * (bushelConversion > 0 ? bushelConversion : 1);
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ import moment from "moment";
|
|||
import { pond } from "protobuf-ts/pond";
|
||||
import { useEffect, useState } from "react";
|
||||
import { getThemeType } from "theme";
|
||||
import { getGrainUnit } from "utils";
|
||||
import GrainBagSVG from "./grainBagSVG";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { useGlobalState } from "providers";
|
||||
|
||||
interface Props {
|
||||
grainBag: GrainBag;
|
||||
|
|
@ -68,6 +68,7 @@ export default function GrainBagVisualizer(props: Props) {
|
|||
const [grainDiff, setGrainDiff] = useState<number | undefined>();
|
||||
const theme = useTheme();
|
||||
const [openTransaction, setOpenTransaction] = useState(false);
|
||||
const [{ user }] = useGlobalState();
|
||||
|
||||
useEffect(() => {
|
||||
setFillLevel((grainBag.bushels() / grainBag.capacity()) * 100);
|
||||
|
|
@ -83,13 +84,13 @@ export default function GrainBagVisualizer(props: Props) {
|
|||
const grainOverlay = () => {
|
||||
let displayPending = pendingGrainAmount;
|
||||
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) {
|
||||
displayPending = Math.round((displayPending / grainBag.bushelsPerTonne()) * 100) / 100;
|
||||
displayDiff = Math.round((displayDiff / grainBag.bushelsPerTonne()) * 100) / 100;
|
||||
}
|
||||
}
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1) {
|
||||
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1) {
|
||||
if (displayPending && displayDiff) {
|
||||
displayPending = Math.round((displayPending / (grainBag.bushelsPerTonne() * 0.907)) * 100) / 100;
|
||||
displayDiff = Math.round((displayDiff / (grainBag.bushelsPerTonne()* 0.907)) * 100) / 100;
|
||||
|
|
@ -148,7 +149,7 @@ export default function GrainBagVisualizer(props: Props) {
|
|||
};
|
||||
|
||||
const grainAmountDisplay = () => {
|
||||
if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1) {
|
||||
if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && grainBag.bushelsPerTonne() > 1) {
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<Typography variant="body2" style={{ fontWeight: "bold", marginRight: "4px" }}>
|
||||
|
|
@ -157,7 +158,7 @@ export default function GrainBagVisualizer(props: Props) {
|
|||
<Typography variant="body2">({grainBag.fillPercent()}%)</Typography>
|
||||
</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 (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<Typography variant="body2" style={{ fontWeight: "bold", marginRight: "4px" }}>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,9 @@
|
|||
import { pond } from "protobuf-ts/pond";
|
||||
import { useEffect, useRef, useCallback, useMemo } from "react";
|
||||
import { useEffect, useRef, useMemo } from "react";
|
||||
import { getWsBaseUrl } from "utils/getWsBaseUrl";
|
||||
|
||||
/**
|
||||
* Derives the WebSocket base URL from VITE_APP_API_URL.
|
||||
* Matches the logic in useWebSocket.ts.
|
||||
*/
|
||||
function getWsBaseUrl(): string {
|
||||
const apiUrl = import.meta.env.VITE_APP_API_URL;
|
||||
if (apiUrl) {
|
||||
return apiUrl.replace(/^http/, "ws");
|
||||
}
|
||||
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||
return `${protocol}//${window.location.host}`;
|
||||
}
|
||||
/** Off by default to reduce server load; set VITE_ENABLE_WEBSOCKETS=true to enable live streams. */
|
||||
const WEBSOCKETS_ENABLED = import.meta.env.VITE_ENABLE_WEBSOCKETS === "true";
|
||||
|
||||
export interface UseDeviceStatusStreamsOptions {
|
||||
/** Device IDs to stream status for (e.g. from the visible devices list) */
|
||||
|
|
@ -21,6 +12,12 @@ export interface UseDeviceStatusStreamsOptions {
|
|||
onStatusUpdate: (deviceId: string, status: pond.DeviceStatus) => void;
|
||||
/** Auth token passed as ?token= query param */
|
||||
token?: string;
|
||||
/** Same as REST/listDevices (?keys=) — required when listing under a context path or group tab */
|
||||
keys?: string[];
|
||||
/** Same as REST (?types=) */
|
||||
types?: string[];
|
||||
/** View-as / impersonation (?as=), same as device list when not already team-first in URL */
|
||||
as?: string;
|
||||
/** Whether the connections should be active. Default true. */
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
|
@ -31,7 +28,7 @@ export interface UseDeviceStatusStreamsOptions {
|
|||
* Readings (plenum, sen5x, co, co2, no2, o2, etc.) stream in real time.
|
||||
*/
|
||||
export function useDeviceStatusStreams(options: UseDeviceStatusStreamsOptions) {
|
||||
const { deviceIds, onStatusUpdate, token, enabled = true } = options;
|
||||
const { deviceIds, onStatusUpdate, token, keys, types, as, enabled = true } = options;
|
||||
|
||||
const onStatusUpdateRef = useRef(onStatusUpdate);
|
||||
onStatusUpdateRef.current = onStatusUpdate;
|
||||
|
|
@ -39,25 +36,67 @@ export function useDeviceStatusStreams(options: UseDeviceStatusStreamsOptions) {
|
|||
const wsMapRef = useRef<Map<string, WebSocket>>(new Map());
|
||||
const retriesRef = useRef<Map<string, number>>(new Map());
|
||||
const reconnectTimeoutsRef = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());
|
||||
/** Bumps only in effect cleanup so late onclose / reconnect timers never run after unmount. */
|
||||
const generationRef = useRef(0);
|
||||
/** Latest ID set so a device dropped from the list does not reconnect on abnormal close. */
|
||||
const allowedIdsRef = useRef<Set<string>>(new Set());
|
||||
allowedIdsRef.current = new Set(deviceIds);
|
||||
|
||||
const connect = useCallback(
|
||||
(deviceId: string) => {
|
||||
// Normalize for stable comparison: same set of IDs = same string regardless of order
|
||||
const deviceIdsKey = useMemo(
|
||||
() => [...new Set(deviceIds)].sort().join(","),
|
||||
[deviceIds.join(",")]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const clearReconnect = (deviceId: string) => {
|
||||
const t = reconnectTimeoutsRef.current.get(deviceId);
|
||||
if (t) {
|
||||
clearTimeout(t);
|
||||
reconnectTimeoutsRef.current.delete(deviceId);
|
||||
}
|
||||
};
|
||||
|
||||
const shutdownAll = () => {
|
||||
reconnectTimeoutsRef.current.forEach((t) => clearTimeout(t));
|
||||
reconnectTimeoutsRef.current.clear();
|
||||
wsMapRef.current.forEach((ws) => ws.close(1000, "cleanup"));
|
||||
wsMapRef.current.clear();
|
||||
retriesRef.current.clear();
|
||||
};
|
||||
|
||||
if (!WEBSOCKETS_ENABLED || !enabled || !token || deviceIds.length === 0) {
|
||||
shutdownAll();
|
||||
return () => {
|
||||
generationRef.current += 1;
|
||||
};
|
||||
}
|
||||
|
||||
const gen = generationRef.current;
|
||||
|
||||
const connect = (deviceId: string) => {
|
||||
if (!token || !deviceId) return;
|
||||
if (gen !== generationRef.current) return;
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.set("token", token);
|
||||
if (keys?.length) params.set("keys", keys.toString());
|
||||
if (types?.length) params.set("types", types.toString());
|
||||
if (as) params.set("as", as);
|
||||
|
||||
const path = `/live/devices/${deviceId}/status`;
|
||||
const path = `/v1/live/devices/${deviceId}/status`;
|
||||
const url = `${getWsBaseUrl()}${path}?${params.toString()}`;
|
||||
const ws = new WebSocket(url);
|
||||
wsMapRef.current.set(deviceId, ws);
|
||||
|
||||
ws.onopen = () => {
|
||||
if (gen !== generationRef.current) return;
|
||||
console.debug(`[ws] connected: ${path}`);
|
||||
retriesRef.current.set(deviceId, 0);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
if (gen !== generationRef.current) return;
|
||||
try {
|
||||
const raw = JSON.parse(event.data);
|
||||
const status = pond.DeviceStatus.fromObject(raw ?? {});
|
||||
|
|
@ -74,7 +113,15 @@ export function useDeviceStatusStreams(options: UseDeviceStatusStreamsOptions) {
|
|||
ws.onclose = (event) => {
|
||||
wsMapRef.current.delete(deviceId);
|
||||
|
||||
// Don't reconnect on clean close or auth rejection
|
||||
if (gen !== generationRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!allowedIdsRef.current.has(deviceId)) {
|
||||
retriesRef.current.delete(deviceId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.code === 1000 || event.code === 4001 || event.code === 4003) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -84,55 +131,36 @@ export function useDeviceStatusStreams(options: UseDeviceStatusStreamsOptions) {
|
|||
retriesRef.current.set(deviceId, retries + 1);
|
||||
console.debug(`[ws] reconnecting ${path} in ${delay}ms...`);
|
||||
|
||||
const timeout = setTimeout(() => connect(deviceId), delay);
|
||||
const timeout = setTimeout(() => {
|
||||
if (gen !== generationRef.current) return;
|
||||
if (!allowedIdsRef.current.has(deviceId)) return;
|
||||
reconnectTimeoutsRef.current.delete(deviceId);
|
||||
connect(deviceId);
|
||||
}, delay);
|
||||
reconnectTimeoutsRef.current.set(deviceId, timeout);
|
||||
};
|
||||
},
|
||||
[token]
|
||||
);
|
||||
|
||||
// Normalize for stable comparison: same set of IDs = same string regardless of order
|
||||
const deviceIdsKey = useMemo(
|
||||
() => [...new Set(deviceIds)].sort().join(","),
|
||||
[deviceIds.join(",")]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!enabled || !token || deviceIds.length === 0) {
|
||||
wsMapRef.current.forEach((ws) => ws.close(1000, "disabled"));
|
||||
wsMapRef.current.clear();
|
||||
reconnectTimeoutsRef.current.forEach((t) => clearTimeout(t));
|
||||
reconnectTimeoutsRef.current.clear();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const currentIds = new Set(deviceIds);
|
||||
|
||||
// Connect to new devices
|
||||
deviceIds.forEach((id) => {
|
||||
if (!wsMapRef.current.has(id)) {
|
||||
connect(id);
|
||||
}
|
||||
});
|
||||
|
||||
// Disconnect from devices no longer in the list
|
||||
wsMapRef.current.forEach((ws, id) => {
|
||||
if (!currentIds.has(id)) {
|
||||
clearReconnect(id);
|
||||
ws.close(1000, "device removed");
|
||||
wsMapRef.current.delete(id);
|
||||
const t = reconnectTimeoutsRef.current.get(id);
|
||||
if (t) {
|
||||
clearTimeout(t);
|
||||
reconnectTimeoutsRef.current.delete(id);
|
||||
}
|
||||
retriesRef.current.delete(id);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
wsMapRef.current.forEach((ws) => ws.close(1000, "cleanup"));
|
||||
wsMapRef.current.clear();
|
||||
reconnectTimeoutsRef.current.forEach((t) => clearTimeout(t));
|
||||
reconnectTimeoutsRef.current.clear();
|
||||
generationRef.current += 1;
|
||||
shutdownAll();
|
||||
};
|
||||
}, [enabled, token, deviceIdsKey, deviceIds.length, connect]);
|
||||
}, [enabled, token, deviceIdsKey, deviceIds.length, keys?.join(), types?.join(), as]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,11 @@
|
|||
import { useEffect, useRef, useCallback } from "react";
|
||||
import { getWsBaseUrl } from "utils/getWsBaseUrl";
|
||||
|
||||
/**
|
||||
* Derives the WebSocket base URL from VITE_APP_API_URL.
|
||||
* e.g. "https://api.brandxtech.ca" -> "wss://api.brandxtech.ca"
|
||||
* Falls back to current page host for local dev.
|
||||
*/
|
||||
function getWsBaseUrl(): string {
|
||||
const apiUrl = import.meta.env.VITE_APP_API_URL;
|
||||
if (apiUrl) {
|
||||
return apiUrl.replace(/^http/, "ws");
|
||||
}
|
||||
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||
return `${protocol}//${window.location.host}`;
|
||||
}
|
||||
/** Off by default to reduce server load; set VITE_ENABLE_WEBSOCKETS=true to enable live streams. */
|
||||
const WEBSOCKETS_ENABLED = import.meta.env.VITE_ENABLE_WEBSOCKETS === "true";
|
||||
|
||||
interface UseWebSocketOptions<T> {
|
||||
/** The API path, e.g. "/v1/live/devices/123/components" */
|
||||
/** The API path including /v1, e.g. "/v1/live/devices/123/components" */
|
||||
path: string;
|
||||
/** Transform the raw MessageEvent into your domain type */
|
||||
parse: (event: MessageEvent) => T;
|
||||
|
|
@ -25,6 +15,12 @@ interface UseWebSocketOptions<T> {
|
|||
token?: string;
|
||||
/** Minimum seconds between updates, passed as ?rate= to the backend */
|
||||
rate?: number;
|
||||
/** Context keys, same as REST device APIs (?keys=) */
|
||||
keys?: string[];
|
||||
/** Context types, same as REST device APIs (?types=) */
|
||||
types?: string[];
|
||||
/** Impersonation / team view key, same as REST (?as=) */
|
||||
as?: string;
|
||||
/** Whether the connection should be active. Default true. */
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
|
@ -41,7 +37,7 @@ interface UseWebSocketOptions<T> {
|
|||
* });
|
||||
*/
|
||||
export function useWebSocket<T>(options: UseWebSocketOptions<T>) {
|
||||
const { path, parse, onMessage, token, rate = 0, enabled = true } = options;
|
||||
const { path, parse, onMessage, token, rate = 0, keys, types, as, enabled = true } = options;
|
||||
|
||||
// Keep latest callbacks in refs so reconnects don't use stale closures
|
||||
const onMessageRef = useRef(onMessage);
|
||||
|
|
@ -52,13 +48,20 @@ export function useWebSocket<T>(options: UseWebSocketOptions<T>) {
|
|||
const wsRef = useRef<WebSocket | null>(null);
|
||||
const reconnectTimeoutRef = useRef<ReturnType<typeof setTimeout>>();
|
||||
const retriesRef = useRef(0);
|
||||
/** Bumps on each effect cleanup so late onclose / reconnect timers never run after unmount or dependency change. */
|
||||
const generationRef = useRef(0);
|
||||
|
||||
const connect = useCallback(() => {
|
||||
if (!token) return;
|
||||
|
||||
const gen = generationRef.current;
|
||||
|
||||
const params = new URLSearchParams();
|
||||
params.set("token", token);
|
||||
if (rate > 0) params.set("rate", rate.toString());
|
||||
if (keys?.length) params.set("keys", keys.toString());
|
||||
if (types?.length) params.set("types", types.toString());
|
||||
if (as) params.set("as", as);
|
||||
|
||||
const url = `${getWsBaseUrl()}${path}?${params.toString()}`;
|
||||
const ws = new WebSocket(url);
|
||||
|
|
@ -86,6 +89,10 @@ export function useWebSocket<T>(options: UseWebSocketOptions<T>) {
|
|||
console.debug(`[ws] closed: ${path} (code: ${event.code})`);
|
||||
wsRef.current = null;
|
||||
|
||||
if (gen !== generationRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't reconnect on clean close or auth rejection
|
||||
if (event.code === 1000 || event.code === 4001 || event.code === 4003) {
|
||||
return;
|
||||
|
|
@ -95,22 +102,33 @@ export function useWebSocket<T>(options: UseWebSocketOptions<T>) {
|
|||
const delay = Math.min(1000 * Math.pow(2, retriesRef.current), 30000);
|
||||
retriesRef.current += 1;
|
||||
console.debug(`[ws] reconnecting in ${delay}ms...`);
|
||||
reconnectTimeoutRef.current = setTimeout(connect, delay);
|
||||
reconnectTimeoutRef.current = setTimeout(() => {
|
||||
if (gen !== generationRef.current) return;
|
||||
connect();
|
||||
}, delay);
|
||||
};
|
||||
}, [path, token, rate]);
|
||||
}, [path, token, rate, keys?.join(), types?.join(), as]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!enabled || !token) {
|
||||
if (!WEBSOCKETS_ENABLED || !enabled || !token) {
|
||||
if (reconnectTimeoutRef.current) {
|
||||
clearTimeout(reconnectTimeoutRef.current);
|
||||
}
|
||||
if (wsRef.current) {
|
||||
wsRef.current.close(1000, "disabled");
|
||||
wsRef.current = null;
|
||||
}
|
||||
return;
|
||||
retriesRef.current = 0;
|
||||
return () => {
|
||||
generationRef.current += 1;
|
||||
};
|
||||
}
|
||||
|
||||
retriesRef.current = 0;
|
||||
connect();
|
||||
|
||||
return () => {
|
||||
generationRef.current += 1;
|
||||
if (reconnectTimeoutRef.current) {
|
||||
clearTimeout(reconnectTimeoutRef.current);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ import { FeatureCollection, Feature } from "geojson";
|
|||
import DrawController from "./mapControllers/drawController";
|
||||
//import { Geometry } from "geojson";
|
||||
import Map, { MapRef, Marker, MarkerDragEvent } from "react-map-gl/mapbox";
|
||||
import { getDistanceUnit } from "utils";
|
||||
import { MapMouseEvent } from "mapbox-gl";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { Result } from "@mapbox/mapbox-gl-geocoder";
|
||||
|
|
@ -499,7 +498,7 @@ export default function MapBase(props: Props) {
|
|||
lineWidth: 5,
|
||||
origin: pond.DataOrigin.DATA_ORIGIN_ADAPTIVE,
|
||||
totalDist:
|
||||
getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||
user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||
? (data.totalDistanceKm * 1000).toFixed(2)
|
||||
: (data.totalDistanceKm * 3280.8398950131).toFixed(2)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import GrainDescriber from "grain/GrainDescriber";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { MarkerData } from "maps/mapMarkers/Markers";
|
||||
import { User } from "models";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { getGrainUnit } from "utils";
|
||||
import { stringToMaterialColour } from "utils/strings";
|
||||
import { or } from "utils/types";
|
||||
|
||||
|
|
@ -236,11 +236,11 @@ export class Bin {
|
|||
return bpt;
|
||||
}
|
||||
|
||||
public grainInventory(): number {
|
||||
public grainInventory(user: User): number {
|
||||
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()
|
||||
}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)
|
||||
}
|
||||
return Math.round(grain*100)/100
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ import { Option } from "common/SearchSelect";
|
|||
import { GrainOptions, ToGrainOption } from "grain";
|
||||
import GrainDescriber from "grain/GrainDescriber";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { User } from "models";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { getGrainUnit, stringToMaterialColour } from "utils";
|
||||
import { stringToMaterialColour } from "utils";
|
||||
import { or } from "utils/types";
|
||||
|
||||
export class Contract {
|
||||
|
|
@ -14,27 +15,29 @@ export class Contract {
|
|||
public label: string = "";
|
||||
private objKey: string = "";
|
||||
|
||||
public static create(pb?: pond.Contract): Contract {
|
||||
public static create(pb?: pond.Contract, user?: User): Contract {
|
||||
let my = new Contract();
|
||||
if (pb) {
|
||||
my.settings = pond.ContractSettings.fromObject(cloneDeep(or(pb.settings, {})));
|
||||
my.title = pb.name;
|
||||
my.objKey = pb.key;
|
||||
my.unit = my.measurementUnit();
|
||||
my.unit = my.measurementUnit(user);
|
||||
my.colour = my.commodityColour();
|
||||
my.label = my.commodityLabel();
|
||||
}
|
||||
return my;
|
||||
}
|
||||
|
||||
private measurementUnit(): string {
|
||||
private measurementUnit(user?: User): string {
|
||||
if (this.settings.type === pond.ContractType.CONTRACT_TYPE_GRAIN) {
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1){
|
||||
if( user ){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1){
|
||||
return "mT"
|
||||
}
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.conversionValue() > 1){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.conversionValue() > 1){
|
||||
return "t"
|
||||
}
|
||||
}
|
||||
return "bu";
|
||||
}
|
||||
return "";
|
||||
|
|
@ -63,21 +66,22 @@ export class Contract {
|
|||
return label;
|
||||
}
|
||||
|
||||
public static clone(other?: Contract): Contract {
|
||||
public static clone(other?: Contract, user?: User): Contract {
|
||||
if (other) {
|
||||
return Contract.create(
|
||||
pond.Contract.fromObject({
|
||||
title: other.title,
|
||||
key: other.objKey,
|
||||
settings: cloneDeep(other.settings)
|
||||
})
|
||||
}),
|
||||
user
|
||||
);
|
||||
}
|
||||
return Contract.create();
|
||||
return Contract.create(undefined, user);
|
||||
}
|
||||
|
||||
public static any(data: any): Contract {
|
||||
return Contract.create(pond.Contract.fromObject(cloneDeep(data)));
|
||||
public static any(data: any, user?: User): Contract {
|
||||
return Contract.create(pond.Contract.fromObject(cloneDeep(data)), user);
|
||||
}
|
||||
|
||||
public key(): string {
|
||||
|
|
@ -204,28 +208,28 @@ export class Contract {
|
|||
return this.conversionValue();
|
||||
}
|
||||
|
||||
public sizeInPreferredUnit(): number {
|
||||
public sizeInPreferredUnit(user: User): number {
|
||||
let size = this.settings.size;
|
||||
switch (this.settings.type) {
|
||||
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();
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
return Math.round(size * 100) / 100;
|
||||
}
|
||||
|
||||
public deliveredInPreferredUnit(): number {
|
||||
public deliveredInPreferredUnit(user: User): number {
|
||||
let del = this.settings.delivered;
|
||||
switch (this.settings.type) {
|
||||
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();
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -237,14 +241,15 @@ export class Contract {
|
|||
public static toStoredUnit(
|
||||
secondaryUnitVal: number,
|
||||
contractType: pond.ContractType,
|
||||
conversionValue: number
|
||||
conversionValue: number,
|
||||
user: User
|
||||
): number {
|
||||
let storedUnitVal = secondaryUnitVal;
|
||||
switch (contractType) {
|
||||
//use the value and conversion they entered directly, it is safe to assume they are both the same unit (ton vs tonne) so dont need to convert anything
|
||||
//before converting to bushels
|
||||
case pond.ContractType.CONTRACT_TYPE_GRAIN:
|
||||
if ((getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,4 +101,20 @@ export class User {
|
|||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,11 @@ import { Column } from "common/ResponsiveTable";
|
|||
import { Option } from "common/SearchSelect";
|
||||
import GrainDescriber from "grain/GrainDescriber";
|
||||
//import { Column } from "material-table";
|
||||
import { Bin, BinYard, Field } from "models";
|
||||
import { Bin, BinYard, Field, User } from "models";
|
||||
//import { Gate } from "models/Gate";
|
||||
import { GrainBag } from "models/GrainBag";
|
||||
//import { ObjectHeater } from "models/ObjectHeater";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { getDistanceUnit, getTemperatureUnit } from "utils";
|
||||
|
||||
interface Sort {
|
||||
order: string; //what to send to the backend list to sort by
|
||||
numerical: boolean; //whether to use a numerical or text sort
|
||||
|
|
@ -20,6 +18,8 @@ export interface ObjectExtension {
|
|||
isTransactionObject: boolean;
|
||||
//this will define the columns to be used for the object in a material table
|
||||
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
|
||||
tableSort: Map<string, Sort>;
|
||||
}
|
||||
|
|
@ -32,25 +32,11 @@ const defaultObject: ObjectExtension = {
|
|||
tableSort: new Map()
|
||||
};
|
||||
|
||||
export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
|
||||
[pond.ObjectType.OBJECT_TYPE_UNKNOWN, defaultObject],
|
||||
[
|
||||
pond.ObjectType.OBJECT_TYPE_BACKPACK,
|
||||
{
|
||||
name: "Backpack",
|
||||
inventoryGroup: "",
|
||||
isTransactionObject: false,
|
||||
tableColumns: [],
|
||||
tableSort: new Map()
|
||||
}
|
||||
],
|
||||
[
|
||||
pond.ObjectType.OBJECT_TYPE_BIN,
|
||||
{
|
||||
name: "Bin",
|
||||
inventoryGroup: "grain",
|
||||
isTransactionObject: true,
|
||||
tableColumns: [
|
||||
const binColumns = (user?: User): Column<any>[] => {
|
||||
const temperatureUnit =
|
||||
user?.tempUnit() ?? pond.TemperatureUnit.TEMPERATURE_UNIT_CELSIUS;
|
||||
|
||||
return [
|
||||
{
|
||||
title: "Name",
|
||||
cellStyle: {padding: "16px"},
|
||||
|
|
@ -74,7 +60,10 @@ export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
|
|||
render: row => {
|
||||
let d = row.settings.specs?.heightCm;
|
||||
if (d) {
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
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";
|
||||
|
|
@ -88,7 +77,10 @@ export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
|
|||
render: row => {
|
||||
let d = row.settings.specs?.diameterCm;
|
||||
if (d) {
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
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";
|
||||
|
|
@ -130,11 +122,10 @@ export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
|
|||
render: row => {
|
||||
let t = row.settings.highTemp;
|
||||
if (t) {
|
||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
if (temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
return (t * 1.8 + 32).toFixed(2) + " °F";
|
||||
} else {
|
||||
return t.toFixed(2) + " °C";
|
||||
}
|
||||
return t.toFixed(2) + " °C";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -144,15 +135,119 @@ export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
|
|||
render: row => {
|
||||
let t = row.settings.lowTemp;
|
||||
if (t) {
|
||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
if (temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
return (t * 1.8 + 32).toFixed(2) + " °F";
|
||||
} else {
|
||||
}
|
||||
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>);
|
||||
}
|
||||
] as Column<Bin>[],
|
||||
}
|
||||
},
|
||||
{
|
||||
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([
|
||||
[pond.ObjectType.OBJECT_TYPE_UNKNOWN, defaultObject],
|
||||
[
|
||||
pond.ObjectType.OBJECT_TYPE_BACKPACK,
|
||||
{
|
||||
name: "Backpack",
|
||||
inventoryGroup: "",
|
||||
isTransactionObject: false,
|
||||
tableColumns: [],
|
||||
tableSort: new Map()
|
||||
}
|
||||
],
|
||||
[
|
||||
pond.ObjectType.OBJECT_TYPE_BIN,
|
||||
{
|
||||
name: "Bin",
|
||||
inventoryGroup: "grain",
|
||||
isTransactionObject: true,
|
||||
tableColumns: binColumns(),
|
||||
getTableColumns: (user?: User) => binColumns(user),
|
||||
tableSort: new Map([
|
||||
["Name", { order: "name", numerical: false }],
|
||||
["Grain", { order: "inventory.grainType", numerical: false }],
|
||||
|
|
@ -395,84 +490,8 @@ export const ObjectExtensions: Map<pond.ObjectType, ObjectExtension> = new Map([
|
|||
name: "Grainbag",
|
||||
inventoryGroup: "grain",
|
||||
isTransactionObject: true,
|
||||
tableColumns: [
|
||||
{
|
||||
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>[],
|
||||
tableColumns: grainBagColumns(),
|
||||
getTableColumns: (user?: User) => grainBagColumns(user),
|
||||
tableSort: new Map([
|
||||
["Name", { order: "name", numerical: false }],
|
||||
["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 {
|
||||
let describer = ObjectExtensions.get(type);
|
||||
return describer ? describer : defaultObject;
|
||||
return ObjectExtensions.get(type) ?? defaultObject;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -745,7 +763,8 @@ export function SearchableObjects(): Option[] {
|
|||
Object.values(pond.ObjectType).forEach(obj => {
|
||||
if (typeof obj !== "string") {
|
||||
let ext = ObjectDescriber(obj);
|
||||
if (ext.tableColumns.length > 0) {
|
||||
const columns = ext.getTableColumns ? ext.getTableColumns() : ext.tableColumns;
|
||||
if (columns.length > 0) {
|
||||
options.push({
|
||||
label: ext.name,
|
||||
value: obj
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { Box, Button, Grid2 as Grid } from "@mui/material";
|
||||
// import { getTableIcons } from "common/ResponsiveTable";
|
||||
import SearchBar from "common/SearchBar";
|
||||
import SearchSelect, { Option } from "common/SearchSelect";
|
||||
// import MaterialTable, { MTableToolbar } from "material-table";
|
||||
// import { Bin, BinYard, Field } from "models";
|
||||
|
|
@ -22,9 +21,8 @@ import {
|
|||
import { useCallback, useEffect, useState } from "react";
|
||||
import TeamSearch from "teams/TeamSearch";
|
||||
import BulkBinSettings from "./bulkEditForms/bulkBinSettings";
|
||||
import BulkGrainBagSettings from "./bulkEditForms/bulkGrainBagSettings";
|
||||
import ResponsiveTable from "common/ResponsiveTable";
|
||||
import { cloneDeep, indexOf } from "lodash";
|
||||
import { cloneDeep } from "lodash";
|
||||
//import BulkGateSettings from "./bulkEditForms/bulkGateSettings";
|
||||
|
||||
interface customButton {
|
||||
|
|
@ -61,6 +59,9 @@ export default function ObjectTable(props: Props) {
|
|||
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 [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
|
||||
const binAPI = useBinAPI();
|
||||
const binyardAPI = useBinYardAPI();
|
||||
|
|
@ -366,7 +367,7 @@ export default function ObjectTable(props: Props) {
|
|||
|
||||
<ResponsiveTable
|
||||
rows={tableData}
|
||||
columns={ObjectDescriber(currentType).tableColumns}
|
||||
columns={columns}
|
||||
onRowClick={rowClickFunction}
|
||||
total={objectTotal}
|
||||
pageSize={pageSize}
|
||||
|
|
@ -383,7 +384,7 @@ export default function ObjectTable(props: Props) {
|
|||
key="objectList"
|
||||
title={ObjectDescriber(currentType).name}
|
||||
icons={getTableIcons()}
|
||||
columns={ObjectDescriber(currentType).tableColumns}
|
||||
columns={ObjectDescriber(currentType, user).tableColumns}
|
||||
data={tableData}
|
||||
page={tablePage}
|
||||
totalCount={objectTotal}
|
||||
|
|
@ -399,10 +400,10 @@ export default function ObjectTable(props: Props) {
|
|||
}}
|
||||
onOrderChange={(by, direction) => {
|
||||
if (by !== -1) {
|
||||
let colName = ObjectDescriber(currentType).tableColumns[by].title?.toString();
|
||||
let colName = ObjectDescriber(currentType, user).tableColumns[by].title?.toString();
|
||||
let order;
|
||||
if (colName) {
|
||||
order = ObjectDescriber(currentType).tableSort.get(colName);
|
||||
order = ObjectDescriber(currentType, user).tableSort.get(colName);
|
||||
setCurrentOrder(order?.order);
|
||||
setCurrentDirection(direction);
|
||||
setIsNumerical(order?.numerical);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { GrainOptions } from "grain";
|
|||
import { pond } from "protobuf-ts/pond";
|
||||
import { useBinAPI, useGlobalState, useSnackbar } from "providers";
|
||||
import React, { useState } from "react";
|
||||
import { fahrenheitToCelsius, getDistanceUnit, getTemperatureUnit } from "utils";
|
||||
import { fahrenheitToCelsius } from "utils";
|
||||
|
||||
interface Props {
|
||||
selectedBins: pond.Bin[];
|
||||
|
|
@ -19,7 +19,7 @@ export default function BulkBinSettings(props: Props) {
|
|||
const gridItemWidth = 3;
|
||||
// bin settings variables
|
||||
const [name, setName] = useState<string | undefined>();
|
||||
const [{as}] = useGlobalState();
|
||||
const [{as, user}] = useGlobalState();
|
||||
const [grainType, setGrainType] = useState<pond.Grain | undefined>();
|
||||
const [grainOption, setGrainOption] = useState<Option | null>();
|
||||
const [height, setHeight] = useState<number | undefined>();
|
||||
|
|
@ -32,10 +32,10 @@ export default function BulkBinSettings(props: Props) {
|
|||
const [lowTemp, setLowTemp] = useState<number | undefined>();
|
||||
|
||||
const convertedDistance = (enteredDistance: number) => {
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
return enteredDistance * 100;
|
||||
}
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
if (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
return enteredDistance * 30.48;
|
||||
}
|
||||
return enteredDistance;
|
||||
|
|
@ -43,7 +43,7 @@ export default function BulkBinSettings(props: Props) {
|
|||
|
||||
const convertedTemp = (enteredTemp: number) => {
|
||||
let t = enteredTemp;
|
||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
t = fahrenheitToCelsius(enteredTemp);
|
||||
}
|
||||
return t;
|
||||
|
|
@ -168,7 +168,7 @@ export default function BulkBinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
|
|
@ -186,7 +186,7 @@ export default function BulkBinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||
{user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"}
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
|
|
@ -204,7 +204,7 @@ export default function BulkBinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
? "°F"
|
||||
: "°C"}
|
||||
</InputAdornment>
|
||||
|
|
@ -224,7 +224,7 @@ export default function BulkBinSettings(props: Props) {
|
|||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position="end">
|
||||
{getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
{user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
? "°F"
|
||||
: "°C"}
|
||||
</InputAdornment>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { GrainBag } from "models/GrainBag";
|
|||
import { pond } from "protobuf-ts/pond";
|
||||
import { useGlobalState, useGrainBagAPI, useSnackbar } from "providers";
|
||||
import React, { useState } from "react";
|
||||
import { getDistanceUnit } from "utils";
|
||||
|
||||
interface Props {
|
||||
selectedBags: GrainBag[];
|
||||
|
|
@ -28,10 +27,10 @@ export default function BulkGrainBagSettings(props: Props) {
|
|||
const [bushels, setBushels] = useState<number | undefined>();
|
||||
const [fillDate, setFillDate] = useState<string | undefined>();
|
||||
const [initialMoisture, setInitialMoisture] = useState<number | undefined>();
|
||||
const [{as}] = useGlobalState();
|
||||
const [{ as, user }] = useGlobalState();
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ import {
|
|||
} from "providers";
|
||||
import React, { SetStateAction, useCallback, useEffect, useState } from "react";
|
||||
// import { getThemeType } from "theme";
|
||||
import { getGrainUnit, stringToMaterialColour } from "utils";
|
||||
import { stringToMaterialColour } from "utils";
|
||||
//import InfiniteScroll from "react-infinite-scroller";
|
||||
import PageContainer from "./PageContainer";
|
||||
import ObjectTable from "objects/ObjectTable";
|
||||
|
|
@ -934,7 +934,7 @@ export default function Bins(props: Props) {
|
|||
return " bu";
|
||||
}
|
||||
|
||||
switch (getGrainUnit()) {
|
||||
switch (user.grainUnit()) {
|
||||
case pond.GrainUnit.GRAIN_UNIT_TONNE:
|
||||
return " mT";
|
||||
case pond.GrainUnit.GRAIN_UNIT_TON:
|
||||
|
|
@ -947,9 +947,9 @@ export default function Bins(props: Props) {
|
|||
const customQuantityDisplay = (customInventory: pond.CustomInventory, bushels: number) => {
|
||||
let amount = bushels
|
||||
if(customInventory.bushelsPerTonne > 1){
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -959,9 +959,9 @@ export default function Bins(props: Props) {
|
|||
const supportedGrainDisplay = (grain: pond.Grain, bushels: number) => {
|
||||
const describer = GrainDescriber(grain)
|
||||
let amount = bushels
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE){
|
||||
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
|
||||
}
|
||||
return Math.round(amount*100)/100
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import PageContainer from "./PageContainer";
|
|||
|
||||
export default function Contracts() {
|
||||
const [openSettings, setOpenSettings] = useState(false);
|
||||
const [{ as }] = useGlobalState()
|
||||
const [{ as, user }] = useGlobalState()
|
||||
const contractAPI = useContractAPI();
|
||||
const [contracts, setContracts] = useState<Contract[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
|
@ -42,7 +42,7 @@ export default function Contracts() {
|
|||
let contractPermissions: Map<string, pond.Permission[]> = new Map();
|
||||
if (resp.data.contracts){
|
||||
resp.data.contracts.forEach(contract => {
|
||||
let c = Contract.create(contract);
|
||||
let c = Contract.create(contract, user);
|
||||
contracts.push(c);
|
||||
let p = pond.EvaluatePermissionsResponse.fromObject(
|
||||
resp.data.contractPermissions[c.key()]
|
||||
|
|
@ -56,7 +56,7 @@ export default function Contracts() {
|
|||
})
|
||||
.catch(err => {});
|
||||
}
|
||||
}, [contractAPI, year, as]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
}, [contractAPI, year, as, user]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ import Grid from '@mui/material/Grid2';
|
|||
import { Component, Device, Interaction, User } from "models";
|
||||
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
||||
import { useDeviceAPI, useGlobalState, useSnackbar } from "providers";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useDeviceStatusStreams } from "hooks/useDeviceStatusStreams";
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useLocation, useParams } from "react-router-dom";
|
||||
import PageContainer from "./PageContainer";
|
||||
import { useHTTP, useMobile } from "hooks";
|
||||
|
|
@ -23,6 +24,25 @@ import DeviceWizard from "device/DeviceWizard";
|
|||
import DeviceScannedComponents from "device/autoDetect/DeviceScannedComponents";
|
||||
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 {
|
||||
device: Device;
|
||||
components: Component[];
|
||||
|
|
@ -38,7 +58,7 @@ export default function DevicePage() {
|
|||
const isMobile = useMobile()
|
||||
const deviceID = useParams<{ deviceID: string }>()?.deviceID ?? "";
|
||||
const groupID = useParams<{ groupID: string }>()?.groupID ?? "";
|
||||
const { state } = useLocation();
|
||||
const { state, pathname: locationPathname } = useLocation();
|
||||
const [{ as, team, user }] = useGlobalState()
|
||||
// console.log(state)
|
||||
const [device, setDevice] = useState<Device>(state?.device ? Device.create(state.device) : Device.create())
|
||||
|
|
@ -68,6 +88,63 @@ export default function DevicePage() {
|
|||
|
||||
const { token } = useHTTP();
|
||||
|
||||
const liveContextKeys = useMemo(() => getContextKeys(), [locationPathname]);
|
||||
const liveContextTypes = useMemo(() => getContextTypes(), [locationPathname]);
|
||||
/** Matches getDevicePageData: omit ?as= when first context type is "team". */
|
||||
const liveAs =
|
||||
as && !(liveContextTypes.length > 0 && liveContextTypes[0] === "team")
|
||||
? as
|
||||
: 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 = () => {
|
||||
if (loading) return
|
||||
if (state?.devicePageData) {
|
||||
|
|
@ -173,7 +250,7 @@ export default function DevicePage() {
|
|||
// When the backend receives a new reading and updates a component,
|
||||
// this fires and updates the component in state without a page refresh.
|
||||
useWebSocket<{ key: string; component: Component } | null>({
|
||||
path: `/live/devices/${deviceID}/components`,
|
||||
path: `/v1/live/devices/${deviceID}/components`,
|
||||
parse: (e) => {
|
||||
try {
|
||||
const raw = JSON.parse(e.data);
|
||||
|
|
@ -197,32 +274,9 @@ export default function DevicePage() {
|
|||
return updated;
|
||||
});
|
||||
},
|
||||
token,
|
||||
enabled: !!deviceID,
|
||||
});
|
||||
|
||||
// --- Real-time device updates (optional) ---
|
||||
// Updates device-level info (name, status, lastActive, etc.)
|
||||
useWebSocket<Device | null>({
|
||||
path: `/live/devices/${deviceID}`,
|
||||
parse: (e) => {
|
||||
try {
|
||||
const raw = JSON.parse(e.data);
|
||||
const dev = Device.any(raw);
|
||||
if (!dev?.settings) {
|
||||
console.warn("[ws] received device without settings:", raw);
|
||||
return null;
|
||||
}
|
||||
return dev;
|
||||
} catch (err) {
|
||||
console.warn("[ws] failed to parse device:", err);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
onMessage: (updatedDevice) => {
|
||||
if (!updatedDevice) return;
|
||||
setDevice(updatedDevice);
|
||||
},
|
||||
keys: liveContextKeys,
|
||||
types: liveContextTypes,
|
||||
as: liveAs,
|
||||
token,
|
||||
enabled: !!deviceID,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -264,10 +264,50 @@ export default function Devices() {
|
|||
)
|
||||
}, [])
|
||||
|
||||
/** Same context chain as deviceAPI.list / GetContext on the backend (path + group tab + ?as=). */
|
||||
const statusStreamKeys = useMemo(() => {
|
||||
if (tab !== "all") {
|
||||
const g = groups[parseInt(tab)]
|
||||
if (g) {
|
||||
const keys = [...getContextKeys()]
|
||||
keys.push(g.id().toString())
|
||||
return keys
|
||||
}
|
||||
}
|
||||
return getContextKeys()
|
||||
}, [tab, groups, location.pathname])
|
||||
|
||||
const statusStreamTypes = useMemo(() => {
|
||||
if (tab !== "all") {
|
||||
const g = groups[parseInt(tab)]
|
||||
if (g) {
|
||||
const types = [...getContextTypes()]
|
||||
types.push("group")
|
||||
return types
|
||||
}
|
||||
}
|
||||
return getContextTypes()
|
||||
}, [tab, groups, location.pathname])
|
||||
|
||||
/** Match Device page / getDevicePageData: omit ?as= when URL context already starts with team. */
|
||||
const statusStreamAs = useMemo(() => {
|
||||
const types =
|
||||
tab !== "all" && groups[parseInt(tab)]
|
||||
? [...getContextTypes(), "group"]
|
||||
: getContextTypes()
|
||||
if (as && !(types.length > 0 && types[0] === "team")) {
|
||||
return as
|
||||
}
|
||||
return undefined
|
||||
}, [as, tab, groups, location.pathname])
|
||||
|
||||
useDeviceStatusStreams({
|
||||
deviceIds,
|
||||
onStatusUpdate: handleStatusUpdate,
|
||||
token,
|
||||
keys: statusStreamKeys,
|
||||
types: statusStreamTypes,
|
||||
as: statusStreamAs,
|
||||
enabled: devices.length > 0 && !!token,
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import TemperatureIcon from "component/TemperatureIcon";
|
|||
import FuelIcon from "products/CommonIcons/fuelIcon";
|
||||
import moment from "moment";
|
||||
import Warning from "@mui/icons-material/Warning";
|
||||
import { getTemperatureUnit } from "utils";
|
||||
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||
import { useParams } from "react-router-dom";
|
||||
|
||||
|
|
@ -286,7 +285,7 @@ export default function Heater() {
|
|||
|
||||
const tempUnit = () => {
|
||||
let unit = "°C";
|
||||
if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) {
|
||||
unit = "°F";
|
||||
}
|
||||
return unit;
|
||||
|
|
|
|||
|
|
@ -13,12 +13,13 @@ import {
|
|||
yellow
|
||||
} from "@mui/material/colors";
|
||||
import { GraphType } from "common/Graph";
|
||||
import { User } from "models";
|
||||
import { IsCardController } from "products/DeviceProduct";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { quack } from "protobuf-ts/quack";
|
||||
import { getTextSecondary } from "theme/text";
|
||||
// import { getTextSecondary } from "theme";
|
||||
import { getDistanceUnit, getPressureUnit, getTemperatureUnit, roundTo } from "utils";
|
||||
import { roundTo } from "utils";
|
||||
import { extract } from "utils/types";
|
||||
|
||||
interface Enumeration {
|
||||
|
|
@ -64,7 +65,8 @@ export class MeasurementDescriber {
|
|||
measurementType: quack.MeasurementType,
|
||||
componentType: quack.ComponentType,
|
||||
componentSubtype: number,
|
||||
product?: pond.DeviceProduct
|
||||
product?: pond.DeviceProduct,
|
||||
user?: User
|
||||
) {
|
||||
this.measurementType = measurementType;
|
||||
this.details = {
|
||||
|
|
@ -87,7 +89,7 @@ export class MeasurementDescriber {
|
|||
case quack.MeasurementType.MEASUREMENT_TYPE_INVALID:
|
||||
break;
|
||||
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;
|
||||
this.details.label = "Temperature";
|
||||
this.details.unit = isFahrenheit ? "°F" : "°C";
|
||||
|
|
@ -233,7 +235,8 @@ export class MeasurementDescriber {
|
|||
}
|
||||
break;
|
||||
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;
|
||||
this.details.label = "Pressure";
|
||||
this.details.unit = isIWG ? "iwg" : "kPa";
|
||||
|
|
@ -437,7 +440,8 @@ export class MeasurementDescriber {
|
|||
this.details.max = 100000;
|
||||
break;
|
||||
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.unit = "cm";
|
||||
if (distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET) {
|
||||
|
|
@ -451,7 +455,8 @@ export class MeasurementDescriber {
|
|||
this.details.max = 100000;
|
||||
break;
|
||||
case quack.MeasurementType.MEASUREMENT_TYPE_SPEED:
|
||||
let speedUnit = getDistanceUnit()
|
||||
let speedUnit =
|
||||
user?.distanceUnit() ?? pond.DistanceUnit.DISTANCE_UNIT_FEET;
|
||||
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.colour = green["500"];
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { Box, Typography } from "@mui/material";
|
|||
import GrainDescriber from "grain/GrainDescriber";
|
||||
import { Transaction } from "models/Transaction";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useGlobalState } from "providers";
|
||||
import React from "react";
|
||||
import { getGrainUnit } from "utils";
|
||||
|
||||
interface Props {
|
||||
transaction: Transaction;
|
||||
|
|
@ -11,13 +11,14 @@ interface Props {
|
|||
|
||||
export default function TransactionDataDisplay(props: Props) {
|
||||
const { transaction } = props;
|
||||
const [{ user }] = useGlobalState();
|
||||
console.log(transaction)
|
||||
|
||||
const grainDisplay = (gt: pond.GrainTransaction) => {
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && gt.bushelsPerTonne > 1){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && gt.bushelsPerTonne > 1){
|
||||
return "Weight: " + Math.round(gt.bushels / gt.bushelsPerTonne*100)/100 + " mT"
|
||||
}
|
||||
if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && gt.bushelsPerTonne > 1){
|
||||
if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && gt.bushelsPerTonne > 1){
|
||||
return "Weight: " + Math.round(gt.bushels / (gt.bushelsPerTonne*0.907)*100)/100 + " t"
|
||||
}
|
||||
return "Bushels: " + gt.bushels
|
||||
|
|
|
|||
16
src/utils/getWsBaseUrl.ts
Normal file
16
src/utils/getWsBaseUrl.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/**
|
||||
* Origin for Pond WebSocket URLs.
|
||||
*
|
||||
* VITE_APP_API_URL usually ends with /v1 (same base axios uses for REST). WS paths are
|
||||
* written as /v1/live/..., so we strip a trailing /v1 from the env URL to avoid /v1/v1/.
|
||||
*/
|
||||
export function getWsBaseUrl(): string {
|
||||
const apiUrl = import.meta.env.VITE_APP_API_URL;
|
||||
if (apiUrl) {
|
||||
let ws = apiUrl.replace(/^http/, "ws");
|
||||
ws = ws.replace(/\/v1\/?$/, "");
|
||||
return ws.replace(/\/$/, "") || ws;
|
||||
}
|
||||
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||
return `${protocol}//${window.location.host}`;
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { pond } from "protobuf-ts/pond";
|
||||
|
||||
//function is deprecated, use User.tempUnit() instead
|
||||
export function getTemperatureUnit(): pond.TemperatureUnit {
|
||||
return localStorage.getItem("temperature") === "f"
|
||||
? pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT
|
||||
|
|
@ -31,6 +32,7 @@ export const fahrenheitToCelsius = (fahrenheit: number) => {
|
|||
return (fahrenheit - 32) * (5 / 9);
|
||||
};
|
||||
|
||||
// function is deprecated, use User.pressureUnit() instead
|
||||
export function getPressureUnit(): pond.PressureUnit {
|
||||
return localStorage.getItem("pressure") === "kpa"
|
||||
? pond.PressureUnit.PRESSURE_UNIT_KILOPASCALS
|
||||
|
|
@ -44,6 +46,7 @@ export function setPressureUnit(unit: pond.PressureUnit) {
|
|||
);
|
||||
}
|
||||
|
||||
// function is deprecated, use User.distanceUnit() instead
|
||||
export function getDistanceUnit(): pond.DistanceUnit {
|
||||
return localStorage.getItem("distance") === "m"
|
||||
? pond.DistanceUnit.DISTANCE_UNIT_METERS
|
||||
|
|
@ -54,6 +57,7 @@ export function setDistanceUnit(unit: pond.DistanceUnit) {
|
|||
localStorage.setItem("distance", unit === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft");
|
||||
}
|
||||
|
||||
// function is deprecated, use User.grainUnit() instead
|
||||
export function getGrainUnit(): pond.GrainUnit {
|
||||
switch(localStorage.getItem("grainUnit")){
|
||||
case "mT":
|
||||
|
|
@ -81,13 +85,11 @@ export function setGrainUnit(unit: pond.GrainUnit) {
|
|||
default:
|
||||
localStorage.setItem("grainUnit", "bu")
|
||||
}
|
||||
// localStorage.setItem("grainUnit", unit === pond.GrainUnit.GRAIN_UNIT_WEIGHT ? "mT" : "bu");
|
||||
}
|
||||
|
||||
export const distanceConversion = (val: number) => {
|
||||
export const distanceConversion = (val: number, distanceUnit: pond.DistanceUnit) => {
|
||||
let converted = val;
|
||||
|
||||
if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
if (distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_METERS) {
|
||||
converted = val / 3.281;
|
||||
}
|
||||
return converted;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue