diff --git a/src/App.tsx b/src/App.tsx
index 52904e0a06c4..cc824b78fa4c 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -18,6 +18,7 @@ import KeyboardProvider from './components/KeyboardProvider';
import {LocaleContextProvider} from './components/LocaleContextProvider';
import OnyxProvider from './components/OnyxProvider';
import PopoverContextProvider from './components/PopoverProvider';
+import {ProductTrainingContextProvider} from './components/ProductTrainingContext';
import SafeArea from './components/SafeArea';
import ScrollOffsetContextProvider from './components/ScrollOffsetContextProvider';
import {SearchRouterContextProvider} from './components/Search/SearchRouter/SearchRouterContext';
@@ -95,6 +96,7 @@ function App({url}: AppProps) {
VideoPopoverMenuContextProvider,
KeyboardProvider,
SearchRouterContextProvider,
+ ProductTrainingContextProvider,
]}
>
diff --git a/src/CONST.ts b/src/CONST.ts
index 15554719ca9d..71c17db3fa52 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -6405,6 +6405,13 @@ const CONST = {
},
MIGRATED_USER_WELCOME_MODAL: 'migratedUserWelcomeModal',
+
+ PRODUCT_TRAINING_TOOLTIP_NAMES: {
+ CONCEIRGE_LHN_GBR: 'conciergeLHNGBR',
+ RENAME_SAVED_SEARCH: 'renameSavedSearch',
+ QUICK_ACTION_BUTTON: 'quickActionButton',
+ WORKSAPCE_CHAT_CREATE: 'workspaceChatCreate',
+ },
} as const;
type Country = keyof typeof CONST.ALL_COUNTRIES;
diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index 45d636c0b1df..2e65b5f372b4 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -111,9 +111,6 @@ const ONYXKEYS = {
/** NVP keys */
- /** Boolean flag only true when first set */
- NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER: 'nvp_isFirstTimeNewExpensifyUser',
-
/** This NVP contains list of at most 5 recent attendees */
NVP_RECENT_ATTENDEES: 'nvp_expensify_recentAttendees',
@@ -216,18 +213,9 @@ const ONYXKEYS = {
/** The end date (epoch timestamp) of the workspace owner’s grace period after the free trial ends. */
NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END: 'nvp_private_billingGracePeriodEnd',
- /** The NVP containing all information related to educational tooltip in workspace chat */
- NVP_WORKSPACE_TOOLTIP: 'workspaceTooltip',
-
/** The NVP containing the target url to navigate to when deleting a transaction */
NVP_DELETE_TRANSACTION_NAVIGATE_BACK_URL: 'nvp_deleteTransactionNavigateBackURL',
- /** Whether to show save search rename tooltip */
- SHOULD_SHOW_SAVED_SEARCH_RENAME_TOOLTIP: 'shouldShowSavedSearchRenameTooltip',
-
- /** Whether to hide gbr tooltip */
- NVP_SHOULD_HIDE_GBR_TOOLTIP: 'nvp_should_hide_gbr_tooltip',
-
/** Does this user have push notifications enabled for this device? */
PUSH_NOTIFICATIONS_ENABLED: 'pushNotificationsEnabled',
@@ -876,7 +864,6 @@ type OnyxCollectionValuesMapping = {
type OnyxValuesMapping = {
[ONYXKEYS.ACCOUNT]: OnyxTypes.Account;
[ONYXKEYS.ACCOUNT_MANAGER_REPORT_ID]: string;
- [ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER]: boolean;
// NVP_ONBOARDING is an array for old users.
[ONYXKEYS.NVP_ONBOARDING]: Onboarding | [];
@@ -1017,9 +1004,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.NVP_BILLING_FUND_ID]: number;
[ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED]: number;
[ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END]: number;
- [ONYXKEYS.NVP_WORKSPACE_TOOLTIP]: OnyxTypes.WorkspaceTooltip;
[ONYXKEYS.NVP_DELETE_TRANSACTION_NAVIGATE_BACK_URL]: string | undefined;
- [ONYXKEYS.NVP_SHOULD_HIDE_GBR_TOOLTIP]: boolean;
[ONYXKEYS.NVP_PRIVATE_CANCELLATION_DETAILS]: OnyxTypes.CancellationDetails[];
[ONYXKEYS.ROOM_MEMBERS_USER_SEARCH_PHRASE]: string;
[ONYXKEYS.APPROVAL_WORKFLOW]: OnyxTypes.ApprovalWorkflowOnyx;
@@ -1027,7 +1012,6 @@ type OnyxValuesMapping = {
[ONYXKEYS.LAST_ROUTE]: string;
[ONYXKEYS.IS_SINGLE_NEW_DOT_ENTRY]: boolean | undefined;
[ONYXKEYS.IS_USING_IMPORTED_STATE]: boolean;
- [ONYXKEYS.SHOULD_SHOW_SAVED_SEARCH_RENAME_TOOLTIP]: boolean;
[ONYXKEYS.NVP_EXPENSIFY_COMPANY_CARDS_CUSTOM_NAMES]: Record;
[ONYXKEYS.CONCIERGE_REPORT_ID]: string;
[ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING]: OnyxTypes.DismissedProductTraining;
diff --git a/src/components/LHNOptionsList/OptionRowLHN.tsx b/src/components/LHNOptionsList/OptionRowLHN.tsx
index c423d3101d92..6b8cf173b0fd 100644
--- a/src/components/LHNOptionsList/OptionRowLHN.tsx
+++ b/src/components/LHNOptionsList/OptionRowLHN.tsx
@@ -11,6 +11,7 @@ import MultipleAvatars from '@components/MultipleAvatars';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import {useSession} from '@components/OnyxProvider';
import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
+import {useProductTrainingContext} from '@components/ProductTrainingContext';
import SubscriptAvatar from '@components/SubscriptAvatar';
import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
@@ -22,7 +23,6 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import DateUtils from '@libs/DateUtils';
import DomUtils from '@libs/DomUtils';
-import {hasCompletedGuidedSetupFlowSelector} from '@libs/onboardingSelectors';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import Parser from '@libs/Parser';
import Performance from '@libs/Performance';
@@ -32,7 +32,6 @@ import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportA
import FreeTrial from '@pages/settings/Subscription/FreeTrial';
import variables from '@styles/variables';
import Timing from '@userActions/Timing';
-import * as User from '@userActions/User';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
@@ -48,18 +47,19 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${optionItem?.reportID || -1}`);
- const [isFirstTimeNewExpensifyUser] = useOnyx(ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER);
- const [isOnboardingCompleted = true] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {
- selector: hasCompletedGuidedSetupFlowSelector,
- });
+
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
const session = useSession();
// Guides are assigned for the MANAGE_TEAM onboarding action, except for emails that have a '+'.
const isOnboardingGuideAssigned = introSelected?.choice === CONST.ONBOARDING_CHOICES.MANAGE_TEAM && !session?.email?.includes('+');
const shouldShowToooltipOnThisReport = isOnboardingGuideAssigned ? ReportUtils.isAdminRoom(report) : ReportUtils.isConciergeChatReport(report);
- const [shouldHideGBRTooltip] = useOnyx(ONYXKEYS.NVP_SHOULD_HIDE_GBR_TOOLTIP, {initialValue: true});
+ const shouldShowGetStartedTooltip = shouldShowToooltipOnThisReport && isScreenFocused;
+ const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
+ CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.CONCEIRGE_LHN_GBR,
+ shouldShowGetStartedTooltip,
+ );
const {translate} = useLocalize();
const [isContextMenuActive, setIsContextMenuActive] = useState(false);
@@ -72,30 +72,6 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti
}, []),
);
- const renderGBRTooltip = useCallback(
- () => (
-
-
- {translate('sidebarScreen.tooltip')}
-
- ),
- [
- styles.alignItemsCenter,
- styles.flexRow,
- styles.justifyContentCenter,
- styles.flexWrap,
- styles.textAlignCenter,
- styles.gap1,
- styles.quickActionTooltipSubtitle,
- theme.tooltipHighlightText,
- translate,
- ],
- );
-
const isInFocusMode = viewMode === CONST.OPTION_MODE.COMPACT;
const sidebarInnerRowStyle = StyleSheet.flatten(
isInFocusMode
@@ -180,17 +156,17 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti
needsOffscreenAlphaCompositing
>
diff --git a/src/components/ProductTrainingContext/PRODUCT_TRAINING_TOOLTIP_DATA.ts b/src/components/ProductTrainingContext/PRODUCT_TRAINING_TOOLTIP_DATA.ts
new file mode 100644
index 000000000000..d7f2a27d94d2
--- /dev/null
+++ b/src/components/ProductTrainingContext/PRODUCT_TRAINING_TOOLTIP_DATA.ts
@@ -0,0 +1,67 @@
+import type {ValueOf} from 'type-fest';
+import {dismissProductTraining} from '@libs/actions/Welcome';
+import CONST from '@src/CONST';
+import type {TranslationPaths} from '@src/languages/types';
+
+const {CONCEIRGE_LHN_GBR, RENAME_SAVED_SEARCH, WORKSAPCE_CHAT_CREATE, QUICK_ACTION_BUTTON} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;
+
+type ProductTrainingTooltipName = ValueOf;
+
+type ShouldShowConditionProps = {
+ shouldUseNarrowLayout?: boolean;
+};
+
+type TooltipData = {
+ content: Array<{text: TranslationPaths; isBold: boolean}>;
+ onHideTooltip: () => void;
+ name: ProductTrainingTooltipName;
+ priority: number;
+ shouldShow: (props: ShouldShowConditionProps) => boolean;
+};
+
+const PRODUCT_TRAINING_TOOLTIP_DATA: Record = {
+ [CONCEIRGE_LHN_GBR]: {
+ content: [
+ {text: 'productTrainingTooltip.conciergeLHNGBR.part1', isBold: false},
+ {text: 'productTrainingTooltip.conciergeLHNGBR.part2', isBold: true},
+ ],
+ onHideTooltip: () => dismissProductTraining(CONCEIRGE_LHN_GBR),
+ name: CONCEIRGE_LHN_GBR,
+ priority: 1300,
+ shouldShow: ({shouldUseNarrowLayout}) => !!shouldUseNarrowLayout,
+ },
+ [RENAME_SAVED_SEARCH]: {
+ content: [
+ {text: 'productTrainingTooltip.saveSearchTooltip.part1', isBold: true},
+ {text: 'productTrainingTooltip.saveSearchTooltip.part2', isBold: false},
+ ],
+ onHideTooltip: () => dismissProductTraining(RENAME_SAVED_SEARCH),
+ name: RENAME_SAVED_SEARCH,
+ priority: 1250,
+ shouldShow: ({shouldUseNarrowLayout}) => !shouldUseNarrowLayout,
+ },
+ [QUICK_ACTION_BUTTON]: {
+ content: [
+ {text: 'productTrainingTooltip.quickActionButton.part1', isBold: true},
+ {text: 'productTrainingTooltip.quickActionButton.part2', isBold: false},
+ ],
+ onHideTooltip: () => dismissProductTraining(QUICK_ACTION_BUTTON),
+ name: QUICK_ACTION_BUTTON,
+ priority: 1200,
+ shouldShow: () => true,
+ },
+ [WORKSAPCE_CHAT_CREATE]: {
+ content: [
+ {text: 'productTrainingTooltip.workspaceChatCreate.part1', isBold: false},
+ {text: 'productTrainingTooltip.workspaceChatCreate.part2', isBold: true},
+ {text: 'productTrainingTooltip.workspaceChatCreate.part3', isBold: false},
+ ],
+ onHideTooltip: () => dismissProductTraining(WORKSAPCE_CHAT_CREATE),
+ name: WORKSAPCE_CHAT_CREATE,
+ priority: 1100,
+ shouldShow: () => true,
+ },
+};
+
+export default PRODUCT_TRAINING_TOOLTIP_DATA;
+export type {ProductTrainingTooltipName};
diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx
new file mode 100644
index 000000000000..92997fe70af3
--- /dev/null
+++ b/src/components/ProductTrainingContext/index.tsx
@@ -0,0 +1,214 @@
+import React, {createContext, useCallback, useContext, useEffect, useMemo, useState} from 'react';
+import {View} from 'react-native';
+import {useOnyx} from 'react-native-onyx';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import useResponsiveLayout from '@hooks/useResponsiveLayout';
+import useTheme from '@hooks/useTheme';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {hasCompletedGuidedSetupFlowSelector} from '@libs/onboardingSelectors';
+import Permissions from '@libs/Permissions';
+import ONYXKEYS from '@src/ONYXKEYS';
+import type ChildrenProps from '@src/types/utils/ChildrenProps';
+import type {ProductTrainingTooltipName} from './PRODUCT_TRAINING_TOOLTIP_DATA';
+import PRODUCT_TRAINING_TOOLTIP_DATA from './PRODUCT_TRAINING_TOOLTIP_DATA';
+
+type ProductTrainingContextType = {
+ shouldRenderTooltip: (tooltipName: ProductTrainingTooltipName) => boolean;
+ registerTooltip: (tooltipName: ProductTrainingTooltipName) => void;
+ unregisterTooltip: (tooltipName: ProductTrainingTooltipName) => void;
+};
+
+const ProductTrainingContext = createContext({
+ shouldRenderTooltip: () => false,
+ registerTooltip: () => {},
+ unregisterTooltip: () => {},
+});
+
+function ProductTrainingContextProvider({children}: ChildrenProps) {
+ const [tryNewDot] = useOnyx(ONYXKEYS.NVP_TRYNEWDOT);
+ const hasBeenAddedToNudgeMigration = !!tryNewDot?.nudgeMigration?.timestamp;
+ const [isOnboardingCompleted = true] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {
+ selector: hasCompletedGuidedSetupFlowSelector,
+ });
+ const [dismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING);
+ const [allBetas] = useOnyx(ONYXKEYS.BETAS);
+ const {shouldUseNarrowLayout} = useResponsiveLayout();
+
+ const [activeTooltips, setActiveTooltips] = useState>(new Set());
+
+ const unregisterTooltip = useCallback(
+ (tooltipName: ProductTrainingTooltipName) => {
+ setActiveTooltips((prev) => {
+ const next = new Set(prev);
+ next.delete(tooltipName);
+ return next;
+ });
+ },
+ [setActiveTooltips],
+ );
+
+ const determineVisibleTooltip = useCallback(() => {
+ if (activeTooltips.size === 0) {
+ return null;
+ }
+
+ const sortedTooltips = Array.from(activeTooltips)
+ .map((name) => ({
+ name,
+ priority: PRODUCT_TRAINING_TOOLTIP_DATA[name]?.priority ?? 0,
+ }))
+ .sort((a, b) => b.priority - a.priority);
+
+ const highestPriorityTooltip = sortedTooltips.at(0);
+
+ if (!highestPriorityTooltip) {
+ return null;
+ }
+
+ return highestPriorityTooltip.name;
+ }, [activeTooltips]);
+
+ const shouldTooltipBeVisible = useCallback(
+ (tooltipName: ProductTrainingTooltipName) => {
+ const isDismissed = !!dismissedProductTraining?.[tooltipName];
+
+ if (isDismissed || !Permissions.shouldShowProductTrainingElements(allBetas)) {
+ return false;
+ }
+ const tooltipConfig = PRODUCT_TRAINING_TOOLTIP_DATA[tooltipName];
+
+ if (!isOnboardingCompleted && !hasBeenAddedToNudgeMigration) {
+ return false;
+ }
+
+ return tooltipConfig.shouldShow({
+ shouldUseNarrowLayout,
+ });
+ },
+ [allBetas, dismissedProductTraining, hasBeenAddedToNudgeMigration, isOnboardingCompleted, shouldUseNarrowLayout],
+ );
+
+ const registerTooltip = useCallback(
+ (tooltipName: ProductTrainingTooltipName) => {
+ const shouldRegister = shouldTooltipBeVisible(tooltipName);
+ if (!shouldRegister) {
+ return;
+ }
+ setActiveTooltips((prev) => new Set([...prev, tooltipName]));
+ },
+ [shouldTooltipBeVisible],
+ );
+
+ const shouldRenderTooltip = useCallback(
+ (tooltipName: ProductTrainingTooltipName) => {
+ // First check base conditions
+ const shouldShow = shouldTooltipBeVisible(tooltipName);
+ if (!shouldShow) {
+ return false;
+ }
+ const visibleTooltip = determineVisibleTooltip();
+
+ // If this is the highest priority visible tooltip, show it
+ if (tooltipName === visibleTooltip) {
+ return true;
+ }
+
+ return false;
+ },
+ [shouldTooltipBeVisible, determineVisibleTooltip],
+ );
+
+ const contextValue = useMemo(
+ () => ({
+ shouldRenderTooltip,
+ registerTooltip,
+ unregisterTooltip,
+ }),
+ [shouldRenderTooltip, registerTooltip, unregisterTooltip],
+ );
+
+ return {children};
+}
+
+const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shouldShow = true) => {
+ const context = useContext(ProductTrainingContext);
+ const styles = useThemeStyles();
+ const theme = useTheme();
+ const {translate} = useLocalize();
+
+ if (!context) {
+ throw new Error('useProductTourContext must be used within a ProductTourProvider');
+ }
+
+ const {shouldRenderTooltip, registerTooltip, unregisterTooltip} = context;
+
+ useEffect(() => {
+ if (shouldShow) {
+ registerTooltip(tooltipName);
+ return () => {
+ unregisterTooltip(tooltipName);
+ };
+ }
+ return () => {};
+ }, [tooltipName, registerTooltip, unregisterTooltip, shouldShow]);
+
+ const renderProductTrainingTooltip = useCallback(() => {
+ const tooltip = PRODUCT_TRAINING_TOOLTIP_DATA[tooltipName];
+ return (
+
+
+
+ {tooltip.content.map(({text, isBold}) => {
+ const translatedText = translate(text);
+ return (
+
+ {translatedText}
+
+ );
+ })}
+
+
+ );
+ }, [
+ styles.alignItemsCenter,
+ styles.flexRow,
+ styles.flexWrap,
+ styles.gap1,
+ styles.justifyContentCenter,
+ styles.p2,
+ styles.quickActionTooltipSubtitle,
+ styles.textAlignCenter,
+ styles.textBold,
+ theme.tooltipHighlightText,
+ tooltipName,
+ translate,
+ ]);
+
+ const shouldShowProductTrainingTooltip = useMemo(() => {
+ return shouldRenderTooltip(tooltipName);
+ }, [shouldRenderTooltip, tooltipName]);
+
+ const hideProductTrainingTooltip = useCallback(() => {
+ const tooltip = PRODUCT_TRAINING_TOOLTIP_DATA[tooltipName];
+ tooltip.onHideTooltip();
+ unregisterTooltip(tooltipName);
+ }, [tooltipName, unregisterTooltip]);
+
+ return {
+ renderProductTrainingTooltip,
+ hideProductTrainingTooltip,
+ shouldShowProductTrainingTooltip: shouldShow && shouldShowProductTrainingTooltip,
+ };
+};
+
+export {ProductTrainingContextProvider, useProductTrainingContext};
diff --git a/src/languages/en.ts b/src/languages/en.ts
index d565893f2fa0..2dece7799259 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -647,10 +647,6 @@ const translations = {
emoji: 'Emoji',
collapse: 'Collapse',
expand: 'Expand',
- tooltip: {
- title: 'Get started!',
- subtitle: ' Submit your first expense',
- },
},
reportActionContextMenu: {
copyToClipboard: 'Copy to clipboard',
@@ -837,10 +833,6 @@ const translations = {
trackDistance: 'Track distance',
noLongerHaveReportAccess: 'You no longer have access to your previous quick action destination. Pick a new one below.',
updateDestination: 'Update destination',
- tooltip: {
- title: 'Quick action! ',
- subtitle: 'Just a tap away.',
- },
},
iou: {
amount: 'Amount',
@@ -4556,7 +4548,6 @@ const translations = {
},
},
saveSearch: 'Save search',
- saveSearchTooltipText: 'You can rename your saved search',
deleteSavedSearch: 'Delete saved search',
deleteSavedSearchConfirm: 'Are you sure you want to delete this search?',
searchName: 'Search name',
@@ -5458,6 +5449,25 @@ const translations = {
crossPlatform: 'Do everything from your phone or browser',
},
},
+ productTrainingTooltip: {
+ conciergeLHNGBR: {
+ part1: 'Get started',
+ part2: ' here!',
+ },
+ saveSearchTooltip: {
+ part1: 'Rename your saved searches',
+ part2: ' here!',
+ },
+ quickActionButton: {
+ part1: 'Quick action!',
+ part2: ' Just a tap away',
+ },
+ workspaceChatCreate: {
+ part1: 'Submit your',
+ part2: ' expenses',
+ part3: ' here!',
+ },
+ },
};
export default translations satisfies TranslationDeepObject;
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 0b59f8a9044c..015f595eb8b3 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -639,10 +639,6 @@ const translations = {
emoji: 'Emoji',
collapse: 'Colapsar',
expand: 'Expandir',
- tooltip: {
- title: '¡Empecemos!',
- subtitle: ' Presenta tu primer gasto',
- },
},
reportActionContextMenu: {
copyToClipboard: 'Copiar al portapapeles',
@@ -832,10 +828,6 @@ const translations = {
trackDistance: 'Crear gasto por desplazamiento',
noLongerHaveReportAccess: 'Ya no tienes acceso al destino previo de esta acción rápida. Escoge uno nuevo a continuación.',
updateDestination: 'Actualiza el destino',
- tooltip: {
- title: '¡Acción rápida! ',
- subtitle: 'A un click.',
- },
},
iou: {
amount: 'Importe',
@@ -4605,7 +4597,6 @@ const translations = {
},
},
saveSearch: 'Guardar búsqueda',
- saveSearchTooltipText: 'Puedes cambiar el nombre de tu búsqueda guardada',
savedSearchesMenuItemTitle: 'Guardadas',
searchName: 'Nombre de la búsqueda',
deleteSavedSearch: 'Eliminar búsqueda guardada',
@@ -5978,6 +5969,25 @@ const translations = {
crossPlatform: 'Haz todo desde tu teléfono o navegador',
},
},
+ productTrainingTooltip: {
+ conciergeLHNGBR: {
+ part1: '¡Comienza',
+ part2: ' aquí!',
+ },
+ saveSearchTooltip: {
+ 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í',
+ },
+ },
};
export default translations satisfies TranslationDeepObject;
diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts
index 8ef5802b80dc..50e37ba6afe5 100644
--- a/src/libs/actions/Search.ts
+++ b/src/libs/actions/Search.ts
@@ -380,14 +380,6 @@ function clearAdvancedFilters() {
Onyx.merge(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, values);
}
-function showSavedSearchRenameTooltip() {
- Onyx.set(ONYXKEYS.SHOULD_SHOW_SAVED_SEARCH_RENAME_TOOLTIP, true);
-}
-
-function dismissSavedSearchRenameTooltip() {
- Onyx.set(ONYXKEYS.SHOULD_SHOW_SAVED_SEARCH_RENAME_TOOLTIP, false);
-}
-
export {
saveSearch,
search,
@@ -400,8 +392,6 @@ export {
clearAllFilters,
clearAdvancedFilters,
deleteSavedSearch,
- dismissSavedSearchRenameTooltip,
- showSavedSearchRenameTooltip,
payMoneyRequestOnSearch,
approveMoneyRequestOnSearch,
handleActionButtonPress,
diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts
index e23422d083ca..4aa8b1e7ec1f 100644
--- a/src/libs/actions/User.ts
+++ b/src/libs/actions/User.ts
@@ -1362,14 +1362,6 @@ function dismissTrackTrainingModal() {
});
}
-function dismissWorkspaceTooltip() {
- Onyx.merge(ONYXKEYS.NVP_WORKSPACE_TOOLTIP, {shouldShow: false});
-}
-
-function dismissGBRTooltip() {
- Onyx.merge(ONYXKEYS.NVP_SHOULD_HIDE_GBR_TOOLTIP, true);
-}
-
function requestRefund() {
API.write(WRITE_COMMANDS.REQUEST_REFUND, null);
}
@@ -1390,7 +1382,6 @@ export {
closeAccount,
dismissReferralBanner,
dismissTrackTrainingModal,
- dismissWorkspaceTooltip,
resendValidateCode,
requestContactMethodValidateCode,
updateNewsletterSubscription,
@@ -1424,6 +1415,5 @@ export {
addPendingContactMethod,
clearValidateCodeActionError,
subscribeToActiveGuides,
- dismissGBRTooltip,
setIsDebugModeEnabled,
};
diff --git a/src/libs/actions/Welcome/index.ts b/src/libs/actions/Welcome/index.ts
index b306daf444ba..f91ab98f7b1d 100644
--- a/src/libs/actions/Welcome/index.ts
+++ b/src/libs/actions/Welcome/index.ts
@@ -207,20 +207,16 @@ function setSelfTourViewed(shouldUpdateOnyxDataOnlyLocally = false) {
function dismissProductTraining(elementName: string) {
const date = new Date();
- // const optimisticData = [
- // {
- // onyxMethod: Onyx.METHOD.MERGE,
- // key: ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING,
- // value: {
- // [elementName]: DateUtils.getDBTime(date.valueOf()),
- // },
- // },
- // ];
- // API.write(WRITE_COMMANDS.DISMISS_PRODUCT_TRAINING, {name: elementName}, {optimisticData});
-
- Onyx.merge(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING, {
- [elementName]: DateUtils.getDBTime(date.valueOf()),
- });
+ const optimisticData = [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING,
+ value: {
+ [elementName]: DateUtils.getDBTime(date.valueOf()),
+ },
+ },
+ ];
+ API.write(WRITE_COMMANDS.DISMISS_PRODUCT_TRAINING, {name: elementName}, {optimisticData});
}
export {
diff --git a/src/libs/migrations/NVPMigration.ts b/src/libs/migrations/NVPMigration.ts
index 20f3d0a86495..8c743e66e79f 100644
--- a/src/libs/migrations/NVPMigration.ts
+++ b/src/libs/migrations/NVPMigration.ts
@@ -9,7 +9,6 @@ import type {OnyxKey} from '@src/ONYXKEYS';
const migrations = {
// eslint-disable-next-line @typescript-eslint/naming-convention
nvp_lastPaymentMethod: ONYXKEYS.NVP_LAST_PAYMENT_METHOD,
- isFirstTimeNewExpensifyUser: ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER,
preferredLocale: ONYXKEYS.NVP_PREFERRED_LOCALE,
preferredEmojiSkinTone: ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE,
frequentlyUsedEmojis: ONYXKEYS.FREQUENTLY_USED_EMOJIS,
diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx
index 02eca4b9fbbc..10c8401b98aa 100644
--- a/src/pages/Search/AdvancedSearchFilters.tsx
+++ b/src/pages/Search/AdvancedSearchFilters.tsx
@@ -439,11 +439,6 @@ function AdvancedSearchFilters() {
return;
}
- // We only want to show the tooltip once, the NVP will not be set if the user has not saved a search yet
- if (!savedSearches) {
- SearchActions.showSavedSearchRenameTooltip();
- }
-
SearchActions.saveSearch({
queryJSON,
});
diff --git a/src/pages/Search/SearchTypeMenu.tsx b/src/pages/Search/SearchTypeMenu.tsx
index 5c93a3877ff6..4a3c0881b5a6 100644
--- a/src/pages/Search/SearchTypeMenu.tsx
+++ b/src/pages/Search/SearchTypeMenu.tsx
@@ -8,6 +8,7 @@ import MenuItem from '@components/MenuItem';
import MenuItemList from '@components/MenuItemList';
import type {MenuItemWithLink} from '@components/MenuItemList';
import {usePersonalDetails} from '@components/OnyxProvider';
+import {useProductTrainingContext} from '@components/ProductTrainingContext';
import {ScrollOffsetContext} from '@components/ScrollOffsetContextProvider';
import ScrollView from '@components/ScrollView';
import type {SearchQueryJSON} from '@components/Search/types';
@@ -62,7 +63,7 @@ function SearchTypeMenu({queryJSON, searchName}: SearchTypeMenuProps) {
const {singleExecution} = useSingleExecution();
const {translate} = useLocalize();
const [savedSearches] = useOnyx(ONYXKEYS.SAVED_SEARCHES);
- const [shouldShowSavedSearchRenameTooltip] = useOnyx(ONYXKEYS.SHOULD_SHOW_SAVED_SEARCH_RENAME_TOOLTIP);
+ const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.RENAME_SAVED_SEARCH);
const {showDeleteModal, DeleteConfirmModal} = useDeleteSavedSearch();
const [session] = useOnyx(ONYXKEYS.SESSION);
@@ -118,65 +119,69 @@ function SearchTypeMenu({queryJSON, searchName}: SearchTypeMenuProps) {
[showDeleteModal],
);
- const createSavedSearchMenuItem = (item: SaveSearchItem, key: string, isNarrow: boolean, index: number) => {
- let title = item.name;
- if (title === item.query) {
- const jsonQuery = SearchQueryUtils.buildSearchQueryJSON(item.query) ?? ({} as SearchQueryJSON);
- title = SearchQueryUtils.buildUserReadableQueryString(jsonQuery, personalDetails, reports, taxRates);
- }
-
- const baseMenuItem: SavedSearchMenuItem = {
- key,
- title,
- hash: key,
- query: item.query,
- shouldShowRightComponent: true,
- focused: Number(key) === hash,
- onPress: () => {
- SearchActions.clearAllFilters();
- Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query: item?.query ?? '', name: item?.name}));
- },
- rightComponent: (
-
- ),
- styles: [styles.alignItemsCenter],
- pendingAction: item.pendingAction,
- disabled: item.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
- shouldIconUseAutoWidthStyle: true,
- };
+ const createSavedSearchMenuItem = useCallback(
+ (item: SaveSearchItem, key: string, isNarrow: boolean, index: number) => {
+ let title = item.name;
+ if (title === item.query) {
+ const jsonQuery = SearchQueryUtils.buildSearchQueryJSON(item.query) ?? ({} as SearchQueryJSON);
+ title = SearchQueryUtils.buildUserReadableQueryString(jsonQuery, personalDetails, reports, taxRates);
+ }
- if (!isNarrow) {
- return {
- ...baseMenuItem,
- shouldRenderTooltip: index === 0 && shouldShowSavedSearchRenameTooltip === true,
- tooltipAnchorAlignment: {
- horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
- vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
- },
- tooltipShiftHorizontal: -32,
- tooltipShiftVertical: 15,
- tooltipWrapperStyle: [styles.bgPaleGreen, styles.mh4, styles.pv2],
- onHideTooltip: SearchActions.dismissSavedSearchRenameTooltip,
- renderTooltipContent: () => {
- return (
-
-
- {translate('search.saveSearchTooltipText')}
-
- );
+ const baseMenuItem: SavedSearchMenuItem = {
+ key,
+ title,
+ hash: key,
+ query: item.query,
+ shouldShowRightComponent: true,
+ focused: Number(key) === hash,
+ onPress: () => {
+ SearchActions.clearAllFilters();
+ Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query: item?.query ?? '', name: item?.name}));
},
+ rightComponent: (
+
+ ),
+ styles: [styles.alignItemsCenter],
+ pendingAction: item.pendingAction,
+ disabled: item.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
+ shouldIconUseAutoWidthStyle: true,
};
- }
- return baseMenuItem;
- };
+ if (!isNarrow) {
+ return {
+ ...baseMenuItem,
+ shouldRenderTooltip: index === 0 && shouldShowProductTrainingTooltip,
+ tooltipAnchorAlignment: {
+ horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
+ vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
+ },
+ tooltipShiftHorizontal: -32,
+ tooltipShiftVertical: 15,
+ tooltipWrapperStyle: [styles.bgPaleGreen, styles.mh4, styles.pv2],
+ onHideTooltip: hideProductTrainingTooltip,
+ renderTooltipContent: renderProductTrainingTooltip,
+ };
+ }
+ return baseMenuItem;
+ },
+ [
+ hash,
+ getOverflowMenu,
+ styles.alignItemsCenter,
+ styles.bgPaleGreen,
+ styles.mh4,
+ styles.pv2,
+ personalDetails,
+ reports,
+ taxRates,
+ shouldShowProductTrainingTooltip,
+ hideProductTrainingTooltip,
+ renderProductTrainingTooltip,
+ ],
+ );
const route = useRoute();
const scrollViewRef = useRef(null);
@@ -201,12 +206,12 @@ function SearchTypeMenu({queryJSON, searchName}: SearchTypeMenuProps) {
scrollViewRef.current.scrollTo({y: scrollOffset, animated: false});
}, [getScrollOffset, route]);
- const savedSearchesMenuItems = () => {
+ const savedSearchesMenuItems = useCallback(() => {
if (!savedSearches) {
return [];
}
return Object.entries(savedSearches).map(([key, item], index) => createSavedSearchMenuItem(item, key, shouldUseNarrowLayout, index));
- };
+ }, [createSavedSearchMenuItem, savedSearches, shouldUseNarrowLayout]);
const renderSavedSearchesSection = useCallback(
(menuItems: MenuItemWithLink[]) => (
diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx
index 97582f75b7b1..47315b604f0b 100644
--- a/src/pages/home/ReportScreen.tsx
+++ b/src/pages/home/ReportScreen.tsx
@@ -131,7 +131,6 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
selector: (parentReportActions) => getParentReportAction(parentReportActions, reportOnyx?.parentReportActionID ?? ''),
});
const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP);
- const [workspaceTooltip] = useOnyx(ONYXKEYS.NVP_WORKSPACE_TOOLTIP);
const wasLoadingApp = usePrevious(isLoadingApp);
const finishedLoadingApp = wasLoadingApp && !isLoadingApp;
const isDeletedParentAction = ReportActionsUtils.isDeletedParentAction(parentReportAction);
@@ -865,7 +864,6 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
isComposerFullSize={!!isComposerFullSize}
isEmptyChat={isEmptyChat}
lastReportAction={lastReportAction}
- workspaceTooltip={workspaceTooltip}
/>
) : null}
diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx
index 893d2b3060d9..78d3288d05f0 100644
--- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx
+++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx
@@ -12,14 +12,12 @@ import type {FileObject} from '@components/AttachmentModal';
import AttachmentModal from '@components/AttachmentModal';
import EmojiPickerButton from '@components/EmojiPicker/EmojiPickerButton';
import ExceededCommentLength from '@components/ExceededCommentLength';
-import Icon from '@components/Icon';
-import * as Expensicons from '@components/Icon/Expensicons';
import ImportedStateIndicator from '@components/ImportedStateIndicator';
import type {Mention} from '@components/MentionSuggestions';
import OfflineIndicator from '@components/OfflineIndicator';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import {usePersonalDetails} from '@components/OnyxProvider';
-import Text from '@components/Text';
+import {useProductTrainingContext} from '@components/ProductTrainingContext';
import EducationalTooltip from '@components/Tooltip/EducationalTooltip';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useDebounce from '@hooks/useDebounce';
@@ -28,7 +26,6 @@ import useHandleExceedMaxTaskTitleLength from '@hooks/useHandleExceedMaxTaskTitl
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
-import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
@@ -116,7 +113,6 @@ function ReportActionCompose({
onComposerFocus,
onComposerBlur,
}: ReportActionComposeProps) {
- const theme = useTheme();
const styles = useThemeStyles();
const {translate} = useLocalize();
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
@@ -129,6 +125,11 @@ function ReportActionCompose({
const [blockedFromConcierge] = useOnyx(ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE);
const [shouldShowComposeInput = true] = useOnyx(ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT);
+ const {renderProductTrainingTooltip, hideProductTrainingTooltip, shouldShowProductTrainingTooltip} = useProductTrainingContext(
+ CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.WORKSAPCE_CHAT_CREATE,
+ shouldShowEducationalTooltip,
+ );
+
/**
* Updates the Highlight state of the composer
*/
@@ -380,34 +381,6 @@ function ReportActionCompose({
return reportActionComposeHeight - emojiOffsetWithComposeBox - CONST.MENU_POSITION_REPORT_ACTION_COMPOSE_BOTTOM;
}, [styles]);
- const renderWorkspaceChatTooltip = useCallback(
- () => (
-
-
-
- {translate('reportActionCompose.tooltip.title')}
- {translate('reportActionCompose.tooltip.subtitle')}
-
-
- ),
- [
- styles.alignItemsCenter,
- styles.flexRow,
- styles.justifyContentCenter,
- styles.flexWrap,
- styles.textAlignCenter,
- styles.gap1,
- styles.quickActionTooltipTitle,
- styles.quickActionTooltipSubtitle,
- theme.tooltipHighlightText,
- translate,
- ],
- );
-
const validateMaxLength = useCallback(
(value: string) => {
const taskCommentMatch = value?.match(CONST.REGEX.TASK_TITLE_WITH_OPTONAL_SHORT_MENTION);
@@ -448,10 +421,10 @@ function ReportActionCompose({
contentContainerStyle={isComposerFullSize ? styles.flex1 : {}}
>
;
- /** Whether to show educational tooltip in workspace chat for first-time user */
- workspaceTooltip: OnyxEntry;
-
/** Whether the chat is empty */
isEmptyChat?: boolean;
@@ -76,7 +73,6 @@ function ReportFooter({
isEmptyChat = true,
isReportReadyForDisplay = true,
isComposerFullSize = false,
- workspaceTooltip,
onComposerBlur,
onComposerFocus,
}: ReportFooterProps) {
@@ -118,7 +114,7 @@ function ReportFooter({
const isSystemChat = ReportUtils.isSystemChat(report);
const isAdminsOnlyPostingRoom = ReportUtils.isAdminsOnlyPostingRoom(report);
const isUserPolicyAdmin = PolicyUtils.isPolicyAdmin(policy);
- const shouldShowEducationalTooltip = !!workspaceTooltip?.shouldShow && !isUserPolicyAdmin;
+ const shouldShowEducationalTooltip = ReportUtils.isPolicyExpenseChat(report) && !!report.isOwnPolicyExpenseChat && !isUserPolicyAdmin;
const allPersonalDetails = usePersonalDetails();
@@ -238,7 +234,6 @@ export default memo(
prevProps.isEmptyChat === nextProps.isEmptyChat &&
prevProps.lastReportAction === nextProps.lastReportAction &&
prevProps.isReportReadyForDisplay === nextProps.isReportReadyForDisplay &&
- prevProps.workspaceTooltip?.shouldShow === nextProps.workspaceTooltip?.shouldShow &&
lodashIsEqual(prevProps.reportMetadata, nextProps.reportMetadata) &&
lodashIsEqual(prevProps.policy?.employeeList, nextProps.policy?.employeeList) &&
lodashIsEqual(prevProps.policy?.role, nextProps.policy?.role),
diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx
index 2a1d085ddf3c..cd954cdb6aaf 100644
--- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx
+++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.tsx
@@ -11,7 +11,7 @@ import FloatingActionButton from '@components/FloatingActionButton';
import * as Expensicons from '@components/Icon/Expensicons';
import type {PopoverMenuItem} from '@components/PopoverMenu';
import PopoverMenu from '@components/PopoverMenu';
-import Text from '@components/Text';
+import {useProductTrainingContext} from '@components/ProductTrainingContext';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
@@ -207,6 +207,12 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl
const [hasSeenTour = false] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {
selector: hasSeenTourSelector,
});
+
+ const {renderProductTrainingTooltip, hideProductTrainingTooltip, shouldShowProductTrainingTooltip} = useProductTrainingContext(
+ CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.QUICK_ACTION_BUTTON,
+ isCreateMenuActive && (!shouldUseNarrowLayout || isFocused),
+ );
+
/**
* There are scenarios where users who have not yet had their group workspace-chats in NewDot (isPolicyExpenseChatEnabled). In those scenarios, things can get confusing if they try to submit/track expenses. To address this, we block them from Creating, Tracking, Submitting expenses from NewDot if they are:
* 1. on at least one group policy
@@ -233,16 +239,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, [personalDetails, session?.accountID, quickActionReport, quickActionPolicy, policyChatForActivePolicy]);
- const renderQuickActionTooltip = useCallback(
- () => (
-
- {translate('quickAction.tooltip.title')}
- {translate('quickAction.tooltip.subtitle')}
-
- ),
- [styles.quickActionTooltipTitle, styles.quickActionTooltipSubtitle, translate],
- );
-
const quickActionTitle = useMemo(() => {
if (isEmptyObject(quickActionReport)) {
return '';
@@ -465,8 +461,10 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl
},
tooltipShiftHorizontal: styles.popoverMenuItem.paddingHorizontal,
tooltipShiftVertical: styles.popoverMenuItem.paddingVertical / 2,
- renderTooltipContent: renderQuickActionTooltip,
+ renderTooltipContent: renderProductTrainingTooltip,
tooltipWrapperStyle: styles.quickActionTooltipWrapper,
+ onHideTooltip: hideProductTrainingTooltip,
+ shouldRenderTooltip: shouldShowProductTrainingTooltip,
};
if (quickAction?.action) {
@@ -482,7 +480,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl
description: !hideQABSubtitle ? ReportUtils.getReportName(quickActionReport) ?? translate('quickAction.updateDestination') : '',
onSelected: () => interceptAnonymousUser(() => navigateToQuickAction()),
shouldShowSubscriptRightAvatar: ReportUtils.isPolicyExpenseChat(quickActionReport),
- shouldRenderTooltip: quickAction.isFirstQuickAction,
},
];
}
@@ -501,7 +498,6 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl
}, true);
}),
shouldShowSubscriptRightAvatar: true,
- shouldRenderTooltip: false,
},
];
}
@@ -513,13 +509,14 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl
styles.popoverMenuItem.paddingHorizontal,
styles.popoverMenuItem.paddingVertical,
styles.quickActionTooltipWrapper,
- renderQuickActionTooltip,
+ renderProductTrainingTooltip,
+ hideProductTrainingTooltip,
quickAction?.action,
- quickAction?.isFirstQuickAction,
policyChatForActivePolicy,
quickActionTitle,
hideQABSubtitle,
quickActionReport,
+ shouldShowProductTrainingTooltip,
navigateToQuickAction,
selectOption,
isValidReport,
diff --git a/src/types/onyx/DismissedProductTraining.ts b/src/types/onyx/DismissedProductTraining.ts
index 9539bc9f0187..fe24dc061aee 100644
--- a/src/types/onyx/DismissedProductTraining.ts
+++ b/src/types/onyx/DismissedProductTraining.ts
@@ -1,3 +1,6 @@
+import CONST from '@src/CONST';
+
+const {CONCEIRGE_LHN_GBR, RENAME_SAVED_SEARCH, WORKSAPCE_CHAT_CREATE, QUICK_ACTION_BUTTON} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;
/**
* This type is used to store the timestamp of when the user dismisses a product training ui elements.
*/
@@ -5,7 +8,27 @@ type DismissedProductTraining = {
/**
* When user dismisses the nudgeMigration Welcome Modal, we store the timestamp here.
*/
- migratedUserWelcomeModal: Date;
+ [CONST.MIGRATED_USER_WELCOME_MODAL]: Date;
+
+ /**
+ * When user dismisses the conciergeLHNGBR product training tooltip, we store the timestamp here.
+ */
+ [CONCEIRGE_LHN_GBR]: Date;
+
+ /**
+ * When user dismisses the renameSavedSearch product training tooltip, we store the timestamp here.
+ */
+ [RENAME_SAVED_SEARCH]: Date;
+
+ /**
+ * When user dismisses the workspaceChatCreate product training tooltip, we store the timestamp here.
+ */
+ [WORKSAPCE_CHAT_CREATE]: Date;
+
+ /**
+ * When user dismisses the quickActionButton product training tooltip, we store the timestamp here.
+ */
+ [QUICK_ACTION_BUTTON]: Date;
};
export default DismissedProductTraining;
diff --git a/src/types/onyx/WorkspaceTooltip.ts b/src/types/onyx/WorkspaceTooltip.ts
deleted file mode 100644
index 4371ac6533d8..000000000000
--- a/src/types/onyx/WorkspaceTooltip.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * The NVP containing all information related to educational tooltip in workspace chat.
- */
-type WorkspaceTooltip = {
- /** Should show educational tooltip in workspace chat for first-time user */
- shouldShow: boolean;
-};
-
-export default WorkspaceTooltip;
diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts
index 20b7d047a092..eeda322f6205 100644
--- a/src/types/onyx/index.ts
+++ b/src/types/onyx/index.ts
@@ -110,7 +110,6 @@ import type WalletOnfido from './WalletOnfido';
import type WalletStatement from './WalletStatement';
import type WalletTerms from './WalletTerms';
import type WalletTransfer from './WalletTransfer';
-import type WorkspaceTooltip from './WorkspaceTooltip';
export type {
TryNewDot,
@@ -234,7 +233,6 @@ export type {
CancellationDetails,
ApprovalWorkflowOnyx,
MobileSelectionMode,
- WorkspaceTooltip,
CardFeeds,
SaveSearch,
RecentSearchItem,