Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
2cd21fc
feat(testdrive): enable access to employees
pac-guerreiro Apr 28, 2025
c55cffb
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro Apr 28, 2025
308ce55
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro Apr 29, 2025
ca74842
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro Apr 29, 2025
46f353f
chore(testdrive): update translations
pac-guerreiro Apr 29, 2025
0369c99
chore: address eslint issues
pac-guerreiro Apr 29, 2025
e2e89e4
chore(testdrive): update onyx onboarding choices
pac-guerreiro Apr 29, 2025
52aa813
fix(testdrive): wrong default value
pac-guerreiro Apr 29, 2025
678cb3b
chore(testdrive): apply suggestions
pac-guerreiro Apr 30, 2025
d0453f9
refactor(testdrive): reuse same logic to set McTest and Test Drive re…
pac-guerreiro Apr 30, 2025
17a6fcf
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro Apr 30, 2025
cb80a7a
fix(testdrive): employee test drive modal description missing
pac-guerreiro Apr 30, 2025
369711e
refactor(testdrive): navigation after onboarding to display test driv…
pac-guerreiro Apr 30, 2025
50cc556
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro Apr 30, 2025
187c921
fix(testdrive): keyboard overlapping boss email input
pac-guerreiro Apr 30, 2025
cc436b3
fix(testdrive): keyboard not dismissed when pressing outside boss ema…
pac-guerreiro Apr 30, 2025
f4d1143
refactor(testdrive): apply suggestions
pac-guerreiro Apr 30, 2025
52a724f
chore(testdrive): add missing argument for asset extension
pac-guerreiro Apr 30, 2025
a38bdf9
fix(testdrive): modal not showing after onboarding on iOS
pac-guerreiro Apr 30, 2025
1c17d0a
refactor(testdrive): apply suggestions
pac-guerreiro May 6, 2025
82633fe
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 6, 2025
9fd512e
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 6, 2025
7e36ce6
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 6, 2025
11b2d04
chore(testdrive): apply suggestions
pac-guerreiro May 7, 2025
ae7c184
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 7, 2025
f75219f
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 7, 2025
e8811a3
refactor(testdrive): apply suggestions
pac-guerreiro May 7, 2025
fa00548
chore(testdrive): add translation for existing boss account error
pac-guerreiro May 7, 2025
21c287d
chore(testdrive): unify inner container styles between admin and empl…
pac-guerreiro May 7, 2025
5a502ac
fix(testdrive): stuck in test drive after boss email validation
pac-guerreiro May 7, 2025
87fc69e
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 7, 2025
9fccf57
chore(testdrive): add spanish translations for scan receipt
pac-guerreiro May 7, 2025
8e12955
fix(testdrive): spacing between modal title and description
pac-guerreiro May 7, 2025
a6809ed
feat(testdrive): add loading state when starting an employee test drive
pac-guerreiro May 7, 2025
81d1608
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 8, 2025
4ecc884
refactor(testdrive): apply suggestions
pac-guerreiro May 8, 2025
0694962
fix(testdrive): loading spinner disappearing before navigating to tes…
pac-guerreiro May 8, 2025
67468f0
chore(testdrive): remove optimistic comment once request is successful
pac-guerreiro May 9, 2025
8472cbe
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 9, 2025
16be5f4
fix(testdrive): missing offline feedback
pac-guerreiro May 9, 2025
ff1f503
fix(testdrive): not displaying first name on optimistic comment
pac-guerreiro May 9, 2025
734f3d0
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 9, 2025
71dd8f9
chore(testdrive): resolve eslint and jest issues
pac-guerreiro May 9, 2025
b14fc40
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 12, 2025
1f8ded6
fix(testdrive): ability to update test drive receipt
pac-guerreiro May 12, 2025
019d90b
fix(testdrive): offline indicator getting overlapped by confirm button
pac-guerreiro May 12, 2025
e0e935b
fix(testdrive): spacing above keyboard
pac-guerreiro May 12, 2025
43af5c1
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 12, 2025
557430b
refactor(testdrive): apply suggestions
pac-guerreiro May 13, 2025
7ddd8d9
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 13, 2025
da8cdec
chore(testdrive): rename test cases to make them more clear
pac-guerreiro May 13, 2025
cf53050
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 13, 2025
a230544
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 13, 2025
150334d
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 14, 2025
77ddc05
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 15, 2025
6ab8eb9
chore(testdrive): add testDriveCommentReportActionID request param
pac-guerreiro May 15, 2025
82514e2
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 15, 2025
a314966
refactor: apply suggestions
pac-guerreiro May 15, 2025
e5b3076
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 15, 2025
43eeb13
feat(testdrive): update fake receipt asset with less negative space
pac-guerreiro May 15, 2025
2d12cff
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
pac-guerreiro May 16, 2025
f1e790c
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
fabioh8010 May 18, 2025
50a0610
Send correct guidedSetupData in RequestMoney API
fabioh8010 May 18, 2025
24beb78
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 19, 2025
849d9fe
Merge branch 'main' into pac-guerreiro/feature/60745-test-drive-phase-2
fabioh8010 May 19, 2025
5d16b50
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 20, 2025
9acabfd
Change non admins to see the test drive bottom up modal
fabioh8010 May 20, 2025
dd45d91
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 20, 2025
edd36de
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 21, 2025
42b0662
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 21, 2025
242d2f2
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 21, 2025
48825f2
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 22, 2025
a15dc49
Fix test drive task message for employees
fabioh8010 May 22, 2025
fdf785d
Keep the previously boss email in the field when boing back from IOU …
fabioh8010 May 22, 2025
44dc4fc
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 22, 2025
5efc220
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 22, 2025
377ef77
Send guidedSetupData to CreateWorkspace API if admin is test drive re…
fabioh8010 May 22, 2025
f2ec950
Change F1 imagery
fabioh8010 May 22, 2025
4acd836
Dont show Free Trial banner for previously Test Drive Receivers
fabioh8010 May 22, 2025
bc243dc
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 22, 2025
a5b2e01
Fix lint
fabioh8010 May 22, 2025
518071d
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 23, 2025
3f4df18
Merge remote-tracking branch 'origin/main' into pac-guerreiro/feature…
fabioh8010 May 23, 2025
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/images/fast-track-cover.jpg
Binary file not shown.
Binary file added assets/images/fast-track-cover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 34 additions & 14 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const backendOnboardingChoices = {
ADMIN: 'newDotAdmin',
SUBMIT: 'newDotSubmit',
TRACK_WORKSPACE: 'newDotTrackWorkspace',
TEST_DRIVE_RECEIVER: 'testDriveReceiver',
} as const;

const onboardingChoices = {
Expand All @@ -118,21 +119,27 @@ const signupQualifiers = {
SMB: 'smb',
} as const;

const selfGuidedTourTask: OnboardingTask = {
const getTestDriveTaskName = (testDriveURL?: string) => (testDriveURL ? `Take a [test drive](${testDriveURL})` : 'Take a test drive');
const testDriveAdminTask: 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 getTestDriveTaskName = (testDriveURL?: string) => (testDriveURL ? `Take a [test drive](${testDriveURL})` : 'Take a test drive');
const testDriveTask: OnboardingTask = {
const testDriveEmployeeTask: OnboardingTask = {
type: 'viewTour',
autoCompleted: false,
mediaAttributes: {},
title: ({testDriveURL}) => getTestDriveTaskName(testDriveURL),
description: ({testDriveURL}) => `[Take a quick product tour](${testDriveURL}) to see why Expensify is the fastest way to do your expenses.`,
description: ({testDriveURL}) => `Take us for a [test drive](${testDriveURL}) and get your team *3 free months of Expensify!*`,
};
const createTestDriveAdminWorkspaceTask: OnboardingTask = {
type: 'createWorkspace',
autoCompleted: false,
mediaAttributes: {},
title: ({workspaceConfirmationLink}) => `[Create](${workspaceConfirmationLink}) a workspace`,
description: 'Create a workspace and configure the settings with the help of your setup specialist!',
};

const createWorkspaceTask: OnboardingTask = {
Expand Down Expand Up @@ -178,7 +185,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,
testDriveEmployeeTask,
{
type: 'submitExpense',
autoCompleted: false,
Expand All @@ -202,7 +209,7 @@ const onboardingEmployerOrSubmitMessage: OnboardingMessage = {
const combinedTrackSubmitOnboardingEmployerOrSubmitMessage: OnboardingMessage = {
...onboardingEmployerOrSubmitMessage,
tasks: [
selfGuidedTourTask,
testDriveEmployeeTask,
{
type: 'submitExpense',
autoCompleted: false,
Expand All @@ -227,7 +234,7 @@ const combinedTrackSubmitOnboardingEmployerOrSubmitMessage: OnboardingMessage =
const onboardingPersonalSpendMessage: OnboardingMessage = {
message: 'Here’s how to track your spend in a few clicks.',
tasks: [
selfGuidedTourTask,
testDriveEmployeeTask,
{
type: 'trackExpense',
autoCompleted: false,
Expand All @@ -251,7 +258,7 @@ const onboardingPersonalSpendMessage: OnboardingMessage = {
const combinedTrackSubmitOnboardingPersonalSpendMessage: OnboardingMessage = {
...onboardingPersonalSpendMessage,
tasks: [
selfGuidedTourTask,
testDriveEmployeeTask,
{
type: 'trackExpense',
autoCompleted: false,
Expand Down Expand Up @@ -303,6 +310,7 @@ type OnboardingTaskLinks = Partial<{
workspaceMoreFeaturesLink: string;
workspaceMembersLink: string;
workspaceAccountingLink: string;
workspaceConfirmationLink: string;
navatticURL: string;
testDriveURL: string;
corporateCardLink: string;
Expand Down Expand Up @@ -5240,7 +5248,7 @@ const CONST = {
VIDEO_URL: `${CLOUDFRONT_URL}/videos/guided-setup-track-business-v2.mp4`,
LEARN_MORE_LINK: `${USE_EXPENSIFY_URL}/track-expenses`,
},
TEST_DRIVE_COVER_ASPECT_RATIO: 500 / 300,
TEST_DRIVE_COVER_ASPECT_RATIO: 1000 / 508,
},

/**
Expand Down Expand Up @@ -5457,7 +5465,7 @@ const CONST = {
message: ({onboardingCompanySize: companySize}) => `Here is a task list I’d recommend for a company of your size with ${companySize} submitters:`,
tasks: [
createWorkspaceTask,
testDriveTask,
testDriveAdminTask,
{
type: 'addAccountingIntegration',
autoCompleted: false,
Expand Down Expand Up @@ -5608,7 +5616,7 @@ const CONST = {
[onboardingChoices.CHAT_SPLIT]: {
message: 'Splitting bills with friends is as easy as sending a message. Here’s how.',
tasks: [
selfGuidedTourTask,
testDriveEmployeeTask,
{
type: 'startChat',
autoCompleted: false,
Expand Down Expand Up @@ -5685,6 +5693,10 @@ const CONST = {
"Expensify is best known for expense and corporate card management, but we do a lot more than that. Let me know what you're interested in and I'll help get you started.",
tasks: [],
},
[onboardingChoices.TEST_DRIVE_RECEIVER]: {
message: "*You've got 3 months free! Get started below.*",
tasks: [testDriveAdminTask, createTestDriveAdminWorkspaceTask],
},
} satisfies Record<OnboardingPurpose, OnboardingMessage>,

CREATE_EXPENSE_ONBOARDING_MESSAGES: {
Expand Down Expand Up @@ -7074,6 +7086,7 @@ const CONST = {
GBR_RBR_CHAT: 'chatGBRRBR',
ACCOUNT_SWITCHER: 'accountSwitcher',
EXPENSE_REPORTS_FILTER: 'expenseReportsFilter',
SCAN_TEST_DRIVE_CONFIRMATION: 'scanTestDriveConfirmation',
},
CHANGE_POLICY_TRAINING_MODAL: 'changePolicyModal',
SMART_BANNER_HEIGHT: 152,
Expand Down Expand Up @@ -7123,6 +7136,12 @@ const CONST = {
ONBOARDING_TASK_NAME: getTestDriveTaskName(),
EMBEDDED_DEMO_WHITELIST: ['http://', 'https://', 'about:'] as string[],
EMBEDDED_DEMO_IFRAME_TITLE: 'Test Drive',
EMPLOYEE_FAKE_RECEIPT: {
AMOUNT: 2000,
CURRENCY: 'USD',
DESCRIPTION: 'My test drive receipt!',
MERCHANT: "Tommy's Tires",
},
},

SCHEDULE_CALL_STATUS: {
Expand Down Expand Up @@ -7157,6 +7176,7 @@ export type {
OnboardingInvite,
OnboardingAccounting,
IOUActionParams,
OnboardingMessage,
};

export {getTestDriveTaskName};
Expand Down
5 changes: 4 additions & 1 deletion src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1963,7 +1963,10 @@ const ROUTES = {
},
WELCOME_VIDEO_ROOT: 'onboarding/welcome-video',
EXPLANATION_MODAL_ROOT: 'onboarding/explanation',
TEST_DRIVE_MODAL_ROOT: 'onboarding/test-drive',
TEST_DRIVE_MODAL_ROOT: {
route: 'onboarding/test-drive',
getRoute: (bossEmail?: string) => `onboarding/test-drive${bossEmail ? `?bossEmail=${encodeURIComponent(bossEmail)}` : ''}` as const,
},
TEST_DRIVE_DEMO_ROOT: 'onboarding/test-drive/demo',
WORKSPACE_CONFIRMATION: {
route: 'workspace/confirmation',
Expand Down
66 changes: 54 additions & 12 deletions src/components/FeatureTrainingModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,15 @@ import CONST from '@src/CONST';
import type IconAsset from '@src/types/utils/IconAsset';
import Button from './Button';
import CheckboxWithLabel from './CheckboxWithLabel';
import FormAlertWithSubmitButton from './FormAlertWithSubmitButton';
import ImageSVG from './ImageSVG';
import Lottie from './Lottie';
import LottieAnimations from './LottieAnimations';
import type DotLottieAnimation from './LottieAnimations/types';
import Modal from './Modal';
import OfflineIndicator from './OfflineIndicator';
import RenderHTML from './RenderHTML';
import ScrollView from './ScrollView';
import Text from './Text';
import VideoPlayer from './VideoPlayer';

Expand Down Expand Up @@ -98,6 +102,24 @@ type BaseFeatureTrainingModalProps = {

/** Whether the modal image is a SVG */
shouldRenderSVG?: boolean;

/** Whether the modal description is written in HTML */
shouldRenderHTMLDescription?: boolean;

/** Whether the modal will be closed on confirm */
shouldCloseOnConfirm?: boolean;

/** Whether the modal should avoid the keyboard */
avoidKeyboard?: boolean;

/** Whether the modal content is scrollable */
shouldUseScrollView?: boolean;

/** Whether the modal is displaying a confirmation loading spinner (useful when fetching data from API during confirmation) */
shouldShowConfirmationLoader?: boolean;

/** Whether the user can confirm the tutorial while offline */
canConfirmWhileOffline?: boolean;
};

type FeatureTrainingModalVideoProps = {
Expand Down Expand Up @@ -155,6 +177,12 @@ function FeatureTrainingModal({
imageHeight,
isModalDisabled = true,
shouldRenderSVG = true,
shouldRenderHTMLDescription = false,
shouldCloseOnConfirm = true,
avoidKeyboard = false,
shouldUseScrollView = false,
shouldShowConfirmationLoader = false,
canConfirmWhileOffline = true,
}: FeatureTrainingModalProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
Expand Down Expand Up @@ -297,9 +325,11 @@ function FeatureTrainingModal({
}, [onClose, willShowAgain]);

const closeAndConfirmModal = useCallback(() => {
closeModal();
if (shouldCloseOnConfirm) {
closeModal();
}
onConfirm?.();
}, [onConfirm, closeModal]);
}, [shouldCloseOnConfirm, onConfirm, closeModal]);

/**
* Extracts values from the non-scraped attribute WEB_PROP_ATTR at build time
Expand All @@ -309,14 +339,17 @@ function FeatureTrainingModal({
*/
useLayoutEffect(parseFSAttributes, []);

const Wrapper = shouldUseScrollView ? ScrollView : View;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a difference in View and ScrollView. In ScrollView there is an extra space that kinda hides the submit button, can we remove it?

View ScrollView
Screenshot 2025-05-07 at 10 09 55 PM Screenshot 2025-05-07 at 10 09 44 PM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@s77rt this is what I get with the current changes:

View ScrollView
Simulator Screenshot - Expensify - App - 2025-05-09 at 15 32 28 Simulator Screenshot - Expensify - App - 2025-05-09 at 15 32 38

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'm referring to that extra space above the keyboard. Can it be removed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is coming from the 20px bottom padding that is passed to the modal in innerContainerStyle. I think we would need to keep the current View and add another wrapper that could be either ScrollView or Fragment. This is needed because we have to satisfy two conditions:

  1. On keyboard open, there should not no empty space above it
Screenshot 2025-05-11 at 8 44 58 PM
  1. On keyboard open and scroll down there should be still a 20px padding
Screenshot 2025-05-11 at 8 45 01 PM

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not tested this well but what I found working is the following:

  1. Change Wrapper to be ScrollView or Fragment and wrap the whole existing View
  2. Set Modal.innerContainerStyle.paddingBottom to 0
  3. Set Wrapper->View.style.paddingBottom to 20
const Wrapper = shouldUseScrollView ? ScrollView : Fragment;
<Modal innerContainerStyle={{paddingBottom: 0}} ... />
<View style={[styles.pb5, ...]} ... />

Copy link
Contributor Author

@pac-guerreiro pac-guerreiro May 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@s77rt I tried these changes and they seem to do the trick:
Screenshot 2025-05-12 at 18 08 31

Results:

442856461-da088978-99ad-4f32-8d25-cff102d804e3.mov

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Let's go with that but please confirm that this does not generate errors as we are passing contentContainerStyle to a Wrapper that could be a View which does not support this prop.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@s77rt I didn't see any console log with my changes, so it should be safe 😄

P.S: I added a condition so contentContainerStyle is undefined when shouldUseScrollView is false


return (
<Modal
avoidKeyboard={avoidKeyboard}
isVisible={isModalVisible}
type={onboardingIsMediumOrLargerScreenWidth ? CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE : CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED}
onClose={closeModal}
innerContainerStyle={{
boxShadow: 'none',
paddingBottom: 20,
...(shouldUseScrollView ? styles.pb0 : styles.pb5),
paddingTop: onboardingIsMediumOrLargerScreenWidth ? undefined : MODAL_PADDING,
...(onboardingIsMediumOrLargerScreenWidth
? // Override styles defined by MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE
Expand All @@ -329,8 +362,9 @@ function FeatureTrainingModal({
...modalInnerContainerStyle,
}}
>
<View
<Wrapper
style={[styles.mh100, onboardingIsMediumOrLargerScreenWidth && StyleUtils.getWidthStyle(width)]}
contentContainerStyle={shouldUseScrollView ? styles.pb5 : undefined}
fsClass={CONST.FULL_STORY.UNMASK}
testID={CONST.FULL_STORY.UNMASK}
>
Expand All @@ -341,7 +375,13 @@ function FeatureTrainingModal({
{!!title && !!description && (
<View style={[onboardingIsMediumOrLargerScreenWidth ? [styles.gap1, styles.mb8] : [styles.mb10], contentInnerContainerStyles]}>
{typeof title === 'string' ? <Text style={[styles.textHeadlineH1]}>{title}</Text> : title}
<Text style={styles.textSupporting}>{description}</Text>
{shouldRenderHTMLDescription ? (
<Text>
<RenderHTML html={description} />
</Text>
Comment on lines +379 to +381
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coming from #63274 , we shouldn’t wrap RenderHTML inside Text.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fedirjh I did it because without it the text was not being rendered at all! cb80a7a

Something must have changed in either RenderHTML or Text components.

) : (
<Text style={styles.textSupporting}>{description}</Text>
)}
{secondaryDescription.length > 0 && <Text style={[styles.textSupporting, styles.mt4]}>{secondaryDescription}</Text>}
{children}
</View>
Expand All @@ -363,17 +403,19 @@ function FeatureTrainingModal({
text={helpText}
/>
)}
<Button
large
success
pressOnEnter
onPress={closeAndConfirmModal}
text={confirmText}
<FormAlertWithSubmitButton
onSubmit={closeAndConfirmModal}
isLoading={shouldShowConfirmationLoader}
buttonText={confirmText}
enabledWhenOffline={canConfirmWhileOffline}
/>
{!canConfirmWhileOffline && <OfflineIndicator />}
</View>
</View>
</Wrapper>
</Modal>
);
}

export default FeatureTrainingModal;

export type {FeatureTrainingModalProps};
12 changes: 10 additions & 2 deletions src/components/MoneyRequestConfirmationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,17 @@ function MoneyRequestConfirmationList({
return transaction?.receipt?.isTestReceipt ?? false;
}, [transaction?.receipt?.isTestReceipt]);

const isTestDriveReceipt = useMemo(() => {
return transaction?.receipt?.isTestDriveReceipt ?? false;
}, [transaction?.receipt?.isTestDriveReceipt]);

const isManagerMcTestReceipt = useMemo(() => {
return Permissions.canUseManagerMcTest(betas) && selectedParticipantsProp.some((participant) => isSelectedManagerMcTest(participant.login));
}, [betas, selectedParticipantsProp]);

const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip} = useProductTrainingContext(
CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_CONFIRMATION,
Permissions.canUseManagerMcTest(betas) && selectedParticipantsProp.some((participant) => isSelectedManagerMcTest(participant.login)),
isTestDriveReceipt ? CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_DRIVE_CONFIRMATION : CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_CONFIRMATION,
isTestDriveReceipt || isManagerMcTestReceipt,
);

const policy = policyReal ?? policyDraft;
Expand Down
1 change: 1 addition & 0 deletions src/components/OnyxProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ OnyxProvider.displayName = 'OnyxProvider';
export default OnyxProvider;

export {
NetworkProvider,
usePersonalDetails,
NetworkContext,
BetasContext,
Expand Down
11 changes: 11 additions & 0 deletions src/components/ProductTrainingContext/TOOLTIPS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const {
GBR_RBR_CHAT,
ACCOUNT_SWITCHER,
EXPENSE_REPORTS_FILTER,
SCAN_TEST_DRIVE_CONFIRMATION,
} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;

type ProductTrainingTooltipName = ValueOf<typeof CONST.PRODUCT_TRAINING_TOOLTIP_NAMES>;
Expand Down Expand Up @@ -171,6 +172,16 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
priority: 1925,
shouldShow: ({isUserPolicyAdmin}) => isUserPolicyAdmin,
},
[SCAN_TEST_DRIVE_CONFIRMATION]: {
content: [
{text: 'productTrainingTooltip.scanTestDriveTooltip.part1', isBold: false},
{text: 'productTrainingTooltip.scanTestDriveTooltip.part2', isBold: true},
],
onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(SCAN_TEST_DRIVE_CONFIRMATION, isDismissedUsingCloseButton),
name: SCAN_TEST_DRIVE_CONFIRMATION,
priority: 1200,
shouldShow: () => true,
},
};

export default TOOLTIPS;
Expand Down
1 change: 1 addition & 0 deletions src/components/ProductTrainingContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ function ProductTrainingContextProvider({children}: ChildrenProps) {
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP &&
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP_MANAGER &&
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_CONFIRMATION &&
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_DRIVE_CONFIRMATION &&
isModalVisible
) {
return false;
Expand Down
27 changes: 27 additions & 0 deletions src/components/TestDrive/Modal/AdminTestDriveModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import {InteractionManager} from 'react-native';
import useLocalize from '@hooks/useLocalize';
import Navigation from '@libs/Navigation/Navigation';
import ROUTES from '@src/ROUTES';
import BaseTestDriveModal from './BaseTestDriveModal';

function AdminTestDriveModal() {
const {translate} = useLocalize();

const navigate = () => {
InteractionManager.runAfterInteractions(() => {
Navigation.navigate(ROUTES.TEST_DRIVE_DEMO_ROOT);
});
};

return (
<BaseTestDriveModal
description={translate('testDrive.modal.description')}
onConfirm={navigate}
/>
);
}

AdminTestDriveModal.displayName = 'AdminTestDriveModal';

export default AdminTestDriveModal;
Loading
Loading