diff --git a/package.json b/package.json index d465087..1db2791 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "start": "vite", - "start-local": "VITE_AUTH0_AUDIENCE=bxt-dev.api.adaptiveagriculture.ca VITE_APP_API_URL=http://localhost:50052/v1 VITE_APP_WS_URL=ws://localhost:50052/v1/live VITE_APP_BILLING_URL=http://localhost:50053/v1 VITE_APP_RECLUSE_URL=http://localhost:50054/v1 VITE_APP_GITLAB_URL=http://localhost:50055/v1 vite", + "start-local": "VITE_AUTH0_CLIENT_ID=dzJTpqIeMA4Rwk4xujtwPbAO3TY32bM1 VITE_AUTH0_AUDIENCE=bxt-dev.api.adaptiveagriculture.ca VITE_APP_API_URL=http://localhost:50052/v1 VITE_APP_WS_URL=ws://localhost:50052/v1/live VITE_APP_BILLING_URL=http://localhost:50053/v1 VITE_APP_RECLUSE_URL=http://localhost:50054/v1 VITE_APP_GITLAB_URL=http://localhost:50055/v1 vite", "start-dev": "VITE_AUTH0_CLIENT_ID=dzJTpqIeMA4Rwk4xujtwPbAO3TY32bM1 VITE_APP_API_URL=https://bxt-dev.api.adaptiveagriculture.ca/v1 VITE_AUTH0_CLIENT_DOMAIN=brandxtech.auth0.com VITE_AUTH0_AUDIENCE=bxt-dev.api.adaptiveagriculture.ca VITE_AUTH0_DEV_CLIENT_ID=dzJTpqIeMA4Rwk4xujtwPbAO3TY32bM1 vite", "start-staging": "VITE_AUTH0_CLIENT_ID=3ib460VvLwdeyse5iUSQfxkVdQaUmphP VITE_AUTH0_AUDIENCE=stagingapi.brandxtech.ca VITE_AUTH0_CLIENT_DOMAIN=adaptivestaging.us.auth0.com VITE_APP_API_URL=https://stagingapi.brandxtech.ca/v1 VITE_APP_WS_URL=ws://stagingapi.brandxtech.ca/v1/live VITE_APP_AUTH0_CLIENT_DOMAIN=adaptivestaging.us.auth0.com VITE_APP_AUTH0_AUDIENCE=stagingapi.brandxtech.ca vite", "build": "tsc -b && vite build", diff --git a/src/common/SmartBreadcrumb.tsx b/src/common/SmartBreadcrumb.tsx index d914ac1..240af69 100644 --- a/src/common/SmartBreadcrumb.tsx +++ b/src/common/SmartBreadcrumb.tsx @@ -11,7 +11,7 @@ import { } from "@mui/material"; import { Replay } from "@mui/icons-material"; import { useMobile } from "hooks"; -import { ReactNode } from "react"; +import { ReactNode, useEffect, useRef } from "react"; import { useLocation } from "react-router"; import { Link as RouterLink } from "react-router-dom"; import { or } from "utils/types"; @@ -47,6 +47,7 @@ interface Props { componentName?: string; groupName?: string; binName?: string; + teamName?: string; reportTarget?: string; loading?: boolean; reload?: () => void; @@ -114,6 +115,11 @@ export default function SmartBreadcrumb(props: Props) { return or(regexMatch[1], "0").toString(); }; + const teamKey = (): string => { + const regexMatch = or(location.pathname.match(/\/teams\/([^/]+)/), []) + return or(regexMatch[1], "0").toString(); + }; + const reportIDShort = (): string => { return reportID().split("-")[0]; }; @@ -220,6 +226,10 @@ export default function SmartBreadcrumb(props: Props) { return "/teams"; } + const teamPath = (): string => { + return "/teams" + "/" + teamKey(); + } + const getBreadcrumbMap = (): { [key: string]: string } => { const { groupName, deviceName, componentName, reportTarget, binName } = props; const deviceLabel: string = deviceName ? deviceName : "Device " + deviceID(); @@ -227,6 +237,13 @@ export default function SmartBreadcrumb(props: Props) { const binLabel: string = binName ?? "Bin " + binID(); const mineLabel: string = "Mine Site"; const jobsiteLabel: string = "Job Site"; + + let lastTeamName = props.teamName; + if (props.teamName) { + localStorage.setItem('lastTeamName-'+teamKey(), props.teamName); + } else { + lastTeamName = or(localStorage.getItem('lastTeamName-'+teamKey()), undefined); + } return { [dashboardPath()]: "Dashboard", @@ -250,7 +267,8 @@ export default function SmartBreadcrumb(props: Props) { [usersPath()]: "Users", [binsPath()]: "Bins", [binPath()]: binLabel, - [teamsPath()]: "Teams" + [teamsPath()]: "Teams", + [teamPath()]: lastTeamName ? lastTeamName : "Team " + teamKey(), }; }; diff --git a/src/navigation/BottomNavigator.tsx b/src/navigation/BottomNavigator.tsx index d7bf295..514429a 100644 --- a/src/navigation/BottomNavigator.tsx +++ b/src/navigation/BottomNavigator.tsx @@ -97,33 +97,37 @@ export default function BottomNavigator(props: Props) { } }; + const getType = () => { + return theme.palette.mode === "light" ? "dark" : "light" + } + const authenticatedNavigation = () => { return ( handleRouteChange(newValue)}> {isAdaptive && ( - } value="fields" /> + } value="fields" /> )} {isAdaptive && ( - } value="bins" /> + } value="bins" /> )} {isAdCon && ( } + icon={} value="constructionsiteMap" /> )} {isOmni && ( } + icon={} value="aviationMap" /> )} {isOmni && ( } + icon={} value="terminals" /> )} @@ -132,11 +136,11 @@ export default function BottomNavigator(props: Props) { label="Devices" icon={ isAdaptive ? ( - + ) : isAdCon ? ( - + ) : isOmni ? ( - + ) : ( ) @@ -146,7 +150,7 @@ export default function BottomNavigator(props: Props) { {isAdCon && ( } + icon={} value="jobsites" /> )} @@ -183,6 +187,7 @@ export default function BottomNavigator(props: Props) { bottom={0} width="100vw" zIndex={theme.zIndex.appBar} + sx={{ background: theme.palette.background.paper }} style={{ overflow: window.location.origin.includes("staging") || window.location.origin.includes("localhost") diff --git a/src/pages/Devices.tsx b/src/pages/Devices.tsx index f37a5c1..327d72d 100644 --- a/src/pages/Devices.tsx +++ b/src/pages/Devices.tsx @@ -120,10 +120,16 @@ export default function Devices() { setGroups(newGroups); }; + const getGroup = () => { + let group = groups[parseInt(tab)] + return group + } + useEffect(() => { setGroupPermissions([]) if (tab === "all") return - groupAPI.getGroupPermissions(parseInt(tab)).then(resp => { + groupAPI.getGroupPermissions(getGroup().id()).then(resp => { + console.log(resp) setGroupPermissions(resp.data.permissions) }) }, [tab]) @@ -375,11 +381,6 @@ export default function Devices() { ) } - const getGroup = () => { - let group = groups[parseInt(tab)] - return group - } - const mobile = (row: Device) => { return ( diff --git a/src/pages/Team.tsx b/src/pages/Team.tsx index 095d90f..7a8f29f 100644 --- a/src/pages/Team.tsx +++ b/src/pages/Team.tsx @@ -2,6 +2,7 @@ import { Avatar, AvatarGroup, Box, Button, Card, Divider, Grid2, List, ListItemB import { makeStyles } from "@mui/styles"; import LoadingScreen from "app/LoadingScreen"; import Chat from "chat/Chat"; +import SmartBreadcrumb from "common/SmartBreadcrumb"; // import SmartBreadcrumb from "common/SmartBreadcrumb"; import { useMobile } from "hooks"; import { cloneDeep } from "lodash"; @@ -162,7 +163,8 @@ export default function TeamPage() { - {team.name()} + {/* {team.name()} */} + {/* */} diff --git a/src/providers/pond/groupAPI.tsx b/src/providers/pond/groupAPI.tsx index cb6437e..8166af2 100644 --- a/src/providers/pond/groupAPI.tsx +++ b/src/providers/pond/groupAPI.tsx @@ -42,6 +42,20 @@ export interface IGroupAPIContext { updateGroupPermissions: (id: number, users: User[]) => Promise; } +function buildQueryString(params: Record): string { + // Filter out null, undefined, or empty string values + const validParams = Object.entries(params) + .filter(([_, value]) => value != null && value !== '') + .map(([key, value]) => `${key}=${value}`); + + if (validParams.length === 0) { + return ''; + } + + // Join parameters with '&' and prepend '?' + return `?${validParams.join('&')}`; +} + export const GroupAPIContext = createContext({} as IGroupAPIContext); interface Props {} @@ -53,8 +67,16 @@ export default function GroupProvider(props: PropsWithChildren) { const [{ as }] = useGlobalState(); const addGroup = (group: pond.GroupSettings) => { - let url = pondURL("/groups") - if (as) url = pondURL("/groups?as=" + as) + // let url = pondURL("/groups") + // let keys = getContextKeys() + // let types = getContextTypes() + // if (as) url = pondURL("/groups?as=" + as) + const params = { + keys: getContextKeys(), + types: getContextTypes(), + as: getContextTypes().includes("team") ? undefined : as + } + let url = pondURL(`/groups${buildQueryString(params)}`) return new Promise((resolve, reject) => { post(url, group).then(resp => { return resolve(resp) @@ -157,19 +179,25 @@ export default function GroupProvider(props: PropsWithChildren) { keys?: string[], types?: string[], ) => { - keys = keys ? keys : getContextKeys(); - types = types? types : getContextTypes(); - let url = "/groupPermissions/" + id - if (as) { - url = url + "?as=" + as + - + - (keys ? "?keys=" + keys.toString() : "") + - (types ? "&types=" + types.toString() : "") - } else { - url = url + - (keys ? "?keys=" + keys.toString() : "") + - (types ? "&types=" + types.toString() : "") + // keys = keys ? keys : getContextKeys(); + // types = types? types : getContextTypes(); + // let url = "/groupPermissions/" + id + // if (as) { + // url = url + "?as=" + as + + // + + // (keys ? "?keys=" + keys.toString() : "") + + // (types ? "&types=" + types.toString() : "") + // } else { + // url = url + + // (keys ? "?keys=" + keys.toString() : "") + + // (types ? "&types=" + types.toString() : "") + // } + const params = { + keys: getContextKeys(), + types: getContextTypes(), + as: getContextTypes().includes("team") ? undefined : as, } + let url = `/groupPermissions/${id}${buildQueryString(params)}` return new Promise>((resolve, reject) => { get(pondURL(url)).then(resp => { resp.data = pond.GetPermissionsResponse.fromObject(resp.data) diff --git a/src/user/UserMenu.tsx b/src/user/UserMenu.tsx index e5d3364..825ba85 100644 --- a/src/user/UserMenu.tsx +++ b/src/user/UserMenu.tsx @@ -1,4 +1,4 @@ -import { Avatar, Box, Button, Checkbox, IconButton, ListItemIcon, ListItemText, Menu, MenuItem, PaletteColor, Theme, Tooltip, useTheme } from "@mui/material"; +import { Avatar, Box, Button, Checkbox, Divider, IconButton, ListItemIcon, ListItemText, Menu, MenuItem, PaletteColor, Theme, Tooltip, useTheme } from "@mui/material"; import { useGlobalState } from "../providers/StateContainer"; import { getSecondaryColour, getSignatureAccentColour } from "../services/whiteLabel"; import { makeStyles } from "@mui/styles"; @@ -270,6 +270,7 @@ export default function UserMenu() { )} + {hasAdmin && ( openAccessObject()} aria-label="Access Object" dense> @@ -280,6 +281,7 @@ export default function UserMenu() { )} +