diff --git a/app/_layout.tsx b/app/_layout.tsx index 65648c9d..153fc6bc 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -2,7 +2,7 @@ import { ThemeProvider } from '@react-navigation/native' import { Slot } from 'expo-router' import { AbsoluteFullFill, Loader } from '~components' -import { useAuth, useNavigationTheme } from '~hooks' +import { useAuth, useNavigationTheme, useRouterNotifications } from '~hooks' import { Providers } from '~providers' export const unstable_settings = { @@ -13,6 +13,8 @@ const Layout = () => { const { isSignedIn } = useAuth() const { navigationTheme } = useNavigationTheme() + useRouterNotifications() // TODO: check if handling notification deeplinks works correctly + if (isSignedIn === null) { return ( diff --git a/src/hooks/navigation/index.ts b/src/hooks/navigation/index.ts index 3dca4660..ef7a2db7 100644 --- a/src/hooks/navigation/index.ts +++ b/src/hooks/navigation/index.ts @@ -1,21 +1,7 @@ -export { useBottomTabBarHeight } from '@react-navigation/bottom-tabs' -export { - useNavigationContainerRef, - useFocusEffect, - useIsFocused, - useLinkBuilder, - useLinkProps, - useLinkTo, - useNavigation, - useNavigationBuilder, - useNavigationState, - useRoute, - useScrollToTop, -} from '@react-navigation/native' -export { useCardAnimation, useGestureHandlerRef } from '@react-navigation/stack' export * from './useNavigationStatePersistence' export * from './useNavigationTheme' export * from './usePreventGoBack' export * from './useScreenOptions' export * from './useScreenTracker' export * from './useWeb' +export * from './useRouterNotifications' diff --git a/src/hooks/navigation/useRouterNotifications.ts b/src/hooks/navigation/useRouterNotifications.ts new file mode 100644 index 00000000..e7329054 --- /dev/null +++ b/src/hooks/navigation/useRouterNotifications.ts @@ -0,0 +1,39 @@ +import * as Notifications from 'expo-notifications' +import { useRouter } from 'expo-router' +import React from 'react' + +export function useRouterNotifications() { + const router = useRouter() + + React.useEffect(() => { + let isMounted = true + + function processUrl(url: string) { + // In case you need to modify the URL to make it relative. + return url + } + + // Handle URL from expo push notifications + Notifications.getLastNotificationResponseAsync().then((response) => { + if (!isMounted) { + return + } + const url = response?.notification.request.content.data.url + if (url) { + router.replace(processUrl(url)) + } + }) + + // Listen to expo push notifications + const subscription = Notifications.addNotificationResponseReceivedListener((response) => { + const url = response.notification.request.content.data.url + router.replace(processUrl(url)) + }) + + return () => { + isMounted = false + subscription.remove() + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) +} diff --git a/src/hooks/useNotificationSetup.ts b/src/hooks/useNotificationSetup.ts deleted file mode 100644 index 586c56ea..00000000 --- a/src/hooks/useNotificationSetup.ts +++ /dev/null @@ -1,80 +0,0 @@ -import AsyncStorage from '@react-native-async-storage/async-storage' -import { useLinkTo } from '@react-navigation/native' -import * as Notifications from 'expo-notifications' -import { useCallback, useEffect } from 'react' - -import { ASYNC_STORAGE_KEYS } from '~constants' -import { authContextRef, useNotificationContext } from '~contexts' -import { registerForPushNotificationsAsync } from '~services' -import { alert } from '~utils' -import { isAuthorizedLink } from '~utils/isAuthorizedLink' - -type Options = { - /** - * When *true* automatically handles deeplink provided in notification. - */ - enableDeeplink?: boolean -} - -export const useNotificationSetup = (opts?: Options) => { - const { inAppNotification, setInAppNotification } = useNotificationContext() - const linkTo = useLinkTo() - - useEffect(() => { - const initNotifications = async () => { - await registerForPushNotificationsAsync() - } - initNotifications() - }, []) - - const handleDeeplink = useCallback( - (deeplinkPath?: string) => { - if (!deeplinkPath) return - - // Deeplink that is used in `linkTo` method after authorized checks - let finalDeeplink = deeplinkPath - - const isAuthorizedPath = isAuthorizedLink(deeplinkPath) - - if (!authContextRef.current?.isSignedIn && isAuthorizedPath) { - AsyncStorage.setItem(ASYNC_STORAGE_KEYS.NEXT_DEEP_LINK, deeplinkPath) - finalDeeplink = '/sign-in' - } - - const addSlash = !finalDeeplink.startsWith('/') - finalDeeplink = `${addSlash ? '/' : ''}${finalDeeplink}` - - if (opts?.enableDeeplink) { - linkTo(finalDeeplink) - } - }, - [linkTo, opts?.enableDeeplink] - ) - - // CONFIG: Handle in app notification - const navigateWithNotification = useCallback( - (notification: Notifications.Notification) => { - const { title, body } = notification?.request?.content ?? {} - alert(title ?? 'Notification', body ?? 'Navigate somewhere', [ - { text: 'Cancel', onPress: () => setInAppNotification(undefined), style: 'cancel' }, - { - text: 'Ok', - onPress: () => { - // Elvis chains prevent crashes in undiscslosed edge cases - const deeplinkPath = notification?.request?.content?.data?.deeplink as - | string - | undefined - handleDeeplink(deeplinkPath) - }, - }, - ]) - }, - [handleDeeplink, setInAppNotification] - ) - - useEffect(() => { - if (inAppNotification) { - navigateWithNotification(inAppNotification) - } - }, [inAppNotification, navigateWithNotification, setInAppNotification]) -} diff --git a/src/navigation/BottomTabNavigator.tsx b/src/navigation/BottomTabNavigator.tsx deleted file mode 100644 index 819ad3fa..00000000 --- a/src/navigation/BottomTabNavigator.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { createBottomTabNavigator, BottomTabNavigationOptions } from '@react-navigation/bottom-tabs' -import { createStackNavigator } from '@react-navigation/stack' -import { memo } from 'react' - -import { bottomTabsScreensData } from './config/tabs' - -import { Text, Icon } from '~components/atoms' -import { TAB_DEFAULT_ICON } from '~constants' -import { useCallback, useNavigationTheme } from '~hooks' - -const { Navigator, Screen } = createBottomTabNavigator() - -type ScreenOptions = (params: BottomTabScreenProps) => BottomTabNavigationOptions - -const navigatorScreens = bottomTabsScreensData.map((props) => { - const Component = memo((): JSX.Element => { - const { Navigator: StackNavigator, Screen: StackScreen } = createStackNavigator() - const screens = props.screens.map((props) => ) - return {screens} - // eslint-disable-next-line react-hooks/exhaustive-deps - }) - - return -}) - -export const BottomTabNavigator = () => { - const { tabBarTheme } = useNavigationTheme() - - const screenOptions = useCallback( - ({ route }) => ({ - tabBarIcon: ({ color, size, focused }) => { - const { active, inactive } = - bottomTabsScreensData.find((screen) => screen.name === route.name)?.icons || {} - const iconToRender = (focused ? active : inactive) || TAB_DEFAULT_ICON - - // CONFIG: You can return any component that you like here! - return - }, - tabBarLabel: ({ color, focused }) => { - const title = - bottomTabsScreensData.find((screen) => screen.name === route.name)?.options?.title || '' - - // CONFIG: You can return any component that you like here! - - const TextComponent = focused ? Text.NavLabelBold : Text.NavLabel - return {title} - }, - headerShown: false, - ...tabBarTheme, - }), - [tabBarTheme] - ) - - return {navigatorScreens} -} diff --git a/src/navigation/RootNavigator.tsx b/src/navigation/RootNavigator.tsx deleted file mode 100644 index d4af3065..00000000 --- a/src/navigation/RootNavigator.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { createStackNavigator } from '@react-navigation/stack' -import { FC } from 'react' -import { Platform, useWindowDimensions } from 'react-native' - -import { rootStackScreensData } from './config/screens' -import { WebNavBar } from './webNavigator/WebNavBar' - -import { WEB_SCREEN_STYLES } from '~constants' -import { useAuth, useNavigationTheme, useWeb } from '~hooks' -import { useNotificationSetup } from '~hooks/useNotificationSetup' - -const { Navigator, Screen, Group } = createStackNavigator() - -const authorizedScreens = rootStackScreensData.authorized.map((props) => ( - -)) - -const unauthorizedScreens = rootStackScreensData.unauthorized.map((props) => ( - -)) - -const modalsScreens = rootStackScreensData.modals.map((props) => ( - -)) - -const RootNavigatorMobile: FC = () => { - const { isSignedIn } = useAuth() - - // CONFIG: Handle in app notification - useNotificationSetup({ - enableDeeplink: true, - }) - - return ( - - {!isSignedIn ? ( - {unauthorizedScreens} - ) : ( - {authorizedScreens} - )} - - {modalsScreens} - - - ) -} - -const RootNavigatorWeb: FC = () => { - const { shouldApplyMobileStyles, webContentWidth } = useWeb() - const { navigationTheme } = useNavigationTheme() - const { width: windowWidth } = useWindowDimensions() - const { isSignedIn } = useAuth() - - return ( - <> - {!shouldApplyMobileStyles && isSignedIn && } - - {!isSignedIn ? ( - {unauthorizedScreens} - ) : ( - {authorizedScreens} - )} - - {modalsScreens} - - - {shouldApplyMobileStyles && isSignedIn && } - - ) -} - -export const RootNavigator = Platform.OS === 'web' ? RootNavigatorWeb : RootNavigatorMobile diff --git a/src/navigation/config/enums.ts b/src/navigation/config/enums.ts deleted file mode 100644 index 408545b1..00000000 --- a/src/navigation/config/enums.ts +++ /dev/null @@ -1,41 +0,0 @@ -type Keys = keyof T -export const keys = (object: T) => Object.keys(object) as (keyof T)[] - -// Root_SCREENS -export const RootStackScreens = { - SignIn: 'SignIn', - SignUp: 'SignUp', - MainTab: 'MainTab', - ApplicationInfo: 'ApplicationInfo', - NotFound: 'NotFound', -} as const - -// BottomTabs_SCREENS -export const BottomTabsScreens = { - HomeStack: 'HomeStack', - ExamplesStack: 'ExamplesStack', - SettingsStack: 'SettingsStack', -} as const - -// ExamplesStack_SCREENS -export const ExamplesStackScreens = { - Examples: 'Examples', - Typography: 'Typography', - Colors: 'Colors', - Components: 'Components', - DataFromBeScreen_EXAMPLE: 'DataFromBeScreen_EXAMPLE', - TestForm: 'TestForm', -} as const - -// HomeStack_SCREENS -export const HomeStackScreens = { - Home: 'Home', - Details: 'Details', -} as const - -// SettingsStack_SCREENS -export const SettingsStackScreens = { - Settings: 'Settings', -} as const - -export type BottomTabsScreensKeys = Keys diff --git a/src/navigation/config/navigation.d.ts b/src/navigation/config/navigation.d.ts deleted file mode 100644 index 2cd654dc..00000000 --- a/src/navigation/config/navigation.d.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { NavigatorScreenParams } from '@react-navigation/native' -import { StackScreenProps } from '@react-navigation/stack' -import { BottomTabScreenProps as BaseBottomTabScreenProps } from '@react-navigation/bottom-tabs' - -declare global { - // PARAMS - type HomeStackParamList = { - Home: undefined - Details: { id: string } - } - - type ExamplesStackParamList = { - TestForm: undefined - Examples: undefined - Components: undefined - Colors: undefined - Typography: undefined - DataFromBeScreen_EXAMPLE: undefined - } - - type SettingsStackParamList = { - Settings: undefined - } - - type MainTabParamList = { - HomeStack: NavigatorScreenParams - ExamplesStack: NavigatorScreenParams - SettingsStack: NavigatorScreenParams - // MainTabParamList END - } - - type WebTabParamList = ExamplesStackParamList & HomeStackParamList & SettingsStackParamList - // WebTabParamListEnd - - type RootStackParamList = { - // Root_unauthorized - SignUp: undefined - SignIn: undefined - - // Root_authorized - MainTab: NavigatorScreenParams - - // Root_modals - ApplicationInfo: undefined - NotFound: undefined - } - - namespace ReactNavigation { - // eslint-disable-next-line @typescript-eslint/no-empty-interface - interface RootParamList extends RootStackParamList {} - } - - // SCREENS - specific screens props - // You can get navigation or route prop for every screen f. eg. - // - HomeScreenNavigationProps['route'] - // - HomeScreenNavigationProps['navigation'] - - type BottomTabScreenProps = BaseBottomTabScreenProps< - MainTabParamList, - 'ExamplesStack' | 'HomeStack' | 'SettingsStack' - // BottomTabScreenProps END - > - - // root_stack - type RootStackScreenProps = ScreenComposite - - // RootStack_SCREENS - - // HomeStack_SCREENS - type HomeScreenProps = ScreenComposite<'Home'> - type DetailsScreenProps = ScreenComposite<'Details'> - - // ExamplesStack_SCREENS - type TestFormScreenProps = ScreenComposite<'TestForm'> - type ExamplesScreenProps = ScreenComposite<'Examples'> - type ComponentsScreenProps = ScreenComposite<'Components'> - - // SettingsStack_SCREENS - type SettingsScreenProps = ScreenComposite<'Settings'> -} - -// type ScreenHehe = ScreenComponent - -// Helper types -type ScreenComposite< - S extends keyof (RootStackParamList & - HomeStackParamList & - ExamplesStackParamList) = keyof RootStackParamList -> = StackScreenProps diff --git a/src/navigation/config/screens.ts b/src/navigation/config/screens.ts deleted file mode 100644 index 65cb6eaf..00000000 --- a/src/navigation/config/screens.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { StackNavigationOptions } from '@react-navigation/stack' -import { t } from 'i18next' -import { Platform } from 'react-native' - -import { RootStackScreens } from './enums' -import { bottomTabsScreensData } from './tabs' - -import { BottomTabNavigator } from '~navigation/BottomTabNavigator' -import { WebNavigator } from '~navigation/webNavigator/WebNavigator' -import { ApplicationInfoScreen, NotFoundScreen, SignInScreen, SignUpScreen } from '~screens' - -const isWeb = Platform.OS === 'web' - -type RootScreenType = { - name: keyof RootStackParamList - // eslint-disable-next-line @typescript-eslint/no-explicit-any - component: (props: { navigation: any; route: any }) => JSX.Element - options?: StackNavigationOptions - deeplink: string -} - -type RootScreensType = { - authorized: RootScreenType[] - unauthorized: RootScreenType[] - modals: RootScreenType[] -} - -// RootStack_SCREENS_START -export const rootStackScreensData: RootScreensType = { - authorized: [ - { - name: RootStackScreens.MainTab, - component: isWeb ? WebNavigator : BottomTabNavigator, - options: { title: t('navigation.screen_titles.home'), headerShown: false }, - deeplink: '/', - }, - // authorized_SCREENS_END - ], - unauthorized: [ - { - name: RootStackScreens.SignIn, - component: SignInScreen, - options: { title: t('navigation.screen_titles.sign_in') }, - deeplink: '/sign-in', - }, - { - name: RootStackScreens.SignUp, - component: SignUpScreen, - options: { title: t('navigation.screen_titles.sign_up') }, - deeplink: '/sign-up', - }, - // unauthorized_SCREENS_END - ], - modals: [ - { - name: RootStackScreens.ApplicationInfo, - component: ApplicationInfoScreen, - options: { title: t('navigation.screen_titles.application_info') }, - deeplink: '/app-info', - }, - { - name: RootStackScreens.NotFound, - component: NotFoundScreen, - options: { title: t('navigation.screen_titles.not_found') }, - deeplink: '*', - }, - // modals_SCREENS_END - ], -} // RootStack_SCREENS_END - -export const webScreensData = bottomTabsScreensData.map((tab) => tab?.screens ?? []).flat() diff --git a/src/navigation/config/tabs.ts b/src/navigation/config/tabs.ts deleted file mode 100644 index 13ace6a4..00000000 --- a/src/navigation/config/tabs.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { StackNavigationOptions } from '@react-navigation/stack' -import { t } from 'i18next' - -import { - BottomTabsScreens, - ExamplesStackScreens, - SettingsStackScreens, - HomeStackScreens, - // StackEnums -} from './enums' - -import { - ColorsScreen, - ComponentsScreen, - DataFromBeScreen_EXAMPLE, - DetailsScreen, - ExamplesScreen, - HomeScreen, - TypographyScreen, - TestFormScreen, - SettingsScreen, -} from '~screens' -import { IconNames } from '~types/icon' - -type ScreenType = { - name: T - // eslint-disable-next-line @typescript-eslint/no-explicit-any - component: (props: { navigation: any; route: any }) => JSX.Element - options?: StackNavigationOptions - deeplink: string -} - -// ExamplesStack_SCREENS_START -const examplesStackScreensData: ScreenType[] = [ - { - name: ExamplesStackScreens.Examples, - component: ExamplesScreen, - options: { title: t('navigation.screen_titles.examples') }, - deeplink: '/examples', - }, - { - name: ExamplesStackScreens.Typography, - component: TypographyScreen, - options: { title: t('navigation.screen_titles.typography') }, - deeplink: '/typography', - }, - { - name: ExamplesStackScreens.Colors, - component: ColorsScreen, - options: { title: t('navigation.screen_titles.colors') }, - deeplink: '/colors', - }, - { - name: ExamplesStackScreens.Components, - component: ComponentsScreen, - options: { title: t('navigation.screen_titles.components') }, - deeplink: '/components', - }, - { - name: ExamplesStackScreens.DataFromBeScreen_EXAMPLE, - component: DataFromBeScreen_EXAMPLE, - options: { title: t('navigation.screen_titles.data_from_be_screen_example') }, - deeplink: '/data-example', - }, - { - name: ExamplesStackScreens.TestForm, - component: TestFormScreen, - // TODO: Add translation here - options: { title: 'TestForm' }, - deeplink: '/testform', - }, - // ExamplesStack_SCREENS_END -] - -// SettingsStack_SCREENS_START -const settingsStackScreensData: ScreenType[] = [ - { - name: SettingsStackScreens.Settings, - component: SettingsScreen, - options: { title: t('navigation.screen_titles.settings') }, - deeplink: '/settings', - }, -] -// SettingsStack_SCREENS_END - -// HomeStack_SCREENS_START -const homeStackScreensData: ScreenType[] = [ - { - name: HomeStackScreens.Home, - component: HomeScreen, - options: { title: t('navigation.screen_titles.home') }, - deeplink: '/', - }, - { - name: HomeStackScreens.Details, - component: DetailsScreen, - options: { title: t('navigation.screen_titles.details') }, - deeplink: '/details', - }, - // HomeStack_SCREENS_END -] - -type BottomTabIcons = { - active: IconNames - inactive: IconNames -} -// BottomTab_SCREENS_START -export const bottomTabsScreensData = [ - { - icons: { - active: 'home-5-fill', - inactive: 'home-line', - } as BottomTabIcons, - name: BottomTabsScreens.HomeStack, - screens: homeStackScreensData, - options: { title: t('navigation.screen_titles.home_stack') }, - }, - { - icons: { - active: 'file-list-2-fill', - inactive: 'file-list-2-line', - } as BottomTabIcons, - name: BottomTabsScreens.ExamplesStack, - screens: examplesStackScreensData, - options: { title: t('navigation.screen_titles.examples_stack') }, - }, - { - icons: { - active: 'home-gear-fill', - inactive: 'home-gear-line', - } as BottomTabIcons, - name: BottomTabsScreens.SettingsStack, - screens: settingsStackScreensData, - options: { title: t('navigation.screen_titles.settings') }, - }, - // BottomTab_SCREENS_END -] - -export const webScreensData = bottomTabsScreensData.map((tab) => tab?.screens ?? []).flat() diff --git a/src/navigation/index.tsx b/src/navigation/index.tsx deleted file mode 100644 index 19e220dd..00000000 --- a/src/navigation/index.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { NavigationContainer, NavigationState } from '@react-navigation/native' -import { FC } from 'react' - -import { RootNavigator } from './RootNavigator' -import { linking } from './linking' - -import { StatusBar } from '~components' -import { - useScreenTracker, - useNavigationStatePersistence, - useNavigationTheme, - useCallback, -} from '~hooks' - -export const Navigation: FC = () => { - const { navigationRef, onReady, onStateChange: onStateChangeScreenTracker } = useScreenTracker() - const { navigationTheme } = useNavigationTheme() - - const { - isReady, - initialState, - onStateChange: onStateChangeNavigationStatePersistance, - } = useNavigationStatePersistence() - - const onStateChange = useCallback( - (state: NavigationState | undefined) => { - onStateChangeScreenTracker() - onStateChangeNavigationStatePersistance(state) - }, - [onStateChangeNavigationStatePersistance, onStateChangeScreenTracker] - ) - - if (!isReady) { - return null - } - - return ( - <> - - - - - - ) -} diff --git a/src/navigation/linking.ts b/src/navigation/linking.ts deleted file mode 100644 index 7fd46261..00000000 --- a/src/navigation/linking.ts +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Learn more about deep linking with React Navigation - * https://reactnavigation.org/docs/deep-linking - * https://reactnavigation.org/docs/configuring-links - */ - -import { LinkingOptions } from '@react-navigation/native' -import Constants from 'expo-constants' -import { createURL } from 'expo-linking' -import { Platform } from 'react-native' - -import { HomeStackScreens, RootStackScreens } from './config/enums' -import { rootStackScreensData } from './config/screens' -import { bottomTabsScreensData, webScreensData } from './config/tabs' - -const prefix = createURL('/') -const universalLinks = Constants.expoConfig?.extra?.universalLinks ?? [] - -const webTabsScreens = webScreensData.reduce<{ [key: string]: string }>((prev, current) => { - prev[current.name] = current.deeplink - return prev -}, {}) - -const mobileTabsScreens = bottomTabsScreensData.reduce<{ - [key: string]: { - initialRouteName: string - screens: { [key: string]: string } - } -}>((prev, current) => { - // issue in typescript, follow this thread: https://github.com/microsoft/TypeScript/issues/44373 - const screens = current.screens as unknown as { - initialRouteName: string - name: string - deeplink: string - screens: { [key: string]: string } - }[] - prev[current.name] = { - initialRouteName: current.screens[0].name, - screens: screens.reduce<{ [key: string]: string }>((prev, current) => { - prev[current.name] = current.deeplink - return prev - }, {}), - } - return prev -}, {}) - -const rootScreensData = [ - // Filter out MainTab because it's handled separately - ...rootStackScreensData.authorized.filter((screen) => screen.name !== RootStackScreens.MainTab), - ...rootStackScreensData.unauthorized, - ...rootStackScreensData.modals, -] - -const webRootScreens = rootScreensData.reduce<{ [key: string]: string }>((prev, current) => { - prev[current.name] = current.deeplink - return prev -}, {}) - -// Visit https://reactnavigation.org/docs/configuring-links#playground to see more -const WEB_LINKS_CONFIG: LinkingOptions['config'] = { - initialRouteName: 'MainTab', - screens: { - MainTab: { - // @ts-expect-error: Enum can't be cast to string, but the values are the same - initialRouteName: HomeStackScreens.Home, - screens: webTabsScreens, - }, - ...webRootScreens, - }, -} - -const APP_LINKS_CONFIG: LinkingOptions['config'] = { - initialRouteName: 'MainTab', - screens: { - MainTab: { - // @ts-expect-error: Enum can't be cast to string, but the values are the same - initialRouteName: HomeStackScreens.Home, - screens: mobileTabsScreens, - }, - ...webRootScreens, - }, -} - -export const linking: LinkingOptions = { - prefixes: [prefix, ...universalLinks], - config: Platform.OS === 'web' ? WEB_LINKS_CONFIG : APP_LINKS_CONFIG, -} diff --git a/src/navigation/webNavigator/WebNavBar.tsx b/src/navigation/webNavigator/WebNavBar.tsx deleted file mode 100644 index 42ed48e7..00000000 --- a/src/navigation/webNavigator/WebNavBar.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import React, { useCallback } from 'react' -import { StyleSheet } from 'react-native' - -import { BottomTabsScreensKeys } from '../config/enums' - -import { Icon, Box, Row, Text, Touchable, Absolute } from '~components' -import { TAB_DEFAULT_ICON, WEB_NAV_BAR_ICON_SIZE } from '~constants' -import { useNavigation, useNavigationState, useNavigationTheme, useWeb } from '~hooks' -import { bottomTabsScreensData } from '~navigation/config/tabs' -import { navigationRef } from '~utils' - -export const WebNavBar = (): JSX.Element => { - const { navigate } = useNavigation() - const { shouldApplyMobileStyles, webContentWidth } = useWeb() - const { tabBarTheme } = useNavigationTheme() - - // This hook call is needed to rerender this component when navigation state will change - // thanks to that function `getCurrentRoute` will have proper value - useNavigationState((state) => state?.routes) - const currentRouteName = navigationRef.current?.getCurrentRoute()?.name ?? '' - - const handleTabPress = useCallback( - (stackName: BottomTabsScreensKeys) => { - // Search for first screen that is in selected tab - const screenToNavigate = bottomTabsScreensData?.find((stack) => stack.name === stackName) - ?.screens?.[0].name as any // eslint-disable-line @typescript-eslint/no-explicit-any - - navigate(screenToNavigate) - }, - [navigate] - ) - - const isActiveTab = useCallback( - (screens: { name: string }[]) => { - // search through screens that are in single bottom tab, - // if one of screens from bottom tab is found then we should mark it as active - return screens.some((screen) => screen.name === currentRouteName) - }, - [currentRouteName] - ) - - return ( - - - - {bottomTabsScreensData.map(({ name, icons, screens, options }) => { - const focused = isActiveTab(screens) - const iconToRender = (focused ? icons.active : icons.inactive) || TAB_DEFAULT_ICON - const color = ( - focused ? tabBarTheme.tabBarActiveTintColor : tabBarTheme.tabBarInactiveTintColor - ) as ColorNames - return ( - - handleTabPress(name)} - > - {({ isHovered, isPressed }) => ( - <> - - - {options.title ? ( - - {options.title} - - ) : null} - - {focused && !shouldApplyMobileStyles && ( - - )} - - )} - - - ) - })} - - - - ) -} - -const styles = StyleSheet.create({ - iconContainer: { - opacity: 0.8, - transform: [{ scale: 0.9 }], - }, -}) diff --git a/src/navigation/webNavigator/WebNavigator.tsx b/src/navigation/webNavigator/WebNavigator.tsx deleted file mode 100644 index 2ea93d41..00000000 --- a/src/navigation/webNavigator/WebNavigator.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { createStackNavigator } from '@react-navigation/stack' -import React from 'react' - -import { webScreensData } from '~navigation/config/tabs' - -const { Navigator: NavigatorWeb, Screen: ScreenWeb } = createStackNavigator() - -const renderScreens = webScreensData.map((screen) => ( - -)) - -export const WebNavigator = () => { - return {renderScreens} -} diff --git a/src/utils/isAuthorizedLink.ts b/src/utils/isAuthorizedLink.ts deleted file mode 100644 index 903efa5c..00000000 --- a/src/utils/isAuthorizedLink.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { rootStackScreensData } from '~navigation/config/screens' - -const unauthorizedPaths = [ - ...rootStackScreensData.modals, - ...rootStackScreensData.unauthorized, -].map((screen) => screen.deeplink) - -/** - * Checks whether provided link contains authorized link or not. - * - * @param linkWithoutPrefix link to check with navigation authorized paths - */ -export const isAuthorizedLink = (linkWithoutPrefix: string): boolean => { - console.log(linkWithoutPrefix, unauthorizedPaths) - return unauthorizedPaths.some((path) => !linkWithoutPrefix.includes(path)) -}