diff --git a/src/App.tsx b/src/App.tsx
index cc824b78fa4c..52904e0a06c4 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -18,7 +18,6 @@ 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';
@@ -96,7 +95,6 @@ function App({url}: AppProps) {
VideoPopoverMenuContextProvider,
KeyboardProvider,
SearchRouterContextProvider,
- ProductTrainingContextProvider,
]}
>
diff --git a/src/CONST.ts b/src/CONST.ts
index 5d2331b6b304..4bfaad7b6d1b 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -6437,17 +6437,6 @@ 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',
- SEARCH_FILTER_BUTTON_TOOLTIP: 'filterButtonTooltip',
- BOTTOM_NAV_INBOX_TOOLTIP: 'bottomNavInboxTooltip',
- LHN_WORKSPACE_CHAT_TOOLTIP: 'workspaceChatLHNTooltip',
- GLOBAL_CREATE_TOOLTIP: 'globalCreateTooltip',
- },
} as const;
type Country = keyof typeof CONST.ALL_COUNTRIES;
diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index cdb21373a2cf..462ca9e22d2d 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -117,6 +117,9 @@ 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',
@@ -219,9 +222,18 @@ 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',
@@ -870,6 +882,7 @@ 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 | [];
@@ -1012,7 +1025,9 @@ 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;
@@ -1020,6 +1035,7 @@ 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/FloatingActionButton.tsx b/src/components/FloatingActionButton.tsx
index e0f0ff4e6dcd..3c831301db8b 100644
--- a/src/components/FloatingActionButton.tsx
+++ b/src/components/FloatingActionButton.tsx
@@ -5,16 +5,10 @@ import type {GestureResponderEvent, Role, Text, View} from 'react-native';
import {Platform} from 'react-native';
import Animated, {createAnimatedPropAdapter, Easing, interpolateColor, processColor, useAnimatedProps, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import Svg, {Path} from 'react-native-svg';
-import useBottomTabIsFocused from '@hooks/useBottomTabIsFocused';
-import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
-import getPlatform from '@libs/getPlatform';
import variables from '@styles/variables';
-import CONST from '@src/CONST';
import {PressableWithoutFeedback} from './Pressable';
-import {useProductTrainingContext} from './ProductTrainingContext';
-import EducationalTooltip from './Tooltip/EducationalTooltip';
const AnimatedPath = Animated.createAnimatedComponent(Path);
AnimatedPath.displayName = 'AnimatedPath';
@@ -62,14 +56,6 @@ function FloatingActionButton({onPress, isActive, accessibilityLabel, role}: Flo
const styles = useThemeStyles();
const borderRadius = styles.floatingActionButton.borderRadius;
const fabPressable = useRef(null);
- const {shouldUseNarrowLayout} = useResponsiveLayout();
- const platform = getPlatform();
- const isNarrowScreenOnWeb = shouldUseNarrowLayout && platform === CONST.PLATFORM.WEB;
- const isFocused = useBottomTabIsFocused();
- const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
- CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP,
- isFocused,
- );
const sharedValue = useSharedValue(isActive ? 1 : 0);
const buttonRef = ref;
@@ -111,45 +97,32 @@ function FloatingActionButton({onPress, isActive, accessibilityLabel, role}: Flo
};
return (
- {
+ fabPressable.current = el ?? null;
+ if (buttonRef && 'current' in buttonRef) {
+ buttonRef.current = el ?? null;
+ }
}}
- shouldUseOverlay
- shiftHorizontal={isNarrowScreenOnWeb ? 0 : variables.fabTooltipShiftHorizontal}
- renderTooltipContent={renderProductTrainingTooltip}
- wrapperStyle={styles.productTrainingTooltipWrapper}
- onHideTooltip={hideProductTrainingTooltip}
+ style={[styles.h100, styles.bottomTabBarItem]}
+ accessibilityLabel={accessibilityLabel}
+ onPress={toggleFabAction}
+ onLongPress={() => {}}
+ role={role}
+ shouldUseHapticsOnLongPress={false}
>
- {
- fabPressable.current = el ?? null;
- if (buttonRef && 'current' in buttonRef) {
- buttonRef.current = el ?? null;
- }
- }}
- style={[styles.h100, styles.bottomTabBarItem]}
- accessibilityLabel={accessibilityLabel}
- onPress={toggleFabAction}
- onLongPress={() => {}}
- role={role}
- shouldUseHapticsOnLongPress={false}
- >
-
-
-
-
-
+
+
+
+
);
}
diff --git a/src/components/LHNOptionsList/OptionRowLHN.tsx b/src/components/LHNOptionsList/OptionRowLHN.tsx
index efdd9659c845..c423d3101d92 100644
--- a/src/components/LHNOptionsList/OptionRowLHN.tsx
+++ b/src/components/LHNOptionsList/OptionRowLHN.tsx
@@ -1,5 +1,5 @@
import {useFocusEffect} from '@react-navigation/native';
-import React, {useCallback, useMemo, useRef, useState} from 'react';
+import React, {useCallback, useRef, useState} from 'react';
import type {GestureResponderEvent, ViewStyle} from 'react-native';
import {StyleSheet, View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
@@ -11,7 +11,6 @@ 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';
@@ -23,6 +22,7 @@ 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,6 +32,7 @@ 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';
@@ -47,21 +48,18 @@ 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 [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
- const isActiveWorkspaceChat = ReportUtils.isPolicyExpenseChat(report) && report?.isOwnPolicyExpenseChat && activePolicyID === report?.policyID;
+ 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();
- const isOnboardingGuideAssigned = introSelected?.choice === CONST.ONBOARDING_CHOICES.MANAGE_TEAM && !session?.email?.includes('+');
- const shouldShowGetStartedTooltip = isOnboardingGuideAssigned ? ReportUtils.isAdminRoom(report) : ReportUtils.isConciergeChatReport(report);
-
- const {tooltipToRender, shouldShowTooltip} = useMemo(() => {
- const tooltip = shouldShowGetStartedTooltip ? CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.CONCEIRGE_LHN_GBR : CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.LHN_WORKSPACE_CHAT_TOOLTIP;
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- return {tooltipToRender: tooltip, shouldShowTooltip: shouldUseNarrowLayout ? isScreenFocused : true};
- }, [shouldShowGetStartedTooltip, isScreenFocused, shouldUseNarrowLayout]);
+ // 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 {shouldShowProductTrainingTooltip, renderProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(tooltipToRender, shouldShowTooltip);
const {translate} = useLocalize();
const [isContextMenuActive, setIsContextMenuActive] = useState(false);
@@ -74,6 +72,30 @@ 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
@@ -158,18 +180,17 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti
needsOffscreenAlphaCompositing
>
diff --git a/src/components/ProductTrainingContext/TOOLTIPS.ts b/src/components/ProductTrainingContext/TOOLTIPS.ts
deleted file mode 100644
index dc2a761a4903..000000000000
--- a/src/components/ProductTrainingContext/TOOLTIPS.ts
+++ /dev/null
@@ -1,118 +0,0 @@
-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,
- SEARCH_FILTER_BUTTON_TOOLTIP,
- BOTTOM_NAV_INBOX_TOOLTIP,
- LHN_WORKSPACE_CHAT_TOOLTIP,
- GLOBAL_CREATE_TOOLTIP,
-} = 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 TOOLTIPS: 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,
- },
- [GLOBAL_CREATE_TOOLTIP]: {
- content: [
- {text: 'productTrainingTooltip.globalCreateTooltip.part1', isBold: true},
- {text: 'productTrainingTooltip.globalCreateTooltip.part2', isBold: false},
- {text: 'productTrainingTooltip.globalCreateTooltip.part3', isBold: false},
- ],
- onHideTooltip: () => dismissProductTraining(GLOBAL_CREATE_TOOLTIP),
- name: GLOBAL_CREATE_TOOLTIP,
- priority: 1200,
- shouldShow: () => true,
- },
- [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: 1150,
- shouldShow: () => true,
- },
- [WORKSAPCE_CHAT_CREATE]: {
- content: [
- {text: 'productTrainingTooltip.workspaceChatCreate.part1', isBold: true},
- {text: 'productTrainingTooltip.workspaceChatCreate.part2', isBold: false},
- ],
- onHideTooltip: () => dismissProductTraining(WORKSAPCE_CHAT_CREATE),
- name: WORKSAPCE_CHAT_CREATE,
- priority: 1100,
- shouldShow: () => true,
- },
- [SEARCH_FILTER_BUTTON_TOOLTIP]: {
- content: [
- {text: 'productTrainingTooltip.searchFilterButtonTooltip.part1', isBold: true},
- {text: 'productTrainingTooltip.searchFilterButtonTooltip.part2', isBold: false},
- ],
- onHideTooltip: () => dismissProductTraining(SEARCH_FILTER_BUTTON_TOOLTIP),
- name: SEARCH_FILTER_BUTTON_TOOLTIP,
- priority: 1000,
- shouldShow: () => true,
- },
- [BOTTOM_NAV_INBOX_TOOLTIP]: {
- content: [
- {text: 'productTrainingTooltip.bottomNavInboxTooltip.part1', isBold: true},
- {text: 'productTrainingTooltip.bottomNavInboxTooltip.part2', isBold: false},
- {text: 'productTrainingTooltip.bottomNavInboxTooltip.part3', isBold: false},
- ],
- onHideTooltip: () => dismissProductTraining(BOTTOM_NAV_INBOX_TOOLTIP),
- name: BOTTOM_NAV_INBOX_TOOLTIP,
- priority: 900,
- shouldShow: () => true,
- },
- [LHN_WORKSPACE_CHAT_TOOLTIP]: {
- content: [
- {text: 'productTrainingTooltip.workspaceChatTooltip.part1', isBold: true},
- {text: 'productTrainingTooltip.workspaceChatTooltip.part2', isBold: false},
- {text: 'productTrainingTooltip.workspaceChatTooltip.part3', isBold: false},
- ],
- onHideTooltip: () => dismissProductTraining(LHN_WORKSPACE_CHAT_TOOLTIP),
- name: LHN_WORKSPACE_CHAT_TOOLTIP,
- priority: 800,
- shouldShow: () => true,
- },
-};
-
-export default TOOLTIPS;
-export type {ProductTrainingTooltipName};
diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx
deleted file mode 100644
index 7cfcf4d3bfa7..000000000000
--- a/src/components/ProductTrainingContext/index.tsx
+++ /dev/null
@@ -1,224 +0,0 @@
-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 CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
-import type ChildrenProps from '@src/types/utils/ChildrenProps';
-import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
-import type {ProductTrainingTooltipName} from './TOOLTIPS';
-import TOOLTIPS from './TOOLTIPS';
-
-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, isOnboardingCompletedMetadata] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {
- selector: hasCompletedGuidedSetupFlowSelector,
- });
- const [dismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING);
- 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: TOOLTIPS[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) => {
- if (isLoadingOnyxValue(isOnboardingCompletedMetadata)) {
- return false;
- }
-
- const isDismissed = !!dismissedProductTraining?.[tooltipName];
-
- if (isDismissed) {
- return false;
- }
- const tooltipConfig = TOOLTIPS[tooltipName];
-
- // if hasBeenAddedToNudgeMigration is true, and welcome modal is not dismissed, don't show tooltip
- if (hasBeenAddedToNudgeMigration && !dismissedProductTraining?.[CONST.MIGRATED_USER_WELCOME_MODAL]) {
- return false;
- }
- if (isOnboardingCompleted === false) {
- return false;
- }
-
- return tooltipConfig.shouldShow({
- shouldUseNarrowLayout,
- });
- },
- [dismissedProductTraining, hasBeenAddedToNudgeMigration, isOnboardingCompleted, isOnboardingCompletedMetadata, 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 = TOOLTIPS[tooltipName];
- return (
-
-
-
- {tooltip.content.map(({text, isBold}) => {
- const translatedText = translate(text);
- return (
-
- {translatedText}
-
- );
- })}
-
-
- );
- }, [
- styles.alignItemsCenter,
- styles.flexRow,
- styles.flexWrap,
- styles.gap3,
- styles.justifyContentCenter,
- styles.mw100,
- styles.p2,
- styles.productTrainingTooltipText,
- styles.textAlignCenter,
- styles.textBold,
- styles.textWrap,
- theme.tooltipHighlightText,
- tooltipName,
- translate,
- ]);
-
- const shouldShowProductTrainingTooltip = useMemo(() => {
- return shouldRenderTooltip(tooltipName);
- }, [shouldRenderTooltip, tooltipName]);
-
- const hideProductTrainingTooltip = useCallback(() => {
- const tooltip = TOOLTIPS[tooltipName];
- tooltip.onHideTooltip();
- unregisterTooltip(tooltipName);
- }, [tooltipName, unregisterTooltip]);
-
- return {
- renderProductTrainingTooltip,
- hideProductTrainingTooltip,
- shouldShowProductTrainingTooltip,
- };
-};
-
-export {ProductTrainingContextProvider, useProductTrainingContext};
diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx
index 21a5832052c0..a78845f126d2 100644
--- a/src/components/Search/SearchPageHeader.tsx
+++ b/src/components/Search/SearchPageHeader.tsx
@@ -1,4 +1,3 @@
-import {useIsFocused} from '@react-navigation/native';
import React, {useMemo, useState} from 'react';
import {InteractionManager, View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
@@ -9,8 +8,6 @@ import ConfirmModal from '@components/ConfirmModal';
import DecisionModal from '@components/DecisionModal';
import * as Expensicons from '@components/Icon/Expensicons';
import {usePersonalDetails} from '@components/OnyxProvider';
-import {useProductTrainingContext} from '@components/ProductTrainingContext';
-import EducationalTooltip from '@components/Tooltip/EducationalTooltip';
import useActiveWorkspace from '@hooks/useActiveWorkspace';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
@@ -58,11 +55,6 @@ function SearchPageHeader({queryJSON}: SearchPageHeaderProps) {
const [isDeleteExpensesConfirmModalVisible, setIsDeleteExpensesConfirmModalVisible] = useState(false);
const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false);
const [isDownloadErrorModalVisible, setIsDownloadErrorModalVisible] = useState(false);
- const isFocused = useIsFocused();
- const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
- CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SEARCH_FILTER_BUTTON_TOOLTIP,
- isFocused,
- );
const {status, hash} = queryJSON;
@@ -356,25 +348,12 @@ function SearchPageHeader({queryJSON}: SearchPageHeaderProps) {
shouldUseStyleUtilityForAnchorPosition
/>
) : (
-
-
-
+
)}
void>();
const [shouldMeasure, setShouldMeasure] = useState(false);
@@ -21,13 +21,6 @@ function BaseEducationalTooltip({children, onHideTooltip: onHideTooltipProp, sho
const didShow = useRef(false);
- const onHideTooltip = useCallback(() => {
- if (!shouldRender) {
- return;
- }
- onHideTooltipProp?.();
- }, [onHideTooltipProp, shouldRender]);
-
const closeTooltip = useCallback(() => {
if (!didShow.current) {
return;
diff --git a/src/hooks/useBottomTabIsFocused.ts b/src/hooks/useBottomTabIsFocused.ts
deleted file mode 100644
index 60817f194628..000000000000
--- a/src/hooks/useBottomTabIsFocused.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import {useIsFocused, useNavigationState} from '@react-navigation/native';
-import CENTRAL_PANE_SCREENS from '@libs/Navigation/AppNavigator/CENTRAL_PANE_SCREENS';
-import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
-import getTopmostFullScreenRoute from '@libs/Navigation/getTopmostFullScreenRoute';
-import type {CentralPaneName, FullScreenName, NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types';
-import SCREENS from '@src/SCREENS';
-import useResponsiveLayout from './useResponsiveLayout';
-
-const useBottomTabIsFocused = () => {
- const {shouldUseNarrowLayout} = useResponsiveLayout();
- const isFocused = useIsFocused();
- const topmostFullScreenName = useNavigationState | undefined>(getTopmostFullScreenRoute);
- const topmostCentralPane = useNavigationState | undefined>(getTopmostCentralPaneRoute);
- // If there is a full screen view such as Workspace Settings or Not Found screen, the bottom tab should not be considered focused
- if (topmostFullScreenName) {
- return false;
- }
- // On the Search screen, isFocused returns false, but it is actually focused
- if (shouldUseNarrowLayout) {
- return isFocused || topmostCentralPane?.name === SCREENS.SEARCH.CENTRAL_PANE;
- }
- // On desktop screen sizes, isFocused always returns false, so we cannot rely on it alone to determine if the bottom tab is focused
- return isFocused || Object.keys(CENTRAL_PANE_SCREENS).includes(topmostCentralPane?.name ?? '');
-};
-
-export default useBottomTabIsFocused;
diff --git a/src/hooks/useOnboardingFlow.ts b/src/hooks/useOnboardingFlow.ts
index 57d432b44f43..7aff640aed94 100644
--- a/src/hooks/useOnboardingFlow.ts
+++ b/src/hooks/useOnboardingFlow.ts
@@ -4,6 +4,7 @@ import {useOnyx} from 'react-native-onyx';
import * as LoginUtils from '@libs/LoginUtils';
import Navigation from '@libs/Navigation/Navigation';
import {hasCompletedGuidedSetupFlowSelector, tryNewDotOnyxSelector} from '@libs/onboardingSelectors';
+import Permissions from '@libs/Permissions';
import * as SearchQueryUtils from '@libs/SearchQueryUtils';
import * as OnboardingFlow from '@userActions/Welcome/OnboardingFlow';
import ONYXKEYS from '@src/ONYXKEYS';
@@ -30,8 +31,9 @@ function useOnboardingFlowRouter() {
const isPrivateDomain = !!session?.email && !LoginUtils.isEmailPublicDomain(session?.email);
const [isSingleNewDotEntry, isSingleNewDotEntryMetadata] = useOnyx(ONYXKEYS.IS_SINGLE_NEW_DOT_ENTRY);
+ const [allBetas, allBetasMetadata] = useOnyx(ONYXKEYS.BETAS);
useEffect(() => {
- if (isLoadingOnyxValue(isOnboardingCompletedMetadata, tryNewDotdMetadata, dismissedProductTrainingMetadata)) {
+ if (isLoadingOnyxValue(isOnboardingCompletedMetadata, tryNewDotdMetadata, dismissedProductTrainingMetadata, allBetasMetadata)) {
return;
}
@@ -39,7 +41,7 @@ function useOnboardingFlowRouter() {
return;
}
- if (hasBeenAddedToNudgeMigration && !dismissedProductTraining?.migratedUserWelcomeModal) {
+ if (hasBeenAddedToNudgeMigration && !dismissedProductTraining?.migratedUserWelcomeModal && Permissions.shouldShowProductTrainingElements(allBetas)) {
const defaultCannedQuery = SearchQueryUtils.buildCannedSearchQuery();
const query = defaultCannedQuery;
Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query}));
@@ -81,6 +83,8 @@ function useOnboardingFlowRouter() {
dismissedProductTraining?.migratedUserWelcomeModal,
dismissedProductTraining,
isPrivateDomain,
+ allBetas,
+ allBetasMetadata,
]);
return {isOnboardingCompleted, isHybridAppOnboardingCompleted};
diff --git a/src/languages/en.ts b/src/languages/en.ts
index c61ef58f8eff..2b73661a432c 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -650,6 +650,10 @@ const translations = {
emoji: 'Emoji',
collapse: 'Collapse',
expand: 'Expand',
+ tooltip: {
+ title: 'Get started!',
+ subtitle: ' Submit your first expense',
+ },
},
reportActionContextMenu: {
copyToClipboard: 'Copy to clipboard',
@@ -836,6 +840,10 @@ 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',
@@ -4559,6 +4567,7 @@ 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',
@@ -5460,44 +5469,6 @@ 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!',
- },
- searchFilterButtonTooltip: {
- part1: 'Customize your search',
- part2: ' here!',
- },
- bottomNavInboxTooltip: {
- part1: 'Your to-do list',
- part2: '\n🟢 = ready for you',
- part3: ' 🔴 = needs review',
- },
- workspaceChatTooltip: {
- part1: 'Submit expenses',
- part2: ' and chat with',
- part3: '\napprovers here!',
- },
- globalCreateTooltip: {
- part1: 'Create expenses',
- part2: ', start chatting,',
- part3: '\nand more!',
- },
- },
};
export default translations satisfies TranslationDeepObject;
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 5220acf3b9d9..529ee6442dad 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -642,6 +642,10 @@ const translations = {
emoji: 'Emoji',
collapse: 'Colapsar',
expand: 'Expandir',
+ tooltip: {
+ title: '¡Empecemos!',
+ subtitle: ' Presenta tu primer gasto',
+ },
},
reportActionContextMenu: {
copyToClipboard: 'Copiar al portapapeles',
@@ -831,6 +835,10 @@ 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',
@@ -4608,6 +4616,7 @@ 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',
@@ -5980,44 +5989,6 @@ 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Ã',
- },
- searchFilterButtonTooltip: {
- part1: 'Personaliza tu búsqueda',
- part2: ' aquÃ!',
- },
- bottomNavInboxTooltip: {
- part1: 'Tu lista de tareas',
- part2: '\n🟢 = listo para ti',
- part3: ' 🔴 = necesita revisión',
- },
- workspaceChatTooltip: {
- part1: 'EnvÃa gastos',
- part2: ' y chatea con',
- part3: '\naprobadores aquÃ!',
- },
- globalCreateTooltip: {
- part1: 'Crea gastos',
- part2: ', comienza a chatear,',
- part3: '\ny mucho más!',
- },
- },
};
export default translations satisfies TranslationDeepObject;
diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx
index 5647c31c6604..b478f09c2e01 100644
--- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx
+++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx
@@ -4,17 +4,13 @@ import {useOnyx} from 'react-native-onyx';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import {PressableWithFeedback} from '@components/Pressable';
-import {useProductTrainingContext} from '@components/ProductTrainingContext';
import type {SearchQueryString} from '@components/Search/types';
import Text from '@components/Text';
-import EducationalTooltip from '@components/Tooltip/EducationalTooltip';
import useActiveWorkspace from '@hooks/useActiveWorkspace';
-import useBottomTabIsFocused from '@hooks/useBottomTabIsFocused';
import useCurrentReportID from '@hooks/useCurrentReportID';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
-import getPlatform from '@libs/getPlatform';
import interceptAnonymousUser from '@libs/interceptAnonymousUser';
import Navigation from '@libs/Navigation/Navigation';
import type {AuthScreensParamList, RootStackParamList, State} from '@libs/Navigation/types';
@@ -81,13 +77,7 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) {
const [chatTabBrickRoad, setChatTabBrickRoad] = useState(() =>
getChatTabBrickRoad(activeWorkspaceID, currentReportID, reports, betas, policies, priorityMode, transactionViolations),
);
- const isFocused = useBottomTabIsFocused();
- const platform = getPlatform();
- const isWebOrDesktop = platform === CONST.PLATFORM.WEB || platform === CONST.PLATFORM.DESKTOP;
- const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
- CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.BOTTOM_NAV_INBOX_TOOLTIP,
- selectedTab !== SCREENS.HOME && isFocused,
- );
+
useEffect(() => {
setChatTabBrickRoad(getChatTabBrickRoad(activeWorkspaceID, currentReportID, reports, betas, policies, priorityMode, transactionViolations));
// We need to get a new brick road state when report actions are updated, otherwise we'll be showing an outdated brick road.
@@ -146,49 +136,30 @@ function BottomTabBar({selectedTab}: BottomTabBarProps) {
/>
)}
-
-
+
+ {!!chatTabBrickRoad && (
+
+ )}
+
+
-
-
- {!!chatTabBrickRoad && (
-
- )}
-
-
- {translate('common.inbox')}
-
-
-
+ {translate('common.inbox')}
+
+
): boolean {
return !!betas?.includes(CONST.BETAS.PER_DIEM) || canUseAllBetas(betas);
}
+// TEMPORARY BETA TO HIDE PRODUCT TRAINING TOOLTIP AND MIGRATE USER WELCOME MODAL
+function shouldShowProductTrainingElements(betas: OnyxEntry): boolean {
+ return !!betas?.includes(CONST.BETAS.PRODUCT_TRAINING) || canUseAllBetas(betas);
+}
+
/**
* Link previews are temporarily disabled.
*/
@@ -50,4 +55,5 @@ export default {
canUseCombinedTrackSubmit,
canUseCategoryAndTagApprovers,
canUsePerDiem,
+ shouldShowProductTrainingElements,
};
diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts
index 50e37ba6afe5..8ef5802b80dc 100644
--- a/src/libs/actions/Search.ts
+++ b/src/libs/actions/Search.ts
@@ -380,6 +380,14 @@ 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,
@@ -392,6 +400,8 @@ export {
clearAllFilters,
clearAdvancedFilters,
deleteSavedSearch,
+ dismissSavedSearchRenameTooltip,
+ showSavedSearchRenameTooltip,
payMoneyRequestOnSearch,
approveMoneyRequestOnSearch,
handleActionButtonPress,
diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts
index 885969857d72..8f8c416ceeb3 100644
--- a/src/libs/actions/User.ts
+++ b/src/libs/actions/User.ts
@@ -1371,6 +1371,14 @@ 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);
}
@@ -1391,6 +1399,7 @@ export {
closeAccount,
dismissReferralBanner,
dismissTrackTrainingModal,
+ dismissWorkspaceTooltip,
resendValidateCode,
requestContactMethodValidateCode,
updateNewsletterSubscription,
@@ -1424,6 +1433,7 @@ export {
addPendingContactMethod,
clearValidateCodeActionError,
subscribeToActiveGuides,
+ dismissGBRTooltip,
setIsDebugModeEnabled,
resetValidateActionCodeSent,
};
diff --git a/src/libs/actions/Welcome/index.ts b/src/libs/actions/Welcome/index.ts
index f91ab98f7b1d..b306daf444ba 100644
--- a/src/libs/actions/Welcome/index.ts
+++ b/src/libs/actions/Welcome/index.ts
@@ -207,16 +207,20 @@ 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});
+ // 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()),
+ });
}
export {
diff --git a/src/libs/migrations/NVPMigration.ts b/src/libs/migrations/NVPMigration.ts
index 8c743e66e79f..20f3d0a86495 100644
--- a/src/libs/migrations/NVPMigration.ts
+++ b/src/libs/migrations/NVPMigration.ts
@@ -9,6 +9,7 @@ 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 10c8401b98aa..02eca4b9fbbc 100644
--- a/src/pages/Search/AdvancedSearchFilters.tsx
+++ b/src/pages/Search/AdvancedSearchFilters.tsx
@@ -439,6 +439,11 @@ 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 6d6543554869..5c93a3877ff6 100644
--- a/src/pages/Search/SearchTypeMenu.tsx
+++ b/src/pages/Search/SearchTypeMenu.tsx
@@ -8,7 +8,6 @@ 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';
@@ -63,18 +62,14 @@ function SearchTypeMenu({queryJSON, searchName}: SearchTypeMenuProps) {
const {singleExecution} = useSingleExecution();
const {translate} = useLocalize();
const [savedSearches] = useOnyx(ONYXKEYS.SAVED_SEARCHES);
- const {isOffline} = useNetwork();
- const shouldShowSavedSearchesMenuItemTitle = Object.values(savedSearches ?? {}).filter((s) => s.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || isOffline).length > 0;
- const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
- CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.RENAME_SAVED_SEARCH,
- shouldShowSavedSearchesMenuItemTitle,
- );
+ const [shouldShowSavedSearchRenameTooltip] = useOnyx(ONYXKEYS.SHOULD_SHOW_SAVED_SEARCH_RENAME_TOOLTIP);
const {showDeleteModal, DeleteConfirmModal} = useDeleteSavedSearch();
const [session] = useOnyx(ONYXKEYS.SESSION);
const personalDetails = usePersonalDetails();
const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
const taxRates = getAllTaxRates();
+ const {isOffline} = useNetwork();
const typeMenuItems: SearchTypeMenuItem[] = [
{
@@ -123,69 +118,65 @@ function SearchTypeMenu({queryJSON, searchName}: SearchTypeMenuProps) {
[showDeleteModal],
);
- 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);
- }
+ 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 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}));
+ 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')}
+
+ );
},
- rightComponent: (
-
- ),
- styles: [styles.alignItemsCenter],
- pendingAction: item.pendingAction,
- disabled: item.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
- shouldIconUseAutoWidthStyle: true,
};
+ }
- 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,
- ],
- );
+ return baseMenuItem;
+ };
const route = useRoute();
const scrollViewRef = useRef(null);
@@ -210,12 +201,12 @@ function SearchTypeMenu({queryJSON, searchName}: SearchTypeMenuProps) {
scrollViewRef.current.scrollTo({y: scrollOffset, animated: false});
}, [getScrollOffset, route]);
- const savedSearchesMenuItems = useCallback(() => {
+ const savedSearchesMenuItems = () => {
if (!savedSearches) {
return [];
}
return Object.entries(savedSearches).map(([key, item], index) => createSavedSearchMenuItem(item, key, shouldUseNarrowLayout, index));
- }, [createSavedSearchMenuItem, savedSearches, shouldUseNarrowLayout]);
+ };
const renderSavedSearchesSection = useCallback(
(menuItems: MenuItemWithLink[]) => (
@@ -249,6 +240,7 @@ function SearchTypeMenu({queryJSON, searchName}: SearchTypeMenuProps) {
/>
);
}
+ const shouldShowSavedSearchesMenuItemTitle = Object.values(savedSearches ?? {}).filter((s) => s.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || isOffline).length > 0;
return (
(null);
- const platform = getPlatform();
- const isWebOrDesktop = platform === CONST.PLATFORM.WEB || platform === CONST.PLATFORM.DESKTOP;
-
const openMenu = useCallback(() => setIsPopoverVisible(true), []);
const closeMenu = useCallback(() => setIsPopoverVisible(false), []);
const onPress = () => {
@@ -81,9 +75,6 @@ function SearchTypeMenuNarrow({typeMenuItems, activeItemIndex, queryJSON, title,
SearchActions.updateAdvancedFilters(values);
Navigation.navigate(ROUTES.SEARCH_ADVANCED_FILTERS);
};
- const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
- CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SEARCH_FILTER_BUTTON_TOOLTIP,
- );
const currentSavedSearch = savedSearchesMenuItems.find((item) => Number(item.hash) === hash);
@@ -209,24 +200,10 @@ function SearchTypeMenuNarrow({typeMenuItems, activeItemIndex, queryJSON, title,
)}
-
-
-
+
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);
@@ -864,6 +865,7 @@ 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 78d3288d05f0..893d2b3060d9 100644
--- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx
+++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx
@@ -12,12 +12,14 @@ 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 {useProductTrainingContext} from '@components/ProductTrainingContext';
+import Text from '@components/Text';
import EducationalTooltip from '@components/Tooltip/EducationalTooltip';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useDebounce from '@hooks/useDebounce';
@@ -26,6 +28,7 @@ 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';
@@ -113,6 +116,7 @@ function ReportActionCompose({
onComposerFocus,
onComposerBlur,
}: ReportActionComposeProps) {
+ const theme = useTheme();
const styles = useThemeStyles();
const {translate} = useLocalize();
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
@@ -125,11 +129,6 @@ 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
*/
@@ -381,6 +380,34 @@ 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);
@@ -421,10 +448,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;
@@ -73,6 +76,7 @@ function ReportFooter({
isEmptyChat = true,
isReportReadyForDisplay = true,
isComposerFullSize = false,
+ workspaceTooltip,
onComposerBlur,
onComposerFocus,
}: ReportFooterProps) {
@@ -114,7 +118,7 @@ function ReportFooter({
const isSystemChat = ReportUtils.isSystemChat(report);
const isAdminsOnlyPostingRoom = ReportUtils.isAdminsOnlyPostingRoom(report);
const isUserPolicyAdmin = PolicyUtils.isPolicyAdmin(policy);
- const shouldShowEducationalTooltip = ReportUtils.isPolicyExpenseChat(report) && !!report.isOwnPolicyExpenseChat && !isUserPolicyAdmin;
+ const shouldShowEducationalTooltip = !!workspaceTooltip?.shouldShow && !isUserPolicyAdmin;
const allPersonalDetails = usePersonalDetails();
@@ -234,6 +238,7 @@ 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 32327d031b9e..4ee42a6eac67 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 {useProductTrainingContext} from '@components/ProductTrainingContext';
+import Text from '@components/Text';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
@@ -206,12 +206,6 @@ 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
@@ -238,6 +232,16 @@ 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 '';
@@ -417,10 +421,8 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl
},
tooltipShiftHorizontal: styles.popoverMenuItem.paddingHorizontal,
tooltipShiftVertical: styles.popoverMenuItem.paddingVertical / 2,
- renderTooltipContent: renderProductTrainingTooltip,
- tooltipWrapperStyle: styles.productTrainingTooltipWrapper,
- onHideTooltip: hideProductTrainingTooltip,
- shouldRenderTooltip: shouldShowProductTrainingTooltip,
+ renderTooltipContent: renderQuickActionTooltip,
+ tooltipWrapperStyle: styles.quickActionTooltipWrapper,
};
if (quickAction?.action) {
@@ -436,6 +438,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl
description: !hideQABSubtitle ? ReportUtils.getReportName(quickActionReport) ?? translate('quickAction.updateDestination') : '',
onSelected: () => interceptAnonymousUser(() => navigateToQuickAction()),
shouldShowSubscriptRightAvatar: ReportUtils.isPolicyExpenseChat(quickActionReport),
+ shouldRenderTooltip: quickAction.isFirstQuickAction,
},
];
}
@@ -454,6 +457,7 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl
}, true);
}),
shouldShowSubscriptRightAvatar: true,
+ shouldRenderTooltip: false,
},
];
}
@@ -466,15 +470,14 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu}: Fl
styles.popoverMenuItem.paddingVertical,
styles.pt3,
styles.pb2,
- styles.productTrainingTooltipWrapper,
- renderProductTrainingTooltip,
- hideProductTrainingTooltip,
+ styles.quickActionTooltipWrapper,
+ renderQuickActionTooltip,
quickAction?.action,
+ quickAction?.isFirstQuickAction,
policyChatForActivePolicy,
quickActionTitle,
hideQABSubtitle,
quickActionReport,
- shouldShowProductTrainingTooltip,
navigateToQuickAction,
selectOption,
quickActionPolicy,
diff --git a/src/styles/index.ts b/src/styles/index.ts
index ae2f97b6b72f..a09796000b36 100644
--- a/src/styles/index.ts
+++ b/src/styles/index.ts
@@ -4001,15 +4001,19 @@ const styles = (theme: ThemeColors) =>
borderRadius: variables.componentBorderRadiusMedium,
},
- productTrainingTooltipWrapper: {
+ quickActionTooltipWrapper: {
backgroundColor: theme.tooltipHighlightBG,
- borderRadius: variables.componentBorderRadiusNormal,
},
- productTrainingTooltipText: {
+ quickActionTooltipTitle: {
+ ...FontUtils.fontFamily.platform.EXP_NEUE_BOLD,
+ fontSize: variables.fontSizeLabel,
+ color: theme.tooltipHighlightText,
+ },
+
+ quickActionTooltipSubtitle: {
fontSize: variables.fontSizeLabel,
color: theme.textDark,
- lineHeight: variables.lineHeightLarge,
},
quickReactionsContainer: {
diff --git a/src/styles/theme/themes/dark.ts b/src/styles/theme/themes/dark.ts
index 68132de5fcad..223fc1c56818 100644
--- a/src/styles/theme/themes/dark.ts
+++ b/src/styles/theme/themes/dark.ts
@@ -81,7 +81,7 @@ const darkTheme = {
ourMentionText: colors.green100,
ourMentionBG: colors.green600,
tooltipHighlightBG: colors.green100,
- tooltipHighlightText: colors.green400,
+ tooltipHighlightText: colors.green500,
tooltipSupportingText: colors.productLight800,
tooltipPrimaryText: colors.productLight900,
trialBannerBackgroundColor: colors.green700,
diff --git a/src/styles/theme/themes/light.ts b/src/styles/theme/themes/light.ts
index 7be69e5461d1..151388e77136 100644
--- a/src/styles/theme/themes/light.ts
+++ b/src/styles/theme/themes/light.ts
@@ -81,7 +81,7 @@ const lightTheme = {
ourMentionText: colors.green600,
ourMentionBG: colors.green100,
tooltipHighlightBG: colors.green100,
- tooltipHighlightText: colors.green400,
+ tooltipHighlightText: colors.green500,
tooltipSupportingText: colors.productDark800,
tooltipPrimaryText: colors.productDark900,
trialBannerBackgroundColor: colors.green100,
diff --git a/src/styles/variables.ts b/src/styles/variables.ts
index 2a2f9a6fc9ef..c8a6f7025912 100644
--- a/src/styles/variables.ts
+++ b/src/styles/variables.ts
@@ -258,12 +258,6 @@ export default {
composerTooltipShiftHorizontal: 10,
composerTooltipShiftVertical: -10,
gbrTooltipShiftHorizontal: -20,
- fabTooltipShiftHorizontal: -15,
- workspaceLHNtooltipShiftHorizontal: 26,
- searchFiltersTooltipShiftHorizontal: -20,
- searchFiltersTooltipShiftHorizontalNarrow: -10,
- searchFiltersTooltipShiftVerticalNarrow: 5,
- bottomTabInboxTooltipShiftHorizontal: 36,
inlineImagePreviewMinSize: 64,
inlineImagePreviewMaxSize: 148,
diff --git a/src/types/onyx/DismissedProductTraining.ts b/src/types/onyx/DismissedProductTraining.ts
index 53df7c403ca0..9539bc9f0187 100644
--- a/src/types/onyx/DismissedProductTraining.ts
+++ b/src/types/onyx/DismissedProductTraining.ts
@@ -1,15 +1,3 @@
-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,
-} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;
/**
* This type is used to store the timestamp of when the user dismisses a product training ui elements.
*/
@@ -17,47 +5,7 @@ type DismissedProductTraining = {
/**
* When user dismisses the nudgeMigration Welcome Modal, we store the timestamp here.
*/
- [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;
-
- /**
- * When user dismisses the searchFilterButtonTooltip product training tooltip, we store the timestamp here.
- */
- [SEARCH_FILTER_BUTTON_TOOLTIP]: Date;
-
- /**
- * When user dismisses the bottomNavInboxTooltip product training tooltip, we store the timestamp here.
- */
- [BOTTOM_NAV_INBOX_TOOLTIP]: Date;
-
- /**
- * When user dismisses the lhnWorkspaceChatTooltip product training tooltip, we store the timestamp here.
- */
- [LHN_WORKSPACE_CHAT_TOOLTIP]: Date;
-
- /**
- * When user dismisses the globalCreateTooltip product training tooltip, we store the timestamp here.
- */
- [GLOBAL_CREATE_TOOLTIP]: Date;
+ migratedUserWelcomeModal: Date;
};
export default DismissedProductTraining;
diff --git a/src/types/onyx/WorkspaceTooltip.ts b/src/types/onyx/WorkspaceTooltip.ts
new file mode 100644
index 000000000000..4371ac6533d8
--- /dev/null
+++ b/src/types/onyx/WorkspaceTooltip.ts
@@ -0,0 +1,9 @@
+/**
+ * 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 9d4d319d05e8..a6fd6d418c90 100644
--- a/src/types/onyx/index.ts
+++ b/src/types/onyx/index.ts
@@ -111,6 +111,7 @@ 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,6 +235,7 @@ export type {
CancellationDetails,
ApprovalWorkflowOnyx,
MobileSelectionMode,
+ WorkspaceTooltip,
CardFeeds,
SaveSearch,
RecentSearchItem,