diff --git a/shared/chat/blocking/invitation-to-block.tsx b/shared/chat/blocking/invitation-to-block.tsx index 7b5c9236c956..d43da6c005d6 100644 --- a/shared/chat/blocking/invitation-to-block.tsx +++ b/shared/chat/blocking/invitation-to-block.tsx @@ -1,11 +1,11 @@ import * as Chat from '@/stores/chat' import {useProfileState} from '@/stores/profile' import * as Kb from '@/common-adapters' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {useCurrentUserState} from '@/stores/current-user' const BlockButtons = () => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const conversationIDKey = Chat.useChatContext(s => s.id) const team = Chat.useChatContext(s => s.meta.teamname) @@ -27,9 +27,9 @@ const BlockButtons = () => { ) const onViewProfile = () => showUserProfile(adder) - const onViewTeam = () => nav.safeNavigateAppend({name: 'team', params: {teamID}}) + const onViewTeam = () => nav.navigateAppend({name: 'team', params: {teamID}}) const onBlock = () => - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'chatBlockingModal', params: { blockUserByDefault: true, diff --git a/shared/chat/conversation/info-panel/add-to-channel.tsx b/shared/chat/conversation/info-panel/add-to-channel.tsx index 9993717cee83..9485a3e9c080 100644 --- a/shared/chat/conversation/info-panel/add-to-channel.tsx +++ b/shared/chat/conversation/info-panel/add-to-channel.tsx @@ -4,7 +4,7 @@ import * as React from 'react' import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' import * as T from '@/constants/types' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {useTeamDetailsSubscribe} from '@/teams/subscriber' import {pluralize} from '@/util/string' import {useChannelParticipants} from '@/teams/common' @@ -14,7 +14,7 @@ type Props = {teamID: T.Teams.TeamID} const AddToChannel = (props: Props) => { const {teamID} = props - const nav = useSafeNavigation() + const nav = useRouteNavigation() const conversationIDKey = Chat.useChatContext(s => s.id) const [toAdd, setToAdd] = React.useState(new Set()) @@ -37,7 +37,7 @@ const AddToChannel = (props: Props) => { const [error, setError] = React.useState('') const addToChannel = C.useRPC(T.RPCChat.localBulkAddToConvRpcPromise) - const onClose = () => nav.safeNavigateUp() + const onClose = () => nav.navigateUp() const loadTeamChannelList = Teams.useTeamsState(s => s.dispatch.loadTeamChannelList) const onAdd = () => { setWaiting(true) @@ -65,7 +65,7 @@ const AddToChannel = (props: Props) => { () => { setWaiting(false) loadTeamChannelList(teamID) - nav.safeNavigateUp() + nav.navigateUp() }, (e: {message: string}) => { setError(e.message) diff --git a/shared/chat/inbox/row/build-team.tsx b/shared/chat/inbox/row/build-team.tsx index 0ab40f0ee1b4..df70e6d16b42 100644 --- a/shared/chat/inbox/row/build-team.tsx +++ b/shared/chat/inbox/row/build-team.tsx @@ -1,10 +1,10 @@ import * as C from '@/constants' import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' function BuildTeam() { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const launchNewTeamWizardOrModal = useTeamsState(s => s.dispatch.launchNewTeamWizardOrModal) const switchTab = C.useRouterState(s => s.dispatch.switchTab) const onCreateTeam = () => { @@ -12,7 +12,7 @@ function BuildTeam() { launchNewTeamWizardOrModal() } const onJoinTeam = () => { - nav.safeNavigateAppend('teamJoinTeamDialog') + nav.navigateAppend('teamJoinTeamDialog') } return ( diff --git a/shared/chat/punycode-link-warning.tsx b/shared/chat/punycode-link-warning.tsx index ca0a08af4c4c..83c37b07a751 100644 --- a/shared/chat/punycode-link-warning.tsx +++ b/shared/chat/punycode-link-warning.tsx @@ -1,5 +1,5 @@ import * as Kb from '@/common-adapters' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import openURL from '@/util/open-url' type PunycodeLinkWarningProps = { @@ -10,11 +10,11 @@ type PunycodeLinkWarningProps = { const PunycodeLinkWarning = (props: PunycodeLinkWarningProps) => { const {url, display, punycode} = props - const nav = useSafeNavigation() - const onCancel = () => nav.safeNavigateUp() + const nav = useRouteNavigation() + const onCancel = () => nav.navigateUp() const onConfirm = () => { openURL(url) - nav.safeNavigateUp() + nav.navigateUp() } const description = `The link you clicked on appears to be ${display}, but actually points to ${punycode}.` return ( diff --git a/shared/common-adapters/confirm-modal.tsx b/shared/common-adapters/confirm-modal.tsx index 9d0d62553e9c..c80e42b5bfaa 100644 --- a/shared/common-adapters/confirm-modal.tsx +++ b/shared/common-adapters/confirm-modal.tsx @@ -87,6 +87,7 @@ const ConfirmModal = (props: Props) => ( disabled={props.onConfirmDeactivated || !props.onConfirm} type="Danger" label={props.confirmText || 'Confirm'} + lockOnClick={!!props.waitingKey} onClick={props.onConfirm} style={styles.button} waitingKey={props.waitingKey} diff --git a/shared/common-adapters/floating-menu/index.tsx b/shared/common-adapters/floating-menu/index.tsx index 5ce05ce5f9aa..39e9847e6e26 100644 --- a/shared/common-adapters/floating-menu/index.tsx +++ b/shared/common-adapters/floating-menu/index.tsx @@ -32,14 +32,14 @@ export type Props = { type SafeNavigationHook = >() => T | null -const useSafeNavigation: SafeNavigationHook = Styles.isMobile +const useMenuNavigation: SafeNavigationHook = Styles.isMobile ? (useNavigation as SafeNavigationHook) : () => null function FloatingMenu(props: Props) { const {items, visible, onHidden, mode} = props - const navigation = useSafeNavigation() + const navigation = useMenuNavigation() React.useEffect(() => { const unsub = navigation?.addListener('state', () => { diff --git a/shared/common-adapters/waiting-button.tsx b/shared/common-adapters/waiting-button.tsx index 041728bfd3b1..322039d25fe9 100644 --- a/shared/common-adapters/waiting-button.tsx +++ b/shared/common-adapters/waiting-button.tsx @@ -8,6 +8,7 @@ const Kb = { } export type Props = { + lockOnClick?: boolean onlyDisable?: boolean waitingKey?: Array | string } & ButtonProps @@ -25,22 +26,41 @@ export type Props = { */ function WaitingButton(props: Props & {ref?: React.Ref}) { - const {onlyDisable, waitingKey, ref, ...buttonProps} = props + const {lockOnClick, onlyDisable, waitingKey, ref, ...buttonProps} = props const storeWaiting = C.Waiting.useAnyWaiting(waitingKey) const [localWaiting, setLocalWaiting] = React.useState(false) + const [trackingStoreWaiting, setTrackingStoreWaiting] = React.useState(false) if (onlyDisable && !waitingKey) { throw new Error('WaitingButton onlyDisable should only be used with a waiting key') } + + React.useEffect(() => { + if (!lockOnClick || !waitingKey || !localWaiting) { + return + } + if (storeWaiting) { + setTrackingStoreWaiting(true) + return + } + if (trackingStoreWaiting) { + setLocalWaiting(false) + setTrackingStoreWaiting(false) + return + } + setLocalWaiting(false) + }, [lockOnClick, localWaiting, storeWaiting, trackingStoreWaiting, waitingKey]) + const waiting = storeWaiting || localWaiting return ( { - if (!waitingKey) { + if (lockOnClick || !waitingKey) { setLocalWaiting(true) + setTrackingStoreWaiting(false) } buttonProps.onClick?.(event) }} diff --git a/shared/constants/index.tsx b/shared/constants/index.tsx index 6a89f4b2aa94..3604da2643b1 100644 --- a/shared/constants/index.tsx +++ b/shared/constants/index.tsx @@ -1,7 +1,7 @@ export * from './platform' export * from './values' export * from './strings' -export {useRouterState, makeScreen} from '@/stores/router' +export {useRouterState, makeScreen, useRouteNavigation} from '@/stores/router' export * as Router2 from '@/stores/router' export * as Tabs from './tabs' export {useWaitingState} from '@/stores/waiting' diff --git a/shared/constants/router.tsx b/shared/constants/router.tsx index c0b72d35ae8a..e98786b909d6 100644 --- a/shared/constants/router.tsx +++ b/shared/constants/router.tsx @@ -6,6 +6,7 @@ import { CommonActions, type NavigationContainerRef, useFocusEffect, + useRoute, createNavigationContainerRef, type NavigationState, } from '@react-navigation/core' @@ -181,6 +182,13 @@ export const navigateUp = () => { return n?.dispatch(CommonActions.goBack()) } +const _routeIsVisible = (routeKey: string) => getVisibleScreen()?.key === routeKey + +export const navigateUpFromRoute = (routeKey: string) => { + if (!_routeIsVisible(routeKey)) return + return navigateUp() +} + export const popStack = () => { DEBUG_NAV && console.log('[Nav] popStack') const n = _getNavigator() @@ -238,6 +246,20 @@ export const navigateAppend = (path: PathParam, replace?: boolean) => { n.dispatch(StackActions.push(routeName, params)) } +export const navigateAppendFromRoute = (routeKey: string, path: PathParam, replace?: boolean) => { + if (!_routeIsVisible(routeKey)) return + return navigateAppend(path, replace) +} + +export const useRouteNavigation = () => { + const route = useRoute() as {key: string} + const routeKey = route.key + return { + navigateAppend: (path: PathParam, replace?: boolean) => navigateAppendFromRoute(routeKey, path, replace), + navigateUp: () => navigateUpFromRoute(routeKey), + } +} + export const switchTab = (name: Tabs.AppTab) => { DEBUG_NAV && console.log('[Nav] switchTab', {name}) const n = _getNavigator() diff --git a/shared/fs/browser/destination-picker.tsx b/shared/fs/browser/destination-picker.tsx index 0d0a2950748f..2dad0642f070 100644 --- a/shared/fs/browser/destination-picker.tsx +++ b/shared/fs/browser/destination-picker.tsx @@ -1,5 +1,5 @@ import * as C from '@/constants' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import * as FsCommon from '@/fs/common' import * as Kb from '@/common-adapters' import * as RowCommon from './rows/common' @@ -46,7 +46,7 @@ const ConnectedDestinationPicker = (ownProps: OwnProps) => { }) ) - const nav = useSafeNavigation() + const nav = useRouteNavigation() const clearModals = C.useRouterState(s => s.dispatch.clearModals) const onBackUp = isShare || !canBackUp(parentPath) @@ -57,14 +57,14 @@ const ConnectedDestinationPicker = (ownProps: OwnProps) => { ? () => { moveOrCopy(parentPath, 'copy') clearModals() - nav.safeNavigateAppend({name: 'fsRoot', params: {path: parentPath}}) + nav.navigateAppend({name: 'fsRoot', params: {path: parentPath}}) } : undefined const onMoveHere = isMovable ? () => { moveOrCopy(parentPath, 'move') clearModals() - nav.safeNavigateAppend({name: 'fsRoot', params: {path: parentPath}}) + nav.navigateAppend({name: 'fsRoot', params: {path: parentPath}}) } : undefined const onNewFolder = diff --git a/shared/fs/common/use-open.tsx b/shared/fs/common/use-open.tsx index 88882569ca69..415a818cb433 100644 --- a/shared/fs/common/use-open.tsx +++ b/shared/fs/common/use-open.tsx @@ -1,6 +1,6 @@ import * as C from '@/constants' import * as T from '@/constants/types' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {useFSState} from '@/stores/fs' import * as FS from '@/stores/fs' @@ -16,10 +16,10 @@ export const useOpen = (props: Props) => { return {destPicker: destinationPicker, pathItems} }) ) - const nav = useSafeNavigation() + const nav = useRouteNavigation() if (typeof props.destinationPickerIndex !== 'number') { - return () => nav.safeNavigateAppend({name: 'fsRoot', params: {path: props.path}}) + return () => nav.navigateAppend({name: 'fsRoot', params: {path: props.path}}) } const isFolder = diff --git a/shared/fs/nav-header/title.tsx b/shared/fs/nav-header/title.tsx index 11f39da5b695..f054afa5b741 100644 --- a/shared/fs/nav-header/title.tsx +++ b/shared/fs/nav-header/title.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import * as T from '@/constants/types' import * as Kb from '@/common-adapters' import * as Kbfs from '../common' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import * as FS from '@/stores/fs' type Props = { @@ -20,11 +20,11 @@ const Breadcrumb = (props: Props) => { .slice(1, -1) .reduce((list, current) => [...list, T.FS.pathConcat(list.at(-1), current)], [FS.defaultPath]) const {inDestinationPicker} = props - const nav = useSafeNavigation() + const nav = useRouteNavigation() const onOpenPath = (path: T.FS.Path) => { inDestinationPicker ? FS.makeActionsForDestinationPickerOpen(0, path) - : nav.safeNavigateAppend({name: 'fsRoot', params: {path}}) + : nav.navigateAppend({name: 'fsRoot', params: {path}}) } const makePopup = (p: Kb.Popup2Parms) => { diff --git a/shared/fs/simple-screens/oops.tsx b/shared/fs/simple-screens/oops.tsx index 71261a5e1075..4ebaa06e0dc0 100644 --- a/shared/fs/simple-screens/oops.tsx +++ b/shared/fs/simple-screens/oops.tsx @@ -1,7 +1,7 @@ import * as T from '@/constants/types' import * as C from '@/constants' import * as Kb from '@/common-adapters' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' type OwnProps = { path: T.FS.Path @@ -98,9 +98,9 @@ const NonExistent = (props: Props) => ( ) const Oops = (props: OwnProps) => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const openParent = () => - nav.safeNavigateAppend({name: 'fsRoot', params: {path: T.FS.getPathParent(props.path)}}) + nav.navigateAppend({name: 'fsRoot', params: {path: T.FS.getPathParent(props.path)}}) switch (props.reason) { case T.FS.SoftError.NoAccess: return diff --git a/shared/git/select-channel.tsx b/shared/git/select-channel.tsx index 46acaceb2f10..bfe4494ffe8d 100644 --- a/shared/git/select-channel.tsx +++ b/shared/git/select-channel.tsx @@ -1,6 +1,6 @@ import * as Git from '@/stores/git' import * as Teams from '@/stores/teams' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import * as Kb from '@/common-adapters' import * as React from 'react' import type * as T from '@/constants/types' @@ -20,10 +20,10 @@ const SelectChannel = (ownProps: OwnProps) => { const waiting = channelMetas.size === 0 // TODO fix this? const channelNames = [...channelMetas.values()].map(info => info.channelname) const [selected, setSelected] = React.useState(_selected) - const nav = useSafeNavigation() + const nav = useRouteNavigation() const setTeamRepoSettings = Git.useGitState(s => s.dispatch.setTeamRepoSettings) const onSubmit = (channelName: string) => setTeamRepoSettings(channelName, teamname, repoID, false) - const onCancel = () => nav.safeNavigateUp() + const onCancel = () => nav.navigateUp() const submit = () => { onSubmit(selected) diff --git a/shared/login/recover-password/prompt-reset-shared.tsx b/shared/login/recover-password/prompt-reset-shared.tsx index eb485a0f9684..eedc4055adb4 100644 --- a/shared/login/recover-password/prompt-reset-shared.tsx +++ b/shared/login/recover-password/prompt-reset-shared.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as AutoReset from '@/stores/autoreset' import * as Kb from '@/common-adapters' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import * as T from '@/constants/types' import {SignupScreen} from '@/signup/common' import type {ButtonType} from '@/common-adapters/button' @@ -12,7 +12,7 @@ export type Props = { } const PromptReset = (props: Props) => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const skipPassword = AutoReset.useAutoResetState(s => s.skipPassword) const error = AutoReset.useAutoResetState(s => s.error) const resetAccount = AutoReset.useAutoResetState(s => s.dispatch.resetAccount) @@ -25,7 +25,7 @@ const PromptReset = (props: Props) => { const onContinue = () => { // dont do this in preflight if (C.androidIsTestDevice) { - nav.safeNavigateUp() + nav.navigateUp() return } if (resetPassword) { @@ -34,14 +34,14 @@ const PromptReset = (props: Props) => { if (skipPassword) { resetAccount() } else { - nav.safeNavigateAppend('resetKnowPassword', true) + nav.navigateAppend('resetKnowPassword', true) } } const onBack = () => { if (skipPassword) { startRecoverPassword({replaceRoute: true, username}) } else { - nav.safeNavigateUp() + nav.navigateUp() } } const title = props.resetPassword ? 'Reset password' : skipPassword ? 'Recover password' : 'Account reset' diff --git a/shared/login/reset/password-enter.tsx b/shared/login/reset/password-enter.tsx index c8213a657269..94b3831aa6f9 100644 --- a/shared/login/reset/password-enter.tsx +++ b/shared/login/reset/password-enter.tsx @@ -3,15 +3,15 @@ import * as AutoReset from '@/stores/autoreset' import * as React from 'react' import * as Kb from '@/common-adapters' import {SignupScreen} from '@/signup/common' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' const EnterPassword = () => { const [password, setPassword] = React.useState('') const error = AutoReset.useAutoResetState(s => s.error) const endTime = AutoReset.useAutoResetState(s => s.endTime) const waiting = C.Waiting.useAnyWaiting(C.waitingKeyAutoresetEnterPipeline) - const nav = useSafeNavigation() - const onBack = () => nav.safeNavigateUp() + const nav = useRouteNavigation() + const onBack = () => nav.navigateUp() const resetAccount = AutoReset.useAutoResetState(s => s.dispatch.resetAccount) const onContinue = () => { diff --git a/shared/login/reset/password-known.tsx b/shared/login/reset/password-known.tsx index 4ef9f7bbad49..ba0296910eb6 100644 --- a/shared/login/reset/password-known.tsx +++ b/shared/login/reset/password-known.tsx @@ -2,14 +2,14 @@ import * as C from '@/constants' import * as AutoReset from '@/stores/autoreset' import * as Kb from '@/common-adapters' import {SignupScreen} from '@/signup/common' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' const KnowPassword = () => { const error = AutoReset.useAutoResetState(s => s.error) const waiting = C.Waiting.useAnyWaiting(C.waitingKeyAutoresetEnterPipeline) - const nav = useSafeNavigation() - const onCancel = () => nav.safeNavigateUp() - const onYes = () => nav.safeNavigateAppend('resetEnterPassword') + const nav = useRouteNavigation() + const onCancel = () => nav.navigateUp() + const onYes = () => nav.navigateAppend('resetEnterPassword') const resetAccount = AutoReset.useAutoResetState(s => s.dispatch.resetAccount) const onNo = () => resetAccount() return ( diff --git a/shared/login/reset/waiting.tsx b/shared/login/reset/waiting.tsx index 936df1a683b1..8b5662da486d 100644 --- a/shared/login/reset/waiting.tsx +++ b/shared/login/reset/waiting.tsx @@ -4,7 +4,7 @@ import {SignupScreen} from '@/signup/common' import {addTicker, removeTicker} from '@/util/second-timer' import * as C from '@/constants' import * as AutoReset from '@/stores/autoreset' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {formatDurationForAutoreset as formatDuration} from '@/util/timestamp' type Props = {pipelineStarted: boolean} @@ -19,8 +19,8 @@ const Waiting = (props: Props) => { const [formattedTime, setFormattedTime] = React.useState('a bit') const [hasSentAgain, setHasSentAgain] = React.useState(false) const [sendAgainSuccess, setSendAgainSuccess] = React.useState(false) - const nav = useSafeNavigation() - const onClose = () => nav.safeNavigateAppend('login', true) + const nav = useRouteNavigation() + const onClose = () => nav.navigateAppend('login', true) const resetAccount = AutoReset.useAutoResetState(s => s.dispatch.resetAccount) const onSendAgain = () => { setHasSentAgain(true) @@ -47,7 +47,7 @@ const Waiting = (props: Props) => { setFormattedTime(newFormattedTime) } if (endTime < Date.now()) { - nav.safeNavigateAppend('resetEnterPassword', true) + nav.navigateAppend('resetEnterPassword', true) } } diff --git a/shared/login/signup/common.tsx b/shared/login/signup/common.tsx index e08faa9a7f7c..cd89377291c4 100644 --- a/shared/login/signup/common.tsx +++ b/shared/login/signup/common.tsx @@ -33,6 +33,7 @@ export const ContinueButton = ({ }) => ( { const {wizard, waitingKey} = props const [selectedImage, setSelectedImage] = React.useState(image) const [imageError, setImageError] = React.useState('') - const nav = useSafeNavigation() - const navUp = () => nav.safeNavigateUp() + const nav = useRouteNavigation() + const navUp = () => nav.navigateUp() const onChooseNewAvatar = () => { const f = async () => { @@ -54,7 +54,7 @@ const AvatarUploadWrapper = (p: Props) => { if (!result.canceled && first) { setSelectedImage(first) } else { - nav.safeNavigateUp() + nav.navigateUp() } } catch (error) { setImageError(String(error)) diff --git a/shared/provision/select-other-device-connected.tsx b/shared/provision/select-other-device-connected.tsx index aa9e0929dcb0..c17bb6e1f760 100644 --- a/shared/provision/select-other-device-connected.tsx +++ b/shared/provision/select-other-device-connected.tsx @@ -1,6 +1,5 @@ import * as C from '@/constants' import * as AutoReset from '@/stores/autoreset' -import {useSafeSubmit} from '@/util/safe-submit' import SelectOtherDevice from './select-other-device' import {useProvisionState} from '@/stores/provision' @@ -9,9 +8,8 @@ const SelectOtherDeviceContainer = () => { const submitDeviceSelect = useProvisionState(s => s.dispatch.dynamic.submitDeviceSelect) const username = useProvisionState(s => s.username) const waiting = C.Waiting.useAnyWaiting(C.waitingKeyProvision) - const navigateUp = C.useRouterState(s => s.dispatch.navigateUp) - const _onBack = navigateUp - const onBack = useSafeSubmit(_onBack, false) + const nav = C.useRouteNavigation() + const onBack = nav.navigateUp const startAccountReset = AutoReset.useAutoResetState(s => s.dispatch.startAccountReset) const onResetAccount = () => { diff --git a/shared/provision/set-public-name.tsx b/shared/provision/set-public-name.tsx index 99c875ffb7dd..37412c0defa3 100644 --- a/shared/provision/set-public-name.tsx +++ b/shared/provision/set-public-name.tsx @@ -1,6 +1,5 @@ import * as C from '@/constants' import * as Devices from '@/stores/devices' -import {useSafeSubmit} from '@/util/safe-submit' import * as Kb from '@/common-adapters' import * as React from 'react' import debounce from 'lodash/debounce' @@ -11,8 +10,8 @@ const SetPublicName = () => { const devices = Provision.useProvisionState(s => s.devices) const error = Provision.useProvisionState(s => s.error) const waiting = C.Waiting.useAnyWaiting(C.waitingKeyProvision) - const navigateUp = C.useRouterState(s => s.dispatch.navigateUp) - const ponBack = useSafeSubmit(navigateUp, !!error) + const nav = C.useRouteNavigation() + const ponBack = nav.navigateUp const psetDeviceName = Provision.useProvisionState(s => s.dispatch.dynamic.setDeviceName) const ponSubmit = (name: string) => { !waiting && psetDeviceName?.(name) diff --git a/shared/provision/username-or-email.tsx b/shared/provision/username-or-email.tsx index d09f5525349f..0b937c717cfb 100644 --- a/shared/provision/username-or-email.tsx +++ b/shared/provision/username-or-email.tsx @@ -1,7 +1,6 @@ import * as C from '@/constants' import * as AutoReset from '@/stores/autoreset' import {useSignupState} from '@/stores/signup' -import {useSafeSubmit} from '@/util/safe-submit' import * as T from '@/constants/types' import * as React from 'react' import type {RPCError} from '@/util/errors' @@ -44,10 +43,9 @@ const UsernameOrEmailContainer = (op: OwnProps) => { // So we can clear the error if the name is changed const _username = useProvisionState(s => s.username) const waiting = C.Waiting.useAnyWaiting(C.waitingKeyProvision) - const hasError = !!error || !!inlineError || inlineSignUpLink - const navigateUp = C.useRouterState(s => s.dispatch.navigateUp) - const onBack = useSafeSubmit(navigateUp, hasError) + const nav = C.useRouteNavigation() + const onBack = nav.navigateUp const navigateAppend = C.useRouterState(s => s.dispatch.navigateAppend) const onForgotUsername = () => navigateAppend('forgotUsername') const requestAutoInvite = useSignupState(s => s.dispatch.requestAutoInvite) diff --git a/shared/settings/account/add-modals.tsx b/shared/settings/account/add-modals.tsx index db284fefe26e..d423bcac6b08 100644 --- a/shared/settings/account/add-modals.tsx +++ b/shared/settings/account/add-modals.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {EnterEmailBody} from '@/signup/email' import {EnterPhoneNumberBody} from '@/signup/phone-number' import VerifyBody from '@/signup/phone-number/verify-body' @@ -9,7 +9,7 @@ import {useSettingsPhoneState} from '@/stores/settings-phone' import {useSettingsEmailState} from '@/stores/settings-email' export const Email = () => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const [email, onChangeEmail] = React.useState('') const [searchable, onChangeSearchable] = React.useState(true) @@ -51,7 +51,7 @@ export const Email = () => { } }, [addEmailInProgress, resetAddingEmail, emailError, emailTrimmed]) - const onClose = () => nav.safeNavigateUp() + const onClose = () => nav.navigateUp() const onContinue = () => { if (disabled || waiting) { return @@ -109,7 +109,7 @@ export const Email = () => { ) } export const Phone = () => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const [phoneNumber, onChangeNumber] = React.useState('') const [valid, onChangeValidity] = React.useState(false) @@ -141,7 +141,7 @@ export const Phone = () => { // watch for go to verify React.useEffect(() => { if (!error && !!pendingVerification) { - nav.safeNavigateAppend('settingsVerifyPhone') + nav.navigateAppend('settingsVerifyPhone') } }, [error, nav, pendingVerification]) // trigger a default phone number country rpc if it's not already loaded @@ -151,7 +151,7 @@ export const Phone = () => { const onClose = () => { clearPhoneNumberAdd() - nav.safeNavigateUp() + nav.navigateUp() } const onContinue = () => { diff --git a/shared/settings/account/confirm-delete.tsx b/shared/settings/account/confirm-delete.tsx index 9aa082b3c5a0..52ce7a0ef9a3 100644 --- a/shared/settings/account/confirm-delete.tsx +++ b/shared/settings/account/confirm-delete.tsx @@ -1,6 +1,6 @@ import * as Kb from '@/common-adapters' import * as PhoneUtil from '@/util/phone-numbers' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {useSettingsPhoneState} from '@/stores/settings-phone' import {useSettingsEmailState} from '@/stores/settings-email' @@ -12,13 +12,13 @@ type OwnProps = { } const DeleteModal = (props: OwnProps) => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const itemAddress = props.address const itemType = props.type const itemSearchable = props.searchable const lastEmail = props.lastEmail ?? false - const onCancel = () => nav.safeNavigateUp() + const onCancel = () => nav.navigateUp() const editPhone = useSettingsPhoneState(s => s.dispatch.editPhone) const editEmail = useSettingsEmailState(s => s.dispatch.editEmail) const onConfirm = () => { @@ -28,7 +28,7 @@ const DeleteModal = (props: OwnProps) => { editEmail({delete: true, email: itemAddress}) } - nav.safeNavigateUp() + nav.navigateUp() } const icon = diff --git a/shared/settings/delete-confirm/index.tsx b/shared/settings/delete-confirm/index.tsx index 44e955d35a4c..363dd17a9c69 100644 --- a/shared/settings/delete-confirm/index.tsx +++ b/shared/settings/delete-confirm/index.tsx @@ -1,7 +1,7 @@ import * as C from '@/constants' import * as React from 'react' import * as Kb from '@/common-adapters' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {usePWState} from '@/stores/settings-password' import {useSettingsState} from '@/stores/settings' import {useCurrentUserState} from '@/stores/current-user' @@ -42,8 +42,8 @@ const DeleteConfirm = () => { const [checkData, setCheckData] = React.useState(false) const [checkTeams, setCheckTeams] = React.useState(false) const [checkUsername, setCheckUsername] = React.useState(false) - const nav = useSafeNavigation() - const onCancel = () => nav.safeNavigateUp() + const nav = useRouteNavigation() + const onCancel = () => nav.navigateUp() const navigateAppend = C.useRouterState(s => s.dispatch.navigateAppend) const onDeleteForever = () => { if (C.androidIsTestDevice) { diff --git a/shared/settings/logout.tsx b/shared/settings/logout.tsx index 93c4df907ee2..d56c373858b7 100644 --- a/shared/settings/logout.tsx +++ b/shared/settings/logout.tsx @@ -1,5 +1,4 @@ import * as React from 'react' -import {useSafeSubmit} from '@/util/safe-submit' import * as C from '@/constants' import * as Kb from '@/common-adapters' import {UpdatePassword} from './password' @@ -51,8 +50,6 @@ const LogoutContainer = () => { submitNewPassword(true) } - const onLogout = useSafeSubmit(_onLogout, false) - const [loggingOut, setLoggingOut] = React.useState(false) const [password, setPassword] = React.useState('') const [showTyping, setShowTyping] = React.useState(false) @@ -63,7 +60,7 @@ const LogoutContainer = () => { const logOut = () => { if (loggingOut) return - onLogout() + _onLogout() setLoggingOut(true) } diff --git a/shared/signup/common.tsx b/shared/signup/common.tsx index 0bfd0b91b3e5..fa7b303be673 100644 --- a/shared/signup/common.tsx +++ b/shared/signup/common.tsx @@ -209,6 +209,7 @@ export const SignupScreen = (props: SignupScreenProps) => ( key={b.label} style={styles.button} {...b} + lockOnClick={true} // TS doesn't narrow the type inside ButtonMeta, so still thinks // waitingKey can be undefined unless we pull it out waitingKey={b.waitingKey} diff --git a/shared/stores/router.tsx b/shared/stores/router.tsx index 4c88df5d7680..af7bfdedf2d2 100644 --- a/shared/stores/router.tsx +++ b/shared/stores/router.tsx @@ -19,6 +19,7 @@ export { getRouteTab, getRouteLoggedIn, useSafeFocusEffect, + useRouteNavigation, makeScreen, } from '@/constants/router' export type {PathParam, Navigator} from '@/constants/router' diff --git a/shared/team-building/contact-restricted.tsx b/shared/team-building/contact-restricted.tsx index 74e721789723..f92c2ee1f01e 100644 --- a/shared/team-building/contact-restricted.tsx +++ b/shared/team-building/contact-restricted.tsx @@ -1,5 +1,5 @@ import * as Kb from '@/common-adapters' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' type Props = { source: 'newFolder' | 'teamAddSomeFailed' | 'teamAddAllFailed' | 'misc' @@ -7,8 +7,8 @@ type Props = { } export const ContactRestricted = (props: Props) => { - const nav = useSafeNavigation() - const onBack = () => nav.safeNavigateUp() + const nav = useRouteNavigation() + const onBack = () => nav.navigateUp() let header = '' let description = '' let disallowedUsers: Array = [] diff --git a/shared/teams/add-members-wizard/add-from-where.tsx b/shared/teams/add-members-wizard/add-from-where.tsx index 82fdadf34da9..aac735368324 100644 --- a/shared/teams/add-members-wizard/add-from-where.tsx +++ b/shared/teams/add-members-wizard/add-from-where.tsx @@ -2,19 +2,19 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import * as Teams from '@/stores/teams' import * as T from '@/constants/types' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' const AddFromWhere = () => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const teamID = Teams.useTeamsState(s => s.addMembersWizard.teamID) const newTeam: boolean = teamID === T.Teams.newTeamWizardTeamID // Clicking "skip" concludes the new team wizard. It can error so we should display that here. const createTeamError = Teams.useTeamsState(s => (newTeam ? s.newTeamWizard.error : undefined)) const appendNewTeamBuilder = C.useRouterState(s => s.appendNewTeamBuilder) const onContinueKeybase = () => appendNewTeamBuilder(teamID) - const onContinuePhone = () => nav.safeNavigateAppend('teamAddToTeamPhone') - const onContinueContacts = () => nav.safeNavigateAppend('teamAddToTeamContacts') - const onContinueEmail = () => nav.safeNavigateAppend('teamAddToTeamEmail') + const onContinuePhone = () => nav.navigateAppend('teamAddToTeamPhone') + const onContinueContacts = () => nav.navigateAppend('teamAddToTeamContacts') + const onContinueEmail = () => nav.navigateAppend('teamAddToTeamEmail') return ( <> diff --git a/shared/teams/add-members-wizard/confirm.tsx b/shared/teams/add-members-wizard/confirm.tsx index 36dca73fc53a..3a8f32b8abd7 100644 --- a/shared/teams/add-members-wizard/confirm.tsx +++ b/shared/teams/add-members-wizard/confirm.tsx @@ -12,7 +12,7 @@ import {useDefaultChannels} from '../team/settings-tab/default-channels' import {ChannelsWidget} from '../common' import {pluralize} from '@/util/string' import logger from '@/logger' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' type DisabledRoles = React.ComponentProps['disabledRoles'] const disabledRolesForNonKeybasePlural = { @@ -193,7 +193,7 @@ const AlreadyInTeam = ({assertions}: {assertions: ReadonlyArray}) => { } const AddMoreMembers = () => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const {appendNewTeamBuilder} = C.useRouterState( C.useShallow(s => ({ appendNewTeamBuilder: s.appendNewTeamBuilder, @@ -203,9 +203,9 @@ const AddMoreMembers = () => { const makePopup = (p: Kb.Popup2Parms) => { const {attachTo, hidePopup} = p const onAddKeybase = () => appendNewTeamBuilder(teamID) - const onAddContacts = () => nav.safeNavigateAppend('teamAddToTeamContacts') - const onAddPhone = () => nav.safeNavigateAppend('teamAddToTeamPhone') - const onAddEmail = () => nav.safeNavigateAppend('teamAddToTeamEmail') + const onAddContacts = () => nav.navigateAppend('teamAddToTeamContacts') + const onAddPhone = () => nav.navigateAppend('teamAddToTeamPhone') + const onAddEmail = () => nav.navigateAppend('teamAddToTeamEmail') return ( { const [recentJoins, setRecentJoins] = React.useState(undefined) @@ -43,11 +43,11 @@ const HeaderTitle = (props: HeaderTitleProps) => { description: description, teamID, } - const nav = useSafeNavigation() - const onEditChannel = () => nav.safeNavigateAppend({name: 'teamEditChannel', params: editChannelProps}) + const nav = useRouteNavigation() + const onEditChannel = () => nav.navigateAppend({name: 'teamEditChannel', params: editChannelProps}) const onAddMembers = () => - nav.safeNavigateAppend({name: 'chatAddToChannel', params: {conversationIDKey, teamID}}) - const onNavToTeam = () => nav.safeNavigateAppend({name: 'team', params: {teamID}}) + nav.navigateAppend({name: 'chatAddToChannel', params: {conversationIDKey, teamID}}) + const onNavToTeam = () => nav.navigateAppend({name: 'team', params: {teamID}}) const activityLevel = useTeamsState(s => s.activityLevels.channels.get(conversationIDKey) || 'none') const newMemberCount = useRecentJoins(conversationIDKey) @@ -78,7 +78,7 @@ const HeaderTitle = (props: HeaderTitleProps) => { { danger: true, onClick: () => { - nav.safeNavigateUp() + nav.navigateUp() deleteChannelConfirmed(teamID, conversationIDKey) }, title: 'Delete channel', diff --git a/shared/teams/confirm-modals/confirm-kick-out.tsx b/shared/teams/confirm-modals/confirm-kick-out.tsx index c38267ca9c7d..920b634c7be5 100644 --- a/shared/teams/confirm-modals/confirm-kick-out.tsx +++ b/shared/teams/confirm-modals/confirm-kick-out.tsx @@ -4,7 +4,7 @@ import * as Teams from '@/stores/teams' import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' type Props = { members: string[] @@ -28,8 +28,8 @@ const ConfirmKickOut = (props: Props) => { members.map(member => subteamIDs.map(subteamID => C.waitingKeyTeamsRemoveMember(subteamID, member))) ) const waiting = C.Waiting.useAnyWaiting(...waitingKeys) - const nav = useSafeNavigation() - const onCancel = () => nav.safeNavigateUp() + const nav = useRouteNavigation() + const onCancel = () => nav.navigateUp() const setMemberSelected = useTeamsState(s => s.dispatch.setMemberSelected) const removeMember = useTeamsState(s => s.dispatch.removeMember) diff --git a/shared/teams/confirm-modals/confirm-remove-from-channel.tsx b/shared/teams/confirm-modals/confirm-remove-from-channel.tsx index 348398b51c05..368a95540f8f 100644 --- a/shared/teams/confirm-modals/confirm-remove-from-channel.tsx +++ b/shared/teams/confirm-modals/confirm-remove-from-channel.tsx @@ -4,7 +4,7 @@ import * as React from 'react' import * as Teams from '@/stores/teams' import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' type Props = { members: string[] @@ -22,8 +22,8 @@ const ConfirmRemoveFromChannel = (props: Props) => { const channelInfo = useTeamsState(s => Teams.getTeamChannelInfo(s, teamID, conversationIDKey)) const {channelname} = channelInfo - const nav = useSafeNavigation() - const onCancel = () => nav.safeNavigateUp() + const nav = useRouteNavigation() + const onCancel = () => nav.navigateUp() const loadTeamChannelList = useTeamsState(s => s.dispatch.loadTeamChannelList) const channelSetMemberSelected = useTeamsState(s => s.dispatch.channelSetMemberSelected) @@ -37,7 +37,7 @@ const ConfirmRemoveFromChannel = (props: Props) => { _ => { setWaiting(false) channelSetMemberSelected(conversationIDKey, '', false, true) - nav.safeNavigateUp() + nav.navigateUp() loadTeamChannelList(teamID) }, err => { diff --git a/shared/teams/confirm-modals/really-leave-team/index.tsx b/shared/teams/confirm-modals/really-leave-team/index.tsx index ac911a27025f..4a572d87f4bb 100644 --- a/shared/teams/confirm-modals/really-leave-team/index.tsx +++ b/shared/teams/confirm-modals/really-leave-team/index.tsx @@ -3,7 +3,6 @@ import * as C from '@/constants' import * as Teams from '@/stores/teams' import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' -import {useSafeSubmit} from '@/util/safe-submit' import type * as T from '@/constants/types' import {useTeamsSubscribe, useTeamDetailsSubscribeMountOnly} from '@/teams/subscriber' import LastOwnerDialog from './last-owner' @@ -132,7 +131,7 @@ const ReallyLeaveTeamContainer = (op: OwnProps) => { } const _onBack = navigateUp const onBack = leaving ? () => {} : _onBack - const onLeave = useSafeSubmit(_onLeave, !leaving) + const onLeave = _onLeave useTeamDetailsSubscribeMountOnly(teamID) return lastOwner ? ( diff --git a/shared/teams/container.tsx b/shared/teams/container.tsx index 6d6f60555d68..5a8ecc439a4a 100644 --- a/shared/teams/container.tsx +++ b/shared/teams/container.tsx @@ -5,7 +5,7 @@ import type * as T from '@/constants/types' import Main from './main' import {useTeamsSubscribe} from './subscriber' import {useActivityLevels} from './common' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' const orderTeams = ( teams: ReadonlyMap, @@ -73,9 +73,9 @@ const Connected = () => { // reload activity levels useActivityLevels(true) - const nav = useSafeNavigation() + const nav = useRouteNavigation() const onCreateTeam = () => launchNewTeamWizardOrModal() - const onJoinTeam = () => nav.safeNavigateAppend('teamJoinTeamDialog') + const onJoinTeam = () => nav.navigateAppend('teamJoinTeamDialog') return ( diff --git a/shared/teams/delete-team.tsx b/shared/teams/delete-team.tsx index 99e6f075af0e..3966019d7543 100644 --- a/shared/teams/delete-team.tsx +++ b/shared/teams/delete-team.tsx @@ -1,6 +1,5 @@ import * as React from 'react' import * as C from '@/constants' -import {useSafeSubmit} from '@/util/safe-submit' import type * as T from '@/constants/types' import * as Kb from '@/common-adapters' import {pluralize} from '@/util/string' @@ -30,7 +29,7 @@ const DeleteTeamContainer = (op: OwnProps) => { const _onDelete = () => { deleteTeam(teamID) } - const onDelete = useSafeSubmit(_onDelete, !deleteWaiting) + const onDelete = _onDelete const [checks, setChecks] = React.useState({ checkChats: false, diff --git a/shared/teams/external-team.tsx b/shared/teams/external-team.tsx index 510170fbf172..41afbbf07621 100644 --- a/shared/teams/external-team.tsx +++ b/shared/teams/external-team.tsx @@ -8,7 +8,7 @@ import * as Teams from '@/stores/teams' import {useTeamLinkPopup} from './common' import {pluralize} from '@/util/string' import capitalize from 'lodash/capitalize' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' type Props = {teamname: string} @@ -132,10 +132,10 @@ const ExternalTeamInfo = ({info}: ExternalTeamProps) => { } const Header = ({info}: ExternalTeamProps) => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const teamname = info.name.parts?.join('.') const onJoin = () => - nav.safeNavigateAppend({name: 'teamJoinTeamDialog', params: {initialTeamname: teamname}}) + nav.navigateAppend({name: 'teamJoinTeamDialog', params: {initialTeamname: teamname}}) const {popupAnchor, showPopup, popup} = useTeamLinkPopup(teamname || '') const metaInfo = ( diff --git a/shared/teams/get-options.tsx b/shared/teams/get-options.tsx index f0cf90c88b0f..dc21c60bddc3 100644 --- a/shared/teams/get-options.tsx +++ b/shared/teams/get-options.tsx @@ -1,14 +1,14 @@ import * as Kb from '@/common-adapters' import {HeaderRightActions} from './main/header' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {useTeamsState} from '@/stores/teams' const useHeaderActions = () => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const launchNewTeamWizardOrModal = useTeamsState(s => s.dispatch.launchNewTeamWizardOrModal) return { onCreateTeam: () => launchNewTeamWizardOrModal(), - onJoinTeam: () => nav.safeNavigateAppend('teamJoinTeamDialog'), + onJoinTeam: () => nav.navigateAppend('teamJoinTeamDialog'), } } diff --git a/shared/teams/join-team/join-from-invite.tsx b/shared/teams/join-team/join-from-invite.tsx index 04b1b9fbf6be..39bb92d0c9ef 100644 --- a/shared/teams/join-team/join-from-invite.tsx +++ b/shared/teams/join-team/join-from-invite.tsx @@ -3,7 +3,7 @@ import * as React from 'react' import {useTeamsState} from '@/stores/teams' import * as Kb from '@/common-adapters' import {Success} from './container' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' const JoinFromInvite = () => { const {inviteID: id, inviteKey: key, inviteDetails: details} = useTeamsState(s => s.teamInviteDetails) @@ -29,9 +29,9 @@ const JoinFromInvite = () => { }, [requestInviteLinkDetails, joinTeam, loaded, key, id]) const [clickedJoin, setClickedJoin] = React.useState(false) - const nav = useSafeNavigation() + const nav = useRouteNavigation() - const onNavUp = () => nav.safeNavigateUp() + const onNavUp = () => nav.navigateUp() const respondToInviteLink = useTeamsState(s => s.dispatch.dynamic.respondToInviteLink) const onJoinTeam = () => { setClickedJoin(true) diff --git a/shared/teams/team/member/add-to-channels.tsx b/shared/teams/team/member/add-to-channels.tsx index d3f65c78618f..a5306f4045e1 100644 --- a/shared/teams/team/member/add-to-channels.tsx +++ b/shared/teams/team/member/add-to-channels.tsx @@ -7,7 +7,7 @@ import * as Kb from '@/common-adapters' import * as Common from '@/teams/common' import {pluralize} from '@/util/string' import {useAllChannelMetas} from '@/teams/common/channel-hooks' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {useCurrentUserState} from '@/stores/current-user' import {useModalHeaderState} from '@/stores/modal-header' @@ -48,7 +48,7 @@ const AddToChannels = function AddToChannels(props: Props) { const justMe = [myUsername] const usernames = props.usernames ?? justMe const mode = props.usernames ? 'others' : 'self' - const nav = useSafeNavigation() + const nav = useRouteNavigation() const {channelMetas, loadingChannels, reloadChannels} = useAllChannelMetas(teamID) const {channelMetasAll, channelMetaGeneral, convIDKeysAvailable} = getChannelsForList(channelMetas, usernames) @@ -97,7 +97,7 @@ const AddToChannels = function AddToChannels(props: Props) { } const onSelectAll = () => setSelected(new Set(convIDKeysAvailable)) const onSelectNone = convIDKeysAvailable.length === 0 ? undefined : () => setSelected(new Set()) - const onCancel = () => nav.safeNavigateUp() + const onCancel = () => nav.navigateUp() const submit = C.useRPC(T.RPCChat.localBulkAddToManyConvsRpcPromise) const [waiting, setWaiting] = React.useState(false) @@ -204,7 +204,7 @@ const AddToChannels = function AddToChannels(props: Props) { if (mode !== 'others') return const handleFinish = () => { if (!selected.size) { - nav.safeNavigateUp() + nav.navigateUp() return } setWaiting(true) @@ -212,7 +212,7 @@ const AddToChannels = function AddToChannels(props: Props) { [{conversations: [...selected].map(T.Chat.keyToConversationID), usernames}], () => { setWaiting(false) - nav.safeNavigateUp() + nav.navigateUp() }, error => { console.error(error) @@ -274,8 +274,8 @@ const HeaderRow = function HeaderRow(p: { onSelectNone?: () => void }) { const {mode, teamID, onSelectAll, onSelectNone} = p - const nav = useSafeNavigation() - const onCreate = () => nav.safeNavigateAppend({name: 'chatCreateChannel', params: {teamID}}) + const nav = useRouteNavigation() + const onCreate = () => nav.navigateAppend({name: 'chatCreateChannel', params: {teamID}}) const canCreate = Teams.useTeamsState(s => Teams.getCanPerformByID(s, teamID).createChannel) return ( @@ -313,7 +313,7 @@ const SelfChannelActions = function SelfChannelActions(p: { selfMode: boolean }) { const {meta, reloadChannels, selfMode} = p - const nav = useSafeNavigation() + const nav = useRouteNavigation() const yourOperations = Teams.useTeamsState(s => Teams.getCanPerformByID(s, meta.teamID)) const isAdmin = yourOperations.deleteChannel const canEdit = yourOperations.editChannelDescription @@ -323,7 +323,7 @@ const SelfChannelActions = function SelfChannelActions(p: { const stopWaiting = () => setWaiting(false) const onEditChannel = () => { - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'teamEditChannel', params: { channelname: meta.channelname, @@ -344,7 +344,7 @@ const SelfChannelActions = function SelfChannelActions(p: { } const onDelete = () => { // TODO: consider not using the confirm modal - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'teamDeleteChannel', params: {conversationIDKey: meta.conversationIDKey, teamID: meta.teamID}, }) diff --git a/shared/teams/team/member/edit-channel.tsx b/shared/teams/team/member/edit-channel.tsx index 9aba5abb82ec..1284a9b1ff65 100644 --- a/shared/teams/team/member/edit-channel.tsx +++ b/shared/teams/team/member/edit-channel.tsx @@ -3,7 +3,7 @@ import * as Kb from '@/common-adapters' import {useTeamsState} from '@/stores/teams' import * as React from 'react' import type * as T from '@/constants/types' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' type Props = { channelname: string @@ -18,7 +18,7 @@ const EditChannel = (props: Props) => { const oldName = props.channelname const oldDescription = props.description - const nav = useSafeNavigation() + const nav = useRouteNavigation() const [name, _setName] = React.useState(oldName) const setName = (newName: string) => _setName(newName.replace(/[^a-zA-Z0-9_-]/, '')) @@ -37,7 +37,7 @@ const EditChannel = (props: Props) => { ] Promise.all(ps) .then(() => { - nav.safeNavigateUp() + nav.navigateUp() loadTeamChannelList(teamID) }) .catch(() => {}) diff --git a/shared/teams/team/member/index.new.tsx b/shared/teams/team/member/index.new.tsx index cd2c2e189336..942facaeb29f 100644 --- a/shared/teams/team/member/index.new.tsx +++ b/shared/teams/team/member/index.new.tsx @@ -13,7 +13,7 @@ import {formatTimeForTeamMember, formatTimeRelativeToNow} from '@/util/timestamp import {pluralize} from '@/util/string' import {useAllChannelMetas} from '@/teams/common/channel-hooks' import {useTeamDetailsSubscribe} from '@/teams/subscriber' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' type Props = { teamID: T.Teams.TeamID @@ -119,7 +119,7 @@ const useMemberships = (targetTeamID: T.Teams.TeamID, username: string) => { } const useNavUpIfRemovedFromTeam = (teamID: T.Teams.TeamID, username: string) => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const waitingKey = C.waitingKeyTeamsRemoveMember(teamID, username) const waiting = C.Waiting.useAnyWaiting(waitingKey) const wasWaitingRef = React.useRef(waiting) @@ -128,7 +128,7 @@ const useNavUpIfRemovedFromTeam = (teamID: T.Teams.TeamID, username: string) => React.useEffect(() => { if (wasWaitingRef.current && !waiting) { setLeaving(true) - nav.safeNavigateUp() + nav.navigateUp() } else { setLeaving(false) } @@ -283,7 +283,7 @@ type NodeNotInRowProps = { } const NodeNotInRow = (props: NodeNotInRowProps) => { useTeamDetailsSubscribe(props.node.teamID) - const nav = useSafeNavigation() + const nav = useRouteNavigation() const onAddWaitingKey = C.waitingKeyTeamsAddMember(props.node.teamID, props.username) const {addToTeam, disabledRoles} = Teams.useTeamsState( C.useShallow(s => ({ @@ -294,7 +294,7 @@ const NodeNotInRow = (props: NodeNotInRowProps) => { const onAdd = (role: T.Teams.TeamRoleType) => { addToTeam(props.node.teamID, [{assertion: props.username, role}], true) } - const openTeam = () => nav.safeNavigateAppend({name: 'team', params: {teamID: props.node.teamID}}) + const openTeam = () => nav.navigateAppend({name: 'team', params: {teamID: props.node.teamID}}) const [open, setOpen] = React.useState(false) return ( @@ -395,9 +395,9 @@ const NodeInRow = (props: NodeInRowProps) => { ) useTeamDetailsSubscribe(props.node.teamID) - const nav = useSafeNavigation() + const nav = useRouteNavigation() const onAddToChannels = () => - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'teamAddToChannels', params: {teamID: props.node.teamID, usernames: [props.username]}, }) @@ -405,11 +405,11 @@ const NodeInRow = (props: NodeInRowProps) => { const onKickOut = () => { removeMember(props.node.teamID, props.username) if (props.isParentTeamMe) { - nav.safeNavigateUp() + nav.navigateUp() } } - const openTeam = () => nav.safeNavigateAppend({name: 'team', params: {teamID: props.node.teamID}}) + const openTeam = () => nav.navigateAppend({name: 'team', params: {teamID: props.node.teamID}}) const {expanded, setExpanded} = props @@ -431,7 +431,7 @@ const NodeInRow = (props: NodeInRowProps) => { editMembership(props.node.teamID, [props.username], role) setOpen(false) if (['reader, writer'].includes(role) && props.isParentTeamMe) { - nav.safeNavigateUp() + nav.navigateUp() } } const changingRole = C.Waiting.useAnyWaiting( @@ -607,7 +607,7 @@ const NodeInRow = (props: NodeInRowProps) => { // exported for stories export const TeamMemberHeader = (props: Props) => { const {teamID, username} = props - const nav = useSafeNavigation() + const nav = useRouteNavigation() const leaving = useNavUpIfRemovedFromTeam(teamID, username) const {teamDetails, teamMeta} = Teams.useTeamsState( @@ -621,7 +621,7 @@ export const TeamMemberHeader = (props: Props) => { const showUserProfile = useProfileState(s => s.dispatch.showUserProfile) const onChat = () => previewConversation({participants: [username], reason: 'memberView'}) const onViewProfile = () => showUserProfile(username) - const onViewTeam = () => nav.safeNavigateAppend({name: 'team', params: {teamID}}) + const onViewTeam = () => nav.navigateAppend({name: 'team', params: {teamID}}) const member = teamDetails?.members.get(username) if (!member) { @@ -691,10 +691,10 @@ export const TeamMemberHeader = (props: Props) => { const BlockDropdown = (props: {username: string}) => { const {username} = props - const nav = useSafeNavigation() + const nav = useRouteNavigation() const makePopup = (p: Kb.Popup2Parms) => { const {attachTo, hidePopup} = p - const onBlock = () => nav.safeNavigateAppend({name: 'chatBlockingModal', params: {username}}) + const onBlock = () => nav.navigateAppend({name: 'chatBlockingModal', params: {username}}) return ( { export default HeaderTitle const useHeaderCallbacks = (teamID: T.Teams.TeamID) => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const {addMembersWizardPushMembers, meta, startAddMembersWizard, yourOperations} = Teams.useTeamsState( C.useShallow(s => ({ addMembersWizardPushMembers: s.dispatch.addMembersWizardPushMembers, @@ -301,13 +301,13 @@ const useHeaderCallbacks = (teamID: T.Teams.TeamID) => { const onChat = () => previewConversation({reason: 'teamHeader', teamname: meta.teamname}) const onEditAvatar = yourOperations.editTeamDescription ? () => - nav.safeNavigateAppend({name: 'profileEditAvatar', params: {sendChatNotification: true, teamID}}) + nav.navigateAppend({name: 'profileEditAvatar', params: {sendChatNotification: true, teamID}}) : undefined const onEditDescription = yourOperations.editTeamDescription - ? () => nav.safeNavigateAppend({name: 'teamEditTeamInfo', params: {teamID}}) + ? () => nav.navigateAppend({name: 'teamEditTeamInfo', params: {teamID}}) : undefined const onRename = yourOperations.renameTeam - ? () => nav.safeNavigateAppend({name: 'teamRename', params: {teamname: meta.teamname}}) + ? () => nav.navigateAppend({name: 'teamRename', params: {teamname: meta.teamname}}) : undefined return { onAddSelf, diff --git a/shared/teams/team/rows/channel-row/add.tsx b/shared/teams/team/rows/channel-row/add.tsx index 508a73c111dd..6f5096fe94ee 100644 --- a/shared/teams/team/rows/channel-row/add.tsx +++ b/shared/teams/team/rows/channel-row/add.tsx @@ -1,12 +1,12 @@ import * as C from '@/constants' import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' const ButtonRow = (props: {teamID: T.Teams.TeamID}) => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const onCreateChannel = () => - nav.safeNavigateAppend({name: 'chatCreateChannel', params: {...props, navToChatOnSuccess: false}}) + nav.navigateAppend({name: 'chatCreateChannel', params: {...props, navToChatOnSuccess: false}}) const waitingKey = C.waitingKeyTeamsGetChannels(props.teamID) const waitingForGet = C.Waiting.useAnyWaiting(waitingKey) diff --git a/shared/teams/team/rows/channel-row/channel.tsx b/shared/teams/team/rows/channel-row/channel.tsx index 1255d21c3355..ae81ee7765ce 100644 --- a/shared/teams/team/rows/channel-row/channel.tsx +++ b/shared/teams/team/rows/channel-row/channel.tsx @@ -2,7 +2,7 @@ import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' import {Activity, useChannelParticipants} from '@/teams/common' import {pluralize} from '@/util/string' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import * as Teams from '@/stores/teams' import {useTeamsState} from '@/stores/teams' @@ -24,14 +24,14 @@ const ChannelRow = (props: ChannelRowProps) => { const hasAllMembers = details?.members.size === numParticipants const activityLevel = useTeamsState(s => s.activityLevels.channels.get(channel.conversationIDKey) || 'none') - const nav = useSafeNavigation() + const nav = useRouteNavigation() const setChannelSelected = useTeamsState(s => s.dispatch.setChannelSelected) const onSelect = (newSelected: boolean) => { setChannelSelected(teamID, channel.conversationIDKey, newSelected) } const onEditChannel = () => { - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'teamEditChannel', params: { channelname: channel.channelname, @@ -42,7 +42,7 @@ const ChannelRow = (props: ChannelRowProps) => { }) } const onNavToChannel = () => { - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'teamChannel', params: { conversationIDKey: channel.conversationIDKey, @@ -51,7 +51,7 @@ const ChannelRow = (props: ChannelRowProps) => { }) } const onNavToSettings = () => { - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'teamChannel', params: { ...props, diff --git a/shared/teams/team/rows/emoji-row/add.tsx b/shared/teams/team/rows/emoji-row/add.tsx index 8f86c20ae821..128c26849ade 100644 --- a/shared/teams/team/rows/emoji-row/add.tsx +++ b/shared/teams/team/rows/emoji-row/add.tsx @@ -1,6 +1,6 @@ import * as Kb from '@/common-adapters' import type * as T from '@/constants/types' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import * as Teams from '@/stores/teams' import {useTeamsState} from '@/stores/teams' @@ -11,15 +11,15 @@ type OwnProps = { setFilter: (filter: string) => void } const AddEmoji = ({teamID, convID, filter, setFilter}: OwnProps) => { - const nav = useSafeNavigation() + const nav = useRouteNavigation() const canManageEmoji = useTeamsState(s => Teams.getCanPerformByID(s, teamID).manageEmojis) const onAddEmoji = () => - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'teamAddEmoji', params: {conversationIDKey: convID, teamID}, }) const onAddAlias = () => - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'teamAddEmojiAlias', params: {conversationIDKey: convID}, }) diff --git a/shared/teams/team/rows/emoji-row/item.tsx b/shared/teams/team/rows/emoji-row/item.tsx index 57072b4bf631..4e1a4aa76242 100644 --- a/shared/teams/team/rows/emoji-row/item.tsx +++ b/shared/teams/team/rows/emoji-row/item.tsx @@ -6,7 +6,7 @@ import * as dateFns from 'date-fns' import {RPCToEmojiData} from '@/common-adapters/emoji' import EmojiMenu from './emoji-menu' import {useEmojiState} from '@/teams/emojis/use-emoji' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {useCurrentUserState} from '@/stores/current-user' type OwnProps = { @@ -18,13 +18,13 @@ type OwnProps = { const ItemRow = ({conversationIDKey, emoji, firstItem, teamID}: OwnProps) => { const emojiData = RPCToEmojiData(emoji, false) - const nav = useSafeNavigation() + const nav = useRouteNavigation() const username = useCurrentUserState(s => s.username) const canManageEmoji = Teams.useTeamsState(s => Teams.getCanPerformByID(s, teamID).manageEmojis) const deleteOtherEmoji = Teams.useTeamsState(s => Teams.getCanPerformByID(s, teamID).deleteOtherEmojis) const canRemove = canManageEmoji && (deleteOtherEmoji || emoji.creationInfo?.username === username) const onAddAlias = () => { - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'teamAddEmojiAlias', params: {conversationIDKey, defaultSelected: emojiData}, }) diff --git a/shared/teams/team/rows/empty-row.tsx b/shared/teams/team/rows/empty-row.tsx index 40d12d4e7713..e265e2948b25 100644 --- a/shared/teams/team/rows/empty-row.tsx +++ b/shared/teams/team/rows/empty-row.tsx @@ -3,7 +3,7 @@ import * as C from '@/constants' import * as Chat from '@/stores/chat' import * as Teams from '@/stores/teams' import * as Kb from '@/common-adapters' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {useCurrentUserState} from '@/stores/current-user' type Props = { @@ -28,14 +28,14 @@ const buttonLabel = { const useSecondaryAction = (props: Props) => { const {teamID, conversationIDKey} = props - const nav = useSafeNavigation() + const nav = useRouteNavigation() const startAddMembersWizard = Teams.useTeamsState(s => s.dispatch.startAddMembersWizard) const launchNewTeamWizardOrModal = Teams.useTeamsState(s => s.dispatch.launchNewTeamWizardOrModal) const onSecondaryAction = () => { switch (props.type) { case 'members': if (conversationIDKey) { - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'chatAddToChannel', params: {conversationIDKey: conversationIDKey, teamID}, }) @@ -47,10 +47,10 @@ const useSecondaryAction = (props: Props) => { launchNewTeamWizardOrModal(teamID) break case 'channelsFew': - nav.safeNavigateAppend({name: 'chatCreateChannel', params: {teamID}}) + nav.navigateAppend({name: 'chatCreateChannel', params: {teamID}}) break case 'channelsEmpty': - nav.safeNavigateAppend({name: 'teamCreateChannels', params: {teamID}}) + nav.navigateAppend({name: 'teamCreateChannels', params: {teamID}}) break } } diff --git a/shared/teams/team/rows/member-row.tsx b/shared/teams/team/rows/member-row.tsx index 0421aaf8effd..c4869d1452c2 100644 --- a/shared/teams/team/rows/member-row.tsx +++ b/shared/teams/team/rows/member-row.tsx @@ -4,7 +4,7 @@ import * as Kb from '@/common-adapters' import * as Teams from '@/stores/teams' import type * as T from '@/constants/types' import MenuHeader from './menu-header.new' -import {useSafeNavigation} from '@/util/safe-navigation' +import {useRouteNavigation} from '@/constants/router' import {useTrackerState} from '@/stores/tracker' import {useProfileState} from '@/stores/profile' import {useUsersState} from '@/stores/users' @@ -80,7 +80,7 @@ export const TeamMemberRow = (props: Props) => { const isYou = props.you === props.username const teamID = props.teamID - const nav = useSafeNavigation() + const nav = useRouteNavigation() const teamSelectedMembers = Teams.useTeamsState(s => s.teamSelectedMembers.get(teamID)) const anySelected = !!teamSelectedMembers?.size const selected = !!teamSelectedMembers?.has(props.username) @@ -158,7 +158,7 @@ export const TeamMemberRow = (props: Props) => { { icon: 'iconfont-chat', onClick: () => - nav.safeNavigateAppend({ + nav.navigateAppend({ name: 'teamAddToChannels', params: {teamID, usernames: [username]}, }), diff --git a/shared/util/safe-navigation.tsx b/shared/util/safe-navigation.tsx deleted file mode 100644 index 2413ced23d2b..000000000000 --- a/shared/util/safe-navigation.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as C from '@/constants' -import {useIsFocused} from '@react-navigation/core' -import type {NavigateAppendType} from '@/router-v2/route-params' - -export const useSafeNavigation = () => { - const isFocused = useIsFocused() - const navigateUp = C.useRouterState(s => s.dispatch.navigateUp) - const navigateAppend = C.useRouterState(s => s.dispatch.navigateAppend) - return { - safeNavigateAppend: (path: NavigateAppendType, replace?: boolean) => - isFocused && navigateAppend(path, replace), - safeNavigateUp: () => isFocused && navigateUp(), - } -} diff --git a/shared/util/safe-submit.tsx b/shared/util/safe-submit.tsx deleted file mode 100644 index a6f0c8a41e89..000000000000 --- a/shared/util/safe-submit.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import * as React from 'react' - -export function useSafeSubmit) => void>(f: F, shouldReset: boolean) { - const safeToCallRef = React.useRef(true) - - React.useEffect(() => { - if (shouldReset) { - safeToCallRef.current = true - } - }, [shouldReset]) - - const safeWrapped = (...args: Array) => { - if (safeToCallRef.current) { - safeToCallRef.current = false - f(...args) - } else { - } - } - - return safeWrapped -}