react-router-dom#matchPath TypeScript Examples

The following examples show how to use react-router-dom#matchPath. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: SideBarItem.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
export default function SideBarItem({ iconStart, iconEnd, path, label }: Props): ReactElement {
  const classes = useStyles()
  const location = useLocation()
  const isSelected = Boolean(path && matchPath(location.pathname, path))

  return (
    <StyledListItem button selected={isSelected} disableRipple>
      <ListItemIcon className={isSelected ? classes.activeIcon : classes.icon}>{iconStart}</ListItemIcon>
      <ListItemText primary={label} />
      <ListItemIcon className={isSelected ? classes.activeIcon : classes.icon}>{iconEnd}</ListItemIcon>
    </StyledListItem>
  )
}
Example #2
Source File: utils.ts    From ovineherd with Apache License 2.0 6 votes vote down vote up
getOrgId = (): string => {
  const matched = matchPath(window.location.pathname, {
    path: '/platform/center/org/:orgId',
  })
  return get(matched, 'params.orgId') || ''
}
Example #3
Source File: path.ts    From mail-my-ballot with Apache License 2.0 6 votes vote down vote up
rawToPath = <P extends Path>(
  url: string,
  pathEnum: PathEnum,
  query: QueryParams,
  exact = false
): P | null => {
  const { path } = pathData[pathEnum]
  const match = matchPath<P>(url, { path, exact })
  if (!match) return null
  return {
    type: pathEnum,
    ...match.params,
    // In Jest testing, URLSearchParams are always undefined so just don't use
    scroll: query['scroll'],
  }
}
Example #4
Source File: index.tsx    From react-amis-admin with Apache License 2.0 6 votes vote down vote up
function isActive(link: any, location: any) {
    const ret = matchPath(location.pathname, {
        path: link ? link.replace(/\?.*$/, '') : '',
        exact: true,
        strict: true
    });

    return !!ret;
}
Example #5
Source File: formatRoutes.tsx    From icejs with MIT License 6 votes vote down vote up
function getComponentByPath(routes, currPath)  {
  function findMatchRoute(routeList) {
    const matchedRoute = routeList.find(route => {
      return matchPath(currPath, route);
    });
    return matchedRoute.children ? findMatchRoute(matchedRoute.children) : matchedRoute;
  }
  const matchedRoute = findMatchRoute(routes);
  return matchedRoute && matchedRoute.component;
}
Example #6
Source File: index.ts    From multisig-react with MIT License 6 votes vote down vote up
safeParamAddressFromStateSelector = (state: AppReduxState): string => {
  const match = matchPath<{ safeAddress: string }>(state.router.location.pathname, {
    path: `${SAFELIST_ADDRESS}/:safeAddress`,
  })

  if (match) {
    return checksumAddress(match.params.safeAddress)
  }

  return ''
}
Example #7
Source File: NodeLink.tsx    From firebase-tools-ui with Apache License 2.0 6 votes vote down vote up
/**
 * Creates a href that replaces the `/:path*` part of the current `<Route>`
 *
 * e.g. `/database/sample/data/a/b/c` -> `/database/sample/data/x/y/z`
 */
function useHrefWithinSameRoute(absolutePath: string) {
  const match = useRouteMatch();

  // remove the wildcard :path param, so we can append it manually
  const withoutPath = match.path.replace('/:path*', '');

  const result = matchPath(match.url, { path: withoutPath, strict: true });
  const baseUrl = result?.url || '';
  return baseUrl === '/' ? absolutePath : `${baseUrl}${absolutePath}`;
}
Example #8
Source File: SideBarStatus.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
export default function SideBarItem({ path }: Props): ReactElement {
  const { status, isLoading } = useContext(Context)
  const classes = useStyles()
  const location = useLocation()
  const isSelected = Boolean(path && matchPath(location.pathname, path))

  return (
    <ListItem
      button
      classes={{ root: `${classes.root} ${status.all ? '' : classes.rootError}`, button: classes.button }}
      selected={isSelected}
      disableRipple
    >
      <ListItemIcon style={{ marginLeft: '30px' }}>
        <StatusIcon checkState={status.all} isLoading={isLoading} />
      </ListItemIcon>
      <ListItemText primary={<Typography className={classes.smallerText}>{`Node ${status.all}`}</Typography>} />
      <ListItemIcon className={classes.icon}>
        {status.all ? null : <ArrowRight className={classes.iconSmall} />}
      </ListItemIcon>
    </ListItem>
  )
}
Example #9
Source File: GameStateRedirects.tsx    From fishbowl with MIT License 6 votes vote down vote up
function GameStateRedirects(props: { joinCode: string }) {
  const location = useLocation()
  const currentGame = React.useContext(CurrentGameContext)

  if (
    matchPath(location.pathname, { path: routes.game.pending, exact: true }) ||
    matchPath(location.pathname, { path: routes.game.settings, exact: true })
  ) {
    return null
  }

  const pair = stateRoutePairs.find((pair) => pair.state === currentGame.state)
  if (
    pair?.state &&
    !matchPath(location.pathname, {
      path: pair.route,
      exact: true,
    })
  ) {
    return (
      <Redirect
        to={generatePath(pair.route, {
          joinCode: props.joinCode,
        })}
      ></Redirect>
    )
  } else {
    return null
  }
}
Example #10
Source File: routing.ts    From metaflow-ui with Apache License 2.0 6 votes vote down vote up
/**
 * Returns parameters from given path (if matching to our defined routes)
 * @param pathname location.pathname
 */
export function getRouteMatch(pathname: string): match<KnownURLParams> | null {
  return matchPath<KnownURLParams>(
    pathname,
    Object.keys(SHORT_PATHS).map((key) => SHORT_PATHS[key as keyof PathDefinition]),
  );
}
Example #11
Source File: BreadcrumbContext.tsx    From one-platform with MIT License 5 votes vote down vote up
BreadcrumbProvider = ({ children }: Props): JSX.Element => {
  // load it up
  const [dynamicCrumbs, setDynamicCrumbs] = useState<Record<string, Breadcrumb>>();
  const [breadcrumbs, setBreadcrumbs] = useState<Breadcrumb[]>([]);
  const { pathname } = useLocation();

  const handleDynamicCrumbs = useCallback((crumb: Record<string, Breadcrumb>): void => {
    // save recent visit to quick link
    setDynamicCrumbs((state) => ({ ...state, ...crumb }));
  }, []);

  useEffect(() => {
    const path = pathname.replace(config.baseURL, '');
    const matchedPath = (Object.keys(BREADCRUMB_USERFLOW) as ApiCatalogLinks[]).find((pattern) =>
      Boolean(matchPath(pattern, path))
    );
    if (matchedPath) {
      const crumbs = BREADCRUMB_USERFLOW[matchedPath]
        .map((userflow) =>
          LOOK_UP_TABLE?.[userflow] ? LOOK_UP_TABLE?.[userflow] : dynamicCrumbs?.[userflow]
        )
        .filter((crumb) => Boolean(crumb)) as Breadcrumb[];
      setBreadcrumbs(crumbs);
    } else {
      setBreadcrumbs([]);
    }
  }, [pathname, dynamicCrumbs]);

  /**
   * Context value to access glabally from anywhere
   * Memo to optimize at best
   */
  const value = useMemo(
    () => ({
      breadcrumbs,
      handleDynamicCrumbs,
    }),

    [breadcrumbs, handleDynamicCrumbs]
  );

  return <BreadcrumbContext.Provider value={value}>{children}</BreadcrumbContext.Provider>;
}
Example #12
Source File: AppBar.tsx    From firebase-tools-ui with Apache License 2.0 5 votes vote down vote up
AppBar: React.FC<React.PropsWithChildren<Props>> = ({
  routes,
}) => {
  let location = useLocation();

  const navRoutes = routes.filter((r) => r.showInNav);

  const tabs = navRoutes.map(({ path, label }: Route) => (
    <Tab
      key={label}
      className="mdc-tab--min-width"
      {...{ tag: Link, to: path }}
    >
      {label}
    </Tab>
  ));

  const activeTabIndex = navRoutes.findIndex((r) =>
    matchPath(location.pathname, {
      path: r.path,
      exact: r.exact,
    })
  );

  return (
    <ThemeProvider
      options={{
        primary: navBarPrimary,
        surface: navBarSurface,
        onSurface: navBarOnSurface,
      }}
      wrap
    >
      <TopAppBar fixed className="AppBar" theme="surface">
        <div className="AppBar-title-row">
          <div className="AppBar-logo-lockup">
            <Logo />
            <Typography use="headline5" className="AppBar-title" tag="h1">
              Firebase Emulator Suite
            </Typography>
          </div>
        </div>
        <TabBar theme="onSurface" activeTabIndex={activeTabIndex}>
          {tabs}
        </TabBar>
      </TopAppBar>
    </ThemeProvider>
  );
}
Example #13
Source File: index.tsx    From firebase-tools-ui with Apache License 2.0 5 votes vote down vote up
Firestore: React.FC<React.PropsWithChildren<unknown>> = React.memo(
  () => {
    const location = useLocation();
    const history = useHistory();
    const [isRefreshing, setIsRefreshing] = useState(false);
    const eject = useEjector();

    // TODO: do something better here!
    const path = location.pathname.replace(/^\/firestore\/data/, '');
    const showCollectionShell = path.split('/').length < 2;
    const showDocumentShell = path.split('/').length < 3;

    const subTabs = firestoreRoutes.map(
      ({ path, label }: FirestoreTabRoute) => (
        <Tab
          key={label}
          className="mdc-tab--min-width"
          {...{ tag: Link, to: path }}
        >
          {label}
        </Tab>
      )
    );
    const activeTabIndex = firestoreRoutes.findIndex((r) =>
      matchPath(location.pathname, {
        path: r.path,
        exact: r.exact,
      })
    );

    async function handleClearData() {
      const shouldNuke = await promptClearAll();
      if (!shouldNuke) return;
      setIsRefreshing(true);
      await eject();
      handleNavigate();
      setIsRefreshing(false);
    }

    function handleNavigate(path?: string) {
      // TODO: move to routing constants
      const root = '/firestore/data';
      if (path === undefined) {
        history.push(root);
      } else {
        history.push(`${root}/${path}`);
      }
    }

    return isRefreshing ? (
      <Spinner span={12} data-testid="firestore-loading" />
    ) : (
      <FirestoreStore>
        <GridCell span={12} className="Firestore">
          <div className="Firestore-sub-tabs">
            <TabBar theme="onSurface" activeTabIndex={activeTabIndex}>
              {subTabs}
            </TabBar>
          </div>

          <Switch>
            <Route path="/firestore/data">
              <FirestoreDataCard
                path={path}
                handleClearData={handleClearData}
                handleNavigate={handleNavigate}
                showCollectionShell={showCollectionShell}
                showDocumentShell={showDocumentShell}
              />
            </Route>
            <Route path="/firestore/requests">
              <FirestoreRequestsCard />
            </Route>
            <Redirect from="/firestore" to="/firestore/data" />
          </Switch>
        </GridCell>
      </FirestoreStore>
    );
  }
)
Example #14
Source File: PageTabs.tsx    From frontegg-react with MIT License 5 votes vote down vote up
findMatchPath = (pathname: string, tabs: { route: string }[]) => {
  const activeTab = tabs.findIndex(({ route }) => matchPath(pathname, { path: route, exact: true }));
  return activeTab === -1 ? 0 : activeTab;
}
Example #15
Source File: App.tsx    From iot-center-v2 with MIT License 5 votes vote down vote up
getPageHelp = (url: string) =>
  PAGE_HELP.filter(({matcher}) => matchPath(url, matcher)).map(
    ({file}) => file
  )[0]
Example #16
Source File: GameLayout.tsx    From fishbowl with MIT License 5 votes vote down vote up
function GameLayout(props: { children: React.ReactNode; joinCode: string }) {
  const currentPlayer = React.useContext(CurrentPlayerContext)
  const location = useLocation()
  const history = useHistory()

  const inSettings = matchPath(location.pathname, {
    path: routes.game.settings,
    exact: true,
  })

  const showFabOnThisRoute = !some(
    [routes.game.pending, routes.game.lobby, routes.game.ended],
    (route) => {
      return matchPath(location.pathname, {
        path: route,
        exact: true,
      })
    }
  )

  return (
    <Box>
      <Box>{props.children}</Box>
      {showFabOnThisRoute && currentPlayer.role === PlayerRole.Host && (
        <Box display="flex" flexDirection="row-reverse" pb={2} pt={6}>
          <Fab
            color="default"
            size="small"
            onClick={() => {
              if (inSettings) {
                history.goBack()
              } else {
                history.push(
                  generatePath(routes.game.settings, {
                    joinCode: props.joinCode.toLocaleUpperCase(),
                  })
                )
              }
            }}
          >
            {inSettings ? <CloseIcon /> : <SettingsIcon />}
          </Fab>
        </Box>
      )}
    </Box>
  )
}
Example #17
Source File: breadcrumb.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
ErdaBreadcrumb = () => {
  const [currentApp] = layoutStore.useStore((s) => [s.currentApp]);
  const routes: IRoute[] = routeInfoStore.useStore((s) => s.routes);
  const [pageName, setPageName] = React.useState<string>();
  const infoMap = breadcrumbStore.useStore((s) => s.infoMap);
  const [query] = routeInfoStore.useStore((s) => [s.query]);

  const [allRoutes, setAllRoutes] = React.useState<IRoute[]>([]);
  const [params, setParams] = React.useState<Obj<string>>({});
  const [pageNameInfo, setPageNameInfo] = React.useState<Function>();
  const checkHasTemplate = React.useCallback(
    (breadcrumbName: string) => {
      const replacePattern = /\{([\w.])+\}/g;
      let _breadcrumbName = breadcrumbName || '';
      const matches = _breadcrumbName.match(replacePattern);
      if (!matches) {
        return _breadcrumbName;
      }
      matches.forEach((match: string) => {
        const [type, key] = match.slice(1, -1).split('.'); // match: {params.id}
        let value;
        if (type === 'params') {
          value = params[key];
        } else if (type === 'query') {
          value = decodeURIComponent(query[key]);
        } else {
          value = infoMap[type];
        }
        _breadcrumbName = _breadcrumbName.replace(match, value);
      });
      if (_breadcrumbName === 'undefined') {
        _breadcrumbName = '';
      }
      return _breadcrumbName;
    },
    [infoMap, params, query],
  );

  const getBreadcrumbTitle = React.useCallback(
    (route: IRoute, isBreadcrumb = false) => {
      const { breadcrumbName, pageName } = route;
      let _title = '';
      if (!isBreadcrumb && pageName) {
        _title = isFunction(pageName)
          ? breadcrumbName({ infoMap, route, params, query })
          : checkHasTemplate(pageName as string);
      } else {
        _title = isFunction(breadcrumbName)
          ? breadcrumbName({ infoMap, route, params, query })
          : checkHasTemplate(breadcrumbName as string);
      }
      return _title;
    },
    [checkHasTemplate, infoMap, params, query],
  );

  React.useEffect(() => {
    if (allRoutes.length) {
      const lastRoute = allRoutes[allRoutes.length - 1];
      const _title = getBreadcrumbTitle(lastRoute);
      setPageNameInfo(() => lastRoute?.pageNameInfo);
      setPageName(_title);
    }
  }, [allRoutes, getBreadcrumbTitle]);

  React.useEffect(() => {
    document.title = pageName ? `${pageName} · Erda` : 'Erda';
  }, [pageName]);

  React.useEffect(() => {
    let _params: Obj<string> = {};
    // get params from path
    if (routes.length > 0) {
      const match = matchPath(window.location.pathname, {
        path: routes[0].path,
        exact: true,
        strict: false,
      });
      if (match) {
        _params = match.params;
        setParams(_params);
      }
    }
    const filteredRoutes = routes.filter((route) => {
      return route.path && (route.breadcrumbName || route.pageName || typeof route.breadcrumbName === 'function');
    });
    if (!isEmpty(currentApp)) {
      const eternalApp = {
        key: currentApp.key,
        eternal: currentApp.href,
        breadcrumbName: currentApp.breadcrumbName,
        path: typeof currentApp.path === 'function' ? currentApp.path(_params || {}, routes) : currentApp.href,
      } as IRoute;
      filteredRoutes.reverse().splice(1, 0, eternalApp);
      setAllRoutes(filteredRoutes.slice(0, -1));
    }
  }, [currentApp, routes]);

  const paths: string[] = [];

  const usefullBreadcrumb = allRoutes.filter((item) => {
    if (!item.breadcrumbName) {
      return false;
    }
    return !!getBreadcrumbTitle(item, true);
  });

  return (
    <div className="flex items-center flex-shrink-0 h-9 text-xs">
      {usefullBreadcrumb.map((item, i) => {
        const isLast = i === usefullBreadcrumb.length - 1;
        paths.push(getPath(item.path, params));

        const _title = getBreadcrumbTitle(item, true);

        return (
          <div key={item.key}>
            <BreadcrumbItem paths={[...paths]} route={item} params={params} title={_title} isLast={isLast} />
            {!isLast && <ErdaIcon className="align-middle mx-1 text-sub" type="right" size="14px" />}
          </div>
        );
      })}
    </div>
  );
}
Example #18
Source File: header.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
Header = ({ layout }: { layout?: RouteConfigItem_Layout }) => {
  const { hideSidebar } = layout || {};
  const [currentApp, topButtonsWidth] = layoutStore.useStore((s) => [s.currentApp, s.topButtonsWidth]);
  const [routes, markedRoutePreview] = routeInfoStore.useStore((s) => [s.routes, s.markedRoutePreview]);
  const [pageName, setPageName] = React.useState<string>();
  const [backToUp, setBackToUp] = React.useState(0);
  const infoMap = breadcrumbStore.useStore((s) => s.infoMap);
  const [query] = routeInfoStore.useStore((s) => [s.query]);
  const [backToUpKey, setBackToUpKey] = React.useState('');

  const [allRoutes, setAllRoutes] = React.useState<IRoute[]>([]);
  const [params, setParams] = React.useState<Obj<string>>({});
  const [pageNameInfo, setPageNameInfo] = React.useState<Function>();
  const checkHasTemplate = React.useCallback(
    (breadcrumbName: string) => {
      const replacePattern = /\{([\w.])+\}/g;
      let _breadcrumbName = breadcrumbName || '';
      const matches = _breadcrumbName.match(replacePattern);
      if (!matches) {
        return _breadcrumbName;
      }
      matches.forEach((match: string) => {
        const [type, key] = match.slice(1, -1).split('.'); // match: {params.id}
        let value;
        if (type === 'params') {
          value = params[key];
        } else if (type === 'query') {
          value = decodeURIComponent(query[key]);
        } else {
          value = infoMap[type];
        }
        _breadcrumbName = _breadcrumbName.replace(match, value);
      });
      if (_breadcrumbName === 'undefined') {
        _breadcrumbName = '';
      }
      return _breadcrumbName;
    },
    [infoMap, params, query],
  );

  const getBreadcrumbTitle = React.useCallback(
    (route: IRoute, isBreadcrumb = false) => {
      const { breadcrumbName, pageName } = route;
      let _title = '';
      if (!isBreadcrumb && pageName) {
        _title = isFunction(pageName)
          ? breadcrumbName({ infoMap, route, params, query })
          : checkHasTemplate(pageName as string);
      } else {
        _title = isFunction(breadcrumbName)
          ? breadcrumbName({ infoMap, route, params, query })
          : checkHasTemplate(breadcrumbName as string);
      }
      return _title;
    },
    [checkHasTemplate, infoMap, params, query],
  );

  React.useEffect(() => {
    if (allRoutes.length) {
      const lastRoute = allRoutes[allRoutes.length - 1];
      const _title = getBreadcrumbTitle(lastRoute);
      setPageNameInfo(() => lastRoute?.pageNameInfo);
      setPageName(_title);
    }
  }, [allRoutes, getBreadcrumbTitle]);

  React.useEffect(() => {
    document.title = pageName ? `${pageName} · Erda` : 'Erda';
  }, [pageName]);

  React.useEffect(() => {
    let _params: Obj<string> = {};
    // get params from path
    if (routes.length > 0) {
      const match = matchPath(window.location.pathname, {
        path: routes[0].path,
        exact: true,
        strict: false,
      });
      if (match) {
        _params = match.params;
        setParams(_params);
      }
      let backToUpLevel = 0;
      const currentRoute = routes[0];
      if (currentRoute.backToUp) {
        const targetRoute = routes.find((a) => a.mark === currentRoute.backToUp);
        if (targetRoute) {
          backToUpLevel = location.pathname.split('/').length - targetRoute.path.split('/').length;
        }
      }
      setBackToUpKey(currentRoute.backToUp);
      setBackToUp(backToUpLevel);
    }
    const filteredRoutes = routes.filter((route) => {
      return route.path && (route.breadcrumbName || route.pageName || typeof route.breadcrumbName === 'function');
    });
    if (!isEmpty(currentApp)) {
      const eternalApp = {
        key: currentApp.key,
        eternal: currentApp.href,
        breadcrumbName: currentApp.breadcrumbName,
        path: typeof currentApp.path === 'function' ? currentApp.path(_params || {}, routes) : currentApp.href,
      };
      filteredRoutes.reverse().splice(1, 0, eternalApp as IRoute);
      setAllRoutes(filteredRoutes);
    }
  }, [currentApp, routes]);

  const displayPageName = () => {
    if (typeof pageNameInfo === 'function') {
      const Comp = pageNameInfo;
      return <Comp />;
    }
    if (backToUp) {
      const search = markedRoutePreview[backToUpKey];
      const _query = search ? { ...parse(search, { arrayFormat: 'bracket' }) } : undefined;
      return (
        <div
          className="text-xl truncate inline-flex items-center cursor-pointer"
          onClick={() => goTo('../'.repeat(backToUp), { query: _query })}
        >
          <ErdaIcon type="arrow-left" className="mr-1" />
          {allWordsFirstLetterUpper(pageName as string)}
        </div>
      );
    }
    return <div className="text-xl truncate">{allWordsFirstLetterUpper(pageName as string)}</div>;
  };

  return (
    <div className="erda-header" style={{ marginRight: topButtonsWidth }}>
      <div className={`erda-header-title-con inline-flex ${hideSidebar ? 'ml-4' : ''}`}>
        {pageName && displayPageName()}
      </div>
      <Tab />
    </div>
  );
}
Example #19
Source File: App.tsx    From back-home-safe with GNU General Public License v3.0 4 votes vote down vote up
App = () => {
  useMigration();
  const [finishedTutorial, setFinishedTutorial] = useLocalStorage(
    "finished_tutorial",
    false
  );
  const [confirmPageIcon, setConfirmPageIcon] = useLocalStorage<string | null>(
    "confirmPageIcon",
    null
  );
  const { lockStore, unlocked, isEncrypted } = useData();

  const { pathname } = useLocation();
  const browserHistory = useHistory();

  const handleBlur = useCallback(() => {
    if (pathname !== "/qrReader" && pathname !== "/cameraSetting") lockStore();
  }, [lockStore, pathname]);

  useEffect(() => {
    window.addEventListener("blur", handleBlur);
    return () => {
      window.removeEventListener("blur", handleBlur);
    };
  }, [handleBlur]);

  const pageMap = useMemo<
    { route: RouteProps; component: React.ReactNode; privateRoute: boolean }[]
  >(
    () => [
      {
        privateRoute: false,
        route: { exact: true, path: "/tutorial" },
        component: <Tutorial setFinishedTutorial={setFinishedTutorial} />,
      },
      {
        privateRoute: false,
        route: { exact: true, path: "/login" },
        component: <Login />,
      },
      {
        privateRoute: true,
        route: {
          exact: true,
          path: "/",
        },
        component: <MainScreen />,
      },
      {
        privateRoute: true,
        route: {
          exact: true,
          path: "/confirm/:id",
        },
        component: <Confirm confirmPageIcon={confirmPageIcon} />,
      },
      {
        privateRoute: true,
        route: {
          exact: true,
          path: "/qrGenerator",
        },
        component: <QRGenerator />,
      },
      {
        privateRoute: true,
        route: {
          exact: true,
          path: "/disclaimer",
        },
        component: <Disclaimer />,
      },
      {
        privateRoute: true,
        route: {
          exact: true,
          path: "/qrReader",
        },
        component: <QRReader />,
      },
      {
        privateRoute: true,
        route: {
          exact: true,
          path: "/cameraSetting",
        },
        component: <CameraSetting />,
      },
      {
        privateRoute: true,
        route: {
          exact: true,
          path: "/confirmPageSetting",
        },
        component: (
          <ConfirmPageSetting
            confirmPageIcon={confirmPageIcon}
            setConfirmPageIcon={setConfirmPageIcon}
          />
        ),
      },
      {
        privateRoute: true,
        route: {
          exact: true,
          path: "/vaccinationQRReader",
        },
        component: <VaccinationQRReader />,
      },
    ],
    [confirmPageIcon, setConfirmPageIcon, setFinishedTutorial]
  );

  // transition group cannot use switch component, thus need manual redirect handling
  // ref: https://reactcommunity.org/react-transition-group/with-react-router
  useEffect(() => {
    if (!unlocked && pathname !== "/login") {
      browserHistory.replace("/login");
    }
    if (unlocked && pathname === "/login") {
      browserHistory.replace("/");
    }
  }, [isEncrypted, unlocked, browserHistory, pathname]);

  useEffect(() => {
    if (!finishedTutorial && pathname !== "/tutorial") {
      browserHistory.replace("/tutorial");
    }
    if (finishedTutorial && pathname === "/tutorial") {
      browserHistory.replace("/");
    }
  }, [finishedTutorial, browserHistory, pathname]);

  useEffect(() => {
    const hasMatch = any(({ route }) => {
      if (!route.path) return false;
      return !isNil(matchPath(pathname, route));
    }, pageMap);

    if (!hasMatch) {
      browserHistory.replace("/");
    }
  }, [browserHistory, pathname, pageMap]);

  return (
    <>
      <GlobalStyle />
      {pageMap.map(({ route, component, privateRoute }) =>
        privateRoute && !unlocked ? (
          <React.Fragment key={String(route.path)} />
        ) : (
          <Route {...route} key={String(route.path)}>
            {({ match }) => (
              <CSSTransition
                in={match != null}
                timeout={300}
                classNames="page"
                unmountOnExit
              >
                <div className="page">
                  <Suspense fallback={<PageLoading />}>{component}</Suspense>
                </div>
              </CSSTransition>
            )}
          </Route>
        )
      )}
    </>
  );
}
Example #20
Source File: App.tsx    From iot-center-v2 with MIT License 4 votes vote down vote up
App: FunctionComponent<RouteComponentProps> = (props) => {
  const [helpCollapsed, setHelpCollapsed] = useHelpCollapsed()
  const [helpText, setHelpText] = useState('')
  const mqttEnabled = useFetchBoolean('/mqtt/enabled')

  const help = getPageHelp(props.location.pathname)

  useEffect(() => {
    setHelpText('')
    if (help) {
      // load markdown from file
      ;(async () => {
        try {
          const response = await fetch(help)
          const txt = await response.text()
          setHelpText((txt ?? '').startsWith('<!') ? 'HELP NOT FOUND' : txt)
        } catch (e) {
          console.error(e)
        }
      })()
    }
  }, [help])

  return (
    <div className="App">
      <Layout style={{minHeight: '100vh'}}>
        <Sider>
          <Menu
            theme="dark"
            selectedKeys={[
              props.location.pathname,
              ...(matchPath(props.location.pathname, '/dashboard/:device')
                ? ['/dashboard/:device']
                : []),
              ...(matchPath(props.location.pathname, '/realtime/:device')
                ? ['/realtime/:device']
                : []),
              ...(matchPath(props.location.pathname, '/dynamic/:device')
                ? ['/dynamic/:device']
                : []),
            ]}
            mode="inline"
          >
            <Menu.Item key="/home" icon={<IconHome />}>
              <NavLink to="/home">Home</NavLink>
            </Menu.Item>
            <Menu.Item key="/devices" icon={<IconDeviceRegistration />}>
              <NavLink to="/devices">Device Registrations</NavLink>
            </Menu.Item>
            <Menu.Item
              key="/devices/virtual_device"
              icon={<IconVirtualDevice />}
            >
              <NavLink to="/devices/virtual_device">Virtual Device</NavLink>
            </Menu.Item>
            <Menu.Item key="/dashboard/:device" icon={<IconDashboard />}>
              <NavLink to="/dashboard">Dashboard</NavLink>
            </Menu.Item>
            <Menu.Item
              style={mqttEnabled === true ? {} : {color: 'gray'}}
              key="/realtime/:device"
              icon={<IconRealtimeDashboard />}
            >
              <NavLink
                style={mqttEnabled === true ? {} : {color: 'gray'}}
                to="/realtime"
              >
                Realtime
              </NavLink>
            </Menu.Item>
            <Menu.Item key="/dynamic/:device" icon={<IconDynamicDashboard />}>
              <NavLink to="/dynamic">Dynamic</NavLink>
            </Menu.Item>
          </Menu>
        </Sider>
        <Switch>
          <Redirect exact from="/" to="/home" />
          <Route exact path="/home" component={HomePage} />
          <Route
            exact
            path="/devices"
            render={(props) => (
              <DevicesPage {...props} helpCollapsed={helpCollapsed} />
            )}
          />
          <Route
            exact
            path="/devices/:deviceId"
            render={(props) => (
              <DevicePage {...props} {...{helpCollapsed, mqttEnabled}} />
            )}
          />
          <Redirect
            exact
            from="/dashboard"
            to={`/dashboard/${VIRTUAL_DEVICE}`}
          />
          <Route
            exact
            path="/dashboard/:deviceId"
            render={(props) => (
              <DashboardPage {...props} helpCollapsed={helpCollapsed} />
            )}
          />
          <Redirect exact from="/realtime" to={`/realtime/${VIRTUAL_DEVICE}`} />
          <Route
            exact
            path="/realtime/:deviceId"
            render={(props) => (
              <RealTimePage {...props} {...{helpCollapsed, mqttEnabled}} />
            )}
          />
          <Redirect exact from="/dynamic" to={`/dynamic/demo`} />
          <Route
            exact
            path="/dynamic/:dashboard/:clientId?"
            render={(props) => (
              <DynamicDashboardPage
                {...props}
                {...{helpCollapsed, mqttEnabled}}
              />
            )}
          />
          <Route path="*" component={NotFoundPage} />
        </Switch>
        {helpText ? (
          <Sider
            reverseArrow
            collapsible
            collapsed={helpCollapsed}
            onCollapse={() => setHelpCollapsed(!helpCollapsed)}
            collapsedWidth={30}
            theme="light"
            width={'20vw'}
            breakpoint="sm"
          >
            <div style={{paddingLeft: 10, paddingRight: 10}}>
              <Markdown source={helpText && !helpCollapsed ? helpText : ''} />
            </div>
          </Sider>
        ) : undefined}
      </Layout>
    </div>
  )
}
Example #21
Source File: index.tsx    From ExpressLRS-Configurator with GNU General Public License v3.0 4 votes vote down vote up
Sidebar: FunctionComponent = () => {
  const location = useLocation();
  const configuratorActive =
    matchPath(location.pathname, '/configurator') !== null;
  const backpackActive = matchPath(location.pathname, '/backpack') !== null;
  // const settingsActive = matchPath(location.pathname, '/settings') !== null;
  const logsActive = matchPath(location.pathname, '/logs') !== null;
  const serialMonitorActive =
    matchPath(location.pathname, '/serial-monitor') !== null;
  const supportActive = matchPath(location.pathname, '/support') !== null;
  const { appStatus } = useAppState();

  const navigationEnabled = appStatus !== AppStatus.Busy;

  return (
    <Drawer sx={styles.drawer} variant="permanent">
      <Toolbar />
      <Divider />
      <Box sx={styles.drawerContainer}>
        <List>
          <ListItem
            component={Link}
            to="/configurator"
            selected={configuratorActive}
            sx={styles.menuItem}
            button
            disabled={!navigationEnabled}
          >
            <ListItemIcon>
              <BuildIcon />
            </ListItemIcon>
            <ListItemText primary="Configurator" />
          </ListItem>
          <ListItem
            component={Link}
            to="/backpack"
            selected={backpackActive}
            sx={styles.menuItem}
            button
            disabled={!navigationEnabled}
          >
            <ListItemIcon>
              <BackpackIcon />
            </ListItemIcon>
            <ListItemText primary="Backpack" />
          </ListItem>

          {/* <ListItem */}
          {/*  component={Link} */}
          {/*  to="/settings" */}
          {/*  selected={settingsActive} */}
          {/*  sx={styles.menuItem} */}
          {/*  button */}
          {/* > */}
          {/*  <ListItemIcon> */}
          {/*    <SettingsIcon /> */}
          {/*  </ListItemIcon> */}
          {/*  <ListItemText primary="Settings" /> */}
          {/* </ListItem> */}

          <ListItem
            component={Link}
            to="/logs"
            selected={logsActive}
            sx={styles.menuItem}
            button
            disabled={!navigationEnabled}
          >
            <ListItemIcon>
              <ListIcon />
            </ListItemIcon>
            <ListItemText primary="Logs" />
          </ListItem>

          <ListItem
            component={Link}
            to="/serial-monitor"
            selected={serialMonitorActive}
            sx={styles.menuItem}
            button
            disabled={!navigationEnabled}
          >
            <ListItemIcon>
              <DvrIcon />
            </ListItemIcon>
            <ListItemText primary="Serial Monitor" />
          </ListItem>

          <ListItem
            component={Link}
            to="/support"
            selected={supportActive}
            sx={styles.menuItem}
            button
            disabled={!navigationEnabled}
          >
            <ListItemIcon>
              <HelpIcon />
            </ListItemIcon>
            <ListItemText primary="Support" />
          </ListItem>
        </List>
      </Box>
    </Drawer>
  );
}