Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Make it possible to click the element the product training tooltip is pointing to #54710

Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6174a6d
Make it possible to click the element the product training tooltip is…
rayane-djouah Dec 17, 2024
ed54b83
use isScreenFocused
rayane-djouah Dec 17, 2024
2d2e16d
Merge branch 'main' into Make-it-possible-to-click-the-element-the-pr…
rayane-djouah Dec 27, 2024
0d49f67
fix bug
rayane-djouah Dec 27, 2024
fe4bcb6
fix bug
rayane-djouah Dec 27, 2024
8de62b1
remove shouldHideEducationalTooltip
rayane-djouah Dec 27, 2024
4c13d72
QAB hideProductTrainingTooltip
rayane-djouah Dec 27, 2024
9d578d3
QAB hideProductTrainingTooltip
rayane-djouah Dec 27, 2024
629c8c2
remove console log
rayane-djouah Dec 27, 2024
5e5b74b
Merge branch 'main' into Make-it-possible-to-click-the-element-the-pr…
rayane-djouah Jan 1, 2025
57811e3
Merge branch 'main' into Make-it-possible-to-click-the-element-the-pr…
rayane-djouah Jan 2, 2025
c8dc967
fix errors
rayane-djouah Jan 2, 2025
b7d5186
correct copy usage
rayane-djouah Jan 2, 2025
2042262
Refactor
rayane-djouah Jan 3, 2025
06f1b75
hideProductTrainingTooltip for RENAME_SAVED_SEARCH tooltip
rayane-djouah Jan 3, 2025
4b2a934
revert a change
rayane-djouah Jan 3, 2025
fcaf530
Fix SEARCH_FILTER_BUTTON_TOOLTIP for narrow layout
rayane-djouah Jan 3, 2025
b8f68ba
Merge branch 'Expensify:main' into Make-it-possible-to-click-the-elem…
rayane-djouah Jan 3, 2025
1992248
Fix: tooltip does not disappear when navigating away for the first time
rayane-djouah Jan 3, 2025
b47997b
Fix bug: when a migrated user logged in and dismiss modal user dont s…
rayane-djouah Jan 3, 2025
127c7f8
Fix lint errors
rayane-djouah Jan 3, 2025
2737c55
add mocks for useNavigationState
rayane-djouah Jan 3, 2025
51eca4a
create useIsCurrentRouteHome hook
rayane-djouah Jan 3, 2025
163bf6a
add useIsCurrentRouteHome mock
rayane-djouah Jan 3, 2025
46da42e
fix ESlint errors
rayane-djouah Jan 3, 2025
0f88b45
Fix: Tooltips not showing on native
rayane-djouah Jan 4, 2025
e8a3b75
Fix: Hide the extra "More" tooltip when we have an educational toolti…
rayane-djouah Jan 4, 2025
b33e69f
Refactor
rayane-djouah Jan 4, 2025
aa2b173
add comment
rayane-djouah Jan 4, 2025
473cad5
Fix bug
rayane-djouah Jan 5, 2025
b4187ee
Fix QAB tooltip does not hide immediately
rayane-djouah Jan 5, 2025
d11826c
Merge branch 'Expensify:main' into Make-it-possible-to-click-the-elem…
rayane-djouah Jan 5, 2025
1a52149
Fix: bottomtab tooltips (inbox and FAB) only hides on navigation to s…
rayane-djouah Jan 6, 2025
ed68330
move prop to most relevant type
rayane-djouah Jan 6, 2025
270a302
Fix: clicking on admin chat dismiss the workspacechat tooltip
rayane-djouah Jan 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/components/FloatingActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {useOnyx} from 'react-native-onyx';
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 useIsCurrentRouteHome from '@hooks/useIsCurrentRouteHome';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
Expand Down Expand Up @@ -69,9 +70,11 @@ function FloatingActionButton({onPress, isActive, accessibilityLabel, role}: Flo
const isNarrowScreenOnWeb = shouldUseNarrowLayout && platform === CONST.PLATFORM.WEB;
const isFocused = useBottomTabIsFocused();
const [isSidebarLoaded] = useOnyx(ONYXKEYS.IS_SIDEBAR_LOADED, {initialValue: false});
const isActiveRouteHome = useIsCurrentRouteHome();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB, but could we use the same terminology here? Either active route or current route.

Suggested change
const isActiveRouteHome = useIsCurrentRouteHome();
const isActiveRouteHome = useIsCurrentRouteHome();

const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GLOBAL_CREATE_TOOLTIP,
isFocused && isSidebarLoaded,
// On Home screen, We need to wait for the sidebar to load before showing the tooltip because there is the Concierge tooltip which is higher priority
isFocused && (!isActiveRouteHome || isSidebarLoaded),
);
const sharedValue = useSharedValue(isActive ? 1 : 0);
const buttonRef = ref;
Expand Down Expand Up @@ -108,6 +111,7 @@ function FloatingActionButton({onPress, isActive, accessibilityLabel, role}: Flo
);

const toggleFabAction = (event: GestureResponderEvent | KeyboardEvent | undefined) => {
hideProductTrainingTooltip();
// Drop focus to avoid blue focus ring.
fabPressable.current?.blur();
onPress(event);
Expand All @@ -120,11 +124,9 @@ function FloatingActionButton({onPress, isActive, accessibilityLabel, role}: Flo
horizontal: isNarrowScreenOnWeb ? CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.CENTER : CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
}}
shouldUseOverlay
shiftHorizontal={isNarrowScreenOnWeb ? 0 : variables.fabTooltipShiftHorizontal}
renderTooltipContent={renderProductTrainingTooltip}
wrapperStyle={styles.productTrainingTooltipWrapper}
onHideTooltip={hideProductTrainingTooltip}
>
<PressableWithoutFeedback
ref={(el) => {
Expand Down
10 changes: 6 additions & 4 deletions src/components/LHNOptionsList/OptionRowLHN.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
import EducationalTooltip from '@components/Tooltip/EducationalTooltip';
import useIsCurrentRouteHome from '@hooks/useIsCurrentRouteHome';
import useLocalize from '@hooks/useLocalize';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useStyleUtils from '@hooks/useStyleUtils';
Expand Down Expand Up @@ -46,22 +47,24 @@
const {shouldUseNarrowLayout} = useResponsiveLayout();

// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${optionItem?.reportID || -1}`);

Check failure on line 50 in src/components/LHNOptionsList/OptionRowLHN.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
const session = useSession();
const isActiveWorkspaceChat = ReportUtils.isPolicyExpenseChat(report) && activePolicyID === report?.policyID && session?.accountID === report?.ownerAccountID;
const isOnboardingGuideAssigned = introSelected?.choice === CONST.ONBOARDING_CHOICES.MANAGE_TEAM && !session?.email?.includes('+');
const shouldShowGetStartedTooltip = isOnboardingGuideAssigned ? ReportUtils.isAdminRoom(report) : ReportUtils.isConciergeChatReport(report);
const isActiveRouteHome = useIsCurrentRouteHome();

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]);
return {tooltipToRender: tooltip, shouldShowTooltip: shouldUseNarrowLayout ? isScreenFocused && isActiveRouteHome : isActiveRouteHome};
}, [shouldShowGetStartedTooltip, isScreenFocused, shouldUseNarrowLayout, isActiveRouteHome]);

const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(tooltipToRender, shouldShowTooltip);

const {translate} = useLocalize();
const [isContextMenuActive, setIsContextMenuActive] = useState(false);

Expand Down Expand Up @@ -165,10 +168,8 @@
horizontal: isActiveWorkspaceChat ? CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT : CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
}}
shouldUseOverlay
shiftHorizontal={isActiveWorkspaceChat ? variables.workspaceLHNtooltipShiftHorizontal : variables.gbrTooltipShiftHorizontal}
shiftVertical={isActiveWorkspaceChat ? 0 : variables.composerTooltipShiftVertical}
onHideTooltip={hideProductTrainingTooltip}
wrapperStyle={styles.productTrainingTooltipWrapper}
>
<View>
Expand All @@ -183,6 +184,7 @@
event?.preventDefault();
// Enable Composer to focus on clicking the same chat after opening the context menu.
ReportActionComposeFocusManager.focus();
hideProductTrainingTooltip();
onSelectRow(optionItem, popoverAnchor);
}}
onMouseDown={(event) => {
Expand Down
11 changes: 5 additions & 6 deletions src/components/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -340,9 +340,6 @@ type MenuItemBaseProps = {
/** Should selected item be marked with checkmark */
shouldShowSelectedItemCheck?: boolean;

/** Handles what to do when hiding the tooltip */
onHideTooltip?: () => void;

/** Should use auto width for the icon container. */
shouldIconUseAutoWidthStyle?: boolean;

Expand All @@ -351,6 +348,9 @@ type MenuItemBaseProps = {

/** Pressable component Test ID. Used to locate the component in tests. */
pressableTestID?: string;

/** Whether to teleport the portal to the modal layer */
shouldTeleportPortalToModalLayer?: boolean;
};

type MenuItemProps = (IconProps | AvatarProps | NoIcon) & MenuItemBaseProps;
Expand Down Expand Up @@ -461,10 +461,10 @@ function MenuItem(
renderTooltipContent,
additionalIconStyles,
shouldShowSelectedItemCheck = false,
onHideTooltip,
shouldIconUseAutoWidthStyle = false,
shouldBreakWord = false,
pressableTestID,
shouldTeleportPortalToModalLayer,
}: MenuItemProps,
ref: PressableRef,
) {
Expand Down Expand Up @@ -600,8 +600,7 @@ function MenuItem(
wrapperStyle={tooltipWrapperStyle}
shiftHorizontal={tooltipShiftHorizontal}
shiftVertical={tooltipShiftVertical}
shouldAutoDismiss
onHideTooltip={onHideTooltip}
shouldTeleportPortalToModalLayer={shouldTeleportPortalToModalLayer}
>
<View>
<Hoverable>
Expand Down
5 changes: 3 additions & 2 deletions src/components/ProductTrainingContext/TOOLTIPS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
},
[WORKSAPCE_CHAT_CREATE]: {
content: [
{text: 'productTrainingTooltip.workspaceChatCreate.part1', isBold: true},
{text: 'productTrainingTooltip.workspaceChatCreate.part2', isBold: false},
{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,
Expand Down
23 changes: 17 additions & 6 deletions src/components/ProductTrainingContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ function ProductTrainingContextProvider({children}: ChildrenProps) {
const [dismissedProductTraining] = useOnyx(ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING);
const {shouldUseNarrowLayout} = useResponsiveLayout();

const [modal] = useOnyx(ONYXKEYS.MODAL);
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const isModalVisible = modal?.isVisible || modal?.willAlertModalBecomeVisible;

const [activeTooltips, setActiveTooltips] = useState<Set<ProductTrainingTooltipName>>(new Set());

const unregisterTooltip = useCallback(
Expand Down Expand Up @@ -92,11 +96,16 @@ function ProductTrainingContextProvider({children}: ChildrenProps) {
return false;
}

// We need to make an exception for the QAB tooltip because it is shown in a modal, otherwise it would be hidden if a modal is visible
if (tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.QUICK_ACTION_BUTTON && isModalVisible) {
return false;
}

return tooltipConfig.shouldShow({
shouldUseNarrowLayout,
});
},
[dismissedProductTraining, hasBeenAddedToNudgeMigration, isOnboardingCompleted, isOnboardingCompletedMetadata, shouldUseNarrowLayout],
[dismissedProductTraining, hasBeenAddedToNudgeMigration, isOnboardingCompleted, isOnboardingCompletedMetadata, shouldUseNarrowLayout, isModalVisible],
);

const registerTooltip = useCallback(
Expand Down Expand Up @@ -156,11 +165,10 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou
useEffect(() => {
if (shouldShow) {
registerTooltip(tooltipName);
return () => {
unregisterTooltip(tooltipName);
};
}
return () => {};
return () => {
unregisterTooltip(tooltipName);
};
}, [tooltipName, registerTooltip, unregisterTooltip, shouldShow]);

const renderProductTrainingTooltip = useCallback(() => {
Expand Down Expand Up @@ -209,10 +217,13 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou
}, [shouldRenderTooltip, tooltipName, shouldShow]);

const hideProductTrainingTooltip = useCallback(() => {
if (!shouldShowProductTrainingTooltip) {
return;
}
const tooltip = TOOLTIPS[tooltipName];
tooltip.onHideTooltip();
unregisterTooltip(tooltipName);
}, [tooltipName, unregisterTooltip]);
}, [tooltipName, shouldShowProductTrainingTooltip, unregisterTooltip]);

return {
renderProductTrainingTooltip,
Expand Down
22 changes: 16 additions & 6 deletions src/components/Search/SearchPageHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useIsFocused} from '@react-navigation/native';
import React, {useMemo, useState} from 'react';
import {useFocusEffect} from '@react-navigation/native';
import React, {useCallback, useMemo, useState} from 'react';
import {InteractionManager, View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import Button from '@components/Button';
Expand Down Expand Up @@ -58,14 +58,25 @@
const [isDeleteExpensesConfirmModalVisible, setIsDeleteExpensesConfirmModalVisible] = useState(false);
const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false);
const [isDownloadErrorModalVisible, setIsDownloadErrorModalVisible] = useState(false);
const isFocused = useIsFocused();

const [isScreenFocused, setIsScreenFocused] = useState(false);

const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SEARCH_FILTER_BUTTON_TOOLTIP,
isFocused,
isScreenFocused,
);

const {status, hash} = queryJSON;

useFocusEffect(
useCallback(() => {
setIsScreenFocused(true);
return () => {
setIsScreenFocused(false);
};
}, []),
);

const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {});

const handleDeleteExpenses = () => {
Expand Down Expand Up @@ -189,7 +200,7 @@

const reportIDList = selectedReports?.filter((report) => !!report).map((report) => report.reportID) ?? [];
SearchActions.exportSearchItemsToCSV(
{query: status, jsonQuery: JSON.stringify(queryJSON), reportIDList, transactionIDList: selectedTransactionsKeys, policyIDs: [activeWorkspaceID ?? '']},

Check failure on line 203 in src/components/Search/SearchPageHeader.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

() => {
setIsDownloadErrorModalVisible(true);
},
Expand Down Expand Up @@ -334,6 +345,7 @@
}

const onFiltersButtonPress = () => {
hideProductTrainingTooltip();
const filterFormValues = SearchQueryUtils.buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList, personalDetails, cardList, reports, taxRates);
SearchActions.updateAdvancedFilters(filterFormValues);

Expand Down Expand Up @@ -362,11 +374,9 @@
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
}}
shouldUseOverlay
shiftHorizontal={variables.searchFiltersTooltipShiftHorizontal}
wrapperStyle={styles.productTrainingTooltipWrapper}
renderTooltipContent={renderProductTrainingTooltip}
onHideTooltip={hideProductTrainingTooltip}
>
<Button
innerStyles={!isCannedQuery && [styles.searchRouterInputResults, styles.borderNone]}
Expand Down
8 changes: 7 additions & 1 deletion src/components/ThreeDotsMenu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function ThreeDotsMenu({
shouldOverlay = false,
shouldSetModalVisibility = true,
disabled = false,
hideProductTrainingTooltip,
}: ThreeDotsMenuProps) {
const [modal] = useOnyx(ONYXKEYS.MODAL);

Expand Down Expand Up @@ -57,13 +58,18 @@ function ThreeDotsMenu({
return (
<>
<View>
<Tooltip text={translate(iconTooltip)}>
<Tooltip
text={translate(iconTooltip)}
// We need to hide the extra "More" tooltip when we have an educational tooltip
shouldRender={!hideProductTrainingTooltip}
>
<PressableWithoutFeedback
onPress={() => {
if (isPopupMenuVisible) {
hidePopoverMenu();
return;
}
hideProductTrainingTooltip?.();
buttonRef.current?.blur();
showPopoverMenu();
if (onIconPress) {
Expand Down
3 changes: 3 additions & 0 deletions src/components/ThreeDotsMenu/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ type ThreeDotsMenuProps = {

/** Should we announce the Modal visibility changes? */
shouldSetModalVisibility?: boolean;

/** Function to hide the product training tooltip */
hideProductTrainingTooltip?: () => void;
};

export default ThreeDotsMenuProps;
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ function BaseGenericTooltip({
wrapperStyle = {},
shouldUseOverlay = false,
onHideTooltip = () => {},
shouldTeleportPortalToModalLayer = false,
}: BaseGenericTooltipProps) {
// The width of tooltip's inner content. Has to be undefined in the beginning
// as a width of 0 will cause the content to be rendered of a width of 0,
Expand Down Expand Up @@ -110,7 +111,7 @@ function BaseGenericTooltip({
}

return (
<Portal hostName={!shouldUseOverlay ? 'modal' : undefined}>
<Portal hostName={shouldTeleportPortalToModalLayer ? 'modal' : undefined}>
{shouldUseOverlay && <TransparentOverlay onPress={onHideTooltip} />}
<Animated.View
ref={rootWrapper}
Expand Down
8 changes: 4 additions & 4 deletions src/components/Tooltip/BaseGenericTooltip/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ type BaseGenericTooltipProps = {

/** Handles what to do when hiding the tooltip */
onHideTooltip?: () => void;
} & Pick<
SharedTooltipProps,
'renderTooltipContent' | 'maxWidth' | 'numberOfLines' | 'text' | 'shouldForceRenderingBelow' | 'wrapperStyle' | 'anchorAlignment' | 'shouldUseOverlay' | 'onHideTooltip'
>;

/** Whether the tooltip should teleport to the modal layer */
shouldTeleportPortalToModalLayer?: boolean;
} & Pick<SharedTooltipProps, 'renderTooltipContent' | 'maxWidth' | 'numberOfLines' | 'text' | 'shouldForceRenderingBelow' | 'wrapperStyle' | 'anchorAlignment' | 'shouldUseOverlay'>;

// eslint-disable-next-line import/prefer-default-export
export type {BaseGenericTooltipProps};
Loading
Loading