react-router#useNavigate TypeScript Examples

The following examples show how to use react-router#useNavigate. 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: EntityOrphanWarning.tsx    From backstage with Apache License 2.0 6 votes vote down vote up
/**
 * Displays a warning alert if the entity is marked as orphan with the ability
 * to delete said entity.
 *
 * @public
 */
export function EntityOrphanWarning() {
  const navigate = useNavigate();
  const catalogLink = useRouteRef(rootRouteRef);
  const [confirmationDialogOpen, setConfirmationDialogOpen] = useState(false);
  const { entity } = useEntity();

  const cleanUpAfterRemoval = async () => {
    setConfirmationDialogOpen(false);
    navigate(catalogLink());
  };

  return (
    <>
      <Alert severity="warning" onClick={() => setConfirmationDialogOpen(true)}>
        This entity is not referenced by any location and is therefore not
        receiving updates. Click here to delete.
      </Alert>
      <DeleteEntityDialog
        open={confirmationDialogOpen}
        entity={entity!}
        onConfirm={cleanUpAfterRemoval}
        onClose={() => setConfirmationDialogOpen(false)}
      />
    </>
  );
}
Example #2
Source File: CreatePostageStampPage.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
export function CreatePostageStampPage(): ReactElement {
  const navigate = useNavigate()

  function onFinished() {
    navigate(ROUTES.STAMPS)
  }

  return (
    <div>
      <HistoryHeader>Buy new postage stamp</HistoryHeader>
      <PostageStampCreation onFinished={onFinished} />
    </div>
  )
}
Example #3
Source File: RoutedTabs.tsx    From backstage with Apache License 2.0 6 votes vote down vote up
export function RoutedTabs(props: { routes: SubRoute[] }) {
  const { routes } = props;
  const navigate = useNavigate();
  const { index, route, element } = useSelectedSubRoute(routes);
  const headerTabs = useMemo(
    () =>
      routes.map(t => ({
        id: t.path,
        label: t.title,
        tabProps: t.tabProps,
      })),
    [routes],
  );

  const onTabChange = (tabIndex: number) =>
    // Remove trailing /*
    // And remove leading / for relative navigation
    // Note! route resolves relative to the position in the React tree,
    // not relative to current location
    navigate(routes[tabIndex].path.replace(/\/\*$/, '').replace(/^\//, ''));

  return (
    <>
      <HeaderTabs
        tabs={headerTabs}
        selectedIndex={index}
        onChange={onTabChange}
      />
      <Content>
        <Helmet title={route.title} />
        {element}
      </Content>
    </>
  );
}
Example #4
Source File: index.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
export default function Index({ header, title, p, next }: Props): ReactElement {
  const { nodeAddresses, balance } = useContext(Context)
  const navigate = useNavigate()

  if (!balance || !nodeAddresses) {
    return <Loading />
  }

  const disabled = balance.dai.toDecimal.lte(1)

  return (
    <>
      <HistoryHeader>{header}</HistoryHeader>
      <Box mb={4}>
        <TopUpProgressIndicator index={0} />
      </Box>
      <Box mb={2}>
        <Typography style={{ fontWeight: 'bold' }}>{title}</Typography>
      </Box>
      <Box mb={4}>{p}</Box>
      <SwarmDivider mb={4} />
      <Box mb={0.25}>
        <ExpandableListItemKey label="Funding wallet address" value={balance.address} expanded />
      </Box>
      <Box mb={4}>
        <ExpandableListItem label="xDAI balance" value={balance.dai.toSignificantDigits(4)} />
      </Box>
      <Grid container direction="row" justifyContent="space-between">
        <SwarmButton iconType={Check} onClick={() => navigate(next)} disabled={disabled}>
          Proceed
        </SwarmButton>
        {disabled ? <Typography>Please deposit xDAI to the address above in order to proceed.</Typography> : null}
      </Grid>
    </>
  )
}
Example #5
Source File: useCharSelectionCallback.tsx    From genshin-optimizer with MIT License 6 votes vote down vote up
/**
 * Basically a history hook to go to the dedicated character page. Will create the character if it doesn't exist.
 * @returns
 */
export default function useCharSelectionCallback() {
  const { database } = useContext(DatabaseContext)
  const navigate = useNavigate()
  // Used to maintain the previous tab, if there is one
  let { params: { tab = "" } } = useMatch({ path: "/characters/:charKey/:tab", end: false }) ?? { params: { tab: "" } }
  const cb = useCallback(
    async (characterKey: CharacterKey) => {
      const character = database._getChar(characterKey)
      let navTab = tab
      // Create a new character + weapon, with linking if char isnt in db.
      if (!character) {
        const newChar = initialCharacter(characterKey)
        database.updateChar(newChar)
        const characterSheet = await CharacterSheet.get(characterKey)
        if (!characterSheet) return
        const weapon = defaultInitialWeapon(characterSheet.weaponTypeKey)
        const weaponId = database.createWeapon(weapon)
        database.setWeaponLocation(weaponId, characterKey)
        // If we are navigating to a new character,
        // redirect to Overview, regardless of previous tab.
        // Trying to enforce a certain UI flow when building new characters
        navTab = ""
      }
      navigate(`/characters/${characterKey}/${navTab}`)
    },
    [navigate, database, tab],
  )
  return cb
}
Example #6
Source File: useRedirectMigratedContent.ts    From atlas with GNU General Public License v3.0 6 votes vote down vote up
useRedirectMigratedContent = ({ type }: { type: 'channel' | 'video' | 'embedded-video' }) => {
  const { id } = useParams() as { id?: string }
  const navigate = useNavigate()

  useEffect(() => {
    if (type !== 'channel' || !id || BUILD_ENV !== 'production') return

    const mapping = migratedContentIdMappings.channelIdsMapEntries
    const migratedId = mapping[id as keyof typeof mapping]

    if (!migratedId) return

    navigate(absoluteRoutes.viewer.channel(migratedId))
  }, [id, navigate, type])

  useEffect(() => {
    if ((type !== 'video' && type !== 'embedded-video') || !id || BUILD_ENV !== 'production') return

    const mapping = migratedContentIdMappings.videoIdsMapEntries
    const migratedId = mapping[id as keyof typeof mapping]

    if (!migratedId) return

    if (type === 'embedded-video') {
      navigate(absoluteRoutes.embedded.video(migratedId))
    } else {
      navigate(absoluteRoutes.viewer.video(migratedId))
    }
  }, [id, navigate, type])
}
Example #7
Source File: useEntityFromUrl.ts    From backstage with Apache License 2.0 6 votes vote down vote up
useEntityFromUrl = (): EntityLoadingStatus => {
  const { kind, namespace, name } = useRouteRefParams(entityRouteRef);
  const navigate = useNavigate();
  const errorApi = useApi(errorApiRef);
  const catalogApi = useApi(catalogApiRef);

  const {
    value: entity,
    error,
    loading,
    retry: refresh,
  } = useAsyncRetry(
    () => catalogApi.getEntityByRef({ kind, namespace, name }),
    [catalogApi, kind, namespace, name],
  );

  useEffect(() => {
    if (!name) {
      errorApi.post(new Error('No name provided!'));
      navigate('/');
    }
  }, [errorApi, navigate, error, loading, entity, name]);

  return { entity, loading, error, refresh };
}
Example #8
Source File: Restart.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
export default function Settings(): ReactElement {
  const [waited, setWaited] = useState(false)
  const { apiHealth } = useContext(Context)
  const navigate = useNavigate()

  useEffect(() => {
    if (waited) {
      return
    }

    const timeout = setTimeout(() => setWaited(true), 5_000)

    return () => clearTimeout(timeout)
  }, [waited])

  useEffect(() => {
    if (!waited) {
      return
    }

    if (apiHealth) {
      navigate(ROUTES.INFO)
    }
  }, [navigate, waited, apiHealth])

  return (
    <>
      <Box mb={4}>
        <Loading />
      </Box>
      <Typography>You will be redirected automatically once your node is up and running.</Typography>
    </>
  )
}
Example #9
Source File: useMetadataField.tsx    From contracts-ui with GNU General Public License v3.0 6 votes vote down vote up
useMetadataField = (): UseMetadataField => {
  const navigate = useNavigate();
  const { codeHash: codeHashUrlParam } = useParams<{ codeHash: string }>();

  const [file, setFile] = useState<OrFalsy<FileState>>(null);

  const codeBundleQuery = useCodeBundle(codeHashUrlParam || '');
  const codeBundle = codeBundleQuery.data;
  const metadata = useMetadata(codeBundle?.document?.abi, {
    isWasmRequired: !codeBundle,
    onChange: setFile,
  });

  const isLoading = useMemo(
    () => !!codeHashUrlParam && codeBundleQuery.isLoading,
    [codeHashUrlParam, codeBundleQuery.isLoading]
  );

  const isStored = useMemo((): boolean => !!codeBundle?.document, [codeBundle?.document]);

  useEffect((): void => {
    if (codeHashUrlParam && !codeBundleQuery.isValid) {
      navigate(`/instantiate/${codeHashUrlParam}`);
    }
  }, [codeHashUrlParam, codeBundleQuery.isValid, navigate]);

  return {
    file,
    isLoading,
    isStored,
    ...metadata,
  };
}
Example #10
Source File: LightModeRestart.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 6 votes vote down vote up
export default function Settings(): ReactElement {
  const [startedAt] = useState(Date.now())
  const { apiHealth, nodeInfo } = useContext(Context)
  const navigate = useNavigate()

  useEffect(() => {
    if (Date.now() - startedAt < 45_000) {
      return
    }

    if (apiHealth && nodeInfo?.beeMode === BeeModes.LIGHT) {
      navigate(ROUTES.INFO)
    }
  }, [startedAt, navigate, nodeInfo, apiHealth])

  return (
    <>
      <Box mb={4}>
        <Loading />
      </Box>
      <Typography>Your node is being upgraded to light mode... postage syncing may take up to 10 minutes.</Typography>
    </>
  )
}
Example #11
Source File: ExtensionStep.tsx    From atlas with GNU General Public License v3.0 6 votes vote down vote up
ExtensionStep: React.FC<ExtensionStepProps> = ({ nextStepPath }) => {
  const navigate = useNavigate()
  const step = useRouterQuery(QUERY_PARAMS.LOGIN)
  const { extensionConnected } = useUser()
  const [openEnableExtensionDialog, closeEnableExtensionDialog] = useConfirmationModal({
    children: <PolkadotExtensionRejected />,
    onExitClick: () => closeEnableExtensionDialog(),
  })
  useEffect(() => {
    if (extensionConnected && step === '1') {
      navigate({ search: nextStepPath })
    }
  }, [extensionConnected, navigate, nextStepPath, step])

  return (
    <StepWrapper>
      <StyledPolkadotLogo />
      <StepTitle variant="h500">Add Polkadot extension</StepTitle>
      <StepSubTitle secondary variant="t200">
        To manage your blockchain account, you will need a Polkadot browser extension. Please install it using the
        following link:
      </StepSubTitle>
      <StyledButton icon={<SvgActionNewTab />} to="https://polkadot.js.org/extension/">
        Install extension
      </StyledButton>
      <Button variant="tertiary" size="small" onClick={() => openEnableExtensionDialog()}>
        Polkadot extension already installed? Click here
      </Button>
      <StyledStepFooter>
        <BottomBarIcon />
        <Text variant="t200" secondary>
          Please reload the page and allow access after installing the extension
        </Text>
      </StyledStepFooter>
    </StepWrapper>
  )
}
Example #12
Source File: NetworkAndUser.tsx    From contracts-ui with GNU General Public License v3.0 6 votes vote down vote up
export function NetworkAndUser() {
  const { endpoint, status } = useApi();
  const navigate = useNavigate();

  return (
    <div className="network-and-user">
      <Dropdown
        className={classes(
          'chain',
          status === 'READY' ? 'isConnected' : '',
          status === 'CONNECTING' ? 'isConnecting' : '',
          status === 'ERROR' ? 'isError' : ''
        )}
        onChange={e => {
          navigate(`/?rpc=${e}`);
        }}
        options={options}
        value={options.find(o => o.value === endpoint)?.value || 'ws://127.0.0.1:9944'}
      />
    </div>
  );
}
Example #13
Source File: index.tsx    From shippo with MIT License 6 votes vote down vote up
Page_setting = () => {
  const history = useNavigate()

  return (
    <Container direction="vertical">
      <Header
        style={{
          height: '45px',
          lineHeight: '45px',
          backgroundColor: '#fff',
          textAlign: 'center',
          fontSize: '18px',
        }}
      >
        设置
      </Header>
      <WhiteSpace size={15} />
      <Main>
        <List>
          <List.Item onClick={() => {}}>编辑资料</List.Item>
          <List.Item onClick={() => {}}>账号与安全</List.Item>
        </List>
        <WhiteSpace size={15} />
        <Button
          block
          size="large"
          style={{ '--border-radius': '0px' }}
          onClick={() => {
            localStorage.removeItem('__PASSPORT')
            history('/')
          }}
        >
          退出登录
        </Button>
      </Main>
    </Container>
  )
}
Example #14
Source File: NotFound.tsx    From contracts-ui with GNU General Public License v3.0 6 votes vote down vote up
export function NotFound() {
  const navigate = useNavigate();
  return (
    <div className="w-full overflow-y-auto overflow-x-hidden px-5 py-3 m-2 flex justify-center items-center">
      <div className=" w-7/12 h-60 border dark:border-gray-700 grid place-content-center">
        <EmojiSadIcon className="w-10 h-10 text-green-400 mb-1 justify-self-center" />
        <p className="text-sm text-gray-300 mb-6">This page does not exist.</p>
        <Button onClick={() => navigate('/')} variant="primary" className="justify-self-center">
          Go Home
        </Button>
      </div>
    </div>
  );
}
Example #15
Source File: index.tsx    From shippo with MIT License 6 votes vote down vote up
My = () => {
  const history = useNavigate()

  return (
    <Container direction="vertical">
      <Header
        style={{
          height: '45px',
          lineHeight: '45px',
          backgroundColor: '#fff',
          textAlign: 'center',
          fontSize: '18px',
        }}
      >
        我
      </Header>
      <WhiteSpace size={15} />
      <Main>
        <UserInfoCard />
        <WhiteSpace size={15} />
        <List>
          <List.Item prefix={<BellOutlined />} onClick={() => {}}>
            通知
          </List.Item>
          <List.Item prefix={<ProfileOutlined />} onClick={() => {}}>
            我的作品
          </List.Item>
          <List.Item prefix={<SettingOutlined />} onClick={() => history('/setting')}>
            设置
          </List.Item>
        </List>
      </Main>
    </Container>
  )
}
Example #16
Source File: ConfirmModal.tsx    From raspiblitz-web with MIT License 6 votes vote down vote up
ConfirmModal: FC<Props> = ({ confirmText, confirmEndpoint, onClose }) => {
  const { t } = useTranslation();
  const { setIsLoggedIn } = useContext(AppContext);
  const navigate = useNavigate();

  const shutdownHandler = async () => {
    const resp = await instance.post(confirmEndpoint);
    if (resp.status === 200) {
      setIsLoggedIn(false);
      navigate("/login");
    }
  };

  return createPortal(
    <ModalDialog close={onClose}>
      {confirmText}
      <div className="flex flex-col p-3 xl:flex-row">
        <button className={btnClasses} onClick={onClose}>
          {t("settings.cancel")}
        </button>
        <button className={btnClasses} onClick={shutdownHandler}>
          {t("settings.confirm")}
        </button>
      </div>
    </ModalDialog>,
    MODAL_ROOT
  );
}
Example #17
Source File: GiftCardTopUpIndex.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
export function GiftCardTopUpIndex(): ReactElement {
  const [loading, setLoading] = useState(false)
  const [giftCode, setGiftCode] = useState('')

  const { enqueueSnackbar } = useSnackbar()
  const navigate = useNavigate()

  async function onProceed() {
    setLoading(true)
    try {
      const wallet = getWalletFromPrivateKeyString(giftCode)
      const dai = new DaiToken(await Rpc._eth_getBalance(wallet.getAddressString()))
      const bzz = new BzzToken(await Rpc._eth_getBalanceERC20(wallet.getAddressString()))

      if (dai.toDecimal.lt(0.001) || bzz.toDecimal.lt(0.001)) {
        throw Error('Gift wallet does not have enough funds')
      }
      enqueueSnackbar('Successfully verified gift wallet', { variant: 'success' })
      navigate(ROUTES.TOP_UP_GIFT_CODE_FUND.replace(':privateKeyString', giftCode))
    } catch (error) {
      enqueueSnackbar(`Gift wallet could not be verified: ${error}`, { variant: 'error' })
    } finally {
      setLoading(false)
    }
  }

  return (
    <>
      <HistoryHeader>Top-up with gift code</HistoryHeader>
      <Box mb={4}>
        <ProgressIndicator index={0} steps={['Paste gift code', 'Fund your node']} />
      </Box>
      <Box mb={2}>
        <Typography style={{ fontWeight: 'bold' }}>Please paste your gift code below</Typography>
      </Box>
      <Box mb={4}>
        A gift code is a unique key to a gift wallet that you can use to fund your node. Please don&apos;t share your
        gift code as it can only be used once.
      </Box>
      <SwarmDivider mb={4} />
      <Box mb={2}>
        <SwarmTextInput
          label="Gift code"
          name="gift-code"
          onChange={event => {
            setGiftCode(event.target.value)
          }}
        />
      </Box>
      <SwarmButton iconType={ArrowRight} loading={loading} disabled={loading} onClick={onProceed}>
        Proceed
      </SwarmButton>
    </>
  )
}
Example #18
Source File: VersioningStrategy.tsx    From backstage with Apache License 2.0 5 votes vote down vote up
export function VersioningStrategy() {
  const navigate = useNavigate();
  const { project } = useProjectContext();
  const { getParsedQuery, getQueryParamsWithUpdates } = useQueryHandler();

  useEffect(() => {
    const { parsedQuery } = getParsedQuery();

    if (!parsedQuery.versioningStrategy && !project.isProvidedViaProps) {
      const { queryParams } = getQueryParamsWithUpdates({
        updates: [
          { key: 'versioningStrategy', value: project.versioningStrategy },
        ],
      });

      navigate(`?${queryParams}`, { replace: true });
    }
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  return (
    <FormControl
      component="fieldset"
      required
      disabled={project.isProvidedViaProps}
    >
      <FormLabel component="legend">Versioning strategy</FormLabel>

      <RadioGroup
        data-testid={TEST_IDS.form.versioningStrategy.radioGroup}
        aria-label="calendar-strategy"
        name="calendar-strategy"
        value={project.versioningStrategy}
        onChange={event => {
          const { queryParams } = getQueryParamsWithUpdates({
            updates: [{ key: 'versioningStrategy', value: event.target.value }],
          });

          navigate(`?${queryParams}`, { replace: true });
        }}
      >
        <FormControlLabel
          value={VERSIONING_STRATEGIES.semver}
          control={<Radio />}
          label="Semantic versioning"
        />

        <FormControlLabel
          value={VERSIONING_STRATEGIES.calver}
          control={<Radio />}
          label="Calendar versioning"
        />
      </RadioGroup>
    </FormControl>
  );
}
Example #19
Source File: ExpandableListItemLink.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
export default function ExpandableListItemLink({
  label,
  value,
  link,
  navigationType = 'NEW_WINDOW',
  allowClipboard = true,
}: Props): ReactElement | null {
  const classes = useStyles()
  const [copied, setCopied] = useState(false)
  const navigate = useNavigate()

  const tooltipClickHandler = () => setCopied(true)
  const tooltipCloseHandler = () => setCopied(false)

  const displayValue = value.length > 22 ? value.slice(0, 19) + '...' : value

  function onNavigation() {
    if (navigationType === 'NEW_WINDOW') {
      window.open(link || value)
    } else {
      navigate(link || value)
    }
  }

  return (
    <ListItem className={classes.header}>
      <Grid container direction="column" justifyContent="space-between" alignItems="stretch">
        <Grid container direction="row" justifyContent="space-between" alignItems="center">
          {label && <Typography variant="body1">{label}</Typography>}
          <Typography variant="body2">
            <div>
              {allowClipboard && (
                <span className={classes.copyValue}>
                  <Tooltip title={copied ? 'Copied' : 'Copy'} placement="top" arrow onClose={tooltipCloseHandler}>
                    <CopyToClipboard text={value}>
                      <span onClick={tooltipClickHandler}>{displayValue}</span>
                    </CopyToClipboard>
                  </Tooltip>
                </span>
              )}
              {!allowClipboard && <span onClick={onNavigation}>{displayValue}</span>}
              <IconButton size="small" className={classes.openLinkIcon}>
                {navigationType === 'NEW_WINDOW' && <OpenInNewSharp onClick={onNavigation} strokeWidth={1} />}
                {navigationType === 'HISTORY_PUSH' && <ArrowForward onClick={onNavigation} strokeWidth={1} />}
              </IconButton>
            </div>
          </Typography>
        </Grid>
      </Grid>
    </ListItem>
  )
}
Example #20
Source File: SignInStepsStepper.tsx    From atlas with GNU General Public License v3.0 5 votes vote down vote up
SignInStepsStepper: React.FC = () => {
  const headTags = useHeadTags('Sign in')
  const [selectedAccountAddress, setSelectedAccountAddress] = useState<undefined | string>()
  const navigate = useNavigate()
  const step = useRouterQuery(QUERY_PARAMS.LOGIN)
  const stepNumber = Number(step)
  const { extensionConnected, signIn, isLoading } = useUser()

  const steps = [
    {
      title: 'Add Polkadot extension',
      element: <ExtensionStep nextStepPath={urlParams({ [QUERY_PARAMS.LOGIN]: 2 })} />,
    },
    {
      title: 'Connect account',
      element: (
        <AccountStep
          nextStepPath={urlParams({ [QUERY_PARAMS.LOGIN]: 3 })}
          selectedAccountAddress={selectedAccountAddress}
          setSelectedAccountAddress={setSelectedAccountAddress}
        />
      ),
    },
    {
      title: 'Accept ToS',
      element: <TermsStep />,
    },
  ]

  useEffect(() => {
    if (extensionConnected === null && stepNumber >= 1) {
      signIn()
    }
  }, [extensionConnected, signIn, stepNumber])

  const showStepper = stepNumber >= 1 && !isLoading
  const showCreateMemberModal = step === 'member'

  return (
    <>
      {(showStepper || showCreateMemberModal) && headTags}
      <StepperModal
        currentStepIdx={stepNumber <= 0 ? 0 : stepNumber - 1}
        steps={steps}
        show={showStepper}
        onExitClick={() => {
          navigate({ search: '' })
        }}
      />
      <CreateMemberModal show={showCreateMemberModal} selectedAccountAddress={selectedAccountAddress} />
    </>
  )
}
Example #21
Source File: pager.tsx    From UsTaxes with GNU Affero General Public License v3.0 5 votes vote down vote up
PagerProvider = <A extends Page>({
  children,
  pages
}: PropsWithChildren<PagerProviderProps<A>>): ReactElement => {
  const lookup = new Map(pages.map((p, i) => [p.url, i]))

  const currentLoc = useLocation()
  const currentPage = lookup.get(currentLoc.pathname) ?? 0

  const navigate = useNavigate()

  const onAdvance: (() => void) | undefined = (() => {
    if (currentPage < pages.length - 1) {
      return () => navigate(pages[currentPage + 1].url)
    }
  })()

  const prev = currentPage > 0 ? pages[currentPage - 1] : undefined

  const navButtons: ReactElement = (
    <PagerButtons
      previousUrl={prev?.url}
      submitText={onAdvance !== undefined ? 'Save and Continue' : undefined}
    />
  )

  return (
    <PagerContext.Provider
      value={{
        onAdvance:
          onAdvance ??
          (() => {
            // end of pages
          }),
        navButtons
      }}
    >
      {children}
    </PagerContext.Provider>
  )
}
Example #22
Source File: ResultWrapper.tsx    From atlas with GNU General Public License v3.0 5 votes vote down vote up
ResultWrapper: React.FC<SearchItemProps> = ({
  to,
  onDelete,
  children,
  onClick,
  selected,
  handleSelectedItem,
  variant = 'default',
  selectedItem,
}) => {
  const wrapperRef = useRef<HTMLAnchorElement>(null)
  const navigate = useNavigate()

  useEffect(() => {
    const onKeyPress = (event: KeyboardEvent) => {
      if (event.key === 'Enter' && selected && to) {
        event.preventDefault()
        navigate(to)
      }
    }
    window.addEventListener('keydown', onKeyPress)
    return () => {
      window.removeEventListener('keydown', onKeyPress)
    }
  }, [navigate, selected, to])

  useEffect(() => {
    if (selected && wrapperRef.current) {
      handleSelectedItem(wrapperRef.current.offsetTop)
    }
  }, [handleSelectedItem, selected])

  return (
    <SearchItemWrapper
      to={to}
      onClick={onClick}
      selected={selected}
      ref={wrapperRef}
      variant={variant}
      selectedItem={selectedItem}
    >
      <SearchItemContent>{children}</SearchItemContent>
      <Shortcut>
        <Text secondary variant="t100">
          Select
        </Text>
        <ShortcutIndicator>↩</ShortcutIndicator>
      </Shortcut>
      {onDelete && (
        <DeleteButton
          size="small"
          onClick={(event) => {
            event.preventDefault()
            event.stopPropagation()
            onDelete()
          }}
          variant="tertiary"
        >
          <SvgActionClose />
        </DeleteButton>
      )}
    </SearchItemWrapper>
  )
}
Example #23
Source File: LookUpCodeHash.tsx    From contracts-ui with GNU General Public License v3.0 5 votes vote down vote up
export function LookUpCodeHash() {
  const navigate = useNavigate();
  const { api } = useApi();
  const [searchString, setSearchString] = useState('');
  const [codeHash, setCodeHash] = useState('');
  const { data: searchResults } = useCodeBundleSearch(searchString);
  const { data, error, isLoading, isValid } = useCodeBundle(codeHash);
  const { document } = data || { document: null };
  useEffect((): void => {
    if (codeHash !== searchString) {
      if (searchString === '' || isValidCodeHash(searchString)) {
        checkOnChainCode(api, searchString)
          .then(isOnChain => (isOnChain ? setCodeHash(searchString) : setCodeHash('')))
          .catch(console.error);
      } else {
        setCodeHash('');
      }
    }
  }, [api, codeHash, searchString]);

  useEffect((): void => {
    codeHash && setSearchString(codeHash);
  }, [codeHash]);

  return (
    <FormField className="h-36 relative" label="Look Up Code Hash">
      <Input
        className={classes('relative flex items-center')}
        onChange={setSearchString}
        placeholder="Paste a code hash or search for existing code bundles already on-chain"
        value={searchString}
      >
        {document && (
          <button className="absolute right-2" onClick={() => setSearchString('')}>
            <XCircleIcon className="w-5 h-5 text-gray-500" aria-hidden="true" />
          </button>
        )}
      </Input>
      <SearchResults
        codeBundles={searchResults}
        isOpen={!codeHash && searchString.length > 0}
        onSelectCodeBundle={document => {
          setCodeHash(document.codeHash);
        }}
      />
      {codeHash && !isLoading && document && (
        <CodeHash
          className="mt-1"
          codeHash={codeHash}
          error={error}
          isError={!isValid}
          isSuccess={isValid}
          name={document?.name || 'On-chain Code Exists'}
          onClick={isValid ? () => navigate(`/instantiate/${codeHash}`) : undefined}
        />
      )}
    </FormField>
  );
}
Example #24
Source File: MemberActivity.tsx    From atlas with GNU General Public License v3.0 5 votes vote down vote up
MemberActivity: React.FC<MemberActivityProps> = ({ memberId, sort = 'createdAt_DESC' }) => {
  const { activities, loading, activitiesTotalCounts } = useActivities(memberId, sort)
  const navigate = useNavigate()
  const placeholderItems = Array.from({ length: PLACEHOLDERS_COUNT }, () => ({ id: undefined }))
  const items = activities && !loading ? activities : (placeholderItems as ActivitiesRecord[])
  return (
    <section>
      {activities?.length === 0 ? (
        <EmptyFallback title="No activity" subtitle="Go out there and explore!" variant="small" />
      ) : (
        <LayoutGrid>
          <GridItem colSpan={{ base: 12, sm: 8 }} rowStart={{ base: 2, sm: 1 }}>
            <LayoutGrid>
              {items?.map((activity, i) => (
                <GridItem key={i} colSpan={{ base: 12 }}>
                  <ActivityItemWithResolvedAsset
                    loading={!activities || loading}
                    onItemClick={() => navigate(absoluteRoutes.viewer.video(activity.video?.id))}
                    date={activity?.date}
                    type={activity?.type}
                    title={activity?.video?.title}
                    description={getDescription(activity)}
                    thumbnailPhoto={activity.video?.thumbnailPhoto}
                  />
                </GridItem>
              ))}
            </LayoutGrid>
          </GridItem>
          {!loading && activitiesTotalCounts && (
            <GridItem colSpan={{ base: 12, sm: 3 }} colStart={{ sm: -4 }}>
              <Text variant="h500">Overview</Text>
              <OverviewContainer>
                <OverviewItem>
                  <StyledIconWrapper icon={<SvgActionBuyNow />} size="large" />
                  <OverviewTextContainer>
                    <Text variant="t100" secondary>
                      NFTs bought
                    </Text>
                    <Text variant="t300">{activitiesTotalCounts.nftsBoughts}</Text>
                  </OverviewTextContainer>
                </OverviewItem>
                <OverviewItem>
                  <StyledIconWrapper icon={<SvgActionSell />} size="large" />
                  <OverviewTextContainer>
                    <Text variant="t100" secondary>
                      NFTs sold
                    </Text>
                    <Text variant="t300">{activitiesTotalCounts.nftsSold}</Text>
                  </OverviewTextContainer>
                </OverviewItem>
                <GridRowWrapper>
                  <OverviewItem>
                    <StyledIconWrapper icon={<SvgActionMint />} size="large" />
                    <OverviewTextContainer>
                      <Text variant="t100" secondary>
                        NFTs created
                      </Text>
                      <Text variant="t300">{activitiesTotalCounts.nftsIssued}</Text>
                    </OverviewTextContainer>
                  </OverviewItem>
                  <OverviewItem>
                    <StyledIconWrapper icon={<SvgActionBid />} size="large" />
                    <OverviewTextContainer>
                      <Text variant="t100" secondary>
                        Bid placed
                      </Text>
                      <Text variant="t300">{activitiesTotalCounts.nftsBidded}</Text>
                    </OverviewTextContainer>
                  </OverviewItem>
                </GridRowWrapper>
              </OverviewContainer>
            </GridItem>
          )}
        </LayoutGrid>
      )}
    </section>
  )
}
Example #25
Source File: AppWrapper.tsx    From flood with GNU General Public License v3.0 5 votes vote down vote up
AppWrapper: FC<AppWrapperProps> = observer(({children, className}: AppWrapperProps) => {
  const navigate = useNavigate();

  const [searchParams] = useSearchParams();

  useEffectOnce(() => {
    AuthActions.verify().then(
      ({initialUser}: {initialUser?: boolean}): void => {
        if (initialUser) {
          navigate('/register', {replace: true});
        } else {
          navigate('/overview', {replace: true});
        }
      },
      (): void => {
        navigate('/login', {replace: true});
      },
    );
  });

  if (searchParams.has('action')) {
    if (searchParams.get('action') === 'add-urls') {
      if (searchParams.has('url')) {
        UIStore.setActiveModal({
          id: 'add-torrents',
          tab: 'by-url',
          urls: [{id: 0, value: searchParams.get('url') as string}],
        });
      }
    }
  }

  let overlay: ReactNode = null;
  if (!AuthStore.isAuthenticating || (AuthStore.isAuthenticated && !UIStore.haveUIDependenciesResolved)) {
    overlay = <LoadingOverlay dependencies={UIStore.dependencies} />;
  }

  if (AuthStore.isAuthenticated && !ClientStatusStore.isConnected && ConfigStore.authMethod !== 'none') {
    overlay = (
      <div className="application__loading-overlay">
        <div className="application__entry-barrier">
          <LogoutButton className={css({position: 'absolute', left: '5px', top: '5px'})} />
          <ClientConnectionInterruption />
        </div>
      </div>
    );
  }

  return (
    <div className={classnames('application', className)}>
      <WindowTitle />
      <TransitionGroup>
        {overlay != null ? (
          <CSSTransition timeout={{enter: 1000, exit: 1000}} classNames="application__loading-overlay">
            {overlay}
          </CSSTransition>
        ) : null}
      </TransitionGroup>
      {children}
    </div>
  );
})
Example #26
Source File: VideoTileViewer.tsx    From atlas with GNU General Public License v3.0 5 votes vote down vote up
VideoTileViewer: React.FC<VideoTileViewerProps> = ({ id, onClick, detailsVariant, direction }) => {
  const { copyToClipboard } = useClipboard()
  const navigate = useNavigate()
  const { video, loading } = useBasicVideo(id ?? '', {
    skip: !id,
    onError: (error) => SentryLogger.error('Failed to fetch video', 'VideoTile', error, { video: { id } }),
  })
  const { avatarPhotoUrl, isLoadingAvatar, isLoadingThumbnail, thumbnailPhotoUrl, videoHref } =
    useVideoTileSharedLogic(video)

  const handleCopyVideoURLClick = useCallback(() => {
    copyToClipboard(videoHref ? location.origin + videoHref : '', 'Video URL copied to clipboard')
  }, [videoHref, copyToClipboard])

  const channelHref = absoluteRoutes.viewer.channel(video?.channel.id)

  return (
    <VideoTile
      onClick={onClick}
      detailsVariant={detailsVariant}
      videoHref={videoHref}
      channelHref={channelHref}
      onChannelAvatarClick={() => navigate(channelHref)}
      loadingDetails={loading || !video}
      loadingThumbnail={isLoadingThumbnail}
      thumbnailUrl={thumbnailPhotoUrl}
      views={video?.views}
      createdAt={video?.createdAt}
      slots={{
        bottomRight: {
          element: video?.duration ? (
            <Pill variant="overlay" label={formatDurationShort(video?.duration)} title="Video duration" />
          ) : null,
        },
        bottomLeft:
          video && video?.nft
            ? {
                element: <Pill label="NFT" variant="overlay" title="NFT" />,
              }
            : undefined,
        center: {
          element: <SvgIllustrativePlay />,
          type: 'hover',
        },
      }}
      channelAvatarUrl={avatarPhotoUrl}
      loadingAvatar={isLoadingAvatar}
      channelTitle={video?.channel?.title}
      videoTitle={video?.title}
      kebabMenuItems={[
        {
          icon: <SvgActionCopy />,
          onClick: handleCopyVideoURLClick,
          title: 'Copy video URL',
        },
      ]}
      direction={direction}
    />
  )
}
Example #27
Source File: index.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
export default function Stamp(): ReactElement {
  const classes = useStyles()

  const navigate = useNavigate()

  const { stamps, isLoading, error, start, stop } = useContext(StampsContext)
  const { status } = useContext(BeeContext)

  useEffect(() => {
    if (!status.all) return
    start()

    return () => stop()
  }, [status]) // eslint-disable-line react-hooks/exhaustive-deps

  if (status.all === CheckState.ERROR) return <TroubleshootConnectionCard />

  function navigateToNewStamp() {
    navigate(ROUTES.STAMPS_NEW)
  }

  return (
    <div className={classes.root}>
      {error && (
        <Container style={{ textAlign: 'center', padding: '50px' }}>
          Error loading postage stamps details: {error.message}
        </Container>
      )}
      {!error && (
        <>
          <div className={classes.actions}>
            <SwarmButton onClick={navigateToNewStamp} iconType={PlusSquare}>
              Buy New Postage Stamp
            </SwarmButton>
            <div style={{ height: '5px' }}>{isLoading && <CircularProgress />}</div>
          </div>
          <StampsTable postageStamps={stamps} />
        </>
      )}
    </div>
  )
}
Example #28
Source File: AuthForm.tsx    From flood with GNU General Public License v3.0 4 votes vote down vote up
AuthForm: FC<AuthFormProps> = ({mode}: AuthFormProps) => {
  const {i18n} = useLingui();
  const formRef = useRef<Form>(null);
  const clientConnectionSettingsRef = useRef<ClientConnectionSettings | null>(null);
  const [errorMessage, setErrorMessage] = useState<string | {id: string} | undefined>(undefined);
  const [isSubmitting, setIsSubmitting] = useState<boolean>(false);

  const navigate = useNavigate();

  const isLoginMode = mode === 'login';

  return (
    <div className="application__entry-barrier">
      <Panel spacing="large">
        <Form
          onSubmit={(submission) => {
            submission.event.preventDefault();

            setIsSubmitting(true);

            const formData = submission.formData as Partial<LoginFormData> | Partial<RegisterFormData>;

            if (formData.username == null || formData.username === '') {
              setIsSubmitting(false);
              setErrorMessage({id: 'auth.error.username.empty'});
              return;
            }

            if (formData.password == null || formData.password === '') {
              setIsSubmitting(false);
              setErrorMessage({id: 'auth.error.password.empty'});
              return;
            }

            if (isLoginMode) {
              const credentials = formData as LoginFormData;

              AuthActions.authenticate({
                username: credentials.username,
                password: credentials.password,
              })
                .then(() => {
                  setIsSubmitting(false);
                  navigate('/overview', {replace: true});
                })
                .catch((error: Error) => {
                  setIsSubmitting(false);
                  setErrorMessage(error.message);
                  navigate('/login', {replace: true});
                });
            } else {
              const config = formData as RegisterFormData;

              if (clientConnectionSettingsRef.current == null) {
                setIsSubmitting(false);
                setErrorMessage({id: 'connection.settings.error.empty'});
                return;
              }

              const connectionSettings = clientConnectionSettingsRef.current;
              if (connectionSettings == null) {
                setIsSubmitting(false);
                setErrorMessage({id: 'connection.settings.error.empty'});
                return;
              }

              AuthActions.register({
                username: config.username,
                password: config.password,
                client: connectionSettings,
                level: AccessLevel.ADMINISTRATOR,
              }).then(
                () => {
                  setIsSubmitting(false);
                  navigate('/overview', {replace: true});
                },
                (error: Error) => {
                  setIsSubmitting(false);
                  setErrorMessage(error.message);
                },
              );
            }
          }}
          ref={formRef}
        >
          <PanelHeader>
            <h1>{isLoginMode ? i18n._('auth.login') : i18n._('auth.create.an.account')}</h1>
          </PanelHeader>
          <PanelContent>
            <p className="copy--lead">
              {isLoginMode ? i18n._('auth.login.intro') : i18n._('auth.create.an.account.intro')}
            </p>
            {errorMessage != null ? (
              <FormRow>
                <FormError isLoading={isSubmitting}>
                  {typeof errorMessage === 'string' ? errorMessage : i18n._(errorMessage)}
                </FormError>
              </FormRow>
            ) : null}
            <FormRow>
              <Textbox placeholder={i18n._('auth.username')} id="username" autoComplete="username" />
            </FormRow>
            <FormRow>
              <Textbox
                placeholder={i18n._('auth.password')}
                id="password"
                type="password"
                autoComplete={isLoginMode ? 'current-password' : 'new-password'}
              />
            </FormRow>
          </PanelContent>
          {isLoginMode ? null : (
            <PanelContent hasBorder>
              <ClientConnectionSettingsForm
                onSettingsChange={(settings) => {
                  clientConnectionSettingsRef.current = settings;
                }}
              />
            </PanelContent>
          )}
          <PanelFooter hasBorder>
            <FormRow justify="end">
              <Button
                priority="tertiary"
                onClick={() => {
                  if (formRef.current != null) {
                    formRef.current.resetForm();
                  }
                }}
              >
                {i18n._('auth.input.clear')}
              </Button>
              <Button isLoading={isSubmitting} type="submit">
                {isLoginMode ? i18n._('auth.log.in') : i18n._('auth.create.account')}
              </Button>
            </FormRow>
          </PanelFooter>
        </Form>
      </Panel>
    </div>
  );
}
Example #29
Source File: Swap.tsx    From bee-dashboard with BSD 3-Clause "New" or "Revised" License 4 votes vote down vote up
export function Swap({ header }: Props): ReactElement {
  const [loading, setLoading] = useState(false)
  const [hasSwapped, setSwapped] = useState(false)

  const { jsonRpcProvider } = useContext(TopUpContext)
  const { balance } = useContext(BeeContext)

  const navigate = useNavigate()
  const { enqueueSnackbar } = useSnackbar()

  if (!balance) {
    return <Loading />
  }

  const daiToSwap = balance.dai.minusBaseUnits('1')

  const daiAfterSwap = new DaiToken(balance.dai.toBigNumber.minus(daiToSwap.toBigNumber))
  const bzzAfterSwap = new BzzToken(daiToSwap.toBigNumber.dividedToIntegerBy(200))

  async function onSwap() {
    if (hasSwapped) {
      return
    }
    setLoading(true)
    setSwapped(true)
    try {
      await performSwap(daiToSwap.toString)
      enqueueSnackbar('Successfully swapped, restarting...', { variant: 'success' })
      await sleepMs(5_000)
      await upgradeToLightNode(jsonRpcProvider)
      await restartBeeNode()
      navigate(ROUTES.RESTART_LIGHT)
      enqueueSnackbar('Upgraded to light node', { variant: 'success' })
    } catch (error) {
      enqueueSnackbar(`Failed to swap: ${error}`, { variant: 'error' })
    } finally {
      setLoading(false)
    }
  }

  return (
    <>
      <HistoryHeader>{header}</HistoryHeader>
      <Box mb={4}>
        <TopUpProgressIndicator index={1} />
      </Box>
      <Box mb={2}>
        <Typography style={{ fontWeight: 'bold' }}>Swap some xDAI to BZZ</Typography>
      </Box>
      <Box mb={4}>
        <Typography>
          You need to swap xDAI to BZZ in order to use Swarm. Make sure to keep at least 1 xDAI in order to pay for
          transaction costs on the network.
        </Typography>
      </Box>
      <SwarmDivider mb={4} />
      <Box mb={4}>
        <Typography>
          Your current balance is {balance.dai.toSignificantDigits(4)} xDAI and {balance.bzz.toSignificantDigits(4)}{' '}
          BZZ.
        </Typography>
      </Box>
      <Box mb={4}>
        <SwarmTextInput
          label="Amount to swap"
          defaultValue={`${daiToSwap.toSignificantDigits(4)} XDAI`}
          name="x"
          onChange={() => false}
        />
      </Box>
      <Box mb={4}>
        <ArrowDown size={24} color="#aaaaaa" />
      </Box>
      <Box mb={0.25}>
        <ExpandableListItemKey label="Funding wallet address" value={balance.address} expanded />
      </Box>
      <Box mb={0.25}>
        <ExpandableListItem
          label="Resulting XDAI balance after swap"
          value={`${daiAfterSwap.toSignificantDigits(4)} XDAI`}
        />
      </Box>
      <Box mb={2}>
        <ExpandableListItem
          label="Resulting BZZ balance after swap"
          value={`${bzzAfterSwap.toSignificantDigits(4)} BZZ`}
        />
      </Box>
      <ExpandableListItemActions>
        <SwarmButton
          iconType={Check}
          onClick={onSwap}
          disabled={hasSwapped || loading || balance.dai.toDecimal.lte(1)}
          loading={loading}
        >
          Swap Now
        </SwarmButton>
      </ExpandableListItemActions>
    </>
  )
}