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[] = [