diff --git a/.env b/.env index 9fdc8f3..90ef699 100644 --- a/.env +++ b/.env @@ -14,6 +14,7 @@ VITE_AUTH0_ADAPTIVE_CONSTRUCTION_CLIENT_ID=32rABabJzXRvJiWivTmeKFgwFiqh4ok7 VITE_AUTH0_AEROGROW_CLIENT_ID=KHl9ooUt1nia1RYw5n224dyggCXdbsSd VITE_AUTH0_MIVENT_CLIENT_ID=VNALE7RW6l3dY5uYcxgwElZV0lcT25Fg VITE_AUTH0_OMNIAIR_CLIENT_ID=IblmarD8wFafiD6doxTmOHQ6Bx3L9wWl +VITE_AUTH0_INTELLIFARMS_CLIENT_ID=RYtuAyOcB4DSaaqJMLDMf3pV8SFY9PdY #Branding (Default theme) VITE_APP_WEBSITE_TITLE="Adaptive Dashboard" diff --git a/README.md b/README.md index b7a7555..4a47964 100644 --- a/README.md +++ b/README.md @@ -18,31 +18,36 @@ Steps to add a new white label - add a `CNAME` record pointing their custom subdomain (ex: dashboard.example.com) to brandxtech.ca - add a login button on their website point to `/login` of their custom subdomain (ex: dashboard.example.com/login) +It is recommended to start with the Auth0 stage once everything from the client has been recieved as things like the client ID will be needed in other stages + -2. Create a PWA folder in `public` that is named after the client and generate PWA assets using [this](https://realfavicongenerator.net/) website (use the company logo but you might need to use a custom favicon depending on the result) +Frontend Steps +1. Create a PWA folder in `public` that is named after the client and generate PWA assets using [this](https://realfavicongenerator.net/) website (use the company logo but you might need to use a custom favicon depending on the result) - https://maskable.app/ also create a maskable icon for PWA - create a 512x512 png as well for PWA -3. Create a white-label branding folder in `src/assets/whitelabels` and create a `darkLogo.png` and `lightLogo.png` from the client's logo -4. In `src/services/whiteLabel.ts`, add a new `Whitelabel` instance with the required fields and add its hostname mapping to the `whitelabels` map (it is very similar to step one but had some constraints when dealing with the `public` folder) -5. If there are any pages specific to the whitelabel be sure to update the side and bottom navigator +2. Create a white-label branding folder in `src/assets/whitelabels` and create a `darkLogo.png` and `lightLogo.png` from the client's logo +3. In `src/services/whiteLabel.ts`, add a new `Whitelabel` instance with the required fields and add its hostname mapping to the `whitelabels` map +4. If there are any pages specific to the whitelabel be sure to update the side and bottom navigator -6. In `dynamic-config.prod.yml`, add a router entry for the new whitelabel -7. In `pond/http/server.go`, add the sub-domain to the `allowedOrigins` -8. In `pond/whitelabel.go`, add an entry for the new white label +Backend Steps +1. In `dynamic-config.prod.yml`, add a router entry for the new whitelabel +2. In `pond/http/server.go`, add the sub-domain to the `allowedOrigins` +3. In `pond/whitelabel.go`, add an entry for the new white label -7. Create a new `Auth0` application for the client + +Auth0 Steps +1. Create a new Single Page App on Auth0 using React as the tech +2. Once you have the client ID add it to your .env file in the frontend +3. Adjust settings accordingly in the new application - use a image bucket like [postimg](https://postimages.org/) to store their company logo and favicon - add a whitelabel logo - - allow necessary `origins`, `callback URLs`, and `CORS domains` to the application settings (see the default application as a guideline) + - allow necessary `origins`, `callback URLs`, and `CORS domains` to the application settings (see other applications/whitelabels as a guideline) - customize the Universal Login page to handle the new whitelabel - check if the client ID matches this client's Auth0 application - change the Universal Login theme using white-label colours and images stored in a bucket (ex: [postimg](https://postimages.org/)) -8. Enable the white-label sub-domain for CORS in the backend - -- in [http.go](https://gitlab.com/brandx/backend/blob/master/pond/http.go), add the white-label sub-domain to the `AllowedOrigins` list ## Expanding the ESLint configuration diff --git a/package-lock.json b/package-lock.json index 2cd53e8..0e54b33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "mui-tel-input": "^7.0.0", "notistack": "^3.0.1", "openweathermap-ts": "^1.2.10", - "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging", + "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#dev", "query-string": "^9.2.1", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", @@ -11205,7 +11205,7 @@ }, "node_modules/protobuf-ts": { "version": "1.0.0", - "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#9c0f668d4a56b8216dd71a44c3110a818aaf3541", + "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#b44f5fa7183d9565e9fd9e7a9ac756114401ddfd", "dependencies": { "protobufjs": "^6.8.8" } diff --git a/public/Intellifarms/IFND-2023-Logo-White.png b/public/Intellifarms/IFND-2023-Logo-White.png new file mode 100644 index 0000000..0afb3bf Binary files /dev/null and b/public/Intellifarms/IFND-2023-Logo-White.png differ diff --git a/public/Intellifarms/IFND-2023-Logo.png b/public/Intellifarms/IFND-2023-Logo.png new file mode 100644 index 0000000..11ff1c8 Binary files /dev/null and b/public/Intellifarms/IFND-2023-Logo.png differ diff --git a/public/Intellifarms/android-chrome-192x192.png b/public/Intellifarms/android-chrome-192x192.png new file mode 100644 index 0000000..11f1839 Binary files /dev/null and b/public/Intellifarms/android-chrome-192x192.png differ diff --git a/public/Intellifarms/android-chrome-512x512.png b/public/Intellifarms/android-chrome-512x512.png new file mode 100644 index 0000000..e4f7470 Binary files /dev/null and b/public/Intellifarms/android-chrome-512x512.png differ diff --git a/public/Intellifarms/apple-touch-icon.png b/public/Intellifarms/apple-touch-icon.png new file mode 100644 index 0000000..408dde9 Binary files /dev/null and b/public/Intellifarms/apple-touch-icon.png differ diff --git a/public/Intellifarms/browserconfig.xml b/public/Intellifarms/browserconfig.xml new file mode 100644 index 0000000..f62a123 --- /dev/null +++ b/public/Intellifarms/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #ffffff + + + diff --git a/public/Intellifarms/favicon-16x16.png b/public/Intellifarms/favicon-16x16.png new file mode 100644 index 0000000..f052e75 Binary files /dev/null and b/public/Intellifarms/favicon-16x16.png differ diff --git a/public/Intellifarms/favicon-32x32.png b/public/Intellifarms/favicon-32x32.png new file mode 100644 index 0000000..460f109 Binary files /dev/null and b/public/Intellifarms/favicon-32x32.png differ diff --git a/public/Intellifarms/favicon-48x48.png b/public/Intellifarms/favicon-48x48.png new file mode 100644 index 0000000..948fec7 Binary files /dev/null and b/public/Intellifarms/favicon-48x48.png differ diff --git a/public/Intellifarms/favicon.ico b/public/Intellifarms/favicon.ico new file mode 100644 index 0000000..f3b5e0c Binary files /dev/null and b/public/Intellifarms/favicon.ico differ diff --git a/public/Intellifarms/manifest.json b/public/Intellifarms/manifest.json new file mode 100644 index 0000000..5288b8b --- /dev/null +++ b/public/Intellifarms/manifest.json @@ -0,0 +1,19 @@ +{ + "name": "Intellifarms", + "short_name": "Intellifarms", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/public/Intellifarms/mstile-150x150.png b/public/Intellifarms/mstile-150x150.png new file mode 100644 index 0000000..03b9ab0 Binary files /dev/null and b/public/Intellifarms/mstile-150x150.png differ diff --git a/public/Intellifarms/safari-pinned-tab.svg b/public/Intellifarms/safari-pinned-tab.svg new file mode 100644 index 0000000..6ea0a3f --- /dev/null +++ b/public/Intellifarms/safari-pinned-tab.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/whitelabels/Intellifarms/IFND-2023-Logo-White.png b/src/assets/whitelabels/Intellifarms/IFND-2023-Logo-White.png new file mode 100644 index 0000000..0afb3bf Binary files /dev/null and b/src/assets/whitelabels/Intellifarms/IFND-2023-Logo-White.png differ diff --git a/src/assets/whitelabels/Intellifarms/IFND-2023-Logo.png b/src/assets/whitelabels/Intellifarms/IFND-2023-Logo.png new file mode 100644 index 0000000..11ff1c8 Binary files /dev/null and b/src/assets/whitelabels/Intellifarms/IFND-2023-Logo.png differ diff --git a/src/bin/BinActions.tsx b/src/bin/BinActions.tsx index a425ea6..c9f7c8f 100644 --- a/src/bin/BinActions.tsx +++ b/src/bin/BinActions.tsx @@ -57,6 +57,8 @@ interface Props { components?: Map; setComponents?: React.Dispatch>>; updateBinStatus?: (componentKeys: string[], removed?: boolean) => void; + componentDevices?: Map + setComponentDevices?: React.Dispatch>>; } interface OpenState { @@ -77,7 +79,9 @@ export default function BinActions(props: Props) { refreshCallback, userID, components, + componentDevices, setComponents, + setComponentDevices, updateBinStatus } = props; const [anchorEl, setAnchorEl] = React.useState(null); @@ -245,7 +249,9 @@ export default function BinActions(props: Props) { open={openState.sensors} userID={userID} components={components} + componentDevices={componentDevices} setComponents={setComponents} + setComponentDevices={setComponentDevices} updateBinStatus={updateBinStatus} onClose={refresh => { if (refresh === true) { diff --git a/src/bin/BinCardV2.tsx b/src/bin/BinCardV2.tsx index 5244db9..ac2b300 100644 --- a/src/bin/BinCardV2.tsx +++ b/src/bin/BinCardV2.tsx @@ -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() + "%" diff --git a/src/bin/BinComponents.tsx b/src/bin/BinComponents.tsx index 7864c46..0b81cba 100644 --- a/src/bin/BinComponents.tsx +++ b/src/bin/BinComponents.tsx @@ -71,7 +71,9 @@ const useStyles = makeStyles((theme: Theme) => { interface Props { components?: Map; + componentDevices?: Map; setComponents?: React.Dispatch>>; + setComponentDevices?: React.Dispatch>>; bin: string; binGrain: pond.Grain; updateBinStatus?: (componentKeys: string[], removed?: boolean) => void; @@ -84,7 +86,7 @@ interface Option { } export default function BinComponents(props: Props) { - const { components, bin, setComponents, updateBinStatus, binGrain } = props; + const { components, componentDevices, bin, setComponents, setComponentDevices, updateBinStatus, binGrain } = props; const [{as}] = useGlobalState(); const classes = useStyles(); const binAPI = useBinAPI(); @@ -208,20 +210,54 @@ export default function BinComponents(props: Props) { // } // }, [selectedDevice, componentAPI, deviceComponents, snackbar]); - const removeComponent = (component: string) => { - binAPI.removeComponent(bin, component, as).then(() => { + const removeComponent = (component: string, device?: number) => { + console.log(device) + binAPI.removeComponent(bin, component, device, as).then(() => { + if (components && setComponents) { if (components.delete(component)) { let newComponents = new Map(components); setComponents(newComponents); } } + if(componentDevices && setComponentDevices) { + if (componentDevices.delete(component)) { + let newComponentDevices = new Map(componentDevices); + setComponentDevices(newComponentDevices); + } + } snackbar.info("Component removed from bin"); }); setComponentToRemove(undefined); }; - const removeComponentConfirmation = () => { + const removeComponentConfirmation = (last?: boolean) => { + let lastComponent = false; + let devId: number | undefined; + if(last){ + lastComponent = last + }else{ + if (componentDevices && componentToRemove) { + const id = componentDevices.get(componentToRemove.key()); + + if (id !== undefined) { + devId = id + let count = 0; + + for (const val of componentDevices.values()) { + if (val === devId) { + count++; + + if (count > 1) { + break; // stop early once we know it's not the last + } + } + } + + lastComponent = count === 1; + } + } + } return ( setComponentToRemove(undefined)}> Remove {componentToRemove?.name()}? - - This will remove {componentToRemove?.name()} from this bin. If you don't have direct - access to this component or the device it is attached to, you will not be able to add it - back. - + {lastComponent ? + + This component {componentToRemove?.name()} is the last component from its device. You can choose to remove only the component itself or the device along with it. + Leaving the device may have unexpected results if the device will continue to be used and it is recommended to remove it if the device is being moved to a new bin. + + : + + This will remove {componentToRemove?.name()} from this bin. If you don't have direct + access to this component or the device it is attached to, you will not be able to add it + back. + + } + {lastComponent + ? + + + + : + } ); @@ -256,7 +310,7 @@ export default function BinComponents(props: Props) { Remove All Components? - This will remove All attached components from this bin. If you don't have direct access + This will remove All attached components and devices from this bin. If you don't have direct access to these components or the devices they are attached to, you will not be able to add them back. @@ -320,6 +374,12 @@ export default function BinComponents(props: Props) { setComponents(newComponents); } } + if(componentDevices && setComponentDevices) { + if (componentDevices.set(component.key(), device)) { + let newComponentDevices = new Map(componentDevices); + setComponentDevices(newComponentDevices); + } + } //if a grain cable was added to the bin update the components grain type to match the bin if (preferences.type === pond.BinComponent.BIN_COMPONENT_GRAIN_CABLE) { let settings = component.settings; @@ -338,15 +398,40 @@ export default function BinComponents(props: Props) { } }); } else { - binAPI.removeComponent(bin, component.key(), as).then(resp => { - if (components && setComponents) { + let lastComponent = false; + if (componentDevices) { + console.log(componentDevices) + let count = 0; + for (const val of componentDevices.values()) { + if (val === device) { + count++; + + if (count > 1) { + break; // stop early once we know it's not the last + } + } + } + lastComponent = count === 1; + } + if(lastComponent){ + setComponentToRemove(component) + }else{ + binAPI.removeComponent(bin, component.key(), undefined, as).then(resp => { + if (components && setComponents) { if (components.delete(component.key())) { let newComponents = new Map(components); setComponents(newComponents); } } + if(componentDevices && setComponentDevices) { + if (componentDevices.delete(component.key())) { + let newComponentDevices = new Map(componentDevices); + setComponentDevices(newComponentDevices); + } + } snackbar.info("Component removed from bin"); - }); + }); + } } }; @@ -567,7 +652,10 @@ export default function BinComponents(props: Props) { {component.name()} - setComponentToRemove(component)}> + { + setComponentToRemove(component) + + }}> diff --git a/src/bin/BinConditioningInteraction.tsx b/src/bin/BinConditioningInteraction.tsx index bd6c3c7..d729462 100644 --- a/src/bin/BinConditioningInteraction.tsx +++ b/src/bin/BinConditioningInteraction.tsx @@ -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"; @@ -103,7 +103,7 @@ export default function BinConditioningInteraction(props: Props) { let sliderVals: Map = new Map(); let sliderMarks: Map = new Map(); passedInteraction.conditions().forEach(condition => { - let describer = describeMeasurement(condition.measurementType, source.type()); + let describer = describeMeasurement(condition.measurementType, source.type(), undefined, undefined, user); //NOTE: toDisplay will convert the temp value to fahrenheit sliderVals.set(condition.measurementType, describer.toDisplay(condition.value)); }); @@ -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 @@ -173,17 +173,17 @@ export default function BinConditioningInteraction(props: Props) { return ( {interaction.conditions().map((condition, i) => { - let describer = describeMeasurement(condition.measurementType, source?.type()); - let labelTail = ""; + let describer = describeMeasurement(condition.measurementType, source?.type(), source.subType(), undefined, user); + let labelTail = describer.unit(); let marks: Mark[] = []; - if (condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE) { - if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) { - labelTail = "°F"; - } else { - labelTail = "°C"; - } - } + // if (condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE) { + // if (user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) { + // labelTail = "°F"; + // } else { + // labelTail = "°C"; + // } + // } if (condition.measurementType === quack.MeasurementType.MEASUREMENT_TYPE_PERCENT) { labelTail = "%"; } @@ -198,7 +198,7 @@ export default function BinConditioningInteraction(props: Props) { return ( - {interactionConditionText(source, condition, false)} + {interactionConditionText(source, condition, false, user)} 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([]); const [manufacturer, SetManufacturer] = useState @@ -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)") } /> diff --git a/src/bin/BinSensors.tsx b/src/bin/BinSensors.tsx index f1c81ac..492091e 100644 --- a/src/bin/BinSensors.tsx +++ b/src/bin/BinSensors.tsx @@ -30,7 +30,9 @@ interface Props { coords?: { longitude: number; latitude: number }; binYards?: pond.BinYardSettings[]; components?: Map; + componentDevices?: Map setComponents?: React.Dispatch>>; + setComponentDevices?: React.Dispatch>>; updateBinStatus?: (componentKeys: string[], removed?: boolean) => void; } @@ -43,7 +45,9 @@ export default function BinSensors(props: Props) { mode, openedBinYard, components, + componentDevices, setComponents, + setComponentDevices, updateBinStatus } = props; const [initialized, setInitialized] = useState(false); @@ -93,7 +97,9 @@ export default function BinSensors(props: Props) { { 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 ( {getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE ? "mT" : "t"} + endAdornment: {user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE ? "mT" : "t"} }} className={classes.bottomSpacing} /> @@ -1099,7 +1099,7 @@ export default function BinSettings(props: Props) { InputProps={{ endAdornment: ( - {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "ft" : "cm"} + {user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "ft" : "cm"} ) }} @@ -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: ( - {getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"} + {user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"} ) }} @@ -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: ( - {getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET + {user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"} @@ -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: ( - {getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET + {user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"} @@ -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: ( - {getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET + {user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"} @@ -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: ( - {getDistanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"} + {user.distanceUnit() !== pond.DistanceUnit.DISTANCE_UNIT_FEET ? "m" : "ft"} ) }} @@ -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: ( - {getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT + {user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "F" : "C"} @@ -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: ( - {getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT + {user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "F" : "C"} @@ -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: ( - {getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT + {user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "F" : "C"} diff --git a/src/bin/BinStorageConditions.tsx b/src/bin/BinStorageConditions.tsx index fa0e957..b0e7e8a 100644 --- a/src/bin/BinStorageConditions.tsx +++ b/src/bin/BinStorageConditions.tsx @@ -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([-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: ( - {getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT + {user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "°F" : "°C"} @@ -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"; diff --git a/src/bin/BinTransactions.tsx b/src/bin/BinTransactions.tsx index 4c9d598..925201c 100644 --- a/src/bin/BinTransactions.tsx +++ b/src/bin/BinTransactions.tsx @@ -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.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" } diff --git a/src/bin/BinVisualizerV2.tsx b/src/bin/BinVisualizerV2.tsx index 2da6f78..437f09d 100644 --- a/src/bin/BinVisualizerV2.tsx +++ b/src/bin/BinVisualizerV2.tsx @@ -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); @@ -1539,7 +1539,7 @@ export default function BinVisualizer(props: Props) { ) : ( - + {fullScreenHandler.enter()}}> )} @@ -1676,7 +1676,7 @@ export default function BinVisualizer(props: Props) { fontWeight: 650, color: tempColour }}> - {ambient?.getTempString(getTemperatureUnit())} + {ambient?.getTempString(user.tempUnit())} diff --git a/src/bin/BinyardDisplay.tsx b/src/bin/BinyardDisplay.tsx index b639759..905ab8c 100644 --- a/src/bin/BinyardDisplay.tsx +++ b/src/bin/BinyardDisplay.tsx @@ -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(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 diff --git a/src/bin/GrainNodeInteractions.tsx b/src/bin/GrainNodeInteractions.tsx index e34cfd1..cc341dd 100644 --- a/src/bin/GrainNodeInteractions.tsx +++ b/src/bin/GrainNodeInteractions.tsx @@ -87,9 +87,24 @@ export default function GrainNodeInteractions(props: Props) { const [nodeHum, setNodeHum] = useState(); const [nodeMoist, setNodeMoist] = useState(); const [{ user, as }] = useGlobalState(); - const tempDescriber = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE); - const humDescriber = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_PERCENT); - const moistureDescriber = describeMeasurement(quack.MeasurementType.MEASUREMENT_TYPE_GRAIN_EMC); + const tempDescriber = describeMeasurement( + quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE, + quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE, + undefined, + undefined, + user); + const humDescriber = describeMeasurement( + quack.MeasurementType.MEASUREMENT_TYPE_PERCENT, + quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE, + undefined, + undefined, + user); + const moistureDescriber = describeMeasurement( + quack.MeasurementType.MEASUREMENT_TYPE_GRAIN_EMC, + quack.ComponentType.COMPONENT_TYPE_GRAIN_CABLE, + undefined, + undefined, + user); const [topNode, setTopNode] = useState(false); const [excluded, setExcluded] = useState(false); const componentAPI = useComponentAPI(); diff --git a/src/bin/conditioning/modeChangeDialog.tsx b/src/bin/conditioning/modeChangeDialog.tsx index b31c8f8..ef2dfbd 100644 --- a/src/bin/conditioning/modeChangeDialog.tsx +++ b/src/bin/conditioning/modeChangeDialog.tsx @@ -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([]) const interactionAPI = useInteractionsAPI() const componentAPI = useComponentAPI(); @@ -289,20 +288,24 @@ if (!selectedDevice) return; describeMeasurement( quack.MeasurementType.MEASUREMENT_TYPE_PERCENT, sensor.settings.type, - sensor.settings.subtype + sensor.settings.subtype, + undefined, + user ).toStored(hum) ) }); 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( quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE, sensor.settings.type, - sensor.settings.subtype + sensor.settings.subtype, + undefined, + user ).toStored(temp); let tempCondition = pond.InteractionCondition.create({ @@ -386,19 +389,23 @@ if (!selectedDevice) return; value: describeMeasurement( quack.MeasurementType.MEASUREMENT_TYPE_PERCENT, sensor.settings.type, - sensor.settings.subtype + sensor.settings.subtype, + undefined, + user ).toStored(humidityPreset) }); 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( quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE, sensor.settings.type, - sensor.settings.subtype + sensor.settings.subtype, + undefined, + user ).toStored(tempPreset); let fanConditionTwo = pond.InteractionCondition.create({ @@ -631,7 +638,7 @@ if (!selectedDevice) return; InputProps={{ endAdornment: ( - {getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT + {user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "°F" : "℃"} diff --git a/src/bin/graphs/BinComponentGraph.tsx b/src/bin/graphs/BinComponentGraph.tsx index 3c5a625..07a9325 100644 --- a/src/bin/graphs/BinComponentGraph.tsx +++ b/src/bin/graphs/BinComponentGraph.tsx @@ -346,14 +346,14 @@ export default function BinComponentGraph(props: Props) { ? measurements?.map(um => areaGraph( um, - describeMeasurement(um.type, component.type(), component.subType()), + describeMeasurement(um.type, component.type(), component.subType(), undefined, user), component.settings.smoothingAverages ) ) : measurements?.map(um => lineGraph( um, - describeMeasurement(um.type, component.type(), component.subType()), + describeMeasurement(um.type, component.type(), component.subType(), undefined, user), component.settings.smoothingAverages ) )} diff --git a/src/bin/graphs/BinLevelOverTime.tsx b/src/bin/graphs/BinLevelOverTime.tsx index 5fe36bc..ed4de8d 100644 --- a/src/bin/graphs/BinLevelOverTime.tsx +++ b/src/bin/graphs/BinLevelOverTime.tsx @@ -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([]); const [dataLoading, setDataLoading] = useState(false); const [capacity, setCapacity] = useState(); @@ -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({ diff --git a/src/cableEstimator/binSVGs/sideView.tsx b/src/cableEstimator/binSVGs/sideView.tsx index e3a1364..907d40a 100644 --- a/src/cableEstimator/binSVGs/sideView.tsx +++ b/src/cableEstimator/binSVGs/sideView.tsx @@ -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( diff --git a/src/cableEstimator/cableEstimator.tsx b/src/cableEstimator/cableEstimator.tsx index 871868b..153b3f8 100644 --- a/src/cableEstimator/cableEstimator.tsx +++ b/src/cableEstimator/cableEstimator.tsx @@ -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([]); const [displayedRows, setDisplayedRows] = useState([]); 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) => {row.HopperAngle} }, { - 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) => {distanceConversion(row.Diameter).toFixed(2)} + render: (row: jsonBin) => ( + + {distanceConversion(row.Diameter, user.distanceUnit()).toFixed(2)} + + ) }, { - 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) => {distanceConversion(row.Sidewall).toFixed(2)} + render: (row: jsonBin) => ( + + {distanceConversion(row.Sidewall, user.distanceUnit()).toFixed(2)} + + ) }, { - 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) => {distanceConversion(row.Peak).toFixed(2)} + render: (row: jsonBin) => ( + + {distanceConversion(row.Peak, user.distanceUnit()).toFixed(2)} + + ) }, { - 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) => {distanceConversion(row.EaveToPeak).toFixed(2)} + render: (row: jsonBin) => ( + + {distanceConversion(row.EaveToPeak, user.distanceUnit()).toFixed(2)} + + ) }, { title: "Roof Angle", @@ -545,7 +563,7 @@ export default function CableEstimator() { InputProps={{ endAdornment: ( - {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"} + {user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"} ) }} @@ -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: ( - {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"} + {user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"} ) }} @@ -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: ( - {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"} + {user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"} ) }} @@ -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); diff --git a/src/cableEstimator/cableMounting.tsx b/src/cableEstimator/cableMounting.tsx index fa14289..3ac6f0f 100644 --- a/src/cableEstimator/cableMounting.tsx +++ b/src/cableEstimator/cableMounting.tsx @@ -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) => {row.Orbit === 0 ? "Center" : row.Orbit} }, { - 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) => ( - {distanceConversion(row.DistanceFromCenter).toFixed(2)} + + {distanceConversion(row.DistanceFromCenter, user.distanceUnit()).toFixed(2)} + ) }, { - 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) => ( - {distanceConversion(roofDist(row.DistanceFromCenter)).toFixed(2)} + + {distanceConversion(roofDist(row.DistanceFromCenter), user.distanceUnit()).toFixed(2)} + ) }, { diff --git a/src/cableEstimator/cableQuote.tsx b/src/cableEstimator/cableQuote.tsx index ae37870..5f45b70 100644 --- a/src/cableEstimator/cableQuote.tsx +++ b/src/cableEstimator/cableQuote.tsx @@ -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 } />; + return ( + } + /> + ); }; return ( diff --git a/src/cableEstimator/cableTable.tsx b/src/cableEstimator/cableTable.tsx index ee73c55..cdc68f3 100644 --- a/src/cableEstimator/cableTable.tsx +++ b/src/cableEstimator/cableTable.tsx @@ -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) => {row.Count} }, { - title: "Length" + (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"), + title: "Length" + (user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"), render: (row) => {row.Length} }, { diff --git a/src/cableEstimator/pdfComponents/cableTable/cableTableHeader.tsx b/src/cableEstimator/pdfComponents/cableTable/cableTableHeader.tsx index 79f95ad..806220a 100644 --- a/src/cableEstimator/pdfComponents/cableTable/cableTableHeader.tsx +++ b/src/cableEstimator/pdfComponents/cableTable/cableTableHeader.tsx @@ -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) { Type Qty - Length {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"} + Length{" "} + {props.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"} Nodes diff --git a/src/cableEstimator/pdfComponents/cableTable/cableTableRow.tsx b/src/cableEstimator/pdfComponents/cableTable/cableTableRow.tsx index 8e80d6a..3a22ba4 100644 --- a/src/cableEstimator/pdfComponents/cableTable/cableTableRow.tsx +++ b/src/cableEstimator/pdfComponents/cableTable/cableTableRow.tsx @@ -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) { {cable.Orbit === 0 ? "Center" : cable.Orbit} {cable.Type === 2 ? "Moisture" : "Temperature"} {cable.Count} - {distanceConversion(cable.Length).toFixed(2)} + + {distanceConversion(cable.Length, props.distanceUnit).toFixed(2)} + {cable.Nodes} ); diff --git a/src/cableEstimator/pdfComponents/mountingTable/mountingTableHeader.tsx b/src/cableEstimator/pdfComponents/mountingTable/mountingTableHeader.tsx index a7708dd..67046c1 100644 --- a/src/cableEstimator/pdfComponents/mountingTable/mountingTableHeader.tsx +++ b/src/cableEstimator/pdfComponents/mountingTable/mountingTableHeader.tsx @@ -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) { Orbit - Radius {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"} + Radius{" "} + {props.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"} - Along Roof {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"} + Along Roof{" "} + {props.distanceUnit === pond.DistanceUnit.DISTANCE_UNIT_FEET ? "(ft)" : "(m)"} Bracket diff --git a/src/cableEstimator/pdfComponents/mountingTable/mountingTableRows.tsx b/src/cableEstimator/pdfComponents/mountingTable/mountingTableRows.tsx index b86f1d1..2824de6 100644 --- a/src/cableEstimator/pdfComponents/mountingTable/mountingTableRows.tsx +++ b/src/cableEstimator/pdfComponents/mountingTable/mountingTableRows.tsx @@ -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}> {orbit.Orbit === 0 ? "C" : orbit.Orbit} - {distanceConversion(orbit.DistanceFromCenter).toFixed(2)} + {distanceConversion(orbit.DistanceFromCenter, props.distanceUnit).toFixed(2)} - {distanceConversion(roofDist(orbit.DistanceFromCenter)).toFixed(2)} + {distanceConversion(roofDist(orbit.DistanceFromCenter), props.distanceUnit).toFixed(2)} {bracketType} diff --git a/src/cableEstimator/pdfComponents/pdfContent.tsx b/src/cableEstimator/pdfComponents/pdfContent.tsx index bce1f15..c5bbb8b 100644 --- a/src/cableEstimator/pdfComponents/pdfContent.tsx +++ b/src/cableEstimator/pdfComponents/pdfContent.tsx @@ -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) { - + @@ -63,8 +66,12 @@ export default function PdfContent(props: Props) { Install Guide - - + + @@ -73,8 +80,12 @@ export default function PdfContent(props: Props) { Recommended Cables - - + + ); diff --git a/src/cableEstimator/pdfComponents/pdfSVG/pdfSideView.tsx b/src/cableEstimator/pdfComponents/pdfSVG/pdfSideView.tsx index cad1209..3a38a9c 100644 --- a/src/cableEstimator/pdfComponents/pdfSVG/pdfSideView.tsx +++ b/src/cableEstimator/pdfComponents/pdfSVG/pdfSideView.tsx @@ -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( diff --git a/src/charts/MeasurementsChart.tsx b/src/charts/MeasurementsChart.tsx index 1baeea6..c4a5d8b 100644 --- a/src/charts/MeasurementsChart.tsx +++ b/src/charts/MeasurementsChart.tsx @@ -67,7 +67,7 @@ export default function MeasurementsChart(props: Props) { const [currentMax, setCurrentMax] = useState("dataMax"); const [newChart, setNewChart] = useState(false); const [xDomain, setXDomain] = useState(["dataMin", "dataMax"]); - const [{ showErrors }, dispatch] = useGlobalState(); + const [{ showErrors, user }, dispatch] = useGlobalState(); const isMobile = useMobile(); // const [zoomStart, setZoomStart] = useState(); // const [zoomEnd, setZoomEnd] = useState(); @@ -123,7 +123,7 @@ export default function MeasurementsChart(props: Props) { if (filters?.selectedInteractions?.includes(interaction.key())) { interaction.settings.conditions.forEach((condition, j) => { if (condition.measurementType === measurementType) { - let describer = describeMeasurement(condition.measurementType); + let describer = describeMeasurement(condition.measurementType, undefined, undefined, undefined, user); selectedInteractions.push( void; colourAboveZero?: ColourData colourBelowZero?: ColourData + minY?: string | number + maxY?: string | number } export default function SingleSetAreaChart(props: Props) { - const { data, maxRef, minRef, newXDomain, multiGraphZoom, yAxisLabel, colourAboveZero, colourBelowZero, tooltipLabel, tooltipUnit } = props; + const { data, maxRef, minRef, newXDomain, multiGraphZoom, yAxisLabel, colourAboveZero, colourBelowZero, tooltipLabel, tooltipUnit, minY, maxY } = props; const [xDomain, setXDomain] = useState(["dataMin", "dataMax"]); const [refLeft, setRefLeft] = useState(); const [refRight, setRefRight] = useState(); @@ -152,7 +154,8 @@ export default function SingleSetAreaChart(props: Props) { /> (props: Props) { 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); @@ -614,7 +619,7 @@ export default function ResponsiveTable(props: Props) { {customElement && - + {customElement} diff --git a/src/component/ComponentForm.tsx b/src/component/ComponentForm.tsx index 21ca747..17c1bf7 100644 --- a/src/component/ComponentForm.tsx +++ b/src/component/ComponentForm.tsx @@ -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"; @@ -146,7 +145,9 @@ export default function ComponentForm(props: Props) { let describer = describeMeasurement( primaryMeasurement(formComponent.settings.type), formComponent.settings.type, - formComponent.settings.subtype + formComponent.settings.subtype, + undefined, + user ); let offset = describer.toDisplay(formComponent.settings.calibrationOffset); let formCoefficients: string[] = []; @@ -177,11 +178,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 +190,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; } @@ -481,7 +482,9 @@ export default function ComponentForm(props: Props) { f.component.settings.calibrationOffset = describeMeasurement( primaryMeasurement(f.component.settings.type), f.component.settings.type, - f.component.settings.subtype + f.component.settings.subtype, + undefined, + user ).toStored(+event.target.value); } setForm(f); @@ -494,7 +497,9 @@ export default function ComponentForm(props: Props) { f.component.settings.calibrations[index].calibrationOffset = describeMeasurement( primaryMeasurement(f.component.settings.type), f.component.settings.type, - f.component.settings.subtype + f.component.settings.subtype, + undefined, + user ).toStored(+event.target.value); } setForm(f); @@ -520,9 +525,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 +554,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 +583,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 +611,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; @@ -732,7 +737,9 @@ export default function ComponentForm(props: Props) { {describeMeasurement( primaryMeasurement(component.settings.type), component.settings.type, - component.settings.subtype + component.settings.subtype, + undefined, + user ).unit()} ) @@ -824,7 +831,7 @@ export default function ComponentForm(props: Props) { const describeSource = (measurementType: quack.MeasurementType): MeasurementDescriber => { const { component } = form; - return describeMeasurement(measurementType, component.type(), component.subType()); + return describeMeasurement(measurementType, component.type(), component.subType(), undefined, user); }; const availableMeasurementTypes = (type: quack.ComponentType): quack.MeasurementType[] => { @@ -1252,7 +1259,7 @@ export default function ComponentForm(props: Props) { InputProps={{ endAdornment: ( - {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS + {user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"} @@ -1276,7 +1283,7 @@ export default function ComponentForm(props: Props) { InputProps={{ endAdornment: ( - {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS + {user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"} @@ -1300,7 +1307,7 @@ export default function ComponentForm(props: Props) { InputProps={{ endAdornment: ( - {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS + {user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"} @@ -1328,7 +1335,7 @@ export default function ComponentForm(props: Props) { InputProps={{ endAdornment: ( - {getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"} + {user.distanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS ? "m" : "ft"} ) }} diff --git a/src/component/ExportDataSettings.tsx b/src/component/ExportDataSettings.tsx index 0a310ba..a17cdc0 100644 --- a/src/component/ExportDataSettings.tsx +++ b/src/component/ExportDataSettings.tsx @@ -210,7 +210,7 @@ class ExportDataSettings extends React.Component { // } formatMeasurements(measurements: Array): Promise> { - const { device, component } = this.props; + const { device, component, user } = this.props; return new Promise(function(resolve, reject) { if (!measurements) reject("Invalid measurements"); @@ -237,7 +237,9 @@ class ExportDataSettings extends React.Component { let unit = describeMeasurement( componentMeasurement.measurementType, component.settings.type, - component.settings.subtype + component.settings.subtype, + undefined, + user ).unit(); let key = componentMeasurement.label + " (" + unit + ")"; row[key] = componentMeasurement.extract(measurement.measurement); diff --git a/src/contract/constractActions.tsx b/src/contract/constractActions.tsx deleted file mode 100644 index 3c1e036..0000000 --- a/src/contract/constractActions.tsx +++ /dev/null @@ -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 ( - - - - {GrainDescriber(contract.grain()).name} - - - {contract.deliveredInPreferredUnit().toFixed(2)}/ - {contract.sizeInPreferredUnit().toFixed(2)} {contract.unit} - - - - - {/* ( - - - - )} - /> */} - - - - - - ); -} diff --git a/src/contract/contractList.tsx b/src/contract/contractList.tsx index aec7497..f266147 100644 --- a/src/contract/contractList.tsx +++ b/src/contract/contractList.tsx @@ -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>(new Map()); //will need need map for custom contracts @@ -173,16 +173,16 @@ export default function ContractsList(props: Props) { {contract.name()} {contract.settings.contractDate} {contract.settings.deliveryWindow?.endDate} - {contract.sizeInPreferredUnit() + " " + contract.unit} - {contract.deliveredInPreferredUnit() + " " + contract.unit} + {contract.sizeInPreferredUnit(user) + " " + contract.unit} + {contract.deliveredInPreferredUnit(user) + " " + contract.unit} {/* */} {/* {((contract.settings.delivered/contract.settings.size)*100).toFixed(1) + "%"} */} - {contract.sizeInPreferredUnit() - - contract.deliveredInPreferredUnit() + + {contract.sizeInPreferredUnit(user) - + contract.deliveredInPreferredUnit(user) + " " + contract.unit} diff --git a/src/contract/contractSettings.tsx b/src/contract/contractSettings.tsx index 13116b0..b1050e6 100644 --- a/src/contract/contractSettings.tsx +++ b/src/contract/contractSettings.tsx @@ -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 } } diff --git a/src/contract/contractTransactionGraph.tsx b/src/contract/contractTransactionGraph.tsx index 5eae1c3..22eeeea 100644 --- a/src/contract/contractTransactionGraph.tsx +++ b/src/contract/contractTransactionGraph.tsx @@ -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([]); 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); diff --git a/src/contract/contractTransactionTable.tsx b/src/contract/contractTransactionTable.tsx index ebee9ba..634993b 100644 --- a/src/contract/contractTransactionTable.tsx +++ b/src/contract/contractTransactionTable.tsx @@ -232,6 +232,7 @@ export default function ContractTransactionTable(props: Props) { Select Files to Upload - {contract.deliveredInPreferredUnit().toFixed(2)}/ - {contract.sizeInPreferredUnit().toFixed(2)} {contract.unit} + {contract.deliveredInPreferredUnit(user).toFixed(2)}/ + {contract.sizeInPreferredUnit(user).toFixed(2)} {contract.unit} diff --git a/src/device/DevicePresetsFromPicker.tsx b/src/device/DevicePresetsFromPicker.tsx index 900df87..a22991b 100644 --- a/src/device/DevicePresetsFromPicker.tsx +++ b/src/device/DevicePresetsFromPicker.tsx @@ -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([]); const [fans, setFans] = useState([]); //const [subscribeBinToAutoTopNode, setSubscribeBinToAutoTopNode] = useState(false); - const [{as}] = useGlobalState(); + const [{as, user}] = useGlobalState(); useEffect(() => { if (deviceComponents.get(deviceIndex.toString())) return; @@ -439,19 +438,23 @@ export default function DevicePresets(props: DevicePresetsProps) { value: describeMeasurement( quack.MeasurementType.MEASUREMENT_TYPE_PERCENT, plenum.settings.type, - plenum.settings.subtype + plenum.settings.subtype, + undefined, + user ).toStored(humidityPreset) }); 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( quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE, plenum.settings.type, - plenum.settings.subtype + plenum.settings.subtype, + undefined, + user ).toStored(tempPreset); let fanConditionTwo = pond.InteractionCondition.create({ @@ -533,7 +536,9 @@ export default function DevicePresets(props: DevicePresetsProps) { describeMeasurement( quack.MeasurementType.MEASUREMENT_TYPE_PERCENT, plenum.settings.type, - plenum.settings.subtype + plenum.settings.subtype, + undefined, + user ).toStored(hum) ) }); @@ -541,13 +546,15 @@ export default function DevicePresets(props: DevicePresetsProps) { } //since the measurement describers function to stored does a conversion into celsius if the users pref is fahrenheit for temperature we need to convert the preset value into fahrenheit - 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( quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE, plenum.settings.type, - plenum.settings.subtype + plenum.settings.subtype, + undefined, + user ).toStored(temp); let tempCondition = pond.InteractionCondition.create({ diff --git a/src/device/presets/devicePresetCard.tsx b/src/device/presets/devicePresetCard.tsx index 2839df3..30cbc63 100644 --- a/src/device/presets/devicePresetCard.tsx +++ b/src/device/presets/devicePresetCard.tsx @@ -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: ( - {getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT + {user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "°F" : "°C"} @@ -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: ( - {getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT + {user.tempUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT ? "°F" : "°C"} @@ -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); diff --git a/src/field/FieldTaskList.tsx b/src/field/FieldTaskList.tsx new file mode 100644 index 0000000..66a32c3 --- /dev/null +++ b/src/field/FieldTaskList.tsx @@ -0,0 +1,173 @@ +import { Fab, Theme } from "@mui/material" +import { Task } from "models" +import { useGlobalState, useTaskAPI } from "providers" +import React, { useCallback, useEffect, useState } from "react" +import TaskDrawer from "tasks/TaskDrawer" +import TaskList from "tasks/TaskList" +import TaskSettings from "tasks/TaskSettings" +import AddIcon from "@mui/icons-material/Add"; +import { makeStyles } from "@mui/styles"; +import { openSnackbar } from "providers/Snackbar" +import { cloneDeep } from "lodash" + + + +interface Props { + field: string +} + +const useStyles = makeStyles((theme: Theme) => { + return ({ + active: { + color: theme.palette.getContrastText(theme.palette.secondary.main), + backgroundColor: theme.palette.secondary.main, + width: theme.spacing(5), + height: theme.spacing(5), + border: 0, + "&:hover": { + backgroundColor: theme.palette.secondary.main + } + }, + fab: { + zIndex: 20, + background: theme.palette.primary.main, + "&:hover": { + background: theme.palette.primary.main + }, + "&:focus": { + background: theme.palette.primary.main + }, + position: "absolute", + bottom: theme.spacing(8), //for mobile navigator + right: theme.spacing(2), + [theme.breakpoints.up("sm")]: { + bottom: theme.spacing(2) + } + }, + overlayFab: { + zIndex: 20, + background: theme.palette.primary.main, + "&:hover": { + background: theme.palette.primary.main + }, + "&:focus": { + background: theme.palette.primary.main + }, + position: "fixed", + bottom: theme.spacing(8), //for mobile navigator + right: theme.spacing(2), + [theme.breakpoints.up("sm")]: { + bottom: theme.spacing(2) + } + } + }); +}); + +export default function FieldTaskList(props: Props) { + const { field } = props + const [{ as }] = useGlobalState() + const taskAPI = useTaskAPI() + const classes = useStyles() + const [selectedTask, setSelectedTask] = useState(undefined) + const [openTaskDrawer, setOpenTaskDrawer] = useState(false) + const [opentaskSettings, setOpenTaskSettings] = useState(false) + const [taskMap, setTaskMap] = useState>(new Map()) + + //load the tasks + const loadTasks = useCallback(() => { + console.log("loading tasks") + taskAPI.listTasks(50, 0, "asc", "start", undefined, undefined, undefined, undefined, undefined, [field], ["field"]).then(resp => { + if(resp.data.tasks){ + let newMap: Map = new Map() + resp.data.tasks.forEach(task => { + newMap.set(task.key, Task.create(task)) + }) + setTaskMap(newMap) + } + }).catch(err => { + + }) + },[as, field]) + + useEffect(()=>{ + loadTasks() + },[loadTasks]) + + const deleteTask = (task: Task) => { + taskAPI.removeTask(task.key).then(resp => { + openSnackbar("success", "Task has been removed") + loadTasks() + }).catch(err => { + openSnackbar("error", "There was a problem removing the task") + }) + } + + const markComplete = (task: Task) => { + let settings = cloneDeep(task.settings) + settings.complete = !task.settings.complete + taskAPI.updateTask(task.key, settings).then(resp => { + openSnackbar("success", "Task has been updated") + loadTasks() + }).catch(err => { + openSnackbar("error", "There was a problem updating the task") + }) + } + //return the task list + return ( + + {selectedTask && + { + setOpenTaskDrawer(false) + setSelectedTask(undefined) + if (refresh) { + loadTasks() + } + }} + keys={[field]} + types={["field"]} + /> + } + { + let task = taskMap.get(id) + if(task){ + setSelectedTask(task) + setOpenTaskDrawer(true) + } + }} + tasks={Array.from(taskMap.values())} + reLoad={() => { + loadTasks() + }} + keys={[field]} + types={["field"]} + /> + { + setOpenTaskSettings(false) + if(reload){ + loadTasks() + } + }} + keys={[field]} + types={["field"]} + task={selectedTask} + /> + {setOpenTaskSettings(true)}} + aria-label="Create Task" + className={classes.overlayFab} + size={"medium"}> + + + + ) +} \ No newline at end of file diff --git a/src/gate/GateDeltaTempGraph.tsx b/src/gate/GateDeltaTempGraph.tsx index d547b1c..4b498dd 100644 --- a/src/gate/GateDeltaTempGraph.tsx +++ b/src/gate/GateDeltaTempGraph.tsx @@ -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 { @@ -190,7 +189,7 @@ export default function GateDeltaTempGraph(props: Props){ {"Delta Temp: "} 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")}
@@ -211,10 +210,12 @@ export default function GateDeltaTempGraph(props: Props){ } /> diff --git a/src/gate/GateDeviceInteraction.tsx b/src/gate/GateDeviceInteraction.tsx index 0303123..aa2e8a0 100644 --- a/src/gate/GateDeviceInteraction.tsx +++ b/src/gate/GateDeviceInteraction.tsx @@ -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; @@ -100,7 +98,6 @@ export default function GateDeviceInteraction(props: Props) { } else if ( gate.preferences[component.key()] === pond.GateComponentType.GATE_COMPONENT_TYPE_PRESSURE ) { - console.log(component) setPressureComponent(component); setPressureSource( quack.ComponentID.create({ @@ -186,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 } } @@ -346,8 +343,8 @@ export default function GateDeviceInteraction(props: Props) { when the difference between the pressures falls within this range and vice versa:
- Upper Limit: {getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? (highDelta/249.089).toFixed(2) + " iwg" : highDelta/1000 + " kPa"} - Lower Limit: {getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? (lowDelta/249.089).toFixed(2) + " iwg" : lowDelta/1000 + " kPa"} + Upper Limit: {user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? (highDelta/249.089).toFixed(2) + " iwg" : highDelta/1000 + " kPa"} + Lower Limit: {user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? (lowDelta/249.089).toFixed(2) + " iwg" : lowDelta/1000 + " kPa"}
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 @@ -372,7 +369,7 @@ export default function GateDeviceInteraction(props: Props) { InputProps={{ endAdornment: ( - {getPressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? "iwg" : "kPa"} + {user.pressureUnit() === pond.PressureUnit.PRESSURE_UNIT_INCHES_OF_WATER ? "iwg" : "kPa"} ) }} diff --git a/src/gate/GateGraphs.tsx b/src/gate/GateGraphs.tsx index b2ec455..5a3a039 100644 --- a/src/gate/GateGraphs.tsx +++ b/src/gate/GateGraphs.tsx @@ -282,13 +282,13 @@ export default function GateGraphs(props: Props) { if (um.values[0] && um.values[0].values.length > 1) { return areaGraph( um, - describeMeasurement(um.type, component.type(), component.subType()), + describeMeasurement(um.type, component.type(), component.subType(), undefined, user), component.settings.smoothingAverages ); } else { return lineGraph( um, - describeMeasurement(um.type, component.type(), component.subType()), + describeMeasurement(um.type, component.type(), component.subType(), undefined, user), component.settings.smoothingAverages ); } diff --git a/src/gate/GateList.tsx b/src/gate/GateList.tsx index 5910808..ba521cc 100644 --- a/src/gate/GateList.tsx +++ b/src/gate/GateList.tsx @@ -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" } diff --git a/src/grain/CustomGrainForm.tsx b/src/grain/CustomGrainForm.tsx index a13478c..8d5fd42 100644 --- a/src/grain/CustomGrainForm.tsx +++ b/src/grain/CustomGrainForm.tsx @@ -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")}/> ) } diff --git a/src/grain/GrainTransaction.tsx b/src/grain/GrainTransaction.tsx index 5605b3a..c6b2cfe 100644 --- a/src/grain/GrainTransaction.tsx +++ b/src/grain/GrainTransaction.tsx @@ -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){ diff --git a/src/grainBag/grainBagInventoryGraph.tsx b/src/grainBag/grainBagInventoryGraph.tsx index 6a661a2..969ab3c 100644 --- a/src/grainBag/grainBagInventoryGraph.tsx +++ b/src/grainBag/grainBagInventoryGraph.tsx @@ -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([]); const [loadingData, setLoadingData] = useState(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 diff --git a/src/grainBag/grainBagSettings.tsx b/src/grainBag/grainBagSettings.tsx index cf5f703..1ec5f2d 100644 --- a/src/grainBag/grainBagSettings.tsx +++ b/src/grainBag/grainBagSettings.tsx @@ -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); diff --git a/src/grainBag/grainBagVisualizer.tsx b/src/grainBag/grainBagVisualizer.tsx index 1d0b5d8..319ad39 100644 --- a/src/grainBag/grainBagVisualizer.tsx +++ b/src/grainBag/grainBagVisualizer.tsx @@ -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(); 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 (
@@ -157,7 +158,7 @@ export default function GrainBagVisualizer(props: Props) { ({grainBag.fillPercent()}%)
); - } else if (getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1) { + } else if (user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && grainBag.bushelsPerTonne() > 1) { return (
diff --git a/src/interactions/InteractionSettings.tsx b/src/interactions/InteractionSettings.tsx index 87bdf98..4f2a2d3 100644 --- a/src/interactions/InteractionSettings.tsx +++ b/src/interactions/InteractionSettings.tsx @@ -195,7 +195,9 @@ export default function InteractionSettings(props: Props) { let value = describeMeasurement( condition.measurementType, or(initialComponent, Component.create()).settings.type, - or(initialComponent, Component.create()).settings.subtype + or(initialComponent, Component.create()).settings.subtype, + undefined, + user ).toDisplay(condition.value); rawConditionValues.push(value.toString()); }); @@ -425,7 +427,7 @@ export default function InteractionSettings(props: Props) { mappedComponents.get(componentIDToString(interaction.settings.source)), Component.create() ); - return describeMeasurement(measurementType, source.settings.type, source.settings.subtype); + return describeMeasurement(measurementType, source.settings.type, source.settings.subtype, undefined, user); }; const describeSink = (): MeasurementDescriber => { @@ -433,7 +435,9 @@ export default function InteractionSettings(props: Props) { return describeMeasurement( Measurement.boolean, or(sink, Component.create()).settings.type, - or(sink, Component.create()).settings.subtype + or(sink, Component.create()).settings.subtype, + undefined, + user ); }; @@ -861,7 +865,7 @@ export default function InteractionSettings(props: Props) { const conditionGroup = (index: number) => { if (index >= numConditions) return; let measurementType = interaction.settings.conditions[index].measurementType; - let source = describeSource(measurementType); + let source = describeSource(measurementType, ); let isBoolean = isBooleanValue(index); return ( diff --git a/src/interactions/InteractionsOverview.tsx b/src/interactions/InteractionsOverview.tsx index 127f2a6..600c88a 100644 --- a/src/interactions/InteractionsOverview.tsx +++ b/src/interactions/InteractionsOverview.tsx @@ -71,7 +71,7 @@ interface Props { export default function InteractionsOverview(props: Props) { const classes = useStyles(); - const [{as}] = useGlobalState(); + const [{as, user}] = useGlobalState(); const interactionsAPI = useInteractionsAPI(); const { success, error } = useSnackbar(); const { device, component, components, permissions, refreshCallback } = props; @@ -118,12 +118,12 @@ export default function InteractionsOverview(props: Props) { if (!conditions) return items; conditions.forEach((condition: pond.IInteractionCondition, conditionIndex: number) => { let measurementType = condition.measurementType; - let measurement = describeMeasurement(condition.measurementType, sourceType, sourceSubtype); + let measurement = describeMeasurement(condition.measurementType, sourceType, sourceSubtype, undefined, user); items.push( - {interactionConditionText(source, condition, conditionIndex > 0)} + {interactionConditionText(source, condition, conditionIndex > 0, user)} @@ -185,7 +185,7 @@ export default function InteractionsOverview(props: Props) { let condition = conditions[conditionIndex]; let sourceType = source && source.settings.type; let sourceSubtype = source && source.settings.subtype; - let describer = describeMeasurement(condition.measurementType, sourceType, sourceSubtype); + let describer = describeMeasurement(condition.measurementType, sourceType, sourceSubtype, undefined, user); condition.value = describer.toStored(value); updatedDirtyInteractions.set(interactionIndex, true); } diff --git a/src/maps/MapBase.tsx b/src/maps/MapBase.tsx index fa4c9c2..a5cc0c7 100644 --- a/src/maps/MapBase.tsx +++ b/src/maps/MapBase.tsx @@ -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) }; diff --git a/src/maps/mapDrawers/FieldDrawer.tsx b/src/maps/mapDrawers/FieldDrawer.tsx index ae7a794..07adbf9 100644 --- a/src/maps/mapDrawers/FieldDrawer.tsx +++ b/src/maps/mapDrawers/FieldDrawer.tsx @@ -14,7 +14,6 @@ import DisplayDrawer from "common/DisplayDrawer"; import HarvestPlanDisplay from "harvestPlan/HarvestPlanDisplay"; import { Field, fieldScope, HarvestPlan, teamScope } from "models"; import React, { useEffect, useState } from "react"; -import TaskViewer from "tasks/TaskViewer"; import Weather from "weather/weather"; import { getThemeType } from "theme"; import GrainDescriber from "grain/GrainDescriber"; @@ -24,6 +23,7 @@ import { useMobile } from "hooks"; import { useGlobalState, useHarvestPlanAPI, useUserAPI } from "providers"; import { makeStyles } from "@mui/styles"; import FieldActions from "field/FieldActions"; +import FieldTaskList from "field/FieldTaskList"; interface TabPanelProps { children?: React.ReactNode; @@ -218,7 +218,7 @@ export default function FieldDrawer(props: Props) { TabIndicatorProps={{ style: { background: "rgba(255,255,0,255)" } }}> - + @@ -273,7 +273,7 @@ export default function FieldDrawer(props: Props) { - + ); diff --git a/src/models/Bin.ts b/src/models/Bin.ts index e720fec..5ad8635 100644 --- a/src/models/Bin.ts +++ b/src/models/Bin.ts @@ -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 diff --git a/src/models/CO2.ts b/src/models/CO2.ts index 62e5d73..fcb1ed5 100644 --- a/src/models/CO2.ts +++ b/src/models/CO2.ts @@ -3,8 +3,6 @@ import { quack } from "protobuf-ts/pond"; import { or } from "utils/types"; import { clone, cloneDeep } from "lodash"; import { Component } from "models"; -import { describeMeasurement } from "pbHelpers/MeasurementDescriber"; -import { extractGrainCable } from "pbHelpers/ComponentTypes"; export class CO2 { public settings: pond.ComponentSettings = pond.ComponentSettings.create(); diff --git a/src/models/Contract.ts b/src/models/Contract.ts index ce55093..81bc001 100644 --- a/src/models/Contract.ts +++ b/src/models/Contract.ts @@ -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,26 +15,28 @@ 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){ - return "mT" - } - if(getGrainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.conversionValue() > 1){ - return "t" + if( user ){ + if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TONNE && this.conversionValue() > 1){ + return "mT" + } + if(user.grainUnit() === pond.GrainUnit.GRAIN_UNIT_TON && this.conversionValue() > 1){ + return "t" + } } return "bu"; } @@ -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; } } diff --git a/src/models/UnitMeasurement.ts b/src/models/UnitMeasurement.ts index d33c17d..9fc3a42 100644 --- a/src/models/UnitMeasurement.ts +++ b/src/models/UnitMeasurement.ts @@ -32,7 +32,7 @@ export class UnitMeasurement { public static create(pb?: pond.UnitMeasurementsForComponent, user?: User): UnitMeasurement { let my = new UnitMeasurement(); if (pb) { - let describer = describeMeasurement(pb.type, pb.componentType); + let describer = describeMeasurement(pb.type, pb.componentType, undefined, undefined, user); let values = pb.values; if (user) { values = unitConversion(pb.values, pb.type, user); diff --git a/src/models/user.ts b/src/models/user.ts index 6c46a31..22bdb26 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -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 + } } diff --git a/src/navigation/BottomNavigator.tsx b/src/navigation/BottomNavigator.tsx index b03a153..6395bd4 100644 --- a/src/navigation/BottomNavigator.tsx +++ b/src/navigation/BottomNavigator.tsx @@ -13,7 +13,7 @@ import BinsIcon from "products/Bindapt/BinsIcon"; import { useGlobalState } from "providers"; import { useCallback, useEffect, useState } from "react"; import { useNavigate, useLocation } from "react-router-dom"; -import { IsAdaptiveAgriculture, isBXT, IsMiVent, IsAdCon, IsOmniAir, IsMiPCA } from "services/whiteLabel"; +import { IsAdaptiveAgriculture, isBXT, IsMiVent, IsAdCon, IsOmniAir, IsMiPCA, IsIntellifarms } from "services/whiteLabel"; import FieldsIcon from "products/AgIcons/FieldsIcon"; import NexusSTIcon from "products/Construction/NexusSTIcon"; import OmniAirDeviceIcon from "products/AviationIcons/OmniAirDeviceIcon"; @@ -36,7 +36,8 @@ export default function BottomNavigator(props: Props) { const { isAuthenticated } = useAuth0(); const [{ user }] = useGlobalState(); const [route, setRoute] = useState(sideIsOpen ? "side" : ""); - const isAdaptive = IsAdaptiveAgriculture(); + const isAg = IsAdaptiveAgriculture(); + const isIntel = IsIntellifarms(); const isMiVent = IsMiVent(); const isAdCon = IsAdCon(); const isOmni = IsOmniAir(); @@ -45,7 +46,7 @@ export default function BottomNavigator(props: Props) { const reRoute = useCallback( (path: string) => { if (path === "") { - if (isAdaptive) { + if (isAg || isIntel) { return "bins"; } if (isMiVent) { @@ -74,7 +75,7 @@ export default function BottomNavigator(props: Props) { } return path; }, - [isAdaptive, isMiVent] + [isAg, isMiVent, isIntel] ); const autoDetectRoute = useCallback(() => { @@ -105,10 +106,10 @@ export default function BottomNavigator(props: Props) { const authenticatedNavigation = () => { return ( handleRouteChange(newValue)}> - {isAdaptive && ( + {isAg || isIntel && ( } value="visualFarm" /> )} - {isAdaptive && ( + {isAg || isIntel && ( } value="bins" /> )} {isAdCon && ( @@ -136,7 +137,7 @@ export default function BottomNavigator(props: Props) { ) : isAdCon ? ( diff --git a/src/navigation/SideNavigator.tsx b/src/navigation/SideNavigator.tsx index 6bab36c..815f30b 100644 --- a/src/navigation/SideNavigator.tsx +++ b/src/navigation/SideNavigator.tsx @@ -27,6 +27,7 @@ import { IsAdaptiveAgriculture, // hasTutorialPlaylist, IsAdCon, + IsIntellifarms, IsMiPCA, // isBXT, IsMiVent, @@ -165,14 +166,15 @@ export default function SideNavigator(props: Props) { const authenticatedSideMenu = () => { const isMiVent = IsMiVent(); - const isAg = IsAdaptiveAgriculture() + const isAg = IsAdaptiveAgriculture() + const isIntel = IsIntellifarms() const isStreamline = IsStreamline() const isOmni = IsOmniAir() const isMiPCA = IsMiPCA() const isAdCon = IsAdCon() return ( - {(isAg || isStreamline || user.hasFeature("admin")) && ( + {(isAg || isIntel || isStreamline || user.hasFeature("admin")) && ( )} - {(isAg || isStreamline || user.hasFeature("admin")) && ( + {(isAg || isIntel || isStreamline || user.hasFeature("admin")) && ( )} - {(isAg || isStreamline || user.hasFeature("admin")) && ( + {(isAg || isIntel || isStreamline || user.hasFeature("admin")) && ( } - {(isAg || isStreamline || user.hasFeature("admin")) && ( + {(isAg || isIntel || isStreamline || user.hasFeature("admin")) && ( } - {(isAg || isStreamline || user.hasFeature("admin")) && ( + {(isAg || isIntel || isStreamline || user.hasFeature("admin")) && ( )} - {(isAg || isStreamline || user.hasFeature("admin")) && ( + {(isAg || isIntel || isStreamline || user.hasFeature("admin")) && ( } - {(isAg || isStreamline || user.hasFeature("admin")) && + {(isAg || isIntel || isStreamline || user.hasFeature("admin")) && { @@ -588,7 +592,9 @@ export default function ObjectHeaterCharts(props: Props) { describer={describeMeasurement( quack.MeasurementType.MEASUREMENT_TYPE_TEMPERATURE, tempHum.type(), - tempHum.subType() + tempHum.subType(), + undefined, + user )} lineData={ambientTemps} numLines={1} diff --git a/src/objects/ObjectDescriber.tsx b/src/objects/ObjectDescriber.tsx index 643482a..ccd29ac 100644 --- a/src/objects/ObjectDescriber.tsx +++ b/src/objects/ObjectDescriber.tsx @@ -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[]; + // Optional factory so columns can depend on the active user settings (units, formatting, etc.) + getTableColumns?: (user?: User) => Column[]; //this map will match the title of the column to what the backend needs to perform the ordering tableSort: Map; } @@ -32,6 +32,202 @@ const defaultObject: ObjectExtension = { tableSort: new Map() }; +const binColumns = (user?: User): Column[] => { + const temperatureUnit = + user?.tempUnit() ?? pond.TemperatureUnit.TEMPERATURE_UNIT_CELSIUS; + + return [ + { + title: "Name", + cellStyle: {padding: "16px"}, + render: row => { + return (
{row.settings.name}
); + } + }, + { + title: "Grain", + cellStyle: {padding: "16px"}, + render: row => { + let grain = row.settings.inventory?.grainType; + if (grain) { + return GrainDescriber(grain).name; + } + } + }, + { + title: "Bin Height", + cellStyle: {padding: "16px"}, + render: row => { + let d = row.settings.specs?.heightCm; + if (d) { + if ( + (user?.distanceUnit() ?? pond.DistanceUnit.DISTANCE_UNIT_FEET) === + pond.DistanceUnit.DISTANCE_UNIT_METERS + ) { + return (d / 100).toFixed(2) + " m"; + } else { + return (d / 30.48).toFixed(2) + " ft"; + } + } + } + }, + { + title: "Bin Diameter", + cellStyle: {padding: "16px"}, + render: row => { + let d = row.settings.specs?.diameterCm; + if (d) { + if ( + (user?.distanceUnit() ?? pond.DistanceUnit.DISTANCE_UNIT_FEET) === + pond.DistanceUnit.DISTANCE_UNIT_METERS + ) { + return (d / 100).toFixed(2) + " m"; + } else { + return (d / 30.48).toFixed(2) + " ft"; + } + } + } + }, + { + title: "Custom Grain Name", + cellStyle: {padding: "16px"}, + render: row => { + return row.settings.inventory?.customTypeName; + } + }, + { + title: "Grain Variant", + cellStyle: {padding: "16px"}, + render: row => { + return row.settings.inventory?.grainSubtype; + } + }, + { + title: "Grain Bushels", + cellStyle: {padding: "16px"}, + render: row => { + return (
{row.settings.inventory ? isNaN(row.settings.inventory.grainBushels) ? 0 : row.settings.inventory.grainBushels : 0}
); + } + }, + { + title: "Grain Capacity", + cellStyle: {padding: "16px"}, + render: row => { + return row.settings.specs?.bushelCapacity; + } + }, + { + title: "High Temp Warning", + cellStyle: {padding: "16px"}, + render: row => { + let t = row.settings.highTemp; + if (t) { + if (temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) { + return (t * 1.8 + 32).toFixed(2) + " °F"; + } + return t.toFixed(2) + " °C"; + } + } + }, + { + title: "Low Temp Warning", + cellStyle: {padding: "16px"}, + render: row => { + let t = row.settings.lowTemp; + if (t) { + if (temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) { + return (t * 1.8 + 32).toFixed(2) + " °F"; + } + return t.toFixed(2) + " °C"; + } + } + } + ] as Column[]; +}; + +const grainBagColumns = (user?: User): Column[] => { + const distanceUnit = + user?.distanceUnit() ?? pond.DistanceUnit.DISTANCE_UNIT_FEET; + return [ + { + title: "Name", + render: row => { + if (row.title) { + return (
{row.title.toString()}
); + } + } + }, + { + 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[]; +}; + export const ObjectExtensions: Map = new Map([ [pond.ObjectType.OBJECT_TYPE_UNKNOWN, defaultObject], [ @@ -50,109 +246,8 @@ export const ObjectExtensions: Map = new Map([ name: "Bin", inventoryGroup: "grain", isTransactionObject: true, - tableColumns: [ - { - title: "Name", - cellStyle: {padding: "16px"}, - render: row => { - return (
{row.settings.name}
); - } - }, - { - title: "Grain", - cellStyle: {padding: "16px"}, - render: row => { - let grain = row.settings.inventory?.grainType; - if (grain) { - return GrainDescriber(grain).name; - } - } - }, - { - title: "Bin Height", - cellStyle: {padding: "16px"}, - render: row => { - let d = row.settings.specs?.heightCm; - if (d) { - if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) { - return (d / 100).toFixed(2) + " m"; - } else { - return (d / 30.48).toFixed(2) + " ft"; - } - } - } - }, - { - title: "Bin Diameter", - cellStyle: {padding: "16px"}, - render: row => { - let d = row.settings.specs?.diameterCm; - if (d) { - if (getDistanceUnit() === pond.DistanceUnit.DISTANCE_UNIT_METERS) { - return (d / 100).toFixed(2) + " m"; - } else { - return (d / 30.48).toFixed(2) + " ft"; - } - } - } - }, - { - title: "Custom Grain Name", - cellStyle: {padding: "16px"}, - render: row => { - return row.settings.inventory?.customTypeName; - } - }, - { - title: "Grain Variant", - cellStyle: {padding: "16px"}, - render: row => { - return row.settings.inventory?.grainSubtype; - } - }, - { - title: "Grain Bushels", - cellStyle: {padding: "16px"}, - render: row => { - return (
{row.settings.inventory ? isNaN(row.settings.inventory.grainBushels) ? 0 : row.settings.inventory.grainBushels : 0}
); - } - }, - { - title: "Grain Capacity", - cellStyle: {padding: "16px"}, - render: row => { - return row.settings.specs?.bushelCapacity; - } - }, - { - title: "High Temp Warning", - cellStyle: {padding: "16px"}, - render: row => { - let t = row.settings.highTemp; - if (t) { - if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) { - return (t * 1.8 + 32).toFixed(2) + " °F"; - } else { - return t.toFixed(2) + " °C"; - } - } - } - }, - { - title: "Low Temp Warning", - cellStyle: {padding: "16px"}, - render: row => { - let t = row.settings.lowTemp; - if (t) { - if (getTemperatureUnit() === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) { - return (t * 1.8 + 32).toFixed(2) + " °F"; - } else { - return t.toFixed(2) + " °C"; - } - } - } - } - ] as Column[], + 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 = new Map([ name: "Grainbag", inventoryGroup: "grain", isTransactionObject: true, - tableColumns: [ - { - title: "Name", - render: row => { - if (row.title) { - return (
{row.title.toString()}
); - } - } - }, - { - 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[], + 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 = 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 diff --git a/src/objects/ObjectTable.tsx b/src/objects/ObjectTable.tsx index 7a7b677..2ef6c86 100644 --- a/src/objects/ObjectTable.tsx +++ b/src/objects/ObjectTable.tsx @@ -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(as ?? user.id()); const [selectedPageRows, setSelectedPageRows] = useState>(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) { { 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); diff --git a/src/objects/bulkEditForms/bulkBinSettings.tsx b/src/objects/bulkEditForms/bulkBinSettings.tsx index f3e01a9..f953def 100644 --- a/src/objects/bulkEditForms/bulkBinSettings.tsx +++ b/src/objects/bulkEditForms/bulkBinSettings.tsx @@ -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(); - const [{as}] = useGlobalState(); + const [{as, user}] = useGlobalState(); const [grainType, setGrainType] = useState(); const [grainOption, setGrainOption] = useState
- setMenuAnchorEl(event.currentTarget)}> - + */} + completeTask(t)} + permissions={permissions} + task={task} + removeTask={deleteTask} + refreshCallback={() => { + closeCallback(true) + }} + keys={props.keys} + types={props.types} + /> @@ -303,7 +291,7 @@ export default function TaskDrawer(props: Props) { {taskTime()} {assignees()} - {taskActions()} + {/* {taskActions()} */} {noteDrawer()} ); @@ -316,7 +304,9 @@ export default function TaskDrawer(props: Props) { displayNext={() => {}} displayPrev={() => {}} drawerBody={drawerBody()} - onClose={closeCallback} + onClose={() => { + closeCallback(false)} + } open={open} /> ); diff --git a/src/tasks/TaskList.tsx b/src/tasks/TaskList.tsx index 6803831..f94f838 100644 --- a/src/tasks/TaskList.tsx +++ b/src/tasks/TaskList.tsx @@ -12,7 +12,6 @@ import ButtonGroup from "common/ButtonGroup"; interface Props { tasks: Task[]; - editTaskMethod: (task: Task) => void; markComplete: (task: Task) => void; deleteTask: (task: Task) => void; openTask: (taskId: string) => void; @@ -20,18 +19,21 @@ interface Props { listHeight?: string | number; label?: string; dateToView?: Date; + keys: string[] + types: string[] } export default function TaskList(props: Props) { const { - editTaskMethod, markComplete, deleteTask, openTask, reLoad, listHeight, label, - dateToView + dateToView, + keys, + types } = props; const [tasks, setTasks] = useState(props.tasks); const [incomplete, setIncomplete] = useState([]); @@ -70,64 +72,16 @@ export default function TaskList(props: Props) { setComplete(complete); }, [tasks, dateToView]); - // const StyledToggleButtonGroup = withStyles(theme => ({ - // grouped: { - // margin: theme.spacing(-0.5), - // border: "none", - // padding: theme.spacing(1), - // "&:not(:first-child):not(:last-child)": { - // borderRadius: 24, - // marginRight: theme.spacing(0.5), - // marginLeft: theme.spacing(0.5) - // }, - // "&:first-child": { - // borderRadius: 24, - // marginLeft: theme.spacing(0.25) - // }, - // "&:last-child": { - // borderRadius: 24, - // marginRight: theme.spacing(0.25) - // } - // }, - // root: { - // backgroundColor: darken( - // theme.palette.background.paper, - // getThemeType() === "light" ? 0.05 : 0.25 - // ), - // borderRadius: 24, - // content: "border-box" - // } - // }))(ToggleButtonGroup); - - // const StyledToggle = withStyles({ - // root: { - // backgroundColor: "transparent", - // overflow: "visible", - // content: "content-box", - // "&$selected": { - // backgroundColor: "gold", - // color: "black", - // borderRadius: 24, - // fontWeight: "bold" - // }, - // "&$selected:hover": { - // backgroundColor: "rgb(255, 255, 0)", - // color: "black", - // borderRadius: 24 - // } - // }, - // selected: {} - // })(ToggleButton); - const incompleteTasks = incomplete.map((task, index) => ( markComplete(task)} deleteTask={(task: Task) => deleteTask(task)} reLoad={reLoad} openTaskPage={(taskId: string) => openTask(taskId)} + keys={keys} + types={types} /> )); @@ -136,11 +90,12 @@ export default function TaskList(props: Props) { markComplete(task)} deleteTask={(task: Task) => deleteTask(task)} reLoad={reLoad} openTaskPage={(taskId: string) => openTask(taskId)} + keys={keys} + types={types} /> )); @@ -162,20 +117,6 @@ export default function TaskList(props: Props) { } ]} /> - {/* - setViewing("upcoming")}> - Upcoming - - setViewing("complete")} - value={"complete"} - aria-label="complete"> - Complete - - */} {location !== "/tasks" && ( diff --git a/src/tasks/TaskSettings.tsx b/src/tasks/TaskSettings.tsx index 9f92548..c2b92ee 100644 --- a/src/tasks/TaskSettings.tsx +++ b/src/tasks/TaskSettings.tsx @@ -2,10 +2,12 @@ import { Avatar, Box, Button, + Checkbox, Dialog, DialogActions, DialogContent, DialogTitle, + FormControlLabel, Grid2 as Grid, InputAdornment, MenuItem, @@ -15,23 +17,24 @@ import moment from "moment"; import React, { useState } from "react"; import { pond } from "protobuf-ts/pond"; import { useGlobalState, useTaskAPI } from "providers"; -import { useSnackbar, useUserAPI } from "hooks"; +import { usePermissionAPI, useSnackbar, useUserAPI } from "hooks"; import { useEffect } from "react"; -import { Task, teamScope, User } from "models"; +import { Task, teamScope, User, userScope } from "models"; import ColourPicker from "common/ColourPicker"; import ResponsiveDialog from "common/ResponsiveDialog"; interface Props { open: boolean; onClose: (reLoad?: boolean) => void; - markComplete?: boolean; startDate?: any; task?: Task; - objectKey?: string; + objectKey?: string; //deprecated, with the new permission structure keys and types will be what determine what a task is connected to type?: string; hasCost?: boolean; costTitle?: string; secondaryCostTitle?: string; + keys?: string[] + types?: string[] } export default function TaskSettings(props: Props) { @@ -45,13 +48,15 @@ export default function TaskSettings(props: Props) { const [worker, setWorker] = useState(user.id()); const [colour, setColour] = useState(""); const taskAPI = useTaskAPI(); + const userAPI = useUserAPI(); + const permissionAPI = usePermissionAPI(); const { openSnack } = useSnackbar(); const [cost, setCost] = useState(""); const [secondaryCost, setSecondaryCost] = useState(""); const [seedCost, setSeedCost] = useState(""); const [poundPerAcre, setPoundPerAcre] = useState(0); - const userAPI = useUserAPI(); const [users, setUsers] = useState([]); + const [shareToCreator, setShareToCreator] = useState(true) useEffect(() => { if (props.task) { @@ -104,7 +109,7 @@ export default function TaskSettings(props: Props) { startTime: startTime, end: endDate, endTime: endTime, - objectKey: props.objectKey ? props.objectKey : user.id(), + objectKey: props.objectKey ? props.objectKey : user.id(), //deprecated description: taskDescription, worker: worker, complete: false, @@ -120,8 +125,24 @@ export default function TaskSettings(props: Props) { returnTask.settings = taskSettings; taskAPI - .addTask(taskSettings, as) + .addTask(taskSettings, as, props.keys, props.types) .then(resp => { + console.log(resp) + if(shareToCreator && resp.data.task){ + let parentScope = userScope(user.id()) + if(as){ + parentScope = teamScope(as) + } + + permissionAPI.shareObjectByKey( + {key: resp.data.task, kind: "task"}, + parentScope.key, + parentScope.kind, + [pond.Permission.PERMISSION_READ, pond.Permission.PERMISSION_WRITE, pond.Permission.PERMISSION_USERS, pond.Permission.PERMISSION_SHARE], + props.keys, + props.types + ) + } props.onClose(true); }) .catch(err => { @@ -318,6 +339,18 @@ export default function TaskSettings(props: Props) { value={endTime} onChange={e => setEndTime(e.target.value)} /> + {props.keys && props.types && !props.task && + setShareToCreator(e.target.checked)} + color="primary" + /> + } + label={"Share task with " + (as ? "team" : "user")} + /> + } Colour setColour(color)} /> diff --git a/src/tasks/TaskViewer.tsx b/src/tasks/TaskViewer.tsx index 12e82d7..b283c5f 100644 --- a/src/tasks/TaskViewer.tsx +++ b/src/tasks/TaskViewer.tsx @@ -26,10 +26,12 @@ import moment from "moment"; import { makeStyles } from "@mui/styles"; interface ViewProps { - objectKey?: string; //only used to save it for the object + // objectKey?: string; //only used to save it for the object --Deprecated with new permission structure-- + keys?: string[]//the keys and types are used to give th object permissions to the task, that is how they will be linked now + types?: string[] label?: string; drawerView?: boolean; - loadKeys?: string[]; //if you want to load tasks for a specific object(s) + // loadKeys?: string[]; //if you want to load tasks for a specific object(s) --Deprecated with new permission structure-- it should use the keys and types now overlayButton?: boolean; } @@ -87,9 +89,16 @@ const useStyles = makeStyles((theme: Theme) => { }); export default function TaskViewer(props: ViewProps) { - const { objectKey, label, drawerView, loadKeys, overlayButton } = props; + const { + //objectKey, + label, + drawerView, + //loadKeys, + keys, + types, + overlayButton + } = props; const [{ user, as }] = useGlobalState(); - //const [{ as }] = useGlobalState(); const taskAPI = useTaskAPI(); const { openSnack } = useSnackbar(); const [tasks, setTasks] = useState>(new Map([])); @@ -137,42 +146,12 @@ export default function TaskViewer(props: ViewProps) { } }; - const setTaskToEdit = (task: Task) => { - setEditTask(task); - openDialog(); - }; - - - const loadMultitask = useCallback(() => { - if (!loadKeys) return; - if (loadKeys.length > 0) { - let temp = new Map(); - setLoaded(false); - taskAPI - .getMultiTasks(loadKeys, as) - .then(resp => { - if(resp.data.tasks){ - resp.data.tasks.forEach(task => { - if (task.settings) { - temp.set(task.key, Task.any(task)); - } - }); - } - setTasks(temp); - setLoaded(true); - }) - .catch(err => { - openSnack("Failed to load"); - }); - } - }, [loadKeys, openSnack, taskAPI, as]); - //loads tasks from the backend database const loadTasks = useCallback(() => { if (!user.id()) return; let temp = new Map(); taskAPI - .listTasks(50, 0, "asc", "start", undefined, undefined, as, prevMonth, nextMonth) + .listTasks(50, 0, "asc", "start", undefined, undefined, as, prevMonth, nextMonth, keys, types) .then(resp => { if(resp.data.tasks){ resp.data.tasks.forEach(task => { @@ -185,20 +164,20 @@ export default function TaskViewer(props: ViewProps) { setLoaded(true); }) .catch(err => { - console.log(err) openSnack("Failed to load tasks"); }); - }, [taskAPI, as, user, openSnack, nextMonth, prevMonth]); + }, [taskAPI, as, user, openSnack, nextMonth, prevMonth, keys, types]); useEffect(() => { - if (drawerView) { - setTasks(new Map()); - setValue(1); - loadMultitask(); - } else { - loadTasks(); - } - }, [loadTasks, loadMultitask, as, drawerView]); + // if (drawerView) { + // setTasks(new Map()); + // setValue(1); + // loadMultitask(); + // } else { + // loadTasks(); + // } + loadTasks() + }, [loadTasks, as, drawerView]); const markComplete = (task: Task) => { task.settings.complete = !task.settings.complete; @@ -314,12 +293,13 @@ export default function TaskViewer(props: ViewProps) { loadTasks()} dateToView={drawerView ? undefined : currentDate} openTask={(taskId: string) => openSelectedTask(taskId)} + keys={[]} + types={[]} /> loadTasks()} listHeight={"40vh"} dateToView={currentDate} openTask={(taskId: string) => openSelectedTask(taskId)} + keys={[]} + types={[]} /> @@ -423,16 +404,11 @@ export default function TaskViewer(props: ViewProps) { { - if (r) { - if (drawerView) { - loadMultitask(); - } else { - loadTasks(); - } - } + loadTasks(); setEditTask(undefined); setNewTaskDialog(false); }} @@ -441,10 +417,14 @@ export default function TaskViewer(props: ViewProps) { setOpenDrawer(false)} + closeCallback={() => { + setOpenDrawer(false) + loadTasks() + }} completeTask={markComplete} deleteTask={deleteTask} - editTask={setTaskToEdit} + keys={keys ?? []} + types={types ?? []} /> } diff --git a/src/tasks/taskActions.tsx b/src/tasks/taskActions.tsx new file mode 100644 index 0000000..116cdec --- /dev/null +++ b/src/tasks/taskActions.tsx @@ -0,0 +1,237 @@ +import { + IconButton, + ListItemIcon, + ListItemText, + Menu, + MenuItem, + Theme +} from "@mui/material"; +import { blue } from "@mui/material/colors"; +import MoreIcon from "@mui/icons-material/MoreVert"; +import ObjectTeamsIcon from "@mui/icons-material/SupervisedUserCircle"; +import { pond } from "protobuf-ts/pond"; +import React, { useState } from "react"; +import { isOffline } from "utils/environment"; +import ObjectTeams from "teams/ObjectTeams"; +import { Task, taskScope } from "models"; +import { makeStyles } from "@mui/styles"; +import { Done, Edit } from "@mui/icons-material"; +import DeleteIcon from "@mui/icons-material/Delete"; +import TaskSettings from "./TaskSettings"; + +const useStyles = makeStyles((theme: Theme) => ({ + shareIcon: { + color: blue["500"], + "&:hover": { + color: blue["600"] + } + }, + removeIcon: { + color: "var(--status-alert)" + }, + red: { + color: "var(--status-alert)" + } +})); + +interface Props { + task: Task; + permissions: pond.Permission[]; + keys: string[] + types: string[] + refreshCallback: () => void; + markComplete: (task: Task) => void; + removeTask: (task: Task) => void; +} + +interface OpenState { + // share: boolean; + // users: boolean; + teams: boolean; + settings: boolean; + // removeSelf: boolean; + delete: boolean +} + +export default function TaskActions(props: Props) { + const classes = useStyles(); + const { task, permissions, refreshCallback, keys, types } = props; + const [anchorEl, setAnchorEl] = React.useState(null); + const [openState, setOpenState] = useState({ + // share: false, + // users: false, + teams: false, + settings: false, + // removeSelf: false + delete: false + }); + + const groupMenu = () => { + // const canShare = permissions.includes(pond.Permission.PERMISSION_SHARE); + const canEdit = permissions.includes(pond.Permission.PERMISSION_WRITE); + const canManageUsers = permissions.includes(pond.Permission.PERMISSION_USERS); + return ( + setAnchorEl(null)} + keepMounted + disableAutoFocusItem> + {/* {!isOffline() && canShare && ( + { + setOpenState({ ...openState, share: true }); + setAnchorEl(null); + }}> + + + + + + )} */} + {/* {!isOffline() && canManageUsers && ( + { + setOpenState({ ...openState, users: true }); + setAnchorEl(null); + }}> + + + + + + )} */} + {!isOffline() && canEdit && ( + { + props.markComplete(props.task); + setAnchorEl(null); + }}> + + + + + + )} + {!isOffline() && canEdit && ( + { + setOpenState({ ...openState, settings: true }); + setAnchorEl(null); + }}> + + + + + + )} + {!isOffline() && canManageUsers && ( + { + setOpenState({ ...openState, teams: true }); + setAnchorEl(null); + }}> + + + + + + )} + {permissions.includes(pond.Permission.PERMISSION_WRITE) && ( + { + props.removeTask(props.task); + setAnchorEl(null); + }}> + + + + + + )} + {/* { + setOpenState({ ...openState, removeSelf: true }); + setAnchorEl(null); + }}> + + + + + */} + + ); + }; + + const dialogs = () => { + const key = task.key; + // const label = task.title(); + return ( + + {/* setOpenState({ ...openState, share: false })} + /> */} + {/* setOpenState({ ...openState, users: false })} + refreshCallback={refreshCallback} + /> */} + {/* setOpenState({ ...openState, removeSelf: false })} + /> */} + setOpenState({ ...openState, teams: false })} + keys={keys} + types={types} + /> + { + setOpenState({ ...openState, settings: false}) + if(r){ + refreshCallback() + } + }} + /> + + ); + }; + + return ( + + ) => setAnchorEl(event.currentTarget)}> + + + {groupMenu()} + {dialogs()} + + ); +} \ No newline at end of file diff --git a/src/teams/ObjectTeams.tsx b/src/teams/ObjectTeams.tsx index d327291..2e0c610 100644 --- a/src/teams/ObjectTeams.tsx +++ b/src/teams/ObjectTeams.tsx @@ -41,6 +41,8 @@ import { useNavigate } from "react-router-dom"; import { makeStyles } from "@mui/styles"; import { Share, RemoveCircle as RemoveUserIcon } from "@mui/icons-material"; import CancelSubmit from "common/CancelSubmit"; +import { permissionToString } from "pbHelpers/Permission"; +import { PermissionChanges } from "providers/pond/permissionAPI"; const useStyles = makeStyles((theme: Theme) => { const avatarBG = theme.palette.secondary["700" as keyof PaletteColor]; @@ -100,6 +102,9 @@ interface Props { userCallback?: (users?: User[] | Team[] | undefined) => void; dialog?: string; cardMode?: boolean; + keys?: string[]; + types?: string[]; + shareLabel?: string; // a custom label to pass in that will replace the share icon } export default function ObjectTeams(props: Props) { @@ -120,7 +125,10 @@ export default function ObjectTeams(props: Props) { refreshCallback, userCallback, dialog, - cardMode + cardMode, + keys, + types, + shareLabel } = props; const prevPermissions = usePrevious(permissions); const prevIsDialogOpen = usePrevious(isDialogOpen); @@ -146,7 +154,7 @@ export default function ObjectTeams(props: Props) { const load = useCallback(() => { setIsLoading(true); teamAPI - .listObjectTeams(scope, as) + .listObjectTeams(scope, as, keys, types) .then((response: any) => { let rTeams: Team[] = []; or(response.data, { teams: [] }).teams.forEach((user: any) => { @@ -184,7 +192,21 @@ export default function ObjectTeams(props: Props) { }; const submit = () => { - permissionAPI + if(keys && types){ + let changes: PermissionChanges[] = [] + users.forEach((user: Team) => { + changes.push({ + key: user.id(), + permissions: user.permissions.map(permission => permissionToString(permission)) + }); + }); + permissionAPI.updateObjectPermissions(scope.key, scope.kind, "team", changes, keys, types).then(resp => { + console.log("no error") + }).catch(err => { + console.log("error") + }) + }else{ + permissionAPI .updatePermissions(scope, users) .then((_response: any) => { success("Users were sucessfully updated for " + label); @@ -197,10 +219,13 @@ export default function ObjectTeams(props: Props) { }) .catch((err: any) => { err.response.data.error - ? warning(err.response.data.error) - : error("Error occured when updating users for " + label); + ? warning(err.response.data.error) + : error("Error occured when updating users for " + label); close(); }); + + } + }; const changeUserPermissions = (user: pond.ITeam) => (event: any) => { @@ -299,12 +324,18 @@ export default function ObjectTeams(props: Props) { {canShare && ( - - - + {shareLabel ? + + : + + + + } )} @@ -588,6 +619,8 @@ export default function ObjectTeams(props: Props) { permissions={permissions} isDialogOpen={isShareObjectDialogOpen} closeDialogCallback={closeShareObjectDialog} + keys={keys} + types={types} /> ); diff --git a/src/teams/ShareWithTeam.tsx b/src/teams/ShareWithTeam.tsx index 070a8c7..ffda3f0 100644 --- a/src/teams/ShareWithTeam.tsx +++ b/src/teams/ShareWithTeam.tsx @@ -88,6 +88,8 @@ interface Props { permissions: pond.Permission[]; isDialogOpen: boolean; closeDialogCallback: Function; + keys?: string[], + types?: string[] } export default function ShareObject(props: Props) { @@ -96,7 +98,7 @@ export default function ShareObject(props: Props) { const classes = useStyles(); const permissionAPI = usePermissionAPI(); const { info, success } = useSnackbar(); - const { scope, label, permissions, isDialogOpen, closeDialogCallback } = props; + const { scope, label, permissions, isDialogOpen, closeDialogCallback, keys, types } = props; const [sharedPermissions, setSharedPermissions] = useState([ pond.Permission.PERMISSION_READ ]); @@ -109,7 +111,8 @@ export default function ShareObject(props: Props) { const [teamKey, setTeamKey] = useState(""); const share = () => { - permissionAPI.shareObjectByKey(scope, teamKey, sharedPermissions).then(resp => { + + permissionAPI.shareObjectByKey(scope, teamKey, "team", sharedPermissions, keys, types).then(resp => { let shareBins = true; if (resp && resp.data && resp.data.existing) { success(label + " was shared with team"); @@ -123,7 +126,7 @@ export default function ShareObject(props: Props) { resp.data.bins.forEach(bin => { if (bin.settings) { let newScope = binScope(bin.settings?.key); - permissionAPI.shareObjectByKey(newScope, teamKey, sharedPermissions).catch(_err => { + permissionAPI.shareObjectByKey(newScope, teamKey, "team", sharedPermissions, keys, types).catch(_err => { successBins = false; }); } @@ -143,7 +146,7 @@ export default function ShareObject(props: Props) { resp.data.gates.forEach(gate => { if (gate) { let newScope = { key: gate.key, kind: "gate" } as Scope; - permissionAPI.shareObjectByKey(newScope, teamKey, sharedPermissions).catch(_err => { + permissionAPI.shareObjectByKey(newScope, teamKey, "team", sharedPermissions, keys, types).catch(_err => { successGates = false; }); } diff --git a/src/transactions/transactionDataDisplay.tsx b/src/transactions/transactionDataDisplay.tsx index b64db64..3bd6220 100644 --- a/src/transactions/transactionDataDisplay.tsx +++ b/src/transactions/transactionDataDisplay.tsx @@ -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 diff --git a/src/user/ObjectUsers.tsx b/src/user/ObjectUsers.tsx index e3221c2..981a838 100644 --- a/src/user/ObjectUsers.tsx +++ b/src/user/ObjectUsers.tsx @@ -108,6 +108,7 @@ interface Props { dialog?: string; cardMode?: boolean; useImitation?: boolean; + shareLabel?: string; // s string to replace the share icon button with a labelled button } export default function ObjectUsers(props: Props) { @@ -127,8 +128,9 @@ export default function ObjectUsers(props: Props) { refreshCallback, userCallback, dialog, - cardMode + cardMode, //useImitation + shareLabel } = props; const prevPermissions = usePrevious(permissions); const prevIsDialogOpen = usePrevious(isDialogOpen); @@ -367,11 +369,17 @@ export default function ObjectUsers(props: Props) { {canShare && ( - + {shareLabel} + + : + - - + + + } )} diff --git a/src/utils/units.ts b/src/utils/units.ts index 41b3601..075a9e1 100644 --- a/src/utils/units.ts +++ b/src/utils/units.ts @@ -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;