diff --git a/src/CONST.ts b/src/CONST.ts index 05175c6b1adb..e33ba5a1b7b8 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -3716,8 +3716,9 @@ const CONST = { type: 'submitExpense', autoCompleted: false, title: 'Submit an expense', - subtitle: 'Submit an expense by entering an amount or scanning a receipt.', - message: + description: + 'Submit an expense by entering an amount or scanning a receipt.\n' + + '\n' + 'Here’s how to submit an expense:\n' + '\n' + '1. Click the green + button.\n' + @@ -3731,8 +3732,9 @@ 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: + description: + 'You’ll need to enable your Expensify Wallet to get paid back. Don’t worry, it’s easy!\n' + + '\n' + 'Here’s how to set up your wallet:\n' + '\n' + '1. Click your profile picture.\n' + @@ -3757,8 +3759,9 @@ const CONST = { type: 'createWorkspace', autoCompleted: true, title: 'Create a workspace', - subtitle: 'Create a workspace to track expenses, scan receipts, chat, and more.', - message: + description: + 'Create a workspace to track expenses, scan receipts, chat, and more.\n' + + '\n' + 'Here’s how to create a workspace:\n' + '\n' + '1. Click your profile picture.\n' + @@ -3770,8 +3773,7 @@ const CONST = { type: 'meetGuide', autoCompleted: false, title: 'Meet your setup specialist', - subtitle: '', - message: ({adminsRoomLink, guideCalendarLink}: {adminsRoomLink: string; guideCalendarLink: string}) => + description: ({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 the specialist in your [#admins room](${adminsRoomLink}) or [schedule a call](${guideCalendarLink}) today.`, @@ -3780,8 +3782,9 @@ const CONST = { type: 'setupCategories', autoCompleted: false, title: 'Set up categories', - subtitle: 'Set up categories so your team can code expenses for easy reporting.', - message: + description: + 'Set up categories so your team can code expenses for easy reporting.\n' + + '\n' + 'Here’s how to set up categories:\n' + '\n' + '1. Click your profile picture.\n' + @@ -3796,8 +3799,9 @@ 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: + description: + 'Add expense approvals to review your team’s spend and keep it under control.\n' + + '\n' + 'Here’s how to add expense approvals:\n' + '\n' + '1. Click your profile picture.\n' + @@ -3812,8 +3816,9 @@ const CONST = { type: 'inviteTeam', autoCompleted: false, title: 'Invite your team', - subtitle: 'Invite your team to Expensify so they can start tracking expenses today.', - message: + description: + 'Invite your team to Expensify so they can start tracking expenses today.\n' + + '\n' + 'Here’s how to invite your team:\n' + '\n' + '1. Click your profile picture.\n' + @@ -3840,8 +3845,9 @@ const CONST = { type: 'trackExpense', autoCompleted: false, title: 'Track an expense', - subtitle: 'Track an expense in any currency, whether you have a receipt or not.', - message: + description: + 'Track an expense in any currency, whether you have a receipt or not.\n' + + '\n' + 'Here’s how to track an expense:\n' + '\n' + '1. Click the green + button.\n' + @@ -3867,8 +3873,9 @@ const CONST = { type: 'startChat', autoCompleted: false, title: 'Start a chat', - subtitle: 'Start a chat with a friend or group using their email or phone number.', - message: + description: + 'Start a chat with a friend or group using their email or phone number.\n' + + '\n' + 'Here’s how to start a chat:\n' + '\n' + '1. Click the green + button.\n' + @@ -3883,8 +3890,9 @@ const CONST = { type: 'splitExpense', autoCompleted: false, title: 'Split an expense', - subtitle: 'Split an expense right in your chat with one or more friends.', - message: + description: + 'Split an expense right in your chat with one or more friends.\n' + + '\n' + 'Here’s how to request money:\n' + '\n' + '1. Click the green + button.\n' + @@ -3898,8 +3906,9 @@ 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: + description: + 'You’ll need to enable your Expensify Wallet to get paid back. Don’t worry, it’s easy!\n' + + '\n' + 'Here’s how to enable your wallet:\n' + '\n' + '1. Click your profile picture.\n' + diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index 2bfb78cf9340..bf35d65340fc 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -215,6 +215,9 @@ type MenuItemBaseProps = { /** Should render the content in HTML format */ shouldRenderAsHTML?: boolean; + /** Whether or not the text should be escaped */ + shouldEscapeText?: boolean; + /** Should we grey out the menu item when it is disabled? */ shouldGreyOutWhenDisabled?: boolean; @@ -317,6 +320,7 @@ function MenuItem( isSmallAvatarSubscriptMenu = false, brickRoadIndicator, shouldRenderAsHTML = false, + shouldEscapeText = undefined, shouldGreyOutWhenDisabled = true, shouldUseDefaultCursorWhenDisabled = false, isAnonymousAction = false, @@ -370,8 +374,8 @@ function MenuItem( return ''; } const parser = new ExpensiMark(); - return parser.replace(title); - }, [title, shouldParseTitle]); + return parser.replace(title, {shouldEscapeText}); + }, [title, shouldParseTitle, shouldEscapeText]); const processedTitle = useMemo(() => { let titleToWrap = ''; diff --git a/src/components/ReportActionItem/TaskView.tsx b/src/components/ReportActionItem/TaskView.tsx index 9711e126907f..ae361ce9dc47 100644 --- a/src/components/ReportActionItem/TaskView.tsx +++ b/src/components/ReportActionItem/TaskView.tsx @@ -23,6 +23,7 @@ import getButtonState from '@libs/getButtonState'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as ReportUtils from '@libs/ReportUtils'; +import * as Url from '@libs/Url'; import * as Session from '@userActions/Session'; import * as Task from '@userActions/Task'; import CONST from '@src/CONST'; @@ -149,6 +150,8 @@ function TaskView({report, shouldShowHorizontalRule, ...props}: TaskViewProps) { shouldGreyOutWhenDisabled={false} numberOfLinesTitle={0} interactive={!isDisableInteractive} + shouldRenderAsHTML + shouldEscapeText={Url.hasURL(report.description ?? '') ? undefined : false} /> diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 78b4195051a1..769832747c41 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3516,12 +3516,6 @@ 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, undefined, taskReportID); if (reportAction.reportAction.message?.[0]) { @@ -3546,22 +3540,6 @@ function buildOptimisticTaskCommentReportAction( 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/Url.ts b/src/libs/Url.ts index 4e3282e7bdb3..80ca98c712cf 100644 --- a/src/libs/Url.ts +++ b/src/libs/Url.ts @@ -56,4 +56,10 @@ function appendParam(url: string, paramName: string, paramValue: string) { return `${url}${separator}${paramName}=${paramValue}`; } -export {addTrailingForwardSlash, hasSameExpensifyOrigin, getPathFromURL, appendParam}; +function hasURL(text: string) { + const urlPattern = /((https|http)?:\/\/[^\s]+)/g; + + return urlPattern.test(text); +} + +export {addTrailingForwardSlash, hasSameExpensifyOrigin, getPathFromURL, appendParam, hasURL}; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index c15fc4a967d5..05d5741725a8 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -3048,13 +3048,19 @@ function completeOnboarding( } const tasksData = data.tasks.map((task, index) => { - const hasSubtitle = !!task.subtitle; + const taskDescription = + typeof task.description === 'function' + ? task.description({ + adminsRoomLink: `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL}${ROUTES.REPORT_WITH_ID.getRoute(adminsChatReportID ?? '')}`, + guideCalendarLink: guideCalendarLink ?? CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL, + }) + : task.description; const currentTask = ReportUtils.buildOptimisticTaskReport( actorAccountID, undefined, targetChatReportID, task.title, - undefined, + taskDescription, targetChatPolicyID, CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, ); @@ -3067,22 +3073,8 @@ function completeOnboarding( targetChatReportID, actorAccountID, index + 3, - { - childVisibleActionCount: hasSubtitle ? 2 : 1, - childCommenterCount: 1, - childLastVisibleActionCreated: DateUtils.getDBTime(), - childOldestFourAccountIDs: `${actorAccountID}`, - }, ); - const subtitleComment = hasSubtitle ? ReportUtils.buildOptimisticAddCommentReportAction(task.subtitle, undefined, actorAccountID, 0, false) : null; - 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); + const completedTaskReportAction = task.autoCompleted ? ReportUtils.buildOptimisticTaskReportAction(currentTask.reportID, CONST.REPORT.ACTIONS.TYPE.TASK_COMPLETED, 'marked as complete', actorAccountID, 2) : null; @@ -3092,134 +3084,79 @@ function completeOnboarding( currentTask, taskCreatedAction, taskReportAction, - subtitleComment, - instructionComment, + taskDescription, 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 = { - 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, - completedTaskReportActionID: completedTaskReportAction?.reportActionID ?? undefined, - 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; - }, - [], - ); - - 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 tasksForParameters = tasksData.map(({task, currentTask, taskCreatedAction, taskReportAction, taskDescription, completedTaskReportAction}) => ({ + type: 'task', + task: task.type, + taskReportID: currentTask.reportID, + parentReportID: currentTask.parentReportID ?? '', + parentReportActionID: taskReportAction.reportAction.reportActionID, + assigneeChatReportID: '', + createdTaskReportActionID: taskCreatedAction.reportActionID, + completedTaskReportActionID: completedTaskReportAction?.reportActionID ?? undefined, + title: currentTask.reportName ?? '', + description: taskDescription, + })); + + const tasksForOptimisticData = tasksData.reduce((acc, {currentTask, taskCreatedAction, taskReportAction, taskDescription, completedTaskReportAction}) => { + 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, - }, - isOptimisticReport: true, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.REPORT}${currentTask.reportID}`, + value: { + ...currentTask, + description: taskDescription, + pendingFields: { + createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + reportName: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + description: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + managerID: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, + isOptimisticReport: true, }, - { - 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, }, - ]; - - 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 (completedTaskReportAction) { + tasksForOptimisticDataAcc.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentTask.reportID}`, + value: { + [completedTaskReportAction.reportActionID]: completedTaskReportAction as ReportAction, + }, + }); - 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, - }, - }); - } + 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; - }, - [], - ); + return tasksForOptimisticDataAcc; + }, []); const tasksForFailureData = tasksData.reduce((acc, {currentTask, taskReportAction}) => { const tasksForFailureDataAcc: OnyxUpdate[] = [