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 @@
+
+
+
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