From 53e0ca31da0f54d1e5f4ff08ed000bfdae48bbd7 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Fri, 5 Apr 2024 12:52:45 +0200 Subject: [PATCH 01/54] feat: added new method for handliung onboarding, build new messages structure for onboarding --- src/CONST.ts | 240 +++++++++++++++++++++++++++++++++++++ src/libs/API/types.ts | 1 + src/libs/actions/Report.ts | 104 ++++++++++++++++ 3 files changed, 345 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index 6d1195ff5c79..b05e71fe7f19 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3541,6 +3541,246 @@ 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.", }, + ONBOARDING_MESSAGES: { + [onboardingChoices.TRACK]: { + message: 'Here are some essential tasks to keep your business spend in shape for tax season.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + title: 'Create a workspace', + subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more. ', + message: + 'Here’s how to create a workspace:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Click Workspaces > New workspace.\n' + + '\n' + + 'Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.', + }, + { + title: 'Track an expense', + subtitle: 'Track an expense in any currency, in just a few clicks.', + message: + 'Here’s how to track an expense:\n' + + '\n' + + '1. Click the green + button.\n' + + '2. Choose Track expense.\n' + + '3. Enter an amount or scan a receipt.\n' + + '4. Click Track.\n' + + '\n' + + 'And you’re done! Yep, it’s that easy.', + }, + ], + }, + [onboardingChoices.EMPLOYER]: { + message: 'Getting paid back is as easy as sending a message. Let’s go over the basics.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + title: 'Submit an expense', + subtitle: 'Submit an expense by entering an amount or scanning a receipt.', + message: + '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.', + }, + { + title: 'Enable your wallet', + subtitle: 'You’ll need to enable your Expensify Wallet to get paid back. Don’t worry, it’s easy!', + message: + '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.MANAGE_TEAM]: { + message: 'Here are some important tasks to help get your team’s expenses under control.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + title: 'Create a workspace', + subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more. ', + message: + 'Here’s how to create a workspace:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Click Workspaces > New workspace.\n' + + '\n' + + 'Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.', + }, + { + title: 'Meet your setup specialist', + subtitle: '', + message: + 'Meet your setup specialist, {guideName}, who can answer any questions as you get started with Expensify. Yes, a real human!\n' + + '\n' + + 'Chat with {guideName} in your [admins room]({adminsRoomID}) or [schedule a call]({guideCalendarLink}) today', + }, + { + title: 'Set up categories', + subtitle: 'Set up categories so your team can code expenses for easy reporting.', + message: + 'Here’s how to set up categories:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Go to Workspaces > [your workspace].\n' + + '3. Click Categories.\n' + + '4. Enable and disable default categories.\n' + + '5. Click Add categories to make your own.\n' + + '\n' + + 'For more controls like requiring a category for every expense, click Settings. ', + }, + { + title: 'Add expense approvals', + subtitle: 'Add expense approvals to review your team’s spend and keep it under control.', + message: + 'Here’s how to add expense approvals:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Go to Workspaces > [your workspace].\n' + + '3. Click More features.\n' + + '4. Enable Workflows.\n' + + '5. In Workflows, enable Add approvals.\n' + + '\n' + + 'You’ll be set as the expense approver. You can change this to any admin once you invite your team. ', + }, + { + title: 'Invite your team', + subtitle: 'Invite your team to Expensify so they can start tracking expenses today.', + message: + 'Here’s how to invite your team:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Go to Workspaces > [your workspace].\n' + + '3. Click Members > Invite member.\n' + + '4. Enter emails or phone numbers. \n' + + '5. Add an invite message if you want.\n' + + '\n' + + 'That’s it! Happy expensing :)', + }, + ], + }, + [onboardingChoices.PERSONAL_SPEND]: { + message: 'Here’s how to track your spend in a few clicks.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + title: 'Track an expense', + subtitle: 'Track an expense in any currency, whether you have a receipt or not.', + message: + 'Here’s how to track an expense:\n' + + '\n' + + '1. Click the green + button.\n' + + '2. Choose Track expense.\n' + + '3. Enter an amount or scan a receipt.\n' + + '4. Click Track.\n' + + '\n' + + 'And you’re done! Yep, it’s that easy.', + }, + ], + }, + [onboardingChoices.CHAT_SPLIT]: { + message: 'Splitting bills with friends is as easy as sending a message. Here’s how.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + title: 'Start a chat', + subtitle: 'Start a chat with a friend or group using their email or phone number.', + message: + 'Here’s how to start a chat:\n' + + '\n' + + '1. rClick the green + button.\n' + + '2. Choose Start chat.\n' + + '3. Enter emails or phone numbers.\n' + + '\n' + + 'If any of your friends aren’t using Expensify already, they’ll be invited automatically. \n' + + '\n' + + 'Every chat will also turn into an email or text that they can respond to directly.', + }, + { + title: 'Split an expense', + subtitle: 'Split an expense right in your chat with one or more friends.', + message: + 'Here’s how to request money:\n' + + '\n' + + '1. Click the green + button.\n' + + '2. Choose Split expense.\n' + + '3. Scan a receipt or enter an amount.\n' + + '4. Add your friend(s) to the request.\n' + + '\n' + + 'Feel free to add more details if you want, or just send it off. Let’s get you paid back!', + }, + { + title: 'Enable your wallet', + subtitle: 'You’ll need to enable your Expensify Wallet to get paid back. Don’t worry, it’s easy!', + message: + 'Here’s how to enable your wallet:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Click Wallet > Enable wallet.\n' + + '3. Add your bank account.\n' + + '\n' + + 'Once that’s done, you can request money from anyone and get paid right into your personal bank account.', + }, + ], + }, + [onboardingChoices.LOOKING_AROUND]: { + message: + '# Welcome to Expensify!\n' + + "Hi there, I'm Concierge. Chat with me here for anything you need.\n" + + '\n' + + "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.", + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [], + }, + }, + REPORT_FIELD_TITLE_FIELD_ID: 'text_title', MOBILE_PAGINATION_SIZE: 15, diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 3cff726a530c..90e03188f3a3 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -134,6 +134,7 @@ const WRITE_COMMANDS = { REOPEN_TASK: 'ReopenTask', COMPLETE_TASK: 'CompleteTask', COMPLETE_ENGAGEMENT_MODAL: 'CompleteEngagementModal', + COMPLETE_GUIDED_SETUP: 'CompleteGuidedSetup', SET_NAME_VALUE_PAIR: 'SetNameValuePair', SET_REPORT_FIELD: 'Report_SetFields', SET_REPORT_NAME: 'RenameReport', diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 179ee87862ff..60cb81c9165a 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2712,6 +2712,109 @@ function getReportPrivateNote(reportID: string | undefined) { API.read(READ_COMMANDS.GET_REPORT_PRIVATE_NOTE, parameters, {optimisticData, successData, failureData}); } +function completeOnboarding(properties: { + data: ValueOf; + firstName: string; + lastName: string; + targetEmail: ValueOf; + engagementChoice: ValueOf; +}) { + const {data, engagementChoice, targetEmail, firstName, lastName} = properties; + const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; + const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID]); + const targetChatReportID = targetChatReport?.reportID ?? ''; + const targetChatPolicyID = targetChatReport?.policyID ?? ''; + + // Text message + const textComment = ReportUtils.buildOptimisticAddCommentReportAction(data.message, undefined); + const textCommentAction: OptimisticAddCommentReportAction = textComment.reportAction; + const textCommentText = textComment.commentText; + + const textMessage: AddCommentOrAttachementParams & {type: string} = { + reportID: targetChatReportID, + reportActionID: textCommentAction.reportActionID, + reportComment: textCommentText, + type: 'message', + }; + + // Video message + const videoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined); + const videoCommentAction: OptimisticAddCommentReportAction = videoComment.reportAction; + const videoCommentText = videoComment.commentText; + + const videoMessage: AddCommentOrAttachementParams & {type: string} & typeof data.video = { + reportID: targetChatReportID, + reportActionID: videoCommentAction.reportActionID, + reportComment: videoCommentText, + type: 'video', + ...data.video, + }; + + // tasks + const tasks = data.tasks.reduce((acc, curr) => { + const currTask = ReportUtils.buildOptimisticTaskReport(actorAccountID, undefined, targetChatReportID, curr.title, undefined, targetChatPolicyID); + const taskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(targetEmail); + const taskAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(currTask.reportID, curr.title, 0, `task for ${curr.title}`, targetChatReportID); + + // subtitle message + const subtitleComment = ReportUtils.buildOptimisticAddCommentReportAction(curr.subtitle, undefined, actorAccountID); + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + const subtitleCommentText = subtitleComment.commentText; + + const subtitleMessage: AddCommentOrAttachementParams = { + reportID: currTask.reportID, + reportActionID: subtitleCommentAction.reportActionID, + reportComment: subtitleCommentText, + }; + + // instruction message + const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(curr.message, undefined, actorAccountID); + const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; + const instructionCommentText = instructionComment.commentText; + + const instructionMessage: AddCommentOrAttachementParams = { + reportID: currTask.reportID, + reportActionID: instructionCommentAction.reportActionID, + reportComment: instructionCommentText, + }; + + return [ + ...acc, + { + parentReportActionID: taskAddCommentReport.reportAction.reportActionID, + parentReportID: currTask.parentReportID, + taskReportID: currTask.reportID, + createdTaskReportActionID: taskCreatedAction.reportActionID, + title: currTask.reportName, + description: currTask.description, + assigneeChatReportID: '', + type: 'task', + task: 'trackExpense', + }, + { + type: 'message', + ...subtitleMessage, + }, + { + type: 'message', + ...instructionMessage, + }, + ]; + }, []); + + const parameters = { + engagementChoice, + firstName, + lastName, + data: JSON.stringify([textMessage, videoMessage, ...tasks]), + }; + + // console.log('-------------------------------------'); + // console.log(JSON.stringify({...parameters, data: JSON.parse(parameters.data)}, ' ', 2)); + + API.write(WRITE_COMMANDS.COMPLETE_GUIDED_SETUP, parameters, {}); +} + /** * Completes the engagement modal that new NewDot users see when they first sign up/log in by doing the following: * @@ -3029,4 +3132,5 @@ export { setGroupDraft, clearGroupChat, startNewChat, + completeOnboarding, }; From c34e8a20a35940b035b987d18e9797211fd3526e Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Fri, 5 Apr 2024 16:31:47 +0200 Subject: [PATCH 02/54] feat: call method --- src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index ae43f850018b..bd8a7ab40917 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -80,7 +80,14 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, on return; } - Report.completeEngagementModal(CONST.ONBOARDING_CONCIERGE[selectedPurpose], selectedPurpose); + // Report.completeEngagementModal(CONST.ONBOARDING_CONCIERGE[selectedPurpose], selectedPurpose); + Report.completeOnboarding({ + data: CONST.ONBOARDING_MESSAGES[selectedPurpose], + engagementChoice: selectedPurpose, + targetEmail: CONST.EMAIL.CONCIERGE, + firstName: 'Test', + lastName: 'Testovsky', + }); Navigation.dismissModal(); // Only navigate to concierge chat when central pane is visible From 880a34a6d6266fbcee789255f7f05ad852436f44 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Fri, 5 Apr 2024 12:52:45 +0200 Subject: [PATCH 03/54] feat: added new method for handliung onboarding, build new messages structure for onboarding --- src/CONST.ts | 240 +++++++++++++++++++++++++++++++++++++ src/libs/API/types.ts | 1 + src/libs/actions/Report.ts | 104 ++++++++++++++++ 3 files changed, 345 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index b07b622cec05..f317a2dca3fa 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3587,6 +3587,246 @@ 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.", }, + ONBOARDING_MESSAGES: { + [onboardingChoices.TRACK]: { + message: 'Here are some essential tasks to keep your business spend in shape for tax season.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + title: 'Create a workspace', + subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more. ', + message: + 'Here’s how to create a workspace:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Click Workspaces > New workspace.\n' + + '\n' + + 'Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.', + }, + { + title: 'Track an expense', + subtitle: 'Track an expense in any currency, in just a few clicks.', + message: + 'Here’s how to track an expense:\n' + + '\n' + + '1. Click the green + button.\n' + + '2. Choose Track expense.\n' + + '3. Enter an amount or scan a receipt.\n' + + '4. Click Track.\n' + + '\n' + + 'And you’re done! Yep, it’s that easy.', + }, + ], + }, + [onboardingChoices.EMPLOYER]: { + message: 'Getting paid back is as easy as sending a message. Let’s go over the basics.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + title: 'Submit an expense', + subtitle: 'Submit an expense by entering an amount or scanning a receipt.', + message: + '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.', + }, + { + title: 'Enable your wallet', + subtitle: 'You’ll need to enable your Expensify Wallet to get paid back. Don’t worry, it’s easy!', + message: + '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.MANAGE_TEAM]: { + message: 'Here are some important tasks to help get your team’s expenses under control.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + title: 'Create a workspace', + subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more. ', + message: + 'Here’s how to create a workspace:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Click Workspaces > New workspace.\n' + + '\n' + + 'Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.', + }, + { + title: 'Meet your setup specialist', + subtitle: '', + message: + 'Meet your setup specialist, {guideName}, who can answer any questions as you get started with Expensify. Yes, a real human!\n' + + '\n' + + 'Chat with {guideName} in your [admins room]({adminsRoomID}) or [schedule a call]({guideCalendarLink}) today', + }, + { + title: 'Set up categories', + subtitle: 'Set up categories so your team can code expenses for easy reporting.', + message: + 'Here’s how to set up categories:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Go to Workspaces > [your workspace].\n' + + '3. Click Categories.\n' + + '4. Enable and disable default categories.\n' + + '5. Click Add categories to make your own.\n' + + '\n' + + 'For more controls like requiring a category for every expense, click Settings. ', + }, + { + title: 'Add expense approvals', + subtitle: 'Add expense approvals to review your team’s spend and keep it under control.', + message: + 'Here’s how to add expense approvals:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Go to Workspaces > [your workspace].\n' + + '3. Click More features.\n' + + '4. Enable Workflows.\n' + + '5. In Workflows, enable Add approvals.\n' + + '\n' + + 'You’ll be set as the expense approver. You can change this to any admin once you invite your team. ', + }, + { + title: 'Invite your team', + subtitle: 'Invite your team to Expensify so they can start tracking expenses today.', + message: + 'Here’s how to invite your team:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Go to Workspaces > [your workspace].\n' + + '3. Click Members > Invite member.\n' + + '4. Enter emails or phone numbers. \n' + + '5. Add an invite message if you want.\n' + + '\n' + + 'That’s it! Happy expensing :)', + }, + ], + }, + [onboardingChoices.PERSONAL_SPEND]: { + message: 'Here’s how to track your spend in a few clicks.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + title: 'Track an expense', + subtitle: 'Track an expense in any currency, whether you have a receipt or not.', + message: + 'Here’s how to track an expense:\n' + + '\n' + + '1. Click the green + button.\n' + + '2. Choose Track expense.\n' + + '3. Enter an amount or scan a receipt.\n' + + '4. Click Track.\n' + + '\n' + + 'And you’re done! Yep, it’s that easy.', + }, + ], + }, + [onboardingChoices.CHAT_SPLIT]: { + message: 'Splitting bills with friends is as easy as sending a message. Here’s how.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [ + { + title: 'Start a chat', + subtitle: 'Start a chat with a friend or group using their email or phone number.', + message: + 'Here’s how to start a chat:\n' + + '\n' + + '1. rClick the green + button.\n' + + '2. Choose Start chat.\n' + + '3. Enter emails or phone numbers.\n' + + '\n' + + 'If any of your friends aren’t using Expensify already, they’ll be invited automatically. \n' + + '\n' + + 'Every chat will also turn into an email or text that they can respond to directly.', + }, + { + title: 'Split an expense', + subtitle: 'Split an expense right in your chat with one or more friends.', + message: + 'Here’s how to request money:\n' + + '\n' + + '1. Click the green + button.\n' + + '2. Choose Split expense.\n' + + '3. Scan a receipt or enter an amount.\n' + + '4. Add your friend(s) to the request.\n' + + '\n' + + 'Feel free to add more details if you want, or just send it off. Let’s get you paid back!', + }, + { + title: 'Enable your wallet', + subtitle: 'You’ll need to enable your Expensify Wallet to get paid back. Don’t worry, it’s easy!', + message: + 'Here’s how to enable your wallet:\n' + + '\n' + + '1. Click your profile picture.\n' + + '2. Click Wallet > Enable wallet.\n' + + '3. Add your bank account.\n' + + '\n' + + 'Once that’s done, you can request money from anyone and get paid right into your personal bank account.', + }, + ], + }, + [onboardingChoices.LOOKING_AROUND]: { + message: + '# Welcome to Expensify!\n' + + "Hi there, I'm Concierge. Chat with me here for anything you need.\n" + + '\n' + + "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.", + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, + tasks: [], + }, + }, + REPORT_FIELD_TITLE_FIELD_ID: 'text_title', MOBILE_PAGINATION_SIZE: 15, diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index fc19ba60693c..c33e96731bdc 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -134,6 +134,7 @@ const WRITE_COMMANDS = { REOPEN_TASK: 'ReopenTask', COMPLETE_TASK: 'CompleteTask', COMPLETE_ENGAGEMENT_MODAL: 'CompleteEngagementModal', + COMPLETE_GUIDED_SETUP: 'CompleteGuidedSetup', SET_NAME_VALUE_PAIR: 'SetNameValuePair', SET_REPORT_FIELD: 'Report_SetFields', DELETE_REPORT_FIELD: 'RemoveReportField', diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index d2f85362baf8..8fe56d93d634 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2774,6 +2774,109 @@ function getReportPrivateNote(reportID: string | undefined) { API.read(READ_COMMANDS.GET_REPORT_PRIVATE_NOTE, parameters, {optimisticData, successData, failureData}); } +function completeOnboarding(properties: { + data: ValueOf; + firstName: string; + lastName: string; + targetEmail: ValueOf; + engagementChoice: ValueOf; +}) { + const {data, engagementChoice, targetEmail, firstName, lastName} = properties; + const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; + const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID]); + const targetChatReportID = targetChatReport?.reportID ?? ''; + const targetChatPolicyID = targetChatReport?.policyID ?? ''; + + // Text message + const textComment = ReportUtils.buildOptimisticAddCommentReportAction(data.message, undefined); + const textCommentAction: OptimisticAddCommentReportAction = textComment.reportAction; + const textCommentText = textComment.commentText; + + const textMessage: AddCommentOrAttachementParams & {type: string} = { + reportID: targetChatReportID, + reportActionID: textCommentAction.reportActionID, + reportComment: textCommentText, + type: 'message', + }; + + // Video message + const videoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined); + const videoCommentAction: OptimisticAddCommentReportAction = videoComment.reportAction; + const videoCommentText = videoComment.commentText; + + const videoMessage: AddCommentOrAttachementParams & {type: string} & typeof data.video = { + reportID: targetChatReportID, + reportActionID: videoCommentAction.reportActionID, + reportComment: videoCommentText, + type: 'video', + ...data.video, + }; + + // tasks + const tasks = data.tasks.reduce((acc, curr) => { + const currTask = ReportUtils.buildOptimisticTaskReport(actorAccountID, undefined, targetChatReportID, curr.title, undefined, targetChatPolicyID); + const taskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(targetEmail); + const taskAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(currTask.reportID, curr.title, 0, `task for ${curr.title}`, targetChatReportID); + + // subtitle message + const subtitleComment = ReportUtils.buildOptimisticAddCommentReportAction(curr.subtitle, undefined, actorAccountID); + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + const subtitleCommentText = subtitleComment.commentText; + + const subtitleMessage: AddCommentOrAttachementParams = { + reportID: currTask.reportID, + reportActionID: subtitleCommentAction.reportActionID, + reportComment: subtitleCommentText, + }; + + // instruction message + const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(curr.message, undefined, actorAccountID); + const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; + const instructionCommentText = instructionComment.commentText; + + const instructionMessage: AddCommentOrAttachementParams = { + reportID: currTask.reportID, + reportActionID: instructionCommentAction.reportActionID, + reportComment: instructionCommentText, + }; + + return [ + ...acc, + { + parentReportActionID: taskAddCommentReport.reportAction.reportActionID, + parentReportID: currTask.parentReportID, + taskReportID: currTask.reportID, + createdTaskReportActionID: taskCreatedAction.reportActionID, + title: currTask.reportName, + description: currTask.description, + assigneeChatReportID: '', + type: 'task', + task: 'trackExpense', + }, + { + type: 'message', + ...subtitleMessage, + }, + { + type: 'message', + ...instructionMessage, + }, + ]; + }, []); + + const parameters = { + engagementChoice, + firstName, + lastName, + data: JSON.stringify([textMessage, videoMessage, ...tasks]), + }; + + // console.log('-------------------------------------'); + // console.log(JSON.stringify({...parameters, data: JSON.parse(parameters.data)}, ' ', 2)); + + API.write(WRITE_COMMANDS.COMPLETE_GUIDED_SETUP, parameters, {}); +} + /** * Completes the engagement modal that new NewDot users see when they first sign up/log in by doing the following: * @@ -3093,4 +3196,5 @@ export { setGroupDraft, clearGroupChat, startNewChat, + completeOnboarding, }; From c396f2af93022c2b13f38804517c122aa423a550 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Fri, 5 Apr 2024 16:31:47 +0200 Subject: [PATCH 04/54] feat: call method --- src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index ae43f850018b..bd8a7ab40917 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -80,7 +80,14 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, on return; } - Report.completeEngagementModal(CONST.ONBOARDING_CONCIERGE[selectedPurpose], selectedPurpose); + // Report.completeEngagementModal(CONST.ONBOARDING_CONCIERGE[selectedPurpose], selectedPurpose); + Report.completeOnboarding({ + data: CONST.ONBOARDING_MESSAGES[selectedPurpose], + engagementChoice: selectedPurpose, + targetEmail: CONST.EMAIL.CONCIERGE, + firstName: 'Test', + lastName: 'Testovsky', + }); Navigation.dismissModal(); // Only navigate to concierge chat when central pane is visible From 9ad33297839823d773b05331be3ca8a522aae2eb Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Wed, 10 Apr 2024 08:41:54 +0200 Subject: [PATCH 05/54] feat: added optimistic data --- src/libs/actions/Report.ts | 133 ++++++++++++++++++++++++++++++++----- 1 file changed, 117 insertions(+), 16 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 8fe56d93d634..8b280e11973b 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -71,6 +71,7 @@ import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/NewRoomForm'; import type {PersonalDetails, PersonalDetailsList, PolicyReportField, RecentlyUsedReportFields, ReportActionReactions, ReportMetadata, ReportUserIsTyping} from '@src/types/onyx'; +import type * as OnyxTypes from '@src/types/onyx'; import type {Decision, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; import type {NotificationPreference, RoomVisibility, WriteCapability} from '@src/types/onyx/Report'; import type Report from '@src/types/onyx/Report'; @@ -2788,38 +2789,50 @@ function completeOnboarding(properties: { const targetChatPolicyID = targetChatReport?.policyID ?? ''; // Text message - const textComment = ReportUtils.buildOptimisticAddCommentReportAction(data.message, undefined); + const textComment = ReportUtils.buildOptimisticAddCommentReportAction(data.message, undefined, actorAccountID); const textCommentAction: OptimisticAddCommentReportAction = textComment.reportAction; const textCommentText = textComment.commentText; - const textMessage: AddCommentOrAttachementParams & {type: string} = { + const textMessage: AddCommentOrAttachementParams = { reportID: targetChatReportID, reportActionID: textCommentAction.reportActionID, reportComment: textCommentText, - type: 'message', }; // Video message - const videoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined); + const videoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID); const videoCommentAction: OptimisticAddCommentReportAction = videoComment.reportAction; const videoCommentText = videoComment.commentText; - const videoMessage: AddCommentOrAttachementParams & {type: string} & typeof data.video = { + const videoMessage: AddCommentOrAttachementParams = { reportID: targetChatReportID, reportActionID: videoCommentAction.reportActionID, reportComment: videoCommentText, - type: 'video', - ...data.video, }; - // tasks - const tasks = data.tasks.reduce((acc, curr) => { - const currTask = ReportUtils.buildOptimisticTaskReport(actorAccountID, undefined, targetChatReportID, curr.title, undefined, targetChatPolicyID); + const tasksData = data.tasks.map((task) => { + const currTask = ReportUtils.buildOptimisticTaskReport(actorAccountID, undefined, targetChatReportID, task.title, undefined, targetChatPolicyID); const taskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(targetEmail); - const taskAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(currTask.reportID, curr.title, 0, `task for ${curr.title}`, targetChatReportID); + const taskAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(currTask.reportID, task.title, 0, `task for ${task.title}`, targetChatReportID); // subtitle message - const subtitleComment = ReportUtils.buildOptimisticAddCommentReportAction(curr.subtitle, undefined, actorAccountID); + const subtitleComment = ReportUtils.buildOptimisticAddCommentReportAction(task.subtitle, undefined, actorAccountID); + + // instruction message + const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(task.message, undefined, actorAccountID); + + return { + currTask, + taskCreatedAction, + taskAddCommentReport, + subtitleComment, + instructionComment, + }; + }); + + // tasks + const tasksForParameters = tasksData.reduce((acc, {currTask, taskCreatedAction, taskAddCommentReport, subtitleComment, instructionComment}) => { + // subtitle message const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; const subtitleCommentText = subtitleComment.commentText; @@ -2830,7 +2843,6 @@ function completeOnboarding(properties: { }; // instruction message - const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(curr.message, undefined, actorAccountID); const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; const instructionCommentText = instructionComment.commentText; @@ -2851,7 +2863,7 @@ function completeOnboarding(properties: { description: currTask.description, assigneeChatReportID: '', type: 'task', - task: 'trackExpense', + task: engagementChoice, }, { type: 'message', @@ -2864,17 +2876,101 @@ function completeOnboarding(properties: { ]; }, []); + const tasksForOptimisticData = tasksData.reduce((acc, {currTask, taskCreatedAction, subtitleComment, instructionComment}) => { + // subtitle message + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + const subtitleCommentText = subtitleComment.commentText; + + const subtitleMessage: AddCommentOrAttachementParams = { + reportID: currTask.reportID, + reportActionID: subtitleCommentAction.reportActionID, + reportComment: subtitleCommentText, + }; + + // instruction message + const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; + const instructionCommentText = instructionComment.commentText; + + const instructionMessage: AddCommentOrAttachementParams = { + reportID: currTask.reportID, + reportActionID: instructionCommentAction.reportActionID, + reportComment: instructionCommentText, + }; + + return [ + ...acc, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${currTask.reportID}`, + value: { + ...currTask, + 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, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currTask.reportID}`, + value: {[taskCreatedAction.reportActionID]: taskCreatedAction as OnyxTypes.ReportAction}, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${currTask.reportID}`, + value: {[subtitleMessage.reportID ?? '']: subtitleMessage, [instructionMessage.reportID ?? '']: instructionMessage}, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: { + [subtitleCommentAction.reportActionID ?? '']: subtitleCommentAction as ReportAction, + [instructionCommentAction.reportActionID ?? '']: instructionCommentAction as ReportAction, + }, + }, + ]; + }, []); + + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${targetChatReportID}`, + value: {[textMessage.reportID ?? '']: textMessage, [videoMessage.reportID ?? '']: videoMessage}, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: {[textCommentAction.reportActionID ?? '']: textCommentAction as ReportAction, [videoCommentAction.reportActionID ?? '']: videoCommentAction as ReportAction}, + }, + ...tasksForOptimisticData, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.NVP_INTRO_SELECTED, + value: {choice: engagementChoice}, + }, + ]; + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + value: {[textCommentAction.reportActionID ?? '']: {pendingAction: null}, [videoCommentAction.reportActionID ?? '']: {pendingAction: null}}, + }, + ]; + const parameters = { engagementChoice, firstName, lastName, - data: JSON.stringify([textMessage, videoMessage, ...tasks]), + data: JSON.stringify([{type: 'message', ...textMessage}, {type: 'video', ...data.video, ...videoMessage}, ...tasksForParameters]), }; // console.log('-------------------------------------'); // console.log(JSON.stringify({...parameters, data: JSON.parse(parameters.data)}, ' ', 2)); - API.write(WRITE_COMMANDS.COMPLETE_GUIDED_SETUP, parameters, {}); + API.write(WRITE_COMMANDS.COMPLETE_GUIDED_SETUP, parameters, {optimisticData, successData}); } /** @@ -2949,6 +3045,11 @@ function completeEngagementModal(text: string, choice: ValueOf Date: Wed, 10 Apr 2024 08:47:26 +0200 Subject: [PATCH 06/54] feat: added optimistic data --- src/libs/actions/Report.ts | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 8b280e11973b..3edd4515a1d2 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -726,6 +726,11 @@ function openReport( key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: settledPersonalDetails, }); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: settledPersonalDetails, + }); // Add the createdReportActionID parameter to the API call parameters.createdReportActionID = optimisticCreatedAction.reportActionID; @@ -1939,16 +1944,6 @@ function deleteReport(reportID: string) { Onyx.multiSet(onyxData); - // Clear the optimistic personal detail - const participantPersonalDetails: OnyxCollection = {}; - report?.participantAccountIDs?.forEach((accountID) => { - if (!allPersonalDetails?.[accountID]?.isOptimisticPersonalDetail) { - return; - } - participantPersonalDetails[accountID] = null; - }); - Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, participantPersonalDetails); - // Delete linked IOU report if (report?.iouReportID) { deleteReport(report.iouReportID); @@ -2900,7 +2895,7 @@ function completeOnboarding(properties: { return [ ...acc, { - onyxMethod: Onyx.METHOD.MERGE, + onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT}${currTask.reportID}`, value: { ...currTask, @@ -2967,9 +2962,6 @@ function completeOnboarding(properties: { data: JSON.stringify([{type: 'message', ...textMessage}, {type: 'video', ...data.video, ...videoMessage}, ...tasksForParameters]), }; - // console.log('-------------------------------------'); - // console.log(JSON.stringify({...parameters, data: JSON.parse(parameters.data)}, ' ', 2)); - API.write(WRITE_COMMANDS.COMPLETE_GUIDED_SETUP, parameters, {optimisticData, successData}); } From 1077782645bd53ca71eb3cc53d0cfbada1a29ec5 Mon Sep 17 00:00:00 2001 From: bartektomczyk Date: Wed, 10 Apr 2024 11:01:34 +0200 Subject: [PATCH 07/54] feat: update method --- src/libs/actions/Report.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 3edd4515a1d2..3f288c29723c 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2920,7 +2920,7 @@ function completeOnboarding(properties: { }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currTask.reportID}`, value: { [subtitleCommentAction.reportActionID ?? '']: subtitleCommentAction as ReportAction, [instructionCommentAction.reportActionID ?? '']: instructionCommentAction as ReportAction, @@ -2940,7 +2940,6 @@ function completeOnboarding(properties: { key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, value: {[textCommentAction.reportActionID ?? '']: textCommentAction as ReportAction, [videoCommentAction.reportActionID ?? '']: videoCommentAction as ReportAction}, }, - ...tasksForOptimisticData, { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.NVP_INTRO_SELECTED, @@ -2962,7 +2961,7 @@ function completeOnboarding(properties: { data: JSON.stringify([{type: 'message', ...textMessage}, {type: 'video', ...data.video, ...videoMessage}, ...tasksForParameters]), }; - API.write(WRITE_COMMANDS.COMPLETE_GUIDED_SETUP, parameters, {optimisticData, successData}); + API.write(WRITE_COMMANDS.COMPLETE_GUIDED_SETUP, parameters, {}); } /** @@ -3037,11 +3036,6 @@ function completeEngagementModal(text: string, choice: ValueOf Date: Thu, 11 Apr 2024 17:00:33 +0200 Subject: [PATCH 08/54] minor fixes of onboarding messages --- src/CONST.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index f5b8ae572cea..65192eedfc94 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3610,12 +3610,12 @@ const CONST = { tasks: [ { title: 'Create a workspace', - subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more. ', + subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more.', message: 'Here’s how to create a workspace:\n' + '\n' + '1. Click your profile picture.\n' + - '2. Click Workspaces > New workspace.\n' + + '2. Click Workspaces > New workspace.\n' + '\n' + 'Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.', }, @@ -3683,7 +3683,7 @@ const CONST = { tasks: [ { title: 'Create a workspace', - subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more. ', + subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more.', message: 'Here’s how to create a workspace:\n' + '\n' + @@ -3712,7 +3712,7 @@ const CONST = { '4. Enable and disable default categories.\n' + '5. Click Add categories to make your own.\n' + '\n' + - 'For more controls like requiring a category for every expense, click Settings. ', + 'For more controls like requiring a category for every expense, click Settings.', }, { title: 'Add expense approvals', @@ -3726,7 +3726,7 @@ const CONST = { '4. Enable Workflows.\n' + '5. In Workflows, enable Add approvals.\n' + '\n' + - 'You’ll be set as the expense approver. You can change this to any admin once you invite your team. ', + 'You’ll be set as the expense approver. You can change this to any admin once you invite your team.', }, { title: 'Invite your team', @@ -3785,7 +3785,7 @@ const CONST = { message: 'Here’s how to start a chat:\n' + '\n' + - '1. rClick the green + button.\n' + + '1. Click the green + button.\n' + '2. Choose Start chat.\n' + '3. Enter emails or phone numbers.\n' + '\n' + From e08f94d3239463edcbbdc47bc6d892120c2020a7 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 11 Apr 2024 17:00:57 +0200 Subject: [PATCH 09/54] create CompleteGuidedSetupParams --- src/libs/API/parameters/CompleteGuidedSetupParams.ts | 11 +++++++++++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 1 + 3 files changed, 13 insertions(+) create mode 100644 src/libs/API/parameters/CompleteGuidedSetupParams.ts diff --git a/src/libs/API/parameters/CompleteGuidedSetupParams.ts b/src/libs/API/parameters/CompleteGuidedSetupParams.ts new file mode 100644 index 000000000000..5ed7b18815af --- /dev/null +++ b/src/libs/API/parameters/CompleteGuidedSetupParams.ts @@ -0,0 +1,11 @@ +import type {ValueOf} from 'type-fest'; +import type CONST from '@src/CONST'; + +type CompleteGuidedSetupParams = { + firstName: string; + lastName: string; + guidedSetupData: string; + engagementChoice: ValueOf; +}; + +export default CompleteGuidedSetupParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 6f5505b263fb..de12dfbe10d3 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -199,3 +199,4 @@ export type {default as SetPolicyForeignCurrencyDefaultParams} from './SetPolicy export type {default as SetPolicyCurrencyDefaultParams} from './SetPolicyCurrencyDefaultParams'; export type {default as UpdatePolicyConnectionConfigParams} from './UpdatePolicyConnectionConfigParams'; export type {default as RenamePolicyTaxParams} from './RenamePolicyTaxParams'; +export type {default as CompleteGuidedSetupParams} from './CompleteGuidedSetupParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index c33e96731bdc..ad48aecb08f0 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -324,6 +324,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.REOPEN_TASK]: Parameters.ReopenTaskParams; [WRITE_COMMANDS.COMPLETE_TASK]: Parameters.CompleteTaskParams; [WRITE_COMMANDS.COMPLETE_ENGAGEMENT_MODAL]: Parameters.CompleteEngagementModalParams; + [WRITE_COMMANDS.COMPLETE_GUIDED_SETUP]: Parameters.CompleteGuidedSetupParams; [WRITE_COMMANDS.SET_NAME_VALUE_PAIR]: Parameters.SetNameValuePairParams; [WRITE_COMMANDS.SET_REPORT_FIELD]: Parameters.SetReportFieldParams; [WRITE_COMMANDS.SET_REPORT_NAME]: Parameters.SetReportNameParams; From 202b1117f5c8949784ed1d1435955f16776e00c4 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 11 Apr 2024 17:01:37 +0200 Subject: [PATCH 10/54] integrate setDisplayName --- src/libs/actions/PersonalDetails.ts | 18 ++++++++++++++++++ .../BaseOnboardingPersonalDetails.tsx | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/PersonalDetails.ts b/src/libs/actions/PersonalDetails.ts index 8248b721c416..b9cea5c9447c 100644 --- a/src/libs/actions/PersonalDetails.ts +++ b/src/libs/actions/PersonalDetails.ts @@ -65,6 +65,23 @@ function updatePronouns(pronouns: string) { }); } +function setDisplayName(firstName: string, lastName: string) { + if (!currentUserAccountID) { + return; + } + + Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { + [currentUserAccountID]: { + firstName, + lastName, + displayName: PersonalDetailsUtils.createDisplayName(currentUserEmail ?? '', { + firstName, + lastName, + }), + }, + }); +} + function updateDisplayName(firstName: string, lastName: string) { if (!currentUserAccountID) { return; @@ -411,6 +428,7 @@ export { updateAutomaticTimezone, updateAvatar, updateDateOfBirth, + setDisplayName, updateDisplayName, updateLegalName, updatePronouns, diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index f49c5c0f506e..248d4af4e9d0 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -37,7 +37,7 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat const {shouldUseNarrowLayout} = useOnboardingLayout(); const saveAndNavigate = useCallback((values: FormOnyxValues<'onboardingPersonalDetailsForm'>) => { - PersonalDetails.updateDisplayName(values.firstName.trim(), values.lastName.trim()); + PersonalDetails.setDisplayName(values.firstName.trim(), values.lastName.trim()); Navigation.navigate(ROUTES.ONBOARDING_PURPOSE); }, []); From fdb7f46dc1b5d612740e2da1ac4571bfd3ae1a54 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 11 Apr 2024 17:02:23 +0200 Subject: [PATCH 11/54] extend functions in ReportUtils --- src/libs/ReportUtils.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index e49c2f25ccc4..48296cb03892 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3173,7 +3173,14 @@ function updateOptimisticParentReportAction(parentReportAction: OnyxEntry Date: Thu, 11 Apr 2024 17:03:51 +0200 Subject: [PATCH 12/54] improve completeOnboarding --- src/libs/actions/Report.ts | 128 ++++++++++++------ .../BaseOnboardingPurpose.tsx | 4 - 2 files changed, 89 insertions(+), 43 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 3f288c29723c..21217ee12bd6 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -15,6 +15,7 @@ import type { AddEmojiReactionParams, AddWorkspaceRoomParams, CompleteEngagementModalParams, + CompleteGuidedSetupParams, DeleteCommentParams, ExpandURLPreviewParams, FlagCommentParams, @@ -70,13 +71,20 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/NewRoomForm'; -import type {PersonalDetails, PersonalDetailsList, PolicyReportField, RecentlyUsedReportFields, ReportActionReactions, ReportMetadata, ReportUserIsTyping} from '@src/types/onyx'; -import type * as OnyxTypes from '@src/types/onyx'; +import type { + PersonalDetails, + PersonalDetailsList, + PolicyReportField, + RecentlyUsedReportFields, + ReportAction, + ReportActionReactions, + ReportMetadata, + ReportUserIsTyping, +} from '@src/types/onyx'; import type {Decision, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; import type {NotificationPreference, RoomVisibility, WriteCapability} from '@src/types/onyx/Report'; import type Report from '@src/types/onyx/Report'; import type {Message, ReportActionBase, ReportActions} from '@src/types/onyx/ReportAction'; -import type ReportAction from '@src/types/onyx/ReportAction'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as CachedPDFPaths from './CachedPDFPaths'; @@ -2770,19 +2778,29 @@ function getReportPrivateNote(reportID: string | undefined) { API.read(READ_COMMANDS.GET_REPORT_PRIVATE_NOTE, parameters, {optimisticData, successData, failureData}); } -function completeOnboarding(properties: { - data: ValueOf; - firstName: string; - lastName: string; - targetEmail: ValueOf; - engagementChoice: ValueOf; -}) { - const {data, engagementChoice, targetEmail, firstName, lastName} = properties; +// #region completeOnboarding +function completeOnboarding(properties: {data: ValueOf; engagementChoice: ValueOf}) { + const {data, engagementChoice} = properties; + const targetEmail = CONST.EMAIL.CONCIERGE; + const login = allPersonalDetails?.[currentUserAccountID]?.login ?? ''; + const firstName = allPersonalDetails?.[currentUserAccountID]?.firstName ?? ''; + const lastName = allPersonalDetails?.[currentUserAccountID]?.lastName ?? ''; const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID]); const targetChatReportID = targetChatReport?.reportID ?? ''; const targetChatPolicyID = targetChatReport?.policyID ?? ''; + // Mention message + const mentionComment = ReportUtils.buildOptimisticAddCommentReportAction(`Hey @${login} 👋`, undefined, actorAccountID); + const mentionCommentAction: OptimisticAddCommentReportAction = mentionComment.reportAction; + const mentionCommentText = mentionComment.commentText; + + const mentionMessage: AddCommentOrAttachementParams = { + reportID: targetChatReportID, + reportActionID: mentionCommentAction.reportActionID, + reportComment: mentionCommentText, + }; + // Text message const textComment = ReportUtils.buildOptimisticAddCommentReportAction(data.message, undefined, actorAccountID); const textCommentAction: OptimisticAddCommentReportAction = textComment.reportAction; @@ -2806,9 +2824,17 @@ function completeOnboarding(properties: { }; const tasksData = data.tasks.map((task) => { - const currTask = ReportUtils.buildOptimisticTaskReport(actorAccountID, undefined, targetChatReportID, task.title, undefined, targetChatPolicyID); + const currentTask = ReportUtils.buildOptimisticTaskReport( + actorAccountID, + undefined, + targetChatReportID, + task.title, + undefined, + targetChatPolicyID, + CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + ); const taskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(targetEmail); - const taskAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(currTask.reportID, task.title, 0, `task for ${task.title}`, targetChatReportID); + const taskReportAction = ReportUtils.buildOptimisticTaskCommentReportAction(currentTask.reportID, task.title, 0, `task for ${task.title}`, targetChatReportID, actorAccountID); // subtitle message const subtitleComment = ReportUtils.buildOptimisticAddCommentReportAction(task.subtitle, undefined, actorAccountID); @@ -2817,22 +2843,22 @@ function completeOnboarding(properties: { const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(task.message, undefined, actorAccountID); return { - currTask, + currentTask, taskCreatedAction, - taskAddCommentReport, + taskReportAction, subtitleComment, instructionComment, }; }); // tasks - const tasksForParameters = tasksData.reduce((acc, {currTask, taskCreatedAction, taskAddCommentReport, subtitleComment, instructionComment}) => { + const tasksForParameters = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { // subtitle message const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; const subtitleCommentText = subtitleComment.commentText; const subtitleMessage: AddCommentOrAttachementParams = { - reportID: currTask.reportID, + reportID: currentTask.reportID, reportActionID: subtitleCommentAction.reportActionID, reportComment: subtitleCommentText, }; @@ -2842,7 +2868,7 @@ function completeOnboarding(properties: { const instructionCommentText = instructionComment.commentText; const instructionMessage: AddCommentOrAttachementParams = { - reportID: currTask.reportID, + reportID: currentTask.reportID, reportActionID: instructionCommentAction.reportActionID, reportComment: instructionCommentText, }; @@ -2850,12 +2876,12 @@ function completeOnboarding(properties: { return [ ...acc, { - parentReportActionID: taskAddCommentReport.reportAction.reportActionID, - parentReportID: currTask.parentReportID, - taskReportID: currTask.reportID, + parentReportActionID: taskReportAction.reportAction.reportActionID, + parentReportID: currentTask.parentReportID, + taskReportID: currentTask.reportID, createdTaskReportActionID: taskCreatedAction.reportActionID, - title: currTask.reportName, - description: currTask.description, + title: currentTask.reportName, + description: currentTask.description, assigneeChatReportID: '', type: 'task', task: engagementChoice, @@ -2871,13 +2897,13 @@ function completeOnboarding(properties: { ]; }, []); - const tasksForOptimisticData = tasksData.reduce((acc, {currTask, taskCreatedAction, subtitleComment, instructionComment}) => { + const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { // subtitle message const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; const subtitleCommentText = subtitleComment.commentText; const subtitleMessage: AddCommentOrAttachementParams = { - reportID: currTask.reportID, + reportID: currentTask.reportID, reportActionID: subtitleCommentAction.reportActionID, reportComment: subtitleCommentText, }; @@ -2887,18 +2913,25 @@ function completeOnboarding(properties: { const instructionCommentText = instructionComment.commentText; const instructionMessage: AddCommentOrAttachementParams = { - reportID: currTask.reportID, + reportID: currentTask.reportID, reportActionID: instructionCommentAction.reportActionID, reportComment: instructionCommentText, }; return [ ...acc, + { + 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}${currTask.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, value: { - ...currTask, + ...currentTask, pendingFields: { createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, reportName: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, @@ -2910,17 +2943,20 @@ function completeOnboarding(properties: { }, { onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currTask.reportID}`, - value: {[taskCreatedAction.reportActionID]: taskCreatedAction as OnyxTypes.ReportAction}, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: {[taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction}, }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${currTask.reportID}`, - value: {[subtitleMessage.reportID ?? '']: subtitleMessage, [instructionMessage.reportID ?? '']: instructionMessage}, + key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, + value: { + [subtitleMessage.reportID ?? '']: subtitleMessage, + [instructionMessage.reportID ?? '']: instructionMessage, + }, }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currTask.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, value: { [subtitleCommentAction.reportActionID ?? '']: subtitleCommentAction as ReportAction, [instructionCommentAction.reportActionID ?? '']: instructionCommentAction as ReportAction, @@ -2930,15 +2966,25 @@ function completeOnboarding(properties: { }, []); const optimisticData: OnyxUpdate[] = [ + ...tasksForOptimisticData, { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${targetChatReportID}`, - value: {[textMessage.reportID ?? '']: textMessage, [videoMessage.reportID ?? '']: videoMessage}, + value: { + [mentionMessage.reportID ?? '']: mentionMessage, + [textMessage.reportID ?? '']: textMessage, + [videoMessage.reportID ?? '']: videoMessage, + lastMentionedTime: DateUtils.getDBTime(), + }, }, { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: {[textCommentAction.reportActionID ?? '']: textCommentAction as ReportAction, [videoCommentAction.reportActionID ?? '']: videoCommentAction as ReportAction}, + value: { + [mentionCommentAction.reportActionID ?? '']: mentionCommentAction as ReportAction, + [textCommentAction.reportActionID ?? '']: textCommentAction as ReportAction, + [videoCommentAction.reportActionID ?? '']: videoCommentAction as ReportAction, + }, }, { onyxMethod: Onyx.METHOD.MERGE, @@ -2950,18 +2996,22 @@ function completeOnboarding(properties: { { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: {[textCommentAction.reportActionID ?? '']: {pendingAction: null}, [videoCommentAction.reportActionID ?? '']: {pendingAction: null}}, + value: { + [mentionCommentAction.reportActionID ?? '']: {pendingAction: null}, + [textCommentAction.reportActionID ?? '']: {pendingAction: null}, + [videoCommentAction.reportActionID ?? '']: {pendingAction: null}, + }, }, ]; - const parameters = { + const parameters: CompleteGuidedSetupParams = { engagementChoice, firstName, lastName, - data: JSON.stringify([{type: 'message', ...textMessage}, {type: 'video', ...data.video, ...videoMessage}, ...tasksForParameters]), + guidedSetupData: JSON.stringify([{type: 'message', ...mentionMessage, ...textMessage}, {type: 'video', ...data.video, ...videoMessage}, ...tasksForParameters]), }; - API.write(WRITE_COMMANDS.COMPLETE_GUIDED_SETUP, parameters, {}); + API.write(WRITE_COMMANDS.COMPLETE_GUIDED_SETUP, parameters, {optimisticData, successData}); } /** diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index bd8a7ab40917..62b8b072381b 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -80,13 +80,9 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, on return; } - // Report.completeEngagementModal(CONST.ONBOARDING_CONCIERGE[selectedPurpose], selectedPurpose); Report.completeOnboarding({ data: CONST.ONBOARDING_MESSAGES[selectedPurpose], engagementChoice: selectedPurpose, - targetEmail: CONST.EMAIL.CONCIERGE, - firstName: 'Test', - lastName: 'Testovsky', }); Navigation.dismissModal(); From 4f291f065706f049c42249fc9458ecd7703cd8d7 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 12 Apr 2024 12:21:47 +0200 Subject: [PATCH 13/54] simplify CompleteGuidedSetupParams --- src/libs/API/parameters/CompleteGuidedSetupParams.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libs/API/parameters/CompleteGuidedSetupParams.ts b/src/libs/API/parameters/CompleteGuidedSetupParams.ts index 5ed7b18815af..6835949382ca 100644 --- a/src/libs/API/parameters/CompleteGuidedSetupParams.ts +++ b/src/libs/API/parameters/CompleteGuidedSetupParams.ts @@ -1,11 +1,8 @@ -import type {ValueOf} from 'type-fest'; -import type CONST from '@src/CONST'; - type CompleteGuidedSetupParams = { firstName: string; lastName: string; guidedSetupData: string; - engagementChoice: ValueOf; + engagementChoice: string; }; export default CompleteGuidedSetupParams; From a32e5ea885d006af6852090fff52139e4d09ad32 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 12 Apr 2024 12:23:08 +0200 Subject: [PATCH 14/54] add todo --- src/libs/actions/Report.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 209ead38f4d7..b77979aadd45 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2788,6 +2788,7 @@ function getReportPrivateNote(reportID: string | undefined) { API.read(READ_COMMANDS.GET_REPORT_PRIVATE_NOTE, parameters, {optimisticData, successData, failureData}); } +// TODO: Clear region // #region completeOnboarding function completeOnboarding(properties: {data: ValueOf; engagementChoice: ValueOf}) { const {data, engagementChoice} = properties; From 30678e2d54a70d5cde2bddcd107d0c6884a1a1fa Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 12 Apr 2024 12:40:35 +0200 Subject: [PATCH 15/54] improve completeOnboarding --- src/libs/actions/Report.ts | 50 +++++++++++++------ .../BaseOnboardingPurpose.tsx | 5 +- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index b77979aadd45..34097945269e 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -99,6 +99,27 @@ type ActionSubscriber = { callback: SubscriberCallback; }; +type TaskForParameters = + | { + type: 'task'; + task: string; + taskReportID: string; + parentReportID: string; + parentReportActionID: string; + assigneeChatReportID: string; + createdTaskReportActionID: string; + title: string; + description: string; + } + | { + type: 'message'; + reportID: string; + reportActionID: string; + reportComment: string; + }; + +type TaskMessage = Required>; + let conciergeChatReportID: string | undefined; let currentUserAccountID = -1; let currentUserEmail: string | undefined; @@ -2790,12 +2811,9 @@ function getReportPrivateNote(reportID: string | undefined) { // TODO: Clear region // #region completeOnboarding -function completeOnboarding(properties: {data: ValueOf; engagementChoice: ValueOf}) { - const {data, engagementChoice} = properties; +function completeOnboarding(engagementChoice: string, data: ValueOf) { const targetEmail = CONST.EMAIL.CONCIERGE; - const login = allPersonalDetails?.[currentUserAccountID]?.login ?? ''; - const firstName = allPersonalDetails?.[currentUserAccountID]?.firstName ?? ''; - const lastName = allPersonalDetails?.[currentUserAccountID]?.lastName ?? ''; + const {login = '', firstName = '', lastName = ''} = allPersonalDetails?.[currentUserAccountID] ?? {}; const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID]); const targetChatReportID = targetChatReport?.reportID ?? ''; @@ -2863,12 +2881,12 @@ function completeOnboarding(properties: {data: ValueOf((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { + const tasksForParameters = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { // subtitle message const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; const subtitleCommentText = subtitleComment.commentText; - const subtitleMessage: AddCommentOrAttachementParams = { + const subtitleMessage: TaskMessage = { reportID: currentTask.reportID, reportActionID: subtitleCommentAction.reportActionID, reportComment: subtitleCommentText, @@ -2878,7 +2896,7 @@ function completeOnboarding(properties: {data: ValueOf Date: Fri, 12 Apr 2024 14:08:40 +0200 Subject: [PATCH 16/54] pass timestamp into getDBTimeWithSkew --- src/libs/DateUtils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 44c7682b47f2..cd0ad4dace94 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -378,11 +378,11 @@ function getDBTime(timestamp: string | number = ''): string { /** * Returns the current time plus skew in milliseconds in the format expected by the database */ -function getDBTimeWithSkew(): string { +function getDBTimeWithSkew(timestamp: string | number = ''): string { if (networkTimeSkew > 0) { - return getDBTime(new Date().valueOf() + networkTimeSkew); + return getDBTime(new Date(timestamp).valueOf() + networkTimeSkew); } - return getDBTime(); + return getDBTime(timestamp); } function subtractMillisecondsFromDateTime(dateTime: string, milliseconds: number): string { From 98175c1a989d5d0ec5c6c5261bdcd67b7a016d60 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 12 Apr 2024 14:08:59 +0200 Subject: [PATCH 17/54] pass createdOffset into buildOptimistic function --- src/libs/ReportUtils.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 24482de2c1d2..dd84cc7e2920 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3095,7 +3095,7 @@ function getPolicyDescriptionText(policy: OnyxEntry): string { return parser.htmlToText(policy.description); } -function buildOptimisticAddCommentReportAction(text?: string, file?: FileObject, actorAccountID?: number): OptimisticReportAction { +function buildOptimisticAddCommentReportAction(text?: string, file?: FileObject, actorAccountID?: number, createdOffset = 0): OptimisticReportAction { const parser = new ExpensiMark(); const commentText = getParsedComment(text ?? ''); const isAttachmentOnly = file && !text; @@ -3134,7 +3134,7 @@ function buildOptimisticAddCommentReportAction(text?: string, file?: FileObject, ], automatic: false, avatar: allPersonalDetails?.[accountID ?? -1]?.avatar ?? UserUtils.getDefaultAvatarURL(accountID), - created: DateUtils.getDBTimeWithSkew(), + created: DateUtils.getDBTimeWithSkew(Date.now() + createdOffset), message: [ { translationKey: isAttachmentOnly ? CONST.TRANSLATION_KEYS.ATTACHMENT : '', @@ -3202,6 +3202,7 @@ function updateOptimisticParentReportAction(parentReportAction: OnyxEntry Date: Fri, 12 Apr 2024 14:09:30 +0200 Subject: [PATCH 18/54] fix bugs and improve completeOnboarding --- src/libs/actions/Report.ts | 82 +++++++++++--------------------------- 1 file changed, 24 insertions(+), 58 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 34097945269e..0dbf8b561299 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2809,29 +2809,19 @@ function getReportPrivateNote(reportID: string | undefined) { API.read(READ_COMMANDS.GET_REPORT_PRIVATE_NOTE, parameters, {optimisticData, successData, failureData}); } -// TODO: Clear region -// #region completeOnboarding function completeOnboarding(engagementChoice: string, data: ValueOf) { const targetEmail = CONST.EMAIL.CONCIERGE; const {login = '', firstName = '', lastName = ''} = allPersonalDetails?.[currentUserAccountID] ?? {}; const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID]); - const targetChatReportID = targetChatReport?.reportID ?? ''; - const targetChatPolicyID = targetChatReport?.policyID ?? ''; + const {reportID: targetChatReportID = '', policyID: targetChatPolicyID = ''} = targetChatReport ?? {}; // Mention message - const mentionComment = ReportUtils.buildOptimisticAddCommentReportAction(`Hey @${login} 👋`, undefined, actorAccountID); + const mentionComment = ReportUtils.buildOptimisticAddCommentReportAction(`Hey @${login.split('@')[0]} 👋`, undefined, actorAccountID); const mentionCommentAction: OptimisticAddCommentReportAction = mentionComment.reportAction; - const mentionCommentText = mentionComment.commentText; - - const mentionMessage: AddCommentOrAttachementParams = { - reportID: targetChatReportID, - reportActionID: mentionCommentAction.reportActionID, - reportComment: mentionCommentText, - }; // Text message - const textComment = ReportUtils.buildOptimisticAddCommentReportAction(data.message, undefined, actorAccountID); + const textComment = ReportUtils.buildOptimisticAddCommentReportAction(data.message, undefined, actorAccountID, 1); const textCommentAction: OptimisticAddCommentReportAction = textComment.reportAction; const textCommentText = textComment.commentText; @@ -2842,7 +2832,7 @@ function completeOnboarding(engagementChoice: string, data: ValueOf { + const tasksData = data.tasks.map((task, index) => { const currentTask = ReportUtils.buildOptimisticTaskReport( actorAccountID, undefined, @@ -2863,7 +2853,15 @@ function completeOnboarding(engagementChoice: string, data: ValueOf((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { - // subtitle message const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; - const subtitleCommentText = subtitleComment.commentText; - - const subtitleMessage: AddCommentOrAttachementParams = { - reportID: currentTask.reportID, - reportActionID: subtitleCommentAction.reportActionID, - reportComment: subtitleCommentText, - }; - - // instruction message const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; - const instructionCommentText = instructionComment.commentText; - - const instructionMessage: AddCommentOrAttachementParams = { - reportID: currentTask.reportID, - reportActionID: instructionCommentAction.reportActionID, - reportComment: instructionCommentText, - }; return [ ...acc, @@ -2953,7 +2934,7 @@ function completeOnboarding(engagementChoice: string, data: ValueOf Date: Fri, 12 Apr 2024 15:08:58 +0200 Subject: [PATCH 19/54] avoid text escaping --- src/libs/ReportUtils.ts | 8 ++++---- src/libs/actions/Report.ts | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index dd84cc7e2920..33e667e0b250 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3053,7 +3053,7 @@ function hasReportNameError(report: OnyxEntry): boolean { * For comments shorter than or equal to 10k chars, convert the comment from MD into HTML because that's how it is stored in the database * For longer comments, skip parsing, but still escape the text, and display plaintext for performance reasons. It takes over 40s to parse a 100k long string!! */ -function getParsedComment(text: string): string { +function getParsedComment(text: string, shouldEscapeText?: boolean): string { const parser = new ExpensiMark(); const textWithMention = text.replace(CONST.REGEX.SHORT_MENTION, (match) => { const mention = match.substring(1); @@ -3074,7 +3074,7 @@ function getParsedComment(text: string): string { return match; }); - return text.length <= CONST.MAX_MARKUP_LENGTH ? parser.replace(textWithMention, {shouldEscapeText: !shouldAllowRawHTMLMessages()}) : lodashEscape(text); + return text.length <= CONST.MAX_MARKUP_LENGTH ? parser.replace(textWithMention, {shouldEscapeText: shouldEscapeText ?? !shouldAllowRawHTMLMessages()}) : lodashEscape(text); } function getReportDescriptionText(report: Report): string { @@ -3095,9 +3095,9 @@ function getPolicyDescriptionText(policy: OnyxEntry): string { return parser.htmlToText(policy.description); } -function buildOptimisticAddCommentReportAction(text?: string, file?: FileObject, actorAccountID?: number, createdOffset = 0): OptimisticReportAction { +function buildOptimisticAddCommentReportAction(text?: string, file?: FileObject, actorAccountID?: number, createdOffset = 0, shouldEscapeText?: boolean): OptimisticReportAction { const parser = new ExpensiMark(); - const commentText = getParsedComment(text ?? ''); + const commentText = getParsedComment(text ?? '', shouldEscapeText); const isAttachmentOnly = file && !text; const isTextOnly = text && !file; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 0dbf8b561299..d62cd8498edd 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2865,9 +2865,7 @@ function completeOnboarding(engagementChoice: string, data: ValueOf Date: Fri, 12 Apr 2024 15:35:11 +0200 Subject: [PATCH 20/54] add replies config --- src/libs/ReportUtils.ts | 27 +++++++++++++++++++++++++++ src/libs/actions/Report.ts | 8 ++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 33e667e0b250..b5a180547a47 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -140,6 +140,10 @@ type OptimisticAddCommentReportAction = Pick< | 'childStatusNum' | 'childStateNum' | 'errors' + | 'childVisibleActionCount' + | 'childCommenterCount' + | 'childLastVisibleActionCreated' + | 'childOldestFourAccountIDs' > & {isOptimisticAction: boolean}; type OptimisticReportAction = { @@ -3212,6 +3216,12 @@ function buildOptimisticTaskCommentReportAction( parentReportID: string, actorAccountID?: number, createdOffset = 0, + repliesConfig?: { + childVisibleActionCount?: number; + childCommenterCount?: number; + childLastVisibleActionCreated?: string; + childOldestFourAccountIDs?: string; + }, ): OptimisticReportAction { const reportAction = buildOptimisticAddCommentReportAction(text, undefined, undefined, createdOffset); if (reportAction.reportAction.message?.[0]) { @@ -3231,10 +3241,27 @@ function buildOptimisticTaskCommentReportAction( reportAction.reportAction.childManagerAccountID = taskAssigneeAccountID; reportAction.reportAction.childStatusNum = CONST.REPORT.STATUS_NUM.OPEN; reportAction.reportAction.childStateNum = CONST.REPORT.STATE_NUM.OPEN; + if (actorAccountID) { reportAction.reportAction.actorAccountID = actorAccountID; } + if (repliesConfig?.childVisibleActionCount) { + reportAction.reportAction.childVisibleActionCount = repliesConfig.childVisibleActionCount; + } + + if (repliesConfig?.childCommenterCount) { + reportAction.reportAction.childCommenterCount = repliesConfig.childCommenterCount; + } + + if (repliesConfig?.childLastVisibleActionCreated) { + reportAction.reportAction.childLastVisibleActionCreated = repliesConfig.childLastVisibleActionCreated; + } + + if (repliesConfig?.childOldestFourAccountIDs) { + reportAction.reportAction.childOldestFourAccountIDs = repliesConfig.childOldestFourAccountIDs; + } + return reportAction; } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index d62cd8498edd..4f7965b6839b 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2861,9 +2861,13 @@ function completeOnboarding(engagementChoice: string, data: ValueOf Date: Fri, 12 Apr 2024 16:02:30 +0200 Subject: [PATCH 21/54] pass mentionMessage and prettify --- src/libs/actions/Report.ts | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 4f7965b6839b..31e0662501a9 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2819,27 +2819,28 @@ function completeOnboarding(engagementChoice: string, data: ValueOf { @@ -2880,22 +2881,17 @@ function completeOnboarding(engagementChoice: string, data: ValueOf((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { - // subtitle message const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; const subtitleCommentText = subtitleComment.commentText; - const subtitleMessage: TaskMessage = { reportID: currentTask.reportID, reportActionID: subtitleCommentAction.reportActionID, reportComment: subtitleCommentText, }; - // instruction message const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; const instructionCommentText = instructionComment.commentText; - const instructionMessage: TaskMessage = { reportID: currentTask.reportID, reportActionID: instructionCommentAction.reportActionID, @@ -3005,7 +3001,7 @@ function completeOnboarding(engagementChoice: string, data: ValueOf Date: Fri, 12 Apr 2024 16:46:36 +0200 Subject: [PATCH 22/54] change ordering of pages --- src/components/TestToolMenu.tsx | 2 +- src/languages/en.ts | 1 - src/languages/es.ts | 1 - .../Navigators/OnboardingModalNavigator.tsx | 8 +-- .../BottomTabBar.tsx | 10 +-- src/libs/Navigation/linkingConfig/config.ts | 10 +-- .../BaseOnboardingPersonalDetails.tsx | 67 +++++++++++++------ .../index.native.tsx | 4 +- src/pages/OnboardingPersonalDetails/index.tsx | 4 +- .../BaseOnboardingPurpose.tsx | 34 ++-------- src/pages/OnboardingPurpose/types.ts | 23 ++++++- 11 files changed, 90 insertions(+), 74 deletions(-) diff --git a/src/components/TestToolMenu.tsx b/src/components/TestToolMenu.tsx index 527b92d4d7dc..4d1f7fe51a62 100644 --- a/src/components/TestToolMenu.tsx +++ b/src/components/TestToolMenu.tsx @@ -97,7 +97,7 @@ function TestToolMenu({user = USER_DEFAULT, network}: TestToolMenuProps) { text="Navigate" onPress={() => { Navigation.dismissModal(); - Navigation.navigate(ROUTES.ONBOARDING_PERSONAL_DETAILS); + Navigation.navigate(ROUTES.ONBOARDING_PURPOSE); }} /> diff --git a/src/languages/en.ts b/src/languages/en.ts index dbdda0d35635..076666fc595b 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1316,7 +1316,6 @@ export default { notYou: ({user}: NotYouParams) => `Not ${user}?`, }, onboarding: { - welcome: 'Welcome!', welcomeVideo: { title: 'Welcome to Expensify', description: 'Getting paid is as easy as sending a message.', diff --git a/src/languages/es.ts b/src/languages/es.ts index e81efa07a58c..30cada0d6534 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1318,7 +1318,6 @@ export default { notYou: ({user}: NotYouParams) => `¿No eres ${user}?`, }, onboarding: { - welcome: '¡Bienvenido!', welcomeVideo: { title: 'Bienvenido a Expensify', description: 'Cobrar es tan fácil como enviar un mensaje.', diff --git a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx index 6f4fbb08403b..3791cbc03641 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx @@ -23,14 +23,14 @@ function OnboardingModalNavigator() { - + diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 391468578fab..b48b54d22f89 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -48,16 +48,8 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps return; } - // Welcome.isOnboardingFlowCompleted({onNotCompleted: () => Navigation.navigate(ROUTES.ONBOARDING_PERSONAL_DETAILS)}); Welcome.isOnboardingFlowCompleted({ - onNotCompleted: () => - Navigation.navigate( - // Uncomment once Stage 1 Onboarding Flow is ready - // - // ROUTES.ONBOARDING_PERSONAL_DETAILS - // - ROUTES.ONBOARD, - ), + onNotCompleted: () => Navigation.navigate(ROUTES.ONBOARDING_PURPOSE), }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoadingApp]); diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 95294b7711b5..9401aa40281d 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -91,16 +91,16 @@ const config: LinkingOptions['config'] = { }, [NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR]: { path: ROUTES.ONBOARDING_ROOT, - initialRouteName: SCREENS.ONBOARDING.PERSONAL_DETAILS, + initialRouteName: SCREENS.ONBOARDING.PURPOSE, screens: { - [SCREENS.ONBOARDING.PERSONAL_DETAILS]: { - path: ROUTES.ONBOARDING_PERSONAL_DETAILS, - exact: true, - }, [SCREENS.ONBOARDING.PURPOSE]: { path: ROUTES.ONBOARDING_PURPOSE, exact: true, }, + [SCREENS.ONBOARDING.PERSONAL_DETAILS]: { + path: ROUTES.ONBOARDING_PERSONAL_DETAILS, + exact: true, + }, }, }, [NAVIGATORS.RIGHT_MODAL_NAVIGATOR]: { diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index 248d4af4e9d0..80d48a7cc29d 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -1,5 +1,6 @@ import React, {useCallback} from 'react'; import {View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormOnyxValues} from '@components/Form/types'; @@ -8,39 +9,56 @@ import KeyboardAvoidingView from '@components/KeyboardAvoidingView'; import OfflineIndicator from '@components/OfflineIndicator'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; -import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import useOnboardingLayout from '@hooks/useOnboardingLayout'; -import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ValidationUtils from '@libs/ValidationUtils'; +import type {BaseOnboardingPersonalDetailsOnyxProps, BaseOnboardingPersonalDetailsProps} from '@pages/OnboardingPurpose/types'; +import variables from '@styles/variables'; import * as PersonalDetails from '@userActions/PersonalDetails'; +import * as Report from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/DisplayNameForm'; -type BaseOnboardingPersonalDetailsProps = { - /* Whether to use native styles tailored for native devices */ - shouldUseNativeStyles: boolean; -}; - -function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNativeStyles}: WithCurrentUserPersonalDetailsProps & BaseOnboardingPersonalDetailsProps) { - const theme = useTheme(); +function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNativeStyles, onboardingPurposeSelected}: BaseOnboardingPersonalDetailsProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {isSmallScreenWidth} = useWindowDimensions(); const {shouldUseNarrowLayout} = useOnboardingLayout(); - const saveAndNavigate = useCallback((values: FormOnyxValues<'onboardingPersonalDetailsForm'>) => { - PersonalDetails.setDisplayName(values.firstName.trim(), values.lastName.trim()); + const completeEngagement = useCallback( + (values: FormOnyxValues<'onboardingPersonalDetailsForm'>) => { + PersonalDetails.setDisplayName(values.firstName.trim(), values.lastName.trim()); - Navigation.navigate(ROUTES.ONBOARDING_PURPOSE); - }, []); + if (!onboardingPurposeSelected) { + return; + } + + Report.completeOnboarding(onboardingPurposeSelected, CONST.ONBOARDING_MESSAGES[onboardingPurposeSelected]); + + Navigation.dismissModal(); + // Only navigate to concierge chat when central pane is visible + // Otherwise stay on the chats screen. + if (isSmallScreenWidth) { + Navigation.navigate(ROUTES.HOME); + } else { + Report.navigateToConciergeChat(); + } + + // Small delay purely due to design considerations, + // no special technical reasons behind that. + setTimeout(() => { + Navigation.navigate(ROUTES.WELCOME_VIDEO_ROOT); + }, variables.welcomeVideoDelay); + }, + [isSmallScreenWidth, onboardingPurposeSelected], + ); const validate = (values: FormOnyxValues<'onboardingPersonalDetailsForm'>) => { const errors = {}; @@ -74,14 +92,18 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat return errors; }; + const handleGoBack = useCallback(() => { + Navigation.goBack(); + }, []); + const PersonalDetailsFooterInstance = ; return ( - {translate('onboarding.welcome')} {translate('onboarding.whatsYourName')} @@ -141,6 +162,10 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat BaseOnboardingPersonalDetails.displayName = 'BaseOnboardingPersonalDetails'; -export default withCurrentUserPersonalDetails(BaseOnboardingPersonalDetails); - -export type {BaseOnboardingPersonalDetailsProps}; +export default withCurrentUserPersonalDetails( + withOnyx({ + onboardingPurposeSelected: { + key: ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, + }, + })(BaseOnboardingPersonalDetails), +); diff --git a/src/pages/OnboardingPersonalDetails/index.native.tsx b/src/pages/OnboardingPersonalDetails/index.native.tsx index 3c49a13178e6..778d68e39458 100644 --- a/src/pages/OnboardingPersonalDetails/index.native.tsx +++ b/src/pages/OnboardingPersonalDetails/index.native.tsx @@ -1,8 +1,8 @@ import React from 'react'; -import type {BaseOnboardingPersonalDetailsProps} from './BaseOnboardingPersonalDetails'; +import type {OnboardingPersonalDetailsProps} from '@pages/OnboardingPurpose/types'; import BaseOnboardingPersonalDetails from './BaseOnboardingPersonalDetails'; -function OnboardingPersonalDetails({...rest}: Omit) { +function OnboardingPersonalDetails({...rest}: Omit) { return ( ) { +function OnboardingPersonalDetails({...rest}: Omit) { return ( { - Navigation.goBack(); - }, []); - const selectedCheckboxIcon = useMemo( () => ( @@ -75,28 +70,13 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, on [styles.pointerEventsAuto, styles.popoverMenuIcon, theme.success], ); - const completeEngagement = useCallback(() => { + const saveAndNavigate = useCallback(() => { if (selectedPurpose === undefined) { return; } - Report.completeOnboarding(selectedPurpose, CONST.ONBOARDING_MESSAGES[selectedPurpose]); - - Navigation.dismissModal(); - // Only navigate to concierge chat when central pane is visible - // Otherwise stay on the chats screen. - if (isSmallScreenWidth) { - Navigation.navigate(ROUTES.HOME); - } else { - Report.navigateToConciergeChat(); - } - - // Small delay purely due to design considerations, - // no special technical reasons behind that. - setTimeout(() => { - Navigation.navigate(ROUTES.WELCOME_VIDEO_ROOT); - }, variables.welcomeVideoDelay); - }, [isSmallScreenWidth, selectedPurpose]); + Navigation.navigate(ROUTES.ONBOARDING_PERSONAL_DETAILS); + }, [selectedPurpose]); const menuItems: MenuItemProps[] = Object.values(CONST.ONBOARDING_CHOICES).map((choice) => { const translationKey = `onboarding.purpose.${choice}` as const; @@ -126,9 +106,9 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, on @@ -152,7 +132,7 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, on return; } setError(false); - completeEngagement(); + saveAndNavigate(); }} message={errorMessage} isAlertVisible={error || Boolean(errorMessage)} diff --git a/src/pages/OnboardingPurpose/types.ts b/src/pages/OnboardingPurpose/types.ts index 586463a26bb0..15d6beec1f6f 100644 --- a/src/pages/OnboardingPurpose/types.ts +++ b/src/pages/OnboardingPurpose/types.ts @@ -1,4 +1,5 @@ import type {OnyxEntry} from 'react-native-onyx'; +import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; type OnboardingPurposeProps = Record; @@ -16,4 +17,24 @@ type BaseOnboardingPurposeProps = OnboardingPurposeProps & shouldEnableMaxHeight: boolean; }; -export type {BaseOnboardingPurposeOnyxProps, BaseOnboardingPurposeProps, OnboardingPurposeProps}; +type OnboardingPersonalDetailsProps = Record; + +type BaseOnboardingPersonalDetailsOnyxProps = { + /** Saved onboarding purpose selected by the user */ + onboardingPurposeSelected: OnyxEntry; +}; + +type BaseOnboardingPersonalDetailsProps = WithCurrentUserPersonalDetailsProps & + BaseOnboardingPersonalDetailsOnyxProps & { + /* Whether to use native styles tailored for native devices */ + shouldUseNativeStyles: boolean; + }; + +export type { + BaseOnboardingPurposeOnyxProps, + BaseOnboardingPurposeProps, + OnboardingPurposeProps, + OnboardingPersonalDetailsProps, + BaseOnboardingPersonalDetailsOnyxProps, + BaseOnboardingPersonalDetailsProps, +}; From f5cd44bbba30f2294149d7f96454b67ca1b063d4 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 12 Apr 2024 16:52:00 +0200 Subject: [PATCH 23/54] fix bottom padding --- .../OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index 80d48a7cc29d..bf39940e1536 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -110,7 +110,7 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat behavior="padding" > Date: Fri, 12 Apr 2024 16:56:50 +0200 Subject: [PATCH 24/54] pass current user info --- src/libs/actions/Report.ts | 14 +++++++++++++- .../BaseOnboardingPersonalDetails.tsx | 13 ++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 31e0662501a9..75ab3c530e36 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2809,7 +2809,19 @@ function getReportPrivateNote(reportID: string | undefined) { API.read(READ_COMMANDS.GET_REPORT_PRIVATE_NOTE, parameters, {optimisticData, successData, failureData}); } -function completeOnboarding(engagementChoice: string, data: ValueOf) { +function completeOnboarding( + engagementChoice: string, + data: ValueOf, + { + login, + firstName, + lastName, + }: { + login: string; + firstName: string; + lastName: string; + }, +) { const targetEmail = CONST.EMAIL.CONCIERGE; const {login = '', firstName = '', lastName = ''} = allPersonalDetails?.[currentUserAccountID] ?? {}; const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index bf39940e1536..776050dc681d 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -34,13 +34,20 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat const completeEngagement = useCallback( (values: FormOnyxValues<'onboardingPersonalDetailsForm'>) => { - PersonalDetails.setDisplayName(values.firstName.trim(), values.lastName.trim()); + const firstName = values.firstName.trim(); + const lastName = values.lastName.trim(); + + PersonalDetails.setDisplayName(firstName, lastName); if (!onboardingPurposeSelected) { return; } - Report.completeOnboarding(onboardingPurposeSelected, CONST.ONBOARDING_MESSAGES[onboardingPurposeSelected]); + Report.completeOnboarding(onboardingPurposeSelected, CONST.ONBOARDING_MESSAGES[onboardingPurposeSelected], { + login: currentUserPersonalDetails.login ?? '', + firstName, + lastName, + }); Navigation.dismissModal(); // Only navigate to concierge chat when central pane is visible @@ -57,7 +64,7 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat Navigation.navigate(ROUTES.WELCOME_VIDEO_ROOT); }, variables.welcomeVideoDelay); }, - [isSmallScreenWidth, onboardingPurposeSelected], + [currentUserPersonalDetails.login, isSmallScreenWidth, onboardingPurposeSelected], ); const validate = (values: FormOnyxValues<'onboardingPersonalDetailsForm'>) => { From 1fb2411c29bb7e4c22e29a8aacbd0da230c2cf09 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 12 Apr 2024 17:13:20 +0200 Subject: [PATCH 25/54] remove line --- src/libs/actions/Report.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 75ab3c530e36..c8ba2b5c0593 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2823,7 +2823,6 @@ function completeOnboarding( }, ) { const targetEmail = CONST.EMAIL.CONCIERGE; - const {login = '', firstName = '', lastName = ''} = allPersonalDetails?.[currentUserAccountID] ?? {}; const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; const targetChatReport = ReportUtils.getChatByParticipants([actorAccountID]); const {reportID: targetChatReportID = '', policyID: targetChatPolicyID = ''} = targetChatReport ?? {}; From 0d23206b7144b63858a5fe52ad97008cafc38b4d Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 15 Apr 2024 17:28:08 +0200 Subject: [PATCH 26/54] integrate OnboardingWork page --- src/ONYXKEYS.ts | 3 + src/ROUTES.ts | 1 + src/SCREENS.ts | 1 + src/languages/en.ts | 2 + src/languages/es.ts | 2 + .../Navigators/OnboardingModalNavigator.tsx | 5 + src/libs/Navigation/linkingConfig/config.ts | 4 + src/libs/Navigation/types.ts | 1 + .../OnboardingWork/BaseOnboardingWork.tsx | 148 ++++++++++++++++++ src/pages/OnboardingWork/index.native.tsx | 17 ++ src/pages/OnboardingWork/index.tsx | 17 ++ src/pages/OnboardingWork/types.ts | 17 ++ src/types/form/WorkForm.ts | 18 +++ src/types/form/index.ts | 1 + 14 files changed, 237 insertions(+) create mode 100644 src/pages/OnboardingWork/BaseOnboardingWork.tsx create mode 100644 src/pages/OnboardingWork/index.native.tsx create mode 100644 src/pages/OnboardingWork/index.tsx create mode 100644 src/pages/OnboardingWork/types.ts create mode 100644 src/types/form/WorkForm.ts diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index cda74da86a54..fe06f9ca71d8 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -384,6 +384,8 @@ const ONYXKEYS = { DISPLAY_NAME_FORM_DRAFT: 'displayNameFormDraft', ONBOARDING_PERSONAL_DETAILS_FORM: 'onboardingPersonalDetailsForm', ONBOARDING_PERSONAL_DETAILS_FORM_DRAFT: 'onboardingPersonalDetailsFormDraft', + ONBOARDING_PERSONAL_WORK: 'onboardingWorkForm', + ONBOARDING_PERSONAL_WORK_DRAFT: 'onboardingWorkFormDraft', ROOM_NAME_FORM: 'roomNameForm', ROOM_NAME_FORM_DRAFT: 'roomNameFormDraft', REPORT_DESCRIPTION_FORM: 'reportDescriptionForm', @@ -474,6 +476,7 @@ type OnyxFormValuesMapping = { [ONYXKEYS.FORMS.PROFILE_SETTINGS_FORM]: FormTypes.ProfileSettingsForm; [ONYXKEYS.FORMS.DISPLAY_NAME_FORM]: FormTypes.DisplayNameForm; [ONYXKEYS.FORMS.ONBOARDING_PERSONAL_DETAILS_FORM]: FormTypes.DisplayNameForm; + [ONYXKEYS.FORMS.ONBOARDING_PERSONAL_WORK]: FormTypes.WorkForm; [ONYXKEYS.FORMS.ROOM_NAME_FORM]: FormTypes.RoomNameForm; [ONYXKEYS.FORMS.REPORT_DESCRIPTION_FORM]: FormTypes.ReportDescriptionForm; [ONYXKEYS.FORMS.LEGAL_NAME_FORM]: FormTypes.LegalNameForm; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 8e4c84f24965..c924e8e86554 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -700,6 +700,7 @@ const ROUTES = { PROCESS_MONEY_REQUEST_HOLD: 'hold-request-educational', ONBOARDING_ROOT: 'onboarding', ONBOARDING_PERSONAL_DETAILS: 'onboarding/personal-details', + ONBOARDING_WORK: 'onboarding/work', ONBOARDING_PURPOSE: 'onboarding/purpose', WELCOME_VIDEO_ROOT: 'onboarding/welcome-video', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 96372d5bbabb..0c709dec955d 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -287,6 +287,7 @@ const SCREENS = { ONBOARDING: { PERSONAL_DETAILS: 'Onboarding_Personal_Details', PURPOSE: 'Onboarding_Purpose', + WORK: 'Onboarding_Work', }, ONBOARD_ENGAGEMENT: { diff --git a/src/languages/en.ts b/src/languages/en.ts index 0793590f69b1..538b2f0b7965 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -320,6 +320,7 @@ export default { subtitleText2: 'button above, or create something using the', subtitleText3: 'button below.', }, + businessName: 'Business name', }, location: { useCurrent: 'Use current location', @@ -1335,6 +1336,7 @@ export default { button: "Let's go", }, whatsYourName: "What's your name?", + whereYouWork: 'Where do you work?', purpose: { title: 'What do you want to do today?', error: 'Please make a selection before continuing', diff --git a/src/languages/es.ts b/src/languages/es.ts index d7e60b53a55a..9a7dc6ffdcb4 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -310,6 +310,7 @@ export default { subtitleText2: 'o crea algo usando el botón', subtitleText3: '.', }, + businessName: 'Nombre del Negocio', }, location: { useCurrent: 'Usar ubicación actual', @@ -1337,6 +1338,7 @@ export default { button: 'Vámonos', }, whatsYourName: '¿Cómo te llamas?', + whereYouWork: '¿Dónde trabajas?', purpose: { title: '¿Qué quieres hacer hoy?', error: 'Por favor, haga una selección antes de continuar.', diff --git a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx index 3791cbc03641..ef3f6340f3e4 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx @@ -8,6 +8,7 @@ import OnboardingModalNavigatorScreenOptions from '@libs/Navigation/AppNavigator import type {OnboardingModalNavigatorParamList} from '@libs/Navigation/types'; import OnboardingPersonalDetails from '@pages/OnboardingPersonalDetails'; import OnboardingPurpose from '@pages/OnboardingPurpose'; +import OnboardingWork from '@pages/OnboardingWork'; import SCREENS from '@src/SCREENS'; import Overlay from './Overlay'; @@ -31,6 +32,10 @@ function OnboardingModalNavigator() { name={SCREENS.ONBOARDING.PERSONAL_DETAILS} component={OnboardingPersonalDetails} /> + diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index e577f6843d66..e060d86e0967 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -105,6 +105,10 @@ const config: LinkingOptions['config'] = { path: ROUTES.ONBOARDING_PERSONAL_DETAILS, exact: true, }, + [SCREENS.ONBOARDING.WORK]: { + path: ROUTES.ONBOARDING_WORK, + exact: true, + }, }, }, [NAVIGATORS.RIGHT_MODAL_NAVIGATOR]: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 09591cfd78db..2520d81744e8 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -710,6 +710,7 @@ type OnboardingModalNavigatorParamList = { [SCREENS.ONBOARDING_MODAL.ONBOARDING]: undefined; [SCREENS.ONBOARDING.PERSONAL_DETAILS]: undefined; [SCREENS.ONBOARDING.PURPOSE]: undefined; + [SCREENS.ONBOARDING.WORK]: undefined; }; type WelcomeVideoModalNavigatorParamList = { diff --git a/src/pages/OnboardingWork/BaseOnboardingWork.tsx b/src/pages/OnboardingWork/BaseOnboardingWork.tsx new file mode 100644 index 000000000000..d00f17ad955b --- /dev/null +++ b/src/pages/OnboardingWork/BaseOnboardingWork.tsx @@ -0,0 +1,148 @@ +import React, {useCallback} from 'react'; +import {View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; +import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import KeyboardAvoidingView from '@components/KeyboardAvoidingView'; +import OfflineIndicator from '@components/OfflineIndicator'; +import Text from '@components/Text'; +import TextInput from '@components/TextInput'; +import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; +import useDisableModalDismissOnEscape from '@hooks/useDisableModalDismissOnEscape'; +import useLocalize from '@hooks/useLocalize'; +import useOnboardingLayout from '@hooks/useOnboardingLayout'; +import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; +import * as ErrorUtils from '@libs/ErrorUtils'; +import Navigation from '@libs/Navigation/Navigation'; +import * as ValidationUtils from '@libs/ValidationUtils'; +import variables from '@styles/variables'; +import * as Policy from '@userActions/Policy'; +import * as Report from '@userActions/Report'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import INPUT_IDS from '@src/types/form/WorkForm'; +import type {BaseOnboardingWorkOnyxProps, BaseOnboardingWorkProps} from './types'; + +function BaseOnboardingWork({currentUserPersonalDetails, shouldUseNativeStyles, onboardingPurposeSelected}: BaseOnboardingWorkProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const {isSmallScreenWidth} = useWindowDimensions(); + const {shouldUseNarrowLayout} = useOnboardingLayout(); + + useDisableModalDismissOnEscape(); + + const completeEngagement = useCallback( + (values: FormOnyxValues<'onboardingWorkForm'>) => { + if (!onboardingPurposeSelected) { + return; + } + + const work = values.work.trim(); + + Policy.createDraftInitialWorkspace(currentUserPersonalDetails.login ?? '', work, undefined, true); + + Report.completeOnboarding(onboardingPurposeSelected, CONST.ONBOARDING_MESSAGES[onboardingPurposeSelected], { + login: currentUserPersonalDetails.login ?? '', + firstName: currentUserPersonalDetails.firstName ?? '', + lastName: currentUserPersonalDetails.lastName ?? '', + }); + + Navigation.dismissModal(); + // Only navigate to concierge chat when central pane is visible + // Otherwise stay on the chats screen. + if (isSmallScreenWidth) { + Navigation.navigate(ROUTES.HOME); + } else { + Report.navigateToConciergeChat(); + } + + // Small delay purely due to design considerations, + // no special technical reasons behind that. + setTimeout(() => { + Navigation.navigate(ROUTES.WELCOME_VIDEO_ROOT); + }, variables.welcomeVideoDelay); + }, + [currentUserPersonalDetails.firstName, currentUserPersonalDetails.lastName, currentUserPersonalDetails.login, isSmallScreenWidth, onboardingPurposeSelected], + ); + + const validate = (values: FormOnyxValues<'onboardingWorkForm'>) => { + const errors: FormInputErrors = {}; + const work = values.work.trim(); + + if (!ValidationUtils.isRequiredFulfilled(work)) { + errors.work = 'workspace.editor.nameIsRequiredError'; + } else if ([...work].length > CONST.TITLE_CHARACTER_LIMIT) { + // Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16 + // code units. + ErrorUtils.addErrorMessage(errors, 'work', ['common.error.characterLimitExceedCounter', {length: [...work].length, limit: CONST.TITLE_CHARACTER_LIMIT}]); + } + + return errors; + }; + + const handleGoBack = useCallback(() => { + Navigation.goBack(); + }, []); + + const WorkFooterInstance = ; + + return ( + + + + + + {translate('onboarding.whereYouWork')} + + + + + + + + ); +} + +BaseOnboardingWork.displayName = 'BaseOnboardingWork'; + +export default withCurrentUserPersonalDetails( + withOnyx({ + onboardingPurposeSelected: { + key: ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, + }, + })(BaseOnboardingWork), +); diff --git a/src/pages/OnboardingWork/index.native.tsx b/src/pages/OnboardingWork/index.native.tsx new file mode 100644 index 000000000000..3e69696aa45a --- /dev/null +++ b/src/pages/OnboardingWork/index.native.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import BaseOnboardingWork from './BaseOnboardingWork'; +import type {OnboardingWorkProps} from './types'; + +function OnboardingWork({...rest}: Omit) { + return ( + + ); +} + +OnboardingWork.displayName = 'OnboardingWork'; + +export default OnboardingWork; diff --git a/src/pages/OnboardingWork/index.tsx b/src/pages/OnboardingWork/index.tsx new file mode 100644 index 000000000000..ba1b8aaeb106 --- /dev/null +++ b/src/pages/OnboardingWork/index.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import BaseOnboardingWork from './BaseOnboardingWork'; +import type {OnboardingWorkProps} from './types'; + +function OnboardingWork({...rest}: Omit) { + return ( + + ); +} + +OnboardingWork.displayName = 'OnboardingPurpose'; + +export default OnboardingWork; diff --git a/src/pages/OnboardingWork/types.ts b/src/pages/OnboardingWork/types.ts new file mode 100644 index 000000000000..930a8081e9c4 --- /dev/null +++ b/src/pages/OnboardingWork/types.ts @@ -0,0 +1,17 @@ +import type {OnyxEntry} from 'react-native-onyx'; +import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; + +type OnboardingWorkProps = Record; + +type BaseOnboardingWorkOnyxProps = { + /** Saved onboarding purpose selected by the user */ + onboardingPurposeSelected: OnyxEntry; +}; + +type BaseOnboardingWorkProps = WithCurrentUserPersonalDetailsProps & + BaseOnboardingWorkOnyxProps & { + /* Whether to use native styles tailored for native devices */ + shouldUseNativeStyles: boolean; + }; + +export type {OnboardingWorkProps, BaseOnboardingWorkOnyxProps, BaseOnboardingWorkProps}; diff --git a/src/types/form/WorkForm.ts b/src/types/form/WorkForm.ts new file mode 100644 index 000000000000..6e5fa8a89311 --- /dev/null +++ b/src/types/form/WorkForm.ts @@ -0,0 +1,18 @@ +import type {ValueOf} from 'type-fest'; +import type Form from './Form'; + +const INPUT_IDS = { + WORK: 'work', +} as const; + +type InputID = ValueOf; + +type WorkForm = Form< + InputID, + { + [INPUT_IDS.WORK]: string; + } +>; + +export type {WorkForm}; +export default INPUT_IDS; diff --git a/src/types/form/index.ts b/src/types/form/index.ts index ce3fcd428999..ddddb99ab89b 100644 --- a/src/types/form/index.ts +++ b/src/types/form/index.ts @@ -48,4 +48,5 @@ export type {WorkspaceTaxCustomName} from './WorkspaceTaxCustomName'; export type {PolicyCreateDistanceRateForm} from './PolicyCreateDistanceRateForm'; export type {PolicyDistanceRateEditForm} from './PolicyDistanceRateEditForm'; export type {NewChatNameForm} from './NewChatNameForm'; +export type {WorkForm} from './WorkForm'; export type {default as Form} from './Form'; From 19d7d50711aed59471d79c7dd6794ca887ff6fa5 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 15 Apr 2024 17:29:12 +0200 Subject: [PATCH 27/54] move types --- .../BaseOnboardingPersonalDetails.tsx | 2 +- .../index.native.tsx | 2 +- src/pages/OnboardingPersonalDetails/index.tsx | 2 +- src/pages/OnboardingPersonalDetails/types.ts | 17 ++++++++++++++ src/pages/OnboardingPurpose/types.ts | 23 +------------------ 5 files changed, 21 insertions(+), 25 deletions(-) create mode 100644 src/pages/OnboardingPersonalDetails/types.ts diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index dac3b4e3d4c1..b1e14b077931 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -18,7 +18,6 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ValidationUtils from '@libs/ValidationUtils'; -import type {BaseOnboardingPersonalDetailsOnyxProps, BaseOnboardingPersonalDetailsProps} from '@pages/OnboardingPurpose/types'; import variables from '@styles/variables'; import * as PersonalDetails from '@userActions/PersonalDetails'; import * as Report from '@userActions/Report'; @@ -26,6 +25,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/DisplayNameForm'; +import type {BaseOnboardingPersonalDetailsOnyxProps, BaseOnboardingPersonalDetailsProps} from './types'; function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNativeStyles, onboardingPurposeSelected}: BaseOnboardingPersonalDetailsProps) { const styles = useThemeStyles(); diff --git a/src/pages/OnboardingPersonalDetails/index.native.tsx b/src/pages/OnboardingPersonalDetails/index.native.tsx index 778d68e39458..b5a4d42f0de1 100644 --- a/src/pages/OnboardingPersonalDetails/index.native.tsx +++ b/src/pages/OnboardingPersonalDetails/index.native.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type {OnboardingPersonalDetailsProps} from '@pages/OnboardingPurpose/types'; import BaseOnboardingPersonalDetails from './BaseOnboardingPersonalDetails'; +import type {OnboardingPersonalDetailsProps} from './types'; function OnboardingPersonalDetails({...rest}: Omit) { return ( diff --git a/src/pages/OnboardingPersonalDetails/index.tsx b/src/pages/OnboardingPersonalDetails/index.tsx index 8409e7e8f0a2..d6a408ee7381 100644 --- a/src/pages/OnboardingPersonalDetails/index.tsx +++ b/src/pages/OnboardingPersonalDetails/index.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import type {OnboardingPersonalDetailsProps} from '@pages/OnboardingPurpose/types'; import BaseOnboardingPersonalDetails from './BaseOnboardingPersonalDetails'; +import type {OnboardingPersonalDetailsProps} from './types'; function OnboardingPersonalDetails({...rest}: Omit) { return ( diff --git a/src/pages/OnboardingPersonalDetails/types.ts b/src/pages/OnboardingPersonalDetails/types.ts new file mode 100644 index 000000000000..6d286373a1ac --- /dev/null +++ b/src/pages/OnboardingPersonalDetails/types.ts @@ -0,0 +1,17 @@ +import type {OnyxEntry} from 'react-native-onyx'; +import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; + +type OnboardingPersonalDetailsProps = Record; + +type BaseOnboardingPersonalDetailsOnyxProps = { + /** Saved onboarding purpose selected by the user */ + onboardingPurposeSelected: OnyxEntry; +}; + +type BaseOnboardingPersonalDetailsProps = WithCurrentUserPersonalDetailsProps & + BaseOnboardingPersonalDetailsOnyxProps & { + /* Whether to use native styles tailored for native devices */ + shouldUseNativeStyles: boolean; + }; + +export type {OnboardingPersonalDetailsProps, BaseOnboardingPersonalDetailsOnyxProps, BaseOnboardingPersonalDetailsProps}; diff --git a/src/pages/OnboardingPurpose/types.ts b/src/pages/OnboardingPurpose/types.ts index 15d6beec1f6f..586463a26bb0 100644 --- a/src/pages/OnboardingPurpose/types.ts +++ b/src/pages/OnboardingPurpose/types.ts @@ -1,5 +1,4 @@ import type {OnyxEntry} from 'react-native-onyx'; -import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; type OnboardingPurposeProps = Record; @@ -17,24 +16,4 @@ type BaseOnboardingPurposeProps = OnboardingPurposeProps & shouldEnableMaxHeight: boolean; }; -type OnboardingPersonalDetailsProps = Record; - -type BaseOnboardingPersonalDetailsOnyxProps = { - /** Saved onboarding purpose selected by the user */ - onboardingPurposeSelected: OnyxEntry; -}; - -type BaseOnboardingPersonalDetailsProps = WithCurrentUserPersonalDetailsProps & - BaseOnboardingPersonalDetailsOnyxProps & { - /* Whether to use native styles tailored for native devices */ - shouldUseNativeStyles: boolean; - }; - -export type { - BaseOnboardingPurposeOnyxProps, - BaseOnboardingPurposeProps, - OnboardingPurposeProps, - OnboardingPersonalDetailsProps, - BaseOnboardingPersonalDetailsOnyxProps, - BaseOnboardingPersonalDetailsProps, -}; +export type {BaseOnboardingPurposeOnyxProps, BaseOnboardingPurposeProps, OnboardingPurposeProps}; From ed44ffdb16a55cc84abcaae96101951ed56f39c3 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 15 Apr 2024 17:43:08 +0200 Subject: [PATCH 28/54] integrate onboarding work --- .../BaseOnboardingPersonalDetails.tsx | 8 ++++++++ src/pages/OnboardingWork/BaseOnboardingWork.tsx | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index b1e14b077931..a2e3765baa9c 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -46,6 +46,14 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat return; } + const openWorkPagePurposes = [CONST.ONBOARDING_CHOICES.EMPLOYER, CONST.ONBOARDING_CHOICES.MANAGE_TEAM]; + + if (openWorkPagePurposes.includes(onboardingPurposeSelected)) { + Navigation.navigate(ROUTES.ONBOARDING_WORK); + + return; + } + Report.completeOnboarding(onboardingPurposeSelected, CONST.ONBOARDING_MESSAGES[onboardingPurposeSelected], { login: currentUserPersonalDetails.login ?? '', firstName, diff --git a/src/pages/OnboardingWork/BaseOnboardingWork.tsx b/src/pages/OnboardingWork/BaseOnboardingWork.tsx index d00f17ad955b..01ec23c8315c 100644 --- a/src/pages/OnboardingWork/BaseOnboardingWork.tsx +++ b/src/pages/OnboardingWork/BaseOnboardingWork.tsx @@ -43,7 +43,7 @@ function BaseOnboardingWork({currentUserPersonalDetails, shouldUseNativeStyles, const work = values.work.trim(); - Policy.createDraftInitialWorkspace(currentUserPersonalDetails.login ?? '', work, undefined, true); + Policy.createWorkspace(currentUserPersonalDetails.login ?? '', true, work); Report.completeOnboarding(onboardingPurposeSelected, CONST.ONBOARDING_MESSAGES[onboardingPurposeSelected], { login: currentUserPersonalDetails.login ?? '', From 41851acf298e8146bb503bbbfcdd911d2e75ef70 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 15 Apr 2024 18:34:02 +0200 Subject: [PATCH 29/54] clarify work cases --- .../OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index a2e3765baa9c..5657f8553113 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -46,7 +46,7 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat return; } - const openWorkPagePurposes = [CONST.ONBOARDING_CHOICES.EMPLOYER, CONST.ONBOARDING_CHOICES.MANAGE_TEAM]; + const openWorkPagePurposes = [CONST.ONBOARDING_CHOICES.TRACK, CONST.ONBOARDING_CHOICES.MANAGE_TEAM]; if (openWorkPagePurposes.includes(onboardingPurposeSelected)) { Navigation.navigate(ROUTES.ONBOARDING_WORK); From 23268d16205517037012dd334129bc9426fd7893 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 15 Apr 2024 19:10:58 +0200 Subject: [PATCH 30/54] fix onboarding screen options --- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index fde0202d3d2f..0edceee43647 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -369,7 +369,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie /> Date: Tue, 16 Apr 2024 13:07:50 +0200 Subject: [PATCH 31/54] add video to tasks --- src/CONST.ts | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index a9d8ba6baece..039598dd2b8a 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3620,6 +3620,13 @@ const CONST = { '2. Click Workspaces > New workspace.\n' + '\n' + 'Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, { title: 'Track an expense', @@ -3633,6 +3640,13 @@ const CONST = { '4. Click Track.\n' + '\n' + 'And you’re done! Yep, it’s that easy.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, ], }, @@ -3658,6 +3672,13 @@ const CONST = { '4. Add your reimburser to the request.\n' + '\n' + 'Then, send your request and wait for that sweet “Cha-ching!” when it’s complete.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, { title: 'Enable your wallet', @@ -3670,6 +3691,13 @@ const CONST = { '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.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, ], }, @@ -3693,6 +3721,13 @@ const CONST = { '2. Click Workspaces > New workspace.\n' + '\n' + 'Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, { title: 'Meet your setup specialist', @@ -3701,6 +3736,13 @@ const CONST = { 'Meet your setup specialist, {guideName}, who can answer any questions as you get started with Expensify. Yes, a real human!\n' + '\n' + 'Chat with {guideName} in your [admins room]({adminsRoomID}) or [schedule a call]({guideCalendarLink}) today', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, { title: 'Set up categories', @@ -3715,6 +3757,13 @@ const CONST = { '5. Click Add categories to make your own.\n' + '\n' + 'For more controls like requiring a category for every expense, click Settings.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, { title: 'Add expense approvals', @@ -3729,6 +3778,13 @@ const CONST = { '5. In Workflows, enable Add approvals.\n' + '\n' + 'You’ll be set as the expense approver. You can change this to any admin once you invite your team.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, { title: 'Invite your team', @@ -3743,6 +3799,13 @@ const CONST = { '5. Add an invite message if you want.\n' + '\n' + 'That’s it! Happy expensing :)', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, ], }, @@ -3768,6 +3831,13 @@ const CONST = { '4. Click Track.\n' + '\n' + 'And you’re done! Yep, it’s that easy.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, ], }, @@ -3794,6 +3864,13 @@ const CONST = { 'If any of your friends aren’t using Expensify already, they’ll be invited automatically. \n' + '\n' + 'Every chat will also turn into an email or text that they can respond to directly.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, { title: 'Split an expense', @@ -3807,6 +3884,13 @@ const CONST = { '4. Add your friend(s) to the request.\n' + '\n' + 'Feel free to add more details if you want, or just send it off. Let’s get you paid back!', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, { title: 'Enable your wallet', @@ -3819,6 +3903,13 @@ const CONST = { '3. Add your bank account.\n' + '\n' + 'Once that’s done, you can request money from anyone and get paid right into your personal bank account.', + video: { + url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, + thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, + duration: 55, + width: 1280, + height: 960, + }, }, ], }, From 5df95e03a0bf73c9c5238fcde740066204f04bac Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 16 Apr 2024 13:24:08 +0200 Subject: [PATCH 32/54] fix workspace creating --- src/pages/OnboardingWork/BaseOnboardingWork.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/OnboardingWork/BaseOnboardingWork.tsx b/src/pages/OnboardingWork/BaseOnboardingWork.tsx index 01ec23c8315c..22ebb57489c2 100644 --- a/src/pages/OnboardingWork/BaseOnboardingWork.tsx +++ b/src/pages/OnboardingWork/BaseOnboardingWork.tsx @@ -43,7 +43,7 @@ function BaseOnboardingWork({currentUserPersonalDetails, shouldUseNativeStyles, const work = values.work.trim(); - Policy.createWorkspace(currentUserPersonalDetails.login ?? '', true, work); + Policy.createWorkspace(undefined, true, work); Report.completeOnboarding(onboardingPurposeSelected, CONST.ONBOARDING_MESSAGES[onboardingPurposeSelected], { login: currentUserPersonalDetails.login ?? '', From ca821a012f3de8599139f740dfa846b58e77f124 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 16 Apr 2024 13:34:11 +0200 Subject: [PATCH 33/54] integrate video to tasks --- src/libs/actions/Report.ts | 106 +++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index cdf38af7f3f2..4e2aa729c706 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -118,6 +118,13 @@ type TaskForParameters = createdTaskReportActionID: string; title: string; description: string; + video: { + url: string; + thumbnailUrl: string; + duration: number; + width: number; + height: number; + }; } | { type: 'message'; @@ -3019,60 +3026,80 @@ function completeOnboarding( }, ); const subtitleComment = ReportUtils.buildOptimisticAddCommentReportAction(task.subtitle, undefined, actorAccountID); + const taskVideoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID); const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(task.message, undefined, actorAccountID, undefined, false); return { + task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, + taskVideoComment, instructionComment, }; }); - const tasksForParameters = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { - const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; - const subtitleCommentText = subtitleComment.commentText; - const subtitleMessage: TaskMessage = { - reportID: currentTask.reportID, - reportActionID: subtitleCommentAction.reportActionID, - reportComment: subtitleCommentText, - }; + const tasksForParameters = tasksData.reduce( + (acc, {task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, taskVideoComment, instructionComment}) => { + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + const subtitleCommentText = subtitleComment.commentText; + const subtitleMessage: TaskMessage = { + reportID: currentTask.reportID, + reportActionID: subtitleCommentAction.reportActionID, + reportComment: subtitleCommentText, + }; - const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; - const instructionCommentText = instructionComment.commentText; - const instructionMessage: TaskMessage = { - reportID: currentTask.reportID, - reportActionID: instructionCommentAction.reportActionID, - reportComment: instructionCommentText, - }; + const taskVideoCommentAction: OptimisticAddCommentReportAction = taskVideoComment.reportAction; + const taskVideoCommentText = instructionComment.commentText; + const taskVideoMessage: TaskMessage = { + reportID: currentTask.reportID, + reportActionID: taskVideoCommentAction.reportActionID, + reportComment: taskVideoCommentText, + }; - return [ - ...acc, - { - type: 'task', - task: engagementChoice, - taskReportID: currentTask.reportID, - parentReportID: currentTask.parentReportID ?? '', - parentReportActionID: taskReportAction.reportAction.reportActionID, - assigneeChatReportID: '', - createdTaskReportActionID: taskCreatedAction.reportActionID, - title: currentTask.reportName ?? '', - description: currentTask.description ?? '', - }, - { - type: 'message', - ...subtitleMessage, - }, - { - type: 'message', - ...instructionMessage, - }, - ]; - }, []); + const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; + const instructionCommentText = instructionComment.commentText; + const instructionMessage: TaskMessage = { + reportID: currentTask.reportID, + reportActionID: instructionCommentAction.reportActionID, + reportComment: instructionCommentText, + }; + + return [ + ...acc, + { + type: 'task', + task: engagementChoice, + taskReportID: currentTask.reportID, + parentReportID: currentTask.parentReportID ?? '', + parentReportActionID: taskReportAction.reportAction.reportActionID, + assigneeChatReportID: '', + createdTaskReportActionID: taskCreatedAction.reportActionID, + title: currentTask.reportName ?? '', + description: currentTask.description ?? '', + video: task.video, + }, + { + type: 'message', + ...taskVideoMessage, + }, + { + type: 'message', + ...subtitleMessage, + }, + { + type: 'message', + ...instructionMessage, + }, + ]; + }, + [], + ); - const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { + const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, taskVideoComment, instructionComment}) => { const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + const taskVideoCommentAction: OptimisticAddCommentReportAction = taskVideoComment.reportAction; const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; return [ @@ -3104,6 +3131,7 @@ function completeOnboarding( value: { [taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction, [subtitleCommentAction.reportActionID]: subtitleCommentAction as ReportAction, + [taskVideoCommentAction.reportActionID]: taskVideoCommentAction as ReportAction, [instructionCommentAction.reportActionID]: instructionCommentAction as ReportAction, }, }, From 9591026558a273e022ff1c97c17676af19f59546 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 16 Apr 2024 13:43:55 +0200 Subject: [PATCH 34/54] integrate OnboardingPurposeType type --- src/CONST.ts | 4 +++- src/libs/API/parameters/CompleteGuidedSetupParams.ts | 4 +++- src/libs/actions/Report.ts | 3 ++- src/pages/OnboardingPersonalDetails/types.ts | 3 ++- src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx | 8 +++----- src/pages/OnboardingPurpose/types.ts | 3 ++- src/pages/OnboardingWork/types.ts | 3 ++- src/types/onyx/IntroSelected.ts | 5 ++--- 8 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 039598dd2b8a..b91c1a06a0fb 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -66,6 +66,8 @@ const onboardingChoices = { LOOKING_AROUND: 'newDotLookingAround', }; +type OnboardingPurposeType = ValueOf; + const CONST = { MERGED_ACCOUNT_PREFIX: 'MERGED_', DEFAULT_POLICY_ROOM_CHAT_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL], @@ -4673,6 +4675,6 @@ const CONST = { type Country = keyof typeof CONST.ALL_COUNTRIES; type IOUType = ValueOf; -export type {Country, IOUType}; +export type {Country, IOUType, OnboardingPurposeType}; export default CONST; diff --git a/src/libs/API/parameters/CompleteGuidedSetupParams.ts b/src/libs/API/parameters/CompleteGuidedSetupParams.ts index 6835949382ca..e3a0309d5113 100644 --- a/src/libs/API/parameters/CompleteGuidedSetupParams.ts +++ b/src/libs/API/parameters/CompleteGuidedSetupParams.ts @@ -1,8 +1,10 @@ +import type {OnboardingPurposeType} from '@src/CONST'; + type CompleteGuidedSetupParams = { firstName: string; lastName: string; guidedSetupData: string; - engagementChoice: string; + engagementChoice: OnboardingPurposeType; }; export default CompleteGuidedSetupParams; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 4e2aa729c706..e05dceb9fead 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -72,6 +72,7 @@ import shouldSkipDeepLinkNavigation from '@libs/shouldSkipDeepLinkNavigation'; import * as UserUtils from '@libs/UserUtils'; 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'; @@ -3190,7 +3191,7 @@ function completeOnboarding( * - Sets the introSelected NVP to the choice the user made * - Creates an optimistic report comment from concierge */ -function completeEngagementModal(text: string, choice: ValueOf) { +function completeEngagementModal(text: string, choice: OnboardingPurposeType) { const conciergeAccountID = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE])[0]; const reportComment = ReportUtils.buildOptimisticAddCommentReportAction(text, undefined, conciergeAccountID); const reportCommentAction: OptimisticAddCommentReportAction = reportComment.reportAction; diff --git a/src/pages/OnboardingPersonalDetails/types.ts b/src/pages/OnboardingPersonalDetails/types.ts index 6d286373a1ac..4828cc6e73bd 100644 --- a/src/pages/OnboardingPersonalDetails/types.ts +++ b/src/pages/OnboardingPersonalDetails/types.ts @@ -1,11 +1,12 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; +import type {OnboardingPurposeType} from '@src/CONST'; type OnboardingPersonalDetailsProps = Record; type BaseOnboardingPersonalDetailsOnyxProps = { /** Saved onboarding purpose selected by the user */ - onboardingPurposeSelected: OnyxEntry; + onboardingPurposeSelected: OnyxEntry; }; type BaseOnboardingPersonalDetailsProps = WithCurrentUserPersonalDetailsProps & diff --git a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx index 8ccbda809d97..a6aec605a8f0 100644 --- a/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx +++ b/src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx @@ -21,14 +21,12 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import Navigation from '@libs/Navigation/Navigation'; import variables from '@styles/variables'; import * as Welcome from '@userActions/Welcome'; +import type {OnboardingPurposeType} from '@src/CONST'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {BaseOnboardingPurposeOnyxProps, BaseOnboardingPurposeProps} from './types'; -type ValuesType = T[keyof T]; -type SelectedPurposeType = ValuesType | undefined; - const menuIcons = { [CONST.ONBOARDING_CHOICES.TRACK]: Illustrations.CompanyCard, [CONST.ONBOARDING_CHOICES.EMPLOYER]: Illustrations.ReceiptUpload, @@ -42,7 +40,7 @@ function BaseOnboardingPurpose({shouldUseNativeStyles, shouldEnableMaxHeight, on const styles = useThemeStyles(); const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useOnboardingLayout(); - const [selectedPurpose, setSelectedPurpose] = useState(undefined); + const [selectedPurpose, setSelectedPurpose] = useState(undefined); const {isSmallScreenWidth, windowHeight} = useWindowDimensions(); const [error, setError] = useState(false); const theme = useTheme(); @@ -155,4 +153,4 @@ export default withOnyx; type BaseOnboardingPurposeOnyxProps = { /** Saved onboarding purpose selected by the user */ - onboardingPurposeSelected: OnyxEntry; + onboardingPurposeSelected: OnyxEntry; }; type BaseOnboardingPurposeProps = OnboardingPurposeProps & diff --git a/src/pages/OnboardingWork/types.ts b/src/pages/OnboardingWork/types.ts index 930a8081e9c4..5bef8048628d 100644 --- a/src/pages/OnboardingWork/types.ts +++ b/src/pages/OnboardingWork/types.ts @@ -1,11 +1,12 @@ import type {OnyxEntry} from 'react-native-onyx'; import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; +import type {OnboardingPurposeType} from '@src/CONST'; type OnboardingWorkProps = Record; type BaseOnboardingWorkOnyxProps = { /** Saved onboarding purpose selected by the user */ - onboardingPurposeSelected: OnyxEntry; + onboardingPurposeSelected: OnyxEntry; }; type BaseOnboardingWorkProps = WithCurrentUserPersonalDetailsProps & diff --git a/src/types/onyx/IntroSelected.ts b/src/types/onyx/IntroSelected.ts index 9917f4b44550..14a0d2f70dfe 100644 --- a/src/types/onyx/IntroSelected.ts +++ b/src/types/onyx/IntroSelected.ts @@ -1,9 +1,8 @@ -import type {ValueOf} from 'type-fest'; -import type CONST from '@src/CONST'; +import type {OnboardingPurposeType} from '@src/CONST'; type IntroSelected = { /** The choice that the user selected in the engagement modal */ - choice: ValueOf; + choice: OnboardingPurposeType; }; export default IntroSelected; From d87069dc843ebf65a0e2f7dca51fedf45d590366 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 16 Apr 2024 13:48:19 +0200 Subject: [PATCH 35/54] integrate GuidedSetupData type --- src/libs/actions/Report.ts | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index e05dceb9fead..cea442efecf7 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -108,6 +108,14 @@ type ActionSubscriber = { callback: SubscriberCallback; }; +type Video = { + url: string; + thumbnailUrl: string; + duration: number; + width: number; + height: number; +}; + type TaskForParameters = | { type: 'task'; @@ -119,13 +127,7 @@ type TaskForParameters = createdTaskReportActionID: string; title: string; description: string; - video: { - url: string; - thumbnailUrl: string; - duration: number; - width: number; - height: number; - }; + video: Video; } | { type: 'message'; @@ -136,6 +138,15 @@ type TaskForParameters = type TaskMessage = Required>; +type GuidedSetupData = Array< + | AddCommentOrAttachementParams + | TaskForParameters + | ({ + type: 'video'; + } & Video & + AddCommentOrAttachementParams) +>; + let conciergeChatReportID: string | undefined; let currentUserAccountID = -1; let currentUserEmail: string | undefined; @@ -3175,11 +3186,18 @@ function completeOnboarding( }, ]; + const guidedSetupData: GuidedSetupData = [ + {type: 'message', ...mentionMessage}, + {type: 'message', ...textMessage}, + {type: 'video', ...data.video, ...videoMessage}, + ...tasksForParameters, + ]; + const parameters: CompleteGuidedSetupParams = { engagementChoice, firstName, lastName, - guidedSetupData: JSON.stringify([{type: 'message', ...mentionMessage}, {type: 'message', ...textMessage}, {type: 'video', ...data.video, ...videoMessage}, ...tasksForParameters]), + guidedSetupData: JSON.stringify(guidedSetupData), }; API.write(WRITE_COMMANDS.COMPLETE_GUIDED_SETUP, parameters, {optimisticData, successData}); From e4a4fa646d28ac9d3a60e83aba05220f1011a702 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 16 Apr 2024 14:04:30 +0200 Subject: [PATCH 36/54] use OnboardingPurposeType --- src/libs/actions/Welcome.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 87762bc856ca..84066c05e80e 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -1,6 +1,6 @@ import type {OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import type {SelectedPurposeType} from '@pages/OnboardingPurpose/BaseOnboardingPurpose'; +import type {OnboardingPurposeType} from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type OnyxPolicy from '@src/types/onyx/Policy'; import type {EmptyObject} from '@src/types/utils/EmptyObject'; @@ -112,7 +112,7 @@ function getPersonalDetails(accountID: number | undefined) { }); } -function setOnboardingPurposeSelected(value: SelectedPurposeType) { +function setOnboardingPurposeSelected(value: OnboardingPurposeType) { Onyx.set(ONYXKEYS.ONBOARDING_PURPOSE_SELECTED, value ?? null); } From ef7f8c6d779cb557db08b9e65d488672786b60f5 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 16 Apr 2024 14:31:20 +0200 Subject: [PATCH 37/54] change progress bar values --- .../OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx | 2 +- src/pages/OnboardingPurpose/BaseOnboardingPurpose.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index 5657f8553113..ee9693a950fd 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -120,7 +120,7 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat From 3c6e51247af49f731c7196ebd747fbc0a60b145a Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 16 Apr 2024 14:54:56 +0200 Subject: [PATCH 38/54] fix task actions ordering --- 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 cea442efecf7..9921816a3e5c 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3038,8 +3038,8 @@ function completeOnboarding( }, ); const subtitleComment = ReportUtils.buildOptimisticAddCommentReportAction(task.subtitle, undefined, actorAccountID); - const taskVideoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID); - const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(task.message, undefined, actorAccountID, undefined, false); + const taskVideoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID, 1); + const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(task.message, undefined, actorAccountID, 2, false); return { task, From 6eb2c290b7f7e42a43816add805784d35d7e2b40 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 16 Apr 2024 15:54:46 +0200 Subject: [PATCH 39/54] integrate addition options --- src/CONST.ts | 14 +-- src/libs/actions/Report.ts | 114 ++++++++++++------ .../OnboardingWork/BaseOnboardingWork.tsx | 19 +-- 3 files changed, 96 insertions(+), 51 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index b91c1a06a0fb..e6675916f15d 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3734,17 +3734,11 @@ const CONST = { { title: 'Meet your setup specialist', subtitle: '', - message: - 'Meet your setup specialist, {guideName}, who can answer any questions as you get started with Expensify. Yes, a real human!\n' + + message: ({adminsRoomLink, guideCalendarLink}: {adminsRoomLink: string; guideCalendarLink: string}) => + `Meet your setup specialist, who can answer any questions as you get started with Expensify. Yes, a real human!\n` + '\n' + - 'Chat with {guideName} in your [admins room]({adminsRoomID}) or [schedule a call]({guideCalendarLink}) today', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, + `Chat with the specialist in your [#admins room](${adminsRoomLink}) or [schedule a call](${guideCalendarLink}) today.`, + video: null, }, { title: 'Set up categories', diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 9921816a3e5c..03636d869ed6 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -127,7 +127,7 @@ type TaskForParameters = createdTaskReportActionID: string; title: string; description: string; - video: Video; + video?: Video; } | { type: 'message'; @@ -163,6 +163,14 @@ Onyx.connect({ }, }); +let guideCalendarLink: string | undefined; +Onyx.connect({ + key: ONYXKEYS.ACCOUNT, + callback: (value) => { + guideCalendarLink = value?.guideCalendarLink ?? ''; + }, +}); + let preferredSkinTone: number = CONST.EMOJI_DEFAULT_SKIN_TONE; Onyx.connect({ key: ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE, @@ -2978,6 +2986,7 @@ function completeOnboarding( firstName: string; lastName: string; }, + adminsChatReportID?: string, ) { const targetEmail = CONST.EMAIL.CONCIERGE; const actorAccountID = PersonalDetailsUtils.getAccountIDsByLogins([targetEmail])[0]; @@ -3037,9 +3046,16 @@ function completeOnboarding( childOldestFourAccountIDs: `${actorAccountID}`, }, ); - const subtitleComment = ReportUtils.buildOptimisticAddCommentReportAction(task.subtitle, undefined, actorAccountID); - const taskVideoComment = ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID, 1); - const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(task.message, undefined, actorAccountID, 2, false); + const subtitleComment = task.subtitle ? ReportUtils.buildOptimisticAddCommentReportAction(task.subtitle, undefined, actorAccountID) : null; + const taskVideoComment = task.video ? ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID, 1) : null; + const taskMessage = + typeof task.message === 'function' + ? task.message({ + adminsRoomLink: `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL}${ROUTES.REPORT_WITH_ID.getRoute(adminsChatReportID ?? '')}`, + guideCalendarLink: guideCalendarLink ?? CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL, + }) + : task.message; + const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 2, false); return { task, @@ -3054,22 +3070,6 @@ function completeOnboarding( const tasksForParameters = tasksData.reduce( (acc, {task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, taskVideoComment, instructionComment}) => { - const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; - const subtitleCommentText = subtitleComment.commentText; - const subtitleMessage: TaskMessage = { - reportID: currentTask.reportID, - reportActionID: subtitleCommentAction.reportActionID, - reportComment: subtitleCommentText, - }; - - const taskVideoCommentAction: OptimisticAddCommentReportAction = taskVideoComment.reportAction; - const taskVideoCommentText = instructionComment.commentText; - const taskVideoMessage: TaskMessage = { - reportID: currentTask.reportID, - reportActionID: taskVideoCommentAction.reportActionID, - reportComment: taskVideoCommentText, - }; - const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; const instructionCommentText = instructionComment.commentText; const instructionMessage: TaskMessage = { @@ -3078,7 +3078,7 @@ function completeOnboarding( reportComment: instructionCommentText, }; - return [ + const tasksForParametersAcc: TaskForParameters[] = [ ...acc, { type: 'task', @@ -3090,31 +3090,53 @@ function completeOnboarding( createdTaskReportActionID: taskCreatedAction.reportActionID, title: currentTask.reportName ?? '', description: currentTask.description ?? '', - video: task.video, + video: task.video ?? undefined, }, { type: 'message', - ...taskVideoMessage, + ...instructionMessage, }, - { + ]; + + if (subtitleComment) { + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + const subtitleCommentText = subtitleComment.commentText; + const subtitleMessage: TaskMessage = { + reportID: currentTask.reportID, + reportActionID: subtitleCommentAction.reportActionID, + reportComment: subtitleCommentText, + }; + + tasksForParametersAcc.push({ type: 'message', ...subtitleMessage, - }, - { + }); + } + + if (taskVideoComment) { + const taskVideoCommentAction: OptimisticAddCommentReportAction = taskVideoComment.reportAction; + const taskVideoCommentText = instructionComment.commentText; + const taskVideoMessage: TaskMessage = { + reportID: currentTask.reportID, + reportActionID: taskVideoCommentAction.reportActionID, + reportComment: taskVideoCommentText, + }; + + tasksForParametersAcc.push({ type: 'message', - ...instructionMessage, - }, - ]; + ...taskVideoMessage, + }); + } + + return tasksForParametersAcc; }, [], ); const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, taskVideoComment, instructionComment}) => { - const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; - const taskVideoCommentAction: OptimisticAddCommentReportAction = taskVideoComment.reportAction; const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; - return [ + const tasksForOptimisticDataAcc: OnyxUpdate[] = [ ...acc, { onyxMethod: Onyx.METHOD.MERGE, @@ -3142,12 +3164,36 @@ function completeOnboarding( key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, value: { [taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction, - [subtitleCommentAction.reportActionID]: subtitleCommentAction as ReportAction, - [taskVideoCommentAction.reportActionID]: taskVideoCommentAction as ReportAction, [instructionCommentAction.reportActionID]: instructionCommentAction as ReportAction, }, }, ]; + + if (subtitleComment) { + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + + tasksForOptimisticDataAcc.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [subtitleCommentAction.reportActionID]: subtitleCommentAction as ReportAction, + }, + }); + } + + if (taskVideoComment) { + const taskVideoCommentAction: OptimisticAddCommentReportAction = taskVideoComment.reportAction; + + tasksForOptimisticDataAcc.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [taskVideoCommentAction.reportActionID]: taskVideoCommentAction as ReportAction, + }, + }); + } + + return tasksForOptimisticDataAcc; }, []); const optimisticData: OnyxUpdate[] = [ diff --git a/src/pages/OnboardingWork/BaseOnboardingWork.tsx b/src/pages/OnboardingWork/BaseOnboardingWork.tsx index 22ebb57489c2..81be2bcc6ac5 100644 --- a/src/pages/OnboardingWork/BaseOnboardingWork.tsx +++ b/src/pages/OnboardingWork/BaseOnboardingWork.tsx @@ -43,13 +43,18 @@ function BaseOnboardingWork({currentUserPersonalDetails, shouldUseNativeStyles, const work = values.work.trim(); - Policy.createWorkspace(undefined, true, work); - - Report.completeOnboarding(onboardingPurposeSelected, CONST.ONBOARDING_MESSAGES[onboardingPurposeSelected], { - login: currentUserPersonalDetails.login ?? '', - firstName: currentUserPersonalDetails.firstName ?? '', - lastName: currentUserPersonalDetails.lastName ?? '', - }); + const adminsChatReportID = Policy.createWorkspace(undefined, true, work); + + Report.completeOnboarding( + onboardingPurposeSelected, + CONST.ONBOARDING_MESSAGES[onboardingPurposeSelected], + { + login: currentUserPersonalDetails.login ?? '', + firstName: currentUserPersonalDetails.firstName ?? '', + lastName: currentUserPersonalDetails.lastName ?? '', + }, + adminsChatReportID, + ); Navigation.dismissModal(); // Only navigate to concierge chat when central pane is visible From 820360ffa66ef70375250f73f1e8bf0d36d2735f Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 16 Apr 2024 15:56:46 +0200 Subject: [PATCH 40/54] fix default value of guideCalendarLink --- 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 03636d869ed6..c08e4928eea1 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -167,7 +167,7 @@ let guideCalendarLink: string | undefined; Onyx.connect({ key: ONYXKEYS.ACCOUNT, callback: (value) => { - guideCalendarLink = value?.guideCalendarLink ?? ''; + guideCalendarLink = value?.guideCalendarLink ?? undefined; }, }); From 2e7d5c072cd802d2b92bb9d9519b4730d1b3be29 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 17 Apr 2024 15:30:05 +0200 Subject: [PATCH 41/54] fix task video assigning --- src/libs/actions/Report.ts | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index e95132418068..9530fe40d1e7 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -116,6 +116,8 @@ type Video = { height: number; }; +type TaskMessage = Required>; + type TaskForParameters = | { type: 'task'; @@ -127,25 +129,16 @@ type TaskForParameters = createdTaskReportActionID: string; title: string; description: string; - video?: Video; } - | { + | ({ type: 'message'; - reportID: string; - reportActionID: string; - reportComment: string; - }; - -type TaskMessage = Required>; - -type GuidedSetupData = Array< - | AddCommentOrAttachementParams - | TaskForParameters + } & TaskMessage) | ({ type: 'video'; - } & Video & - AddCommentOrAttachementParams) ->; + } & TaskMessage & + Video); + +type GuidedSetupData = Array; let conciergeChatReportID: string | undefined; let currentUserAccountID = -1; @@ -3095,7 +3088,6 @@ function completeOnboarding( createdTaskReportActionID: taskCreatedAction.reportActionID, title: currentTask.reportName ?? '', description: currentTask.description ?? '', - video: task.video ?? undefined, }, { type: 'message', @@ -3118,9 +3110,9 @@ function completeOnboarding( }); } - if (taskVideoComment) { + if (taskVideoComment && task.video) { const taskVideoCommentAction: OptimisticAddCommentReportAction = taskVideoComment.reportAction; - const taskVideoCommentText = instructionComment.commentText; + const taskVideoCommentText = taskVideoComment.commentText; const taskVideoMessage: TaskMessage = { reportID: currentTask.reportID, reportActionID: taskVideoCommentAction.reportActionID, @@ -3128,7 +3120,8 @@ function completeOnboarding( }; tasksForParametersAcc.push({ - type: 'message', + type: 'video', + ...task.video, ...taskVideoMessage, }); } From cb102de3d9c50658c3f52af431eb1e23f7dd4f14 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 17 Apr 2024 15:40:12 +0200 Subject: [PATCH 42/54] minor improvement --- 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 e89b3048d8cb..82e4eab5c2df 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2973,7 +2973,7 @@ function getReportPrivateNote(reportID: string | undefined) { } function completeOnboarding( - engagementChoice: string, + engagementChoice: OnboardingPurposeType, data: ValueOf, { login, From f81ba49eb72a92f118facf2ef3ed4d4932c752b1 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 18 Apr 2024 12:06:39 +0200 Subject: [PATCH 43/54] cut task videos off --- src/libs/actions/Report.ts | 133 ++++++++++++++----------------------- 1 file changed, 51 insertions(+), 82 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 412beb3187d2..1faf850b6d76 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -132,13 +132,16 @@ type TaskForParameters = } | ({ type: 'message'; - } & TaskMessage) + } & TaskMessage); + +type GuidedSetupData = Array< + | ({type: 'message'} & AddCommentOrAttachementParams) + | TaskForParameters | ({ type: 'video'; - } & TaskMessage & - Video); - -type GuidedSetupData = Array; + } & Video & + AddCommentOrAttachementParams) +>; let conciergeChatReportID: string | undefined; let currentUserAccountID = -1; @@ -3051,7 +3054,6 @@ function completeOnboarding( }, ); const subtitleComment = task.subtitle ? ReportUtils.buildOptimisticAddCommentReportAction(task.subtitle, undefined, actorAccountID) : null; - const taskVideoComment = task.video ? ReportUtils.buildOptimisticAddCommentReportAction(CONST.ATTACHMENT_MESSAGE_TEXT, undefined, actorAccountID, 1) : null; const taskMessage = typeof task.message === 'function' ? task.message({ @@ -3059,85 +3061,64 @@ function completeOnboarding( guideCalendarLink: guideCalendarLink ?? CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL, }) : task.message; - const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 2, false); + const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 1, false); return { - task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, - taskVideoComment, instructionComment, }; }); - const tasksForParameters = tasksData.reduce( - (acc, {task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, taskVideoComment, instructionComment}) => { - const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; - const instructionCommentText = instructionComment.commentText; - const instructionMessage: TaskMessage = { + const tasksForParameters = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { + const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; + const instructionCommentText = instructionComment.commentText; + const instructionMessage: TaskMessage = { + reportID: currentTask.reportID, + reportActionID: instructionCommentAction.reportActionID, + reportComment: instructionCommentText, + }; + + const tasksForParametersAcc: TaskForParameters[] = [ + ...acc, + { + type: 'task', + task: engagementChoice, + taskReportID: currentTask.reportID, + parentReportID: currentTask.parentReportID ?? '', + parentReportActionID: taskReportAction.reportAction.reportActionID, + assigneeChatReportID: '', + createdTaskReportActionID: taskCreatedAction.reportActionID, + title: currentTask.reportName ?? '', + description: currentTask.description ?? '', + }, + { + type: 'message', + ...instructionMessage, + }, + ]; + + if (subtitleComment) { + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + const subtitleCommentText = subtitleComment.commentText; + const subtitleMessage: TaskMessage = { reportID: currentTask.reportID, - reportActionID: instructionCommentAction.reportActionID, - reportComment: instructionCommentText, + reportActionID: subtitleCommentAction.reportActionID, + reportComment: subtitleCommentText, }; - const tasksForParametersAcc: TaskForParameters[] = [ - ...acc, - { - type: 'task', - task: engagementChoice, - taskReportID: currentTask.reportID, - parentReportID: currentTask.parentReportID ?? '', - parentReportActionID: taskReportAction.reportAction.reportActionID, - assigneeChatReportID: '', - createdTaskReportActionID: taskCreatedAction.reportActionID, - title: currentTask.reportName ?? '', - description: currentTask.description ?? '', - }, - { - type: 'message', - ...instructionMessage, - }, - ]; - - if (subtitleComment) { - const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; - const subtitleCommentText = subtitleComment.commentText; - const subtitleMessage: TaskMessage = { - reportID: currentTask.reportID, - reportActionID: subtitleCommentAction.reportActionID, - reportComment: subtitleCommentText, - }; - - tasksForParametersAcc.push({ - type: 'message', - ...subtitleMessage, - }); - } - - if (taskVideoComment && task.video) { - const taskVideoCommentAction: OptimisticAddCommentReportAction = taskVideoComment.reportAction; - const taskVideoCommentText = taskVideoComment.commentText; - const taskVideoMessage: TaskMessage = { - reportID: currentTask.reportID, - reportActionID: taskVideoCommentAction.reportActionID, - reportComment: taskVideoCommentText, - }; - - tasksForParametersAcc.push({ - type: 'video', - ...task.video, - ...taskVideoMessage, - }); - } + tasksForParametersAcc.push({ + type: 'message', + ...subtitleMessage, + }); + } - return tasksForParametersAcc; - }, - [], - ); + return tasksForParametersAcc; + }, []); - const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, taskVideoComment, instructionComment}) => { + const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; const tasksForOptimisticDataAcc: OnyxUpdate[] = [ @@ -3185,18 +3166,6 @@ function completeOnboarding( }); } - if (taskVideoComment) { - const taskVideoCommentAction: OptimisticAddCommentReportAction = taskVideoComment.reportAction; - - tasksForOptimisticDataAcc.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: { - [taskVideoCommentAction.reportActionID]: taskVideoCommentAction as ReportAction, - }, - }); - } - return tasksForOptimisticDataAcc; }, []); From 18cf4a82cbd17513db3bebb6c8b11eed4a3966e9 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 18 Apr 2024 15:27:00 +0200 Subject: [PATCH 44/54] Revert "add video to tasks" This reverts commit 52fde4a3350d75b66084e80e69ce560d960a306d. --- src/CONST.ts | 85 ---------------------------------------------------- 1 file changed, 85 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index f96c3087dff7..9d2992859efc 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3623,13 +3623,6 @@ const CONST = { '2. Click Workspaces > New workspace.\n' + '\n' + 'Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, { title: 'Track an expense', @@ -3643,13 +3636,6 @@ const CONST = { '4. Click Track.\n' + '\n' + 'And you’re done! Yep, it’s that easy.', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, ], }, @@ -3675,13 +3661,6 @@ const CONST = { '4. Add your reimburser to the request.\n' + '\n' + 'Then, send your request and wait for that sweet “Cha-ching!” when it’s complete.', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, { title: 'Enable your wallet', @@ -3694,13 +3673,6 @@ const CONST = { '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.', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, ], }, @@ -3724,13 +3696,6 @@ const CONST = { '2. Click Workspaces > New workspace.\n' + '\n' + 'Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, { title: 'Meet your setup specialist', @@ -3739,7 +3704,6 @@ const CONST = { `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}) or [schedule a call](${guideCalendarLink}) today.`, - video: null, }, { title: 'Set up categories', @@ -3754,13 +3718,6 @@ const CONST = { '5. Click Add categories to make your own.\n' + '\n' + 'For more controls like requiring a category for every expense, click Settings.', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, { title: 'Add expense approvals', @@ -3775,13 +3732,6 @@ const CONST = { '5. In Workflows, enable Add approvals.\n' + '\n' + 'You’ll be set as the expense approver. You can change this to any admin once you invite your team.', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, { title: 'Invite your team', @@ -3796,13 +3746,6 @@ const CONST = { '5. Add an invite message if you want.\n' + '\n' + 'That’s it! Happy expensing :)', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, ], }, @@ -3828,13 +3771,6 @@ const CONST = { '4. Click Track.\n' + '\n' + 'And you’re done! Yep, it’s that easy.', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, ], }, @@ -3861,13 +3797,6 @@ const CONST = { 'If any of your friends aren’t using Expensify already, they’ll be invited automatically. \n' + '\n' + 'Every chat will also turn into an email or text that they can respond to directly.', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, { title: 'Split an expense', @@ -3881,13 +3810,6 @@ const CONST = { '4. Add your friend(s) to the request.\n' + '\n' + 'Feel free to add more details if you want, or just send it off. Let’s get you paid back!', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, { title: 'Enable your wallet', @@ -3900,13 +3822,6 @@ const CONST = { '3. Add your bank account.\n' + '\n' + 'Once that’s done, you can request money from anyone and get paid right into your personal bank account.', - video: { - url: `${CLOUDFRONT_URL}/videos/intro-1280.mp4`, - thumbnailUrl: `${CLOUDFRONT_URL}/images/expensify__favicon.png`, - duration: 55, - width: 1280, - height: 960, - }, }, ], }, From 070e9339104cab33bdc14f20f2d9661bdef24786 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 18 Apr 2024 15:54:29 +0200 Subject: [PATCH 45/54] fix mentionHandle --- src/libs/actions/Report.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 1faf850b6d76..b4beb9cb287f 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -56,6 +56,7 @@ import * as EmojiUtils from '@libs/EmojiUtils'; import * as Environment from '@libs/Environment/Environment'; import * as ErrorUtils from '@libs/ErrorUtils'; import Log from '@libs/Log'; +import * as LoginUtils from '@libs/LoginUtils'; import Navigation from '@libs/Navigation/Navigation'; import LocalNotification from '@libs/Notification/LocalNotification'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; @@ -3001,7 +3002,8 @@ function completeOnboarding( const {reportID: targetChatReportID = '', policyID: targetChatPolicyID = ''} = targetChatReport ?? {}; // Mention message - const mentionComment = ReportUtils.buildOptimisticAddCommentReportAction(`Hey @${login.split('@')[0]} 👋`, undefined, actorAccountID); + const mentionHandle = LoginUtils.isEmailPublicDomain(login) ? login : login.split('@')[0]; + const mentionComment = ReportUtils.buildOptimisticAddCommentReportAction(`Hey @${mentionHandle} 👋`, undefined, actorAccountID); const mentionCommentAction: OptimisticAddCommentReportAction = mentionComment.reportAction; const mentionMessage: AddCommentOrAttachementParams = { reportID: targetChatReportID, From 41e7786f101eb0ebf954c6728d24b57dbc93958f Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 18 Apr 2024 17:42:41 +0200 Subject: [PATCH 46/54] fix link of message --- 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 b4beb9cb287f..9f6a6cfb7468 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3063,7 +3063,7 @@ function completeOnboarding( guideCalendarLink: guideCalendarLink ?? CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL, }) : task.message; - const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 1, false); + const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 1); return { currentTask, From 76d419c539c0d00b2e0c1cc0668cf5f711f620f5 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 19 Apr 2024 12:07:26 +0200 Subject: [PATCH 47/54] fix bold text --- src/libs/actions/Report.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 4ac7d28d1ac4..8b1d9b64e080 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3056,14 +3056,14 @@ function completeOnboarding( }, ); const subtitleComment = task.subtitle ? ReportUtils.buildOptimisticAddCommentReportAction(task.subtitle, undefined, actorAccountID) : null; - const taskMessage = - typeof task.message === 'function' - ? task.message({ - adminsRoomLink: `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL}${ROUTES.REPORT_WITH_ID.getRoute(adminsChatReportID ?? '')}`, - guideCalendarLink: guideCalendarLink ?? CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL, - }) - : task.message; - const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 1); + const isTaskMessageFunction = typeof task.message === 'function'; + const taskMessage = isTaskMessageFunction + ? task.message({ + adminsRoomLink: `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL}${ROUTES.REPORT_WITH_ID.getRoute(adminsChatReportID ?? '')}`, + guideCalendarLink: guideCalendarLink ?? CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL, + }) + : task.message; + const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 1, isTaskMessageFunction ? undefined : false); return { currentTask, From 67a2e10f217599232b32feff3f68455aed7baefa Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 19 Apr 2024 13:13:30 +0200 Subject: [PATCH 48/54] add task types --- src/CONST.ts | 13 +++++++++++++ src/libs/actions/Report.ts | 5 +++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 1c5097ae2ce5..acc9193a6729 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3620,6 +3620,7 @@ const CONST = { }, tasks: [ { + type: 'createWorkspace', title: 'Create a workspace', subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more.', message: @@ -3631,6 +3632,7 @@ const CONST = { 'Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.', }, { + type: 'trackExpense', title: 'Track an expense', subtitle: 'Track an expense in any currency, in just a few clicks.', message: @@ -3656,6 +3658,7 @@ const CONST = { }, tasks: [ { + type: 'submitExpense', title: 'Submit an expense', subtitle: 'Submit an expense by entering an amount or scanning a receipt.', message: @@ -3669,6 +3672,7 @@ const CONST = { 'Then, send your request and wait for that sweet “Cha-ching!” when it’s complete.', }, { + type: 'enableWallet', title: 'Enable your wallet', subtitle: 'You’ll need to enable your Expensify Wallet to get paid back. Don’t worry, it’s easy!', message: @@ -3693,6 +3697,7 @@ const CONST = { }, tasks: [ { + type: 'createWorkspace', title: 'Create a workspace', subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more.', message: @@ -3704,6 +3709,7 @@ const CONST = { 'Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.', }, { + type: 'meetGuide', title: 'Meet your setup specialist', subtitle: '', message: ({adminsRoomLink, guideCalendarLink}: {adminsRoomLink: string; guideCalendarLink: string}) => @@ -3712,6 +3718,7 @@ const CONST = { `Chat with the specialist in your [#admins room](${adminsRoomLink}) or [schedule a call](${guideCalendarLink}) today.`, }, { + type: 'setupCategories', title: 'Set up categories', subtitle: 'Set up categories so your team can code expenses for easy reporting.', message: @@ -3726,6 +3733,7 @@ const CONST = { 'For more controls like requiring a category for every expense, click Settings.', }, { + type: 'addExpenseApprovals', title: 'Add expense approvals', subtitle: 'Add expense approvals to review your team’s spend and keep it under control.', message: @@ -3740,6 +3748,7 @@ const CONST = { 'You’ll be set as the expense approver. You can change this to any admin once you invite your team.', }, { + type: 'inviteTeam', title: 'Invite your team', subtitle: 'Invite your team to Expensify so they can start tracking expenses today.', message: @@ -3766,6 +3775,7 @@ const CONST = { }, tasks: [ { + type: 'trackExpense', title: 'Track an expense', subtitle: 'Track an expense in any currency, whether you have a receipt or not.', message: @@ -3791,6 +3801,7 @@ const CONST = { }, tasks: [ { + type: 'startChat', title: 'Start a chat', subtitle: 'Start a chat with a friend or group using their email or phone number.', message: @@ -3805,6 +3816,7 @@ const CONST = { 'Every chat will also turn into an email or text that they can respond to directly.', }, { + type: 'splitExpense', title: 'Split an expense', subtitle: 'Split an expense right in your chat with one or more friends.', message: @@ -3818,6 +3830,7 @@ const CONST = { 'Feel free to add more details if you want, or just send it off. Let’s get you paid back!', }, { + type: 'enableWallet', title: 'Enable your wallet', subtitle: 'You’ll need to enable your Expensify Wallet to get paid back. Don’t worry, it’s easy!', message: diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 8b1d9b64e080..5f7ed3d36d0d 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3066,6 +3066,7 @@ function completeOnboarding( const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 1, isTaskMessageFunction ? undefined : false); return { + task, currentTask, taskCreatedAction, taskReportAction, @@ -3074,7 +3075,7 @@ function completeOnboarding( }; }); - const tasksForParameters = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { + const tasksForParameters = tasksData.reduce((acc, {task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; const instructionCommentText = instructionComment.commentText; const instructionMessage: TaskMessage = { @@ -3087,7 +3088,7 @@ function completeOnboarding( ...acc, { type: 'task', - task: engagementChoice, + task: task.type, taskReportID: currentTask.reportID, parentReportID: currentTask.parentReportID ?? '', parentReportActionID: taskReportAction.reportAction.reportActionID, From 3ec3c82a63e52bdc2c1502f84c7fcd3b60f6a681 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 19 Apr 2024 14:27:18 +0200 Subject: [PATCH 49/54] complete tasks --- src/libs/actions/Report.ts | 179 ++++++++++++++++++++----------------- 1 file changed, 96 insertions(+), 83 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 5f7ed3d36d0d..47655cfe9f55 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -128,6 +128,7 @@ type TaskForParameters = parentReportActionID: string; assigneeChatReportID: string; createdTaskReportActionID: string; + completedTaskReportActionID: string; title: string; description: string; } @@ -3064,6 +3065,7 @@ function completeOnboarding( }) : task.message; const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 1, isTaskMessageFunction ? undefined : false); + const completedTaskReportAction = ReportUtils.buildOptimisticTaskReportAction(currentTask.reportID, CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED, 'marked as complete'); return { task, @@ -3072,105 +3074,116 @@ function completeOnboarding( taskReportAction, subtitleComment, instructionComment, + completedTaskReportAction, }; }); - const tasksForParameters = tasksData.reduce((acc, {task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { - const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; - const instructionCommentText = instructionComment.commentText; - const instructionMessage: TaskMessage = { - reportID: currentTask.reportID, - reportActionID: instructionCommentAction.reportActionID, - reportComment: instructionCommentText, - }; - - const tasksForParametersAcc: TaskForParameters[] = [ - ...acc, - { - type: 'task', - task: task.type, - taskReportID: currentTask.reportID, - parentReportID: currentTask.parentReportID ?? '', - parentReportActionID: taskReportAction.reportAction.reportActionID, - assigneeChatReportID: '', - createdTaskReportActionID: taskCreatedAction.reportActionID, - title: currentTask.reportName ?? '', - description: currentTask.description ?? '', - }, - { - type: 'message', - ...instructionMessage, - }, - ]; - - if (subtitleComment) { - const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; - const subtitleCommentText = subtitleComment.commentText; - const subtitleMessage: TaskMessage = { + const tasksForParameters = tasksData.reduce( + (acc, {task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment, completedTaskReportAction}) => { + const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; + const instructionCommentText = instructionComment.commentText; + const instructionMessage: TaskMessage = { reportID: currentTask.reportID, - reportActionID: subtitleCommentAction.reportActionID, - reportComment: subtitleCommentText, + reportActionID: instructionCommentAction.reportActionID, + reportComment: instructionCommentText, }; - tasksForParametersAcc.push({ - type: 'message', - ...subtitleMessage, - }); - } + const tasksForParametersAcc: TaskForParameters[] = [ + ...acc, + { + type: 'task', + task: task.type, + taskReportID: currentTask.reportID, + parentReportID: currentTask.parentReportID ?? '', + parentReportActionID: taskReportAction.reportAction.reportActionID, + assigneeChatReportID: '', + createdTaskReportActionID: taskCreatedAction.reportActionID, + completedTaskReportActionID: completedTaskReportAction.reportActionID, + title: currentTask.reportName ?? '', + description: currentTask.description ?? '', + }, + { + type: 'message', + ...instructionMessage, + }, + ]; + + if (subtitleComment) { + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + const subtitleCommentText = subtitleComment.commentText; + const subtitleMessage: TaskMessage = { + reportID: currentTask.reportID, + reportActionID: subtitleCommentAction.reportActionID, + reportComment: subtitleCommentText, + }; + + tasksForParametersAcc.push({ + type: 'message', + ...subtitleMessage, + }); + } - return tasksForParametersAcc; - }, []); + return tasksForParametersAcc; + }, + [], + ); - const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { - const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; + const tasksForOptimisticData = tasksData.reduce( + (acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment, completedTaskReportAction}) => { + const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; - const tasksForOptimisticDataAcc: OnyxUpdate[] = [ - ...acc, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [taskReportAction.reportAction.reportActionID]: taskReportAction.reportAction as ReportAction, + const tasksForOptimisticDataAcc: OnyxUpdate[] = [ + ...acc, + { + 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, - 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, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, + value: { + ...currentTask, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, + 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, }, - isOptimisticReport: true, }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: { - [taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction, - [instructionCommentAction.reportActionID]: instructionCommentAction as ReportAction, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction, + [instructionCommentAction.reportActionID]: instructionCommentAction as ReportAction, + [completedTaskReportAction.reportActionID]: completedTaskReportAction as ReportAction, + }, }, - }, - ]; + ]; - if (subtitleComment) { - const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + if (subtitleComment) { + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; - tasksForOptimisticDataAcc.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: { - [subtitleCommentAction.reportActionID]: subtitleCommentAction as ReportAction, - }, - }); - } + tasksForOptimisticDataAcc.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [subtitleCommentAction.reportActionID]: subtitleCommentAction as ReportAction, + }, + }); + } - return tasksForOptimisticDataAcc; - }, []); + return tasksForOptimisticDataAcc; + }, + [], + ); const optimisticData: OnyxUpdate[] = [ ...tasksForOptimisticData, From 8cfbe4cf861c2ab5bd4bb37b44d598c4e245a080 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 19 Apr 2024 14:27:30 +0200 Subject: [PATCH 50/54] Revert "complete tasks" This reverts commit 3ec3c82a63e52bdc2c1502f84c7fcd3b60f6a681. --- src/libs/actions/Report.ts | 179 +++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 96 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 47655cfe9f55..5f7ed3d36d0d 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -128,7 +128,6 @@ type TaskForParameters = parentReportActionID: string; assigneeChatReportID: string; createdTaskReportActionID: string; - completedTaskReportActionID: string; title: string; description: string; } @@ -3065,7 +3064,6 @@ function completeOnboarding( }) : task.message; const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 1, isTaskMessageFunction ? undefined : false); - const completedTaskReportAction = ReportUtils.buildOptimisticTaskReportAction(currentTask.reportID, CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED, 'marked as complete'); return { task, @@ -3074,116 +3072,105 @@ function completeOnboarding( taskReportAction, subtitleComment, instructionComment, - completedTaskReportAction, }; }); - const tasksForParameters = tasksData.reduce( - (acc, {task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment, completedTaskReportAction}) => { - const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; - const instructionCommentText = instructionComment.commentText; - const instructionMessage: TaskMessage = { + const tasksForParameters = tasksData.reduce((acc, {task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { + const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; + const instructionCommentText = instructionComment.commentText; + const instructionMessage: TaskMessage = { + reportID: currentTask.reportID, + reportActionID: instructionCommentAction.reportActionID, + reportComment: instructionCommentText, + }; + + const tasksForParametersAcc: TaskForParameters[] = [ + ...acc, + { + type: 'task', + task: task.type, + taskReportID: currentTask.reportID, + parentReportID: currentTask.parentReportID ?? '', + parentReportActionID: taskReportAction.reportAction.reportActionID, + assigneeChatReportID: '', + createdTaskReportActionID: taskCreatedAction.reportActionID, + title: currentTask.reportName ?? '', + description: currentTask.description ?? '', + }, + { + type: 'message', + ...instructionMessage, + }, + ]; + + if (subtitleComment) { + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + const subtitleCommentText = subtitleComment.commentText; + const subtitleMessage: TaskMessage = { reportID: currentTask.reportID, - reportActionID: instructionCommentAction.reportActionID, - reportComment: instructionCommentText, + reportActionID: subtitleCommentAction.reportActionID, + reportComment: subtitleCommentText, }; - const tasksForParametersAcc: TaskForParameters[] = [ - ...acc, - { - type: 'task', - task: task.type, - taskReportID: currentTask.reportID, - parentReportID: currentTask.parentReportID ?? '', - parentReportActionID: taskReportAction.reportAction.reportActionID, - assigneeChatReportID: '', - createdTaskReportActionID: taskCreatedAction.reportActionID, - completedTaskReportActionID: completedTaskReportAction.reportActionID, - title: currentTask.reportName ?? '', - description: currentTask.description ?? '', - }, - { - type: 'message', - ...instructionMessage, - }, - ]; - - if (subtitleComment) { - const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; - const subtitleCommentText = subtitleComment.commentText; - const subtitleMessage: TaskMessage = { - reportID: currentTask.reportID, - reportActionID: subtitleCommentAction.reportActionID, - reportComment: subtitleCommentText, - }; - - tasksForParametersAcc.push({ - type: 'message', - ...subtitleMessage, - }); - } + tasksForParametersAcc.push({ + type: 'message', + ...subtitleMessage, + }); + } - return tasksForParametersAcc; - }, - [], - ); + return tasksForParametersAcc; + }, []); - const tasksForOptimisticData = tasksData.reduce( - (acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment, completedTaskReportAction}) => { - const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; + const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { + const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; - const tasksForOptimisticDataAcc: OnyxUpdate[] = [ - ...acc, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [taskReportAction.reportAction.reportActionID]: taskReportAction.reportAction as ReportAction, - }, + const tasksForOptimisticDataAcc: OnyxUpdate[] = [ + ...acc, + { + 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, - stateNum: CONST.REPORT.STATE_NUM.APPROVED, - statusNum: CONST.REPORT.STATUS_NUM.APPROVED, - 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, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, + value: { + ...currentTask, + 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, }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: { - [taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction, - [instructionCommentAction.reportActionID]: instructionCommentAction as ReportAction, - [completedTaskReportAction.reportActionID]: completedTaskReportAction as ReportAction, - }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction, + [instructionCommentAction.reportActionID]: instructionCommentAction as ReportAction, }, - ]; + }, + ]; - if (subtitleComment) { - const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + if (subtitleComment) { + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; - tasksForOptimisticDataAcc.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: { - [subtitleCommentAction.reportActionID]: subtitleCommentAction as ReportAction, - }, - }); - } + tasksForOptimisticDataAcc.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [subtitleCommentAction.reportActionID]: subtitleCommentAction as ReportAction, + }, + }); + } - return tasksForOptimisticDataAcc; - }, - [], - ); + return tasksForOptimisticDataAcc; + }, []); const optimisticData: OnyxUpdate[] = [ ...tasksForOptimisticData, From 4e5a21b697bae8082b56a0c5ff2c4d2433b4e7c9 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 19 Apr 2024 15:21:42 +0200 Subject: [PATCH 51/54] Reapply "complete tasks" This reverts commit 8cfbe4cf861c2ab5bd4bb37b44d598c4e245a080. --- src/libs/actions/Report.ts | 179 ++++++++++++++++++++----------------- 1 file changed, 96 insertions(+), 83 deletions(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 5f7ed3d36d0d..47655cfe9f55 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -128,6 +128,7 @@ type TaskForParameters = parentReportActionID: string; assigneeChatReportID: string; createdTaskReportActionID: string; + completedTaskReportActionID: string; title: string; description: string; } @@ -3064,6 +3065,7 @@ function completeOnboarding( }) : task.message; const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 1, isTaskMessageFunction ? undefined : false); + const completedTaskReportAction = ReportUtils.buildOptimisticTaskReportAction(currentTask.reportID, CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED, 'marked as complete'); return { task, @@ -3072,105 +3074,116 @@ function completeOnboarding( taskReportAction, subtitleComment, instructionComment, + completedTaskReportAction, }; }); - const tasksForParameters = tasksData.reduce((acc, {task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { - const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; - const instructionCommentText = instructionComment.commentText; - const instructionMessage: TaskMessage = { - reportID: currentTask.reportID, - reportActionID: instructionCommentAction.reportActionID, - reportComment: instructionCommentText, - }; - - const tasksForParametersAcc: TaskForParameters[] = [ - ...acc, - { - type: 'task', - task: task.type, - taskReportID: currentTask.reportID, - parentReportID: currentTask.parentReportID ?? '', - parentReportActionID: taskReportAction.reportAction.reportActionID, - assigneeChatReportID: '', - createdTaskReportActionID: taskCreatedAction.reportActionID, - title: currentTask.reportName ?? '', - description: currentTask.description ?? '', - }, - { - type: 'message', - ...instructionMessage, - }, - ]; - - if (subtitleComment) { - const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; - const subtitleCommentText = subtitleComment.commentText; - const subtitleMessage: TaskMessage = { + const tasksForParameters = tasksData.reduce( + (acc, {task, currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment, completedTaskReportAction}) => { + const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; + const instructionCommentText = instructionComment.commentText; + const instructionMessage: TaskMessage = { reportID: currentTask.reportID, - reportActionID: subtitleCommentAction.reportActionID, - reportComment: subtitleCommentText, + reportActionID: instructionCommentAction.reportActionID, + reportComment: instructionCommentText, }; - tasksForParametersAcc.push({ - type: 'message', - ...subtitleMessage, - }); - } + const tasksForParametersAcc: TaskForParameters[] = [ + ...acc, + { + type: 'task', + task: task.type, + taskReportID: currentTask.reportID, + parentReportID: currentTask.parentReportID ?? '', + parentReportActionID: taskReportAction.reportAction.reportActionID, + assigneeChatReportID: '', + createdTaskReportActionID: taskCreatedAction.reportActionID, + completedTaskReportActionID: completedTaskReportAction.reportActionID, + title: currentTask.reportName ?? '', + description: currentTask.description ?? '', + }, + { + type: 'message', + ...instructionMessage, + }, + ]; + + if (subtitleComment) { + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + const subtitleCommentText = subtitleComment.commentText; + const subtitleMessage: TaskMessage = { + reportID: currentTask.reportID, + reportActionID: subtitleCommentAction.reportActionID, + reportComment: subtitleCommentText, + }; + + tasksForParametersAcc.push({ + type: 'message', + ...subtitleMessage, + }); + } - return tasksForParametersAcc; - }, []); + return tasksForParametersAcc; + }, + [], + ); - const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment}) => { - const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; + const tasksForOptimisticData = tasksData.reduce( + (acc, {currentTask, taskCreatedAction, taskReportAction, subtitleComment, instructionComment, completedTaskReportAction}) => { + const instructionCommentAction: OptimisticAddCommentReportAction = instructionComment.reportAction; - const tasksForOptimisticDataAcc: OnyxUpdate[] = [ - ...acc, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${targetChatReportID}`, - value: { - [taskReportAction.reportAction.reportActionID]: taskReportAction.reportAction as ReportAction, + const tasksForOptimisticDataAcc: OnyxUpdate[] = [ + ...acc, + { + 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, - 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, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, + value: { + ...currentTask, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, + 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, }, - isOptimisticReport: true, }, - }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: { - [taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction, - [instructionCommentAction.reportActionID]: instructionCommentAction as ReportAction, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction, + [instructionCommentAction.reportActionID]: instructionCommentAction as ReportAction, + [completedTaskReportAction.reportActionID]: completedTaskReportAction as ReportAction, + }, }, - }, - ]; + ]; - if (subtitleComment) { - const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; + if (subtitleComment) { + const subtitleCommentAction: OptimisticAddCommentReportAction = subtitleComment.reportAction; - tasksForOptimisticDataAcc.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, - value: { - [subtitleCommentAction.reportActionID]: subtitleCommentAction as ReportAction, - }, - }); - } + tasksForOptimisticDataAcc.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [subtitleCommentAction.reportActionID]: subtitleCommentAction as ReportAction, + }, + }); + } - return tasksForOptimisticDataAcc; - }, []); + return tasksForOptimisticDataAcc; + }, + [], + ); const optimisticData: OnyxUpdate[] = [ ...tasksForOptimisticData, From b1c34f1e114dbd528969693e43f03b899a975ea8 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 19 Apr 2024 15:38:02 +0200 Subject: [PATCH 52/54] integrate autocompleted tasks --- src/CONST.ts | 13 +++++++++++++ src/libs/ReportUtils.ts | 12 +++++++++--- src/libs/actions/Report.ts | 30 ++++++++++++++++++++++++------ 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index acc9193a6729..0d07d1a6acb8 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3621,6 +3621,7 @@ const CONST = { tasks: [ { type: 'createWorkspace', + autoCompleted: true, title: 'Create a workspace', subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more.', message: @@ -3633,6 +3634,7 @@ const CONST = { }, { type: 'trackExpense', + autoCompleted: false, title: 'Track an expense', subtitle: 'Track an expense in any currency, in just a few clicks.', message: @@ -3659,6 +3661,7 @@ const CONST = { tasks: [ { type: 'submitExpense', + autoCompleted: false, title: 'Submit an expense', subtitle: 'Submit an expense by entering an amount or scanning a receipt.', message: @@ -3673,6 +3676,7 @@ const CONST = { }, { type: 'enableWallet', + autoCompleted: false, title: 'Enable your wallet', subtitle: 'You’ll need to enable your Expensify Wallet to get paid back. Don’t worry, it’s easy!', message: @@ -3698,6 +3702,7 @@ const CONST = { tasks: [ { type: 'createWorkspace', + autoCompleted: true, title: 'Create a workspace', subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more.', message: @@ -3710,6 +3715,7 @@ const CONST = { }, { type: 'meetGuide', + autoCompleted: false, title: 'Meet your setup specialist', subtitle: '', message: ({adminsRoomLink, guideCalendarLink}: {adminsRoomLink: string; guideCalendarLink: string}) => @@ -3719,6 +3725,7 @@ const CONST = { }, { type: 'setupCategories', + autoCompleted: false, title: 'Set up categories', subtitle: 'Set up categories so your team can code expenses for easy reporting.', message: @@ -3734,6 +3741,7 @@ const CONST = { }, { type: 'addExpenseApprovals', + autoCompleted: false, title: 'Add expense approvals', subtitle: 'Add expense approvals to review your team’s spend and keep it under control.', message: @@ -3749,6 +3757,7 @@ const CONST = { }, { type: 'inviteTeam', + autoCompleted: false, title: 'Invite your team', subtitle: 'Invite your team to Expensify so they can start tracking expenses today.', message: @@ -3776,6 +3785,7 @@ const CONST = { tasks: [ { type: 'trackExpense', + autoCompleted: false, title: 'Track an expense', subtitle: 'Track an expense in any currency, whether you have a receipt or not.', message: @@ -3802,6 +3812,7 @@ const CONST = { tasks: [ { type: 'startChat', + autoCompleted: false, title: 'Start a chat', subtitle: 'Start a chat with a friend or group using their email or phone number.', message: @@ -3817,6 +3828,7 @@ const CONST = { }, { type: 'splitExpense', + autoCompleted: false, title: 'Split an expense', subtitle: 'Split an expense right in your chat with one or more friends.', message: @@ -3831,6 +3843,7 @@ const CONST = { }, { type: 'enableWallet', + autoCompleted: false, title: 'Enable your wallet', subtitle: 'You’ll need to enable your Expensify Wallet to get paid back. Don’t worry, it’s easy!', message: diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 19c031966d8a..e759e6fbe1d9 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3919,7 +3919,13 @@ function updateReportPreview(iouReport: OnyxEntry, reportPreviewAction: }; } -function buildOptimisticTaskReportAction(taskReportID: string, actionName: OriginalMessageActionName, message = ''): OptimisticTaskReportAction { +function buildOptimisticTaskReportAction( + taskReportID: string, + actionName: OriginalMessageActionName, + message = '', + actorAccountID = currentUserAccountID, + createdOffset = 0, +): OptimisticTaskReportAction { const originalMessage = { taskReportID, type: actionName, @@ -3927,7 +3933,7 @@ function buildOptimisticTaskReportAction(taskReportID: string, actionName: Origi }; return { actionName, - actorAccountID: currentUserAccountID, + actorAccountID, automatic: false, avatar: getCurrentUserAvatarOrDefault(), isAttachment: false, @@ -3948,7 +3954,7 @@ function buildOptimisticTaskReportAction(taskReportID: string, actionName: Origi ], reportActionID: NumberUtils.rand64(), shouldShow: true, - created: DateUtils.getDBTime(), + created: DateUtils.getDBTimeWithSkew(Date.now() + createdOffset), isFirstItem: false, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 47655cfe9f55..f8bc1e0e4979 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -128,7 +128,7 @@ type TaskForParameters = parentReportActionID: string; assigneeChatReportID: string; createdTaskReportActionID: string; - completedTaskReportActionID: string; + completedTaskReportActionID?: string; title: string; description: string; } @@ -3065,7 +3065,9 @@ function completeOnboarding( }) : task.message; const instructionComment = ReportUtils.buildOptimisticAddCommentReportAction(taskMessage, undefined, actorAccountID, 1, isTaskMessageFunction ? undefined : false); - const completedTaskReportAction = ReportUtils.buildOptimisticTaskReportAction(currentTask.reportID, CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED, 'marked as complete'); + const completedTaskReportAction = task.autoCompleted + ? ReportUtils.buildOptimisticTaskReportAction(currentTask.reportID, CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED, 'marked as complete', actorAccountID, 2) + : null; return { task, @@ -3098,7 +3100,7 @@ function completeOnboarding( parentReportActionID: taskReportAction.reportAction.reportActionID, assigneeChatReportID: '', createdTaskReportActionID: taskCreatedAction.reportActionID, - completedTaskReportActionID: completedTaskReportAction.reportActionID, + completedTaskReportActionID: completedTaskReportAction?.reportActionID ?? undefined, title: currentTask.reportName ?? '', description: currentTask.description ?? '', }, @@ -3146,8 +3148,6 @@ function completeOnboarding( key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, value: { ...currentTask, - stateNum: CONST.REPORT.STATE_NUM.APPROVED, - statusNum: CONST.REPORT.STATUS_NUM.APPROVED, pendingFields: { createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, reportName: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, @@ -3163,7 +3163,6 @@ function completeOnboarding( value: { [taskCreatedAction.reportActionID]: taskCreatedAction as ReportAction, [instructionCommentAction.reportActionID]: instructionCommentAction as ReportAction, - [completedTaskReportAction.reportActionID]: completedTaskReportAction as ReportAction, }, }, ]; @@ -3180,6 +3179,25 @@ function completeOnboarding( }); } + if (completedTaskReportAction) { + tasksForOptimisticDataAcc.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [completedTaskReportAction.reportActionID]: completedTaskReportAction as ReportAction, + }, + }); + + tasksForOptimisticDataAcc.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, + value: { + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, + }, + }); + } + return tasksForOptimisticDataAcc; }, [], From c3360e07f338ee5d171425af46a340e65b7e1cb6 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 19 Apr 2024 15:45:36 +0200 Subject: [PATCH 53/54] improve progress bar --- .../BaseOnboardingPersonalDetails.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index ee9693a950fd..96ef9f70f048 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -27,6 +27,8 @@ import ROUTES from '@src/ROUTES'; import INPUT_IDS from '@src/types/form/DisplayNameForm'; import type {BaseOnboardingPersonalDetailsOnyxProps, BaseOnboardingPersonalDetailsProps} from './types'; +const OPEN_WORK_PAGE_PURPOSES = [CONST.ONBOARDING_CHOICES.TRACK, CONST.ONBOARDING_CHOICES.MANAGE_TEAM]; + function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNativeStyles, onboardingPurposeSelected}: BaseOnboardingPersonalDetailsProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -46,9 +48,7 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat return; } - const openWorkPagePurposes = [CONST.ONBOARDING_CHOICES.TRACK, CONST.ONBOARDING_CHOICES.MANAGE_TEAM]; - - if (openWorkPagePurposes.includes(onboardingPurposeSelected)) { + if (OPEN_WORK_PAGE_PURPOSES.includes(onboardingPurposeSelected)) { Navigation.navigate(ROUTES.ONBOARDING_WORK); return; @@ -120,7 +120,7 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat Date: Sun, 21 Apr 2024 11:32:37 +0100 Subject: [PATCH 54/54] Apply review changes --- .../createCustomBottomTabNavigator/BottomTabBar.tsx | 9 ++++++++- .../BaseOnboardingPersonalDetails.tsx | 7 ++----- src/pages/OnboardingWork/BaseOnboardingWork.tsx | 7 ++----- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx index 4df23c110278..0be4ac5518f3 100644 --- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx +++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx @@ -50,7 +50,14 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps } Welcome.isOnboardingFlowCompleted({ - onNotCompleted: () => Navigation.navigate(ROUTES.ONBOARDING_PURPOSE), + onNotCompleted: () => + Navigation.navigate( + // Uncomment once Stage 1 Onboarding Flow is ready + // + // ROUTES.ONBOARDING_PERSONAL_DETAILS + // + ROUTES.ONBOARD, + ), }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoadingApp]); diff --git a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx index 96ef9f70f048..c7387c2b6aee 100644 --- a/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx +++ b/src/pages/OnboardingPersonalDetails/BaseOnboardingPersonalDetails.tsx @@ -61,6 +61,7 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat }); Navigation.dismissModal(); + // Only navigate to concierge chat when central pane is visible // Otherwise stay on the chats screen. if (isSmallScreenWidth) { @@ -110,10 +111,6 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat return errors; }; - const handleGoBack = useCallback(() => { - Navigation.goBack(); - }, []); - const PersonalDetailsFooterInstance = ; return ( @@ -121,7 +118,7 @@ function BaseOnboardingPersonalDetails({currentUserPersonalDetails, shouldUseNat { - Navigation.goBack(); - }, []); - const WorkFooterInstance = ; return ( @@ -100,7 +97,7 @@ function BaseOnboardingWork({currentUserPersonalDetails, shouldUseNativeStyles,