From 422ec4d69cd45dffce7002aea98d9076c61efc4b Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Wed, 26 Mar 2025 16:10:50 +0100 Subject: [PATCH 1/7] add QAB optimistic data --- src/CONST.ts | 1 + src/languages/en.ts | 1 + src/languages/es.ts | 1 + src/libs/actions/Report.ts | 19 +++++++++- src/pages/NewReportWorkspaceSelectionPage.tsx | 3 +- .../FloatingActionButtonAndPopover.tsx | 37 +++++++++++++++---- 6 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 6de65ae74f63..98a373239526 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1122,6 +1122,7 @@ const CONST = { TRACK_DISTANCE: 'trackDistance', ASSIGN_TASK: 'assignTask', SEND_MONEY: 'sendMoney', + CREATE_REPORT: 'createReport', }, RECEIPT: { diff --git a/src/languages/en.ts b/src/languages/en.ts index 6baefcb7ed9d..57b9117365ae 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -885,6 +885,7 @@ const translations = { header: 'Quick action', noLongerHaveReportAccess: 'You no longer have access to your previous quick action destination. Pick a new one below.', updateDestination: 'Update destination', + createReport: 'Create report', }, iou: { amount: 'Amount', diff --git a/src/languages/es.ts b/src/languages/es.ts index 5e62dfa6156b..88351195c550 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -880,6 +880,7 @@ const translations = { header: 'Acción rápida', noLongerHaveReportAccess: 'Ya no tienes acceso al destino previo de esta acción rápida. Escoge uno nuevo a continuación.', updateDestination: 'Actualiza el destino', + createReport: 'Crear informe', }, iou: { amount: 'Importe', diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 0313355739e1..cf63e2007239 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2528,6 +2528,15 @@ function buildNewReportOptimisticData(policy: OnyxEntry, reportID: strin key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReport?.reportID}`, value: {[reportActionID]: optimisticReportPreview}, }, + { + onyxMethod: Onyx.METHOD.SET, + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + value: { + action: CONST.QUICK_ACTIONS.CREATE_REPORT, + chatReportID: parentReport?.reportID, + isFirstQuickAction: isEmptyObject(quickAction), + }, + }, ]; const failureData: OnyxUpdate[] = [ @@ -2541,6 +2550,11 @@ function buildNewReportOptimisticData(policy: OnyxEntry, reportID: strin key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, value: {[reportActionID]: {errorFields: {create: getMicroSecondOnyxErrorWithTranslationKey('report.genericCreateReportFailureMessage')}}}, }, + { + onyxMethod: Onyx.METHOD.SET, + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + value: quickAction ?? null, + }, ]; const successData: OnyxUpdate[] = [ @@ -2572,12 +2586,12 @@ function buildNewReportOptimisticData(policy: OnyxEntry, reportID: strin return {optimisticData, successData, failureData}; } -function createNewReport(creatorPersonalDetails: PersonalDetails, policyID?: string) { +function createNewReport(creatorPersonalDetails: PersonalDetails, policyID?: string, shouldForceReplaceScreen = false) { const policy = getPolicy(policyID); const optimisticReportID = generateReportID(); const reportActionID = rand64(); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const reportName = `${creatorPersonalDetails.firstName || 'User'}'s report`; + const reportName = `${creatorPersonalDetails.firstName || 'User'}'s aaaaa`; const {optimisticData, successData, failureData} = buildNewReportOptimisticData(policy, optimisticReportID, reportActionID, reportName, creatorPersonalDetails); @@ -2586,6 +2600,7 @@ function createNewReport(creatorPersonalDetails: PersonalDetails, policyID?: str {reportName, type: CONST.REPORT.TYPE.EXPENSE, policyID, reportID: optimisticReportID, reportActionID}, {optimisticData, successData, failureData}, ); + Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID, backTo: Navigation.getActiveRoute()}), {forceReplace: shouldForceReplaceScreen}); return optimisticReportID; } diff --git a/src/pages/NewReportWorkspaceSelectionPage.tsx b/src/pages/NewReportWorkspaceSelectionPage.tsx index 554a3a378893..6096715d6d69 100644 --- a/src/pages/NewReportWorkspaceSelectionPage.tsx +++ b/src/pages/NewReportWorkspaceSelectionPage.tsx @@ -45,8 +45,7 @@ function NewReportWorkspaceSelectionPage() { if (!policyID) { return; } - const createdReportID = createNewReport(currentUserPersonalDetails, policyID); - Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: createdReportID, backTo: Navigation.getActiveRoute()}), {forceReplace: true}); + createNewReport(currentUserPersonalDetails, policyID, true); }, [currentUserPersonalDetails], ); diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx index b7e70e5dd812..b24a220fd11c 100644 --- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx @@ -110,6 +110,8 @@ const getQuickActionIcon = (action: QuickActionName): React.FC => { return getIconForAction(CONST.IOU.TYPE.TRACK); case CONST.QUICK_ACTIONS.TRACK_SCAN: return Expensicons.ReceiptScan; + case CONST.QUICK_ACTIONS.CREATE_REPORT: + return Expensicons.Document; default: return Expensicons.MoneyCircle; } @@ -160,6 +162,8 @@ const getQuickActionTitle = (action: QuickActionName): TranslationPaths => { return 'quickAction.paySomeone'; case CONST.QUICK_ACTIONS.ASSIGN_TASK: return 'quickAction.assignTask'; + case CONST.QUICK_ACTIONS.CREATE_REPORT: + return 'quickAction.createReport'; default: return '' as TranslationPaths; } @@ -191,6 +195,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT }, [activePolicy, activePolicyID, session?.accountID, allReports]); const [quickActionPolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${quickActionReport?.policyID}`); const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: (c) => mapOnyxCollectionItems(c, policySelector)}); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const [isCreateMenuActive, setIsCreateMenuActive] = useState(false); const [modalVisible, setModalVisible] = useState(false); @@ -383,6 +388,25 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT shouldTeleportPortalToModalLayer: true, }; + if (quickAction?.action === CONST.QUICK_ACTIONS.CREATE_REPORT) { + const onSelected = () => { + interceptAnonymousUser(() => { + createNewReport(currentUserPersonalDetails, quickActionPolicy?.id); + }); + }; + + return [ + { + ...baseQuickAction, + icon: getQuickActionIcon(quickAction?.action), + text: quickActionTitle, + description: quickActionPolicy?.name ?? '', + onSelected, + shouldShowSubscriptRightAvatar: true, + }, + ]; + } + if (quickAction?.action) { const iouType = getIouType(quickAction?.action); if (!!iouType && !canCreateRequest(quickActionReport, quickActionPolicy, iouType)) { @@ -440,9 +464,10 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT quickActionAvatars, quickAction, policyChatForActivePolicy, - quickActionReport, - quickActionPolicy, quickActionTitle, + quickActionPolicy, + currentUserPersonalDetails, + quickActionReport, hideQABSubtitle, isValidReport, selectOption, @@ -450,7 +475,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT const viewTourTaskReportID = introSelected?.viewTour; const [viewTourTaskReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${viewTourTaskReportID}`); - const currentUserPersonalDetails = useCurrentUserPersonalDetails(); + const canModifyTask = canModifyTaskUtils(viewTourTaskReport, currentUserPersonalDetails.accountID); const canActionTask = canActionTaskUtils(viewTourTaskReport, currentUserPersonalDetails.accountID); @@ -492,14 +517,12 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT // If the user's default workspace is a paid group workspace with chat enabled, we create a report with it by default if (activePolicy && activePolicy.isPolicyExpenseChatEnabled && isPaidGroupPolicy(activePolicy)) { - const createdReportID = createNewReport(currentUserPersonalDetails, activePolicyID); - Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: createdReportID, backTo: Navigation.getActiveRoute()})); + createNewReport(currentUserPersonalDetails, activePolicyID); return; } if (groupPoliciesWithChatEnabled.length === 1) { - const createdReportID = createNewReport(currentUserPersonalDetails, groupPoliciesWithChatEnabled.at(0)?.id); - Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: createdReportID, backTo: Navigation.getActiveRoute()})); + createNewReport(currentUserPersonalDetails, groupPoliciesWithChatEnabled.at(0)?.id); return; } From 3ae66bd1af93ffb80b2a67e7d5fc1b4d7920e212 Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Thu, 27 Mar 2025 14:41:54 +0100 Subject: [PATCH 2/7] clean up Create Report QAB --- .../API/parameters/CreateAppReportParams.ts | 1 + src/libs/actions/QuickActionNavigation.ts | 16 +++++++-- src/libs/actions/Report.ts | 4 +-- src/pages/NewReportWorkspaceSelectionPage.tsx | 1 - .../FloatingActionButtonAndPopover.tsx | 34 ++++++------------- tests/unit/QuickActionNavigationTest.ts | 8 ++--- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/libs/API/parameters/CreateAppReportParams.ts b/src/libs/API/parameters/CreateAppReportParams.ts index 5fccf0e7a166..e765c8356877 100644 --- a/src/libs/API/parameters/CreateAppReportParams.ts +++ b/src/libs/API/parameters/CreateAppReportParams.ts @@ -4,5 +4,6 @@ type CreateAppReportParams = { type: string; reportID: string; reportActionID: string; + shouldUpdateQAB: boolean; }; export default CreateAppReportParams; diff --git a/src/libs/actions/QuickActionNavigation.ts b/src/libs/actions/QuickActionNavigation.ts index cb05c42b2fa3..b35c8e106297 100644 --- a/src/libs/actions/QuickActionNavigation.ts +++ b/src/libs/actions/QuickActionNavigation.ts @@ -1,9 +1,11 @@ import {generateReportID} from '@libs/ReportUtils'; import CONST from '@src/CONST'; +import type {PersonalDetails} from '@src/types/onyx'; import type {QuickActionName} from '@src/types/onyx/QuickAction'; import type QuickAction from '@src/types/onyx/QuickAction'; import type {IOURequestType} from './IOU'; import {startMoneyRequest} from './IOU'; +import {createNewReport} from './Report'; import {startOutCreateTaskQuickAction} from './Task'; function getQuickActionRequestType(action: QuickActionName | undefined): IOURequestType | undefined { @@ -25,7 +27,14 @@ function getQuickActionRequestType(action: QuickActionName | undefined): IOURequ return requestType; } -function navigateToQuickAction(isValidReport: boolean, quickActionReportID: string, quickAction: QuickAction, selectOption: (onSelected: () => void, shouldRestrictAction: boolean) => void) { +function navigateToQuickAction( + isValidReport: boolean, + quickAction: QuickAction, + currentUserPersonalDetails: PersonalDetails, + policyID: string | undefined, + selectOption: (onSelected: () => void, shouldRestrictAction: boolean) => void, +) { + const quickActionReportID = `${quickAction?.chatReportID ?? CONST.DEFAULT_NUMBER_ID}`; const reportID = isValidReport ? quickActionReportID : generateReportID(); const requestType = getQuickActionRequestType(quickAction?.action); @@ -46,11 +55,14 @@ function navigateToQuickAction(isValidReport: boolean, quickActionReportID: stri return; case CONST.QUICK_ACTIONS.ASSIGN_TASK: selectOption(() => startOutCreateTaskQuickAction(isValidReport ? reportID : '', quickAction.targetAccountID ?? CONST.DEFAULT_NUMBER_ID), false); - break; + return; case CONST.QUICK_ACTIONS.TRACK_MANUAL: case CONST.QUICK_ACTIONS.TRACK_SCAN: case CONST.QUICK_ACTIONS.TRACK_DISTANCE: selectOption(() => startMoneyRequest(CONST.IOU.TYPE.TRACK, reportID, requestType, true), false); + return; + case CONST.QUICK_ACTIONS.CREATE_REPORT: + selectOption(() => createNewReport(currentUserPersonalDetails, policyID), true); break; default: } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index cf63e2007239..6bde487e0116 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2591,13 +2591,13 @@ function createNewReport(creatorPersonalDetails: PersonalDetails, policyID?: str const optimisticReportID = generateReportID(); const reportActionID = rand64(); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const reportName = `${creatorPersonalDetails.firstName || 'User'}'s aaaaa`; + const reportName = `${creatorPersonalDetails.firstName || 'User'}'s report`; const {optimisticData, successData, failureData} = buildNewReportOptimisticData(policy, optimisticReportID, reportActionID, reportName, creatorPersonalDetails); API.write( WRITE_COMMANDS.CREATE_APP_REPORT, - {reportName, type: CONST.REPORT.TYPE.EXPENSE, policyID, reportID: optimisticReportID, reportActionID}, + {reportName, type: CONST.REPORT.TYPE.EXPENSE, policyID, reportID: optimisticReportID, reportActionID, shouldUpdateQAB: true}, {optimisticData, successData, failureData}, ); Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID, backTo: Navigation.getActiveRoute()}), {forceReplace: shouldForceReplaceScreen}); diff --git a/src/pages/NewReportWorkspaceSelectionPage.tsx b/src/pages/NewReportWorkspaceSelectionPage.tsx index 6096715d6d69..5df715fdc3e6 100644 --- a/src/pages/NewReportWorkspaceSelectionPage.tsx +++ b/src/pages/NewReportWorkspaceSelectionPage.tsx @@ -20,7 +20,6 @@ import {isPolicyAdmin, shouldShowPolicy} from '@libs/PolicyUtils'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; type WorkspaceListItem = { diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx index b24a220fd11c..798eef828c94 100644 --- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx @@ -272,6 +272,13 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT return quickAction?.action === CONST.QUICK_ACTIONS.SEND_MONEY && displayName.length === 0; }, [isValidReport, quickActionAvatars, personalDetails, quickAction?.action]); + const quickActionSubtitle = useMemo(() => { + if (quickAction?.action === CONST.QUICK_ACTIONS.CREATE_REPORT) { + return quickActionPolicy?.name; + } + return !hideQABSubtitle ? getReportName(quickActionReport) ?? translate('quickAction.updateDestination') : ''; + }, [hideQABSubtitle, quickAction?.action, quickActionPolicy?.name, quickActionReport, translate]); + const selectOption = useCallback( (onSelected: () => void, shouldRestrictAction: boolean) => { if (shouldRestrictAction && quickActionReport?.policyID && shouldRestrictUserBillableActions(quickActionReport.policyID)) { @@ -388,25 +395,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT shouldTeleportPortalToModalLayer: true, }; - if (quickAction?.action === CONST.QUICK_ACTIONS.CREATE_REPORT) { - const onSelected = () => { - interceptAnonymousUser(() => { - createNewReport(currentUserPersonalDetails, quickActionPolicy?.id); - }); - }; - - return [ - { - ...baseQuickAction, - icon: getQuickActionIcon(quickAction?.action), - text: quickActionTitle, - description: quickActionPolicy?.name ?? '', - onSelected, - shouldShowSubscriptRightAvatar: true, - }, - ]; - } - if (quickAction?.action) { const iouType = getIouType(quickAction?.action); if (!!iouType && !canCreateRequest(quickActionReport, quickActionPolicy, iouType)) { @@ -417,7 +405,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT } const onSelected = () => { interceptAnonymousUser(() => { - navigateToQuickAction(isValidReport, `${quickActionReport?.reportID ?? CONST.DEFAULT_NUMBER_ID}`, quickAction, selectOption); + navigateToQuickAction(isValidReport, quickAction, currentUserPersonalDetails, quickActionPolicy?.id, selectOption); }); }; return [ @@ -425,7 +413,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT ...baseQuickAction, icon: getQuickActionIcon(quickAction?.action), text: quickActionTitle, - description: !hideQABSubtitle ? getReportName(quickActionReport) ?? translate('quickAction.updateDestination') : '', + description: quickActionSubtitle, onSelected, shouldShowSubscriptRightAvatar: isPolicyExpenseChat(quickActionReport), }, @@ -465,10 +453,10 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT quickAction, policyChatForActivePolicy, quickActionTitle, - quickActionPolicy, + quickActionSubtitle, currentUserPersonalDetails, + quickActionPolicy, quickActionReport, - hideQABSubtitle, isValidReport, selectOption, ]); diff --git a/tests/unit/QuickActionNavigationTest.ts b/tests/unit/QuickActionNavigationTest.ts index 86c54ca51685..3142a668b3ac 100644 --- a/tests/unit/QuickActionNavigationTest.ts +++ b/tests/unit/QuickActionNavigationTest.ts @@ -14,7 +14,7 @@ describe('IOU Utils', () => { it('should be navigated to Manual Submit Expense', () => { // When the quick action is REQUEST_MANUAL - navigateToQuickAction(true, reportID, {action: CONST.QUICK_ACTIONS.REQUEST_MANUAL}, (onSelected: () => void) => { + navigateToQuickAction(true, {action: CONST.QUICK_ACTIONS.REQUEST_MANUAL, chatReportID: reportID}, {accountID: 1234}, undefined, (onSelected: () => void) => { onSelected(); }); // Then we should start manual submit request flow @@ -23,7 +23,7 @@ describe('IOU Utils', () => { it('should be navigated to Scan receipt Split Expense', () => { // When the quick action is SPLIT_SCAN - navigateToQuickAction(true, reportID, {action: CONST.QUICK_ACTIONS.SPLIT_SCAN}, (onSelected: () => void) => { + navigateToQuickAction(true, {action: CONST.QUICK_ACTIONS.SPLIT_SCAN, chatReportID: reportID}, {accountID: 1234}, undefined, (onSelected: () => void) => { onSelected(); }); // Then we should start scan split request flow @@ -32,7 +32,7 @@ describe('IOU Utils', () => { it('should be navigated to Track distance Expense', () => { // When the quick action is TRACK_DISTANCE - navigateToQuickAction(true, reportID, {action: CONST.QUICK_ACTIONS.TRACK_DISTANCE}, (onSelected: () => void) => { + navigateToQuickAction(true, {action: CONST.QUICK_ACTIONS.TRACK_DISTANCE, chatReportID: reportID}, {accountID: 1234}, undefined, (onSelected: () => void) => { onSelected(); }); // Then we should start distance track request flow @@ -41,7 +41,7 @@ describe('IOU Utils', () => { it('should be navigated to Per Diem Expense', () => { // When the quick action is PER_DIEM - navigateToQuickAction(true, reportID, {action: CONST.QUICK_ACTIONS.PER_DIEM}, (onSelected: () => void) => { + navigateToQuickAction(true, {action: CONST.QUICK_ACTIONS.PER_DIEM, chatReportID: reportID}, {accountID: 1234}, undefined, (onSelected: () => void) => { onSelected(); }); // Then we should start per diem request flow From 92a5a89f09e3026b0d74c4aba7c59d0687236941 Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Thu, 27 Mar 2025 16:04:34 +0100 Subject: [PATCH 3/7] fix PR comments --- src/libs/actions/QuickActionNavigation.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/QuickActionNavigation.ts b/src/libs/actions/QuickActionNavigation.ts index b35c8e106297..98a1afeb2735 100644 --- a/src/libs/actions/QuickActionNavigation.ts +++ b/src/libs/actions/QuickActionNavigation.ts @@ -44,23 +44,23 @@ function navigateToQuickAction( case CONST.QUICK_ACTIONS.REQUEST_DISTANCE: case CONST.QUICK_ACTIONS.PER_DIEM: selectOption(() => startMoneyRequest(CONST.IOU.TYPE.SUBMIT, reportID, requestType, true), true); - return; + break; case CONST.QUICK_ACTIONS.SPLIT_MANUAL: case CONST.QUICK_ACTIONS.SPLIT_SCAN: case CONST.QUICK_ACTIONS.SPLIT_DISTANCE: selectOption(() => startMoneyRequest(CONST.IOU.TYPE.SPLIT, reportID, requestType, true), true); - return; + break; case CONST.QUICK_ACTIONS.SEND_MONEY: selectOption(() => startMoneyRequest(CONST.IOU.TYPE.PAY, reportID, undefined, true), false); - return; + break; case CONST.QUICK_ACTIONS.ASSIGN_TASK: selectOption(() => startOutCreateTaskQuickAction(isValidReport ? reportID : '', quickAction.targetAccountID ?? CONST.DEFAULT_NUMBER_ID), false); - return; + break; case CONST.QUICK_ACTIONS.TRACK_MANUAL: case CONST.QUICK_ACTIONS.TRACK_SCAN: case CONST.QUICK_ACTIONS.TRACK_DISTANCE: selectOption(() => startMoneyRequest(CONST.IOU.TYPE.TRACK, reportID, requestType, true), false); - return; + break; case CONST.QUICK_ACTIONS.CREATE_REPORT: selectOption(() => createNewReport(currentUserPersonalDetails, policyID), true); break; From d78e97c5289b53cbadf4f4a0eb03cde9ededb888 Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Fri, 28 Mar 2025 10:50:23 +0100 Subject: [PATCH 4/7] fix PR comments --- src/libs/actions/QuickActionNavigation.ts | 10 +++++++--- src/libs/actions/Report.ts | 3 +-- src/pages/NewReportWorkspaceSelectionPage.tsx | 4 +++- .../home/sidebar/FloatingActionButtonAndPopover.tsx | 7 +++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/QuickActionNavigation.ts b/src/libs/actions/QuickActionNavigation.ts index 98a1afeb2735..68dbd660507d 100644 --- a/src/libs/actions/QuickActionNavigation.ts +++ b/src/libs/actions/QuickActionNavigation.ts @@ -1,5 +1,7 @@ +import Navigation from '@libs/Navigation/Navigation'; import {generateReportID} from '@libs/ReportUtils'; import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; import type {PersonalDetails} from '@src/types/onyx'; import type {QuickActionName} from '@src/types/onyx/QuickAction'; import type QuickAction from '@src/types/onyx/QuickAction'; @@ -34,8 +36,7 @@ function navigateToQuickAction( policyID: string | undefined, selectOption: (onSelected: () => void, shouldRestrictAction: boolean) => void, ) { - const quickActionReportID = `${quickAction?.chatReportID ?? CONST.DEFAULT_NUMBER_ID}`; - const reportID = isValidReport ? quickActionReportID : generateReportID(); + const reportID = isValidReport && quickAction?.chatReportID ? quickAction?.chatReportID : generateReportID(); const requestType = getQuickActionRequestType(quickAction?.action); switch (quickAction?.action) { @@ -62,7 +63,10 @@ function navigateToQuickAction( selectOption(() => startMoneyRequest(CONST.IOU.TYPE.TRACK, reportID, requestType, true), false); break; case CONST.QUICK_ACTIONS.CREATE_REPORT: - selectOption(() => createNewReport(currentUserPersonalDetails, policyID), true); + selectOption(() => { + const optimisticReportID = createNewReport(currentUserPersonalDetails, policyID); + Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID, backTo: Navigation.getActiveRoute()})); + }, true); break; default: } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 6bde487e0116..28e3c69efb48 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -2586,7 +2586,7 @@ function buildNewReportOptimisticData(policy: OnyxEntry, reportID: strin return {optimisticData, successData, failureData}; } -function createNewReport(creatorPersonalDetails: PersonalDetails, policyID?: string, shouldForceReplaceScreen = false) { +function createNewReport(creatorPersonalDetails: PersonalDetails, policyID?: string) { const policy = getPolicy(policyID); const optimisticReportID = generateReportID(); const reportActionID = rand64(); @@ -2600,7 +2600,6 @@ function createNewReport(creatorPersonalDetails: PersonalDetails, policyID?: str {reportName, type: CONST.REPORT.TYPE.EXPENSE, policyID, reportID: optimisticReportID, reportActionID, shouldUpdateQAB: true}, {optimisticData, successData, failureData}, ); - Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID, backTo: Navigation.getActiveRoute()}), {forceReplace: shouldForceReplaceScreen}); return optimisticReportID; } diff --git a/src/pages/NewReportWorkspaceSelectionPage.tsx b/src/pages/NewReportWorkspaceSelectionPage.tsx index 5df715fdc3e6..92c913b09f36 100644 --- a/src/pages/NewReportWorkspaceSelectionPage.tsx +++ b/src/pages/NewReportWorkspaceSelectionPage.tsx @@ -20,6 +20,7 @@ import {isPolicyAdmin, shouldShowPolicy} from '@libs/PolicyUtils'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; type WorkspaceListItem = { @@ -44,7 +45,8 @@ function NewReportWorkspaceSelectionPage() { if (!policyID) { return; } - createNewReport(currentUserPersonalDetails, policyID, true); + const optimisticReportID = createNewReport(currentUserPersonalDetails, policyID); + Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID, backTo: Navigation.getActiveRoute()}), {forceReplace: true}); }, [currentUserPersonalDetails], ); diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx index 798eef828c94..26dea9866ec7 100644 --- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx @@ -505,12 +505,15 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT // If the user's default workspace is a paid group workspace with chat enabled, we create a report with it by default if (activePolicy && activePolicy.isPolicyExpenseChatEnabled && isPaidGroupPolicy(activePolicy)) { - createNewReport(currentUserPersonalDetails, activePolicyID); + const optimisticReportID = createNewReport(currentUserPersonalDetails, activePolicyID); + Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID, backTo: Navigation.getActiveRoute()})); + return; } if (groupPoliciesWithChatEnabled.length === 1) { - createNewReport(currentUserPersonalDetails, groupPoliciesWithChatEnabled.at(0)?.id); + const optimisticReportID = createNewReport(currentUserPersonalDetails, groupPoliciesWithChatEnabled.at(0)?.id); + Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID, backTo: Navigation.getActiveRoute()})); return; } From 80dc09ee430da277e916aa0a9542ade013896ac8 Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Fri, 28 Mar 2025 11:24:18 +0100 Subject: [PATCH 5/7] add tests for QuickActionNavigation --- tests/unit/QuickActionNavigationTest.ts | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/unit/QuickActionNavigationTest.ts b/tests/unit/QuickActionNavigationTest.ts index 3142a668b3ac..e37cb1153403 100644 --- a/tests/unit/QuickActionNavigationTest.ts +++ b/tests/unit/QuickActionNavigationTest.ts @@ -1,11 +1,19 @@ import {startMoneyRequest} from '@libs/actions/IOU'; import {navigateToQuickAction} from '@libs/actions/QuickActionNavigation'; +import {createNewReport} from '@libs/actions/Report'; +import {startOutCreateTaskQuickAction} from '@libs/actions/Task'; import {generateReportID} from '@libs/ReportUtils'; import CONST from '@src/CONST'; jest.mock('@libs/actions/IOU', () => ({ startMoneyRequest: jest.fn(), })); +jest.mock('@libs/actions/Report', () => ({ + createNewReport: jest.fn(), +})); +jest.mock('@libs/actions/Task', () => ({ + startOutCreateTaskQuickAction: jest.fn(), +})); describe('IOU Utils', () => { // Given navigateToQuickAction is called with quick action argument when clicking on quick action button from Global create menu @@ -49,3 +57,22 @@ describe('IOU Utils', () => { }); }); }); + +describe('Non IOU quickActions test:', () => { + const reportID = generateReportID(); + + describe('navigateToQuickAction', () => { + it('creates new report for "createReport" quick action', () => { + navigateToQuickAction(true, {action: CONST.QUICK_ACTIONS.CREATE_REPORT, chatReportID: reportID}, {accountID: 1234}, undefined, (onSelected: () => void) => { + onSelected(); + }); + expect(createNewReport).toHaveBeenCalled(); + }); + it('starts create task flow for "assignTask" quick action', () => { + navigateToQuickAction(true, {action: CONST.QUICK_ACTIONS.ASSIGN_TASK, targetAccountID: 123}, {accountID: 1234}, undefined, (onSelected: () => void) => { + onSelected(); + }); + expect(startOutCreateTaskQuickAction).toHaveBeenCalled(); + }); + }); +}); From a3f8e99cb45ef2217dae20f06b7bb09ec94eb6cc Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Fri, 28 Mar 2025 13:57:03 +0100 Subject: [PATCH 6/7] add QAB test --- tests/actions/ReportTest.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/actions/ReportTest.ts b/tests/actions/ReportTest.ts index d18213bd8f54..416577f78e70 100644 --- a/tests/actions/ReportTest.ts +++ b/tests/actions/ReportTest.ts @@ -1485,4 +1485,37 @@ describe('actions/Report', () => { expect(report?.lastMentionedTime).toBeUndefined(); }); + + it('should create new report and "create report" quick action, when createNewReport gets called', async () => { + const reportID = Report.createNewReport({accountID: 1234}, '5678'); + await new Promise((resolve) => { + const connection = Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT, + waitForCollectionCallback: true, + callback: (reports) => { + Onyx.disconnect(connection); + const createdReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]; + + // assert correctness of crucial onyx data + expect(createdReport?.reportID).toBe(reportID); + expect(createdReport?.total).toBe(0); + + resolve(); + }, + }); + }); + + await new Promise((resolve) => { + const connection = Onyx.connect({ + key: ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE, + callback: (quickAction) => { + Onyx.disconnect(connection); + + // Then the quickAction.action should be set to CREATE_REPORT + expect(quickAction?.action).toBe(CONST.QUICK_ACTIONS.CREATE_REPORT); + resolve(); + }, + }); + }); + }); }); From 575f1d467f730332a716e2cd0c076c28a5cc0a7b Mon Sep 17 00:00:00 2001 From: Jakub Szymczak Date: Fri, 28 Mar 2025 14:21:49 +0100 Subject: [PATCH 7/7] fix wrong navigation --- src/pages/NewReportWorkspaceSelectionPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/NewReportWorkspaceSelectionPage.tsx b/src/pages/NewReportWorkspaceSelectionPage.tsx index d769a3deccbf..1414702635d0 100644 --- a/src/pages/NewReportWorkspaceSelectionPage.tsx +++ b/src/pages/NewReportWorkspaceSelectionPage.tsx @@ -47,7 +47,7 @@ function NewReportWorkspaceSelectionPage() { } const optimisticReportID = createNewReport(currentUserPersonalDetails, policyID); Navigation.setNavigationActionToMicrotaskQueue(() => { - Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID, backTo: Navigation.getActiveRoute()}), {forceReplace: true}); + Navigation.navigate(ROUTES.SEARCH_MONEY_REQUEST_REPORT.getRoute({reportID: optimisticReportID}), {forceReplace: true}); }); }, [currentUserPersonalDetails],