react-router#useMatch TypeScript Examples

The following examples show how to use react-router#useMatch. 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: 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 #2
Source File: hooks.ts    From atlas with GNU General Public License v3.0 5 votes vote down vote up
useVideoWorkspaceRouting = (): Location => {
  const navigate = useNavigate()

  const location = useLocation()
  const locationState = location.state as RoutingState
  const [cachedLocation, setCachedLocation] = useState<Location>()

  const videoWorkspaceMatch = useMatch(WORKSPACE_MATCH)
  const { isWorkspaceOpen, setIsWorkspaceOpen } = useVideoWorkspace()
  const [cachedIsWorkspaceOpen, setCachedIsWorkspaceOpen] = useState(false)

  useEffect(() => {
    if (location === cachedLocation) {
      return
    }
    setCachedLocation(location)

    if (videoWorkspaceMatch && !isWorkspaceOpen) {
      // route changed to video edit
      const state: RoutingState = {
        overlaidLocation: cachedLocation ?? defaultLocation,
      }
      navigate(location, { replace: true, state })
      setIsWorkspaceOpen(true)
    }
  }, [location, cachedLocation, videoWorkspaceMatch, navigate, isWorkspaceOpen, setIsWorkspaceOpen])

  useEffect(() => {
    if (isWorkspaceOpen === cachedIsWorkspaceOpen) {
      return
    }
    setCachedIsWorkspaceOpen(isWorkspaceOpen)

    if (!isWorkspaceOpen) {
      // restore the old location when videoWorkspace was closed
      const oldLocation = locationState?.overlaidLocation ?? absoluteRoutes.studio.index()
      navigate(oldLocation)
    }
    if (isWorkspaceOpen && !videoWorkspaceMatch) {
      // isWorkspaceOpen changed without the route change, change URL and save current location
      const state: RoutingState = {
        overlaidLocation: location,
      }
      navigate(absoluteRoutes.studio.videoWorkspace(), { state: state })
    }
  }, [cachedIsWorkspaceOpen, isWorkspaceOpen, location, locationState, navigate, videoWorkspaceMatch])

  if (videoWorkspaceMatch) {
    return locationState?.overlaidLocation ?? cachedLocation ?? defaultLocation
  }

  return location
}
Example #3
Source File: CreateMemberModal.tsx    From atlas with GNU General Public License v3.0 4 votes vote down vote up
CreateMemberModal: React.FC<CreateMemberModalProps> = ({ show, selectedAccountAddress }) => {
  const { activeAccountId, refetchMemberships, extensionConnected, setActiveUser } = useUser()
  const nodeConnectionStatus = useConnectionStatusStore((state) => state.nodeConnectionStatus)
  const navigate = useNavigate()
  const { pathname } = useLocation()
  const isSignIn = useMatch(absoluteRoutes.studio.signIn())
  const isStudio = pathname.search(absoluteRoutes.studio.index()) !== -1
  const accountIdRef = useRef(activeAccountId)

  const [membershipBlock, setMembershipBlock] = useState<number | null>(null)
  const [openCreatingMemberDialog, closeCreatingMemberDialog] = useConfirmationModal({
    headerIcon: <Loader variant="medium" />,
    title: 'Creating membership...',
    description:
      "Please wait while your membership is being created. Our faucet server will create it for you so you don't need to worry about any fees. This should take about 15 seconds.",
  })
  const [isCreatingMembership, setIsCreatingMembership] = useState(false)
  const [openErrorDialog, closeErrorDialog] = useConfirmationModal()
  const { displaySnackbar } = useSnackbar()

  const { queryNodeState, error: queryNodeStateError } = useQueryNodeStateSubscription({ skip: !membershipBlock })
  // subscription doesn't allow 'onError' callback
  useEffect(() => {
    if (!queryNodeStateError) return
    SentryLogger.error('Failed to subscribe to query node state', 'CreateMemberView', queryNodeStateError)
  }, [queryNodeStateError])

  const accountSet = !!selectedAccountAddress && !!extensionConnected

  const { reset, register, errors, handleSubmit, isValid, getValues, watch } = useCreateEditMemberForm({})

  // success
  useEffect(() => {
    if (!membershipBlock || !queryNodeState || !activeAccountId) {
      return
    }

    if (queryNodeState.indexerHead >= membershipBlock) {
      // trigger membership refetch
      closeCreatingMemberDialog()
      refetchMemberships().then(({ data }) => {
        const lastCreatedMembership = data.memberships[data.memberships.length - 1]
        if (lastCreatedMembership) {
          setActiveUser({ memberId: lastCreatedMembership.id, channelId: null })
        }
      })
      setIsCreatingMembership(false)
      reset()
      setMembershipBlock(null)
      displaySnackbar({
        title: 'Your membership has been created',
        description: 'Browse, watch, create, collect videos across the platform and have fun!',
        iconType: 'success',
      })

      if (isStudio) {
        navigate(isSignIn ? absoluteRoutes.studio.newChannel() : absoluteRoutes.studio.signIn())
      } else {
        navigate(pathname)
      }
    }
  }, [
    activeAccountId,
    closeCreatingMemberDialog,
    displaySnackbar,
    isSignIn,
    isStudio,
    membershipBlock,
    navigate,
    pathname,
    queryNodeState,
    refetchMemberships,
    reset,
    setActiveUser,
  ])

  const handleCreateMember = handleSubmit(async (data) => {
    if (!selectedAccountAddress) {
      return
    }

    try {
      setActiveUser({ accountId: selectedAccountAddress })
      openCreatingMemberDialog()
      setIsCreatingMembership(true)
      const { block } = await createNewMember(selectedAccountAddress, data)
      setMembershipBlock(block)
    } catch (error) {
      setActiveUser({ accountId: accountIdRef.current })
      closeCreatingMemberDialog()
      const errorMessage = (error.isAxiosError && (error as AxiosError).response?.data.error) || 'Unknown error'
      openErrorDialog({
        iconType: 'error',
        title: 'Something went wrong...',
        description: `Some unexpected error was encountered. If this persists, our Discord community may be a good place to find some help. Error code: ${errorMessage}`,
        secondaryButton: {
          text: 'Close',
          onClick: () => {
            setIsCreatingMembership(false)
            closeErrorDialog()
          },
        },
      })
    }
  })

  const handleExitClick = () => {
    reset()
    navigate({ search: '' })
  }

  if (queryNodeStateError) {
    return <ViewErrorFallback />
  }
  return (
    <StyledDialogModal
      title="Create a Joystream membership"
      show={show && accountSet && !isCreatingMembership}
      dividers
      as="form"
      onSubmit={handleCreateMember}
      onExitClick={handleExitClick}
      additionalActionsNode={
        <StyledButton disabled={nodeConnectionStatus !== 'connected' || !isValid} type="submit" size="large">
          Create membership
        </StyledButton>
      }
    >
      <Wrapper>
        <Text variant="t200" secondary>
          Membership represents you as a member of the Joystream community - it's your on-chain identity. It lets you
          interact with the network - create a channel, publish content, issue and trade NFTs. It also lets you to
          participate in the platform governance, shaping its future.
        </Text>
        <StyledAvatar
          size="channel-card"
          assetUrl={errors.avatar ? undefined : getValues('avatar')}
          hasAvatarUploadFailed={!!errors.avatar}
        />
      </Wrapper>
      <CreateEditMemberInputs register={register} errors={errors} watch={watch} />
    </StyledDialogModal>
  )
}