diff --git a/src/CONST.ts b/src/CONST.ts
index cfccbfd12ff1..ca117e9f5057 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -6806,17 +6806,19 @@ const CONST = {
BASE_LIST_ITEM_TEST_ID: 'base-list-item-',
PRODUCT_TRAINING_TOOLTIP_NAMES: {
+ // TODO: CONCEIRGE_LHN_GBR tooltip will be replaced by a tooltip in the #admins room
+ // https://github.com/Expensify/App/issues/57045#issuecomment-2701455668
CONCEIRGE_LHN_GBR: 'conciergeLHNGBR',
RENAME_SAVED_SEARCH: 'renameSavedSearch',
- QUICK_ACTION_BUTTON: 'quickActionButton',
- WORKSAPCE_CHAT_CREATE: 'workspaceChatCreate',
- SEARCH_FILTER_BUTTON_TOOLTIP: 'filterButtonTooltip',
BOTTOM_NAV_INBOX_TOOLTIP: 'bottomNavInboxTooltip',
LHN_WORKSPACE_CHAT_TOOLTIP: 'workspaceChatLHNTooltip',
GLOBAL_CREATE_TOOLTIP: 'globalCreateTooltip',
SCAN_TEST_TOOLTIP: 'scanTestTooltip',
SCAN_TEST_TOOLTIP_MANAGER: 'scanTestTooltipManager',
SCAN_TEST_CONFIRMATION: 'scanTestConfirmation',
+ EXPENSE_REPORTS_FILTER: 'expenseReportsFilter',
+ GBR_RBR_CHAT: 'chatGBRRBR',
+ ACCOUNT_SWITCHER: 'accountSwitcher',
},
CHANGE_POLICY_TRAINING_MODAL: 'changePolicyModal',
SMART_BANNER_HEIGHT: 152,
diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx
index ed2eae7a0a4c..ea4eec229056 100644
--- a/src/components/AccountSwitcher.tsx
+++ b/src/components/AccountSwitcher.tsx
@@ -10,11 +10,11 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import {clearDelegatorErrors, connect, disconnect} from '@libs/actions/Delegate';
-import * as EmojiUtils from '@libs/EmojiUtils';
-import * as ErrorUtils from '@libs/ErrorUtils';
-import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import {getProcessedText, splitTextWithEmojis} from '@libs/EmojiUtils';
+import {getLatestError} from '@libs/ErrorUtils';
+import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils';
import variables from '@styles/variables';
-import * as Modal from '@userActions/Modal';
+import {close} from '@userActions/Modal';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {PersonalDetails} from '@src/types/onyx';
@@ -26,7 +26,9 @@ import * as Expensicons from './Icon/Expensicons';
import type {PopoverMenuItem} from './PopoverMenu';
import PopoverMenu from './PopoverMenu';
import {PressableWithFeedback} from './Pressable';
+import {useProductTrainingContext} from './ProductTrainingContext';
import Text from './Text';
+import EducationalTooltip from './Tooltip/EducationalTooltip';
function AccountSwitcher() {
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
@@ -47,7 +49,12 @@ function AccountSwitcher() {
const isActingAsDelegate = !!account?.delegatedAccess?.delegate ?? false;
const canSwitchAccounts = delegators.length > 0 || isActingAsDelegate;
- const processedTextArray = EmojiUtils.splitTextWithEmojis(currentUserPersonalDetails?.displayName);
+ const processedTextArray = splitTextWithEmojis(currentUserPersonalDetails?.displayName);
+
+ const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
+ CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.ACCOUNT_SWITCHER,
+ canSwitchAccounts,
+ );
const createBaseMenuItem = (
personalDetails: PersonalDetails | undefined,
@@ -58,7 +65,7 @@ function AccountSwitcher() {
return {
text: personalDetails?.displayName ?? personalDetails?.login ?? '',
description: Str.removeSMSDomain(personalDetails?.login ?? ''),
- avatarID: personalDetails?.accountID ?? -1,
+ avatarID: personalDetails?.accountID ?? CONST.DEFAULT_NUMBER_ID,
icon: personalDetails?.avatar ?? '',
iconType: CONST.ICON_TYPE_AVATAR,
outerWrapperStyle: shouldUseNarrowLayout ? {} : styles.accountSwitcherPopover,
@@ -86,14 +93,14 @@ function AccountSwitcher() {
return [currentUserMenuItem];
}
- const delegatePersonalDetails = PersonalDetailsUtils.getPersonalDetailByEmail(delegateEmail);
- const error = ErrorUtils.getLatestError(account?.delegatedAccess?.errorFields?.disconnect);
+ const delegatePersonalDetails = getPersonalDetailByEmail(delegateEmail);
+ const error = getLatestError(account?.delegatedAccess?.errorFields?.disconnect);
return [
createBaseMenuItem(delegatePersonalDetails, error, {
onSelected: () => {
if (isOffline) {
- Modal.close(() => setShouldShowOfflineModal(true));
+ close(() => setShouldShowOfflineModal(true));
return;
}
disconnect();
@@ -107,13 +114,13 @@ function AccountSwitcher() {
.filter(({email}) => email !== currentUserPersonalDetails.login)
.map(({email, role}) => {
const errorFields = account?.delegatedAccess?.errorFields ?? {};
- const error = ErrorUtils.getLatestError(errorFields?.connect?.[email]);
- const personalDetails = PersonalDetailsUtils.getPersonalDetailByEmail(email);
+ const error = getLatestError(errorFields?.connect?.[email]);
+ const personalDetails = getPersonalDetailByEmail(email);
return createBaseMenuItem(personalDetails, error, {
badgeText: translate('delegate.role', {role}),
onSelected: () => {
if (isOffline) {
- Modal.close(() => setShouldShowOfflineModal(true));
+ close(() => setShouldShowOfflineModal(true));
return;
}
connect(email);
@@ -124,65 +131,81 @@ function AccountSwitcher() {
return [currentUserMenuItem, ...delegatorMenuItems];
};
+ const onPressSwitcher = () => {
+ hideProductTrainingTooltip();
+ setShouldShowDelegatorMenu(!shouldShowDelegatorMenu);
+ };
+
return (
<>
- {
- setShouldShowDelegatorMenu(!shouldShowDelegatorMenu);
+
-
-
-
-
+
+
+
+
+
+
+ {processedTextArray.length !== 0 ? getProcessedText(processedTextArray, styles.initialSettingsUsernameEmoji) : currentUserPersonalDetails?.displayName}
+
+ {!!canSwitchAccounts && (
+
+
+
+ )}
+
- {processedTextArray.length !== 0
- ? EmojiUtils.getProcessedText(processedTextArray, styles.initialSettingsUsernameEmoji)
- : currentUserPersonalDetails?.displayName}
+ {Str.removeSMSDomain(currentUserPersonalDetails?.login ?? '')}
- {!!canSwitchAccounts && (
-
-
-
+ {!!user?.isDebugModeEnabled && (
+
+ AccountID: {session?.accountID}
+
)}
-
- {Str.removeSMSDomain(currentUserPersonalDetails?.login ?? '')}
-
- {!!user?.isDebugModeEnabled && (
-
- AccountID: {session?.accountID}
-
- )}
-
-
+
+
+
{!!canSwitchAccounts && (
{
+ if (!shouldShowProductTrainingTooltip) {
+ return undefined;
+ }
+ return data.find((reportID) => {
+ const itemFullReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
+ const itemReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`];
+ if (!itemFullReport) {
+ return false;
+ }
+ if (hasReportErrors(itemFullReport, itemReportActions)) {
+ return true;
+ }
+ const itemParentReportActions = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${itemFullReport?.parentReportID}`];
+ const itemParentReportAction = itemFullReport?.parentReportActionID ? itemParentReportActions?.[itemFullReport?.parentReportActionID] : undefined;
+ const hasGBR = requiresAttentionFromCurrentUser(itemFullReport, itemParentReportAction);
+ return hasGBR;
+ });
+ }, [shouldShowProductTrainingTooltip, data, reportActions, reports]);
+
// When the first item renders we want to call the onFirstItemRendered callback.
// At this point in time we know that the list is actually displaying items.
const hasCalledOnLayout = React.useRef(false);
@@ -179,6 +201,8 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
}
const lastMessageTextFromReport = getLastMessageTextForReport(itemFullReport, lastActorDetails, itemPolicy);
+ const shouldShowRBRorGPRTooltip = firstReportIDWithGBRorRGR === reportID;
+
return (
);
},
@@ -220,6 +245,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
transactionViolations,
onLayoutItem,
isOffline,
+ firstReportIDWithGBRorRGR,
],
);
diff --git a/src/components/LHNOptionsList/OptionRowLHN.tsx b/src/components/LHNOptionsList/OptionRowLHN.tsx
index a4e0164e388b..90d1e6544997 100644
--- a/src/components/LHNOptionsList/OptionRowLHN.tsx
+++ b/src/components/LHNOptionsList/OptionRowLHN.tsx
@@ -12,6 +12,7 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback';
import {useSession} from '@components/OnyxProvider';
import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
import {useProductTrainingContext} from '@components/ProductTrainingContext';
+import type {ProductTrainingTooltipName} from '@components/ProductTrainingContext/TOOLTIPS';
import SubscriptAvatar from '@components/SubscriptAvatar';
import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
@@ -49,7 +50,17 @@ import ONYXKEYS from '@src/ONYXKEYS';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type {OptionRowLHNProps} from './types';
-function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, optionItem, viewMode = 'default', style, onLayout = () => {}, hasDraftComment}: OptionRowLHNProps) {
+function OptionRowLHN({
+ reportID,
+ isFocused = false,
+ onSelectRow = () => {},
+ optionItem,
+ viewMode = 'default',
+ style,
+ onLayout = () => {},
+ hasDraftComment,
+ shouldShowRBRorGPRTooltip,
+}: OptionRowLHNProps) {
const theme = useTheme();
const styles = useThemeStyles();
const popoverAnchor = useRef(null);
@@ -70,13 +81,22 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti
const isReportsSplitNavigatorLast = useRootNavigationState((state) => state?.routes?.at(-1)?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR);
const {tooltipToRender, shouldShowTooltip} = useMemo(() => {
- const tooltip = shouldShowGetStartedTooltip ? CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.CONCEIRGE_LHN_GBR : CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.LHN_WORKSPACE_CHAT_TOOLTIP;
- const shouldShowTooltips = shouldShowWokspaceChatTooltip || shouldShowGetStartedTooltip;
+ let tooltip: ProductTrainingTooltipName;
+ // TODO: CONCEIRGE_LHN_GBR tooltip will be replaced by a tooltip in the #admins room
+ // https://github.com/Expensify/App/issues/57045#issuecomment-2701455668
+ tooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.CONCEIRGE_LHN_GBR;
+ if (shouldShowWokspaceChatTooltip) {
+ tooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.LHN_WORKSPACE_CHAT_TOOLTIP;
+ }
+ if (shouldShowRBRorGPRTooltip) {
+ tooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GBR_RBR_CHAT;
+ }
+ const shouldShowTooltips = shouldShowRBRorGPRTooltip || shouldShowWokspaceChatTooltip || shouldShowGetStartedTooltip;
const shouldTooltipBeVisible = shouldUseNarrowLayout ? isScreenFocused && isReportsSplitNavigatorLast : isReportsSplitNavigatorLast && !isFullscreenVisible;
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
return {tooltipToRender: tooltip, shouldShowTooltip: shouldShowTooltips && shouldTooltipBeVisible};
- }, [shouldShowGetStartedTooltip, shouldShowWokspaceChatTooltip, isScreenFocused, shouldUseNarrowLayout, isReportsSplitNavigatorLast, isFullscreenVisible]);
+ }, [shouldShowRBRorGPRTooltip, shouldShowGetStartedTooltip, shouldShowWokspaceChatTooltip, isScreenFocused, shouldUseNarrowLayout, isReportsSplitNavigatorLast, isFullscreenVisible]);
const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(tooltipToRender, shouldShowTooltip);
@@ -194,8 +214,8 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti
horizontal: shouldShowWokspaceChatTooltip ? CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT : CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
}}
- shiftHorizontal={shouldShowWokspaceChatTooltip ? variables.workspaceLHNtooltipShiftHorizontal : variables.gbrTooltipShiftHorizontal}
- shiftVertical={shouldShowWokspaceChatTooltip ? 0 : variables.composerTooltipShiftVertical}
+ shiftHorizontal={shouldShowWokspaceChatTooltip ? variables.workspaceLHNTooltipShiftHorizontal : variables.gbrTooltipShiftHorizontal}
+ shiftVertical={shouldShowWokspaceChatTooltip ? 0 : variables.gbrTooltipShiftVertical}
wrapperStyle={styles.productTrainingTooltipWrapper}
onTooltipPress={onOptionPress}
shouldHideOnScroll
diff --git a/src/components/LHNOptionsList/types.ts b/src/components/LHNOptionsList/types.ts
index 597523dd522a..e631b537e134 100644
--- a/src/components/LHNOptionsList/types.ts
+++ b/src/components/LHNOptionsList/types.ts
@@ -102,6 +102,9 @@ type OptionRowLHNDataProps = {
/** Callback to execute when the OptionList lays out */
onLayout?: (event: LayoutChangeEvent) => void;
+
+ /** Whether to show the educational tooltip for the GBR or RBR */
+ shouldShowRBRorGPRTooltip: boolean;
};
type OptionRowLHNProps = {
@@ -127,6 +130,9 @@ type OptionRowLHNProps = {
hasDraftComment: boolean;
onLayout?: (event: LayoutChangeEvent) => void;
+
+ /** Whether to show the educational tooltip on the GBR or RBR */
+ shouldShowRBRorGPRTooltip: boolean;
};
type RenderItemProps = {item: string};
diff --git a/src/components/ProductTrainingContext/TOOLTIPS.ts b/src/components/ProductTrainingContext/TOOLTIPS.ts
index 90e91166fba7..fbf0761dc1e6 100644
--- a/src/components/ProductTrainingContext/TOOLTIPS.ts
+++ b/src/components/ProductTrainingContext/TOOLTIPS.ts
@@ -6,15 +6,15 @@ import type {TranslationPaths} from '@src/languages/types';
const {
CONCEIRGE_LHN_GBR,
RENAME_SAVED_SEARCH,
- WORKSAPCE_CHAT_CREATE,
- QUICK_ACTION_BUTTON,
- SEARCH_FILTER_BUTTON_TOOLTIP,
BOTTOM_NAV_INBOX_TOOLTIP,
LHN_WORKSPACE_CHAT_TOOLTIP,
GLOBAL_CREATE_TOOLTIP,
SCAN_TEST_TOOLTIP,
SCAN_TEST_TOOLTIP_MANAGER,
SCAN_TEST_CONFIRMATION,
+ EXPENSE_REPORTS_FILTER,
+ GBR_RBR_CHAT,
+ ACCOUNT_SWITCHER,
} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;
type ProductTrainingTooltipName = ValueOf;
@@ -41,7 +41,9 @@ const TOOLTIPS: Record = {
onHideTooltip: () => dismissProductTraining(CONCEIRGE_LHN_GBR),
name: CONCEIRGE_LHN_GBR,
priority: 1300,
- shouldShow: ({shouldUseNarrowLayout}) => !!shouldUseNarrowLayout,
+ // TODO: CONCEIRGE_LHN_GBR tooltip will be replaced by a tooltip in the #admins room
+ // https://github.com/Expensify/App/issues/57045#issuecomment-2701455668
+ shouldShow: () => false,
},
[RENAME_SAVED_SEARCH]: {
content: [
@@ -61,60 +63,63 @@ const TOOLTIPS: Record = {
],
onHideTooltip: () => dismissProductTraining(GLOBAL_CREATE_TOOLTIP),
name: GLOBAL_CREATE_TOOLTIP,
- priority: 1200,
+ priority: 1950,
shouldShow: () => true,
},
- [QUICK_ACTION_BUTTON]: {
+ [BOTTOM_NAV_INBOX_TOOLTIP]: {
content: [
- {text: 'productTrainingTooltip.quickActionButton.part1', isBold: true},
- {text: 'productTrainingTooltip.quickActionButton.part2', isBold: false},
+ {text: 'productTrainingTooltip.bottomNavInboxTooltip.part1', isBold: false},
+ {text: 'productTrainingTooltip.bottomNavInboxTooltip.part2', isBold: true},
+ {text: 'productTrainingTooltip.bottomNavInboxTooltip.part3', isBold: false},
+ {text: 'productTrainingTooltip.bottomNavInboxTooltip.part4', isBold: true},
],
- onHideTooltip: () => dismissProductTraining(QUICK_ACTION_BUTTON),
- name: QUICK_ACTION_BUTTON,
- priority: 1150,
+ onHideTooltip: () => dismissProductTraining(BOTTOM_NAV_INBOX_TOOLTIP),
+ name: BOTTOM_NAV_INBOX_TOOLTIP,
+ priority: 1700,
shouldShow: () => true,
},
- [WORKSAPCE_CHAT_CREATE]: {
+ [LHN_WORKSPACE_CHAT_TOOLTIP]: {
content: [
- {text: 'productTrainingTooltip.workspaceChatCreate.part1', isBold: false},
- {text: 'productTrainingTooltip.workspaceChatCreate.part2', isBold: true},
- {text: 'productTrainingTooltip.workspaceChatCreate.part3', isBold: false},
+ {text: 'productTrainingTooltip.workspaceChatTooltip.part1', isBold: false},
+ {text: 'productTrainingTooltip.workspaceChatTooltip.part2', isBold: true},
],
- onHideTooltip: () => dismissProductTraining(WORKSAPCE_CHAT_CREATE),
- name: WORKSAPCE_CHAT_CREATE,
- priority: 1100,
+ onHideTooltip: () => dismissProductTraining(LHN_WORKSPACE_CHAT_TOOLTIP),
+ name: LHN_WORKSPACE_CHAT_TOOLTIP,
+ priority: 1800,
shouldShow: () => true,
},
- [SEARCH_FILTER_BUTTON_TOOLTIP]: {
+ [EXPENSE_REPORTS_FILTER]: {
content: [
- {text: 'productTrainingTooltip.searchFilterButtonTooltip.part1', isBold: true},
- {text: 'productTrainingTooltip.searchFilterButtonTooltip.part2', isBold: false},
+ {text: 'productTrainingTooltip.expenseReportsFilter.part1', isBold: false},
+ {text: 'productTrainingTooltip.expenseReportsFilter.part2', isBold: true},
+ {text: 'productTrainingTooltip.expenseReportsFilter.part3', isBold: false},
],
- onHideTooltip: () => dismissProductTraining(SEARCH_FILTER_BUTTON_TOOLTIP),
- name: SEARCH_FILTER_BUTTON_TOOLTIP,
- priority: 1000,
- shouldShow: () => true,
+ onHideTooltip: () => dismissProductTraining(EXPENSE_REPORTS_FILTER),
+ name: EXPENSE_REPORTS_FILTER,
+ priority: 2000,
+ shouldShow: ({shouldUseNarrowLayout}) => !shouldUseNarrowLayout,
},
- [BOTTOM_NAV_INBOX_TOOLTIP]: {
+ [GBR_RBR_CHAT]: {
content: [
- {text: 'productTrainingTooltip.bottomNavInboxTooltip.part1', isBold: true},
- {text: 'productTrainingTooltip.bottomNavInboxTooltip.part2', isBold: false},
- {text: 'productTrainingTooltip.bottomNavInboxTooltip.part3', isBold: false},
+ {text: 'productTrainingTooltip.GBRRBRChat.part1', isBold: false},
+ {text: 'productTrainingTooltip.GBRRBRChat.part2', isBold: true},
+ {text: 'productTrainingTooltip.GBRRBRChat.part3', isBold: false},
+ {text: 'productTrainingTooltip.GBRRBRChat.part4', isBold: true},
],
- onHideTooltip: () => dismissProductTraining(BOTTOM_NAV_INBOX_TOOLTIP),
- name: BOTTOM_NAV_INBOX_TOOLTIP,
- priority: 900,
+ onHideTooltip: () => dismissProductTraining(GBR_RBR_CHAT),
+ name: GBR_RBR_CHAT,
+ priority: 1900,
shouldShow: () => true,
},
- [LHN_WORKSPACE_CHAT_TOOLTIP]: {
+ [ACCOUNT_SWITCHER]: {
content: [
- {text: 'productTrainingTooltip.workspaceChatTooltip.part1', isBold: true},
- {text: 'productTrainingTooltip.workspaceChatTooltip.part2', isBold: false},
- {text: 'productTrainingTooltip.workspaceChatTooltip.part3', isBold: false},
+ {text: 'productTrainingTooltip.accountSwitcher.part1', isBold: false},
+ {text: 'productTrainingTooltip.accountSwitcher.part2', isBold: true},
+ {text: 'productTrainingTooltip.accountSwitcher.part3', isBold: false},
],
- onHideTooltip: () => dismissProductTraining(LHN_WORKSPACE_CHAT_TOOLTIP),
- name: LHN_WORKSPACE_CHAT_TOOLTIP,
- priority: 800,
+ onHideTooltip: () => dismissProductTraining(ACCOUNT_SWITCHER),
+ name: ACCOUNT_SWITCHER,
+ priority: 1600,
shouldShow: () => true,
},
[SCAN_TEST_TOOLTIP]: {
diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx
index ca365949a005..449a54abe1f6 100644
--- a/src/components/ProductTrainingContext/index.tsx
+++ b/src/components/ProductTrainingContext/index.tsx
@@ -101,9 +101,8 @@ function ProductTrainingContextProvider({children}: ChildrenProps) {
return false;
}
- // We need to make an exception for the QAB tooltip because it is shown in a modal, otherwise it would be hidden if a modal is visible
+ // We need to make an exception for these tooltips because it is shown in a modal, otherwise it would be hidden if a modal is visible
if (
- tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.QUICK_ACTION_BUTTON &&
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP &&
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP_MANAGER &&
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_CONFIRMATION &&
diff --git a/src/components/Search/SearchPageHeader/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader/SearchPageHeader.tsx
index fba02f066e7f..3e3c3f9d4259 100644
--- a/src/components/Search/SearchPageHeader/SearchPageHeader.tsx
+++ b/src/components/Search/SearchPageHeader/SearchPageHeader.tsx
@@ -1,15 +1,12 @@
-import {useFocusEffect} from '@react-navigation/native';
-import React, {useCallback, useMemo, useState} from 'react';
+import React, {useCallback, useMemo} from 'react';
import {View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import Button from '@components/Button';
import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types';
import * as Expensicons from '@components/Icon/Expensicons';
import {usePersonalDetails} from '@components/OnyxProvider';
-import {useProductTrainingContext} from '@components/ProductTrainingContext';
import {useSearchContext} from '@components/Search/SearchContext';
import type {SearchQueryJSON} from '@components/Search/types';
-import EducationalTooltip from '@components/Tooltip/EducationalTooltip';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import {updateAdvancedFilters} from '@libs/actions/Search';
@@ -18,7 +15,6 @@ import Navigation from '@libs/Navigation/Navigation';
import {getAllTaxRates} from '@libs/PolicyUtils';
import {buildFilterFormValuesFromQuery} from '@libs/SearchQueryUtils';
import SearchSelectedNarrow from '@pages/Search/SearchSelectedNarrow';
-import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
@@ -50,62 +46,25 @@ function SearchPageHeader({queryJSON, searchName, searchRouterListVisible, hideS
const [currencyList = {}] = useOnyx(ONYXKEYS.CURRENCY_LIST);
const [policyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES);
const [policyTagsLists] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS);
- const [isScreenFocused, setIsScreenFocused] = useState(false);
-
- const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
- CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SEARCH_FILTER_BUTTON_TOOLTIP,
- isScreenFocused,
- );
-
- useFocusEffect(
- useCallback(() => {
- setIsScreenFocused(true);
- return () => {
- setIsScreenFocused(false);
- };
- }, []),
- );
const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {});
const onFiltersButtonPress = useCallback(() => {
- hideProductTrainingTooltip();
const filterFormValues = buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList, personalDetails, allCards, reports, taxRates);
updateAdvancedFilters(filterFormValues);
Navigation.navigate(ROUTES.SEARCH_ADVANCED_FILTERS);
- }, [allCards, currencyList, hideProductTrainingTooltip, personalDetails, policyCategories, policyTagsLists, queryJSON, reports, taxRates]);
+ }, [allCards, currencyList, personalDetails, policyCategories, policyTagsLists, queryJSON, reports, taxRates]);
const InputRightComponent = useMemo(() => {
return (
-
-
-
+
);
- }, [
- onFiltersButtonPress,
- renderProductTrainingTooltip,
- shouldShowProductTrainingTooltip,
- styles.bgTransparent,
- styles.borderNone,
- styles.productTrainingTooltipWrapper,
- styles.searchAutocompleteInputResults,
- ]);
+ }, [onFiltersButtonPress, styles.bgTransparent, styles.borderNone, styles.searchAutocompleteInputResults]);
if (shouldUseNarrowLayout && selectionMode?.isEnabled) {
return (
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 5f44cde8afb5..5604ee807870 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -5942,6 +5942,8 @@ const translations = {
},
},
productTrainingTooltip: {
+ // TODO: CONCEIRGE_LHN_GBR tooltip will be replaced by a tooltip in the #admins room
+ // https://github.com/Expensify/App/issues/57045#issuecomment-2701455668
conciergeLHNGBR: {
part1: 'Get started',
part2: ' here!',
@@ -5950,33 +5952,37 @@ const translations = {
part1: 'Rename your saved searches',
part2: ' here!',
},
- quickActionButton: {
- part1: 'Quick action!',
- part2: ' Just a tap away',
- },
- workspaceChatCreate: {
- part1: 'Submit your',
- part2: ' expenses',
- part3: ' here!',
- },
- searchFilterButtonTooltip: {
- part1: 'Customize your search',
- part2: ' here!',
- },
bottomNavInboxTooltip: {
- part1: 'Your to-do list',
- part2: '\n🟢 = ready for you',
- part3: ' 🔴 = needs review',
+ part1: 'Check what ',
+ part2: 'needs your attention',
+ part3: '\nand ',
+ 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!',
+ },
+ GBRRBRChat: {
+ part1: 'You’ll see 🟢 on ',
+ part2: 'actions to take',
+ part3: ',\nand 🔴 on ',
+ part4: 'errors to review.',
+ },
+ expenseReportsFilter: {
+ part1: 'Welcome!\nFind all of your ',
+ part2: "company's reports",
+ part3: ' here.',
+ },
+ accountSwitcher: {
+ part1: 'Access your ',
+ part2: 'Copilot accounts',
+ part3: ' here',
},
scanTestTooltip: {
part1: 'Want to see how Scan works?',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 33b62a5eb8d4..4eab09a58c64 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -6464,6 +6464,8 @@ const translations = {
},
},
productTrainingTooltip: {
+ // TODO: CONCEIRGE_LHN_GBR tooltip will be replaced by a tooltip in the #admins room
+ // https://github.com/Expensify/App/issues/57045#issuecomment-2701455668
conciergeLHNGBR: {
part1: '¡Comienza',
part2: ' aquÃ!',
@@ -6472,33 +6474,37 @@ const translations = {
part1: 'Renombra tus búsquedas guardadas',
part2: ' aquÃ',
},
- quickActionButton: {
- part1: '¡Acción rápida!',
- part2: ' A solo un toque',
- },
- workspaceChatCreate: {
- part1: 'EnvÃa tus',
- part2: ' gastos',
- part3: ' aquÃ',
- },
- searchFilterButtonTooltip: {
- part1: 'Personaliza tu búsqueda',
- part2: ' aquÃ!',
- },
bottomNavInboxTooltip: {
- part1: 'Tu lista de tareas',
- part2: '\n🟢 = listo para ti',
- part3: ' 🔴 = necesita revisión',
+ part1: 'Consulta lo que ',
+ part2: 'requiere tu atención',
+ part3: '\ny ',
+ part4: 'chatea sobre gastos.',
},
workspaceChatTooltip: {
- part1: 'EnvÃa gastos',
- part2: ' y chatea con',
- part3: '\naprobadores aquÃ!',
+ part1: 'Chatea con ',
+ part2: 'aprobadores',
},
globalCreateTooltip: {
part1: 'Crea gastos',
part2: ', comienza a chatear,',
part3: '\ny mucho más!',
+ part4: ' ¡Pruébalo!',
+ },
+ expenseReportsFilter: {
+ part1: '¡Bienvenido!\nEncuentra todos los ',
+ part2: 'informes de tu empresa',
+ part3: ' aquÃ.',
+ },
+ GBRRBRChat: {
+ part1: 'Verás 🟢 en ',
+ part2: 'acciones a realizar',
+ part3: ',\ny 🔴 en ',
+ part4: 'errores para revisar.',
+ },
+ accountSwitcher: {
+ part1: 'Accede a tus ',
+ part2: 'cuentas Copilot',
+ part3: ' aquÃ',
},
scanTestTooltip: {
part1: '¿Quieres ver cómo funciona Escanear?',
diff --git a/src/pages/Search/SearchTypeMenu.tsx b/src/pages/Search/SearchTypeMenu.tsx
index 0f85d2984a36..07bb0e385672 100644
--- a/src/pages/Search/SearchTypeMenu.tsx
+++ b/src/pages/Search/SearchTypeMenu.tsx
@@ -52,6 +52,11 @@ function SearchTypeMenu({queryJSON}: SearchTypeMenuProps) {
CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.RENAME_SAVED_SEARCH,
shouldShowSavedSearchesMenuItemTitle && isFocused,
);
+ const {
+ shouldShowProductTrainingTooltip: shouldShowExpenseReportsTypeTooltip,
+ renderProductTrainingTooltip: renderExpenseReportsTypeTooltip,
+ hideProductTrainingTooltip: hideExpenseReportsTypeTooltip,
+ } = useProductTrainingContext(CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.EXPENSE_REPORTS_FILTER, true);
const {showDeleteModal, DeleteConfirmModal} = useDeleteSavedSearch();
const [session] = useOnyx(ONYXKEYS.SESSION);
const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
@@ -88,9 +93,9 @@ function SearchTypeMenu({queryJSON}: SearchTypeMenuProps) {
),
style: [styles.alignItemsCenter],
@@ -101,23 +106,23 @@ function SearchTypeMenu({queryJSON}: SearchTypeMenuProps) {
tooltipShiftHorizontal: variables.savedSearchShiftHorizontal,
tooltipShiftVertical: variables.savedSearchShiftVertical,
tooltipWrapperStyle: [styles.mh4, styles.pv2, styles.productTrainingTooltipWrapper],
- renderTooltipContent: renderProductTrainingTooltip,
+ renderTooltipContent: renderSavedSearchTooltip,
};
},
[
allCards,
hash,
getOverflowMenu,
+ shouldShowSavedSearchTooltip,
+ hideSavedSearchTooltip,
styles.alignItemsCenter,
styles.mh4,
styles.pv2,
styles.productTrainingTooltipWrapper,
+ renderSavedSearchTooltip,
personalDetails,
reports,
taxRates,
- shouldShowProductTrainingTooltip,
- hideProductTrainingTooltip,
- renderProductTrainingTooltip,
cardFeedNamesWithType,
],
);
@@ -186,7 +191,12 @@ function SearchTypeMenu({queryJSON}: SearchTypeMenuProps) {
>
{typeMenuItems.map((item, index) => {
+ const shouldShowTooltip = item.translationPath === 'common.expenseReports' && index !== activeItemIndex && shouldShowExpenseReportsTypeTooltip;
+
const onPress = singleExecution(() => {
+ if (shouldShowTooltip) {
+ hideExpenseReportsTypeTooltip();
+ }
clearAllFilters();
clearSelectedTransactions();
Navigation.navigate(item.getRoute(queryJSON.policyID));
@@ -205,6 +215,15 @@ function SearchTypeMenu({queryJSON}: SearchTypeMenuProps) {
focused={index === activeItemIndex}
onPress={onPress}
shouldIconUseAutoWidthStyle
+ shouldRenderTooltip={shouldShowTooltip}
+ renderTooltipContent={renderExpenseReportsTypeTooltip}
+ tooltipAnchorAlignment={{
+ horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
+ vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
+ }}
+ tooltipShiftHorizontal={variables.expenseReportsTypeTooltipShiftHorizontal}
+ tooltipWrapperStyle={styles.productTrainingTooltipWrapper}
+ onEducationTooltipPress={onPress}
/>
);
})}
diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx
index d89a20eea497..91ae01fa7551 100644
--- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx
+++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx
@@ -1,9 +1,8 @@
-import {useFocusEffect} from '@react-navigation/native';
import lodashDebounce from 'lodash/debounce';
import noop from 'lodash/noop';
import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react';
import type {MeasureInWindowOnSuccessCallback, NativeSyntheticEvent, TextInputFocusEventData, TextInputSelectionChangeEventData} from 'react-native';
-import {InteractionManager, View} from 'react-native';
+import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import {runOnUI, useSharedValue} from 'react-native-reanimated';
@@ -17,8 +16,6 @@ import type {Mention} from '@components/MentionSuggestions';
import OfflineIndicator from '@components/OfflineIndicator';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import {usePersonalDetails} from '@components/OnyxProvider';
-import {useProductTrainingContext} from '@components/ProductTrainingContext';
-import EducationalTooltip from '@components/Tooltip/EducationalTooltip';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useDebounce from '@hooks/useDebounce';
import useHandleExceedMaxCommentLength from '@hooks/useHandleExceedMaxCommentLength';
@@ -27,7 +24,6 @@ import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
-import useViewportOffsetTop from '@hooks/useViewportOffsetTop';
import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
import {canUseTouchScreen} from '@libs/DeviceCapabilities';
import DomUtils from '@libs/DomUtils';
@@ -40,7 +36,6 @@ import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutsi
import ParticipantLocalTime from '@pages/home/report/ParticipantLocalTime';
import ReportDropUI from '@pages/home/report/ReportDropUI';
import ReportTypingIndicator from '@pages/home/report/ReportTypingIndicator';
-import variables from '@styles/variables';
import {hideEmojiPicker, isActive as isActiveEmojiPickerAction} from '@userActions/EmojiPickerAction';
import {addAttachment as addAttachmentReportActions, setIsComposerFullSize} from '@userActions/Report';
import Timing from '@userActions/Timing';
@@ -87,9 +82,6 @@ type ReportActionComposeProps = Pick(null);
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const personalDetails = usePersonalDetails();
const [blockedFromConcierge] = useOnyx(ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE);
const [shouldShowComposeInput = true] = useOnyx(ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT);
- const [isScreenTransitionEnded, setIsScreenTransitionEnded] = useState(false);
-
- useFocusEffect(
- React.useCallback(() => {
- const task = InteractionManager.runAfterInteractions(() => {
- setIsScreenTransitionEnded(true);
- });
-
- return () => {
- task.cancel();
- setIsScreenTransitionEnded(false);
- };
- }, []),
- );
-
- const {renderProductTrainingTooltip, hideProductTrainingTooltip, shouldShowProductTrainingTooltip} = useProductTrainingContext(
- CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.WORKSAPCE_CHAT_CREATE,
- shouldShowEducationalTooltip && isScreenTransitionEnded,
- );
/**
* Updates the Highlight state of the composer
@@ -247,12 +218,11 @@ function ReportActionCompose({
);
const onAddActionPressed = useCallback(() => {
- hideProductTrainingTooltip();
if (!willBlurTextInputOnTapOutside) {
isKeyboardVisibleWhenShowingModalRef.current = !!composerRef.current?.isFocused();
}
composerRef.current?.blur();
- }, [hideProductTrainingTooltip]);
+ }, []);
const onItemSelected = useCallback(() => {
isKeyboardVisibleWhenShowingModalRef.current = false;
@@ -432,136 +402,120 @@ function ReportActionCompose({
style={isComposerFullSize ? styles.chatItemFullComposeRow : {}}
contentContainerStyle={isComposerFullSize ? styles.flex1 : {}}
>
- {
- setMenuVisibility(true);
- onAddActionPressed();
- }}
+
- setIsAttachmentPreviewActive(true)}
+ onModalHide={onAttachmentPreviewClose}
+ shouldDisableSendButton={!!exceededMaxLength}
>
- setIsAttachmentPreviewActive(true)}
- onModalHide={onAttachmentPreviewClose}
- shouldDisableSendButton={!!exceededMaxLength}
- >
- {({displayFileInModal}) => (
- <>
- {
- if (!shouldFocusInputOnScreenFocus) {
- return;
- }
- focus();
- }}
- actionButtonRef={actionButtonRef}
- shouldDisableAttachmentItem={!!exceededMaxLength}
- />
- {
- composerRef.current = ref ?? undefined;
- composerRefShared.set({
- clear: ref?.clear,
- });
- }}
- suggestionsRef={suggestionsRef}
- isNextModalWillOpenRef={isNextModalWillOpenRef}
- isScrollLikelyLayoutTriggered={isScrollLikelyLayoutTriggered}
- raiseIsScrollLikelyLayoutTriggered={raiseIsScrollLikelyLayoutTriggered}
- reportID={reportID}
- policyID={report?.policyID}
- includeChronos={chatIncludesChronos(report)}
- isGroupPolicyReport={isGroupPolicyReport}
- lastReportAction={lastReportAction}
- isMenuVisible={isMenuVisible}
- inputPlaceholder={inputPlaceholder}
- isComposerFullSize={isComposerFullSize}
- setIsFullComposerAvailable={setIsFullComposerAvailable}
- displayFileInModal={displayFileInModal}
- onCleared={submitForm}
- isBlockedFromConcierge={isBlockedFromConcierge}
- disabled={disabled}
- setIsCommentEmpty={setIsCommentEmpty}
- handleSendMessage={handleSendMessage}
- shouldShowComposeInput={shouldShowComposeInput}
- onFocus={onFocus}
- onBlur={onBlur}
- measureParentContainer={measureContainer}
- onValueChange={onValueChange}
- didHideComposerInput={didHideComposerInput}
- />
- {
- if (isAttachmentPreviewActive) {
- return;
- }
- const data = event.dataTransfer?.files[0];
- if (data) {
- data.uri = URL.createObjectURL(data);
- displayFileInModal(data);
- }
- }}
- />
- >
- )}
-
- {canUseTouchScreen() && isMediumScreenWidth ? null : (
- {
- if (isNavigating) {
- return;
- }
- const activeElementId = DomUtils.getActiveElement()?.id;
- if (activeElementId === CONST.COMPOSER.NATIVE_ID || activeElementId === CONST.EMOJI_PICKER_BUTTON_NATIVE_ID) {
- return;
- }
- focus();
- }}
- onEmojiSelected={(...args) => composerRef.current?.replaceSelectionWithText(...args)}
- emojiPickerID={report?.reportID}
- shiftVertical={emojiShiftVertical}
- />
+ {({displayFileInModal}) => (
+ <>
+ {
+ if (!shouldFocusInputOnScreenFocus) {
+ return;
+ }
+ focus();
+ }}
+ actionButtonRef={actionButtonRef}
+ shouldDisableAttachmentItem={!!exceededMaxLength}
+ />
+ {
+ composerRef.current = ref ?? undefined;
+ composerRefShared.set({
+ clear: ref?.clear,
+ });
+ }}
+ suggestionsRef={suggestionsRef}
+ isNextModalWillOpenRef={isNextModalWillOpenRef}
+ isScrollLikelyLayoutTriggered={isScrollLikelyLayoutTriggered}
+ raiseIsScrollLikelyLayoutTriggered={raiseIsScrollLikelyLayoutTriggered}
+ reportID={reportID}
+ policyID={report?.policyID}
+ includeChronos={chatIncludesChronos(report)}
+ isGroupPolicyReport={isGroupPolicyReport}
+ lastReportAction={lastReportAction}
+ isMenuVisible={isMenuVisible}
+ inputPlaceholder={inputPlaceholder}
+ isComposerFullSize={isComposerFullSize}
+ setIsFullComposerAvailable={setIsFullComposerAvailable}
+ displayFileInModal={displayFileInModal}
+ onCleared={submitForm}
+ isBlockedFromConcierge={isBlockedFromConcierge}
+ disabled={disabled}
+ setIsCommentEmpty={setIsCommentEmpty}
+ handleSendMessage={handleSendMessage}
+ shouldShowComposeInput={shouldShowComposeInput}
+ onFocus={onFocus}
+ onBlur={onBlur}
+ measureParentContainer={measureContainer}
+ onValueChange={onValueChange}
+ didHideComposerInput={didHideComposerInput}
+ />
+ {
+ if (isAttachmentPreviewActive) {
+ return;
+ }
+ const data = event.dataTransfer?.files[0];
+ if (data) {
+ data.uri = URL.createObjectURL(data);
+ displayFileInModal(data);
+ }
+ }}
+ />
+ >
)}
-
+ {canUseTouchScreen() && isMediumScreenWidth ? null : (
+ {
+ if (isNavigating) {
+ return;
+ }
+ const activeElementId = DomUtils.getActiveElement()?.id;
+ if (activeElementId === CONST.COMPOSER.NATIVE_ID || activeElementId === CONST.EMOJI_PICKER_BUTTON_NATIVE_ID) {
+ return;
+ }
+ focus();
+ }}
+ onEmojiSelected={(...args) => composerRef.current?.replaceSelectionWithText(...args)}
+ emojiPickerID={report?.reportID}
+ shiftVertical={emojiShiftVertical}
/>
-
-
+ )}
+
+
session?.authTokenType === CONST.AUTH_TOKEN_TYPES.ANONYMOUS});
@@ -120,8 +117,6 @@ function ReportFooter({
const isAdminsOnlyPostingRoom = isAdminsOnlyPostingRoomUtil(report);
const isUserPolicyAdmin = isPolicyAdmin(policy);
- const shouldShowEducationalTooltip = isPolicyExpenseChat(report) && !!report.isOwnPolicyExpenseChat;
-
const allPersonalDetails = usePersonalDetails();
const handleCreateTask = useCallback(
@@ -228,7 +223,6 @@ function ReportFooter({
pendingAction={pendingAction}
isComposerFullSize={isComposerFullSize}
isReportReadyForDisplay={isReportReadyForDisplay}
- shouldShowEducationalTooltip={didScreenTransitionEnd && shouldShowEducationalTooltip}
didHideComposerInput={didHideComposerInput}
/>
diff --git a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx
index b574bdd07688..c50457a19614 100644
--- a/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx
+++ b/src/pages/home/sidebar/FloatingActionButtonAndPopover.tsx
@@ -13,7 +13,6 @@ import FloatingActionButton from '@components/FloatingActionButton';
import * as Expensicons from '@components/Icon/Expensicons';
import type {PopoverMenuItem} from '@components/PopoverMenu';
import PopoverMenu from '@components/PopoverMenu';
-import {useProductTrainingContext} from '@components/ProductTrainingContext';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
@@ -213,11 +212,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT
const {setRootStatusBarEnabled} = useContext(CustomStatusBarAndBackgroundContext);
- const {renderProductTrainingTooltip, hideProductTrainingTooltip, shouldShowProductTrainingTooltip} = useProductTrainingContext(
- CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.QUICK_ACTION_BUTTON,
- isCreateMenuActive && (!shouldUseNarrowLayout || isFocused),
- );
-
const groupPoliciesWithChatEnabled = useMemo(() => getGroupPaidPoliciesWithExpenseChatEnabled(allPolicies as OnyxCollection), [allPolicies]);
/**
@@ -381,11 +375,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
},
- tooltipShiftHorizontal: variables.quickActionTooltipShiftHorizontal,
- tooltipShiftVertical: styles.popoverMenuItem.paddingVertical / 2,
- renderTooltipContent: renderProductTrainingTooltip,
- tooltipWrapperStyle: styles.productTrainingTooltipWrapper,
- shouldRenderTooltip: shouldShowProductTrainingTooltip,
shouldTeleportPortalToModalLayer: true,
};
@@ -399,7 +388,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT
}
const onSelected = () => {
interceptAnonymousUser(() => {
- hideProductTrainingTooltip();
navigateToQuickAction(isValidReport, `${quickActionReport?.reportID ?? CONST.DEFAULT_NUMBER_ID}`, quickAction, selectOption);
});
};
@@ -410,10 +398,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT
text: quickActionTitle,
description: !hideQABSubtitle ? getReportName(quickActionReport) ?? translate('quickAction.updateDestination') : '',
onSelected,
- onEducationTooltipPress: () => {
- hideCreateMenu();
- onSelected();
- },
shouldShowSubscriptRightAvatar: isPolicyExpenseChat(quickActionReport),
},
];
@@ -421,7 +405,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT
if (!isEmptyObject(policyChatForActivePolicy)) {
const onSelected = () => {
interceptAnonymousUser(() => {
- hideProductTrainingTooltip();
if (policyChatForActivePolicy?.policyID && shouldRestrictUserBillableActions(policyChatForActivePolicy.policyID)) {
Navigation.navigate(ROUTES.RESTRICTED_ACTION.getRoute(policyChatForActivePolicy.policyID));
return;
@@ -439,10 +422,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT
text: translate('quickAction.scanReceipt'),
description: getReportName(policyChatForActivePolicy),
onSelected,
- onEducationTooltipPress: () => {
- hideCreateMenu();
- onSelected();
- },
shouldShowSubscriptRightAvatar: true,
},
];
@@ -453,21 +432,15 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, isT
translate,
styles.pt3,
styles.pb2,
- styles.popoverMenuItem.paddingVertical,
- styles.productTrainingTooltipWrapper,
quickActionAvatars,
- renderProductTrainingTooltip,
- shouldShowProductTrainingTooltip,
quickAction,
policyChatForActivePolicy,
quickActionReport,
quickActionPolicy,
quickActionTitle,
hideQABSubtitle,
- hideProductTrainingTooltip,
isValidReport,
selectOption,
- hideCreateMenu,
]);
const viewTourTaskReportID = introSelected?.viewTour;
diff --git a/src/styles/variables.ts b/src/styles/variables.ts
index 2b39f2320b91..3b79c1a0a590 100644
--- a/src/styles/variables.ts
+++ b/src/styles/variables.ts
@@ -263,18 +263,16 @@ export default {
searchTypeColumnWidth: 52,
- composerTooltipShiftHorizontal: 4,
- composerTooltipShiftVertical: -10,
gbrTooltipShiftHorizontal: -15,
+ gbrTooltipShiftVertical: -10,
fabTooltipShiftHorizontal: -11,
- workspaceLHNtooltipShiftHorizontal: 23,
- searchFiltersTooltipShiftHorizontal: -4,
- quickActionTooltipShiftHorizontal: 24,
+ workspaceLHNTooltipShiftHorizontal: 23,
savedSearchShiftHorizontal: -10,
savedSearchShiftVertical: 6,
- searchFiltersTooltipShiftHorizontalNarrow: -10,
- searchFiltersTooltipShiftVerticalNarrow: 5,
bottomTabInboxTooltipShiftHorizontal: 36,
+ expenseReportsTypeTooltipShiftHorizontal: 10,
+ accountSwitcherTooltipShiftVertical: 7,
+ accountSwitcherTooltipShiftHorizontal: 4,
inlineImagePreviewMinSize: 64,
inlineImagePreviewMaxSize: 148,
diff --git a/src/types/onyx/DismissedProductTraining.ts b/src/types/onyx/DismissedProductTraining.ts
index 283c660be2e1..11c30bf85020 100644
--- a/src/types/onyx/DismissedProductTraining.ts
+++ b/src/types/onyx/DismissedProductTraining.ts
@@ -3,15 +3,15 @@ import CONST from '@src/CONST';
const {
CONCEIRGE_LHN_GBR,
RENAME_SAVED_SEARCH,
- WORKSAPCE_CHAT_CREATE,
- QUICK_ACTION_BUTTON,
- SEARCH_FILTER_BUTTON_TOOLTIP,
BOTTOM_NAV_INBOX_TOOLTIP,
LHN_WORKSPACE_CHAT_TOOLTIP,
GLOBAL_CREATE_TOOLTIP,
SCAN_TEST_TOOLTIP,
SCAN_TEST_TOOLTIP_MANAGER,
SCAN_TEST_CONFIRMATION,
+ EXPENSE_REPORTS_FILTER,
+ ACCOUNT_SWITCHER,
+ GBR_RBR_CHAT,
} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;
/**
* This type is used to store the timestamp of when the user dismisses a product training ui elements.
@@ -22,6 +22,8 @@ type DismissedProductTraining = {
*/
[CONST.MIGRATED_USER_WELCOME_MODAL]: string;
+ // TODO: CONCEIRGE_LHN_GBR tooltip will be replaced by a tooltip in the #admins room
+ // https://github.com/Expensify/App/issues/57045#issuecomment-2701455668
/**
* When user dismisses the conciergeLHNGBR product training tooltip, we store the timestamp here.
*/
@@ -32,21 +34,6 @@ type DismissedProductTraining = {
*/
[RENAME_SAVED_SEARCH]: string;
- /**
- * When user dismisses the workspaceChatCreate product training tooltip, we store the timestamp here.
- */
- [WORKSAPCE_CHAT_CREATE]: string;
-
- /**
- * When user dismisses the quickActionButton product training tooltip, we store the timestamp here.
- */
- [QUICK_ACTION_BUTTON]: string;
-
- /**
- * When user dismisses the searchFilterButtonTooltip product training tooltip, we store the timestamp here.
- */
- [SEARCH_FILTER_BUTTON_TOOLTIP]: string;
-
/**
* When user dismisses the bottomNavInboxTooltip product training tooltip, we store the timestamp here.
*/
@@ -77,6 +64,21 @@ type DismissedProductTraining = {
*/
[SCAN_TEST_CONFIRMATION]: string;
+ /**
+ * When user dismisses the expenseReportsFilter product training tooltip, we store the timestamp here.
+ */
+ [EXPENSE_REPORTS_FILTER]: string;
+
+ /**
+ * When user dismisses the accountSwitcher product training tooltip, we store the timestamp here.
+ */
+ [ACCOUNT_SWITCHER]: string;
+
+ /**
+ * When user dismisses the gbrRbrChat product training tooltip, we store the timestamp here.
+ */
+ [GBR_RBR_CHAT]: string;
+
/**
* When user dismisses the ChangeReportPolicy feature training modal, we store the timestamp here.
*/
diff --git a/tests/ui/components/ProductTrainingContextProvider.tsx b/tests/ui/components/ProductTrainingContextProvider.tsx
index 6bc131f80be2..ad9c165fae90 100644
--- a/tests/ui/components/ProductTrainingContextProvider.tsx
+++ b/tests/ui/components/ProductTrainingContextProvider.tsx
@@ -197,10 +197,10 @@ describe('ProductTrainingContextProvider', () => {
Onyx.merge(ONYXKEYS.NVP_ONBOARDING, {hasCompletedGuidedSetupFlow: true});
await waitForBatchedUpdatesWithAct();
- const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.CONCEIRGE_LHN_GBR;
+ const testTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.EXPENSE_REPORTS_FILTER;
const {result, rerender} = renderHook(() => useProductTrainingContext(testTooltip), {wrapper});
// Then narrow layout tooltip should not show
- expect(result.current.shouldShowProductTrainingTooltip).toBe(false);
+ expect(result.current.shouldShowProductTrainingTooltip).toBe(true);
// When narrow layout changes to true
mockUseResponsiveLayout.mockReturnValue({...DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE, shouldUseNarrowLayout: true});
@@ -208,7 +208,7 @@ describe('ProductTrainingContextProvider', () => {
await waitForBatchedUpdatesWithAct();
// Then narrow layout tooltip should show
- expect(result.current.shouldShowProductTrainingTooltip).toBe(true);
+ expect(result.current.shouldShowProductTrainingTooltip).toBe(false);
});
it('should handle wide layout specific tooltips based on screen width', async () => {
// When narrow layout is true
@@ -244,7 +244,7 @@ describe('ProductTrainingContextProvider', () => {
// Then only highest priority tooltip should show
const highPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP;
- const lowPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SEARCH_FILTER_BUTTON_TOOLTIP;
+ const lowPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.LHN_WORKSPACE_CHAT_TOOLTIP;
const {result} = renderHook(
() => ({
@@ -264,7 +264,7 @@ describe('ProductTrainingContextProvider', () => {
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.SEARCH_FILTER_BUTTON_TOOLTIP;
+ const lowPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.LHN_WORKSPACE_CHAT_TOOLTIP;
Onyx.merge(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {
migratedUserWelcomeModal: DateUtils.getDBTime(date.valueOf()),
@@ -296,7 +296,7 @@ describe('ProductTrainingContextProvider', () => {
await waitForBatchedUpdatesWithAct();
const highPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP;
- const lowPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SEARCH_FILTER_BUTTON_TOOLTIP;
+ const lowPriorityTooltip = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.LHN_WORKSPACE_CHAT_TOOLTIP;
const {result} = renderHook(
() => ({