diff --git a/README.md b/README.md index 74872fd..b7a7555 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,43 @@ Currently, two official plugins are available: - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh +### White-labeling + +Steps to add a new white label + +1. Client Instructions: + +- supply assets and colours to be used for the white-label (favicon if necessary) +- determine a sub-domain to use as mask, dashboard is preferred (ex: dashboard.example.com) +- 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) + + +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) + +- 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 + + +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 + +7. Create a new `Auth0` application for the client + - 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) + - 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 If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: diff --git a/package-lock.json b/package-lock.json index 17726ba..24be34b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,11 @@ "mui-tel-input": "^7.0.0", "notistack": "^3.0.1", "openweathermap-ts": "^1.2.10", +<<<<<<< HEAD "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#dev", +======= + "protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging", +>>>>>>> messages_overhaul "query-string": "^9.2.1", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", @@ -11967,7 +11971,11 @@ }, "node_modules/protobuf-ts": { "version": "1.0.0", +<<<<<<< HEAD "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#bcf085706791036841f7047a5b37f00c18e54574", +======= + "resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#ab9e8d4fd38f9af7802398403d38fddda5eb01da", +>>>>>>> messages_overhaul "dependencies": { "protobufjs": "^6.8.8" } diff --git a/public/MiPCA/android-chrome-192x192.png b/public/MiPCA/android-chrome-192x192.png new file mode 100644 index 0000000..4ed494c Binary files /dev/null and b/public/MiPCA/android-chrome-192x192.png differ diff --git a/public/MiPCA/android-chrome-512x512.png b/public/MiPCA/android-chrome-512x512.png new file mode 100644 index 0000000..72ba797 Binary files /dev/null and b/public/MiPCA/android-chrome-512x512.png differ diff --git a/public/MiPCA/apple-touch-icon.png b/public/MiPCA/apple-touch-icon.png new file mode 100644 index 0000000..c5d4d8b Binary files /dev/null and b/public/MiPCA/apple-touch-icon.png differ diff --git a/public/MiPCA/browserconfig.xml b/public/MiPCA/browserconfig.xml new file mode 100644 index 0000000..b3930d0 --- /dev/null +++ b/public/MiPCA/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/public/MiPCA/favicon-16x16.png b/public/MiPCA/favicon-16x16.png new file mode 100644 index 0000000..f54fc91 Binary files /dev/null and b/public/MiPCA/favicon-16x16.png differ diff --git a/public/MiPCA/favicon-32x32.png b/public/MiPCA/favicon-32x32.png new file mode 100644 index 0000000..48b5897 Binary files /dev/null and b/public/MiPCA/favicon-32x32.png differ diff --git a/public/MiPCA/favicon.ico b/public/MiPCA/favicon.ico new file mode 100644 index 0000000..48e87f6 Binary files /dev/null and b/public/MiPCA/favicon.ico differ diff --git a/public/MiPCA/manifest.json b/public/MiPCA/manifest.json new file mode 100644 index 0000000..d98df92 --- /dev/null +++ b/public/MiPCA/manifest.json @@ -0,0 +1,33 @@ +{ + "name": "MiPCA", + "short_name": "MiPCA", + "icons": [ + { + "src": "favicon.ico", + "sizes": "48x48", + "type": "image/x-icon" + }, + { + "src": "android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "maskable_icon.png", + "sizes": "196x196", + "type": "image/png", + "purpose": "any maskable" + } + ], + "start_url": "/", + "theme_color": "#272727", + "background_color": "#303030", + "display": "standalone", + "orientation": "any" + } + diff --git a/public/MiPCA/mstile-150x150.png b/public/MiPCA/mstile-150x150.png new file mode 100644 index 0000000..d5b8d98 Binary files /dev/null and b/public/MiPCA/mstile-150x150.png differ diff --git a/public/MiPCA/safari-pinned-tab.svg b/public/MiPCA/safari-pinned-tab.svg new file mode 100644 index 0000000..2758652 --- /dev/null +++ b/public/MiPCA/safari-pinned-tab.svg @@ -0,0 +1,50 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + + + + + + diff --git a/src/app/UserWrapper.tsx b/src/app/UserWrapper.tsx index 9ead445..e69ea85 100644 --- a/src/app/UserWrapper.tsx +++ b/src/app/UserWrapper.tsx @@ -13,7 +13,7 @@ import { CssBaseline, Theme } from '@mui/material' import { AppThemeProvider } from 'theme/AppThemeProvider' import HTTPProvider from 'providers/http' import { Crisp } from "crisp-sdk-web"; -import { useSnackbar } from 'hooks' +import { useMobile, useSnackbar } from 'hooks' // import FirmwareLoader from './FirmwareLoader' const reducer = (state: GlobalState, action: GlobalStateAction): GlobalState => { @@ -67,6 +67,7 @@ export default function UserWrapper(props: Props) { const hasFetched = useRef(false); const [global, setGlobal] = useState(undefined) const snackbar = useSnackbar() + const isMobile = useMobile() const user_id = or(useAuth.user?.sub, "") @@ -128,6 +129,54 @@ export default function UserWrapper(props: Props) { Crisp.setTokenId(global?.user.id()); // e.g., your DB user ID } }, [global]); + + // useEffect(() => { + // if (window.$crisp) { + // if (isMobile) { + // $crisp.push(["config", "position:offset", [20, 120]]); + // } else { + // $crisp.push(["config", "position:offset", [20, 20]]); + // } + // } + // }, [isMobile]); + + // useEffect(() => { + // console.log("crisb") + // const crispEl = document.getElementById("crisp-chatbox"); + // console.log(crispEl) + // if (crispEl) { + // if (isMobile) { + // console.log("setting margin") + // crispEl.style.setProperty("margin-bottom", "180px", "important"); + // } else { + // crispEl.style.setProperty("margin-bottom", "0px", "important"); + // } + // } + // }, [isMobile]); + + useEffect(() => { + let style = document.getElementById("crisp-offset-override"); + if (!style) { + style = document.createElement("style"); + style.id = "crisp-offset-override"; + document.head.appendChild(style); + } + + if (isMobile) { + style.textContent = ` + #crisp-chatbox [aria-label="Open chat"] { + bottom: 6em !important; + } + // #crisp-chatbox [data-visible][style*="width: 360px"] { + // bottom: 180px !important; + // } + `; + } else { + style.textContent = ""; + } + + return () => style?.remove(); + }, [isMobile]); useEffect(() => { if (loading) return; diff --git a/src/assets/whitelabels/MiPCA/MiPCALogo.png b/src/assets/whitelabels/MiPCA/MiPCALogo.png new file mode 100644 index 0000000..c828035 Binary files /dev/null and b/src/assets/whitelabels/MiPCA/MiPCALogo.png differ diff --git a/src/bin/BinSettings.tsx b/src/bin/BinSettings.tsx index 69e0510..4192974 100644 --- a/src/bin/BinSettings.tsx +++ b/src/bin/BinSettings.tsx @@ -65,7 +65,7 @@ import { getDistanceUnit, or, getTemperatureUnit, getGrainUnit } from "utils"; import { makeStyles } from "@mui/styles"; import { useNavigate } from "react-router-dom"; import BinSelector from "./BinSelector"; -import CustomGrainForm from "grain/CustomGrainForm"; +import CustomGrainSelector from "grain/CustomGrainSelector"; // import BinSelector from "./BinSelector"; const useStyles = makeStyles((theme: Theme) => { @@ -1054,7 +1054,7 @@ export default function BinSettings(props: Props) { : - {setCustomGrain(newGrainSettings)}}/> + {setCustomGrain(newGrainSettings)}}/> } diff --git a/src/bin/BinVisualizerV2.tsx b/src/bin/BinVisualizerV2.tsx index f1addd8..9997927 100644 --- a/src/bin/BinVisualizerV2.tsx +++ b/src/bin/BinVisualizerV2.tsx @@ -70,7 +70,7 @@ import Edit from "@mui/icons-material/Edit"; import { makeStyles } from "@mui/styles"; import ButtonGroup from "common/ButtonGroup"; import ModeChangeDialog from "./conditioning/modeChangeDialog"; -import CustomGrainForm from "grain/CustomGrainForm"; +import CustomGrainSelector from "grain/CustomGrainSelector"; const useStyles = makeStyles((theme: Theme) => { return ({ @@ -332,14 +332,23 @@ export default function BinVisualizer(props: Props) { setNewGrainSettings(bin.customGrain()); } if (bin.settings) { - let t = bin.settings.outdoorTemp; + let t = 0 + let h = 0 + if(ambient){ + t = ambient.temperature + h = ambient.humidity + }else{ + t = bin.settings.outdoorTemp;//use what is already set in the bin settings + h = bin.settings.outdoorHumidity + } + if (user.settings.temperatureUnit === pond.TemperatureUnit.TEMPERATURE_UNIT_FAHRENHEIT) { t = CtoF(t); } setOutdoorTemp(t); + setOutdoorHumidity(h) } - if (bin.settings) setOutdoorHumidity(bin.settings.outdoorHumidity); - }, [bin, user]); + }, [bin, user, ambient]); useEffect(() => { //if(loadingTrend) return @@ -861,7 +870,7 @@ export default function BinVisualizer(props: Props) { className={classes.bottomSpacing} /> )} */} - {setNewGrainSettings(settings)}}/> + {setNewGrainSettings(settings)}}/> ) : ( { if (bin.settings.inventory?.empty === true) return null; + const canEdit = permissions ? permissions.includes(pond.Permission.PERMISSION_WRITE) : false; return ( { setGrainUpdate(true); }} style={{ margin: "auto", - backgroundColor: "gold", + backgroundColor: canEdit ? "gold" : "grey", color: "black", height: "100%", width: isMobile ? 35 : 40 @@ -1459,6 +1470,7 @@ export default function BinVisualizer(props: Props) { alignContent="flex-end"> {fillPercentage !== null && ( { refresh(); }); @@ -2025,8 +2037,8 @@ export default function BinVisualizer(props: Props) { if(refresh) updateBin(); }} defaultTargetMoisture={bin.settings.inventory?.initialMoisture} - // defaultOutdoorTemp={get this from any ambient sensors} - // defaultOutdoorHumidity={get this from any ambient sensors} + defaultOutdoorTemp={outdoorTemp} + defaultOutdoorHumidity={outdoorHumidity} changeTargetMoisture={newMoisture => { setTargetMoisture(newMoisture) }} diff --git a/src/bin/conditioning/modeChangeDialog.tsx b/src/bin/conditioning/modeChangeDialog.tsx index 2913e4a..b31c8f8 100644 --- a/src/bin/conditioning/modeChangeDialog.tsx +++ b/src/bin/conditioning/modeChangeDialog.tsx @@ -108,9 +108,9 @@ export default function ModeChangeDialog(props: Props){ const [deviceOption, setDeviceOption] = useState