From 202650423a8becbdbec3c210fc0987a323e3ad20 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Tue, 23 Jul 2024 18:13:49 +0200 Subject: [PATCH 01/33] add onboarding message for newly created admins --- src/CONST.ts | 87 ++++++++++++++++++++++++++++++--- src/libs/actions/Report.ts | 57 +++++++++++++++++++++ src/types/onyx/IntroSelected.ts | 12 +++-- 3 files changed, 147 insertions(+), 9 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index b809bdaacaf6..1efefabe4000 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4,6 +4,7 @@ import dateSubtract from 'date-fns/sub'; import Config from 'react-native-config'; import * as KeyCommand from 'react-native-key-command'; import type {ValueOf} from 'type-fest'; +import type {Video} from './libs/actions/Report'; import BankAccount from './libs/models/BankAccount'; import * as Url from './libs/Url'; import SCREENS from './SCREENS'; @@ -69,10 +70,34 @@ const onboardingChoices = { EMPLOYER: 'newDotEmployer', CHAT_SPLIT: 'newDotSplitChat', LOOKING_AROUND: 'newDotLookingAround', + ADMIN: 'newDotAdmin', + SUBMIT: 'newDotSubmit', }; type OnboardingPurposeType = ValueOf; +const onboardingInviteTypes = { + IOU: 'iou', + INVOICE: 'invoice', + CHAT: 'chat', +}; + +type OnboardingInviteType = ValueOf; + +type OnboardingTaskType = { + type: string; + autoCompleted: boolean; + title: string; + description: string | ((params: Partial<{adminsRoomLink: string; workspaceLink: string}>) => string); +}; + +type OnboardingMessageType = { + message: string; + video?: Video; + tasks: OnboardingTaskType[]; + type?: string; +}; + const CONST = { RECENT_WAYPOINTS_NUMBER: 20, DEFAULT_DB_NAME: 'OnyxDB', @@ -4122,6 +4147,7 @@ const CONST = { ONBOARDING_INTRODUCTION: 'Let’s get you set up 🔧', ONBOARDING_CHOICES: {...onboardingChoices}, + ONBOARDING_INVITE_TYPES: {...onboardingInviteTypes}, ACTIONABLE_TRACK_EXPENSE_WHISPER_MESSAGE: 'What would you like to do with this expense?', ONBOARDING_CONCIERGE: { [onboardingChoices.EMPLOYER]: @@ -4235,7 +4261,7 @@ const CONST = { type: 'meetGuide', autoCompleted: false, title: 'Meet your setup specialist', - description: ({adminsRoomLink}: {adminsRoomLink: string}) => + description: ({adminsRoomLink}) => `Meet your setup specialist, who can answer any questions as you get started with Expensify. Yes, a real human!\n` + '\n' + `Chat with the specialist in your [#admins room](${adminsRoomLink}).`, @@ -4244,7 +4270,7 @@ const CONST = { type: 'setupCategories', autoCompleted: false, title: 'Set up categories', - description: ({workspaceLink}: {workspaceLink: string}) => + description: ({workspaceLink}) => '*Set up categories* so your team can code expenses for easy reporting.\n' + '\n' + 'Here’s how to set up categories:\n' + @@ -4261,7 +4287,7 @@ const CONST = { type: 'addExpenseApprovals', autoCompleted: false, title: 'Add expense approvals', - description: ({workspaceLink}: {workspaceLink: string}) => + description: ({workspaceLink}) => '*Add expense approvals* to review your team’s spend and keep it under control.\n' + '\n' + 'Here’s how to add expense approvals:\n' + @@ -4278,7 +4304,7 @@ const CONST = { type: 'inviteTeam', autoCompleted: false, title: 'Invite your team', - description: ({workspaceLink}: {workspaceLink: string}) => + description: ({workspaceLink}) => '*Invite your team* to Expensify so they can start tracking expenses today.\n' + '\n' + 'Here’s how to invite your team:\n' + @@ -4381,12 +4407,61 @@ const CONST = { }, ], }, + [onboardingChoices.ADMIN]: { + message: "Hey 👋\nAs an admin, learn how to manage your team's workspace and submit expenses yourself.", + video: { + url: `${CLOUDFRONT_URL}/videos/guided-setup-manage-team-v2.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/guided-setup-manage-team.jpg`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + type: 'meetSetupSpecialist', + autoCompleted: false, + title: 'Meet your setup specialist', + description: + '*Meet your setup specialist* who can answer any questions as you get started with Expensify. Yes, a real human!' + + '\n' + + 'Chat with them in your #admins room or schedule a call today.', + }, + { + type: 'reviewWorkspaceSettings', + autoCompleted: false, + title: 'Review your workspace settings', + description: + "Here's how to review and update your workspace settings:" + + '\n' + + '1. Click your profile picture.' + + '2. Click *Workspaces* > [Your workspace].' + + '\n' + + "Make any changes there and we'll track them in the #admins room.", + }, + { + type: 'submitExpense', + autoCompleted: false, + title: 'Submit an expense', + description: + '*Submit an expense* by entering an amount or scanning a receipt.\n' + + '\n' + + 'Here’s how to submit an expense:\n' + + '\n' + + '1. Click the green *+* button.\n' + + '2. Choose *Submit expense*.\n' + + '3. Enter an amount or scan a receipt.\n' + + '4. Add your reimburser to the request.\n' + + '\n' + + 'Then, send your request and wait for that sweet “Cha-ching!” when it’s complete.', + }, + ], + }, [onboardingChoices.LOOKING_AROUND]: { message: "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: [], }, - }, + } satisfies Record, REPORT_FIELD_TITLE_FIELD_ID: 'text_title', @@ -5280,6 +5355,6 @@ type FeedbackSurveyOptionID = ValueOf; -export type {Country, IOUAction, IOUType, RateAndUnit, OnboardingPurposeType, IOURequestType, SubscriptionType, FeedbackSurveyOptionID}; +export type {Country, IOUAction, IOUType, RateAndUnit, OnboardingPurposeType, IOURequestType, SubscriptionType, FeedbackSurveyOptionID, OnboardingInviteType}; export default CONST; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 3060f53f12c3..7e9564a6c9c8 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -87,6 +87,7 @@ import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/NewRoomForm'; import type { + IntroSelected, InvitedEmailsToAccountIDs, NewGroupChatDraft, PersonalDetailsList, @@ -254,6 +255,12 @@ Onyx.connect({ callback: (val) => (quickAction = val), }); +let introSelected: OnyxEntry = {}; +Onyx.connect({ + key: ONYXKEYS.NVP_INTRO_SELECTED, + callback: (val) => (introSelected = val), +}); + registerPaginationConfig({ initialCommand: WRITE_COMMANDS.OPEN_REPORT, previousCommand: READ_COMMANDS.GET_OLDER_ACTIONS, @@ -719,6 +726,51 @@ function clearAvatarErrors(reportID: string) { }); } +// Add a helper function called getInviteOnboardingDetails to Report. That function will: +// Read the value of nvp_introSelected +// Check that it is set, if not return early +// Check that isInviteOnboardingComplete is false, if not return early +// Check that inviteType is not iou or invoice, if it is, return early +// Get the first and last names from personal details +// Get the correct onboarding message from ONBOARDING_MESSAGES (link) +// When choice is newDotSubmit we want to call ONBOARDING_MESSAGES[newDotEmployer] +// When choice is newDotAdmin we want to call ONBOARDING_MESSAGES[newDotAdmin] which will be added here. +// Optimistically set nvp_introSelected.isInviteOnboardingComplete to true +// Return the firstName, lastName, and onboardingMessage values + +function getInviteOnboardingDetails() { + if (!introSelected) { + return; + } + const {choice, isInviteOnboardingComplete, inviteType} = introSelected; + if (isInviteOnboardingComplete) { + return; + } + if (inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU || inviteType === CONST.ONBOARDING_INVITE_TYPES.INVOICE) { + return; + } + const personalDetails = allPersonalDetails?.[currentUserAccountID]; + const firstName = personalDetails?.firstName ?? ''; + const lastName = personalDetails?.lastName ?? ''; + + Onyx.set(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); + + if (choice === CONST.ONBOARDING_CHOICES.ADMIN) { + return { + firstName, + lastName, + onboardingMessage: CONST.ONBOARDING_MESSAGES.ADMIN, + }; + } + if (choice === CONST.ONBOARDING_CHOICES.SUBMIT) { + return { + firstName, + lastName, + onboardingMessage: CONST.ONBOARDING_MESSAGES.EMPLOYER, + }; + } +} + /** * Gets the latest page of report actions and updates the last read message * If a chat with the passed reportID is not found, we will create a chat based on the passed participantList @@ -751,6 +803,8 @@ function openReport( reportName: ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportName ?? CONST.REPORT.DEFAULT_REPORT_NAME, }; + const inviteOnboardingDetails = getInviteOnboardingDetails(); + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -806,6 +860,7 @@ function openReport( emailList: participantLoginList ? participantLoginList.join(',') : '', accountIDList: participantAccountIDList ? participantAccountIDList.join(',') : '', parentReportActionID, + ...inviteOnboardingDetails, }; if (ReportUtils.isGroupChat(newReportObject)) { @@ -3762,6 +3817,8 @@ function setGroupDraft(newGroupDraft: Partial) { Onyx.merge(ONYXKEYS.NEW_GROUP_CHAT_DRAFT, newGroupDraft); } +export type {Video}; + export { searchInServer, addComment, diff --git a/src/types/onyx/IntroSelected.ts b/src/types/onyx/IntroSelected.ts index 6850f651ca2a..0e1b4ec60ae4 100644 --- a/src/types/onyx/IntroSelected.ts +++ b/src/types/onyx/IntroSelected.ts @@ -1,9 +1,15 @@ -import type {OnboardingPurposeType} from '@src/CONST'; +import type {OnboardingInviteType, OnboardingPurposeType} from '@src/CONST'; /** Model of onboarding */ -type IntroSelected = { +type IntroSelected = Partial<{ /** The choice that the user selected in the engagement modal */ choice: OnboardingPurposeType; -}; + + /** The invite type */ + inviteType: OnboardingInviteType; + + /** Whether the onboarding is complete */ + isInviteOnboardingComplete: boolean; +}>; export default IntroSelected; From 9610a9f879a887b9abfaf3e79b885248ce8cf78e Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Fri, 26 Jul 2024 11:11:37 +0200 Subject: [PATCH 02/33] separate selectable onboarding choices from ones sent through API --- src/CONST.ts | 11 ++++++++++- src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index ff89a5a83d38..eb0b7c53de33 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -64,16 +64,24 @@ const chatTypes = { // Explicit type annotation is required const cardActiveStates: number[] = [2, 3, 4, 7]; -const onboardingChoices = { +const selectableOnboardingChoices = { PERSONAL_SPEND: 'newDotPersonalSpend', MANAGE_TEAM: 'newDotManageTeam', EMPLOYER: 'newDotEmployer', CHAT_SPLIT: 'newDotSplitChat', LOOKING_AROUND: 'newDotLookingAround', +}; + +const backendOnboardingChoices = { ADMIN: 'newDotAdmin', SUBMIT: 'newDotSubmit', }; +const onboardingChoices = { + ...selectableOnboardingChoices, + ...backendOnboardingChoices, +}; + type OnboardingPurposeType = ValueOf; const onboardingInviteTypes = { @@ -4209,6 +4217,7 @@ const CONST = { ONBOARDING_INTRODUCTION: 'Let’s get you set up 🔧', ONBOARDING_CHOICES: {...onboardingChoices}, + SELECTABLE_ONBOARDING_CHOICES: {...selectableOnboardingChoices}, ONBOARDING_INVITE_TYPES: {...onboardingInviteTypes}, ACTIONABLE_TRACK_EXPENSE_WHISPER_MESSAGE: 'What would you like to do with this expense?', ONBOARDING_CONCIERGE: { diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index d91110db62f8..6d12c33f749a 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -86,7 +86,7 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight}: B Navigation.navigate(ROUTES.ONBOARDING_PERSONAL_DETAILS); }, [selectedPurpose]); - const menuItems: MenuItemProps[] = Object.values(CONST.ONBOARDING_CHOICES).map((choice) => { + const menuItems: MenuItemProps[] = Object.values(CONST.SELECTABLE_ONBOARDING_CHOICES).map((choice) => { const translationKey = `onboarding.purpose.${choice}` as const; const isSelected = selectedPurpose === choice; return { From 2b923ceffc6118da01b805f5ec1851c4733e2c71 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Fri, 26 Jul 2024 12:07:09 +0200 Subject: [PATCH 03/33] correct indexing of onboarding messages for admin and employer --- src/libs/actions/Report.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 208733469578..bd6656b830e8 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -765,14 +765,14 @@ function getInviteOnboardingDetails() { return { firstName, lastName, - onboardingMessage: CONST.ONBOARDING_MESSAGES.ADMIN, + onboardingMessage: CONST.ONBOARDING_MESSAGES[CONST.ONBOARDING_CHOICES.ADMIN], }; } if (choice === CONST.ONBOARDING_CHOICES.SUBMIT) { return { firstName, lastName, - onboardingMessage: CONST.ONBOARDING_MESSAGES.EMPLOYER, + onboardingMessage: CONST.ONBOARDING_MESSAGES[CONST.ONBOARDING_CHOICES.EMPLOYER], }; } } From 0089f73313275df9f652e73e853c7a5816b3aee1 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 29 Jul 2024 11:10:24 +0200 Subject: [PATCH 04/33] clean-up comment and correct CONST onboarding message selector --- src/CONST.ts | 2 +- src/libs/actions/Report.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 9d956b3db026..97e8974c26ca 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4261,7 +4261,7 @@ const CONST = { }, ONBOARDING_MESSAGES: { - [onboardingChoices.EMPLOYER]: { + [onboardingChoices.EMPLOYER || onboardingChoices.SUBMIT]: { message: 'Getting paid back is as easy as sending a message. Let’s go over the basics.', video: { url: `${CLOUDFRONT_URL}/videos/guided-setup-get-paid-back-v2.mp4`, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index f669703ef379..7f07e4e095a0 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -744,6 +744,9 @@ function clearAvatarErrors(reportID: string) { // Optimistically set nvp_introSelected.isInviteOnboardingComplete to true // Return the firstName, lastName, and onboardingMessage values +/** + * Gets details for an invite onboarding if certain conditions are met + */ function getInviteOnboardingDetails() { if (!introSelected) { return; @@ -772,7 +775,7 @@ function getInviteOnboardingDetails() { return { firstName, lastName, - onboardingMessage: CONST.ONBOARDING_MESSAGES[CONST.ONBOARDING_CHOICES.EMPLOYER], + onboardingMessage: CONST.ONBOARDING_MESSAGES[CONST.ONBOARDING_CHOICES.SUBMIT], }; } } From bccc3b4bcf6c20630eee0b80df85ed0f9890ae2a Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:18:21 +0200 Subject: [PATCH 05/33] code review cleanup --- src/libs/actions/Report.ts | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 7f07e4e095a0..dd6c27b627c1 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -732,30 +732,16 @@ function clearAvatarErrors(reportID: string) { }); } -// Add a helper function called getInviteOnboardingDetails to Report. That function will: -// Read the value of nvp_introSelected -// Check that it is set, if not return early -// Check that isInviteOnboardingComplete is false, if not return early -// Check that inviteType is not iou or invoice, if it is, return early -// Get the first and last names from personal details -// Get the correct onboarding message from ONBOARDING_MESSAGES (link) -// When choice is newDotSubmit we want to call ONBOARDING_MESSAGES[newDotEmployer] -// When choice is newDotAdmin we want to call ONBOARDING_MESSAGES[newDotAdmin] which will be added here. -// Optimistically set nvp_introSelected.isInviteOnboardingComplete to true -// Return the firstName, lastName, and onboardingMessage values - /** * Gets details for an invite onboarding if certain conditions are met + * @returns firstName, lastName, and onboardingMessage values */ function getInviteOnboardingDetails() { if (!introSelected) { return; } const {choice, isInviteOnboardingComplete, inviteType} = introSelected; - if (isInviteOnboardingComplete) { - return; - } - if (inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU || inviteType === CONST.ONBOARDING_INVITE_TYPES.INVOICE) { + if (isInviteOnboardingComplete || inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU || inviteType === CONST.ONBOARDING_INVITE_TYPES.INVOICE) { return; } const personalDetails = allPersonalDetails?.[currentUserAccountID]; @@ -764,18 +750,11 @@ function getInviteOnboardingDetails() { Onyx.set(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); - if (choice === CONST.ONBOARDING_CHOICES.ADMIN) { - return { - firstName, - lastName, - onboardingMessage: CONST.ONBOARDING_MESSAGES[CONST.ONBOARDING_CHOICES.ADMIN], - }; - } - if (choice === CONST.ONBOARDING_CHOICES.SUBMIT) { + if (choice === CONST.ONBOARDING_CHOICES.ADMIN || choice == CONST.ONBOARDING_CHOICES.SUBMIT) { return { firstName, lastName, - onboardingMessage: CONST.ONBOARDING_MESSAGES[CONST.ONBOARDING_CHOICES.SUBMIT], + onboardingMessage: CONST.ONBOARDING_MESSAGES[choice], }; } } From 8b1e02faa9d943e0e70ddd54293f176a904d940c Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Tue, 30 Jul 2024 09:32:26 +0200 Subject: [PATCH 06/33] fix lint errors --- src/libs/actions/Report.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index dd6c27b627c1..9dacdff51946 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -741,7 +741,7 @@ function getInviteOnboardingDetails() { return; } const {choice, isInviteOnboardingComplete, inviteType} = introSelected; - if (isInviteOnboardingComplete || inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU || inviteType === CONST.ONBOARDING_INVITE_TYPES.INVOICE) { + if (isInviteOnboardingComplete ?? inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU ?? inviteType === CONST.ONBOARDING_INVITE_TYPES.INVOICE) { return; } const personalDetails = allPersonalDetails?.[currentUserAccountID]; @@ -750,7 +750,7 @@ function getInviteOnboardingDetails() { Onyx.set(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); - if (choice === CONST.ONBOARDING_CHOICES.ADMIN || choice == CONST.ONBOARDING_CHOICES.SUBMIT) { + if (choice === CONST.ONBOARDING_CHOICES.ADMIN || choice === CONST.ONBOARDING_CHOICES.SUBMIT) { return { firstName, lastName, From 7a507fb72c63cd52ec4f0e0616c97ee8622cf001 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Fri, 9 Aug 2024 15:10:31 +0200 Subject: [PATCH 07/33] fix CONST definition for multiple onboarding choices using the same message --- src/CONST.ts | 89 +++++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 43 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index bf78ba09054a..e8323ff428bc 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -83,6 +83,50 @@ const onboardingChoices = { ...backendOnboardingChoices, }; +const onboardingEmployerOrSubmitMessage = { + message: 'Getting paid back is as easy as sending a message. Let’s go over the basics.', + video: { + url: `${CLOUDFRONT_URL}/videos/guided-setup-get-paid-back-v2.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/guided-setup-get-paid-back.jpg`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + type: 'submitExpense', + autoCompleted: false, + title: 'Submit an expense', + description: + '*Submit an expense* by entering an amount or scanning a receipt.\n' + + '\n' + + 'Here’s how to submit an expense:\n' + + '\n' + + '1. Click the green *+* button.\n' + + '2. Choose *Submit expense*.\n' + + '3. Enter an amount or scan a receipt.\n' + + '4. Add your reimburser to the request.\n' + + '\n' + + 'Then, send your request and wait for that sweet “Cha-ching!” when it’s complete.', + }, + { + type: 'enableWallet', + autoCompleted: false, + title: 'Enable your wallet', + description: + 'You’ll need to *enable your Expensify Wallet* to get paid back. Don’t worry, it’s easy!\n' + + '\n' + + 'Here’s how to set up your wallet:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Click *Wallet* > *Enable wallet*.\n' + + '3. Connect your bank account.\n' + + '\n' + + 'Once that’s done, you can request money from anyone and get paid back right into your personal bank account.', + }, + ], +}; + type OnboardingPurposeType = ValueOf; const onboardingInviteTypes = { @@ -4278,49 +4322,8 @@ const CONST = { }, ONBOARDING_MESSAGES: { - [onboardingChoices.EMPLOYER || onboardingChoices.SUBMIT]: { - message: 'Getting paid back is as easy as sending a message. Let’s go over the basics.', - video: { - url: `${CLOUDFRONT_URL}/videos/guided-setup-get-paid-back-v2.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/guided-setup-get-paid-back.jpg`, - duration: 55, - width: 1280, - height: 960, - }, - tasks: [ - { - type: 'submitExpense', - autoCompleted: false, - title: 'Submit an expense', - description: - '*Submit an expense* by entering an amount or scanning a receipt.\n' + - '\n' + - 'Here’s how to submit an expense:\n' + - '\n' + - '1. Click the green *+* button.\n' + - '2. Choose *Submit expense*.\n' + - '3. Enter an amount or scan a receipt.\n' + - '4. Add your reimburser to the request.\n' + - '\n' + - 'Then, send your request and wait for that sweet “Cha-ching!” when it’s complete.', - }, - { - type: 'enableWallet', - autoCompleted: false, - title: 'Enable your wallet', - description: - 'You’ll need to *enable your Expensify Wallet* to get paid back. Don’t worry, it’s easy!\n' + - '\n' + - 'Here’s how to set up your wallet:\n' + - '\n' + - '1. Click your profile picture.\n' + - '2. Click *Wallet* > *Enable wallet*.\n' + - '3. Connect your bank account.\n' + - '\n' + - 'Once that’s done, you can request money from anyone and get paid back right into your personal bank account.', - }, - ], - }, + [onboardingChoices.EMPLOYER]: {...onboardingEmployerOrSubmitMessage}, + [onboardingChoices.SUBMIT]: {...onboardingEmployerOrSubmitMessage}, [onboardingChoices.MANAGE_TEAM]: { message: 'Here are some important tasks to help get your team’s expenses under control.', video: { From 2cb743cd93fae923bb1b0fbbec87408aaa5a67dc Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 19 Aug 2024 03:53:00 +0200 Subject: [PATCH 08/33] correct guidedSetupParams for this onboarding flow --- src/libs/API/parameters/OpenReportParams.ts | 1 + src/libs/actions/Report.ts | 161 +++++++++++++++++++- 2 files changed, 157 insertions(+), 5 deletions(-) diff --git a/src/libs/API/parameters/OpenReportParams.ts b/src/libs/API/parameters/OpenReportParams.ts index 0f9cb7075fce..63ee06b58367 100644 --- a/src/libs/API/parameters/OpenReportParams.ts +++ b/src/libs/API/parameters/OpenReportParams.ts @@ -14,6 +14,7 @@ type OpenReportParams = { chatType?: string; optimisticAccountIDList?: string; file?: File | CustomRNImageManipulatorResult; + guidedSetupObject?: string; }; export default OpenReportParams; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 85210544e63d..92c8a14ed905 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -750,8 +750,6 @@ function getInviteOnboardingDetails() { const firstName = personalDetails?.firstName ?? ''; const lastName = personalDetails?.lastName ?? ''; - Onyx.set(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); - if (choice === CONST.ONBOARDING_CHOICES.ADMIN || choice === CONST.ONBOARDING_CHOICES.SUBMIT) { return { firstName, @@ -793,8 +791,6 @@ function openReport( reportName: ReportConnection.getAllReports()?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]?.reportName ?? CONST.REPORT.DEFAULT_REPORT_NAME, }; - const inviteOnboardingDetails = getInviteOnboardingDetails(); - const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -844,13 +840,168 @@ function openReport( }, ]; + const inviteOnboardingDetails = getInviteOnboardingDetails(); + + const isAccountIDOdd = AccountUtils.isAccountIDOddNumber(currentUserAccountID ?? 0); + const targetEmail = isAccountIDOdd ? CONST.EMAIL.NOTIFICATIONS : CONST.EMAIL.CONCIERGE; + + const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; + const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID, currentUserAccountID]); + const {reportID: targetChatReportID = '', policyID: targetChatPolicyID = ''} = targetChatReport ?? {}; + + // Introductory message + const introductionComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ONBOARDING_INTRODUCTION, undefined, actorAccountID); + const introductionCommentAction: OptimisticAddCommentReportAction = introductionComment.reportAction; + const introductionMessage: AddCommentOrAttachementParams = { + reportID: targetChatReportID, + reportActionID: introductionCommentAction.reportActionID, + reportComment: introductionComment.commentText, + }; + + // Text message + const textComment = ReportUtils.buildOptimisticAddCommentReportAction(inviteOnboardingDetails?.onboardingMessage?.message, undefined, actorAccountID, 1); + const textCommentAction: OptimisticAddCommentReportAction = textComment.reportAction; + const textMessage: AddCommentOrAttachementParams = { + reportID: targetChatReportID, + reportActionID: textCommentAction.reportActionID, + reportComment: textComment.commentText, + }; + + let videoCommentAction: OptimisticAddCommentReportAction | null = null; + let videoMessage: AddCommentOrAttachementParams | null = null; + if (inviteOnboardingDetails?.onboardingMessage?.video) { + const videoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID, 2); + videoCommentAction = videoComment.reportAction; + videoMessage = { + reportID: targetChatReportID, + reportActionID: videoCommentAction.reportActionID, + reportComment: videoComment.commentText, + }; + } + + const guidedSetupData: GuidedSetupData = [ + {type: 'message', ...introductionMessage}, + {type: 'message', ...textMessage}, + ]; + + const guidedSetupObject = { + ...inviteOnboardingDetails, + guidedSetupData, + }; + + if (inviteOnboardingDetails?.onboardingMessage?.video && videoCommentAction && videoMessage) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [videoCommentAction.reportActionID]: videoCommentAction as ReportAction, + }, + }); + + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [videoCommentAction.reportActionID]: {pendingAction: null}, + }, + }); + + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [videoCommentAction.reportActionID]: { + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), + } as ReportAction, + }, + }); + + guidedSetupData.push({type: 'video', ...inviteOnboardingDetails?.onboardingMessage?.video, ...videoMessage}); + } + + optimisticData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${targetChatReportID}`, + value: { + lastMentionedTime: DateUtils.getDBTime(), + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [introductionCommentAction.reportActionID]: introductionCommentAction as ReportAction, + [textCommentAction.reportActionID]: textCommentAction as ReportAction, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.NVP_INTRO_SELECTED, + value: {choice: introSelected?.choice}, + }, + ); + + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [introductionCommentAction.reportActionID]: {pendingAction: null}, + [textCommentAction.reportActionID]: {pendingAction: null}, + }, + }); + + let failureReport: Partial = { + lastMessageTranslationKey: '', + lastMessageText: '', + lastVisibleActionCreated: '', + hasOutstandingChildTask: false, + }; + const {lastMessageText = '', lastMessageTranslationKey = ''} = ReportActionsUtils.getLastVisibleMessage(targetChatReportID); + if (lastMessageText || lastMessageTranslationKey) { + const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(targetChatReportID); + const lastVisibleActionCreated = lastVisibleAction?.created; + const lastActorAccountID = lastVisibleAction?.actorAccountID; + failureReport = { + lastMessageTranslationKey, + lastMessageText, + lastVisibleActionCreated, + lastActorAccountID, + }; + } + + failureData.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${targetChatReportID}`, + value: failureReport, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [introductionCommentAction.reportActionID]: { + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), + } as ReportAction, + [textCommentAction.reportActionID]: { + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), + } as ReportAction, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.NVP_INTRO_SELECTED, + value: {choice: null}, + }, + ); + const parameters: OpenReportParams = { reportID, reportActionID, emailList: participantLoginList ? participantLoginList.join(',') : '', accountIDList: participantAccountIDList ? participantAccountIDList.join(',') : '', parentReportActionID, - ...inviteOnboardingDetails, + guidedSetupObject: JSON.stringify(guidedSetupObject), }; if (ReportUtils.isGroupChat(newReportObject)) { From bc16df0f8d73433cbc0a6c330772d7520caaa690 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:09:53 +0200 Subject: [PATCH 09/33] set as const and fix typing, remove unused imports --- src/CONST.ts | 12 ++++++------ src/libs/actions/Report.ts | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 6a744927ee2f..ab2d6be7cc9d 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -71,17 +71,17 @@ const selectableOnboardingChoices = { EMPLOYER: 'newDotEmployer', CHAT_SPLIT: 'newDotSplitChat', LOOKING_AROUND: 'newDotLookingAround', -}; +} as const; const backendOnboardingChoices = { ADMIN: 'newDotAdmin', SUBMIT: 'newDotSubmit', -}; +} as const; const onboardingChoices = { ...selectableOnboardingChoices, ...backendOnboardingChoices, -}; +} as const; const onboardingEmployerOrSubmitMessage = { message: 'Getting paid back is as easy as sending a message. Let’s go over the basics.', @@ -133,7 +133,7 @@ const onboardingInviteTypes = { IOU: 'iou', INVOICE: 'invoice', CHAT: 'chat', -}; +} as const; type OnboardingInviteType = ValueOf; @@ -4318,8 +4318,8 @@ const CONST = { }, ONBOARDING_MESSAGES: { - [onboardingChoices.EMPLOYER]: {...onboardingEmployerOrSubmitMessage}, - [onboardingChoices.SUBMIT]: {...onboardingEmployerOrSubmitMessage}, + [onboardingChoices.EMPLOYER]: onboardingEmployerOrSubmitMessage, + [onboardingChoices.SUBMIT]: onboardingEmployerOrSubmitMessage, [onboardingChoices.MANAGE_TEAM]: { message: 'Here are some important tasks to help get your team’s expenses under control.', video: { diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index ee49bad0a575..60a96091ef71 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -859,7 +859,7 @@ function openReport( const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID, currentUserAccountID]); - const {reportID: targetChatReportID = '', policyID: targetChatPolicyID = ''} = targetChatReport ?? {}; + const {reportID: targetChatReportID = ''} = targetChatReport ?? {}; // Introductory message const introductionComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ONBOARDING_INTRODUCTION, undefined, actorAccountID); @@ -3543,7 +3543,7 @@ function completeOnboarding( let videoCommentAction: OptimisticAddCommentReportAction | null = null; let videoMessage: AddCommentOrAttachementParams | null = null; - if (data.video) { + if ('video' in data && data.video) { const videoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID, 2); videoCommentAction = videoComment.reportAction; videoMessage = { @@ -3824,7 +3824,7 @@ function completeOnboarding( {type: 'message', ...textMessage}, ]; - if (data.video && videoCommentAction && videoMessage) { + if ('video' in data && data.video && videoCommentAction && videoMessage) { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, From 23b909ebd268bdbf707a93470b429685ca33b67f Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:15:35 +0200 Subject: [PATCH 10/33] fix typecheck errors after as const --- src/ONYXKEYS.ts | 3 ++- src/pages/OnboardingWork/BaseOnboardingWork.tsx | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 19439ddd1f40..06ae0abf12ed 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -5,6 +5,7 @@ import type * as OnyxTypes from './types/onyx'; import type Onboarding from './types/onyx/Onboarding'; import type AssertTypesEqual from './types/utils/AssertTypesEqual'; import type DeepValueOf from './types/utils/DeepValueOf'; +import { OnboardingPurposeType } from './CONST'; /** * This is a file containing constants for all the top level keys in our store @@ -881,7 +882,7 @@ type OnyxValuesMapping = { [ONYXKEYS.MAX_CANVAS_AREA]: number; [ONYXKEYS.MAX_CANVAS_HEIGHT]: number; [ONYXKEYS.MAX_CANVAS_WIDTH]: number; - [ONYXKEYS.ONBOARDING_PURPOSE_SELECTED]: string; + [ONYXKEYS.ONBOARDING_PURPOSE_SELECTED]: OnboardingPurposeType; [ONYXKEYS.ONBOARDING_ERROR_MESSAGE]: string; [ONYXKEYS.ONBOARDING_POLICY_ID]: string; [ONYXKEYS.ONBOARDING_ADMINS_CHAT_REPORT_ID]: string; diff --git a/src/pages/OnboardingWork/BaseOnboardingWork.tsx b/src/pages/OnboardingWork/BaseOnboardingWork.tsx index cf0809c8fb99..0796a055b058 100644 --- a/src/pages/OnboardingWork/BaseOnboardingWork.tsx +++ b/src/pages/OnboardingWork/BaseOnboardingWork.tsx @@ -25,8 +25,6 @@ import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/WorkForm'; import type {BaseOnboardingWorkOnyxProps, BaseOnboardingWorkProps} from './types'; -const OPEN_WORK_PAGE_PURPOSES = [CONST.ONBOARDING_CHOICES.MANAGE_TEAM]; - function BaseOnboardingWork({shouldUseNativeStyles, onboardingPurposeSelected, onboardingPolicyID, route}: BaseOnboardingWorkProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -80,7 +78,7 @@ function BaseOnboardingWork({shouldUseNativeStyles, onboardingPurposeSelected, o Date: Tue, 3 Sep 2024 15:23:11 +0200 Subject: [PATCH 11/33] fix lint errors --- src/ONYXKEYS.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 06ae0abf12ed..0e2fbfeb61dc 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -1,11 +1,11 @@ import type {ValueOf} from 'type-fest'; import type CONST from './CONST'; +import type {OnboardingPurposeType} from './CONST'; import type * as FormTypes from './types/form'; import type * as OnyxTypes from './types/onyx'; import type Onboarding from './types/onyx/Onboarding'; import type AssertTypesEqual from './types/utils/AssertTypesEqual'; import type DeepValueOf from './types/utils/DeepValueOf'; -import { OnboardingPurposeType } from './CONST'; /** * This is a file containing constants for all the top level keys in our store From ac707beb8574a5810abb8ed41b9711362c69da96 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 4 Sep 2024 21:27:04 +0200 Subject: [PATCH 12/33] refactor the onboarding message code inside openReport --- src/libs/actions/Report.ts | 462 ++++++++++++++++++++++++++----------- 1 file changed, 327 insertions(+), 135 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 8e669486ee42..7cf3dbe3cb8e 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -757,10 +757,12 @@ function getInviteOnboardingDetails() { if (!introSelected) { return; } + const {choice, isInviteOnboardingComplete, inviteType} = introSelected; if (isInviteOnboardingComplete ?? inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU ?? inviteType === CONST.ONBOARDING_INVITE_TYPES.INVOICE) { return; } + const personalDetails = allPersonalDetails?.[currentUserAccountID]; const firstName = personalDetails?.firstName ?? ''; const lastName = personalDetails?.lastName ?? ''; @@ -855,169 +857,359 @@ function openReport( }, ]; + const parameters: OpenReportParams = { + reportID, + reportActionID, + emailList: participantLoginList ? participantLoginList.join(',') : '', + accountIDList: participantAccountIDList ? participantAccountIDList.join(',') : '', + parentReportActionID, + }; + const inviteOnboardingDetails = getInviteOnboardingDetails(); + if (!isEmptyObject(inviteOnboardingDetails)) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.SET, + key: ONYXKEYS.NVP_INTRO_SELECTED, + value: {isInviteOnboardingComplete: true}, + }); - const isAccountIDOdd = AccountUtils.isAccountIDOddNumber(currentUserAccountID ?? 0); - const targetEmail = isAccountIDOdd ? CONST.EMAIL.NOTIFICATIONS : CONST.EMAIL.CONCIERGE; + const isAccountIDOdd = AccountUtils.isAccountIDOddNumber(currentUserAccountID ?? 0); + const targetEmail = isAccountIDOdd ? CONST.EMAIL.NOTIFICATIONS : CONST.EMAIL.CONCIERGE; - const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; - const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID, currentUserAccountID]); - const {reportID: targetChatReportID = ''} = targetChatReport ?? {}; + // If the target report isn't opened, the permission field will not exist. So we should add the fallback permission for task report + const fallbackPermission = isAccountIDOdd ? [CONST.REPORT.PERMISSIONS.READ] : [CONST.REPORT.PERMISSIONS.READ, CONST.REPORT.PERMISSIONS.WRITE]; - // Introductory message - const introductionComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ONBOARDING_INTRODUCTION, undefined, actorAccountID); - const introductionCommentAction: OptimisticAddCommentReportAction = introductionComment.reportAction; - const introductionMessage: AddCommentOrAttachementParams = { - reportID: targetChatReportID, - reportActionID: introductionCommentAction.reportActionID, - reportComment: introductionComment.commentText, - }; + const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; + const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID, currentUserAccountID]); + const {reportID: targetChatReportID = '', policyID: targetChatPolicyID = ''} = targetChatReport ?? {}; - // Text message - const textComment = ReportUtils.buildOptimisticAddCommentReportAction(inviteOnboardingDetails?.onboardingMessage?.message, undefined, actorAccountID, 1); - const textCommentAction: OptimisticAddCommentReportAction = textComment.reportAction; - const textMessage: AddCommentOrAttachementParams = { - reportID: targetChatReportID, - reportActionID: textCommentAction.reportActionID, - reportComment: textComment.commentText, - }; - - let videoCommentAction: OptimisticAddCommentReportAction | null = null; - let videoMessage: AddCommentOrAttachementParams | null = null; - if (inviteOnboardingDetails?.onboardingMessage?.video) { - const videoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID, 2); - videoCommentAction = videoComment.reportAction; - videoMessage = { + // Introductory message + const introductionComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ONBOARDING_INTRODUCTION, undefined, actorAccountID); + const introductionCommentAction: OptimisticAddCommentReportAction = introductionComment.reportAction; + const introductionMessage: AddCommentOrAttachementParams = { reportID: targetChatReportID, - reportActionID: videoCommentAction.reportActionID, - reportComment: videoComment.commentText, + reportActionID: introductionCommentAction.reportActionID, + reportComment: introductionComment.commentText, }; - } - const guidedSetupData: GuidedSetupData = [ - {type: 'message', ...introductionMessage}, - {type: 'message', ...textMessage}, - ]; + // Text message + const textComment = ReportUtils.buildOptimisticAddCommentReportAction(inviteOnboardingDetails.onboardingMessage.message, undefined, actorAccountID, 1); + const textCommentAction: OptimisticAddCommentReportAction = textComment.reportAction; + const textMessage: AddCommentOrAttachementParams = { + reportID: targetChatReportID, + reportActionID: textCommentAction.reportActionID, + reportComment: textComment.commentText, + }; - const guidedSetupObject = { - ...inviteOnboardingDetails, - guidedSetupData, - }; + let videoCommentAction: OptimisticAddCommentReportAction | null = null; + let videoMessage: AddCommentOrAttachementParams | null = null; + if ('video' in inviteOnboardingDetails.onboardingMessage && inviteOnboardingDetails.onboardingMessage.video) { + const videoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID, 2); + videoCommentAction = videoComment.reportAction; + videoMessage = { + reportID: targetChatReportID, + reportActionID: videoCommentAction.reportActionID, + reportComment: videoComment.commentText, + }; + } - if (inviteOnboardingDetails?.onboardingMessage?.video && videoCommentAction && videoMessage) { - optimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [videoCommentAction.reportActionID]: videoCommentAction as ReportAction, - }, + const tasksData = inviteOnboardingDetails.onboardingMessage.tasks.map((task, index) => { + const taskDescription = task.description; + const currentTask = ReportUtils.buildOptimisticTaskReport( + actorAccountID, + currentUserAccountID, + targetChatReportID, + task.title, + taskDescription, + targetChatPolicyID, + CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + ); + const taskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(targetEmail); + const taskReportAction = ReportUtils.buildOptimisticTaskCommentReportAction( + currentTask.reportID, + task.title, + 0, + `task for ${task.title}`, + targetChatReportID, + actorAccountID, + index + 3, + ); + currentTask.parentReportActionID = taskReportAction.reportAction.reportActionID; + + const completedTaskReportAction = task.autoCompleted + ? ReportUtils.buildOptimisticTaskReportAction(currentTask.reportID, CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED, 'marked as complete', actorAccountID, 2) + : null; + + return { + task, + currentTask, + taskCreatedAction, + taskReportAction, + taskDescription: currentTask.description, + completedTaskReportAction, + }; }); - successData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [videoCommentAction.reportActionID]: {pendingAction: null}, + const tasksForParameters = tasksData.map(({task, currentTask, taskCreatedAction, taskReportAction, taskDescription, completedTaskReportAction}) => ({ + type: 'task', + task: task.type, + taskReportID: currentTask.reportID, + parentReportID: currentTask.parentReportID ?? '-1', + parentReportActionID: taskReportAction.reportAction.reportActionID, + assigneeChatReportID: '', + createdTaskReportActionID: taskCreatedAction.reportActionID, + completedTaskReportActionID: completedTaskReportAction?.reportActionID ?? undefined, + title: currentTask.reportName ?? '', + description: taskDescription ?? '', + })); + + const hasOutstandingChildTask = tasksData.some((task) => !task.completedTaskReportAction); + + const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, taskDescription, completedTaskReportAction}) => { + acc.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [taskReportAction.reportAction.reportActionID]: taskReportAction.reportAction as ReportAction, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, + value: { + ...currentTask, + description: taskDescription, + pendingFields: { + createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + reportName: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + description: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + managerID: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + isOptimisticReport: true, + managerID: currentUserAccountID, + permissions: targetChatReport?.permissions ?? fallbackPermission, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction, + }, + }, + ); + + if (completedTaskReportAction) { + acc.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [completedTaskReportAction.reportActionID]: completedTaskReportAction as ReportAction, + }, + }); + + acc.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, + value: { + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, + managerID: currentUserAccountID, + }, + }); + } + + return acc; + }, []); + + const tasksForFailureData = tasksData.reduce((acc, {currentTask, taskReportAction}) => { + acc.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [taskReportAction.reportAction.reportActionID]: { + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), + } as ReportAction, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: null, + }, + ); + + return acc; + }, []); + + const tasksForSuccessData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, completedTaskReportAction}) => { + acc.push( + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [taskReportAction.reportAction.reportActionID]: {pendingAction: null}, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, + value: { + pendingFields: { + createChat: null, + reportName: null, + description: null, + managerID: null, + }, + isOptimisticReport: false, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [taskCreatedAction.reportActionID]: {pendingAction: null}, + }, + }, + ); + + if (completedTaskReportAction) { + acc.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [completedTaskReportAction.reportActionID]: {pendingAction: null}, + }, + }); + } + + return acc; + }, []); + + optimisticData.push( + ...tasksForOptimisticData, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${targetChatReportID}`, + value: { + lastMentionedTime: DateUtils.getDBTime(), + hasOutstandingChildTask, + }, }, - }); + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [introductionCommentAction.reportActionID]: introductionCommentAction as ReportAction, + [textCommentAction.reportActionID]: textCommentAction as ReportAction, + }, + }, + ); - failureData.push({ + successData.push( + ...tasksForSuccessData, + { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, value: { - [videoCommentAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), - } as ReportAction, + [introductionCommentAction.reportActionID]: {pendingAction: null}, + [textCommentAction.reportActionID]: {pendingAction: null}, }, }); - guidedSetupData.push({type: 'video', ...inviteOnboardingDetails?.onboardingMessage?.video, ...videoMessage}); - } + let failureReport: Partial = { + lastMessageTranslationKey: '', + lastMessageText: '', + lastVisibleActionCreated: '', + hasOutstandingChildTask: false, + }; + const {lastMessageText = '', lastMessageTranslationKey = ''} = ReportActionsUtils.getLastVisibleMessage(targetChatReportID); + if (lastMessageText || lastMessageTranslationKey) { + const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(targetChatReportID); + const lastVisibleActionCreated = lastVisibleAction?.created; + const lastActorAccountID = lastVisibleAction?.actorAccountID; + failureReport = { + lastMessageTranslationKey, + lastMessageText, + lastVisibleActionCreated, + lastActorAccountID, + }; + } - optimisticData.push( - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${targetChatReportID}`, - value: { - lastMentionedTime: DateUtils.getDBTime(), + failureData.push( + ...tasksForFailureData, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${targetChatReportID}`, + value: failureReport, }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [introductionCommentAction.reportActionID]: introductionCommentAction as ReportAction, - [textCommentAction.reportActionID]: textCommentAction as ReportAction, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [introductionCommentAction.reportActionID]: { + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), + } as ReportAction, + [textCommentAction.reportActionID]: { + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), + } as ReportAction, + }, }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.NVP_INTRO_SELECTED, - value: {choice: introSelected?.choice}, - }, - ); + ); - successData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [introductionCommentAction.reportActionID]: {pendingAction: null}, - [textCommentAction.reportActionID]: {pendingAction: null}, - }, - }); + const guidedSetupData: GuidedSetupData = [ + {type: 'message', ...introductionMessage}, + {type: 'message', ...textMessage}, + ]; - let failureReport: Partial = { - lastMessageTranslationKey: '', - lastMessageText: '', - lastVisibleActionCreated: '', - hasOutstandingChildTask: false, - }; - const {lastMessageText = '', lastMessageTranslationKey = ''} = ReportActionsUtils.getLastVisibleMessage(targetChatReportID); - if (lastMessageText || lastMessageTranslationKey) { - const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(targetChatReportID); - const lastVisibleActionCreated = lastVisibleAction?.created; - const lastActorAccountID = lastVisibleAction?.actorAccountID; - failureReport = { - lastMessageTranslationKey, - lastMessageText, - lastVisibleActionCreated, - lastActorAccountID, + if ('video' in inviteOnboardingDetails.onboardingMessage && inviteOnboardingDetails.onboardingMessage.video && videoCommentAction && videoMessage) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [videoCommentAction.reportActionID]: videoCommentAction as ReportAction, + }, + }); + + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [videoCommentAction.reportActionID]: {pendingAction: null}, + }, + }); + + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [videoCommentAction.reportActionID]: { + errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), + } as ReportAction, + }, + }); + + guidedSetupData.push({type: 'video', ...inviteOnboardingDetails.onboardingMessage.video, ...videoMessage}); + } + + guidedSetupData.push(...tasksForParameters); + + const guidedSetupObject = { + ...inviteOnboardingDetails, + guidedSetupData, }; - } - failureData.push( - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${targetChatReportID}`, - value: failureReport, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [introductionCommentAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), - } as ReportAction, - [textCommentAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), - } as ReportAction, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.NVP_INTRO_SELECTED, - value: {choice: null}, - }, - ); + console.log("#test", "xd"); - const parameters: OpenReportParams = { - reportID, - reportActionID, - emailList: participantLoginList ? participantLoginList.join(',') : '', - accountIDList: participantAccountIDList ? participantAccountIDList.join(',') : '', - parentReportActionID, - guidedSetupObject: JSON.stringify(guidedSetupObject), - }; + parameters.guidedSetupObject = JSON.stringify(guidedSetupObject); + } if (ReportUtils.isGroupChat(newReportObject)) { parameters.chatType = CONST.REPORT.CHAT_TYPE.GROUP; From cd04c889031bafdb7bf4813473ffd71ef6cbae23 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 4 Sep 2024 21:28:07 +0200 Subject: [PATCH 13/33] fix prettier issues --- src/libs/actions/Report.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 7cf3dbe3cb8e..46a336ae7ced 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1113,9 +1113,7 @@ function openReport( }, ); - successData.push( - ...tasksForSuccessData, - { + successData.push(...tasksForSuccessData, { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, value: { @@ -1206,7 +1204,7 @@ function openReport( guidedSetupData, }; - console.log("#test", "xd"); + console.log('#test', 'xd'); parameters.guidedSetupObject = JSON.stringify(guidedSetupObject); } From 511050ad60626fa9145a76a48e2ba9d38c7246d6 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 4 Sep 2024 23:02:11 +0200 Subject: [PATCH 14/33] replace unnecessary data duplicate with completeGuidedSetup call --- src/libs/actions/Report.ts | 353 ++----------------------------------- 1 file changed, 13 insertions(+), 340 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 46a336ae7ced..ac7b38a1b67c 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -769,9 +769,12 @@ function getInviteOnboardingDetails() { if (choice === CONST.ONBOARDING_CHOICES.ADMIN || choice === CONST.ONBOARDING_CHOICES.SUBMIT) { return { - firstName, - lastName, - onboardingMessage: CONST.ONBOARDING_MESSAGES[choice], + choice, + data: CONST.ONBOARDING_MESSAGES[choice], + personalDetails: { + firstName, + lastName + }, }; } } @@ -866,347 +869,17 @@ function openReport( }; const inviteOnboardingDetails = getInviteOnboardingDetails(); - if (!isEmptyObject(inviteOnboardingDetails)) { - optimisticData.push({ - onyxMethod: Onyx.METHOD.SET, - key: ONYXKEYS.NVP_INTRO_SELECTED, - value: {isInviteOnboardingComplete: true}, - }); - - const isAccountIDOdd = AccountUtils.isAccountIDOddNumber(currentUserAccountID ?? 0); - const targetEmail = isAccountIDOdd ? CONST.EMAIL.NOTIFICATIONS : CONST.EMAIL.CONCIERGE; - - // If the target report isn't opened, the permission field will not exist. So we should add the fallback permission for task report - const fallbackPermission = isAccountIDOdd ? [CONST.REPORT.PERMISSIONS.READ] : [CONST.REPORT.PERMISSIONS.READ, CONST.REPORT.PERMISSIONS.WRITE]; - - const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; - const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID, currentUserAccountID]); - const {reportID: targetChatReportID = '', policyID: targetChatPolicyID = ''} = targetChatReport ?? {}; - - // Introductory message - const introductionComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ONBOARDING_INTRODUCTION, undefined, actorAccountID); - const introductionCommentAction: OptimisticAddCommentReportAction = introductionComment.reportAction; - const introductionMessage: AddCommentOrAttachementParams = { - reportID: targetChatReportID, - reportActionID: introductionCommentAction.reportActionID, - reportComment: introductionComment.commentText, - }; - - // Text message - const textComment = ReportUtils.buildOptimisticAddCommentReportAction(inviteOnboardingDetails.onboardingMessage.message, undefined, actorAccountID, 1); - const textCommentAction: OptimisticAddCommentReportAction = textComment.reportAction; - const textMessage: AddCommentOrAttachementParams = { - reportID: targetChatReportID, - reportActionID: textCommentAction.reportActionID, - reportComment: textComment.commentText, - }; - - let videoCommentAction: OptimisticAddCommentReportAction | null = null; - let videoMessage: AddCommentOrAttachementParams | null = null; - if ('video' in inviteOnboardingDetails.onboardingMessage && inviteOnboardingDetails.onboardingMessage.video) { - const videoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID, 2); - videoCommentAction = videoComment.reportAction; - videoMessage = { - reportID: targetChatReportID, - reportActionID: videoCommentAction.reportActionID, - reportComment: videoComment.commentText, - }; - } - - const tasksData = inviteOnboardingDetails.onboardingMessage.tasks.map((task, index) => { - const taskDescription = task.description; - const currentTask = ReportUtils.buildOptimisticTaskReport( - actorAccountID, - currentUserAccountID, - targetChatReportID, - task.title, - taskDescription, - targetChatPolicyID, - CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, - ); - const taskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(targetEmail); - const taskReportAction = ReportUtils.buildOptimisticTaskCommentReportAction( - currentTask.reportID, - task.title, - 0, - `task for ${task.title}`, - targetChatReportID, - actorAccountID, - index + 3, - ); - currentTask.parentReportActionID = taskReportAction.reportAction.reportActionID; - - const completedTaskReportAction = task.autoCompleted - ? ReportUtils.buildOptimisticTaskReportAction(currentTask.reportID, CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED, 'marked as complete', actorAccountID, 2) - : null; - - return { - task, - currentTask, - taskCreatedAction, - taskReportAction, - taskDescription: currentTask.description, - completedTaskReportAction, - }; - }); - - const tasksForParameters = tasksData.map(({task, currentTask, taskCreatedAction, taskReportAction, taskDescription, completedTaskReportAction}) => ({ - type: 'task', - task: task.type, - taskReportID: currentTask.reportID, - parentReportID: currentTask.parentReportID ?? '-1', - parentReportActionID: taskReportAction.reportAction.reportActionID, - assigneeChatReportID: '', - createdTaskReportActionID: taskCreatedAction.reportActionID, - completedTaskReportActionID: completedTaskReportAction?.reportActionID ?? undefined, - title: currentTask.reportName ?? '', - description: taskDescription ?? '', - })); - - const hasOutstandingChildTask = tasksData.some((task) => !task.completedTaskReportAction); - - const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, taskDescription, completedTaskReportAction}) => { - acc.push( - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [taskReportAction.reportAction.reportActionID]: taskReportAction.reportAction as ReportAction, - }, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, - value: { - ...currentTask, - description: taskDescription, - pendingFields: { - createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - reportName: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - description: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - managerID: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, - }, - isOptimisticReport: true, - managerID: currentUserAccountID, - permissions: targetChatReport?.permissions ?? fallbackPermission, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: { - [taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction, - }, - }, - ); - - if (completedTaskReportAction) { - acc.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: { - [completedTaskReportAction.reportActionID]: completedTaskReportAction as ReportAction, - }, - }); - - acc.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, - value: { - stateNum: CONST.REPORT.STATE_NUM.APPROVED, - statusNum: CONST.REPORT.STATUS_NUM.APPROVED, - managerID: currentUserAccountID, - }, - }); - } - - return acc; - }, []); - - const tasksForFailureData = tasksData.reduce((acc, {currentTask, taskReportAction}) => { - acc.push( - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [taskReportAction.reportAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), - } as ReportAction, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, - value: null, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: null, - }, - ); - - return acc; - }, []); + if (inviteOnboardingDetails && !introSelected?.isInviteOnboardingComplete) { + const {choice, data, personalDetails} = inviteOnboardingDetails; + completeOnboarding(choice, data, {...personalDetails}); - const tasksForSuccessData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, completedTaskReportAction}) => { - acc.push( - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [taskReportAction.reportAction.reportActionID]: {pendingAction: null}, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, - value: { - pendingFields: { - createChat: null, - reportName: null, - description: null, - managerID: null, - }, - isOptimisticReport: false, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: { - [taskCreatedAction.reportActionID]: {pendingAction: null}, - }, - }, - ); - - if (completedTaskReportAction) { - acc.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: { - [completedTaskReportAction.reportActionID]: {pendingAction: null}, - }, - }); - } - - return acc; - }, []); + Onyx.set(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); - optimisticData.push( - ...tasksForOptimisticData, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${targetChatReportID}`, - value: { - lastMentionedTime: DateUtils.getDBTime(), - hasOutstandingChildTask, - }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [introductionCommentAction.reportActionID]: introductionCommentAction as ReportAction, - [textCommentAction.reportActionID]: textCommentAction as ReportAction, - }, - }, - ); - - successData.push(...tasksForSuccessData, { + optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [introductionCommentAction.reportActionID]: {pendingAction: null}, - [textCommentAction.reportActionID]: {pendingAction: null}, - }, + key: ONYXKEYS.NVP_INTRO_SELECTED, + value: {isInviteOnboardingComplete: true}, }); - - let failureReport: Partial = { - lastMessageTranslationKey: '', - lastMessageText: '', - lastVisibleActionCreated: '', - hasOutstandingChildTask: false, - }; - const {lastMessageText = '', lastMessageTranslationKey = ''} = ReportActionsUtils.getLastVisibleMessage(targetChatReportID); - if (lastMessageText || lastMessageTranslationKey) { - const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(targetChatReportID); - const lastVisibleActionCreated = lastVisibleAction?.created; - const lastActorAccountID = lastVisibleAction?.actorAccountID; - failureReport = { - lastMessageTranslationKey, - lastMessageText, - lastVisibleActionCreated, - lastActorAccountID, - }; - } - - failureData.push( - ...tasksForFailureData, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${targetChatReportID}`, - value: failureReport, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [introductionCommentAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), - } as ReportAction, - [textCommentAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), - } as ReportAction, - }, - }, - ); - - const guidedSetupData: GuidedSetupData = [ - {type: 'message', ...introductionMessage}, - {type: 'message', ...textMessage}, - ]; - - if ('video' in inviteOnboardingDetails.onboardingMessage && inviteOnboardingDetails.onboardingMessage.video && videoCommentAction && videoMessage) { - optimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [videoCommentAction.reportActionID]: videoCommentAction as ReportAction, - }, - }); - - successData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [videoCommentAction.reportActionID]: {pendingAction: null}, - }, - }); - - failureData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [videoCommentAction.reportActionID]: { - errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('report.genericAddCommentFailureMessage'), - } as ReportAction, - }, - }); - - guidedSetupData.push({type: 'video', ...inviteOnboardingDetails.onboardingMessage.video, ...videoMessage}); - } - - guidedSetupData.push(...tasksForParameters); - - const guidedSetupObject = { - ...inviteOnboardingDetails, - guidedSetupData, - }; - - console.log('#test', 'xd'); - - parameters.guidedSetupObject = JSON.stringify(guidedSetupObject); } if (ReportUtils.isGroupChat(newReportObject)) { From fd3663b7856a00ac2eada1f3e136d57c5462d867 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 4 Sep 2024 23:02:59 +0200 Subject: [PATCH 15/33] fix prettier --- src/libs/actions/Report.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index ac7b38a1b67c..cc636b3f8822 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -773,7 +773,7 @@ function getInviteOnboardingDetails() { data: CONST.ONBOARDING_MESSAGES[choice], personalDetails: { firstName, - lastName + lastName, }, }; } From ee3ab24374adf23693343aa202aa0dac3a73f396 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Thu, 5 Sep 2024 08:57:01 +0200 Subject: [PATCH 16/33] allow split_chat option to be picked during non-organic guided setup --- src/libs/actions/Report.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index cc636b3f8822..0c6dbe4da687 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -767,7 +767,7 @@ function getInviteOnboardingDetails() { const firstName = personalDetails?.firstName ?? ''; const lastName = personalDetails?.lastName ?? ''; - if (choice === CONST.ONBOARDING_CHOICES.ADMIN || choice === CONST.ONBOARDING_CHOICES.SUBMIT) { + if (choice === CONST.ONBOARDING_CHOICES.ADMIN || choice === CONST.ONBOARDING_CHOICES.SUBMIT || choice === CONST.ONBOARDING_CHOICES.CHAT_SPLIT) { return { choice, data: CONST.ONBOARDING_MESSAGES[choice], From d65fd44218f75f0529f92f81a5f61d359a6f97de Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:20:08 +0200 Subject: [PATCH 17/33] fix typescript convention errors and move types --- src/CONST.ts | 19 +++++++++++++------ src/ONYXKEYS.ts | 3 +-- .../parameters/CompleteGuidedSetupParams.ts | 4 ++-- src/libs/actions/Report.ts | 4 ++-- src/libs/actions/Welcome.ts | 4 ++-- src/pages/OnboardingPersonalDetails/types.ts | 4 ++-- src/pages/OnboardingWork/types.ts | 4 ++-- .../report/SystemChatReportFooterMessage.tsx | 5 ++--- src/types/onyx/IntroSelected.ts | 5 +++-- src/types/onyx/index.ts | 2 ++ 10 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 138016e5c43c..2d2c5a826c9f 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -127,7 +127,7 @@ const onboardingEmployerOrSubmitMessage = { ], }; -type OnboardingPurposeType = ValueOf; +type OnboardingPurpose = ValueOf; const onboardingInviteTypes = { IOU: 'iou', @@ -137,17 +137,24 @@ const onboardingInviteTypes = { type OnboardingInviteType = ValueOf; -type OnboardingTaskType = { +type OnboardingTask = { type: string; autoCompleted: boolean; title: string; description: string | ((params: Partial<{adminsRoomLink: string; workspaceCategoriesLink: string; workspaceMoreFeaturesLink: string; workspaceMembersLink: string}>) => string); }; -type OnboardingMessageType = { +type OnboardingMessage = { + /** Text message that will be displayed first */ message: string; + + /** Video object to be displayed after initial description message */ video?: Video; - tasks: OnboardingTaskType[]; + + /** List of tasks connected with the message, they will have a checkbox and a separate report for more information */ + tasks: OnboardingTask[]; + + /** Type of task described in a string format */ type?: string; }; @@ -4642,7 +4649,7 @@ 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: [], }, - } satisfies Record, + } satisfies Record, REPORT_FIELD_TITLE_FIELD_ID: 'text_title', @@ -5714,6 +5721,6 @@ type FeedbackSurveyOptionID = ValueOf; type CancellationType = ValueOf; -export type {Country, IOUAction, IOUType, RateAndUnit, OnboardingPurposeType, IOURequestType, SubscriptionType, FeedbackSurveyOptionID, CancellationType, OnboardingInviteType}; +export type {Country, IOUAction, IOUType, RateAndUnit, OnboardingPurpose, IOURequestType, SubscriptionType, FeedbackSurveyOptionID, CancellationType, OnboardingInviteType}; export default CONST; diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 8704b1b1a85e..895045c19a53 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -1,6 +1,5 @@ import type {ValueOf} from 'type-fest'; import type CONST from './CONST'; -import type {OnboardingPurposeType} from './CONST'; import type * as FormTypes from './types/form'; import type * as OnyxTypes from './types/onyx'; import type Onboarding from './types/onyx/Onboarding'; @@ -891,7 +890,7 @@ type OnyxValuesMapping = { [ONYXKEYS.MAX_CANVAS_AREA]: number; [ONYXKEYS.MAX_CANVAS_HEIGHT]: number; [ONYXKEYS.MAX_CANVAS_WIDTH]: number; - [ONYXKEYS.ONBOARDING_PURPOSE_SELECTED]: OnboardingPurposeType; + [ONYXKEYS.ONBOARDING_PURPOSE_SELECTED]: OnyxTypes.OnboardingPurpose; [ONYXKEYS.ONBOARDING_ERROR_MESSAGE]: string; [ONYXKEYS.ONBOARDING_POLICY_ID]: string; [ONYXKEYS.ONBOARDING_ADMINS_CHAT_REPORT_ID]: string; diff --git a/src/libs/API/parameters/CompleteGuidedSetupParams.ts b/src/libs/API/parameters/CompleteGuidedSetupParams.ts index 8e1273ac6053..d312d66f5d95 100644 --- a/src/libs/API/parameters/CompleteGuidedSetupParams.ts +++ b/src/libs/API/parameters/CompleteGuidedSetupParams.ts @@ -1,11 +1,11 @@ -import type {OnboardingPurposeType} from '@src/CONST'; +import type {OnboardingPurpose} from '@src/types/onyx'; type CompleteGuidedSetupParams = { firstName: string; lastName: string; actorAccountID: number; guidedSetupData: string; - engagementChoice: OnboardingPurposeType; + engagementChoice: OnboardingPurpose; }; export default CompleteGuidedSetupParams; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 5283dffc4a09..9ddaad63c703 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -83,7 +83,6 @@ import {doesReportBelongToWorkspace} from '@libs/ReportUtils'; import shouldSkipDeepLinkNavigation from '@libs/shouldSkipDeepLinkNavigation'; import Visibility from '@libs/Visibility'; import CONFIG from '@src/CONFIG'; -import type {OnboardingPurposeType} from '@src/CONST'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; @@ -93,6 +92,7 @@ import type { IntroSelected, InvitedEmailsToAccountIDs, NewGroupChatDraft, + OnboardingPurpose, PersonalDetailsList, PolicyReportField, QuickAction, @@ -3367,7 +3367,7 @@ function getReportPrivateNote(reportID: string | undefined) { } function completeOnboarding( - engagementChoice: OnboardingPurposeType, + engagementChoice: OnboardingPurpose, data: ValueOf, { firstName, diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index d54314ae6f05..8a8ec10b30b4 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -5,9 +5,9 @@ import * as API from '@libs/API'; import {WRITE_COMMANDS} from '@libs/API/types'; import Navigation from '@libs/Navigation/Navigation'; import variables from '@styles/variables'; -import type {OnboardingPurposeType} from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {OnboardingPurpose} from '@src/types/onyx'; import type Onboarding from '@src/types/onyx/Onboarding'; import type TryNewDot from '@src/types/onyx/TryNewDot'; @@ -136,7 +136,7 @@ function checkOnboardingDataReady() { resolveOnboardingFlowStatus(); } -function setOnboardingPurposeSelected(value: OnboardingPurposeType) { +function setOnboardingPurposeSelected(value: OnboardingPurpose) { Onyx.set(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, value ?? null); } diff --git a/src/pages/OnboardingPersonalDetails/types.ts b/src/pages/OnboardingPersonalDetails/types.ts index 5371f289e743..7fcb2e52e3cd 100644 --- a/src/pages/OnboardingPersonalDetails/types.ts +++ b/src/pages/OnboardingPersonalDetails/types.ts @@ -3,14 +3,14 @@ import type {StackScreenProps} from '@react-navigation/stack'; import type {OnyxEntry} from 'react-native-onyx'; import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; import type {OnboardingModalNavigatorParamList} from '@libs/Navigation/types'; -import type {OnboardingPurposeType} from '@src/CONST'; import type SCREENS from '@src/SCREENS'; +import type {OnboardingPurpose} from '@src/types/onyx'; type OnboardingPersonalDetailsProps = Record & StackScreenProps; type BaseOnboardingPersonalDetailsOnyxProps = { /** Saved onboarding purpose selected by the user */ - onboardingPurposeSelected: OnyxEntry; + onboardingPurposeSelected: OnyxEntry; /** Saved onboarding admin chat report ID */ onboardingAdminsChatReportID: OnyxEntry; diff --git a/src/pages/OnboardingWork/types.ts b/src/pages/OnboardingWork/types.ts index d87843944cd6..480fcc812e09 100644 --- a/src/pages/OnboardingWork/types.ts +++ b/src/pages/OnboardingWork/types.ts @@ -1,14 +1,14 @@ import type {StackScreenProps} from '@react-navigation/stack'; import type {OnyxEntry} from 'react-native-onyx'; import type {OnboardingModalNavigatorParamList} from '@libs/Navigation/types'; -import type {OnboardingPurposeType} from '@src/CONST'; import type SCREENS from '@src/SCREENS'; +import type {OnboardingPurpose} from '@src/types/onyx'; type OnboardingWorkProps = Record & StackScreenProps; type BaseOnboardingWorkOnyxProps = { /** Saved onboarding purpose selected by the user */ - onboardingPurposeSelected: OnyxEntry; + onboardingPurposeSelected: OnyxEntry; /** Saved onboarding purpose selected by the user */ onboardingPolicyID: OnyxEntry; diff --git a/src/pages/home/report/SystemChatReportFooterMessage.tsx b/src/pages/home/report/SystemChatReportFooterMessage.tsx index 4775b7ff6487..d5c07cbeb450 100644 --- a/src/pages/home/report/SystemChatReportFooterMessage.tsx +++ b/src/pages/home/report/SystemChatReportFooterMessage.tsx @@ -10,15 +10,14 @@ import useThemeStyles from '@hooks/useThemeStyles'; import * as PolicyUtils from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; import * as ReportInstance from '@userActions/Report'; -import type {OnboardingPurposeType} from '@src/CONST'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {Policy as PolicyType} from '@src/types/onyx'; +import type {OnboardingPurpose, Policy as PolicyType} from '@src/types/onyx'; type SystemChatReportFooterMessageOnyxProps = { /** Saved onboarding purpose selected by the user */ - choice: OnyxEntry; + choice: OnyxEntry; /** The list of this user's policies */ policies: OnyxCollection; diff --git a/src/types/onyx/IntroSelected.ts b/src/types/onyx/IntroSelected.ts index 0e1b4ec60ae4..82b76f64b8f9 100644 --- a/src/types/onyx/IntroSelected.ts +++ b/src/types/onyx/IntroSelected.ts @@ -1,9 +1,10 @@ -import type {OnboardingInviteType, OnboardingPurposeType} from '@src/CONST'; +import type {OnboardingInviteType} from '@src/CONST'; +import type {OnboardingPurpose} from './index'; /** Model of onboarding */ type IntroSelected = Partial<{ /** The choice that the user selected in the engagement modal */ - choice: OnboardingPurposeType; + choice: OnboardingPurpose; /** The invite type */ inviteType: OnboardingInviteType; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 0073e47bb65c..69e5559c1a65 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -1,3 +1,4 @@ +import type {OnboardingPurpose} from '@src/CONST'; import type Account from './Account'; import type AccountData from './AccountData'; import type {ApprovalWorkflowOnyx} from './ApprovalWorkflow'; @@ -228,4 +229,5 @@ export type { WorkspaceTooltip, CardFeeds, ImportedSpreadsheet, + OnboardingPurpose, }; From 2bf730ef08286b06d673b86cb6f26d4394df9921 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:55:35 +0200 Subject: [PATCH 18/33] remove partial in favor of optional params --- src/types/onyx/IntroSelected.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/types/onyx/IntroSelected.ts b/src/types/onyx/IntroSelected.ts index 82b76f64b8f9..c8b025c02c0e 100644 --- a/src/types/onyx/IntroSelected.ts +++ b/src/types/onyx/IntroSelected.ts @@ -2,15 +2,15 @@ import type {OnboardingInviteType} from '@src/CONST'; import type {OnboardingPurpose} from './index'; /** Model of onboarding */ -type IntroSelected = Partial<{ +type IntroSelected = { /** The choice that the user selected in the engagement modal */ - choice: OnboardingPurpose; + choice?: OnboardingPurpose; /** The invite type */ - inviteType: OnboardingInviteType; + inviteType?: OnboardingInviteType; /** Whether the onboarding is complete */ - isInviteOnboardingComplete: boolean; -}>; + isInviteOnboardingComplete?: boolean; +}; export default IntroSelected; From bcb360594719ecd37fa1a701012934f5538a5c0f Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:17:12 +0200 Subject: [PATCH 19/33] separate completeOnboarding onyx data preparation into a function --- src/libs/actions/Report.ts | 64 ++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 9ddaad63c703..e7856f66c4cf 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -767,14 +767,13 @@ function getInviteOnboardingDetails() { const firstName = personalDetails?.firstName ?? ''; const lastName = personalDetails?.lastName ?? ''; + Onyx.merge(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); + if (choice === CONST.ONBOARDING_CHOICES.ADMIN || choice === CONST.ONBOARDING_CHOICES.SUBMIT || choice === CONST.ONBOARDING_CHOICES.CHAT_SPLIT) { return { - choice, - data: CONST.ONBOARDING_MESSAGES[choice], - personalDetails: { - firstName, - lastName, - }, + firstName, + lastName, + onboardingMessage: CONST.ONBOARDING_MESSAGES[choice], }; } } @@ -869,17 +868,25 @@ function openReport( }; const inviteOnboardingDetails = getInviteOnboardingDetails(); - if (inviteOnboardingDetails && !introSelected?.isInviteOnboardingComplete) { - const {choice, data, personalDetails} = inviteOnboardingDetails; - completeOnboarding(choice, data, {...personalDetails}); + if (inviteOnboardingDetails && !introSelected?.isInviteOnboardingComplete && introSelected?.choice) { + const onboardingData = prepareOnboardingOptimisticData(introSelected?.choice, inviteOnboardingDetails.onboardingMessage); - Onyx.set(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); + optimisticData.push( + ...onboardingData.optimisticData, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.NVP_INTRO_SELECTED, + value: { + isInviteOnboardingComplete: true, + } + } + ); - optimisticData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.NVP_INTRO_SELECTED, - value: {isInviteOnboardingComplete: true}, - }); + successData.push(...onboardingData.successData); + + failureData.push(...onboardingData.failureData); + + parameters.guidedSetupObject = JSON.stringify(onboardingData.guidedSetupData); } if (ReportUtils.isGroupChat(newReportObject)) { @@ -3366,16 +3373,9 @@ function getReportPrivateNote(reportID: string | undefined) { API.read(READ_COMMANDS.GET_REPORT_PRIVATE_NOTE, parameters, {optimisticData, successData, failureData}); } -function completeOnboarding( +function prepareOnboardingOptimisticData( engagementChoice: OnboardingPurpose, data: ValueOf, - { - firstName, - lastName, - }: { - firstName: string; - lastName: string; - }, adminsChatReportID?: string, onboardingPolicyID?: string, ) { @@ -3724,6 +3724,24 @@ function completeOnboarding( guidedSetupData.push(...tasksForParameters); + return {optimisticData, successData, failureData, guidedSetupData, actorAccountID}; +} + +function completeOnboarding( + engagementChoice: OnboardingPurpose, + data: ValueOf, + { + firstName, + lastName, + }: { + firstName: string; + lastName: string; + }, + adminsChatReportID?: string, + onboardingPolicyID?: string, +) { + const {optimisticData, successData, failureData, guidedSetupData, actorAccountID} = prepareOnboardingOptimisticData(engagementChoice, data, adminsChatReportID, onboardingPolicyID); + const parameters: CompleteGuidedSetupParams = { engagementChoice, firstName, From 86a8ad0ee3e25a2f1a8e4590c7268b04c5b9b4fe Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:17:54 +0200 Subject: [PATCH 20/33] fix prettier --- src/libs/actions/Report.ts | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index e7856f66c4cf..59bf97f99faf 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -871,16 +871,13 @@ function openReport( if (inviteOnboardingDetails && !introSelected?.isInviteOnboardingComplete && introSelected?.choice) { const onboardingData = prepareOnboardingOptimisticData(introSelected?.choice, inviteOnboardingDetails.onboardingMessage); - optimisticData.push( - ...onboardingData.optimisticData, - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.NVP_INTRO_SELECTED, - value: { - isInviteOnboardingComplete: true, - } - } - ); + optimisticData.push(...onboardingData.optimisticData, { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.NVP_INTRO_SELECTED, + value: { + isInviteOnboardingComplete: true, + }, + }); successData.push(...onboardingData.successData); @@ -3373,12 +3370,7 @@ function getReportPrivateNote(reportID: string | undefined) { API.read(READ_COMMANDS.GET_REPORT_PRIVATE_NOTE, parameters, {optimisticData, successData, failureData}); } -function prepareOnboardingOptimisticData( - engagementChoice: OnboardingPurpose, - data: ValueOf, - adminsChatReportID?: string, - onboardingPolicyID?: string, -) { +function prepareOnboardingOptimisticData(engagementChoice: OnboardingPurpose, data: ValueOf, adminsChatReportID?: string, onboardingPolicyID?: string) { const isAccountIDOdd = AccountUtils.isAccountIDOddNumber(currentUserAccountID ?? 0); const targetEmail = isAccountIDOdd ? CONST.EMAIL.NOTIFICATIONS : CONST.EMAIL.CONCIERGE; From 7e5c1f14ff7dfab4ca6894f059e46804c515ce37 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 18 Sep 2024 21:11:06 +0200 Subject: [PATCH 21/33] refactor onboarding guided setup param name into guidedSetupData --- src/libs/API/parameters/OpenReportParams.ts | 2 +- src/libs/actions/IOU.ts | 14 +++- src/libs/actions/Report.ts | 72 +++++++++------------ 3 files changed, 42 insertions(+), 46 deletions(-) diff --git a/src/libs/API/parameters/OpenReportParams.ts b/src/libs/API/parameters/OpenReportParams.ts index 63ee06b58367..a665313580e8 100644 --- a/src/libs/API/parameters/OpenReportParams.ts +++ b/src/libs/API/parameters/OpenReportParams.ts @@ -14,7 +14,7 @@ type OpenReportParams = { chatType?: string; optimisticAccountIDList?: string; file?: File | CustomRNImageManipulatorResult; - guidedSetupObject?: string; + guidedSetupData?: string; }; export default OpenReportParams; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index b0d025e0768f..f6e08e17dd6c 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -70,6 +70,7 @@ import * as Category from './Policy/Category'; import * as Policy from './Policy/Policy'; import * as Tag from './Policy/Tag'; import * as Report from './Report'; +import type Onboarding from '@src/types/onyx/Onboarding'; type IOURequestType = ValueOf; @@ -286,6 +287,12 @@ Onyx.connect({ callback: (value) => (personalDetailsList = value), }); +let onboarding: OnyxEntry; +Onyx.connect({ + key: ONYXKEYS.NVP_ONBOARDING, + callback: (value) => (onboarding = value), +}); + /** * Find the report preview action from given chat report and iou report */ @@ -7502,9 +7509,10 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O * @param paymentSelected based on which we choose the onboarding choice and concierge message */ function completePaymentOnboarding(paymentSelected: ValueOf) { - const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? false; - - if (isInviteOnboardingComplete || !introSelected?.choice) { + const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? true; + const hasCompletedGuidedSetup = Array.isArray(onboarding) || onboarding?.hasCompletedGuidedSetupFlow; + + if (hasCompletedGuidedSetup || isInviteOnboardingComplete || !introSelected?.choice) { return; } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 85242197c365..262667e62326 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -112,6 +112,7 @@ import navigateFromNotification from './navigateFromNotification'; import * as Session from './Session'; import * as Welcome from './Welcome'; import * as OnboardingFlow from './Welcome/OnboardingFlow'; +import type Onboarding from '@src/types/onyx/Onboarding'; type SubscriberCallback = (isFromCurrentUser: boolean, reportActionID: string | undefined) => void; @@ -275,6 +276,12 @@ Onyx.connect({ let environmentURL: string; Environment.getEnvironmentURL().then((url: string) => (environmentURL = url)); +let onboarding: OnyxEntry; +Onyx.connect({ + key: ONYXKEYS.NVP_ONBOARDING, + callback: (value) => (onboarding = value), +}); + registerPaginationConfig({ initialCommand: WRITE_COMMANDS.OPEN_REPORT, previousCommand: READ_COMMANDS.GET_OLDER_ACTIONS, @@ -756,35 +763,6 @@ function clearAvatarErrors(reportID: string) { }); } -/** - * Gets details for an invite onboarding if certain conditions are met - * @returns firstName, lastName, and onboardingMessage values - */ -function getInviteOnboardingDetails() { - if (!introSelected) { - return; - } - - const {choice, isInviteOnboardingComplete, inviteType} = introSelected; - if (isInviteOnboardingComplete ?? inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU ?? inviteType === CONST.ONBOARDING_INVITE_TYPES.INVOICE) { - return; - } - - const personalDetails = allPersonalDetails?.[currentUserAccountID]; - const firstName = personalDetails?.firstName ?? ''; - const lastName = personalDetails?.lastName ?? ''; - - Onyx.merge(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); - - if (choice === CONST.ONBOARDING_CHOICES.ADMIN || choice === CONST.ONBOARDING_CHOICES.SUBMIT || choice === CONST.ONBOARDING_CHOICES.CHAT_SPLIT) { - return { - firstName, - lastName, - onboardingMessage: CONST.ONBOARDING_MESSAGES[choice], - }; - } -} - /** * Gets the latest page of report actions and updates the last read message * If a chat with the passed reportID is not found, we will create a chat based on the passed participantList @@ -874,23 +852,33 @@ function openReport( parentReportActionID, }; - const inviteOnboardingDetails = getInviteOnboardingDetails(); - if (inviteOnboardingDetails && !introSelected?.isInviteOnboardingComplete && introSelected?.choice) { - const onboardingData = prepareOnboardingOptimisticData(introSelected?.choice, inviteOnboardingDetails.onboardingMessage); + const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? true; + const hasCompletedGuidedSetup = Array.isArray(onboarding) || onboarding?.hasCompletedGuidedSetupFlow; + + if(!hasCompletedGuidedSetup && introSelected && !isInviteOnboardingComplete) { + const {choice, inviteType} = introSelected; + const isInviteIOUorInvoice = inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU || inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU; - optimisticData.push(...onboardingData.optimisticData, { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.NVP_INTRO_SELECTED, - value: { - isInviteOnboardingComplete: true, - }, - }); + if(choice && !isInviteIOUorInvoice) { + const onboardingMessage = CONST.ONBOARDING_MESSAGES[choice]; + const onboardingData = prepareOnboardingOptimisticData(choice, onboardingMessage); - successData.push(...onboardingData.successData); + Onyx.merge(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); - failureData.push(...onboardingData.failureData); + optimisticData.push(...onboardingData.optimisticData, { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.NVP_INTRO_SELECTED, + value: { + isInviteOnboardingComplete: true, + }, + }); - parameters.guidedSetupObject = JSON.stringify(onboardingData.guidedSetupData); + successData.push(...onboardingData.successData); + + failureData.push(...onboardingData.failureData); + + parameters.guidedSetupData = JSON.stringify(onboardingData.guidedSetupData); + } } if (ReportUtils.isGroupChat(newReportObject)) { From a34ed0381f186a335cceaa19b676741501566132 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 18 Sep 2024 21:11:48 +0200 Subject: [PATCH 22/33] fix prettier --- src/libs/actions/IOU.ts | 4 ++-- src/libs/actions/Report.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f6e08e17dd6c..e45aab43219c 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -59,6 +59,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant, Split} from '@src/types/onyx/IOU'; +import type Onboarding from '@src/types/onyx/Onboarding'; import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type ReportAction from '@src/types/onyx/ReportAction'; @@ -70,7 +71,6 @@ import * as Category from './Policy/Category'; import * as Policy from './Policy/Policy'; import * as Tag from './Policy/Tag'; import * as Report from './Report'; -import type Onboarding from '@src/types/onyx/Onboarding'; type IOURequestType = ValueOf; @@ -7511,7 +7511,7 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O function completePaymentOnboarding(paymentSelected: ValueOf) { const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? true; const hasCompletedGuidedSetup = Array.isArray(onboarding) || onboarding?.hasCompletedGuidedSetupFlow; - + if (hasCompletedGuidedSetup || isInviteOnboardingComplete || !introSelected?.choice) { return; } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 262667e62326..865d2bd4cdb1 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -100,6 +100,7 @@ import type { ReportActionReactions, ReportUserIsTyping, } from '@src/types/onyx'; +import type Onboarding from '@src/types/onyx/Onboarding'; import type {Decision} from '@src/types/onyx/OriginalMessage'; import type {ConnectionName} from '@src/types/onyx/Policy'; import type {NotificationPreference, Participants, Participant as ReportParticipant, RoomVisibility, WriteCapability} from '@src/types/onyx/Report'; @@ -112,7 +113,6 @@ import navigateFromNotification from './navigateFromNotification'; import * as Session from './Session'; import * as Welcome from './Welcome'; import * as OnboardingFlow from './Welcome/OnboardingFlow'; -import type Onboarding from '@src/types/onyx/Onboarding'; type SubscriberCallback = (isFromCurrentUser: boolean, reportActionID: string | undefined) => void; @@ -854,12 +854,12 @@ function openReport( const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? true; const hasCompletedGuidedSetup = Array.isArray(onboarding) || onboarding?.hasCompletedGuidedSetupFlow; - - if(!hasCompletedGuidedSetup && introSelected && !isInviteOnboardingComplete) { + + if (!hasCompletedGuidedSetup && introSelected && !isInviteOnboardingComplete) { const {choice, inviteType} = introSelected; const isInviteIOUorInvoice = inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU || inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU; - if(choice && !isInviteIOUorInvoice) { + if (choice && !isInviteIOUorInvoice) { const onboardingMessage = CONST.ONBOARDING_MESSAGES[choice]; const onboardingData = prepareOnboardingOptimisticData(choice, onboardingMessage); From 9eaa30df53f40c3f6bb14ab8c3644a8726983f89 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 18 Sep 2024 21:39:30 +0200 Subject: [PATCH 23/33] clean up code and remove duplicate definitions --- src/libs/actions/IOU.ts | 2 +- src/libs/actions/Report.ts | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index e45aab43219c..15b7e3692dd8 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7512,7 +7512,7 @@ function completePaymentOnboarding(paymentSelected: ValueOf { const connection = Onyx.connect({ key: ONYXKEYS.NVP_ONBOARDING, - callback: (onboarding) => { - if (onboarding) { + callback: (onboardingData) => { + if (onboardingData) { // Once the onboarding data is available, we want to disconnect the connection // so it won't trigger the deeplink again every time the data is changed, for example, when relogin. Onyx.disconnect(connection); @@ -2742,7 +2743,7 @@ function openReportFromDeepLink(url: string) { const state = navigationRef.getRootState(); const currentFocusedRoute = findFocusedRoute(state); - const hasCompletedGuidedSetupFlow = hasCompletedGuidedSetupFlowSelector(onboarding); + const hasCompletedGuidedSetupFlow = hasCompletedGuidedSetupFlowSelector(onboardingData); // We need skip deeplinking if the user hasn't completed the guided setup flow. if (!hasCompletedGuidedSetupFlow) { From 891a79b955ab9762164aa85f1314486ad0ae42d4 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 18 Sep 2024 21:54:51 +0200 Subject: [PATCH 24/33] refactor SystemChatReportFooterMessage to useOnyx --- .../report/SystemChatReportFooterMessage.tsx | 34 ++++--------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/src/pages/home/report/SystemChatReportFooterMessage.tsx b/src/pages/home/report/SystemChatReportFooterMessage.tsx index d5c07cbeb450..a000550751e3 100644 --- a/src/pages/home/report/SystemChatReportFooterMessage.tsx +++ b/src/pages/home/report/SystemChatReportFooterMessage.tsx @@ -1,6 +1,5 @@ import React, {useMemo} from 'react'; -import {useOnyx, withOnyx} from 'react-native-onyx'; -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import Banner from '@components/Banner'; import * as Expensicons from '@components/Icon/Expensicons'; import Text from '@components/Text'; @@ -13,25 +12,14 @@ import * as ReportInstance from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {OnboardingPurpose, Policy as PolicyType} from '@src/types/onyx'; -type SystemChatReportFooterMessageOnyxProps = { - /** Saved onboarding purpose selected by the user */ - choice: OnyxEntry; - - /** The list of this user's policies */ - policies: OnyxCollection; - - /** policyID for main workspace */ - activePolicyID: OnyxEntry>; -}; - -type SystemChatReportFooterMessageProps = SystemChatReportFooterMessageOnyxProps; - -function SystemChatReportFooterMessage({choice, policies, activePolicyID}: SystemChatReportFooterMessageProps) { +function SystemChatReportFooterMessage() { const {translate} = useLocalize(); const styles = useThemeStyles(); const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email}); + const [choice] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED); + const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); + const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); const adminChatReportID = useMemo(() => { const adminPolicy = activePolicyID @@ -87,14 +75,4 @@ function SystemChatReportFooterMessage({choice, policies, activePolicyID}: Syste SystemChatReportFooterMessage.displayName = 'SystemChatReportFooterMessage'; -export default withOnyx({ - choice: { - key: ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, - }, - policies: { - key: ONYXKEYS.COLLECTION.POLICY, - }, - activePolicyID: { - key: ONYXKEYS.NVP_ACTIVE_POLICY_ID, - }, -})(SystemChatReportFooterMessage); +export default SystemChatReportFooterMessage; From c0db8a16aee04d51a61886565539e8f8e71f0fbe Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Fri, 20 Sep 2024 22:19:20 +0200 Subject: [PATCH 25/33] correct conditionals for onboarding and fix multiple concierge chats --- src/libs/actions/IOU.ts | 10 +--------- src/libs/actions/Report.ts | 19 ++++++++----------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 773c6059ae81..41b4283936c1 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -59,7 +59,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant, Split} from '@src/types/onyx/IOU'; -import type Onboarding from '@src/types/onyx/Onboarding'; import type {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon'; import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type ReportAction from '@src/types/onyx/ReportAction'; @@ -287,12 +286,6 @@ Onyx.connect({ callback: (value) => (personalDetailsList = value), }); -let onboarding: OnyxEntry; -Onyx.connect({ - key: ONYXKEYS.NVP_ONBOARDING, - callback: (value) => (onboarding = value), -}); - /** * Find the report preview action from given chat report and iou report */ @@ -7516,9 +7509,8 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O */ function completePaymentOnboarding(paymentSelected: ValueOf) { const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? true; - const hasCompletedGuidedSetup = Array.isArray(onboarding) || onboarding?.hasCompletedGuidedSetupFlow; - if (hasCompletedGuidedSetup ?? isInviteOnboardingComplete ?? !introSelected?.choice) { + if (isInviteOnboardingComplete ?? !introSelected?.choice) { return; } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 86fe48c2a083..03880926a55c 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -100,7 +100,6 @@ import type { ReportActionReactions, ReportUserIsTyping, } from '@src/types/onyx'; -import type Onboarding from '@src/types/onyx/Onboarding'; import type {Decision} from '@src/types/onyx/OriginalMessage'; import type {ConnectionName} from '@src/types/onyx/Policy'; import type {NotificationPreference, Participants, Participant as ReportParticipant, RoomVisibility, WriteCapability} from '@src/types/onyx/Report'; @@ -276,12 +275,6 @@ Onyx.connect({ let environmentURL: string; Environment.getEnvironmentURL().then((url: string) => (environmentURL = url)); -let onboarding: OnyxEntry; -Onyx.connect({ - key: ONYXKEYS.NVP_ONBOARDING, - callback: (value) => (onboarding = value), -}); - registerPaginationConfig({ initialCommand: WRITE_COMMANDS.OPEN_REPORT, previousCommand: READ_COMMANDS.GET_OLDER_ACTIONS, @@ -853,18 +846,21 @@ function openReport( }; const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? true; - const hasCompletedGuidedSetup = Array.isArray(onboarding) || onboarding?.hasCompletedGuidedSetupFlow; - if (!hasCompletedGuidedSetup && introSelected && !isInviteOnboardingComplete) { + if (introSelected && !isInviteOnboardingComplete) { const {choice, inviteType} = introSelected; const isInviteIOUorInvoice = inviteType === CONST.ONBOARDING_INVITE_TYPES.IOU || inviteType === CONST.ONBOARDING_INVITE_TYPES.INVOICE; const isInviteChoiceCorrect = choice === CONST.ONBOARDING_CHOICES.ADMIN || choice === CONST.ONBOARDING_CHOICES.SUBMIT || choice === CONST.ONBOARDING_CHOICES.CHAT_SPLIT; if (isInviteChoiceCorrect && !isInviteIOUorInvoice) { const onboardingMessage = CONST.ONBOARDING_MESSAGES[choice]; - const onboardingData = prepareOnboardingOptimisticData(choice, onboardingMessage); + if (choice === CONST.ONBOARDING_CHOICES.CHAT_SPLIT) { + const updatedTasks = onboardingMessage.tasks.map((task) => (task.type === 'startChat' ? {...task, autoCompleted: true} : task)); + onboardingMessage.tasks = updatedTasks; + } - Onyx.merge(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); + const onboardingData = prepareOnboardingOptimisticData(choice, onboardingMessage); + introSelected.isInviteOnboardingComplete = true; optimisticData.push(...onboardingData.optimisticData, { onyxMethod: Onyx.METHOD.MERGE, @@ -1022,6 +1018,7 @@ function openReport( paginationConfig, ).finally(() => { Onyx.set(ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, false); + Onyx.merge(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); }); } else { // eslint-disable-next-line rulesdir/no-multiple-api-calls From 937544855b42d8785d002969b8b92b729b19b3ca Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 2 Oct 2024 18:04:53 +0200 Subject: [PATCH 26/33] fix prettier --- src/libs/actions/Welcome/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Welcome/index.ts b/src/libs/actions/Welcome/index.ts index bcef4dd84d8a..bd2d77e2e5ea 100644 --- a/src/libs/actions/Welcome/index.ts +++ b/src/libs/actions/Welcome/index.ts @@ -4,8 +4,8 @@ import Onyx from 'react-native-onyx'; import * as API from '@libs/API'; import {SIDE_EFFECT_REQUEST_COMMANDS} from '@libs/API/types'; import Log from '@libs/Log'; -import type {OnboardingPurpose} from '@src/types/onyx'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {OnboardingPurpose} from '@src/types/onyx'; import type Onboarding from '@src/types/onyx/Onboarding'; import type TryNewDot from '@src/types/onyx/TryNewDot'; import * as OnboardingFlow from './OnboardingFlow'; From 96aaf8a2dd145b3736e4013961c88122cfa90c5d Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:15:53 +0200 Subject: [PATCH 27/33] fix prettier and eslint --- src/libs/API/parameters/CompleteGuidedSetupParams.ts | 2 +- src/libs/actions/Report.ts | 11 ++++------- src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx | 4 ++-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/libs/API/parameters/CompleteGuidedSetupParams.ts b/src/libs/API/parameters/CompleteGuidedSetupParams.ts index 96c24a84478d..7ed78bbe8a59 100644 --- a/src/libs/API/parameters/CompleteGuidedSetupParams.ts +++ b/src/libs/API/parameters/CompleteGuidedSetupParams.ts @@ -1,5 +1,5 @@ -import type {OnboardingPurpose} from '@src/types/onyx'; import type {OnboardingAccountingType, OnboardingCompanySizeType} from '@src/CONST'; +import type {OnboardingPurpose} from '@src/types/onyx'; type CompleteGuidedSetupParams = { firstName: string; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 36ba49ec1b21..1394ecbc3bdb 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3747,16 +3747,13 @@ function prepareOnboardingOptimisticData( function completeOnboarding( engagementChoice: OnboardingPurpose, data: ValueOf, - { - firstName, - lastName, - }: { - firstName: string; - lastName: string; - }, + firstName = '', + lastName = '', adminsChatReportID?: string, onboardingPolicyID?: string, paymentSelected?: string, + companySize?: OnboardingCompanySizeType, + userReportedIntegration?: OnboardingAccountingType, ) { const {optimisticData, successData, failureData, guidedSetupData, actorAccountID} = prepareOnboardingOptimisticData(engagementChoice, data, adminsChatReportID, onboardingPolicyID); diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index a59042c572a1..e26416620a3c 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -22,15 +22,15 @@ import type {TOnboardingRef} from '@libs/OnboardingRefManager'; import variables from '@styles/variables'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; -import type {OnboardingPurposeType} from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {OnboardingPurpose} from '@src/types/onyx'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; import type {BaseOnboardingPurposeProps} from './types'; const selectableOnboardingChoices = Object.values(CONST.SELECTABLE_ONBOARDING_CHOICES); -function getOnboardingChoices(customChoices: OnboardingPurposeType[]) { +function getOnboardingChoices(customChoices: OnboardingPurpose[]) { if (customChoices.length === 0) { return selectableOnboardingChoices; } From f9ced59538e0f050676098bf54ee19ff0e6ec830 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 6 Nov 2024 12:13:45 +0100 Subject: [PATCH 28/33] Rename a type to fix TS --- src/libs/TourUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/TourUtils.ts b/src/libs/TourUtils.ts index a88ee47cc563..141ed6b23a2b 100644 --- a/src/libs/TourUtils.ts +++ b/src/libs/TourUtils.ts @@ -1,8 +1,8 @@ import type {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; -import type {OnboardingPurposeType} from '@src/CONST'; +import type {OnboardingPurpose} from '@src/CONST'; -function getNavatticURL(environment: ValueOf, introSelected?: OnboardingPurposeType) { +function getNavatticURL(environment: ValueOf, introSelected?: OnboardingPurpose) { const adminTourURL = environment === CONST.ENVIRONMENT.PRODUCTION ? CONST.NAVATTIC.ADMIN_TOUR_PRODUCTION : CONST.NAVATTIC.ADMIN_TOUR_STAGING; const employeeTourURL = environment === CONST.ENVIRONMENT.PRODUCTION ? CONST.NAVATTIC.EMPLOYEE_TOUR_PRODUCTION : CONST.NAVATTIC.EMPLOYEE_TOUR_STAGING; return introSelected === CONST.SELECTABLE_ONBOARDING_CHOICES.MANAGE_TEAM ? adminTourURL : employeeTourURL; From 3897043e1d323e84e9ea012655cba66c8c965442 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 6 Nov 2024 15:43:07 +0100 Subject: [PATCH 29/33] Export renamed types --- src/CONST.ts | 6 +++--- src/ONYXKEYS.ts | 4 ++-- src/libs/API/parameters/CompleteGuidedSetupParams.ts | 6 +++--- src/libs/actions/Report.ts | 10 +++++----- src/libs/actions/Welcome/index.ts | 4 ++-- .../OnboardingAccounting/BaseOnboardingAccounting.tsx | 6 +++--- .../OnboardingEmployees/BaseOnboardingEmployees.tsx | 6 +++--- src/types/onyx/IntroSelected.ts | 4 ++-- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 2fd838dbb6fe..9fe64d0fcafe 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -6281,13 +6281,13 @@ export type { IOUAction, IOUType, OnboardingPurpose, - OnboardingCompanySize as OnboardingCompanySizeType, + OnboardingCompanySize, IOURequestType, SubscriptionType, FeedbackSurveyOptionID, CancellationType, - OnboardingInvite as OnboardingInviteType, - OnboardingAccounting as OnboardingAccountingType, + OnboardingInvite, + OnboardingAccounting, }; export default CONST; diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 41b030307c70..d537c99d7704 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -1,6 +1,6 @@ import type {ValueOf} from 'type-fest'; import type CONST from './CONST'; -import type {OnboardingCompanySizeType} from './CONST'; +import type {OnboardingCompanySize} from './CONST'; import type Platform from './libs/getPlatform/types'; import type * as FormTypes from './types/form'; import type * as OnyxTypes from './types/onyx'; @@ -977,7 +977,7 @@ type OnyxValuesMapping = { [ONYXKEYS.MAX_CANVAS_HEIGHT]: number; [ONYXKEYS.MAX_CANVAS_WIDTH]: number; [ONYXKEYS.ONBOARDING_PURPOSE_SELECTED]: OnyxTypes.OnboardingPurpose; - [ONYXKEYS.ONBOARDING_COMPANY_SIZE]: OnboardingCompanySizeType; + [ONYXKEYS.ONBOARDING_COMPANY_SIZE]: OnboardingCompanySize; [ONYXKEYS.ONBOARDING_CUSTOM_CHOICES]: OnyxTypes.OnboardingPurpose[] | []; [ONYXKEYS.ONBOARDING_ERROR_MESSAGE]: string; [ONYXKEYS.ONBOARDING_POLICY_ID]: string; diff --git a/src/libs/API/parameters/CompleteGuidedSetupParams.ts b/src/libs/API/parameters/CompleteGuidedSetupParams.ts index 3e56d155e003..febb1a47d8b6 100644 --- a/src/libs/API/parameters/CompleteGuidedSetupParams.ts +++ b/src/libs/API/parameters/CompleteGuidedSetupParams.ts @@ -1,4 +1,4 @@ -import type {OnboardingAccountingType, OnboardingCompanySizeType} from '@src/CONST'; +import type {OnboardingAccounting, OnboardingCompanySize} from '@src/CONST'; import type {OnboardingPurpose} from '@src/types/onyx'; type CompleteGuidedSetupParams = { @@ -8,8 +8,8 @@ type CompleteGuidedSetupParams = { guidedSetupData: string; engagementChoice: OnboardingPurpose; paymentSelected?: string; - companySize?: OnboardingCompanySizeType; - userReportedIntegration?: OnboardingAccountingType; + companySize?: OnboardingCompanySize; + userReportedIntegration?: OnboardingAccounting; policyID?: string; }; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 6f50a6e0b9ba..24c7a353c69b 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -89,7 +89,7 @@ import shouldSkipDeepLinkNavigation from '@libs/shouldSkipDeepLinkNavigation'; import {getNavatticURL} from '@libs/TourUtils'; import Visibility from '@libs/Visibility'; import CONFIG from '@src/CONFIG'; -import type {OnboardingAccountingType, OnboardingCompanySizeType} from '@src/CONST'; +import type {OnboardingAccounting, OnboardingCompanySize} from '@src/CONST'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; @@ -3461,8 +3461,8 @@ function prepareOnboardingOptimisticData( data: ValueOf, adminsChatReportID?: string, onboardingPolicyID?: string, - companySize?: OnboardingCompanySizeType, - userReportedIntegration?: OnboardingAccountingType, + companySize?: OnboardingCompanySize, + userReportedIntegration?: OnboardingAccounting, ) { // If the user has the "combinedTrackSubmit" beta enabled we'll show different tasks for track and submit expense. if (Permissions.canUseCombinedTrackSubmit(allBetas)) { @@ -3884,8 +3884,8 @@ function completeOnboarding( adminsChatReportID?: string, onboardingPolicyID?: string, paymentSelected?: string, - companySize?: OnboardingCompanySizeType, - userReportedIntegration?: OnboardingAccountingType, + companySize?: OnboardingCompanySize, + userReportedIntegration?: OnboardingAccounting, ) { const {optimisticData, successData, failureData, guidedSetupData, actorAccountID} = prepareOnboardingOptimisticData(engagementChoice, data, adminsChatReportID, onboardingPolicyID); diff --git a/src/libs/actions/Welcome/index.ts b/src/libs/actions/Welcome/index.ts index f341e6f3966d..4a0d9bb4bcaa 100644 --- a/src/libs/actions/Welcome/index.ts +++ b/src/libs/actions/Welcome/index.ts @@ -4,7 +4,7 @@ import Onyx from 'react-native-onyx'; import * as API from '@libs/API'; import {SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; import Log from '@libs/Log'; -import type {OnboardingCompanySizeType} from '@src/CONST'; +import type {OnboardingCompanySize} from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {OnboardingPurpose} from '@src/types/onyx'; import type Onboarding from '@src/types/onyx/Onboarding'; @@ -98,7 +98,7 @@ function setOnboardingPurposeSelected(value: OnboardingPurpose) { Onyx.set(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, value ?? null); } -function setOnboardingCompanySize(value: OnboardingCompanySizeType) { +function setOnboardingCompanySize(value: OnboardingCompanySize) { Onyx.set(ONYXKEYS.ONBOARDING_COMPANY_SIZE, value); } diff --git a/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx b/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx index ef5a58caf4ea..4ca266c92fbc 100644 --- a/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx +++ b/src/pages/OnboardingAccounting/BaseOnboardingAccounting.tsx @@ -23,13 +23,13 @@ import variables from '@styles/variables'; import * as Report from '@userActions/Report'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; -import type {OnboardingAccountingType} from '@src/CONST'; +import type {OnboardingAccounting} from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {} from '@src/types/onyx/Bank'; import type {BaseOnboardingAccountingProps} from './types'; type OnboardingListItem = ListItem & { - keyForList: OnboardingAccountingType; + keyForList: OnboardingAccounting; }; function BaseOnboardingAccounting({shouldUseNativeStyles, route}: BaseOnboardingAccountingProps) { @@ -48,7 +48,7 @@ function BaseOnboardingAccounting({shouldUseNativeStyles, route}: BaseOnboarding const {canUseDefaultRooms} = usePermissions(); const {activeWorkspaceID} = useActiveWorkspace(); - const [userReportedIntegration, setUserReportedIntegration] = useState(undefined); + const [userReportedIntegration, setUserReportedIntegration] = useState(undefined); const [error, setError] = useState(''); const accountingOptions: OnboardingListItem[] = useMemo(() => { diff --git a/src/pages/OnboardingEmployees/BaseOnboardingEmployees.tsx b/src/pages/OnboardingEmployees/BaseOnboardingEmployees.tsx index 1dd8807cc26e..fee409c6480d 100644 --- a/src/pages/OnboardingEmployees/BaseOnboardingEmployees.tsx +++ b/src/pages/OnboardingEmployees/BaseOnboardingEmployees.tsx @@ -15,13 +15,13 @@ import Navigation from '@libs/Navigation/Navigation'; import * as Policy from '@userActions/Policy/Policy'; import * as Welcome from '@userActions/Welcome'; import CONST from '@src/CONST'; -import type {OnboardingCompanySizeType} from '@src/CONST'; +import type {OnboardingCompanySize} from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {BaseOnboardingEmployeesProps} from './types'; type OnboardingListItem = ListItem & { - keyForList: OnboardingCompanySizeType; + keyForList: OnboardingCompanySize; }; function BaseOnboardingEmployees({shouldUseNativeStyles, route}: BaseOnboardingEmployeesProps) { const styles = useThemeStyles(); @@ -30,7 +30,7 @@ function BaseOnboardingEmployees({shouldUseNativeStyles, route}: BaseOnboardingE const [onboardingPurposeSelected] = useOnyx(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED); const [onboardingPolicyID] = useOnyx(ONYXKEYS.ONBOARDING_POLICY_ID); const {onboardingIsMediumOrLargerScreenWidth} = useResponsiveLayout(); - const [selectedCompanySize, setSelectedCompanySize] = useState(onboardingCompanySize); + const [selectedCompanySize, setSelectedCompanySize] = useState(onboardingCompanySize); const [error, setError] = useState(''); const companySizeOptions: OnboardingListItem[] = useMemo(() => { diff --git a/src/types/onyx/IntroSelected.ts b/src/types/onyx/IntroSelected.ts index c8b025c02c0e..edeb79d34113 100644 --- a/src/types/onyx/IntroSelected.ts +++ b/src/types/onyx/IntroSelected.ts @@ -1,4 +1,4 @@ -import type {OnboardingInviteType} from '@src/CONST'; +import type {OnboardingInvite} from '@src/CONST'; import type {OnboardingPurpose} from './index'; /** Model of onboarding */ @@ -7,7 +7,7 @@ type IntroSelected = { choice?: OnboardingPurpose; /** The invite type */ - inviteType?: OnboardingInviteType; + inviteType?: OnboardingInvite; /** Whether the onboarding is complete */ isInviteOnboardingComplete?: boolean; From 5278d20a80b4a0bbbb1ce00c8eb08a0a6a4f6ebd Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 6 Nov 2024 16:21:10 +0100 Subject: [PATCH 30/33] Fix possible race condition on FE --- src/libs/actions/IOU.ts | 2 +- src/libs/actions/Report.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 10b1718e3d92..4fb991241f7e 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7646,7 +7646,7 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O * @param paymentSelected based on which we choose the onboarding choice and concierge message */ function completePaymentOnboarding(paymentSelected: ValueOf) { - const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? true; + const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? false; if (isInviteOnboardingComplete ?? !introSelected?.choice) { return; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 24c7a353c69b..416777543e96 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -853,7 +853,7 @@ function openReport( parentReportActionID, }; - const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? true; + const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? false; if (introSelected && !isInviteOnboardingComplete) { const {choice, inviteType} = introSelected; @@ -1032,7 +1032,6 @@ function openReport( paginationConfig, ).finally(() => { Onyx.set(ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, false); - Onyx.merge(ONYXKEYS.NVP_INTRO_SELECTED, {isInviteOnboardingComplete: true}); }); } else { // eslint-disable-next-line rulesdir/no-multiple-api-calls From d0f451a9b5edcdbf3d51c02574d00557572814ae Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Wed, 6 Nov 2024 16:49:51 +0100 Subject: [PATCH 31/33] Fix tests and pass all data to prepareOnboardingOptimisticData --- src/libs/actions/IOU.ts | 8 ++++---- src/libs/actions/Report.ts | 9 +++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 4fb991241f7e..bb0933415867 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -7648,7 +7648,7 @@ function cancelPayment(expenseReport: OnyxEntry, chatReport: O function completePaymentOnboarding(paymentSelected: ValueOf) { const isInviteOnboardingComplete = introSelected?.isInviteOnboardingComplete ?? false; - if (isInviteOnboardingComplete ?? !introSelected?.choice) { + if (isInviteOnboardingComplete || !introSelected?.choice) { return; } @@ -7657,12 +7657,12 @@ function completePaymentOnboarding(paymentSelected: ValueOf, adminsChatReportID?: string, onboardingPolicyID?: string, - companySize?: OnboardingCompanySize, userReportedIntegration?: OnboardingAccounting, ) { // If the user has the "combinedTrackSubmit" beta enabled we'll show different tasks for track and submit expense. @@ -3886,7 +3885,13 @@ function completeOnboarding( companySize?: OnboardingCompanySize, userReportedIntegration?: OnboardingAccounting, ) { - const {optimisticData, successData, failureData, guidedSetupData, actorAccountID} = prepareOnboardingOptimisticData(engagementChoice, data, adminsChatReportID, onboardingPolicyID); + const {optimisticData, successData, failureData, guidedSetupData, actorAccountID} = prepareOnboardingOptimisticData( + engagementChoice, + data, + adminsChatReportID, + onboardingPolicyID, + userReportedIntegration, + ); const parameters: CompleteGuidedSetupParams = { engagementChoice, From cb3d7b96332d918f75fafb1090d06a734ca0a448 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 7 Nov 2024 13:58:11 +0100 Subject: [PATCH 32/33] Fix that no onboarding messages were sent for a first time user --- src/libs/actions/Report.ts | 12 +++++--- src/libs/actions/RequestConflictUtils.ts | 39 +++++++++++++++++++++++- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index e640ae2a5fc7..8d3c6cfa7db9 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -118,7 +118,13 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as CachedPDFPaths from './CachedPDFPaths'; import * as Modal from './Modal'; import navigateFromNotification from './navigateFromNotification'; -import {createUpdateCommentMatcher, resolveCommentDeletionConflicts, resolveDuplicationConflictAction, resolveEditCommentWithNewAddCommentRequest} from './RequestConflictUtils'; +import { + createUpdateCommentMatcher, + resolveCommentDeletionConflicts, + resolveDuplicationConflictAction, + resolveEditCommentWithNewAddCommentRequest, + resolveOpenReportDuplicationConflictAction, +} from './RequestConflictUtils'; import * as Session from './Session'; import * as Welcome from './Welcome'; import * as OnboardingFlow from './Welcome/OnboardingFlow'; @@ -868,7 +874,6 @@ function openReport( } const onboardingData = prepareOnboardingOptimisticData(choice, onboardingMessage); - introSelected.isInviteOnboardingComplete = true; optimisticData.push(...onboardingData.optimisticData, { onyxMethod: Onyx.METHOD.MERGE, @@ -1036,8 +1041,7 @@ function openReport( } else { // eslint-disable-next-line rulesdir/no-multiple-api-calls API.paginate(CONST.API_REQUEST_TYPE.WRITE, WRITE_COMMANDS.OPEN_REPORT, parameters, {optimisticData, successData, failureData}, paginationConfig, { - checkAndFixConflictingRequest: (persistedRequests) => - resolveDuplicationConflictAction(persistedRequests, (request) => request.command === WRITE_COMMANDS.OPEN_REPORT && request.data?.reportID === reportID), + checkAndFixConflictingRequest: (persistedRequests) => resolveOpenReportDuplicationConflictAction(persistedRequests, reportID), }); } } diff --git a/src/libs/actions/RequestConflictUtils.ts b/src/libs/actions/RequestConflictUtils.ts index e363ff02a127..67d4cbcc8199 100644 --- a/src/libs/actions/RequestConflictUtils.ts +++ b/src/libs/actions/RequestConflictUtils.ts @@ -50,6 +50,37 @@ function resolveDuplicationConflictAction(persistedRequests: OnyxRequest[], requ }; } +function resolveOpenReportDuplicationConflictAction(persistedRequests: OnyxRequest[], originalReportID: string): ConflictActionData { + for (let index = 0; index < persistedRequests.length; index++) { + const request = persistedRequests.at(index); + if (request && request.command === WRITE_COMMANDS.OPEN_REPORT && request.data?.reportID === originalReportID) { + // If the previous request had guided setup data, we can safely ignore the new request + if (request.data.guidedSetupData) { + return { + conflictAction: { + type: 'noAction', + }, + }; + } + + // In other cases it's safe to replace the previous request with the new one + return { + conflictAction: { + type: 'replace', + index, + }, + }; + } + } + + // If we didn't find any request to replace, we should push the new request + return { + conflictAction: { + type: 'push', + }, + }; +} + function resolveCommentDeletionConflicts(persistedRequests: OnyxRequest[], reportActionID: string, originalReportID: string): ConflictActionData { const commentIndicesToDelete: number[] = []; const commentCouldBeThread: Record = {}; @@ -144,4 +175,10 @@ function resolveEditCommentWithNewAddCommentRequest(persistedRequests: OnyxReque } as ConflictActionData; } -export {resolveDuplicationConflictAction, resolveCommentDeletionConflicts, resolveEditCommentWithNewAddCommentRequest, createUpdateCommentMatcher}; +export { + resolveDuplicationConflictAction, + resolveOpenReportDuplicationConflictAction, + resolveCommentDeletionConflicts, + resolveEditCommentWithNewAddCommentRequest, + createUpdateCommentMatcher, +}; From c3c6e44079a15fd806652e830c3ed0eb2b2afc92 Mon Sep 17 00:00:00 2001 From: zfurtak Date: Tue, 12 Nov 2024 01:43:14 +0000 Subject: [PATCH 33/33] Adjusted message for admin --- src/CONST.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 9fe64d0fcafe..89c731760a9a 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -5074,7 +5074,7 @@ const CONST = { ], }, [onboardingChoices.ADMIN]: { - message: "Hey 👋\nAs an admin, learn how to manage your team's workspace and submit expenses yourself.", + message: "As an admin, learn how to manage your team's workspace and submit expenses yourself.", video: { url: `${CLOUDFRONT_URL}/videos/guided-setup-manage-team-v2.mp4`, thumbnailUrl: `${CLOUDFRONT_URL}/images/guided-setup-manage-team.jpg`,