Skip to content

Commit 5f4e091

Browse files
authored
Merge pull request #59577 from ishpaul777/revert-59576-georgia-revert-59008
Make tooltips dismissible with 'X'
2 parents 08fd684 + cb1bb74 commit 5f4e091

File tree

12 files changed

+159
-63
lines changed

12 files changed

+159
-63
lines changed

src/components/ProductTrainingContext/TOOLTIPS.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type ShouldShowConditionProps = {
2222

2323
type TooltipData = {
2424
content: Array<{text: TranslationPaths; isBold: boolean}>;
25-
onHideTooltip: () => void;
25+
onHideTooltip: (isDismissedUsingCloseButton?: boolean) => void;
2626
name: ProductTrainingTooltipName;
2727
priority: number;
2828
shouldShow: (props: ShouldShowConditionProps) => boolean;
@@ -35,7 +35,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
3535
{text: 'productTrainingTooltip.conciergeLHNGBR.part1', isBold: false},
3636
{text: 'productTrainingTooltip.conciergeLHNGBR.part2', isBold: true},
3737
],
38-
onHideTooltip: () => dismissProductTraining(CONCEIRGE_LHN_GBR),
38+
onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(CONCEIRGE_LHN_GBR, isDismissedUsingCloseButton),
3939
name: CONCEIRGE_LHN_GBR,
4040
priority: 1300,
4141
// TODO: CONCEIRGE_LHN_GBR tooltip will be replaced by a tooltip in the #admins room
@@ -47,7 +47,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
4747
{text: 'productTrainingTooltip.saveSearchTooltip.part1', isBold: true},
4848
{text: 'productTrainingTooltip.saveSearchTooltip.part2', isBold: false},
4949
],
50-
onHideTooltip: () => dismissProductTraining(RENAME_SAVED_SEARCH),
50+
onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(RENAME_SAVED_SEARCH, isDismissedUsingCloseButton),
5151
name: RENAME_SAVED_SEARCH,
5252
priority: 1250,
5353
shouldShow: ({shouldUseNarrowLayout}) => !shouldUseNarrowLayout,
@@ -58,7 +58,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
5858
{text: 'productTrainingTooltip.globalCreateTooltip.part2', isBold: false},
5959
{text: 'productTrainingTooltip.globalCreateTooltip.part3', isBold: false},
6060
],
61-
onHideTooltip: () => dismissProductTraining(GLOBAL_CREATE_TOOLTIP),
61+
onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(GLOBAL_CREATE_TOOLTIP, isDismissedUsingCloseButton),
6262
name: GLOBAL_CREATE_TOOLTIP,
6363
priority: 1200,
6464
shouldShow: () => true,
@@ -69,7 +69,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
6969
{text: 'productTrainingTooltip.bottomNavInboxTooltip.part2', isBold: false},
7070
{text: 'productTrainingTooltip.bottomNavInboxTooltip.part3', isBold: false},
7171
],
72-
onHideTooltip: () => dismissProductTraining(BOTTOM_NAV_INBOX_TOOLTIP),
72+
onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(BOTTOM_NAV_INBOX_TOOLTIP, isDismissedUsingCloseButton),
7373
name: BOTTOM_NAV_INBOX_TOOLTIP,
7474
priority: 900,
7575
shouldShow: () => true,
@@ -80,7 +80,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
8080
{text: 'productTrainingTooltip.workspaceChatTooltip.part2', isBold: false},
8181
{text: 'productTrainingTooltip.workspaceChatTooltip.part3', isBold: false},
8282
],
83-
onHideTooltip: () => dismissProductTraining(LHN_WORKSPACE_CHAT_TOOLTIP),
83+
onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(LHN_WORKSPACE_CHAT_TOOLTIP, isDismissedUsingCloseButton),
8484
name: LHN_WORKSPACE_CHAT_TOOLTIP,
8585
priority: 800,
8686
shouldShow: () => true,
@@ -102,7 +102,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
102102
{text: 'productTrainingTooltip.scanTestTooltip.part4', isBold: true},
103103
{text: 'productTrainingTooltip.scanTestTooltip.part5', isBold: false},
104104
],
105-
onHideTooltip: () => dismissProductTraining(SCAN_TEST_TOOLTIP_MANAGER),
105+
onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(SCAN_TEST_TOOLTIP_MANAGER, isDismissedUsingCloseButton),
106106
name: SCAN_TEST_TOOLTIP_MANAGER,
107107
priority: 1000,
108108
shouldShow: () => true,
@@ -113,7 +113,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
113113
{text: 'productTrainingTooltip.scanTestTooltip.part7', isBold: true},
114114
{text: 'productTrainingTooltip.scanTestTooltip.part8', isBold: false},
115115
],
116-
onHideTooltip: () => dismissProductTraining(SCAN_TEST_CONFIRMATION),
116+
onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(SCAN_TEST_CONFIRMATION, isDismissedUsingCloseButton),
117117
name: SCAN_TEST_CONFIRMATION,
118118
priority: 1100,
119119
shouldShow: () => true,

src/components/ProductTrainingContext/index.tsx

Lines changed: 71 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@ import {useOnyx} from 'react-native-onyx';
44
import Button from '@components/Button';
55
import Icon from '@components/Icon';
66
import * as Expensicons from '@components/Icon/Expensicons';
7+
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
78
import Text from '@components/Text';
89
import useLocalize from '@hooks/useLocalize';
910
import useResponsiveLayout from '@hooks/useResponsiveLayout';
1011
import useSidePanel from '@hooks/useSidePanel';
1112
import useTheme from '@hooks/useTheme';
1213
import useThemeStyles from '@hooks/useThemeStyles';
1314
import {parseFSAttributes} from '@libs/Fullstory';
15+
import getPlatform from '@libs/getPlatform';
1416
import {hasCompletedGuidedSetupFlowSelector} from '@libs/onboardingSelectors';
17+
import isProductTrainingElementDismissed from '@libs/TooltipUtils';
18+
import variables from '@styles/variables';
1519
import CONST from '@src/CONST';
1620
import ONYXKEYS from '@src/ONYXKEYS';
1721
import type ChildrenProps from '@src/types/utils/ChildrenProps';
@@ -98,7 +102,7 @@ function ProductTrainingContextProvider({children}: ChildrenProps) {
98102
return false;
99103
}
100104

101-
const isDismissed = !!dismissedProductTraining?.[tooltipName];
105+
const isDismissed = isProductTrainingElementDismissed(tooltipName, dismissedProductTraining);
102106

103107
if (isDismissed) {
104108
return false;
@@ -203,6 +207,22 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou
203207
*/
204208
useLayoutEffect(parseFSAttributes, []);
205209

210+
const shouldShowProductTrainingTooltip = useMemo(() => {
211+
return shouldShow && shouldRenderTooltip(tooltipName) && !shouldHideToolTip;
212+
}, [shouldRenderTooltip, tooltipName, shouldShow, shouldHideToolTip]);
213+
214+
const hideTooltip = useCallback(
215+
(isDismissedUsingCloseButton = false) => {
216+
if (!shouldShowProductTrainingTooltip) {
217+
return;
218+
}
219+
const tooltip = TOOLTIPS[tooltipName];
220+
tooltip.onHideTooltip(isDismissedUsingCloseButton);
221+
unregisterTooltip(tooltipName);
222+
},
223+
[tooltipName, shouldShowProductTrainingTooltip, unregisterTooltip],
224+
);
225+
206226
const renderProductTrainingTooltip = useCallback(() => {
207227
const tooltip = TOOLTIPS[tooltipName];
208228
return (
@@ -218,7 +238,8 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou
218238
styles.flexWrap,
219239
styles.textAlignCenter,
220240
styles.gap3,
221-
styles.p2,
241+
styles.pv2,
242+
styles.ph1,
222243
]}
223244
>
224245
<Icon
@@ -239,6 +260,37 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou
239260
);
240261
})}
241262
</Text>
263+
{!tooltip?.shouldRenderActionButtons && (
264+
<PressableWithoutFeedback
265+
// On some Samsung devices, `onPress` is never triggered.
266+
// So, we use `onPressIn` for Android to ensure the button is pressable.
267+
onPressIn={
268+
getPlatform() === CONST.PLATFORM.ANDROID
269+
? () => {
270+
hideTooltip(true);
271+
}
272+
: undefined
273+
}
274+
// For other platforms, we stick with `onPress`.
275+
onPress={
276+
getPlatform() !== CONST.PLATFORM.ANDROID
277+
? () => {
278+
hideTooltip(true);
279+
}
280+
: undefined
281+
}
282+
shouldUseAutoHitSlop
283+
accessibilityLabel={translate('productTrainingTooltip.scanTestTooltip.noThanks')}
284+
role={CONST.ROLE.BUTTON}
285+
>
286+
<Icon
287+
src={Expensicons.Close}
288+
fill={theme.icon}
289+
width={variables.iconSizeSemiSmall}
290+
height={variables.iconSizeSemiSmall}
291+
/>
292+
</PressableWithoutFeedback>
293+
)}
242294
</View>
243295
{!!tooltip?.shouldRenderActionButtons && (
244296
<View style={[styles.alignItemsCenter, styles.justifyContentBetween, styles.flexRow, styles.ph2, styles.pv2, styles.gap2]}>
@@ -258,42 +310,35 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou
258310
</View>
259311
);
260312
}, [
261-
config.onConfirm,
262-
config.onDismiss,
313+
tooltipName,
263314
styles.alignItemsCenter,
264-
styles.flex1,
265315
styles.flexRow,
316+
styles.justifyContentStart,
317+
styles.justifyContentCenter,
266318
styles.flexWrap,
319+
styles.textAlignCenter,
267320
styles.gap3,
268-
styles.justifyContentBetween,
269-
styles.justifyContentCenter,
270-
styles.mw100,
271-
styles.p2,
272-
styles.productTrainingTooltipText,
273321
styles.pv2,
274-
styles.textAlignCenter,
275-
styles.textBold,
322+
styles.ph1,
323+
styles.productTrainingTooltipText,
276324
styles.textWrap,
277-
styles.gap2,
278-
styles.justifyContentStart,
325+
styles.mw100,
326+
styles.flex1,
327+
styles.justifyContentBetween,
279328
styles.ph2,
329+
styles.gap2,
330+
styles.textBold,
280331
theme.tooltipHighlightText,
281-
tooltipName,
332+
theme.icon,
282333
translate,
334+
config.onConfirm,
335+
config.onDismiss,
336+
hideTooltip,
283337
]);
284338

285-
const shouldShowProductTrainingTooltip = useMemo(() => {
286-
return shouldShow && shouldRenderTooltip(tooltipName) && !shouldHideToolTip;
287-
}, [shouldRenderTooltip, tooltipName, shouldShow, shouldHideToolTip]);
288-
289339
const hideProductTrainingTooltip = useCallback(() => {
290-
if (!shouldShowProductTrainingTooltip) {
291-
return;
292-
}
293-
const tooltip = TOOLTIPS[tooltipName];
294-
tooltip.onHideTooltip();
295-
unregisterTooltip(tooltipName);
296-
}, [tooltipName, shouldShowProductTrainingTooltip, unregisterTooltip]);
340+
hideTooltip(false);
341+
}, [hideTooltip]);
297342

298343
return {
299344
renderProductTrainingTooltip,

src/hooks/useOnboardingFlow.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {startOnboardingFlow} from '@libs/actions/Welcome/OnboardingFlow';
66
import Navigation from '@libs/Navigation/Navigation';
77
import {hasCompletedGuidedSetupFlowSelector, tryNewDotOnyxSelector} from '@libs/onboardingSelectors';
88
import {buildCannedSearchQuery} from '@libs/SearchQueryUtils';
9+
import isProductTrainingElementDismissed from '@libs/TooltipUtils';
910
import CONFIG from '@src/CONFIG';
1011
import ONYXKEYS from '@src/ONYXKEYS';
1112
import ROUTES from '@src/ROUTES';
@@ -45,8 +46,7 @@ function useOnboardingFlowRouter() {
4546
if (CONFIG.IS_HYBRID_APP && isLoadingOnyxValue(isSingleNewDotEntryMetadata)) {
4647
return;
4748
}
48-
49-
if (hasBeenAddedToNudgeMigration && !dismissedProductTraining?.migratedUserWelcomeModal) {
49+
if (hasBeenAddedToNudgeMigration && !isProductTrainingElementDismissed('migratedUserWelcomeModal', dismissedProductTraining)) {
5050
const defaultCannedQuery = buildCannedSearchQuery();
5151
const query = defaultCannedQuery;
5252
Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query}));
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
type DismissProductTrainingParams = {
22
name: string;
3+
dismissedMethod: 'x' | 'click';
34
};
45

56
export default DismissProductTrainingParams;

src/libs/TooltipUtils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type {OnyxEntry} from 'react-native-onyx';
2+
import type {DismissedProductTraining} from '@src/types/onyx';
3+
4+
function isProductTrainingElementDismissed(elementName: keyof DismissedProductTraining, dismissedProductTraining: OnyxEntry<DismissedProductTraining>) {
5+
return typeof dismissedProductTraining?.[elementName] === 'string' ? !!dismissedProductTraining?.[elementName] : !!dismissedProductTraining?.[elementName]?.timestamp;
6+
}
7+
8+
export default isProductTrainingElementDismissed;

src/libs/actions/Report.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4869,11 +4869,14 @@ function dismissChangePolicyModal() {
48694869
onyxMethod: Onyx.METHOD.MERGE,
48704870
key: ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING,
48714871
value: {
4872-
[CONST.CHANGE_POLICY_TRAINING_MODAL]: DateUtils.getDBTime(date.valueOf()),
4872+
[CONST.CHANGE_POLICY_TRAINING_MODAL]: {
4873+
timestamp: DateUtils.getDBTime(date.valueOf()),
4874+
dismissedMethod: 'click',
4875+
},
48734876
},
48744877
},
48754878
];
4876-
API.write(WRITE_COMMANDS.DISMISS_PRODUCT_TRAINING, {name: CONST.CHANGE_POLICY_TRAINING_MODAL}, {optimisticData});
4879+
API.write(WRITE_COMMANDS.DISMISS_PRODUCT_TRAINING, {name: CONST.CHANGE_POLICY_TRAINING_MODAL, dismissedMethod: 'click'}, {optimisticData});
48774880
}
48784881

48794882
/**

src/libs/actions/Welcome/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,18 +207,22 @@ function setSelfTourViewed(shouldUpdateOnyxDataOnlyLocally = false) {
207207
API.write(WRITE_COMMANDS.SELF_TOUR_VIEWED, null, {optimisticData});
208208
}
209209

210-
function dismissProductTraining(elementName: string) {
210+
function dismissProductTraining(elementName: string, isDismissedUsingCloseButton = false) {
211211
const date = new Date();
212+
const dismissedMethod = isDismissedUsingCloseButton ? 'x' : 'click';
212213
const optimisticData = [
213214
{
214215
onyxMethod: Onyx.METHOD.MERGE,
215216
key: ONYXKEYS.NVP_DISMISSED_PRODUCT_TRAINING,
216217
value: {
217-
[elementName]: DateUtils.getDBTime(date.valueOf()),
218+
[elementName]: {
219+
timestamp: DateUtils.getDBTime(date.valueOf()),
220+
dismissedMethod,
221+
},
218222
},
219223
},
220224
];
221-
API.write(WRITE_COMMANDS.DISMISS_PRODUCT_TRAINING, {name: elementName}, {optimisticData});
225+
API.write(WRITE_COMMANDS.DISMISS_PRODUCT_TRAINING, {name: elementName, dismissedMethod}, {optimisticData});
222226
}
223227

224228
export {

src/pages/iou/request/step/IOURequestStepScan/index.native.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ function IOURequestStepScan({
536536
{
537537
onConfirm: setTestReceiptAndNavigate,
538538
onDismiss: () => {
539-
dismissProductTraining(CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP);
539+
dismissProductTraining(CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP, true);
540540
},
541541
},
542542
);

src/pages/iou/request/step/IOURequestStepScan/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ function IOURequestStepScan({
590590
{
591591
onConfirm: setTestReceiptAndNavigate,
592592
onDismiss: () => {
593-
dismissProductTraining(CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP);
593+
dismissProductTraining(CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP, true);
594594
},
595595
},
596596
);

0 commit comments

Comments
 (0)