From 57e63066ecf2cb1654002ffb909ca5f8ed9edfaa Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Mon, 4 Mar 2024 12:23:17 +0100 Subject: [PATCH 01/40] 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 02/40] 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 03/40] 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 04/40] 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 05/40] 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 06/40] 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 07/40] 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 08/40] 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 09/40] 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 10/40] 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 11/40] 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 afd404c89b69ff0d5b509f1f7b10a54defe7b5a3 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:45:12 +0100 Subject: [PATCH 12/40] add base terms and conditions modal --- src/languages/en.ts | 11 ++++ src/pages/Travel/TravelTerms.tsx | 100 +++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 src/pages/Travel/TravelTerms.tsx diff --git a/src/languages/en.ts b/src/languages/en.ts index 2b483de57c93..5104feaa7b4e 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1726,6 +1726,17 @@ export default { saveMoney: 'Save money on your bookings', alerts: 'Get real time alerts if your travel plans change', }, + termsAndConditions: { + header: 'Before we continue...', + title: 'Please read the Terms & Conditions for travel', + subtitle: 'To enable travel on your workspace you must agree to our ', + termsconditions: 'terms & conditions', + helpDocIntro: 'Check out this ', + helpDocOutro: 'for more information or reach out to Concierge or your Account Manager.', + helpDoc: 'Help Doc', + agree: 'I agree to the travel ', + error: 'You must accept the Terms & Conditions for travel to continue' + } }, workspace: { common: { diff --git a/src/pages/Travel/TravelTerms.tsx b/src/pages/Travel/TravelTerms.tsx new file mode 100644 index 000000000000..ffd18031ee65 --- /dev/null +++ b/src/pages/Travel/TravelTerms.tsx @@ -0,0 +1,100 @@ +import React, { useCallback, useEffect, useState } from 'react'; +import CheckboxWithLabel from "@components/CheckboxWithLabel"; +import HeaderWithBackButton from "@components/HeaderWithBackButton"; +import ScreenWrapper from "@components/ScreenWrapper"; +import Text from "@components/Text"; +import TextLink from "@components/TextLink"; +import useLocalize from "@hooks/useLocalize"; +import useThemeStyles from "@hooks/useThemeStyles"; +import Navigation from "@libs/Navigation/Navigation"; +import { ScrollView } from "react-native-gesture-handler"; +import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; +import { View } from 'react-native'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; + +function TravelTerms() { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const [hasAcceptedTravelTerms, setHasAcceptedTravelTerms] = useState(false); + const [error, setError] = useState(false); + + const errorMessage = error ? 'travel.termsAndConditions.error' : ''; + + const toggleTravelTerms = () => { + setHasAcceptedTravelTerms(!hasAcceptedTravelTerms); + }; + + useEffect(() => { + if(!hasAcceptedTravelTerms) { + return; + } + + setError(false); + }, [hasAcceptedTravelTerms]); + + const AgreeToTheLabel = useCallback(() => ( + + {`${translate('travel.termsAndConditions.agree')}`} + {`${translate('travel.termsAndConditions.termsconditions')}`} + + ), [translate]); + + // Add beta support for FullPageNotFound that is universal across travel pages + return ( + + + Navigation.goBack()} + /> + + + {`${translate('travel.termsAndConditions.title')}`} + + {`${translate('travel.termsAndConditions.subtitle')}`} + {`${translate('travel.termsAndConditions.termsconditions')}.`} + + + {`${translate('travel.termsAndConditions.helpDocIntro')}`} + {`${translate('travel.termsAndConditions.helpDoc')} `} + {`${translate('travel.termsAndConditions.helpDocOutro')}`} + + + + + + { + if(!hasAcceptedTravelTerms) { + setError(true); + return; + } + + // API call for AcceptSpontanaTerms when backend gets implemented + setError(false); + Navigation.goBack(); + }} + message={errorMessage} + isAlertVisible={error || Boolean(errorMessage)} + containerStyles={[styles.mh0, styles.mv4]} + /> + + + + ) +} + +TravelTerms.displayName = 'TravelMenu'; + +export default TravelTerms; \ No newline at end of file From f74e2d27a62e367e1552ff43657e5aed3a212703 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Fri, 29 Mar 2024 16:42:55 +0100 Subject: [PATCH 13/40] Add es translations for TravelTerms page --- src/languages/en.ts | 5 +++-- src/languages/es.ts | 14 +++++++++++++- src/pages/Travel/TravelTerms.tsx | 4 ++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 32d9239104c7..fe425cf78889 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1732,12 +1732,13 @@ export default { title: 'Please read the Terms & Conditions for travel', subtitle: 'To enable travel on your workspace you must agree to our ', termsconditions: 'terms & conditions', + travelTermsAndConditions: 'terms & conditions', helpDocIntro: 'Check out this ', helpDocOutro: 'for more information or reach out to Concierge or your Account Manager.', helpDoc: 'Help Doc', agree: 'I agree to the travel ', - error: 'You must accept the Terms & Conditions for travel to continue' - } + error: 'You must accept the Terms & Conditions for travel to continue', + }, }, workspace: { common: { diff --git a/src/languages/es.ts b/src/languages/es.ts index 35707cf7424e..79f230088d08 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1746,11 +1746,23 @@ export default { 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', + bookTravel: 'Reservar viajes', features: { saveMoney: 'Ahorra dinero en tus reservas', alerts: 'Recibe alertas en tiempo real si cambian tus planes de viaje', }, - bookTravel: 'Reservar viajes', + termsAndConditions: { + header: 'Antes de continuar...', + title: 'Por favor lea los Términos y condiciones para viajar', + subtitle: 'Para permitir viajar en su espacio de trabajo debe aceptar nuestros ', + termsconditions: 'términos y condiciones', + travelTermsAndConditions: 'términos y condiciones de viaje', + helpDocIntro: 'Consulte este ', + helpDocOutro: 'para obtener más información o comuníquese con el conserje o su administrador de cuentas.', + helpDoc: 'documento de ayuda', + agree: 'Acepto los ', + error: 'Debes aceptar los Términos y condiciones para que el viaje continúe', + }, }, workspace: { common: { diff --git a/src/pages/Travel/TravelTerms.tsx b/src/pages/Travel/TravelTerms.tsx index ffd18031ee65..dfcf8a722888 100644 --- a/src/pages/Travel/TravelTerms.tsx +++ b/src/pages/Travel/TravelTerms.tsx @@ -35,7 +35,7 @@ function TravelTerms() { const AgreeToTheLabel = useCallback(() => ( {`${translate('travel.termsAndConditions.agree')}`} - {`${translate('travel.termsAndConditions.termsconditions')}`} + {`${translate('travel.termsAndConditions.travelTermsAndConditions')}`} ), [translate]); @@ -65,7 +65,7 @@ function TravelTerms() { From c261f00eb7075eefdcaf0f304c87348e9687b444 Mon Sep 17 00:00:00 2001 From: smelaa Date: Tue, 9 Apr 2024 17:16:00 +0200 Subject: [PATCH 14/40] Fixes after merging with main --- .../Navigation/AppNavigator/ModalStackNavigators/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index aab9ad12baf1..71fc44fa992b 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -28,6 +28,7 @@ import type { SplitDetailsNavigatorParamList, TaskDetailsNavigatorParamList, TeachersUniteNavigatorParamList, + TravelNavigatorParamList, WalletStatementNavigatorParamList, WorkspaceSwitcherNavigatorParamList, } from '@navigation/types'; @@ -97,6 +98,10 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Profile/PersonalDetails/StateSelectionPage').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, @@ -342,5 +347,6 @@ export { TaskModalStackNavigator, WalletStatementStackNavigator, ProcessMoneyRequestHoldStackNavigator, + TravelModalStackNavigator, WorkspaceSettingsModalStackNavigator, }; From 5ef17d93ae4cf7a3536a73245f1ea20177d9c318 Mon Sep 17 00:00:00 2001 From: smelaa Date: Tue, 9 Apr 2024 17:55:28 +0200 Subject: [PATCH 15/40] Fixes after matching with main --- .../Navigation/AppNavigator/ModalStackNavigators/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index aab9ad12baf1..4f5598007d64 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -28,6 +28,7 @@ import type { SplitDetailsNavigatorParamList, TaskDetailsNavigatorParamList, TeachersUniteNavigatorParamList, + TravelNavigatorParamList, WalletStatementNavigatorParamList, WorkspaceSwitcherNavigatorParamList, } from '@navigation/types'; @@ -97,6 +98,10 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Profile/PersonalDetails/StateSelectionPage').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, @@ -327,6 +332,7 @@ export { PrivateNotesModalStackNavigator, ProfileModalStackNavigator, ReferralModalStackNavigator, + TravelModalStackNavigator, WorkspaceSwitcherModalStackNavigator, ReimbursementAccountModalStackNavigator, ReportDetailsModalStackNavigator, From fa4fe368d2ea4e88614ee37c3502f83aed64158d Mon Sep 17 00:00:00 2001 From: smelaa Date: Tue, 9 Apr 2024 18:21:21 +0200 Subject: [PATCH 16/40] Fixes after merging with travel/travel-page --- src/components/Icon/Illustrations.ts | 4 ++-- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- .../Navigation/AppNavigator/ModalStackNavigators/index.tsx | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts index f12cde1083d3..44b4d08134e8 100644 --- a/src/components/Icon/Illustrations.ts +++ b/src/components/Icon/Illustrations.ts @@ -156,8 +156,6 @@ export { QRCode, ReceiptEnvelope, Approval, - PiggyBank, - Pencil, WalletAlt, Workflows, ThreeLeggedLaptopWoman, @@ -169,9 +167,11 @@ export { CompanyCard, ReceiptUpload, SplitBill, + PiggyBank, Accounting, Car, Coins, + Pencil, Tag, CarIce, }; diff --git a/src/languages/en.ts b/src/languages/en.ts index 51c4617e1c2a..c30b3a7f92b1 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1809,11 +1809,11 @@ export default { 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', - bookTravel: 'Book Travel', features: { saveMoney: 'Save money on your bookings', alerts: 'Get real time alerts if your travel plans change', }, + bookTravel: 'Book Travel', termsAndConditions: { header: 'Before we continue...', title: 'Please read the Terms & Conditions for travel', diff --git a/src/languages/es.ts b/src/languages/es.ts index c2b4334351d8..6980fad0fa10 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1836,11 +1836,11 @@ export default { 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', - bookTravel: 'Reservar viajes', features: { saveMoney: 'Ahorra dinero en tus reservas', alerts: 'Recibe alertas en tiempo real si cambian tus planes de viaje', }, + bookTravel: 'Reservar viajes', termsAndConditions: { header: 'Antes de continuar...', title: 'Por favor lea los Términos y condiciones para viajar', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 6a7bc8e870b7..4f5598007d64 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -348,6 +348,5 @@ export { TaskModalStackNavigator, WalletStatementStackNavigator, ProcessMoneyRequestHoldStackNavigator, - TravelModalStackNavigator, WorkspaceSettingsModalStackNavigator, }; From abbe116aa3e57dc383e5136a9809a9b841e4a1ee Mon Sep 17 00:00:00 2001 From: smelaa Date: Wed, 10 Apr 2024 10:22:56 +0200 Subject: [PATCH 17/40] Text changes --- src/languages/en.ts | 7 +++---- src/languages/es.ts | 5 ++--- src/pages/Travel/ManageTrips.tsx | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 1bf50c9adae8..ba3cf3213026 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1806,14 +1806,13 @@ export default { }, travel: { header: 'My trips', - title: 'Book or manage your trips', + title: 'Book and 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', + alerts: 'Get realtime updates and alerts', }, - bookTravel: 'Book Travel', + bookTravel: 'Book travel', }, workspace: { common: { diff --git a/src/languages/es.ts b/src/languages/es.ts index ba7eb05e1823..6b3d9d1e7eec 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1833,12 +1833,11 @@ export default { }, travel: { header: 'Mis viajes', - title: 'Reserva o gestiona tus viajes', + title: 'Reserva y 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', + alerts: 'Obtén actualizaciones y alertas en tiempo real', }, bookTravel: 'Reservar viajes', }, diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index 817fb430c054..e09e475118d0 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -32,8 +32,8 @@ function ManageTrips() { menuItems={tripsFeatures} title={translate('travel.title')} subtitle={translate('travel.subtitle')} - ctaText={translate('travel.bookOrManage')} - ctaAccessibilityLabel={translate('travel.bookOrManage')} + ctaText={translate('travel.bookTravel')} + ctaAccessibilityLabel={translate('travel.bookTravel')} onCtaPress={() => {}} illustration={LottieAnimations.Plane} illustrationStyle={styles.travelIllustrationStyle} From 3bfea6950158bca8adca5ae22ecb30e15f058052 Mon Sep 17 00:00:00 2001 From: smelaa Date: Wed, 10 Apr 2024 10:27:15 +0200 Subject: [PATCH 18/40] Fix a typo --- src/languages/en.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index d122f558e8d7..b705441e2d60 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1810,7 +1810,7 @@ export default { subtitle: 'Use Expensify Travel to get the best travel offers and manage all your business expenses in a single place.', features: { saveMoney: 'Save money on your bookings', - alerts: 'Get realtime updates and alerts', + alerts: 'Get real time updates and alerts', }, bookTravel: 'Book travel', termsAndConditions: { From d0a32a63ed370f618f98645c7f2dee857c6e31ff Mon Sep 17 00:00:00 2001 From: smelaa Date: Thu, 18 Apr 2024 14:02:30 +0200 Subject: [PATCH 19/40] Address design feedback --- assets/animations/Plane.lottie | Bin 26027 -> 26709 bytes src/components/FeatureList.tsx | 12 +++++++++++- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- src/libs/Permissions.ts | 1 + src/pages/Travel/ManageTrips.tsx | 2 ++ src/pages/Travel/MyTripsPage.tsx | 1 - src/styles/index.ts | 4 ++-- 8 files changed, 18 insertions(+), 6 deletions(-) diff --git a/assets/animations/Plane.lottie b/assets/animations/Plane.lottie index 77a7c0f5dfa8a734b8e0b6c7cb021088ecf3674c..5244cb7bea10be474ab631acd5ce3b5e51d8626e 100644 GIT binary patch delta 26583 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 I|5AMZ2lYh2_W%F@ delta 25912 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 Ii~o)O2ZA&hy#N3J diff --git a/src/components/FeatureList.tsx b/src/components/FeatureList.tsx index 5f713d5f3aef..a9e928b28084 100644 --- a/src/components/FeatureList.tsx +++ b/src/components/FeatureList.tsx @@ -1,6 +1,6 @@ import React from 'react'; import {View} from 'react-native'; -import type {StyleProp, ViewStyle} from 'react-native'; +import type {StyleProp, TextStyle, ViewStyle} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; @@ -43,6 +43,12 @@ type FeatureListProps = { /** The background color to apply in the upper half of the screen. */ illustrationBackgroundColor?: string; + + /** The style passed to the list container */ + containerStyles?: StyleProp; + + /** The style used for the title */ + titleStyles?: StyleProp; }; function FeatureList({ @@ -55,6 +61,8 @@ function FeatureList({ illustration, illustrationStyle, illustrationBackgroundColor, + containerStyles, + titleStyles, }: FeatureListProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -68,6 +76,8 @@ function FeatureList({ illustration={illustration} illustrationBackgroundColor={illustrationBackgroundColor} illustrationStyle={illustrationStyle} + containerStyles={containerStyles} + titleStyles={titleStyles} > diff --git a/src/languages/en.ts b/src/languages/en.ts index c7be8408ec9a..30bb2d49c3eb 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1801,7 +1801,7 @@ export default { offlineMessageRetry: "Looks like you're offline. Please check your connection and try again.", }, travel: { - header: 'My trips', + header: 'Book travel', title: 'Book and manage your trips', subtitle: 'Use Expensify Travel to get the best travel offers and manage all your business expenses in a single place.', features: { diff --git a/src/languages/es.ts b/src/languages/es.ts index 95a79a840247..12da744dc102 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1825,7 +1825,7 @@ export default { offlineMessageRetry: 'Parece que estás desconectado. Por favor, comprueba tu conexión e inténtalo de nuevo.', }, travel: { - header: 'Mis viajes', + header: 'Reservar viajes', title: 'Reserva y 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.', features: { diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index 3473a181a4f8..f51158f2bef6 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -37,6 +37,7 @@ function canUseWorkflowsDelayedSubmission(betas: OnyxEntry): boolean { } function canUseSpotnanaTravel(betas: OnyxEntry): boolean { + return true; return !!betas?.includes(CONST.BETAS.SPOTNANA_TRAVEL) || canUseAllBetas(betas); } diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index e09e475118d0..af38e2e09905 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -38,6 +38,8 @@ function ManageTrips() { illustration={LottieAnimations.Plane} illustrationStyle={styles.travelIllustrationStyle} illustrationBackgroundColor={colors.blue600} + containerStyles={styles.p5} + titleStyles={styles.textHeadlineH1} /> diff --git a/src/pages/Travel/MyTripsPage.tsx b/src/pages/Travel/MyTripsPage.tsx index 003775d1a10c..6ab85c7b7207 100644 --- a/src/pages/Travel/MyTripsPage.tsx +++ b/src/pages/Travel/MyTripsPage.tsx @@ -24,7 +24,6 @@ function MyTripsPage() { shouldShow={!canUseSpotnanaTravel} > diff --git a/src/styles/index.ts b/src/styles/index.ts index ee5338f394ac..6d9deb8dbcc8 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -1818,8 +1818,8 @@ const styles = (theme: ThemeColors) => }, travelIllustrationStyle: { - marginTop: 20, - marginBottom: -20, + marginTop: 16, + marginBottom: -16, }, overlayStyles: (current: OverlayStylesParams, isModalOnTheLeft: boolean) => From 24835cc067eacbc53b6220376f93cb182f809c3b Mon Sep 17 00:00:00 2001 From: smelaa Date: Thu, 18 Apr 2024 14:07:22 +0200 Subject: [PATCH 20/40] Fix spotnana travel beta --- src/libs/Permissions.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index f51158f2bef6..3473a181a4f8 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -37,7 +37,6 @@ function canUseWorkflowsDelayedSubmission(betas: OnyxEntry): boolean { } function canUseSpotnanaTravel(betas: OnyxEntry): boolean { - return true; return !!betas?.includes(CONST.BETAS.SPOTNANA_TRAVEL) || canUseAllBetas(betas); } From 09329008ae638604df026ae44ab5d2261ba53ca6 Mon Sep 17 00:00:00 2001 From: smelaa Date: Thu, 18 Apr 2024 15:03:52 +0200 Subject: [PATCH 21/40] Change card content padding --- src/components/FeatureList.tsx | 10 +++++----- src/components/Section/index.tsx | 6 +++++- src/pages/Travel/ManageTrips.tsx | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/components/FeatureList.tsx b/src/components/FeatureList.tsx index a9e928b28084..85f421731cfa 100644 --- a/src/components/FeatureList.tsx +++ b/src/components/FeatureList.tsx @@ -44,11 +44,11 @@ type FeatureListProps = { /** The background color to apply in the upper half of the screen. */ illustrationBackgroundColor?: string; - /** The style passed to the list container */ - containerStyles?: StyleProp; - /** The style used for the title */ titleStyles?: StyleProp; + + /** Padding for content on large screens */ + contentPaddingOnLargeScreens?: {padding: number}; }; function FeatureList({ @@ -61,8 +61,8 @@ function FeatureList({ illustration, illustrationStyle, illustrationBackgroundColor, - containerStyles, titleStyles, + contentPaddingOnLargeScreens, }: FeatureListProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -76,8 +76,8 @@ function FeatureList({ illustration={illustration} illustrationBackgroundColor={illustrationBackgroundColor} illustrationStyle={illustrationStyle} - containerStyles={containerStyles} titleStyles={titleStyles} + contentPaddingOnLargeScreens={contentPaddingOnLargeScreens} > diff --git a/src/components/Section/index.tsx b/src/components/Section/index.tsx index 848761c9e982..9ac4ebd58181 100644 --- a/src/components/Section/index.tsx +++ b/src/components/Section/index.tsx @@ -68,6 +68,9 @@ type SectionProps = ChildrenProps & { /** Styles to apply to illustration component */ illustrationStyle?: StyleProp; + /** Padding for content on large screens*/ + contentPaddingOnLargeScreens?: {padding: number}; + /** Overlay content to display on top of animation */ overlayContent?: () => ReactNode; @@ -92,6 +95,7 @@ function Section({ illustration, illustrationBackgroundColor, illustrationStyle, + contentPaddingOnLargeScreens, overlayContent, renderSubtitle, }: SectionProps) { @@ -124,7 +128,7 @@ function Section({ {overlayContent?.()} )} - + {cardLayout === CARD_LAYOUT.ICON_ON_LEFT && ( From 0c04a9e4c0ceb9b8dcfcd2813743d042dd855282 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Tue, 23 Apr 2024 16:04:21 +0200 Subject: [PATCH 22/40] add routing, wire up terms --- src/ROUTES.ts | 1 + src/SCREENS.ts | 1 + .../ModalStackNavigators/index.tsx | 1 + src/libs/Navigation/linkingConfig/config.ts | 1 + src/pages/Travel/ManageTrips.tsx | 6 +- src/pages/Travel/TravelTerms.tsx | 55 ++++++++++--------- 6 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 8069b99fea5d..8be2a618ce72 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -699,6 +699,7 @@ const ROUTES = { }, PROCESS_MONEY_REQUEST_HOLD: 'hold-request-educational', TRAVEL_MY_TRIPS: 'travel', + TRAVEL_TCS: 'travel/terms', ONBOARDING_ROOT: 'onboarding', ONBOARDING_PERSONAL_DETAILS: 'onboarding/personal-details', ONBOARDING_PURPOSE: 'onboarding/purpose', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index f55068374faa..047f42014162 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -24,6 +24,7 @@ const SCREENS = { SETTINGS_CENTRAL_PANE: 'SettingsCentralPane', TRAVEL: { MY_TRIPS: 'Travel_MyTrips', + TCS: 'Travel_TCS', }, WORKSPACES_CENTRAL_PANE: 'WorkspacesCentralPane', SETTINGS: { diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 8ddcc505ea78..0ea8c6b058bd 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -99,6 +99,7 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator({ [SCREENS.TRAVEL.MY_TRIPS]: () => require('../../../../pages/Travel/MyTripsPage').default as React.ComponentType, + [SCREENS.TRAVEL.TCS]: () => require('../../../../pages/Travel/TravelTerms').default as React.ComponentType, }); const SplitDetailsModalStackNavigator = createModalStackNavigator({ diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 804a106a35a9..6722cd8fab36 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -640,6 +640,7 @@ const config: LinkingOptions['config'] = { [SCREENS.RIGHT_MODAL.TRAVEL]: { screens: { [SCREENS.TRAVEL.MY_TRIPS]: ROUTES.TRAVEL_MY_TRIPS, + [SCREENS.TRAVEL.TCS]: ROUTES.TRAVEL_TCS, }, }, }, diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index 53c227dd156c..0335122b3739 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -7,7 +7,9 @@ import LottieAnimations from '@components/LottieAnimations'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; +import Navigation from '@libs/Navigation/Navigation'; import colors from '@styles/theme/colors'; +import ROUTES from '@src/ROUTES'; const tripsFeatures: FeatureListItem[] = [ { @@ -34,7 +36,9 @@ function ManageTrips() { subtitle={translate('travel.subtitle')} ctaText={translate('travel.bookTravel')} ctaAccessibilityLabel={translate('travel.bookTravel')} - onCtaPress={() => {}} + onCtaPress={() => { + Navigation.navigate(ROUTES.TRAVEL_TCS); + }} illustration={LottieAnimations.Plane} illustrationStyle={styles.travelIllustrationStyle} illustrationBackgroundColor={colors.blue600} diff --git a/src/pages/Travel/TravelTerms.tsx b/src/pages/Travel/TravelTerms.tsx index dfcf8a722888..79b402fff028 100644 --- a/src/pages/Travel/TravelTerms.tsx +++ b/src/pages/Travel/TravelTerms.tsx @@ -1,44 +1,49 @@ -import React, { useCallback, useEffect, useState } from 'react'; -import CheckboxWithLabel from "@components/CheckboxWithLabel"; -import HeaderWithBackButton from "@components/HeaderWithBackButton"; -import ScreenWrapper from "@components/ScreenWrapper"; -import Text from "@components/Text"; -import TextLink from "@components/TextLink"; -import useLocalize from "@hooks/useLocalize"; -import useThemeStyles from "@hooks/useThemeStyles"; -import Navigation from "@libs/Navigation/Navigation"; -import { ScrollView } from "react-native-gesture-handler"; -import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; -import { View } from 'react-native'; +import React, {useCallback, useEffect, useState} from 'react'; +import {View} from 'react-native'; +import {ScrollView} from 'react-native-gesture-handler'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import CheckboxWithLabel from '@components/CheckboxWithLabel'; +import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import Text from '@components/Text'; +import TextLink from '@components/TextLink'; +import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; function TravelTerms() { const styles = useThemeStyles(); const {translate} = useLocalize(); + const {canUseSpotnanaTravel} = usePermissions(); const [hasAcceptedTravelTerms, setHasAcceptedTravelTerms] = useState(false); const [error, setError] = useState(false); - const errorMessage = error ? 'travel.termsAndConditions.error' : ''; + const errorMessage = error ? 'travel.termsAndConditions.error' : ''; const toggleTravelTerms = () => { setHasAcceptedTravelTerms(!hasAcceptedTravelTerms); }; useEffect(() => { - if(!hasAcceptedTravelTerms) { + if (!hasAcceptedTravelTerms) { return; } setError(false); }, [hasAcceptedTravelTerms]); - const AgreeToTheLabel = useCallback(() => ( + const AgreeToTheLabel = useCallback( + () => ( {`${translate('travel.termsAndConditions.agree')}`} {`${translate('travel.termsAndConditions.travelTermsAndConditions')}`} - ), [translate]); - + ), + [translate], + ); + // Add beta support for FullPageNotFound that is universal across travel pages return ( - + Navigation.goBack()} - /> + title={translate('travel.termsAndConditions.header')} + onBackButtonPress={() => Navigation.goBack()} + /> {`${translate('travel.termsAndConditions.title')}`} @@ -76,14 +81,14 @@ function TravelTerms() { buttonText={translate('common.continue')} isDisabled={!hasAcceptedTravelTerms} onSubmit={() => { - if(!hasAcceptedTravelTerms) { + if (!hasAcceptedTravelTerms) { setError(true); return; } // API call for AcceptSpontanaTerms when backend gets implemented setError(false); - Navigation.goBack(); + Navigation.navigate(); }} message={errorMessage} isAlertVisible={error || Boolean(errorMessage)} @@ -92,9 +97,9 @@ function TravelTerms() { - ) + ); } TravelTerms.displayName = 'TravelMenu'; -export default TravelTerms; \ No newline at end of file +export default TravelTerms; From c040d3dffe6584fb6639036d1283c4833302f4c9 Mon Sep 17 00:00:00 2001 From: smelaa Date: Tue, 23 Apr 2024 16:23:58 +0200 Subject: [PATCH 23/40] Change textcontent --- src/languages/en.ts | 4 ++-- src/languages/es.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 10631b52bdf8..d36053095441 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1806,8 +1806,8 @@ export default { }, travel: { header: 'Book travel', - title: 'Book and manage your trips', - subtitle: 'Use Expensify Travel to get the best travel offers and manage all your business expenses in a single place.', + title: 'Travel smart', + subtitle: 'Use Expensify Travel to get the best travel offers and manage all your business expenses in one place.', features: { saveMoney: 'Save money on your bookings', alerts: 'Get real time updates and alerts', diff --git a/src/languages/es.ts b/src/languages/es.ts index b4f731a18960..1ae004c5b417 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1830,7 +1830,7 @@ export default { }, travel: { header: 'Reservar viajes', - title: 'Reserva y gestiona tus viajes', + title: 'Viaja de forma inteligente', subtitle: 'Utiliza Expensify Travel para obtener las mejores ofertas de viaje y gestionar todos tus gastos de negocio en un solo lugar.', features: { saveMoney: 'Ahorra dinero en tus reservas', From aea71e4fe559c4066e29cd4c4aaadf928001a84a Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Thu, 25 Apr 2024 11:49:53 +0200 Subject: [PATCH 24/40] wire up accept terms wip --- src/libs/API/types.ts | 2 ++ src/libs/actions/Travel.ts | 26 ++++++++++++++++++++++++++ src/pages/Travel/TravelTerms.tsx | 5 +++-- src/types/onyx/Account.ts | 4 ++++ src/types/onyx/Policy.ts | 4 ++++ src/types/onyx/TravelSettings.ts | 19 +++++++++++++++++++ tests/utils/collections/userAccount.ts | 4 ++++ 7 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/libs/actions/Travel.ts create mode 100644 src/types/onyx/TravelSettings.ts diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 7a40400b3826..0f3e8727ae6e 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -212,6 +212,7 @@ const WRITE_COMMANDS = { CATEGORIZE_TRACKED_EXPENSE: 'CategorizeTrackedExpense', SHARE_TRACKED_EXPENSE: 'ShareTrackedExpense', LEAVE_POLICY: 'LeavePolicy', + ACCEPT_SPOTNANA_TERMS: 'AcceptSpotnanaTerms', } as const; type WriteCommand = ValueOf; @@ -424,6 +425,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.CATEGORIZE_TRACKED_EXPENSE]: Parameters.CategorizeTrackedExpenseParams; [WRITE_COMMANDS.SHARE_TRACKED_EXPENSE]: Parameters.ShareTrackedExpenseParams; [WRITE_COMMANDS.LEAVE_POLICY]: Parameters.LeavePolicyParams; + [WRITE_COMMANDS.ACCEPT_SPOTNANA_TERMS]: EmptyObject; }; const READ_COMMANDS = { diff --git a/src/libs/actions/Travel.ts b/src/libs/actions/Travel.ts new file mode 100644 index 000000000000..02affae0fe67 --- /dev/null +++ b/src/libs/actions/Travel.ts @@ -0,0 +1,26 @@ +import type {OnyxUpdate} from 'react-native-onyx'; +import * as API from '@libs/API'; +import {WRITE_COMMANDS} from '@libs/API/types'; +import ONYXKEYS from '@src/ONYXKEYS'; + +/** + * Accept Spotnana terms and conditions to receive a proper token used for authenticating further actions + */ +function acceptSpotnanaTerms() { + const successData: OnyxUpdate[] = [ + { + onyxMethod: 'merge', + key: ONYXKEYS.ACCOUNT, + value: { + travelSettings: { + hasAcceptedTerms: true, + }, + }, + }, + ]; + + API.write(WRITE_COMMANDS.ACCEPT_SPOTNANA_TERMS, {}, {successData}); +} + +// eslint-disable-next-line import/prefer-default-export +export {acceptSpotnanaTerms}; diff --git a/src/pages/Travel/TravelTerms.tsx b/src/pages/Travel/TravelTerms.tsx index 79b402fff028..c4dea32c5f50 100644 --- a/src/pages/Travel/TravelTerms.tsx +++ b/src/pages/Travel/TravelTerms.tsx @@ -12,6 +12,7 @@ import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; +import * as Travel from '@userActions/Travel'; function TravelTerms() { const styles = useThemeStyles(); @@ -85,8 +86,8 @@ function TravelTerms() { setError(true); return; } - - // API call for AcceptSpontanaTerms when backend gets implemented + console.log('SUBMIT'); + Travel.acceptSpotnanaTerms(); setError(false); Navigation.navigate(); }} diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index 67ff12c74150..cdc8e7471156 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -2,6 +2,7 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type DismissedReferralBanners from './DismissedReferralBanners'; import type * as OnyxCommon from './OnyxCommon'; +import type {TravelSettings} from './TravelSettings'; type TwoFactorAuthStep = ValueOf | ''; @@ -59,6 +60,9 @@ type Account = { codesAreCopied?: boolean; twoFactorAuthStep?: TwoFactorAuthStep; dismissedReferralBanners?: DismissedReferralBanners; + + /** Object containing all account information necessary to connect with Spotnana */ + travelSettings: TravelSettings; }; export default Account; diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 7d6bf83bcbf6..15f026c6440b 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -2,6 +2,7 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type * as OnyxTypes from '.'; import type * as OnyxCommon from './OnyxCommon'; +import type { WorkspaceTravelSettings } from './TravelSettings'; type Unit = 'mi' | 'km'; @@ -444,6 +445,9 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< /** Indicates if the Policy ownership change is failed */ isChangeOwnerFailed?: boolean; + + /** Object containing all policy information necessary to connect with Spotnan */ + travelSettings: WorkspaceTravelSettings; } & Partial, 'generalSettings' | 'addWorkspaceRoom' | keyof ACHAccount >; diff --git a/src/types/onyx/TravelSettings.ts b/src/types/onyx/TravelSettings.ts new file mode 100644 index 000000000000..9406fca72c7c --- /dev/null +++ b/src/types/onyx/TravelSettings.ts @@ -0,0 +1,19 @@ +import type {Address} from './PrivatePersonalDetails'; + +type TravelSettings = { + /** UUIDs that spotnana provides us with when we provision users in their system, and the spotnanaCompanyIDs as the values */ + accountIDs: Record; + + /** Whether the user has completed the travel terms and conditions checkbox */ + hasAcceptedTerms: boolean; +}; + +type WorkspaceTravelSettings = { + /** The UUID that spotnana provides us when we create a “company” in their system */ + spotnanaCompanyID: string; + + /** The UUID that spotnana provides us when we provision the workspace as an “entity” in their system */ + spotnanaEntityID: boolean; +}; + +export type {TravelSettings, WorkspaceTravelSettings}; diff --git a/tests/utils/collections/userAccount.ts b/tests/utils/collections/userAccount.ts index 9e7c33a228d5..ebaa0a132169 100644 --- a/tests/utils/collections/userAccount.ts +++ b/tests/utils/collections/userAccount.ts @@ -7,6 +7,10 @@ function getValidAccount(credentialLogin = ''): Account { primaryLogin: credentialLogin, isLoading: false, requiresTwoFactorAuth: false, + travelSettings: { + accountIDs: {}, + hasAcceptedTerms: false, + }, }; } From 3eff605eb4d87abc1a1d5a833736af4008960056 Mon Sep 17 00:00:00 2001 From: BrtqKr Date: Thu, 25 Apr 2024 16:50:01 +0200 Subject: [PATCH 25/40] cleanup --- src/pages/Travel/TravelTerms.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Travel/TravelTerms.tsx b/src/pages/Travel/TravelTerms.tsx index c4dea32c5f50..a833eeec09dc 100644 --- a/src/pages/Travel/TravelTerms.tsx +++ b/src/pages/Travel/TravelTerms.tsx @@ -86,10 +86,10 @@ function TravelTerms() { setError(true); return; } - console.log('SUBMIT'); + Travel.acceptSpotnanaTerms(); setError(false); - Navigation.navigate(); + Navigation.resetToHome(); }} message={errorMessage} isAlertVisible={error || Boolean(errorMessage)} From b96d89aeeaf41051161c48ada096cc82bdfb5598 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 29 Apr 2024 10:33:36 +0200 Subject: [PATCH 26/40] fix spanish translations --- src/languages/es.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index 70645f5aee75..48f3381d611c 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1836,7 +1836,7 @@ export default { travel: { header: 'Reservar viajes', title: 'Viaja de forma inteligente', - subtitle: 'Utiliza Expensify Travel para obtener las mejores ofertas de viaje y gestionar todos tus gastos de negocio en un solo lugar.', + subtitle: 'Utiliza Expensify Travel para obtener las mejores ofertas de viaje y gestionar todos los gastos de tu negocio en un solo lugar.', features: { saveMoney: 'Ahorra dinero en tus reservas', alerts: 'Obtén actualizaciones y alertas en tiempo real', @@ -1844,12 +1844,12 @@ export default { bookTravel: 'Reservar viajes', termsAndConditions: { header: 'Antes de continuar...', - title: 'Por favor lea los Términos y condiciones para viajar', - subtitle: 'Para permitir viajar en su espacio de trabajo debe aceptar nuestros ', + title: 'Por favor, lee los Términos y condiciones para reservar viajes', + subtitle: 'Para permitir la opción de reservar viajes en su espacio de trabajo debe aceptar nuestros ', termsconditions: 'términos y condiciones', travelTermsAndConditions: 'términos y condiciones de viaje', - helpDocIntro: 'Consulte este ', - helpDocOutro: 'para obtener más información o comuníquese con el conserje o su administrador de cuentas.', + helpDocIntro: 'Consulta este ', + helpDocOutro: 'para obtener más información o comunícate con Concierge o tu gestor de cuentas.', helpDoc: 'documento de ayuda', agree: 'Acepto los ', error: 'Debes aceptar los Términos y condiciones para que el viaje continúe', From 9def0708d4f8967a8ec87cfa4c8bc6ee047163d8 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 29 Apr 2024 10:51:36 +0200 Subject: [PATCH 27/40] fix lint issues --- src/components/Section/index.tsx | 2 +- src/pages/Travel/ManageTrips.tsx | 3 ++- src/pages/Travel/MyTripsPage.tsx | 1 - src/types/onyx/TravelSettings.ts | 2 -- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/Section/index.tsx b/src/components/Section/index.tsx index 9ac4ebd58181..7f7d759c72aa 100644 --- a/src/components/Section/index.tsx +++ b/src/components/Section/index.tsx @@ -68,7 +68,7 @@ type SectionProps = ChildrenProps & { /** Styles to apply to illustration component */ illustrationStyle?: StyleProp; - /** Padding for content on large screens*/ + /** Padding for content on large screens */ contentPaddingOnLargeScreens?: {padding: number}; /** Overlay content to display on top of animation */ diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index 0335122b3739..6924ff15a336 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -1,7 +1,8 @@ import React from 'react'; -import {ScrollView, View} from 'react-native'; +import {View} from 'react-native'; import type {FeatureListItem} from '@components/FeatureList'; import FeatureList from '@components/FeatureList'; +import ScrollView from '@components/ScrollView'; import * as Illustrations from '@components/Icon/Illustrations'; import LottieAnimations from '@components/LottieAnimations'; import useLocalize from '@hooks/useLocalize'; diff --git a/src/pages/Travel/MyTripsPage.tsx b/src/pages/Travel/MyTripsPage.tsx index 6ab85c7b7207..be29e8dc8c12 100644 --- a/src/pages/Travel/MyTripsPage.tsx +++ b/src/pages/Travel/MyTripsPage.tsx @@ -1,7 +1,6 @@ import React from 'react'; 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 usePermissions from '@hooks/usePermissions'; diff --git a/src/types/onyx/TravelSettings.ts b/src/types/onyx/TravelSettings.ts index 9406fca72c7c..e653c3378572 100644 --- a/src/types/onyx/TravelSettings.ts +++ b/src/types/onyx/TravelSettings.ts @@ -1,5 +1,3 @@ -import type {Address} from './PrivatePersonalDetails'; - type TravelSettings = { /** UUIDs that spotnana provides us with when we provision users in their system, and the spotnanaCompanyIDs as the values */ accountIDs: Record; From 27ee79f9f94dbc09745c64daa0503d643b0703a4 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 29 Apr 2024 10:51:45 +0200 Subject: [PATCH 28/40] fix prettier --- src/pages/Travel/ManageTrips.tsx | 2 +- src/types/onyx/Policy.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index 6924ff15a336..c02c5b915ea4 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -2,9 +2,9 @@ import React from 'react'; import {View} from 'react-native'; import type {FeatureListItem} from '@components/FeatureList'; import FeatureList from '@components/FeatureList'; -import ScrollView from '@components/ScrollView'; import * as Illustrations from '@components/Icon/Illustrations'; import LottieAnimations from '@components/LottieAnimations'; +import ScrollView from '@components/ScrollView'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index fb6b536dc430..487a1dc2a750 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -2,7 +2,7 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type * as OnyxTypes from '.'; import type * as OnyxCommon from './OnyxCommon'; -import type { WorkspaceTravelSettings } from './TravelSettings'; +import type {WorkspaceTravelSettings} from './TravelSettings'; type Unit = 'mi' | 'km'; From c77d1d4cefada0c50515264a9fee0834b4fe4337 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 29 Apr 2024 11:09:30 +0200 Subject: [PATCH 29/40] fix comments and type requirements for travelSettings --- src/types/onyx/Account.ts | 4 ++-- src/types/onyx/Policy.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index cdc8e7471156..c53d7ea816f8 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -61,8 +61,8 @@ type Account = { twoFactorAuthStep?: TwoFactorAuthStep; dismissedReferralBanners?: DismissedReferralBanners; - /** Object containing all account information necessary to connect with Spotnana */ - travelSettings: TravelSettings; + /** Object containing all account information necessary to connect with Spontana */ + travelSettings?: TravelSettings; }; export default Account; diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 487a1dc2a750..47a570dcb233 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -449,8 +449,8 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< /** Indicates if the Policy ownership change is failed */ isChangeOwnerFailed?: boolean; - /** Object containing all policy information necessary to connect with Spotnan */ - travelSettings: WorkspaceTravelSettings; + /** Object containing all policy information necessary to connect with Spontana */ + travelSettings?: WorkspaceTravelSettings; } & Partial, 'generalSettings' | 'addWorkspaceRoom' | keyof ACHAccount >; From 89ec881f5f59715732bb26758b7d9c87b1ef42e1 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 30 Apr 2024 14:05:56 +0200 Subject: [PATCH 30/40] Update margin in TravelTerms page --- src/pages/Travel/TravelTerms.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Travel/TravelTerms.tsx b/src/pages/Travel/TravelTerms.tsx index a833eeec09dc..d6771ff6d5f9 100644 --- a/src/pages/Travel/TravelTerms.tsx +++ b/src/pages/Travel/TravelTerms.tsx @@ -93,7 +93,7 @@ function TravelTerms() { }} message={errorMessage} isAlertVisible={error || Boolean(errorMessage)} - containerStyles={[styles.mh0, styles.mv4]} + containerStyles={[styles.mh0, styles.mv5]} /> From e05bfab34a148e12b85e151b3542995ae27e2a6a Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 30 Apr 2024 14:35:46 +0200 Subject: [PATCH 31/40] Fix padding in TravelTerms --- src/pages/Travel/TravelTerms.tsx | 80 +++++++++++++++++--------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/src/pages/Travel/TravelTerms.tsx b/src/pages/Travel/TravelTerms.tsx index d6771ff6d5f9..6852275dfe91 100644 --- a/src/pages/Travel/TravelTerms.tsx +++ b/src/pages/Travel/TravelTerms.tsx @@ -5,6 +5,7 @@ import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView import CheckboxWithLabel from '@components/CheckboxWithLabel'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import SafeAreaConsumer from '@components/SafeAreaConsumer'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; @@ -57,45 +58,48 @@ function TravelTerms() { title={translate('travel.termsAndConditions.header')} onBackButtonPress={() => Navigation.goBack()} /> - - - {`${translate('travel.termsAndConditions.title')}`} - - {`${translate('travel.termsAndConditions.subtitle')}`} - {`${translate('travel.termsAndConditions.termsconditions')}.`} - - - {`${translate('travel.termsAndConditions.helpDocIntro')}`} - {`${translate('travel.termsAndConditions.helpDoc')} `} - {`${translate('travel.termsAndConditions.helpDocOutro')}`} - - - - - - { - if (!hasAcceptedTravelTerms) { - setError(true); - return; - } + + {({safeAreaPaddingBottomStyle}) => ( + + + {`${translate('travel.termsAndConditions.title')}`} + + {`${translate('travel.termsAndConditions.subtitle')}`} + {`${translate('travel.termsAndConditions.termsconditions')}.`} + + + {`${translate('travel.termsAndConditions.helpDocIntro')}`} + {`${translate('travel.termsAndConditions.helpDoc')} `} + {`${translate('travel.termsAndConditions.helpDocOutro')}`} + + + - Travel.acceptSpotnanaTerms(); - setError(false); - Navigation.resetToHome(); - }} - message={errorMessage} - isAlertVisible={error || Boolean(errorMessage)} - containerStyles={[styles.mh0, styles.mv5]} - /> - + { + if (!hasAcceptedTravelTerms) { + setError(true); + return; + } + + Travel.acceptSpotnanaTerms(); + setError(false); + Navigation.resetToHome(); + }} + message={errorMessage} + isAlertVisible={error || Boolean(errorMessage)} + containerStyles={[styles.mh0, styles.mt5]} + /> + + )} + ); From 2aef4fd7389ec454310fa73736737e3b33e2e56a Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 30 Apr 2024 14:40:21 +0200 Subject: [PATCH 32/40] Refactor comment in BottomTabBar --- .../createCustomBottomTabNavigator/BottomTabBar.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 54d93ad20a52..7f26177eeb0f 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -44,12 +44,9 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps const navigationState = navigation.getState() as State | undefined; const routes = navigationState?.routes; const currentRoute = routes?.[navigationState?.index ?? 0]; - if ( - // 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 - Boolean(currentRoute && currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && currentRoute.name !== NAVIGATORS.CENTRAL_PANE_NAVIGATOR) || - Session.isAnonymousUser() - ) { + // 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 + if (Boolean(currentRoute && currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && currentRoute.name !== NAVIGATORS.CENTRAL_PANE_NAVIGATOR) || Session.isAnonymousUser()) { return; } From d7b9716a9b645fd2d1a86f3e1da5d42305eaba77 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 30 Apr 2024 15:12:19 +0200 Subject: [PATCH 33/40] Add getTripIllustrationStyle --- src/pages/Travel/ManageTrips.tsx | 4 +++- .../Travel/getTripIllustrationStyle/index.native.ts | 8 ++++++++ src/pages/Travel/getTripIllustrationStyle/index.ts | 9 +++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/pages/Travel/getTripIllustrationStyle/index.native.ts create mode 100644 src/pages/Travel/getTripIllustrationStyle/index.ts diff --git a/src/pages/Travel/ManageTrips.tsx b/src/pages/Travel/ManageTrips.tsx index c02c5b915ea4..401f06277b5e 100644 --- a/src/pages/Travel/ManageTrips.tsx +++ b/src/pages/Travel/ManageTrips.tsx @@ -11,6 +11,7 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import Navigation from '@libs/Navigation/Navigation'; import colors from '@styles/theme/colors'; import ROUTES from '@src/ROUTES'; +import getTripIllustrationStyle from './getTripIllustrationStyle'; const tripsFeatures: FeatureListItem[] = [ { @@ -27,6 +28,7 @@ function ManageTrips() { const styles = useThemeStyles(); const {isSmallScreenWidth} = useWindowDimensions(); const {translate} = useLocalize(); + const illustrationStyle = getTripIllustrationStyle(); return ( @@ -41,7 +43,7 @@ function ManageTrips() { Navigation.navigate(ROUTES.TRAVEL_TCS); }} illustration={LottieAnimations.Plane} - illustrationStyle={styles.travelIllustrationStyle} + illustrationStyle={illustrationStyle} illustrationBackgroundColor={colors.blue600} titleStyles={styles.textHeadlineH1} contentPaddingOnLargeScreens={styles.p5} diff --git a/src/pages/Travel/getTripIllustrationStyle/index.native.ts b/src/pages/Travel/getTripIllustrationStyle/index.native.ts new file mode 100644 index 000000000000..4633f1f2d1f4 --- /dev/null +++ b/src/pages/Travel/getTripIllustrationStyle/index.native.ts @@ -0,0 +1,8 @@ +import type {ViewStyle} from 'react-native'; + +// Styling lottie animations for the ManageTrips component requires different margin values ​​depending on the platform +export default function getTripIllustrationStyle(): ViewStyle { + return { + marginVertical: 20, + }; +} diff --git a/src/pages/Travel/getTripIllustrationStyle/index.ts b/src/pages/Travel/getTripIllustrationStyle/index.ts new file mode 100644 index 000000000000..d4bb1b0ee5b8 --- /dev/null +++ b/src/pages/Travel/getTripIllustrationStyle/index.ts @@ -0,0 +1,9 @@ +import type {ViewStyle} from 'react-native'; + +// Styling lottie animations for the ManageTrips component requires different margin values ​​depending on the platform +export default function getTripIllustrationStyle(): ViewStyle { + return { + marginTop: 20, + marginBottom: -20, + }; +} From 76cc3e303a88e5ff29658df37c81b3a68c484a2b Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 30 Apr 2024 15:23:27 +0200 Subject: [PATCH 34/40] Fix lint --- src/pages/Travel/getTripIllustrationStyle/index.native.ts | 2 +- src/pages/Travel/getTripIllustrationStyle/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/Travel/getTripIllustrationStyle/index.native.ts b/src/pages/Travel/getTripIllustrationStyle/index.native.ts index 4633f1f2d1f4..e5b0a1381d7e 100644 --- a/src/pages/Travel/getTripIllustrationStyle/index.native.ts +++ b/src/pages/Travel/getTripIllustrationStyle/index.native.ts @@ -1,6 +1,6 @@ import type {ViewStyle} from 'react-native'; -// Styling lottie animations for the ManageTrips component requires different margin values ​​depending on the platform +// Styling lottie animations for the ManageTrips component requires different margin values depending on the platform. export default function getTripIllustrationStyle(): ViewStyle { return { marginVertical: 20, diff --git a/src/pages/Travel/getTripIllustrationStyle/index.ts b/src/pages/Travel/getTripIllustrationStyle/index.ts index d4bb1b0ee5b8..a2a141022d73 100644 --- a/src/pages/Travel/getTripIllustrationStyle/index.ts +++ b/src/pages/Travel/getTripIllustrationStyle/index.ts @@ -1,6 +1,6 @@ import type {ViewStyle} from 'react-native'; -// Styling lottie animations for the ManageTrips component requires different margin values ​​depending on the platform +// Styling lottie animations for the ManageTrips component requires different margin values depending on the platform. export default function getTripIllustrationStyle(): ViewStyle { return { marginTop: 20, From 1609ab36dcdc94cd5d2dd203de33593862c74b61 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 2 May 2024 18:49:41 +0530 Subject: [PATCH 35/40] add url to const --- src/CONST.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CONST.ts b/src/CONST.ts index 5f97087581ce..9c7b06c23aea 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -583,6 +583,7 @@ const CONST = { ONFIDO_PRIVACY_POLICY_URL: 'https://onfido.com/privacy/', ONFIDO_TERMS_OF_SERVICE_URL: 'https://onfido.com/terms-of-service/', LIST_OF_RESTRICTED_BUSINESSES: 'https://community.expensify.com/discussion/6191/list-of-restricted-businesses', + TRAVEL_TERMS_URL: `${USE_EXPENSIFY_URL}/travelterms`, // Use Environment.getEnvironmentURL to get the complete URL with port number DEV_NEW_EXPENSIFY_URL: 'https://dev.new.expensify.com:', From 1d7660b30beba99fb19f1ae74aeced74f94b8f29 Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 2 May 2024 18:49:59 +0530 Subject: [PATCH 36/40] lang --- src/languages/en.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 4f923a647a4c..35bf59809d1d 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1843,7 +1843,7 @@ export default { subtitle: 'Use Expensify Travel to get the best travel offers and manage all your business expenses in one place.', features: { saveMoney: 'Save money on your bookings', - alerts: 'Get real time updates and alerts', + alerts: 'Get realtime updates and alerts', }, bookTravel: 'Book travel', termsAndConditions: { From 8edd0cea8a2483af50ec0237d0052bf0467c013f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 2 May 2024 18:50:11 +0530 Subject: [PATCH 37/40] use const --- src/pages/Travel/TravelTerms.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/Travel/TravelTerms.tsx b/src/pages/Travel/TravelTerms.tsx index 6852275dfe91..468ca9b8082a 100644 --- a/src/pages/Travel/TravelTerms.tsx +++ b/src/pages/Travel/TravelTerms.tsx @@ -14,6 +14,7 @@ import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import * as Travel from '@userActions/Travel'; +import CONST from '@src/CONST'; function TravelTerms() { const styles = useThemeStyles(); @@ -40,7 +41,7 @@ function TravelTerms() { () => ( {`${translate('travel.termsAndConditions.agree')}`} - {`${translate('travel.termsAndConditions.travelTermsAndConditions')}`} + {`${translate('travel.termsAndConditions.travelTermsAndConditions')}`} ), [translate], @@ -65,7 +66,7 @@ function TravelTerms() { {`${translate('travel.termsAndConditions.title')}`} {`${translate('travel.termsAndConditions.subtitle')}`} - {`${translate('travel.termsAndConditions.termsconditions')}.`} + {`${translate('travel.termsAndConditions.termsconditions')}.`} {`${translate('travel.termsAndConditions.helpDocIntro')}`} From 30cc4ecf3e85dbc48b64ea31ba647db62e497e8f Mon Sep 17 00:00:00 2001 From: Rushat Gabhane Date: Thu, 2 May 2024 22:11:19 +0530 Subject: [PATCH 38/40] change icon size to 48 x 48 --- src/components/FeatureList.tsx | 4 ++-- src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx | 4 ++-- src/styles/variables.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/FeatureList.tsx b/src/components/FeatureList.tsx index 85f421731cfa..8ee87caa7778 100644 --- a/src/components/FeatureList.tsx +++ b/src/components/FeatureList.tsx @@ -89,8 +89,8 @@ function FeatureList({ Date: Thu, 2 May 2024 22:13:45 +0530 Subject: [PATCH 39/40] rename to menuIconSize --- src/components/FeatureList.tsx | 4 ++-- src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx | 4 ++-- src/styles/variables.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/FeatureList.tsx b/src/components/FeatureList.tsx index 8ee87caa7778..5e4ab89cf150 100644 --- a/src/components/FeatureList.tsx +++ b/src/components/FeatureList.tsx @@ -89,8 +89,8 @@ function FeatureList({ Date: Thu, 2 May 2024 22:28:28 +0530 Subject: [PATCH 40/40] update icons --- .../simple-illustration__alert.svg | 28 +++--- .../simple-illustration__piggybank.svg | 98 +++++++++---------- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/assets/images/simple-illustrations/simple-illustration__alert.svg b/assets/images/simple-illustrations/simple-illustration__alert.svg index 55429cf39b8f..2e7bca02f5e3 100644 --- a/assets/images/simple-illustrations/simple-illustration__alert.svg +++ b/assets/images/simple-illustrations/simple-illustration__alert.svg @@ -1,15 +1,15 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/assets/images/simple-illustrations/simple-illustration__piggybank.svg b/assets/images/simple-illustrations/simple-illustration__piggybank.svg index a9cf2b02c5dc..be87ff34752a 100644 --- a/assets/images/simple-illustrations/simple-illustration__piggybank.svg +++ b/assets/images/simple-illustrations/simple-illustration__piggybank.svg @@ -1,50 +1,50 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +