Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,13 @@ const signupQualifiers = {
SMB: 'smb',
} as const;

const selfGuidedTourTask: OnboardingTask = {
const getTestDriveTaskName = (testDriveURL?: string) => (testDriveURL ? `Take a [test drive](${testDriveURL})` : 'Take a test drive');
const testDriveTask: OnboardingTask = {
type: 'viewTour',
autoCompleted: false,
mediaAttributes: {},
title: ({navatticURL}) => `Take a [2-minute tour](${navatticURL})`,
description: ({navatticURL}) => `[Take a self-guided product tour](${navatticURL}) and learn about everything Expensify has to offer.`,
title: ({testDriveURL}) => getTestDriveTaskName(testDriveURL),
description: ({testDriveURL}) => `[Take a quick product tour](${testDriveURL}) to see why Expensify is the fastest way to do your expenses.`,
};

const createWorkspaceTask: OnboardingTask = {
Expand Down Expand Up @@ -164,7 +165,7 @@ const setupCategoriesTask: OnboardingTask = {
const onboardingEmployerOrSubmitMessage: OnboardingMessage = {
message: 'Getting paid back is as easy as sending a message. Let’s go over the basics.',
tasks: [
selfGuidedTourTask,
testDriveTask,
{
type: 'submitExpense',
autoCompleted: false,
Expand All @@ -188,7 +189,7 @@ const onboardingEmployerOrSubmitMessage: OnboardingMessage = {
const combinedTrackSubmitOnboardingEmployerOrSubmitMessage: OnboardingMessage = {
...onboardingEmployerOrSubmitMessage,
tasks: [
selfGuidedTourTask,
testDriveTask,
{
type: 'submitExpense',
autoCompleted: false,
Expand All @@ -213,7 +214,7 @@ const combinedTrackSubmitOnboardingEmployerOrSubmitMessage: OnboardingMessage =
const onboardingPersonalSpendMessage: OnboardingMessage = {
message: 'Here’s how to track your spend in a few clicks.',
tasks: [
selfGuidedTourTask,
testDriveTask,
{
type: 'trackExpense',
autoCompleted: false,
Expand All @@ -237,7 +238,7 @@ const onboardingPersonalSpendMessage: OnboardingMessage = {
const combinedTrackSubmitOnboardingPersonalSpendMessage: OnboardingMessage = {
...onboardingPersonalSpendMessage,
tasks: [
selfGuidedTourTask,
testDriveTask,
{
type: 'trackExpense',
autoCompleted: false,
Expand Down Expand Up @@ -289,6 +290,7 @@ type OnboardingTaskLinks = Partial<{
workspaceMembersLink: string;
workspaceAccountingLink: string;
navatticURL: string;
testDriveURL: string;
}>;

type OnboardingTask = {
Expand Down Expand Up @@ -1094,6 +1096,12 @@ const CONST = {
EMPLOYEE_TOUR_STAGING: 'https://expensify.navattic.com/cf15002s',
COMPLETED: 'completed',
},
STORYLANE: {
ADMIN_TOUR_PRODUCTION: 'https://app.storylane.io/demo/nrkhnm80nbix?embed=inline',
ADMIN_TOUR_MOBILE_PRODUCTION: 'https://app.storylane.io/demo/wg7a9qqg6qkf?embed=inline',
ADMIN_TOUR_STAGING: 'https://app.storylane.io/demo/nrkhnm80nbix?embed=inline',
ADMIN_TOUR_MOBILE_STAGING: 'https://app.storylane.io/demo/wg7a9qqg6qkf?embed=inline',
},
OLD_DOT_PUBLIC_URLS: {
TERMS_URL: `${EXPENSIFY_URL}/terms`,
PRIVACY_URL: `${EXPENSIFY_URL}/privacy`,
Expand Down Expand Up @@ -1493,6 +1501,7 @@ const CONST = {
BOTTOM_DOCKED: 'bottom_docked',
POPOVER: 'popover',
RIGHT_DOCKED: 'right_docked',
FULLSCREEN: 'fullscreen',
},
ANCHOR_ORIGIN_VERTICAL: {
TOP: 'top',
Expand Down Expand Up @@ -5376,7 +5385,7 @@ const CONST = {
message: 'Here are some important tasks to help get your team’s expenses under control.',
tasks: [
createWorkspaceTask,
selfGuidedTourTask,
testDriveTask,
{
type: 'setupCategoriesAndTags',
autoCompleted: false,
Expand Down Expand Up @@ -5510,7 +5519,7 @@ const CONST = {
[onboardingChoices.CHAT_SPLIT]: {
message: 'Splitting bills with friends is as easy as sending a message. Here’s how.',
tasks: [
selfGuidedTourTask,
testDriveTask,
{
type: 'startChat',
autoCompleted: false,
Expand Down Expand Up @@ -6989,6 +6998,10 @@ const CONST = {
BILLING: {
TYPE_FAILED_2018: 'failed_2018',
},

TEST_DRIVE: {
ONBOARDING_TASK_NAME: getTestDriveTaskName(),
},
} as const;

type Country = keyof typeof CONST.ALL_COUNTRIES;
Expand All @@ -7008,6 +7021,7 @@ export type {
IOUType,
OnboardingPurpose,
OnboardingCompanySize,
OnboardingTaskLinks,
IOURequestType,
SubscriptionType,
FeedbackSurveyOptionID,
Expand Down
1 change: 1 addition & 0 deletions src/NAVIGATORS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default {
EXPLANATION_MODAL_NAVIGATOR: 'ExplanationModalNavigator',
MIGRATED_USER_MODAL_NAVIGATOR: 'MigratedUserModalNavigator',
TEST_DRIVE_MODAL_NAVIGATOR: 'TestDriveModalNavigator',
TEST_DRIVE_DEMO_NAVIGATOR: 'TestDriveDemoNavigator',
REPORTS_SPLIT_NAVIGATOR: 'ReportsSplitNavigator',
SETTINGS_SPLIT_NAVIGATOR: 'SettingsSplitNavigator',
WORKSPACE_SPLIT_NAVIGATOR: 'WorkspaceSplitNavigator',
Expand Down
1 change: 1 addition & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1894,6 +1894,7 @@ const ROUTES = {
WELCOME_VIDEO_ROOT: 'onboarding/welcome-video',
EXPLANATION_MODAL_ROOT: 'onboarding/explanation',
TEST_DRIVE_MODAL_ROOT: 'onboarding/test-drive',
TEST_DRIVE_DEMO_ROOT: 'onboarding/test-drive/demo',
WORKSPACE_CONFIRMATION: {
route: 'workspace/confirmation',
getRoute: (backTo?: string) => getUrlWithBackToParam(`workspace/confirmation`, backTo),
Expand Down
4 changes: 4 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,10 @@ const SCREENS = {
ROOT: 'TestDrive_Modal_Root',
},

TEST_DRIVE_DEMO: {
ROOT: 'TestDrive_Demo_Root',
},

I_KNOW_A_TEACHER: 'I_Know_A_Teacher',
INTRO_SCHOOL_PRINCIPAL: 'Intro_School_Principal',
I_AM_A_TEACHER: 'I_Am_A_Teacher',
Expand Down
23 changes: 23 additions & 0 deletions src/components/EmbeddedDemo/index.native.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import WebView from 'react-native-webview';
import type EmbeddedDemoProps from './types';

function EmbeddedDemo({url, webViewProps}: EmbeddedDemoProps) {
return (
<WebView
source={{
uri: url,
}}
originWhitelist={['http://', 'https://', 'about:']}
style={{
flex: 1,
}}
// eslint-disable-next-line react/jsx-props-no-spreading
{...webViewProps}
/>
);
}

EmbeddedDemo.displayName = 'EmbeddedDemo';

export default EmbeddedDemo;
18 changes: 18 additions & 0 deletions src/components/EmbeddedDemo/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import type EmbeddedDemoProps from './types';

function EmbeddedDemo({url, iframeTitle, iframeProps}: EmbeddedDemoProps) {
return (
<iframe
title={iframeTitle}
src={url}
style={{height: '100%', width: '100%', border: 'none'}}
// eslint-disable-next-line react/jsx-props-no-spreading
{...iframeProps}
/>
);
}

EmbeddedDemo.displayName = 'EmbeddedDemo';

export default EmbeddedDemo;
11 changes: 11 additions & 0 deletions src/components/EmbeddedDemo/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type {DetailedHTMLProps, IframeHTMLAttributes} from 'react';
import type {WebViewProps} from 'react-native-webview';

type EmbeddedDemoProps = {
url: string;
iframeTitle?: string;
iframeProps?: DetailedHTMLProps<IframeHTMLAttributes<HTMLIFrameElement>, HTMLIFrameElement> & Record<string, unknown>;
webViewProps?: WebViewProps;
};

export default EmbeddedDemoProps;
37 changes: 37 additions & 0 deletions src/components/TestDrive/TestDriveBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import {View} from 'react-native';
import Button from '@components/Button';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';

type TestDriveBannerProps = {
onPress: () => void;
};

function TestDriveBanner({onPress}: TestDriveBannerProps) {
const styles = useThemeStyles();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const {translate} = useLocalize();

return (
<View style={[styles.highlightBG, styles.gap2, styles.alignItemsCenter, styles.flexRow, styles.justifyContentCenter, {height: 40}]}>
<Text>
{shouldUseNarrowLayout
? translate('testDrive.banner.currentlyTestDrivingExpensify')
: `${translate('testDrive.banner.currentlyTestDrivingExpensify')}. ${translate('testDrive.banner.readyForTheRealThing')}`}
</Text>
<Button
text={translate('testDrive.banner.getStarted')}
small
success
onPress={onPress}
/>
</View>
);
}

TestDriveBanner.displayName = 'TestDriveBanner';

export default TestDriveBanner;
61 changes: 61 additions & 0 deletions src/components/TestDrive/TestDriveDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, {useCallback, useEffect, useState} from 'react';
import {InteractionManager} from 'react-native';
import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView';
import EmbeddedDemo from '@components/EmbeddedDemo';
import Modal from '@components/Modal';
import SafeAreaConsumer from '@components/SafeAreaConsumer';
import useEnvironment from '@hooks/useEnvironment';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import {completeTestDriveTask} from '@libs/actions/Task';
import Navigation from '@libs/Navigation/Navigation';
import {getTestDriveURL} from '@libs/TourUtils';
import CONST from '@src/CONST';
import TestDriveBanner from './TestDriveBanner';

function TestDriveDemo() {
const {environment} = useEnvironment();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const [isVisible, setIsVisible] = useState(false);

useEffect(() => {
InteractionManager.runAfterInteractions(() => {
setIsVisible(true);
completeTestDriveTask();
});
}, []);

const closeModal = useCallback(() => {
setIsVisible(false);
InteractionManager.runAfterInteractions(() => {
Navigation.goBack();
});
}, []);

return (
<SafeAreaConsumer>
{({paddingTop, paddingBottom}) => (
<Modal
isVisible={isVisible}
onClose={closeModal}
type={CONST.MODAL.MODAL_TYPE.FULLSCREEN}
style={{backgroundColor: 'white'}}
innerContainerStyle={{flex: 1, marginTop: paddingTop, marginBottom: paddingBottom}}
>
<TestDriveBanner onPress={closeModal} />
<FullPageOfflineBlockingView>
<EmbeddedDemo
url={getTestDriveURL(environment, shouldUseNarrowLayout)}
iframeTitle="Test Drive"
// eslint-disable-next-line @typescript-eslint/naming-convention
// iframeProps={{'data-navattic-demo-id': 'clzt21qk0000109l46k8tbtce'}}
/>
</FullPageOfflineBlockingView>
</Modal>
)}
</SafeAreaConsumer>
);
}

TestDriveDemo.displayName = 'TestDriveDemo';

export default TestDriveDemo;
7 changes: 6 additions & 1 deletion src/components/TestDriveModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import FeatureTrainingModal from './FeatureTrainingModal';

function TestDriveModal() {
Expand All @@ -14,7 +15,11 @@ function TestDriveModal() {
Navigation.dismissModal();
};

const navigateTestDriveDemo = () => {};
const navigateTestDriveDemo = () => {
setTimeout(() => {
Navigation.navigate(ROUTES.TEST_DRIVE_DEMO_ROOT);
}, 1000);
};

return (
<FeatureTrainingModal
Expand Down
5 changes: 5 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6234,6 +6234,11 @@ const translations = {
confirmText: 'Start test drive',
helpText: 'Skip',
},
banner: {
currentlyTestDrivingExpensify: "You're currently test driving Expensify",
readyForTheRealThing: 'Ready for the real thing?',
getStarted: 'Get started',
},
},
};

Expand Down
5 changes: 5 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6756,6 +6756,11 @@ const translations = {
confirmText: 'Iniciar prueba',
helpText: 'Omitir',
},
banner: {
currentlyTestDrivingExpensify: 'Actualmente estás probando Expensify',
readyForTheRealThing: '¿Listo para la versión real?',
getStarted: 'Comenzar',
},
},
};

Expand Down
6 changes: 6 additions & 0 deletions src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import OnboardingModalNavigator from './Navigators/OnboardingModalNavigator';
import RightModalNavigator from './Navigators/RightModalNavigator';
import TestDriveModalNavigator from './Navigators/TestDriveModalNavigator';
import WelcomeVideoModalNavigator from './Navigators/WelcomeVideoModalNavigator';
import TestDriveDemoNavigator from './TestDriveDemoNavigator';
import useRootNavigatorScreenOptions from './useRootNavigatorScreenOptions';

type AuthScreensProps = {
Expand Down Expand Up @@ -636,6 +637,11 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
options={rootNavigatorScreenOptions.basicModalNavigator}
component={TestDriveModalNavigator}
/>
<RootStack.Screen
name={NAVIGATORS.TEST_DRIVE_DEMO_NAVIGATOR}
options={rootNavigatorScreenOptions.basicModalNavigator}
component={TestDriveDemoNavigator}
/>
<RootStack.Screen
name={NAVIGATORS.FEATURE_TRANING_MODAL_NAVIGATOR}
options={rootNavigatorScreenOptions.basicModalNavigator}
Expand Down
29 changes: 29 additions & 0 deletions src/libs/Navigation/AppNavigator/TestDriveDemoNavigator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import {View} from 'react-native';
import NoDropZone from '@components/DragAndDrop/NoDropZone';
import TestDriveDemo from '@components/TestDrive/TestDriveDemo';
import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation';
import type {TestDriveDemoNavigatorParamList} from '@libs/Navigation/types';
import SCREENS from '@src/SCREENS';

const Stack = createPlatformStackNavigator<TestDriveDemoNavigatorParamList>();

function TestDriveDemoNavigator() {
return (
<NoDropZone>
<View>
<Stack.Navigator screenOptions={{headerShown: false, animation: Animations.SLIDE_FROM_RIGHT}}>
<Stack.Screen
name={SCREENS.TEST_DRIVE_DEMO.ROOT}
component={TestDriveDemo}
/>
</Stack.Navigator>
</View>
</NoDropZone>
);
}

TestDriveDemoNavigator.displayName = 'TestDriveDemoNavigator';

export default TestDriveDemoNavigator;
Loading
Loading