diff --git a/src/components/ProductTrainingContext/TOOLTIPS.ts b/src/components/ProductTrainingContext/TOOLTIPS.ts index bc10a5be185e0..3d8a6c7eff94e 100644 --- a/src/components/ProductTrainingContext/TOOLTIPS.ts +++ b/src/components/ProductTrainingContext/TOOLTIPS.ts @@ -19,6 +19,7 @@ type ProductTrainingTooltipName = ValueOf = { {text: 'productTrainingTooltip.globalCreateTooltip.part1', isBold: true}, {text: 'productTrainingTooltip.globalCreateTooltip.part2', isBold: false}, {text: 'productTrainingTooltip.globalCreateTooltip.part3', isBold: false}, + {text: 'productTrainingTooltip.globalCreateTooltip.part4', isBold: false}, ], onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(GLOBAL_CREATE_TOOLTIP, isDismissedUsingCloseButton), name: GLOBAL_CREATE_TOOLTIP, - priority: 1200, - shouldShow: () => true, + priority: 1950, + shouldShow: ({isUserPolicyEmployee}) => isUserPolicyEmployee, }, [BOTTOM_NAV_INBOX_TOOLTIP]: { content: [ @@ -80,14 +82,13 @@ const TOOLTIPS: Record = { }, [LHN_WORKSPACE_CHAT_TOOLTIP]: { content: [ - {text: 'productTrainingTooltip.workspaceChatTooltip.part1', isBold: true}, - {text: 'productTrainingTooltip.workspaceChatTooltip.part2', isBold: false}, - {text: 'productTrainingTooltip.workspaceChatTooltip.part3', isBold: false}, + {text: 'productTrainingTooltip.workspaceChatTooltip.part1', isBold: false}, + {text: 'productTrainingTooltip.workspaceChatTooltip.part2', isBold: true}, ], onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(LHN_WORKSPACE_CHAT_TOOLTIP, isDismissedUsingCloseButton), name: LHN_WORKSPACE_CHAT_TOOLTIP, - priority: 800, - shouldShow: () => true, + priority: 1800, + shouldShow: ({isUserPolicyEmployee}) => isUserPolicyEmployee, }, [EXPENSE_REPORTS_FILTER]: { content: [ diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx index d5fea75202c1c..48a6cddf2c18c 100644 --- a/src/components/ProductTrainingContext/index.tsx +++ b/src/components/ProductTrainingContext/index.tsx @@ -14,7 +14,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {parseFSAttributes} from '@libs/Fullstory'; import getPlatform from '@libs/getPlatform'; import {hasCompletedGuidedSetupFlowSelector} from '@libs/onboardingSelectors'; -import {getActiveAdminWorkspaces} from '@libs/PolicyUtils'; +import {getActiveAdminWorkspaces, getActiveEmployeeWorkspaces} from '@libs/PolicyUtils'; import isProductTrainingElementDismissed from '@libs/TooltipUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; @@ -60,6 +60,13 @@ function ProductTrainingContextProvider({children}: ChildrenProps) { const [allPolicies, allPoliciesMetadata] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true}); const [currentUserLogin, currentUserLoginMetadata] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email, canBeMissing: true}); + const isUserPolicyEmployee = useMemo(() => { + if (!allPolicies || !currentUserLogin || isLoadingOnyxValue(allPoliciesMetadata, currentUserLoginMetadata)) { + return false; + } + return getActiveEmployeeWorkspaces(allPolicies, currentUserLogin).length > 0; + }, [allPolicies, currentUserLogin, allPoliciesMetadata, currentUserLoginMetadata]); + const isUserPolicyAdmin = useMemo(() => { if (!allPolicies || !currentUserLogin || isLoadingOnyxValue(allPoliciesMetadata, currentUserLoginMetadata)) { return false; @@ -68,6 +75,7 @@ function ProductTrainingContextProvider({children}: ChildrenProps) { }, [allPolicies, currentUserLogin, allPoliciesMetadata, currentUserLoginMetadata]); const [dismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {canBeMissing: true}); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const [modal] = useOnyx(ONYXKEYS.MODAL, {canBeMissing: true}); @@ -141,6 +149,7 @@ function ProductTrainingContextProvider({children}: ChildrenProps) { return tooltipConfig.shouldShow({ shouldUseNarrowLayout, + isUserPolicyEmployee, isUserPolicyAdmin, hasBeenAddedToNudgeMigration, }); @@ -153,6 +162,7 @@ function ProductTrainingContextProvider({children}: ChildrenProps) { shouldUseNarrowLayout, isModalVisible, isLoadingApp, + isUserPolicyEmployee, isUserPolicyAdmin, ], ); diff --git a/src/languages/en.ts b/src/languages/en.ts index 5d47575108525..df9994f6e67b1 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6218,14 +6218,14 @@ const translations = { part4: 'chat about expenses.', }, workspaceChatTooltip: { - part1: 'Submit expenses', - part2: ' and chat with', - part3: '\napprovers here!', + part1: 'Chat with ', + part2: 'approvers', }, globalCreateTooltip: { part1: 'Create expenses', part2: ', start chatting,', - part3: '\nand more!', + part3: '\nand more.', + part4: ' Try it out!', }, expenseReportsFilter: { part1: 'Welcome! Find all of your', diff --git a/src/languages/es.ts b/src/languages/es.ts index a96d9cc6bb973..d610b35efeaf4 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -6743,14 +6743,14 @@ const translations = { part4: 'chatea sobre los gastos.', }, workspaceChatTooltip: { - part1: 'Envía gastos', - part2: ' y chatea con', - part3: '\naprobadores aquí!', + part1: 'Chatea con ', + part2: 'los aprobadores', }, globalCreateTooltip: { part1: 'Crea gastos', - part2: ', comienza a chatear,', - part3: '\ny mucho más!', + part2: ', empieza a chatear', + part3: '\ny más.', + part4: ' ¡Pruébalo!', }, expenseReportsFilter: { part1: '¡Bienvenido! Aquí encontrarás todos los', diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 577b5e85d6714..81e9e42f13148 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -718,6 +718,12 @@ function getActiveAdminWorkspaces(policies: OnyxCollection | null, curre return activePolicies.filter((policy) => shouldShowPolicy(policy, isOfflineNetworkStore(), currentUserLogin) && isPolicyAdmin(policy, currentUserLogin)); } +/** Return active policies where current user is an employee (of the role "user") */ +function getActiveEmployeeWorkspaces(policies: OnyxCollection | null, currentUserLogin: string | undefined): Policy[] { + const activePolicies = getActivePolicies(policies, currentUserLogin); + return activePolicies.filter((policy) => shouldShowPolicy(policy, isOfflineNetworkStore(), currentUserLogin) && isPolicyUser(policy, currentUserLogin)); +} + /** * * Checks whether the current user has a policy with Xero accounting software integration @@ -1559,6 +1565,7 @@ export { getManagerAccountID, isPrefferedExporter, areAllGroupPoliciesExpenseChatDisabled, + getActiveEmployeeWorkspaces, isUserInvitedToWorkspace, }; diff --git a/tests/ui/components/ProductTrainingContextProvider.tsx b/tests/ui/components/ProductTrainingContextProvider.tsx index 3d4f3ebb293de..9494214dcb543 100644 --- a/tests/ui/components/ProductTrainingContextProvider.tsx +++ b/tests/ui/components/ProductTrainingContextProvider.tsx @@ -93,7 +93,7 @@ describe('ProductTrainingContextProvider', () => { Onyx.merge(ONYXKEYS.IS_LOADING_APP, true); await waitForBatchedUpdatesWithAct(); - const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP; + const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP; const {result} = renderHook(() => useProductTrainingContext(testTooltip), {wrapper}); // Then tooltip should not show @@ -105,7 +105,7 @@ describe('ProductTrainingContextProvider', () => { Onyx.merge(ONYXKEYS.NVP_ONBOARDING, {hasCompletedGuidedSetupFlow: false}); await waitForBatchedUpdatesWithAct(); - const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP; + const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP; const {result} = renderHook(() => useProductTrainingContext(testTooltip), {wrapper}); // Then tooltip should not show @@ -117,7 +117,7 @@ describe('ProductTrainingContextProvider', () => { Onyx.merge(ONYXKEYS.NVP_ONBOARDING, {hasCompletedGuidedSetupFlow: true}); await waitForBatchedUpdatesWithAct(); - const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP; + const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP; const {result} = renderHook(() => useProductTrainingContext(testTooltip), {wrapper}); // Then tooltip should show @@ -125,7 +125,7 @@ describe('ProductTrainingContextProvider', () => { }); it('should keep tooltip visible when another tooltip with shouldShow=false is unmounted', async () => { - const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP; + const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP; const ref = createRef(); // When multiple tooltips with the same name but different shouldShow values are rendered @@ -178,7 +178,7 @@ describe('ProductTrainingContextProvider', () => { await waitForBatchedUpdatesWithAct(); // Then tooltips should not show - const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP; + const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.BOTTOM_NAV_INBOX_TOOLTIP; const {result} = renderHook(() => useProductTrainingContext(testTooltip), {wrapper}); // Expect tooltip to be hidden @@ -197,7 +197,7 @@ describe('ProductTrainingContextProvider', () => { }); await waitForBatchedUpdatesWithAct(); - const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP; + const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.BOTTOM_NAV_INBOX_TOOLTIP; const {result} = renderHook(() => useProductTrainingContext(testTooltip), {wrapper}); // Then tooltip should show @@ -210,7 +210,7 @@ describe('ProductTrainingContextProvider', () => { // When a tooltip has been dismissed const date = new Date(); Onyx.merge(ONYXKEYS.NVP_ONBOARDING, {hasCompletedGuidedSetupFlow: true}); - const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP; + const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP; Onyx.merge(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, { migratedUserWelcomeModal: { timestamp: DateUtils.getDBTime(date.valueOf()), @@ -237,7 +237,7 @@ describe('ProductTrainingContextProvider', () => { }, }); await waitForBatchedUpdatesWithAct(); - const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP; + const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP; const {result, rerender} = renderHook(() => useProductTrainingContext(testTooltip), {wrapper}); // When the user dismiss the tooltip result.current.hideProductTrainingTooltip(); @@ -295,8 +295,8 @@ describe('ProductTrainingContextProvider', () => { await waitForBatchedUpdatesWithAct(); // Then only highest priority tooltip should show - const highPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP; - const lowPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.LHN_WORKSPACE_CHAT_TOOLTIP; + const highPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP_MANAGER; + const lowPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP; const {result} = renderHook( () => ({ @@ -315,8 +315,8 @@ describe('ProductTrainingContextProvider', () => { // When higher priority tooltip is dismissed Onyx.merge(ONYXKEYS.NVP_ONBOARDING, {hasCompletedGuidedSetupFlow: true}); const date = new Date(); - const highPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP; - const lowPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.LHN_WORKSPACE_CHAT_TOOLTIP; + const highPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP_MANAGER; + const lowPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP; Onyx.merge(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, { migratedUserWelcomeModal: { @@ -353,8 +353,8 @@ describe('ProductTrainingContextProvider', () => { }); await waitForBatchedUpdatesWithAct(); - const highPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP; - const lowPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.LHN_WORKSPACE_CHAT_TOOLTIP; + const highPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP_MANAGER; + const lowPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP; const {result} = renderHook( () => ({