From 57e63066ecf2cb1654002ffb909ca5f8ed9edfaa Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 4 Mar 2024 12:23:17 +0100 Subject: [PATCH 001/703] Add initial config for MyTripsPage --- src/ROUTES.ts | 2 ++ src/SCREENS.ts | 3 +++ .../BaseCentralPaneNavigator.tsx | 6 +++++- .../BottomTabBar.tsx | 9 +++++---- src/libs/Navigation/linkingConfig/config.ts | 2 ++ src/libs/Navigation/types.ts | 1 + src/pages/Travel/MyTripsPage.tsx | 20 +++++++++++++++++++ 7 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 src/pages/Travel/MyTripsPage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index e9cdce4f6ed9..f7c455e923a6 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -553,6 +553,8 @@ const ROUTES = { getRoute: (contentType: string, backTo?: string) => getUrlWithBackToParam(`referral/${contentType}`, backTo), }, PROCESS_MONEY_REQUEST_HOLD: 'hold-request-educational', + + TRAVEL_MY_TRIPS: 'travel', } as const; /** diff --git a/src/SCREENS.ts b/src/SCREENS.ts index ff3dbfd7f901..234a24476d2a 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -22,6 +22,9 @@ const SCREENS = { VALIDATE_LOGIN: 'ValidateLogin', UNLINK_LOGIN: 'UnlinkLogin', SETTINGS_CENTRAL_PANE: 'SettingsCentralPane', + TRAVEL: { + MY_TRIPS: 'Travel_MyTrips', + }, SETTINGS: { ROOT: 'Settings_Root', SHARE_CODE: 'Settings_Share_Code', diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx index 1e5d3639a32f..ab20497a3c73 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx @@ -4,6 +4,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import ReportScreenWrapper from '@libs/Navigation/AppNavigator/ReportScreenWrapper'; import getCurrentUrl from '@libs/Navigation/currentUrl'; import type {CentralPaneNavigatorParamList} from '@navigation/types'; +import MyTripsPage from '@pages/Travel/MyTripsPage'; import SCREENS from '@src/SCREENS'; const Stack = createStackNavigator(); @@ -43,7 +44,10 @@ function BaseCentralPaneNavigator() { initialParams={{openOnAdminRoom: openOnAdminRoom === 'true' || undefined}} component={ReportScreenWrapper} /> - + {Object.entries(workspaceSettingsScreens).map(([screenName, componentGetter]) => ( - interceptAnonymousUser(() => - activeWorkspaceID ? Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(activeWorkspaceID)) : Navigation.navigate(ROUTES.ALL_SETTINGS), - ) + onPress={ + () => Navigation.navigate(ROUTES.TRAVEL_MY_TRIPS) + // interceptAnonymousUser(() => + // activeWorkspaceID ? Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(activeWorkspaceID)) : Navigation.navigate(ROUTES.ALL_SETTINGS), + // ) } role={CONST.ROLE.BUTTON} accessibilityLabel={translate('common.settings')} diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 276829e8c691..3515f17f3867 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -67,6 +67,8 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.CATEGORIES]: { path: ROUTES.WORKSPACE_CATEGORIES.route, }, + + [SCREENS.TRAVEL.MY_TRIPS]: ROUTES.TRAVEL_MY_TRIPS, }, }, [SCREENS.NOT_FOUND]: '*', diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index a1e558869ebe..03d6bbeb5cca 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -90,6 +90,7 @@ type CentralPaneNavigatorParamList = { [SCREENS.WORKSPACE.CATEGORIES]: { policyID: string; }; + [SCREENS.TRAVEL.MY_TRIPS]: undefined; }; type WorkspaceSwitcherNavigatorParamList = { diff --git a/src/pages/Travel/MyTripsPage.tsx b/src/pages/Travel/MyTripsPage.tsx new file mode 100644 index 000000000000..1983332c4e10 --- /dev/null +++ b/src/pages/Travel/MyTripsPage.tsx @@ -0,0 +1,20 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React from 'react'; +import {View} from 'react-native'; +import Text from '@components/Text'; +import type {CentralPaneNavigatorParamList} from '@navigation/types'; +import type SCREENS from '@src/SCREENS'; + +type MyTripsPageProps = StackScreenProps; + +function MyTripsPage({route}: MyTripsPageProps) { + return ( + + MyTripsPage + + ); +} + +MyTripsPage.displayName = 'MyTripsPage'; + +export default MyTripsPage; From 3e95765db62e01513f27bfaf32161a4dd6598ec4 Mon Sep 17 00:00:00 2001 From: smelaa Date: Mon, 4 Mar 2024 15:50:52 +0100 Subject: [PATCH 002/703] ManageTrips init --- src/languages/en.ts | 10 +++++++ src/languages/es.ts | 10 +++++++ src/pages/Travel/ManageTrips.tsx | 47 ++++++++++++++++++++++++++++++++ src/pages/Travel/MyTripsPage.tsx | 27 ++++++++++++++---- 4 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 src/pages/Travel/ManageTrips.tsx diff --git a/src/languages/en.ts b/src/languages/en.ts index bd57843e9245..2b483de57c93 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1717,6 +1717,16 @@ export default { session: { offlineMessageRetry: "Looks like you're offline. Please check your connection and try again.", }, + travel: { + header: 'My trips', + title: 'Book or manage your trips', + subtitle: 'Use Expensify Travel to get the best travel offers and manage all your business expenses in a single place.', + bookOrManage: 'Book or manage', + features: { + saveMoney: 'Save money on your bookings', + alerts: 'Get real time alerts if your travel plans change', + }, + }, workspace: { common: { card: 'Cards', diff --git a/src/languages/es.ts b/src/languages/es.ts index 83ed2ca1c89c..d0ca18d0aead 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1741,6 +1741,16 @@ export default { session: { offlineMessageRetry: 'Parece que estás desconectado. Por favor, comprueba tu conexión e inténtalo de nuevo.', }, + travel: { + header: 'Mis viajes', + title: 'Reserva o gestiona tus viajes', + subtitle: 'Utiliza Expensify Travel para obtener las mejores ofertas de viaje y gestionar todos tus gastos de negocio en un solo lugar.', + bookOrManage: 'Reservar o gestionar', + features: { + saveMoney: 'Ahorra dinero en tus reservas', + alerts: 'Recibe alertas en tiempo real si cambian tus planes de viaje', + }, + }, workspace: { common: { card: 'Tarjetas', diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx new file mode 100644 index 000000000000..3cd09c8e98d2 --- /dev/null +++ b/src/pages/Travel/ManageTrips.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import {ScrollView, View} from 'react-native'; +import type {FeatureListItem} from '@components/FeatureList'; +import FeatureList from '@components/FeatureList'; +import * as Illustrations from '@components/Icon/Illustrations'; +import LottieAnimations from '@components/LottieAnimations'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; +import App from '@src/App'; + +const tripsFeatures: FeatureListItem[] = [ + { + icon: Illustrations.MoneyReceipts, + translationKey: 'travel.features.saveMoney', + }, + { + icon: Illustrations.CreditCardsNew, + translationKey: 'travel.features.alerts', + }, +]; + +function ManageTrips() { + const styles = useThemeStyles(); + const {isSmallScreenWidth} = useWindowDimensions(); + const {translate} = useLocalize(); + + return ( + + + console.log('pressed')} + illustration={LottieAnimations.SaveTheWorld} + /> + + + ); +} + +ManageTrips.displayName = 'ManageTrips'; + +export default ManageTrips; diff --git a/src/pages/Travel/MyTripsPage.tsx b/src/pages/Travel/MyTripsPage.tsx index 1983332c4e10..ae9e604cc177 100644 --- a/src/pages/Travel/MyTripsPage.tsx +++ b/src/pages/Travel/MyTripsPage.tsx @@ -1,17 +1,34 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; -import {View} from 'react-native'; -import Text from '@components/Text'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import * as Illustrations from '@components/Icon/Illustrations'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useLocalize from '@hooks/useLocalize'; +import Navigation from '@libs/Navigation/Navigation'; import type {CentralPaneNavigatorParamList} from '@navigation/types'; import type SCREENS from '@src/SCREENS'; +import ManageTrips from './ManageTrips'; type MyTripsPageProps = StackScreenProps; function MyTripsPage({route}: MyTripsPageProps) { + const {translate} = useLocalize(); return ( - - MyTripsPage - + + Navigation.goBack()} + /> + + ); } From 011d2273613ae5e72108af56212456267e2fef3a Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 4 Mar 2024 15:55:15 +0100 Subject: [PATCH 003/703] Add TravelMenu page --- src/ROUTES.ts | 2 + src/SCREENS.ts | 1 + src/languages/en.ts | 3 + src/languages/es.ts | 3 + .../Navigators/BottomTabNavigator.tsx | 6 ++ .../BottomTabBar.tsx | 29 +++++-- .../TAB_TO_CENTRAL_PANE_MAPPING.ts | 1 + src/libs/Navigation/linkingConfig/config.ts | 1 + src/libs/Navigation/types.ts | 1 + src/pages/Travel/TravelMenu.tsx | 86 +++++++++++++++++++ 10 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 src/pages/Travel/TravelMenu.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index f7c455e923a6..4496d102d037 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -555,6 +555,8 @@ const ROUTES = { PROCESS_MONEY_REQUEST_HOLD: 'hold-request-educational', TRAVEL_MY_TRIPS: 'travel', + + TRAVEL_HOME: 'travel-home', } as const; /** diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 234a24476d2a..b08f8efabf45 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -23,6 +23,7 @@ const SCREENS = { UNLINK_LOGIN: 'UnlinkLogin', SETTINGS_CENTRAL_PANE: 'SettingsCentralPane', TRAVEL: { + HOME: 'Travel_Home', MY_TRIPS: 'Travel_MyTrips', }, SETTINGS: { diff --git a/src/languages/en.ts b/src/languages/en.ts index bd57843e9245..1a7c08371f27 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2427,4 +2427,7 @@ export default { offline: "You appear to be offline. Unfortunately, Expensify Classic doesn't work offline, but New Expensify does. If you prefer to use Expensify Classic, try again when you have an internet connection.", }, + travel: { + myTrips: 'My trips', + }, } satisfies TranslationBase; diff --git a/src/languages/es.ts b/src/languages/es.ts index 83ed2ca1c89c..ff6cc2b03e9c 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2919,4 +2919,7 @@ export default { offline: 'Parece que estás desconectado. Desafortunadamente, Expensify Classic no funciona sin conexión, pero New Expensify sí. Si prefieres utilizar Expensify Classic, inténtalo de nuevo cuando tengas conexión a internet.', }, + travel: { + myTrips: 'Mis viajes', + }, } satisfies EnglishTranslation; diff --git a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx index ce03a8d5bcba..9ce1b8425f51 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx @@ -11,6 +11,8 @@ import ActiveRouteContext from './ActiveRouteContext'; const loadWorkspaceInitialPage = () => require('../../../../pages/workspace/WorkspaceInitialPage').default as React.ComponentType; +const loadTravelMenuPage = () => require('../../../../pages/Travel/TravelMenu').default as React.ComponentType; + const Tab = createCustomBottomTabNavigator(); const screenOptions: StackNavigationOptions = { @@ -35,6 +37,10 @@ function BottomTabNavigator() { name={SCREENS.WORKSPACE.INITIAL} getComponent={loadWorkspaceInitialPage} /> + ); diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 39435fb6287d..6e2595c515eb 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -91,14 +91,30 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps - + + Navigation.navigate(ROUTES.TRAVEL_MY_TRIPS)} + role={CONST.ROLE.BUTTON} + accessibilityLabel={translate('workspace.common.travel')} + wrapperStyle={styles.flexGrow1} + style={styles.bottomTabBarItem} + > + + + + + Navigation.navigate(ROUTES.TRAVEL_MY_TRIPS) - // interceptAnonymousUser(() => - // activeWorkspaceID ? Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(activeWorkspaceID)) : Navigation.navigate(ROUTES.ALL_SETTINGS), - // ) + onPress={() => + interceptAnonymousUser(() => + activeWorkspaceID ? Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(activeWorkspaceID)) : Navigation.navigate(ROUTES.ALL_SETTINGS), + ) } role={CONST.ROLE.BUTTON} accessibilityLabel={translate('common.settings')} @@ -116,6 +132,7 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps + ); } diff --git a/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts index f4316009b70b..94945fc2aa54 100755 --- a/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts @@ -15,6 +15,7 @@ const TAB_TO_CENTRAL_PANE_MAPPING: Record = { SCREENS.WORKSPACE.MEMBERS, SCREENS.WORKSPACE.CATEGORIES, ], + [SCREENS.TRAVEL.HOME]: [SCREENS.TRAVEL.MY_TRIPS], }; const generateCentralPaneToTabMapping = (): Record => { diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 3515f17f3867..babe4862bfeb 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -34,6 +34,7 @@ const config: LinkingOptions['config'] = { path: ROUTES.WORKSPACE_INITIAL.route, exact: true, }, + [SCREENS.TRAVEL.HOME]: ROUTES.TRAVEL_HOME, }, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 03d6bbeb5cca..daaf867f16c2 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -514,6 +514,7 @@ type BottomTabNavigatorParamList = { [SCREENS.HOME]: undefined; [SCREENS.ALL_SETTINGS]: undefined; [SCREENS.WORKSPACE.INITIAL]: undefined; + [SCREENS.TRAVEL.HOME]: undefined; }; type PublicScreensParamList = { diff --git a/src/pages/Travel/TravelMenu.tsx b/src/pages/Travel/TravelMenu.tsx new file mode 100644 index 000000000000..19a5a61991b4 --- /dev/null +++ b/src/pages/Travel/TravelMenu.tsx @@ -0,0 +1,86 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React, {useMemo} from 'react'; +import {ScrollView} from 'react-native'; +import Breadcrumbs from '@components/Breadcrumbs'; +import * as Expensicons from '@components/Icon/Expensicons'; +import MenuItemList from '@components/MenuItemList'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import useWaitForNavigation from '@hooks/useWaitForNavigation'; +import useWindowDimensions from '@hooks/useWindowDimensions'; +import Navigation from '@libs/Navigation/Navigation'; +import type {BottomTabNavigatorParamList} from '@navigation/types'; +import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; + +type TravelMenuProps = StackScreenProps; + +function TravelMenu({route}: TravelMenuProps) { + const styles = useThemeStyles(); + const waitForNavigate = useWaitForNavigation(); + const {translate} = useLocalize(); + const {isSmallScreenWidth} = useWindowDimensions(); + + /** + * Retuns a list of menu items data for Travel menu + * @returns {Object} object with translationKey, style and items + */ + const menuItems = useMemo(() => { + const baseMenuItems = [ + { + translationKey: 'travel.myTrips', + icon: Expensicons.Luggage, + action: () => { + waitForNavigate(() => { + Navigation.navigate(ROUTES.TRAVEL_MY_TRIPS); + })(); + }, + focused: !isSmallScreenWidth, + }, + ]; + return baseMenuItems.map((item) => ({ + key: item.translationKey, + title: translate(item.translationKey as TranslationPaths), + icon: item.icon, + onPress: item.action, + wrapperStyle: styles.sectionMenuItem, + isPaneMenu: true, + focused: item.focused, + hoverAndPressStyle: styles.hoveredComponentBG, + })); + }, [isSmallScreenWidth, styles.hoveredComponentBG, styles.sectionMenuItem, translate, waitForNavigate]); + + return ( + + + + + + + ); +} + +TravelMenu.displayName = 'TravelMenu'; + +export default TravelMenu; From 0bf79160068973dad3dd71df6098e8eb364275da Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 5 Mar 2024 12:38:43 +0100 Subject: [PATCH 004/703] Add suitcase icon to Expensicons --- assets/images/suitcase.svg | 3 +++ src/components/Icon/Expensicons.ts | 2 ++ .../createCustomBottomTabNavigator/BottomTabBar.tsx | 2 +- src/pages/Travel/TravelMenu.tsx | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 assets/images/suitcase.svg diff --git a/assets/images/suitcase.svg b/assets/images/suitcase.svg new file mode 100644 index 000000000000..97036db6b5ac --- /dev/null +++ b/assets/images/suitcase.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index 6c6c1b86eee1..4eaeff4b15ac 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -134,6 +134,7 @@ import Podcast from '@assets/images/social-podcast.svg'; import Twitter from '@assets/images/social-twitter.svg'; import Youtube from '@assets/images/social-youtube.svg'; import Stopwatch from '@assets/images/stopwatch.svg'; +import Suitcase from '@assets/images/suitcase.svg'; import Sync from '@assets/images/sync.svg'; import Task from '@assets/images/task.svg'; import ThreeDots from '@assets/images/three-dots.svg'; @@ -280,6 +281,7 @@ export { Send, Shield, Stopwatch, + Suitcase, Sync, Task, ThumbsUp, diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 6e2595c515eb..f3911f84ce05 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -101,7 +101,7 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps > { waitForNavigate(() => { Navigation.navigate(ROUTES.TRAVEL_MY_TRIPS); From d2cd60cd1921bb5851a6158499e5054d13583dee Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 5 Mar 2024 13:44:07 +0100 Subject: [PATCH 005/703] Add simple illustrations for MyTripsPage --- .../simple-illustration__alert.svg | 15 ++++++ .../simple-illustration__piggybank.svg | 50 +++++++++++++++++++ src/components/Icon/Illustrations.ts | 4 ++ src/pages/Travel/ManageTrips.tsx | 7 +-- src/pages/Travel/MyTripsPage.tsx | 7 ++- 5 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 assets/images/simple-illustrations/simple-illustration__alert.svg create mode 100644 assets/images/simple-illustrations/simple-illustration__piggybank.svg diff --git a/assets/images/simple-illustrations/simple-illustration__alert.svg b/assets/images/simple-illustrations/simple-illustration__alert.svg new file mode 100644 index 000000000000..55429cf39b8f --- /dev/null +++ b/assets/images/simple-illustrations/simple-illustration__alert.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/assets/images/simple-illustrations/simple-illustration__piggybank.svg b/assets/images/simple-illustrations/simple-illustration__piggybank.svg new file mode 100644 index 000000000000..c89eb3b342ef --- /dev/null +++ b/assets/images/simple-illustrations/simple-illustration__piggybank.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts index f8c048ebc4c0..728400f95bb3 100644 --- a/src/components/Icon/Illustrations.ts +++ b/src/components/Icon/Illustrations.ts @@ -29,6 +29,7 @@ import TadaYellow from '@assets/images/product-illustrations/tada--yellow.svg'; import TeleScope from '@assets/images/product-illustrations/telescope.svg'; import ThreeLeggedLaptopWoman from '@assets/images/product-illustrations/three_legged_laptop_woman.svg'; import ToddBehindCloud from '@assets/images/product-illustrations/todd-behind-cloud.svg'; +import Alert from '@assets/images/simple-illustrations/simple-illustration__alert.svg'; import Approval from '@assets/images/simple-illustrations/simple-illustration__approval.svg'; import BankArrow from '@assets/images/simple-illustrations/simple-illustration__bank-arrow.svg'; import BigRocket from '@assets/images/simple-illustrations/simple-illustration__bigrocket.svg'; @@ -58,6 +59,7 @@ import MoneyIntoWallet from '@assets/images/simple-illustrations/simple-illustra import MoneyWings from '@assets/images/simple-illustrations/simple-illustration__moneywings.svg'; import OpenSafe from '@assets/images/simple-illustrations/simple-illustration__opensafe.svg'; import PalmTree from '@assets/images/simple-illustrations/simple-illustration__palmtree.svg'; +import PiggyBank from '@assets/images/simple-illustrations/simple-illustration__piggybank.svg'; import Profile from '@assets/images/simple-illustrations/simple-illustration__profile.svg'; import QRCode from '@assets/images/simple-illustrations/simple-illustration__qr-code.svg'; import ReceiptEnvelope from '@assets/images/simple-illustrations/simple-illustration__receipt-envelope.svg'; @@ -146,4 +148,6 @@ export { Workflows, ThreeLeggedLaptopWoman, House, + PiggyBank, + Alert, }; diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index 3cd09c8e98d2..fd608374b4f4 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -7,15 +7,15 @@ import LottieAnimations from '@components/LottieAnimations'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import App from '@src/App'; +import colors from '@styles/theme/colors'; const tripsFeatures: FeatureListItem[] = [ { - icon: Illustrations.MoneyReceipts, + icon: Illustrations.PiggyBank, translationKey: 'travel.features.saveMoney', }, { - icon: Illustrations.CreditCardsNew, + icon: Illustrations.Alert, translationKey: 'travel.features.alerts', }, ]; @@ -36,6 +36,7 @@ function ManageTrips() { ctaAccessibilityLabel={translate('travel.bookOrManage')} onCtaPress={() => console.log('pressed')} illustration={LottieAnimations.SaveTheWorld} + illustrationBackgroundColor={colors.blue600} /> diff --git a/src/pages/Travel/MyTripsPage.tsx b/src/pages/Travel/MyTripsPage.tsx index ae9e604cc177..a89a0d2a60da 100644 --- a/src/pages/Travel/MyTripsPage.tsx +++ b/src/pages/Travel/MyTripsPage.tsx @@ -4,6 +4,7 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Illustrations from '@components/Icon/Illustrations'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; +import useWindowDimensions from '@hooks/useWindowDimensions'; import Navigation from '@libs/Navigation/Navigation'; import type {CentralPaneNavigatorParamList} from '@navigation/types'; import type SCREENS from '@src/SCREENS'; @@ -13,6 +14,8 @@ type MyTripsPageProps = StackScreenProps Navigation.goBack()} /> From a467a7403fe662f23e9e31db16b6e50e88907a61 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 5 Mar 2024 14:53:47 +0100 Subject: [PATCH 006/703] Remove TravelMenuProps --- src/pages/Travel/TravelMenu.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/pages/Travel/TravelMenu.tsx b/src/pages/Travel/TravelMenu.tsx index 5c0830549f56..7edb2d37da24 100644 --- a/src/pages/Travel/TravelMenu.tsx +++ b/src/pages/Travel/TravelMenu.tsx @@ -1,4 +1,3 @@ -import type {StackScreenProps} from '@react-navigation/stack'; import React, {useMemo} from 'react'; import {ScrollView} from 'react-native'; import Breadcrumbs from '@components/Breadcrumbs'; @@ -10,15 +9,13 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import useWindowDimensions from '@hooks/useWindowDimensions'; import Navigation from '@libs/Navigation/Navigation'; -import type {BottomTabNavigatorParamList} from '@navigation/types'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ROUTES from '@src/ROUTES'; -import type SCREENS from '@src/SCREENS'; -type TravelMenuProps = StackScreenProps; +// type TravelMenuProps = StackScreenProps; -function TravelMenu({route}: TravelMenuProps) { +function TravelMenu() { const styles = useThemeStyles(); const waitForNavigate = useWaitForNavigation(); const {translate} = useLocalize(); From 4cb11200f50d5fc35664b6b3824d170f31cfa86e Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 5 Mar 2024 15:45:08 +0100 Subject: [PATCH 007/703] Add fixes to travel page --- src/languages/en.ts | 3 --- .../createCustomBottomTabNavigator/BottomTabBar.tsx | 2 +- src/pages/Travel/TravelMenu.tsx | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 34314e1e65d8..2b483de57c93 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2437,7 +2437,4 @@ export default { offline: "You appear to be offline. Unfortunately, Expensify Classic doesn't work offline, but New Expensify does. If you prefer to use Expensify Classic, try again when you have an internet connection.", }, - travel: { - myTrips: 'My trips', - }, } satisfies TranslationBase; diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index f3911f84ce05..5eaf56eb7edd 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -93,7 +93,7 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps Navigation.navigate(ROUTES.TRAVEL_MY_TRIPS)} + onPress={() => Navigation.navigate(ROUTES.TRAVEL_HOME)} role={CONST.ROLE.BUTTON} accessibilityLabel={translate('workspace.common.travel')} wrapperStyle={styles.flexGrow1} diff --git a/src/pages/Travel/TravelMenu.tsx b/src/pages/Travel/TravelMenu.tsx index 7edb2d37da24..12fca5d0c587 100644 --- a/src/pages/Travel/TravelMenu.tsx +++ b/src/pages/Travel/TravelMenu.tsx @@ -28,7 +28,7 @@ function TravelMenu() { const menuItems = useMemo(() => { const baseMenuItems = [ { - translationKey: 'travel.myTrips', + translationKey: 'travel.header', icon: Expensicons.Suitcase, action: () => { waitForNavigate(() => { From ec06f1646d3de6329f2ff5fb43b0652c48a7d6f1 Mon Sep 17 00:00:00 2001 From: smelaa Date: Wed, 6 Mar 2024 10:32:34 +0100 Subject: [PATCH 008/703] Add main illustration --- assets/animations/Plane.lottie | Bin 0 -> 26027 bytes src/components/LottieAnimations/index.tsx | 5 +++++ src/pages/Travel/ManageTrips.tsx | 3 ++- src/styles/index.ts | 5 +++++ 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 assets/animations/Plane.lottie diff --git a/assets/animations/Plane.lottie b/assets/animations/Plane.lottie new file mode 100644 index 0000000000000000000000000000000000000000..77a7c0f5dfa8a734b8e0b6c7cb021088ecf3674c GIT binary patch literal 26027 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 literal 0 HcmV?d00001 diff --git a/src/components/LottieAnimations/index.tsx b/src/components/LottieAnimations/index.tsx index 18cb9188d60c..598819e19361 100644 --- a/src/components/LottieAnimations/index.tsx +++ b/src/components/LottieAnimations/index.tsx @@ -67,6 +67,11 @@ const DotLottieAnimations = { w: 200, h: 120, }, + Plane: { + file: require('@assets/animations/Plane.lottie'), + w: 180, + h: 200, + }, } satisfies Record; export default DotLottieAnimations; diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index fd608374b4f4..30c2f1151492 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -35,7 +35,8 @@ function ManageTrips() { ctaText={translate('travel.bookOrManage')} ctaAccessibilityLabel={translate('travel.bookOrManage')} onCtaPress={() => console.log('pressed')} - illustration={LottieAnimations.SaveTheWorld} + illustration={LottieAnimations.Plane} + illustrationStyle={styles.travelIllustrationStyle} illustrationBackgroundColor={colors.blue600} /> diff --git a/src/styles/index.ts b/src/styles/index.ts index 405a05cfce78..d16e769f95b8 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1769,6 +1769,11 @@ const styles = (theme: ThemeColors) => marginBottom: -20, }, + travelIllustrationStyle: { + marginTop: 20, + marginBottom: -20, + }, + overlayStyles: (current: OverlayStylesParams, isModalOnTheLeft: boolean) => ({ ...positioning.pFixed, From bb77b15c4833a6185d0b0c279ef45402b4360f66 Mon Sep 17 00:00:00 2001 From: smelaa Date: Thu, 7 Mar 2024 14:04:36 +0100 Subject: [PATCH 009/703] Add beta visibility --- src/CONST.ts | 1 + src/libs/Permissions.ts | 5 +++++ src/pages/Travel/MyTripsPage.tsx | 21 +++++++++++++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 9ed2903941b6..fa33b2578a54 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -309,6 +309,7 @@ const CONST = { VIOLATIONS: 'violations', REPORT_FIELDS: 'reportFields', WORKFLOWS_DELAYED_SUBMISSION: 'workflowsDelayedSubmission', + SPOTNANA_TRAVEL: 'spotnanaTravel', }, BUTTON_STATES: { DEFAULT: 'default', diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index c9f386f5bd7a..b3d7c302234d 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -30,6 +30,10 @@ function canUseWorkflowsDelayedSubmission(betas: OnyxEntry): boolean { return !!betas?.includes(CONST.BETAS.WORKFLOWS_DELAYED_SUBMISSION) || canUseAllBetas(betas); } +function canSeeTravelPage(betas: OnyxEntry): boolean { + return !!betas?.includes(CONST.BETAS.SPOTNANA_TRAVEL) || canUseAllBetas(betas); +} + /** * Link previews are temporarily disabled. */ @@ -45,4 +49,5 @@ export default { canUseViolations, canUseReportFields, canUseWorkflowsDelayedSubmission, + canSeeTravelPage, }; diff --git a/src/pages/Travel/MyTripsPage.tsx b/src/pages/Travel/MyTripsPage.tsx index a89a0d2a60da..e82a73dd5247 100644 --- a/src/pages/Travel/MyTripsPage.tsx +++ b/src/pages/Travel/MyTripsPage.tsx @@ -1,20 +1,29 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; +import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Illustrations from '@components/Icon/Illustrations'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useWindowDimensions from '@hooks/useWindowDimensions'; import Navigation from '@libs/Navigation/Navigation'; +import Permissions from '@libs/Permissions'; import type {CentralPaneNavigatorParamList} from '@navigation/types'; +import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; +import type {Beta} from '@src/types/onyx'; import ManageTrips from './ManageTrips'; -type MyTripsPageProps = StackScreenProps; +type MyTripsPageOnyxProps = {betas: OnyxEntry}; -function MyTripsPage({route}: MyTripsPageProps) { +type MyTripsPageProps = StackScreenProps & MyTripsPageOnyxProps; + +function MyTripsPage({betas}: MyTripsPageProps) { const {translate} = useLocalize(); const {isSmallScreenWidth} = useWindowDimensions(); + const canSeeTravelPage = Permissions.canSeeTravelPage(betas); return ( Navigation.goBack()} /> - + {canSeeTravelPage ? : } ); } MyTripsPage.displayName = 'MyTripsPage'; -export default MyTripsPage; +export default withOnyx({ + betas: { + key: ONYXKEYS.BETAS, + }, +})(MyTripsPage); From ff03721e9dfba525fa5f4329a97579372cac3d10 Mon Sep 17 00:00:00 2001 From: smelaa Date: Thu, 7 Mar 2024 14:10:54 +0100 Subject: [PATCH 010/703] Wrap ManageTrips in FullPageNotFoundView --- src/pages/Travel/MyTripsPage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/Travel/MyTripsPage.tsx b/src/pages/Travel/MyTripsPage.tsx index e82a73dd5247..ddef2f303318 100644 --- a/src/pages/Travel/MyTripsPage.tsx +++ b/src/pages/Travel/MyTripsPage.tsx @@ -39,7 +39,9 @@ function MyTripsPage({betas}: MyTripsPageProps) { shouldShowBackButton={isSmallScreenWidth} onBackButtonPress={() => Navigation.goBack()} /> - {canSeeTravelPage ? : } + + + ); } From 7c30e70bc77b637bfc3a59fba430ebc839875aee Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 8 Mar 2024 13:03:36 +0100 Subject: [PATCH 011/703] Refactor MyTripsPage --- src/ROUTES.ts | 2 - src/SCREENS.ts | 2 +- src/languages/en.ts | 1 + src/languages/es.ts | 4 +- .../AppNavigator/ModalStackNavigators.tsx | 6 ++ .../Navigators/BottomTabNavigator.tsx | 6 -- .../BaseCentralPaneNavigator.tsx | 5 -- .../Navigators/RightModalNavigator.tsx | 4 + .../BottomTabBar.tsx | 24 +----- .../TAB_TO_CENTRAL_PANE_MAPPING.ts | 1 - src/libs/Navigation/linkingConfig/config.ts | 9 +- src/libs/Navigation/types.ts | 8 +- src/libs/Permissions.ts | 4 +- src/pages/Travel/ManageTrips.tsx | 2 +- src/pages/Travel/MyTripsPage.tsx | 42 +++------- src/pages/Travel/TravelMenu.tsx | 83 ------------------- .../FloatingActionButtonAndPopover.js | 12 +++ 17 files changed, 56 insertions(+), 159 deletions(-) delete mode 100644 src/pages/Travel/TravelMenu.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 4496d102d037..f7c455e923a6 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -555,8 +555,6 @@ const ROUTES = { PROCESS_MONEY_REQUEST_HOLD: 'hold-request-educational', TRAVEL_MY_TRIPS: 'travel', - - TRAVEL_HOME: 'travel-home', } as const; /** diff --git a/src/SCREENS.ts b/src/SCREENS.ts index b08f8efabf45..b30ee4d45ec3 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -23,7 +23,6 @@ const SCREENS = { UNLINK_LOGIN: 'UnlinkLogin', SETTINGS_CENTRAL_PANE: 'SettingsCentralPane', TRAVEL: { - HOME: 'Travel_Home', MY_TRIPS: 'Travel_MyTrips', }, SETTINGS: { @@ -127,6 +126,7 @@ const SCREENS = { ROOM_INVITE: 'RoomInvite', REFERRAL: 'Referral', PROCESS_MONEY_REQUEST_HOLD: 'ProcessMoneyRequestHold', + TRAVEL: 'Travel', }, SIGN_IN_WITH_APPLE_DESKTOP: 'AppleSignInDesktop', SIGN_IN_WITH_GOOGLE_DESKTOP: 'GoogleSignInDesktop', diff --git a/src/languages/en.ts b/src/languages/en.ts index 2b483de57c93..65a3be6a2cfb 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1726,6 +1726,7 @@ export default { saveMoney: 'Save money on your bookings', alerts: 'Get real time alerts if your travel plans change', }, + bookTravel: 'Book Travel', }, workspace: { common: { diff --git a/src/languages/es.ts b/src/languages/es.ts index ca6cc81e8705..35707cf7424e 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1750,6 +1750,7 @@ export default { saveMoney: 'Ahorra dinero en tus reservas', alerts: 'Recibe alertas en tiempo real si cambian tus planes de viaje', }, + bookTravel: 'Reservar viajes', }, workspace: { common: { @@ -2929,7 +2930,4 @@ export default { offline: 'Parece que estás desconectado. Desafortunadamente, Expensify Classic no funciona sin conexión, pero New Expensify sí. Si prefieres utilizar Expensify Classic, inténtalo de nuevo cuando tengas conexión a internet.', }, - travel: { - myTrips: 'Mis viajes', - }, } satisfies EnglishTranslation; diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index 545641957c9a..ed3e34e76c1c 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -29,6 +29,7 @@ import type { SplitDetailsNavigatorParamList, TaskDetailsNavigatorParamList, TeachersUniteNavigatorParamList, + TravelNavigatorParamList, WalletStatementNavigatorParamList, WorkspaceSwitcherNavigatorParamList, } from '@navigation/types'; @@ -108,6 +109,10 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator require('../../../pages/EditRequestReceiptPage').default as React.ComponentType, }); +const TravelModalStackNavigator = createModalStackNavigator({ + [SCREENS.TRAVEL.MY_TRIPS]: () => require('../../../pages/Travel/MyTripsPage').default as React.ComponentType, +}); + const SplitDetailsModalStackNavigator = createModalStackNavigator({ [SCREENS.SPLIT_DETAILS.ROOT]: () => require('../../../pages/iou/SplitBillDetailsPage').default as React.ComponentType, [SCREENS.SPLIT_DETAILS.EDIT_REQUEST]: () => require('../../../pages/EditSplitBillPage').default as React.ComponentType, @@ -336,4 +341,5 @@ export { TaskModalStackNavigator, WalletStatementStackNavigator, ProcessMoneyRequestHoldStackNavigator, + TravelModalStackNavigator, }; diff --git a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx index 9ce1b8425f51..ce03a8d5bcba 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx @@ -11,8 +11,6 @@ import ActiveRouteContext from './ActiveRouteContext'; const loadWorkspaceInitialPage = () => require('../../../../pages/workspace/WorkspaceInitialPage').default as React.ComponentType; -const loadTravelMenuPage = () => require('../../../../pages/Travel/TravelMenu').default as React.ComponentType; - const Tab = createCustomBottomTabNavigator(); const screenOptions: StackNavigationOptions = { @@ -37,10 +35,6 @@ function BottomTabNavigator() { name={SCREENS.WORKSPACE.INITIAL} getComponent={loadWorkspaceInitialPage} /> - ); diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx index ab20497a3c73..5f3d522f6b41 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator/BaseCentralPaneNavigator.tsx @@ -4,7 +4,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import ReportScreenWrapper from '@libs/Navigation/AppNavigator/ReportScreenWrapper'; import getCurrentUrl from '@libs/Navigation/currentUrl'; import type {CentralPaneNavigatorParamList} from '@navigation/types'; -import MyTripsPage from '@pages/Travel/MyTripsPage'; import SCREENS from '@src/SCREENS'; const Stack = createStackNavigator(); @@ -44,10 +43,6 @@ function BaseCentralPaneNavigator() { initialParams={{openOnAdminRoom: openOnAdminRoom === 'true' || undefined}} component={ReportScreenWrapper} /> - {Object.entries(workspaceSettingsScreens).map(([screenName, componentGetter]) => ( + diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 5eaf56eb7edd..58d9efb43df5 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -11,6 +11,7 @@ import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as Session from '@libs/actions/Session'; import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute'; import Navigation from '@libs/Navigation/Navigation'; @@ -47,7 +48,8 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps // When we are redirected to the Settings tab from the OldDot, we don't want to call the Welcome.show() method. // To prevent this, the value of the bottomTabRoute?.name is checked here bottomTabRoute?.name === SCREENS.WORKSPACE.INITIAL || - (currentRoute && currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && currentRoute.name !== NAVIGATORS.CENTRAL_PANE_NAVIGATOR) + Boolean(currentRoute && currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && currentRoute.name !== NAVIGATORS.CENTRAL_PANE_NAVIGATOR) || + Session.isAnonymousUser() ) { return; } @@ -91,24 +93,7 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps - - Navigation.navigate(ROUTES.TRAVEL_HOME)} - role={CONST.ROLE.BUTTON} - accessibilityLabel={translate('workspace.common.travel')} - wrapperStyle={styles.flexGrow1} - style={styles.bottomTabBarItem} - > - - - - - + @@ -132,7 +117,6 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps - ); } diff --git a/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts b/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts index 94945fc2aa54..f4316009b70b 100755 --- a/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/TAB_TO_CENTRAL_PANE_MAPPING.ts @@ -15,7 +15,6 @@ const TAB_TO_CENTRAL_PANE_MAPPING: Record = { SCREENS.WORKSPACE.MEMBERS, SCREENS.WORKSPACE.CATEGORIES, ], - [SCREENS.TRAVEL.HOME]: [SCREENS.TRAVEL.MY_TRIPS], }; const generateCentralPaneToTabMapping = (): Record => { diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index babe4862bfeb..c7a259513885 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -34,14 +34,12 @@ const config: LinkingOptions['config'] = { path: ROUTES.WORKSPACE_INITIAL.route, exact: true, }, - [SCREENS.TRAVEL.HOME]: ROUTES.TRAVEL_HOME, }, }, [NAVIGATORS.CENTRAL_PANE_NAVIGATOR]: { screens: { [SCREENS.REPORT]: ROUTES.REPORT_WITH_ID.route, - [SCREENS.SETTINGS.WORKSPACES]: ROUTES.SETTINGS_WORKSPACES, [SCREENS.WORKSPACE.PROFILE]: ROUTES.WORKSPACE_PROFILE.route, [SCREENS.WORKSPACE.CARD]: { @@ -68,8 +66,6 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.CATEGORIES]: { path: ROUTES.WORKSPACE_CATEGORIES.route, }, - - [SCREENS.TRAVEL.MY_TRIPS]: ROUTES.TRAVEL_MY_TRIPS, }, }, [SCREENS.NOT_FOUND]: '*', @@ -529,6 +525,11 @@ const config: LinkingOptions['config'] = { [SCREENS.PROCESS_MONEY_REQUEST_HOLD_ROOT]: ROUTES.PROCESS_MONEY_REQUEST_HOLD, }, }, + [SCREENS.RIGHT_MODAL.TRAVEL]: { + screens: { + [SCREENS.TRAVEL.MY_TRIPS]: ROUTES.TRAVEL_MY_TRIPS, + }, + }, }, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index daaf867f16c2..8b89ee7b9ea2 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -90,7 +90,6 @@ type CentralPaneNavigatorParamList = { [SCREENS.WORKSPACE.CATEGORIES]: { policyID: string; }; - [SCREENS.TRAVEL.MY_TRIPS]: undefined; }; type WorkspaceSwitcherNavigatorParamList = { @@ -495,6 +494,11 @@ type RightModalNavigatorParamList = { [SCREENS.RIGHT_MODAL.PROCESS_MONEY_REQUEST_HOLD]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.REFERRAL]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.PRIVATE_NOTES]: NavigatorScreenParams; + [SCREENS.RIGHT_MODAL.TRAVEL]: NavigatorScreenParams; +}; + +type TravelNavigatorParamList = { + [SCREENS.TRAVEL.MY_TRIPS]: undefined; }; type SettingsCentralPaneNavigatorParamList = { @@ -514,7 +518,6 @@ type BottomTabNavigatorParamList = { [SCREENS.HOME]: undefined; [SCREENS.ALL_SETTINGS]: undefined; [SCREENS.WORKSPACE.INITIAL]: undefined; - [SCREENS.TRAVEL.HOME]: undefined; }; type PublicScreensParamList = { @@ -635,4 +638,5 @@ export type { WorkspaceSwitcherNavigatorParamList, OnboardEngagementNavigatorParamList, SwitchPolicyIDParams, + TravelNavigatorParamList, }; diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index b3d7c302234d..beafd92024bd 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -30,7 +30,7 @@ function canUseWorkflowsDelayedSubmission(betas: OnyxEntry): boolean { return !!betas?.includes(CONST.BETAS.WORKFLOWS_DELAYED_SUBMISSION) || canUseAllBetas(betas); } -function canSeeTravelPage(betas: OnyxEntry): boolean { +function canUseSpotnanaTravel(betas: OnyxEntry): boolean { return !!betas?.includes(CONST.BETAS.SPOTNANA_TRAVEL) || canUseAllBetas(betas); } @@ -49,5 +49,5 @@ export default { canUseViolations, canUseReportFields, canUseWorkflowsDelayedSubmission, - canSeeTravelPage, + canUseSpotnanaTravel, }; diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index 30c2f1151492..817fb430c054 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -34,7 +34,7 @@ function ManageTrips() { subtitle={translate('travel.subtitle')} ctaText={translate('travel.bookOrManage')} ctaAccessibilityLabel={translate('travel.bookOrManage')} - onCtaPress={() => console.log('pressed')} + onCtaPress={() => {}} illustration={LottieAnimations.Plane} illustrationStyle={styles.travelIllustrationStyle} illustrationBackgroundColor={colors.blue600} diff --git a/src/pages/Travel/MyTripsPage.tsx b/src/pages/Travel/MyTripsPage.tsx index ddef2f303318..003775d1a10c 100644 --- a/src/pages/Travel/MyTripsPage.tsx +++ b/src/pages/Travel/MyTripsPage.tsx @@ -1,29 +1,15 @@ -import type {StackScreenProps} from '@react-navigation/stack'; import React from 'react'; -import {withOnyx} from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Illustrations from '@components/Icon/Illustrations'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; -import useWindowDimensions from '@hooks/useWindowDimensions'; -import Navigation from '@libs/Navigation/Navigation'; -import Permissions from '@libs/Permissions'; -import type {CentralPaneNavigatorParamList} from '@navigation/types'; -import ONYXKEYS from '@src/ONYXKEYS'; -import type SCREENS from '@src/SCREENS'; -import type {Beta} from '@src/types/onyx'; +import usePermissions from '@hooks/usePermissions'; import ManageTrips from './ManageTrips'; -type MyTripsPageOnyxProps = {betas: OnyxEntry}; - -type MyTripsPageProps = StackScreenProps & MyTripsPageOnyxProps; - -function MyTripsPage({betas}: MyTripsPageProps) { +function MyTripsPage() { const {translate} = useLocalize(); - const {isSmallScreenWidth} = useWindowDimensions(); - const canSeeTravelPage = Permissions.canSeeTravelPage(betas); + const {canUseSpotnanaTravel} = usePermissions(); return ( - Navigation.goBack()} - /> - + + @@ -48,8 +36,4 @@ function MyTripsPage({betas}: MyTripsPageProps) { MyTripsPage.displayName = 'MyTripsPage'; -export default withOnyx({ - betas: { - key: ONYXKEYS.BETAS, - }, -})(MyTripsPage); +export default MyTripsPage; diff --git a/src/pages/Travel/TravelMenu.tsx b/src/pages/Travel/TravelMenu.tsx deleted file mode 100644 index 12fca5d0c587..000000000000 --- a/src/pages/Travel/TravelMenu.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React, {useMemo} from 'react'; -import {ScrollView} from 'react-native'; -import Breadcrumbs from '@components/Breadcrumbs'; -import * as Expensicons from '@components/Icon/Expensicons'; -import MenuItemList from '@components/MenuItemList'; -import ScreenWrapper from '@components/ScreenWrapper'; -import useLocalize from '@hooks/useLocalize'; -import useThemeStyles from '@hooks/useThemeStyles'; -import useWaitForNavigation from '@hooks/useWaitForNavigation'; -import useWindowDimensions from '@hooks/useWindowDimensions'; -import Navigation from '@libs/Navigation/Navigation'; -import CONST from '@src/CONST'; -import type {TranslationPaths} from '@src/languages/types'; -import ROUTES from '@src/ROUTES'; - -// type TravelMenuProps = StackScreenProps; - -function TravelMenu() { - const styles = useThemeStyles(); - const waitForNavigate = useWaitForNavigation(); - const {translate} = useLocalize(); - const {isSmallScreenWidth} = useWindowDimensions(); - - /** - * Retuns a list of menu items data for Travel menu - * @returns {Object} object with translationKey, style and items - */ - const menuItems = useMemo(() => { - const baseMenuItems = [ - { - translationKey: 'travel.header', - icon: Expensicons.Suitcase, - action: () => { - waitForNavigate(() => { - Navigation.navigate(ROUTES.TRAVEL_MY_TRIPS); - })(); - }, - focused: !isSmallScreenWidth, - }, - ]; - return baseMenuItems.map((item) => ({ - key: item.translationKey, - title: translate(item.translationKey as TranslationPaths), - icon: item.icon, - onPress: item.action, - wrapperStyle: styles.sectionMenuItem, - isPaneMenu: true, - focused: item.focused, - hoverAndPressStyle: styles.hoveredComponentBG, - })); - }, [isSmallScreenWidth, styles.hoveredComponentBG, styles.sectionMenuItem, translate, waitForNavigate]); - - return ( - - - - - - - ); -} - -TravelMenu.displayName = 'TravelMenu'; - -export default TravelMenu; diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 573cbe370aa7..090e8384c615 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -9,6 +9,7 @@ import withNavigation from '@components/withNavigation'; import withNavigationFocus from '@components/withNavigationFocus'; import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; @@ -78,6 +79,8 @@ function FloatingActionButtonAndPopover(props) { const prevIsFocused = usePrevious(props.isFocused); + const {canUseSpotnanaTravel} = usePermissions(); + /** * Check if LHN status changed from active to inactive. * Used to close already opened FAB menu when open any other pages (i.e. Press Command + K on web). @@ -191,6 +194,15 @@ function FloatingActionButtonAndPopover(props) { text: translate('sidebarScreen.saveTheWorld'), onSelected: () => interceptAnonymousUser(() => Navigation.navigate(ROUTES.TEACHERS_UNITE)), }, + ...(canUseSpotnanaTravel + ? [ + { + icon: Expensicons.Suitcase, + text: translate('travel.bookTravel'), + onSelected: () => interceptAnonymousUser(() => Navigation.navigate(ROUTES.TRAVEL_MY_TRIPS)), + }, + ] + : []), ...(!props.isLoading && !Policy.hasActiveFreePolicy(props.allPolicies) ? [ { From 42b22e0383afdfa5221f116b197eb2877834c085 Mon Sep 17 00:00:00 2001 From: smelaa Date: Wed, 13 Mar 2024 10:52:07 +0100 Subject: [PATCH 012/703] Initial config to workspace address page --- src/ROUTES.ts | 4 +++ src/SCREENS.ts | 1 + src/languages/en.ts | 1 + src/languages/es.ts | 1 + .../AppNavigator/ModalStackNavigators.tsx | 1 + .../CENTRAL_PANE_TO_RHP_MAPPING.ts | 2 +- src/libs/Navigation/linkingConfig/config.ts | 3 ++ src/libs/Navigation/types.ts | 1 + .../workspace/WorkspaceProfileAddressPage.tsx | 32 +++++++++++++++++++ src/pages/workspace/WorkspaceProfilePage.tsx | 17 ++++++++++ 10 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/pages/workspace/WorkspaceProfileAddressPage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index d9f0c6658a2b..2b27179db7a0 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -465,6 +465,10 @@ const ROUTES = { route: 'workspace/:policyID/profile', getRoute: (policyID: string) => `workspace/${policyID}/profile` as const, }, + WORKSPACE_PROFILE_ADDRESS: { + route: 'workspace/:policyID/profile/address', + getRoute: (policyID: string) => `workspace/${policyID}/profile/address` as const, + }, WORKSPACE_PROFILE_CURRENCY: { route: 'workspace/:policyID/profile/currency', getRoute: (policyID: string) => `workspace/${policyID}/profile/currency` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index a0e06b98da2b..b5c0040dd9f7 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -219,6 +219,7 @@ const SCREENS = { TAGS_SETTINGS: 'Tags_Settings', TAGS_EDIT: 'Tags_Edit', CURRENCY: 'Workspace_Profile_Currency', + ADDRESS: 'Workspace_Profile_Address', WORKFLOWS: 'Workspace_Workflows', WORKFLOWS_APPROVER: 'Workspace_Workflows_Approver', WORKFLOWS_AUTO_REPORTING_FREQUENCY: 'Workspace_Workflows_Auto_Reporting_Frequency', diff --git a/src/languages/en.ts b/src/languages/en.ts index ff91a4f6f205..9aeca12dd5d7 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1984,6 +1984,7 @@ export default { currencyInputLabel: 'Default currency', currencyInputHelpText: 'All expenses on this workspace will be converted to this currency.', currencyInputDisabledText: "The default currency can't be changed because this workspace is linked to a USD bank account.", + addressInputLabel: 'Company address', save: 'Save', genericFailureMessage: 'An error occurred updating the workspace, please try again.', avatarUploadFailureMessage: 'An error occurred uploading the avatar, please try again.', diff --git a/src/languages/es.ts b/src/languages/es.ts index c21f46ed8853..9580ec8df535 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2009,6 +2009,7 @@ export default { currencyInputLabel: 'Moneda por defecto', currencyInputHelpText: 'Todas los gastos en este espacio de trabajo serán convertidos a esta moneda.', currencyInputDisabledText: 'La moneda predeterminada no se puede cambiar porque este espacio de trabajo está vinculado a una cuenta bancaria en USD.', + addressInputLabel: 'Dirección de la empresa', save: 'Guardar', genericFailureMessage: 'Se produjo un error al guardar el espacio de trabajo. Por favor, inténtalo de nuevo.', avatarUploadFailureMessage: 'No se pudo subir el avatar. Por favor, inténtalo de nuevo.', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx index d56e38564149..df67de82d635 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.tsx @@ -249,6 +249,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../pages/workspace/WorkspaceProfileDescriptionPage').default as React.ComponentType, [SCREENS.WORKSPACE.SHARE]: () => require('../../../pages/workspace/WorkspaceProfileSharePage').default as React.ComponentType, [SCREENS.WORKSPACE.CURRENCY]: () => require('../../../pages/workspace/WorkspaceProfileCurrencyPage').default as React.ComponentType, + [SCREENS.WORKSPACE.ADDRESS]: () => require('../../../pages/workspace/WorkspaceProfileAddressPage').default as React.ComponentType, [SCREENS.WORKSPACE.CATEGORY_SETTINGS]: () => require('../../../pages/workspace/categories/CategorySettingsPage').default as React.ComponentType, [SCREENS.WORKSPACE.CATEGORIES_SETTINGS]: () => require('../../../pages/workspace/categories/WorkspaceCategoriesSettingsPage').default as React.ComponentType, [SCREENS.WORKSPACE.MEMBER_DETAILS]: () => require('../../../pages/workspace/members/WorkspaceMemberDetailsPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts index 743bf2e0cff1..f6fe75901848 100755 --- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts @@ -2,7 +2,7 @@ import type {CentralPaneName} from '@libs/Navigation/types'; import SCREENS from '@src/SCREENS'; const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = { - [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE], + [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.ADDRESS, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE], [SCREENS.WORKSPACE.REIMBURSE]: [SCREENS.WORKSPACE.RATE_AND_UNIT, SCREENS.WORKSPACE.RATE_AND_UNIT_RATE, SCREENS.WORKSPACE.RATE_AND_UNIT_UNIT], [SCREENS.WORKSPACE.MEMBERS]: [SCREENS.WORKSPACE.INVITE, SCREENS.WORKSPACE.INVITE_MESSAGE, SCREENS.WORKSPACE.MEMBER_DETAILS, SCREENS.WORKSPACE.MEMBER_DETAILS_ROLE_SELECTION], [SCREENS.WORKSPACE.WORKFLOWS]: [SCREENS.WORKSPACE.WORKFLOWS_APPROVER, SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_FREQUENCY, SCREENS.WORKSPACE.WORKFLOWS_AUTO_REPORTING_MONTHLY_OFFSET], diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 97d7650a9043..296ccc30ba69 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -249,6 +249,9 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.CURRENCY]: { path: ROUTES.WORKSPACE_PROFILE_CURRENCY.route, }, + [SCREENS.WORKSPACE.ADDRESS]: { + path: ROUTES.WORKSPACE_PROFILE_ADDRESS.route, + }, [SCREENS.WORKSPACE.DESCRIPTION]: { path: ROUTES.WORKSPACE_PROFILE_DESCRIPTION.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 33e79b637cc4..1443a60f4b16 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -186,6 +186,7 @@ type SettingsNavigatorParamList = { [SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE]: undefined; [SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_TIME]: undefined; [SCREENS.WORKSPACE.CURRENCY]: undefined; + [SCREENS.WORKSPACE.ADDRESS]: undefined; [SCREENS.WORKSPACE.NAME]: undefined; [SCREENS.WORKSPACE.DESCRIPTION]: undefined; [SCREENS.WORKSPACE.SHARE]: undefined; diff --git a/src/pages/workspace/WorkspaceProfileAddressPage.tsx b/src/pages/workspace/WorkspaceProfileAddressPage.tsx new file mode 100644 index 000000000000..80f9066040be --- /dev/null +++ b/src/pages/workspace/WorkspaceProfileAddressPage.tsx @@ -0,0 +1,32 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import React from 'react'; +import {Text, View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; +import ScreenWrapper from '@components/ScreenWrapper'; +import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; +import type {PrivatePersonalDetails} from '@src/types/onyx'; + +type WorkspaceProfileAddressPageOnyxProps = { + /** User's private personal details */ + privatePersonalDetails: OnyxEntry; +}; + +type WorkspaceProfileAddressPageProps = StackScreenProps & WorkspaceProfileAddressPageOnyxProps; + +function WorkspaceProfileAddressPage({privatePersonalDetails, route}: WorkspaceProfileAddressPageProps) { + return ( + + abc + + ); +} + +WorkspaceProfileAddressPage.displayName = 'WorkspaceProfileAddressPage'; + +export default WorkspaceProfileAddressPage; diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index 9d90557b1d37..154708688fb0 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -50,7 +50,10 @@ function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfi const currencySymbol = currencyList?.[outputCurrency]?.symbol ?? ''; const formattedCurrency = !isEmptyObject(policy) && !isEmptyObject(currencyList) ? `${outputCurrency} - ${currencySymbol}` : ''; + const formattedAddress = 'abc'; + const onPressCurrency = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_PROFILE_CURRENCY.getRoute(policy?.id ?? '')), [policy?.id]); + const onPressAddress = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_PROFILE_ADDRESS.getRoute(policy?.id ?? '')), [policy?.id]); const onPressName = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_PROFILE_NAME.getRoute(policy?.id ?? '')), [policy?.id]); const onPressDescription = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_PROFILE_DESCRIPTION.getRoute(policy?.id ?? '')), [policy?.id]); const onPressShare = useCallback(() => Navigation.navigate(ROUTES.WORKSPACE_PROFILE_SHARE.getRoute(policy?.id ?? '')), [policy?.id]); @@ -186,6 +189,20 @@ function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfi + + + + + {!readOnly && (