diff --git a/package-lock.json b/package-lock.json
index 1d88f79..af61e6b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -49,6 +49,7 @@
"react-color": "^2.19.3",
"react-day-picker": "^9.6.5",
"react-dom": "^18.3.1",
+ "react-emoji-render": "^2.0.1",
"react-error-boundary": "^5.0.0",
"react-full-screen": "^1.1.1",
"react-horizontal-scrolling-menu": "^7.1.1",
@@ -9188,6 +9189,15 @@
"node": ">=12"
}
},
+ "node_modules/invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"node_modules/is-array-buffer": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
@@ -9971,6 +9981,18 @@
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
},
+ "node_modules/lodash.flatten": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+ "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
+ "license": "MIT"
+ },
"node_modules/lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -11107,6 +11129,29 @@
"react": "^18.3.1"
}
},
+ "node_modules/react-emoji-render": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/react-emoji-render/-/react-emoji-render-2.0.1.tgz",
+ "integrity": "sha512-SKtsdwgEf2BFNiE9y4UBFZBWjkRcyWmhMprVly52+J77/zxThcfaQ3sCA0+2LtGJIRMpm4DGWSvyLg72fd1rXQ==",
+ "license": "MIT",
+ "dependencies": {
+ "classnames": "^2.2.5",
+ "emoji-regex": "^8.0.0",
+ "lodash.flatten": "^4.4.0",
+ "prop-types": "^15.5.8",
+ "string-replace-to-array": "^1.0.1"
+ },
+ "peerDependencies": {
+ "react": ">=0.14.0",
+ "react-dom": ">=0.14.0"
+ }
+ },
+ "node_modules/react-emoji-render/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
+ },
"node_modules/react-error-boundary": {
"version": "5.0.0",
"integrity": "sha512-tnjAxG+IkpLephNcePNA7v6F/QpWLH8He65+DmedchDwg162JZqx4NmbXj0mlAYVVEd81OW7aFhmbsScYfiAFQ==",
@@ -12408,6 +12453,17 @@
"safe-buffer": "~5.2.0"
}
},
+ "node_modules/string-replace-to-array": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string-replace-to-array/-/string-replace-to-array-1.0.3.tgz",
+ "integrity": "sha512-QIdKvmfXbdFvblXAAz6IIjR7A+C6SU6m2A+e7fE/0EYDC5yfeWNMJQ193fPsW7nG+9q52dv/UjnVrDaNVZXpmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "invariant": "^2.2.1",
+ "lodash.flatten": "^4.2.0",
+ "lodash.isstring": "^4.0.1"
+ }
+ },
"node_modules/string.prototype.matchall": {
"version": "4.0.12",
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
diff --git a/package.json b/package.json
index af322fc..fc7a1ac 100644
--- a/package.json
+++ b/package.json
@@ -61,6 +61,7 @@
"react-color": "^2.19.3",
"react-day-picker": "^9.6.5",
"react-dom": "^18.3.1",
+ "react-emoji-render": "^2.0.1",
"react-error-boundary": "^5.0.0",
"react-full-screen": "^1.1.1",
"react-horizontal-scrolling-menu": "^7.1.1",
diff --git a/public/Streamline/stream-logo-dark.png b/public/Streamline/stream-logo-dark.png
new file mode 100644
index 0000000..a486c1e
Binary files /dev/null and b/public/Streamline/stream-logo-dark.png differ
diff --git a/src/app/main.tsx b/src/app/main.tsx
index e2acdd9..2d8615c 100644
--- a/src/app/main.tsx
+++ b/src/app/main.tsx
@@ -19,7 +19,7 @@ if ('serviceWorker' in navigator) {
}
createRoot(document.getElementById('root')!).render(
-
+ //
- ,
+ // ,
)
diff --git a/src/common/Tour.tsx b/src/common/Tour.tsx
index 4781e21..9d328a7 100644
--- a/src/common/Tour.tsx
+++ b/src/common/Tour.tsx
@@ -1,4 +1,4 @@
-import Joyride, { Step, CallBackProps, STATUS, TooltipRenderProps, Locale } from "react-joyride";
+import Joyride, { Step, CallBackProps, STATUS, TooltipRenderProps, Locale, ACTIONS, EVENTS } from "react-joyride";
import {
Button,
Card,
@@ -10,12 +10,13 @@ import {
Tooltip,
IconButton,
Theme,
- useTheme
+ useTheme,
} from "@mui/material";
import { KeyboardArrowLeft, KeyboardArrowRight, Close as CloseIcon } from "@mui/icons-material";
import classNames from "classnames";
import { grey } from "@mui/material/colors";
import { makeStyles } from "@mui/styles";
+import { CSSProperties } from "react";
const useStyles = makeStyles((theme: Theme) => {
return ({
@@ -46,6 +47,10 @@ const useStyles = makeStyles((theme: Theme) => {
})
});
+export interface TourStep extends Step {
+ onNext?: () => void; // Define onNext as an optional function
+}
+
const StepContainer = (props: TooltipRenderProps, numSteps: number, skip: () => void) => {
const {
continuous,
@@ -114,18 +119,30 @@ const StepContainer = (props: TooltipRenderProps, numSteps: number, skip: () =>
interface Props {
run: boolean;
- steps: Step[];
+ steps: TourStep[];
endTourCallback: () => void;
+ spotlightStyle?: CSSProperties,
+ setStepIndex?: React.Dispatch>,
}
export default function Tour(props: Props) {
- const { run, steps, endTourCallback } = props;
+ const { run, steps, endTourCallback, setStepIndex, spotlightStyle } = props;
const theme = useTheme();
const handleTourCallback = (data: CallBackProps) => {
- const { status } = data;
+ const { action, index, status, type } = data;
const finishedStatuses: string[] = [STATUS.FINISHED, STATUS.SKIPPED];
+ if (setStepIndex) setStepIndex(index)
+
+ if (action === ACTIONS.NEXT && type === EVENTS.STEP_AFTER) {
+ // Safely access the step and call onNext if it exists
+ const currentStep = steps[index];
+ if (currentStep.onNext) {
+ currentStep.onNext();
+ }
+ }
+
if (finishedStatuses.includes(status)) {
endTourCallback();
}
@@ -150,6 +167,9 @@ export default function Tour(props: Props) {
primaryColor: theme.palette.primary.main,
textColor: theme.palette.text.primary,
zIndex: theme.zIndex.modal
+ },
+ spotlight: {
+ ...spotlightStyle
}
}}
/>
diff --git a/src/device/SyncDevice.tsx b/src/device/SyncDevice.tsx
index e816967..f608d28 100644
--- a/src/device/SyncDevice.tsx
+++ b/src/device/SyncDevice.tsx
@@ -50,7 +50,10 @@ export default function SyncDevice(props: Props) {
console.error(err);
error("Unable to resync device");
close();
- });
+ })
+ .finally(() => {
+ close()
+ })
};
return (
diff --git a/src/navigation/Router.tsx b/src/navigation/Router.tsx
index 29362ad..f6badb1 100644
--- a/src/navigation/Router.tsx
+++ b/src/navigation/Router.tsx
@@ -9,6 +9,7 @@ import { getWhitelabel } from "services/whiteLabel";
import Ventilation from "pages/VentEditor";
import { useGlobalState } from "providers";
import DeviceSupport from "pages/DeviceSupport";
+import SignupCallback from "pages/SignupCallback";
const DeviceHistory = lazy(() => import("pages/DeviceHistory"));
const DevicePage = lazy(() => import("pages/Device"));
@@ -302,6 +303,8 @@ export default function Router() {
{/* Redirects */}
} />
+ {/* } /> */}
+ } />
{/* } /> */}
{/* } /> */}
{/* } /> */}
diff --git a/src/navigation/SideNavigator.tsx b/src/navigation/SideNavigator.tsx
index 38a10cb..f71ca9c 100644
--- a/src/navigation/SideNavigator.tsx
+++ b/src/navigation/SideNavigator.tsx
@@ -221,7 +221,7 @@ export default function SideNavigator(props: Props) {
{(isAg || isStreamline || user.hasFeature("admin")) && (
goTo("/bins")}
classes={getClasses("/bin")}
>
@@ -277,7 +277,7 @@ export default function SideNavigator(props: Props) {
{(isMiVent || user.hasFeature("admin")) && (
goTo("/mines")}
classes={getClasses("/mine")}
>
@@ -330,7 +330,7 @@ export default function SideNavigator(props: Props) {
}
goTo("/teams")}
classes={getClasses("/team")}
>
@@ -342,7 +342,7 @@ export default function SideNavigator(props: Props) {
goTo("/users")}
classes={getClasses("/user")}
>
diff --git a/src/pages/Bin.tsx b/src/pages/Bin.tsx
index fc9463f..fcc1117 100644
--- a/src/pages/Bin.tsx
+++ b/src/pages/Bin.tsx
@@ -1107,7 +1107,7 @@ export default function Bin(props: Props) {
};
return (
-
+
{showPlenumError()}
{
@@ -141,11 +140,13 @@ export default function Bins(props: Props) {
const classes = useStyles();
const isMobile = useMobile();
const binAPI = useBinAPI();
+ const teamAPI = useTeamAPI();
// const binyardAPI = useBinYardAPI();
const interactionsAPI = useInteractionsAPI();
const [{ user, as }] = useGlobalState();
const [allLoading, setAllLoading] = useState(false);
const [binsLoading, setBinsLoading] = useState(false);
+ const [doneLoadingPage, setDoneLoadingPage] = useState(false)
const [addBinOpen, setAddBinOpen] = useState(false);
const [paginatedBins, setPaginatedBins] = useState({
bins: [],
@@ -188,13 +189,16 @@ export default function Bins(props: Props) {
const [qrKeyList, setQrKeyList] = useState([]);
const [totalFanControllers, setTotalFanControllers] = useState(0);
const [totalFanControllersOn, setTotalFanControllersOn] = useState(0);
- const [yardsLoading, setYardsLoading] = useState(false);
+ // const [yardsLoading, setYardsLoading] = useState(false);
const [openAddAlerts, setOpenAddAlerts] = useState(false);
const [alertBins, setAlertBins] = useState([]);
const { openSnack } = useSnackbar();
// const history = useHistory();
const navigate = useNavigate()
const [cardValDisplay, setCardValDisplay] = useState<"high" | "low" | "average">("average");
+
+ const [teamsDialog, setTeamsDialog] = useState(false)
+
// const [scrollTranslations, setScrollTranslations] = useState({
// bins: 0,
// empty: 0,
@@ -252,6 +256,18 @@ export default function Bins(props: Props) {
// selected: {}
// }));
+ useEffect(() => {
+ if (doneLoadingPage && grainBins.length < 1 && grainBags.length < 1) {
+ teamAPI.listTeams(1, 0).then(resp => {
+ // console.log(resp.data.teams)
+ if (resp.data.teams.length > 0) {
+ // console.log("should?")
+ setTeamsDialog(true)
+ }
+ })
+ }
+ }, [doneLoadingPage, grainBins, grainBags])
+
useEffect(() => {
let ebt = sessionStorage.getItem("expandBinTotal");
if (ebt === "true") {
@@ -400,7 +416,7 @@ export default function Bins(props: Props) {
const bags = resp.data.bags.map(b => GrainBag.create(b));
setGrainBags(bags);
})
- .catch(err => {
+ .catch(() => {
setPaginatedBins({ bins: [], binsOffset: 0, binsTotal: 0 });
setBinMetrics(pond.BinMetrics.create());
setYards([]);
@@ -408,6 +424,7 @@ export default function Bins(props: Props) {
.finally(() => {
setAllLoading(false);
setBinsLoading(false);
+ setDoneLoadingPage(true)
});
}, [binAPI, yardFilter, order, orderBy, as, loadingAs, loadingFilter]); // eslint-disable-line react-hooks/exhaustive-deps
@@ -454,7 +471,7 @@ export default function Bins(props: Props) {
setFertilizerBins([...fert]);
setQrKeyList([...newKeyList]);
})
- .catch(err => {
+ .catch(() => {
setPaginatedBins({ bins: [], binsOffset: 0, binsTotal: 0 });
})
.finally(() => {
@@ -462,13 +479,13 @@ export default function Bins(props: Props) {
});
};
- const searchYards = (
- search?: string,
- limit?: number,
- offset?: number,
- order?: "asc" | "desc"
- ) => {
- setYardsLoading(true);
+ // const searchYards = (
+ // search?: string,
+ // limit?: number,
+ // offset?: number,
+ // order?: "asc" | "desc"
+ // ) => {
+ // setYardsLoading(true);
// binyardAPI.listBinYards(limit ?? binsLimit, offset ?? 0, order, "name", search).then(resp => {
// let y: pond.BinYardSettings[] = [];
// let p: Dictionary = {};
@@ -493,7 +510,7 @@ export default function Bins(props: Props) {
// }
// setYardsLoading(false);
// });
- };
+ // };
useEffect(() => {
loadBins();
@@ -515,7 +532,7 @@ export default function Bins(props: Props) {
}
const duplicateBin = (bin: Bin) => {
- binAPI.addBin(bin.settings, as).then(resp => {
+ binAPI.addBin(bin.settings, as).then(() => {
loadMoreBins(contentFilter);
});
};
@@ -556,7 +573,7 @@ export default function Bins(props: Props) {
.then(resp => {
openSnack("Successfully added " + resp.data.numAlertsSet + " alerts");
})
- .catch(err => {
+ .catch(() => {
console.log("errors found");
});
};
@@ -1080,7 +1097,7 @@ export default function Bins(props: Props) {
control={
{
+ onChange={(_, checked) => {
setDisplayGrain(checked);
}}
/>
@@ -1093,7 +1110,7 @@ export default function Bins(props: Props) {
control={
{
+ onChange={(_, checked) => {
setDisplayFert(checked);
}}
/>
@@ -1106,7 +1123,7 @@ export default function Bins(props: Props) {
control={
{
+ onChange={(_, checked) => {
setDisplayEmpty(checked);
}}
/>
@@ -1392,15 +1409,17 @@ export default function Bins(props: Props) {
{addALertsDialog()}
{
- searchYards(search, limit, offset);
- }}
+ // loadYards={(search, limit, offset) => {
+ // searchYards(search, limit, offset);
+ // }}
+ loadYards={() => {}}
grainBags={grainBags}
setShowing={(val: "all" | "bins" | "bags") => {
setShowing(val);
@@ -1473,6 +1492,13 @@ export default function Bins(props: Props) {
/>
{binMenu()}
setAddBinOpen(true)} pulse={binsTotal < 1 && !allLoading} />
+
);
};
diff --git a/src/pages/DeviceSupport.tsx b/src/pages/DeviceSupport.tsx
index a6a19de..6c9a0db 100644
--- a/src/pages/DeviceSupport.tsx
+++ b/src/pages/DeviceSupport.tsx
@@ -3,7 +3,7 @@ import PageContainer from "./PageContainer";
import { pond } from "protobuf-ts/pond";
import LogsDisplay from "common/LogsDisplay";
import { useEffect, useState } from "react";
-import { useDeviceAPI, useSnackbar } from "hooks";
+import { useDeviceAPI, useMobile, useSnackbar } from "hooks";
import { useLocation, useParams } from "react-router-dom";
import { Component, Device, Interaction } from "models";
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
@@ -43,6 +43,7 @@ export default function DeviceSupport() {
const deviceAPI = useDeviceAPI()
const snackbar = useSnackbar()
const theme = useTheme()
+ const isMobile = useMobile()
const { state } = useLocation();
const [{ user, as }] = useGlobalState()
@@ -188,7 +189,7 @@ export default function DeviceSupport() {
}
return (
-
+
diff --git a/src/pages/Devices.tsx b/src/pages/Devices.tsx
index fe47b3c..7721ec1 100644
--- a/src/pages/Devices.tsx
+++ b/src/pages/Devices.tsx
@@ -5,7 +5,7 @@ import { makeStyles } from "@mui/styles";
import ResponsiveTable, { Column } from "common/ResponsiveTable";
import ProvisionDevice from "device/ProvisionDevice";
import { pond } from "protobuf-ts/pond";
-import { useDeviceAPI, useGlobalState, useGroupAPI } from "providers";
+import { useDeviceAPI, useGlobalState, useGroupAPI, useTeamAPI } from "providers";
import { useCallback, useEffect, useState } from "react";
import PageContainer from "./PageContainer";
import { useMobile } from "hooks";
@@ -28,6 +28,7 @@ import StatusDust from "common/StatusDust";
import StatusGas from "common/StatusGas";
import { cloneDeep } from "lodash";
import LoadingScreen from "app/LoadingScreen";
+import TeamDialog from "teams/TeamDialog";
const useStyles = makeStyles((theme: Theme) => {
return ({
@@ -98,9 +99,12 @@ export default function Devices() {
const location = useLocation();
const deviceAPI = useDeviceAPI();
const groupAPI = useGroupAPI();
+ const teamAPI = useTeamAPI();
const [devicesLoading, setDevicesLoading] = useState(false)
const [limit, setLimit] = useState(10);
const [page, setPage] = useState(0);
+ const [doneLoading, setDoneLoading] = useState(false)
+ const [teamsDialog, setTeamsDialog] = useState(false)
const [{ user }] = useGlobalState()
@@ -186,7 +190,7 @@ export default function Devices() {
const [preferencesAnchor, setPreferencesAnchor] = useState(null)
- const [{ as }] = useGlobalState()
+ const [{ as, team }] = useGlobalState()
const updateGroups = (newGroups: Group[]) => {
setGroups(newGroups);
@@ -327,6 +331,7 @@ export default function Devices() {
setTotal(resp.data.total)
}).finally(() => {
setDevicesLoading(false)
+ setDoneLoading(true)
})
}
@@ -338,6 +343,16 @@ export default function Devices() {
loadGroups()
}, [groupLimit, groupPage, orderGroup, orderGroupBy, searchGroup, as])
+ useEffect(() => {
+ if (doneLoading && devices.length < 1 && groups.length < 1) {
+ teamAPI.listTeams(1, 0).then(resp => {
+ if (resp.data.teams.length > 0 && team.key().length < 1) {
+ setTeamsDialog(true);
+ }
+ })
+ }
+ }, [doneLoading, devices, groups])
+
const handleChange = (event: any) => {
setLimit(event.target.value);
};
@@ -826,6 +841,13 @@ export default function Devices() {
addGroupCallback={addGroupCallback}
/>
{preferencesMenu()}
+
)
}
\ No newline at end of file
diff --git a/src/pages/Firmware.tsx b/src/pages/Firmware.tsx
index b3a7c58..1ae97af 100644
--- a/src/pages/Firmware.tsx
+++ b/src/pages/Firmware.tsx
@@ -12,7 +12,7 @@ import {
TypeBackground
} from "@mui/material";
import { blue, green, orange, red } from "@mui/material/colors";
-import { createStyles, makeStyles } from "@mui/styles";
+import { makeStyles } from "@mui/styles";
//import { TypeBackground } from "@material-ui/core/styles/createPalette";
import {
ArrowUpward,
@@ -267,7 +267,7 @@ export default function Firmware() {
if (selected) {
firmwareAPI
.removeFirmware(selected.settings.platform, selected.settings.version)
- .then((response: any) => {
+ .then(() => {
success("Successfully removed firmware");
})
.catch((err: any) => {
diff --git a/src/pages/PageContainer.tsx b/src/pages/PageContainer.tsx
index 524fbbf..2915e5b 100644
--- a/src/pages/PageContainer.tsx
+++ b/src/pages/PageContainer.tsx
@@ -48,7 +48,7 @@ export const PageContainer: React.FunctionComponent = (props: Props) => {
const { children, fullViewport, isCenterCenter, sx } = props;
// let fullViewport = false
// let isCenterCenter = false
- const spacing = props.spacing ? props.spacing : 2;
+ const spacing = props.spacing ?? 0;
return (
{
+ setLoading(true)
+ userAPI.completeSignup().then(() => {
+ teamAPI.listTeams(1, 0).then(resp => {
+ setHasTeams(resp.data.teams.length > 0)
+ }).finally(() => setDoneTeams(true))
+ deviceAPI.list(1, 0).then(resp => {
+ setHasDevices(resp.data.devices.length > 0)
+ }).finally(() => setDoneDevices(true))
+ binAPI.listBins(1, 0).then(resp => {
+ setHasBins(resp.data.bins.length > 0)
+ }).finally(() => setDoneBins(true))
+ }).finally(() => setLoading(false))
+ }, [])
+
+ const loadingComplete = () => {
+ return loading === false && doneBins && doneTeams && doneDevices
+ }
+
+ const content = () => {
+ return (
+
+ { loadingComplete() ?
+
+ :
+
+ }
+
+ {hasTeams && "Teams found!"}
+
+ {hasDevices && "Devices found!"}
+
+ {hasBins && "Bins found!"}
+
+
+ )
+ }
+
+ const getTourSteps = (): TourStep[] => {
+ let steps: TourStep[] = [
+ {
+ title: (
+ <>
+ Welcome to {whiteLabel.name}
+
+ >
+ ),
+ content: (
+ <>
+
+ {"Hello " + user.name()}
+
+
+
+ Thank you for signing up! Let me give you the tour
+
+
+ >
+ ),
+ target: "body",
+ placement: "center",
+ disableBeacon: true,
+ },
+ {
+ title: "User Menu",
+ content: (
+ <>
+
+ In the user menu, you can make changes to your profile, and adjust unit preferences.
+
+
+
+ If you are part of a team, you can select it here as well.
+
+ >
+ ),
+ target: "#tour-user-menu",
+ placement: "bottom",
+ disableBeacon: true,
+ // onNext: () => setDoneFirst(true)
+ },
+ // {
+ // title:
+ // }
+ ];
+ if (hasTeams) steps.push({
+ title: "Teams",
+ content: (
+ <>
+
+ Here, you can view your team(s), access their settings, and choose your favourite.
+
+ >
+ ),
+ target: "#tour-teams",
+ placement: "right",
+ // spotlightPadding: 50,
+ })
+ steps.push({
+ title: "Devices",
+ content: (
+ <>
+
+ You can view your devices and their readings here.
+
+
+
+ If you are viewing as a team, your team's devices will be displayed here instead.
+
+ >
+ ),
+ target: "#tour-dashboard",
+ placement: "right"
+ })
+ if (IsAdaptiveAgriculture()) steps.push({
+ title: "Bins",
+ content: (
+ <>
+
+ You can view your bins and their inventory here.
+
+
+
+ If you are viewing as a team, your team's bins will be displayed here instead.
+
+ >
+ ),
+ target: "#tour-bins",
+ placement: "right",
+ disableBeacon: true,
+ })
+ return steps;
+ };
+
+ const endTour = () => {
+ setIsTourRunning(false);
+ // if (user) {
+ // user.status.finishedBinIntro = moment().toJSON();
+ // userAPI
+ // .updateUser(userID, user.protobuf())
+ // .then(() => dispatch({ key: "user", value: user }))
+ // .catch((err: any) => error(err));
+ // }
+ };
+
+ const closeDialog = () => {
+ setSignupDialogOpen(false)
+ setIsTourRunning(true)
+ }
+
+ useEffect(() => {
+ console.log(stepIndex)
+ }, [stepIndex])
+
+ return (
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/pages/Team.tsx b/src/pages/Team.tsx
index 7a8f29f..dd88fdd 100644
--- a/src/pages/Team.tsx
+++ b/src/pages/Team.tsx
@@ -214,7 +214,7 @@ export default function TeamPage() {
}
return (
-
+
{title()}
diff --git a/src/pages/Teams.tsx b/src/pages/Teams.tsx
index 2e74628..90e3401 100644
--- a/src/pages/Teams.tsx
+++ b/src/pages/Teams.tsx
@@ -5,7 +5,7 @@ import TeamList from "teams/TeamList";
export default function Teams() {
const isMobile = useMobile()
return (
-
+
);
diff --git a/src/pages/Users.tsx b/src/pages/Users.tsx
index 00ef9f7..296c60a 100644
--- a/src/pages/Users.tsx
+++ b/src/pages/Users.tsx
@@ -349,7 +349,7 @@ export default function Users() {
}
return (
-
+
title="Users"
rows={rows}
diff --git a/src/providers/auth.tsx b/src/providers/auth.tsx
index 22ac76d..2a8f6bb 100644
--- a/src/providers/auth.tsx
+++ b/src/providers/auth.tsx
@@ -9,28 +9,36 @@ interface Props extends PropsWithChildren{
export default function AuthWrapper(props: Props) {
const { children, setToken } = props;
- const { isLoading, loginWithRedirect, isAuthenticated, getAccessTokenSilently } = useAuth0();
+ const {
+ isLoading,
+ loginWithRedirect,
+ isAuthenticated,
+ getAccessTokenSilently,
+ // getIdTokenClaims
+ } = useAuth0();
useEffect(() => {
const url = new URL(window.location.href);
-
const isManualLoginPage = url.pathname.includes("/login");
+ const options: RedirectLoginOptions = {
+ authorizationParams: {} // Initialize here
+ };
- if (isManualLoginPage) {
- const options: RedirectLoginOptions = {
- authorizationParams: {} // Initialize here
- };
-
+ if (isManualLoginPage && options.authorizationParams) {
+
let parsed = queryString.parse(url.search);
if (parsed.signup === "true") {
- options.authorizationParams!.screen_hint = "signup";
- options.authorizationParams!.prompt = "login";
+ options.authorizationParams.screen_hint = "signUp";
+ // options.authorizationParams.m
+ // options.authorizationParams.prompt = "login";
}
if (parsed.email && parsed.email !== "") {
- options.authorizationParams!.login_hint = parsed.email.toString(); // prefill email
+ options.authorizationParams.login_hint = parsed.email.toString(); // prefill email
}
+
+ options.authorizationParams.redirect_uri = "http://localhost:5173/signupCallback"
loginWithRedirect(options)
@@ -40,15 +48,27 @@ export default function AuthWrapper(props: Props) {
}, [isAuthenticated, loginWithRedirect, isLoading]);
useEffect(() => {
- if (isAuthenticated) getAccessTokenSilently().then(t => {
- if (t.length < 1) {
+ // const url = new URL(window.location.href);
+ // const isSignupCallback = url.pathname.includes("/signupCallback");
+ if (isAuthenticated) {
+ getAccessTokenSilently().then(t => {
+ if (t.length < 1) {
+ loginWithRedirect()
+ }
+ setToken(t)
+ }).catch(() => {
+ // No token, go back to login
loginWithRedirect()
- }
- setToken(t)
- }).catch(() => {
- // No token, go back to login
- loginWithRedirect()
- })
+ })
+ // if (isSignupCallback) {
+ // getIdTokenClaims().then(id_claims => {
+ // console.log(id_claims)
+ // console.log(id_claims?.nickname)
+ // if (id_claims) console.log(Object.keys(id_claims))
+ // })
+ // }
+
+ }
}, [setToken, isAuthenticated])
return children;
diff --git a/src/providers/pond/userAPI.tsx b/src/providers/pond/userAPI.tsx
index 247f77c..0d33b2e 100644
--- a/src/providers/pond/userAPI.tsx
+++ b/src/providers/pond/userAPI.tsx
@@ -28,6 +28,7 @@ export interface IUserAPIContext {
prefixSearch?: string,
) => Promise;
listProfiles: () => Promise;
+ completeSignup: () => Promise;
listObjectUsers: (scope: Scope) => Promise;
updateObjectUsers: (scope: Scope, users: pond.IUser[]) => Promise;
getUser: (id: string, scope?: Scope) => Promise;
@@ -55,8 +56,21 @@ export const UserAPIContext = createContext({} as IUserAPIConte
export default function UserProvider(props: PropsWithChildren) {
const { children } = props;
- const { get, put } = useHTTP();
- const [{ as }] = useGlobalState();
+ const { get, put, post } = useHTTP();
+ const [{ as, user }] = useGlobalState();
+
+ const completeSignup = (): Promise => {
+ return new Promise((resolve, reject) => {
+ let request = pond.CompleteSignupUserRequest.create();
+ request.avatar = user.settings.avatar
+ request.email = user.settings.email
+ request.id = user.id()
+ request.name = user.name()
+ post(pondURL("/signups"), request).then(res => {
+ resolve(pond.CompleteSignupUserResponse.create())
+ })
+ })
+ }
const listUsers = (
limit: number,
@@ -234,6 +248,7 @@ export default function UserProvider(props: PropsWithChildren) {
return (
) => void;
+ title?: string;
+ info?: string;
+ hideKey?: string;
}
const useStyles = makeStyles((theme: Theme) => {
@@ -37,16 +43,22 @@ const useStyles = makeStyles((theme: Theme) => {
});
export default function TeamDialog(props: Props) {
- const { open, setOpen } = props;
+ const { open, setOpen, title, info, hideKey } = props;
const teamAPI = useTeamAPI();
const userAPI = useUserAPI();
const [, dispatch] = useGlobalState();
const [teamKey, setTeamKey] = useState("");
const [{ team, user }] = useGlobalState();
+ const [viewAsTeam, setViewAsTeam] = useState(user.settings.useTeam)
+ const [doNotShow, setDoNotShow] = useState(false)
const classes = useStyles();
+ const shouldHide = hideKey ?
+ (localStorage.getItem(hideKey) === "true" ? true : false)
+ : false
+
const setTeam = () => {
- setOpen(false);
+ onClose()
dispatch({ key: "as", value: teamKey });
if (teamKey === "" || teamKey.includes("auth")) {
dispatch({ key: "team", value: Team.create() });
@@ -55,13 +67,19 @@ export default function TeamDialog(props: Props) {
teamAPI.getTeam(teamKey).then(team => {
dispatch({ key: "team", value: team });
user.settings.defaultTeam = team.key();
- user.settings.useTeam = true; //when selecting a team now set to view as team by default
+ user.settings.useTeam = viewAsTeam; //when selecting a team now set to view as team by default
userAPI.updateUser(user.id(), user.protobuf());
});
};
+ const onClose = () => {
+ console.log("close")
+ setOpen(false)
+ if (hideKey) localStorage.setItem(hideKey, ""+doNotShow)
+ }
+
return (
- setOpen(false)}>
+
- Select a Team to View As
+ { title ? title : "Select a Team to View As"}
-
@@ -84,12 +102,40 @@ export default function TeamDialog(props: Props) {
Viewing as: {team.name()}
)}
+ {info &&
+
+ {info}
+
+ }
+ {/* setViewAsTeam(!viewAsTeam)} /> */}
+
+ setViewAsTeam(!viewAsTeam)}
+ />
+ }
+ label="View as team"
+ />
+
+ {hideKey &&
+ setDoNotShow(!doNotShow)}
+ />
+ }
+ label="Do not show again"
+ />
+ }
);
}
diff --git a/src/user/UserMenu.tsx b/src/user/UserMenu.tsx
index 2b41a6f..c7b8ab3 100644
--- a/src/user/UserMenu.tsx
+++ b/src/user/UserMenu.tsx
@@ -228,7 +228,7 @@ export default function UserMenu() {
*/}
{hasTeams && (
-