Skip to content

Commit

Permalink
Merge pull request #54064 from ishpaul777/new-product-training-tooltips
Browse files Browse the repository at this point in the history
  • Loading branch information
puneetlath authored Dec 13, 2024
2 parents f60ba09 + f22bbc2 commit 12de96f
Show file tree
Hide file tree
Showing 22 changed files with 449 additions and 186 deletions.
4 changes: 4 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6441,6 +6441,10 @@ const CONST = {
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;

Expand Down
75 changes: 51 additions & 24 deletions src/components/FloatingActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ 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';
Expand Down Expand Up @@ -56,6 +62,14 @@ function FloatingActionButton({onPress, isActive, accessibilityLabel, role}: Flo
const styles = useThemeStyles();
const borderRadius = styles.floatingActionButton.borderRadius;
const fabPressable = useRef<HTMLDivElement | View | Text | null>(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;

Expand Down Expand Up @@ -97,32 +111,45 @@ function FloatingActionButton({onPress, isActive, accessibilityLabel, role}: Flo
};

return (
<PressableWithoutFeedback
ref={(el) => {
fabPressable.current = el ?? null;
if (buttonRef && 'current' in buttonRef) {
buttonRef.current = el ?? null;
}
<EducationalTooltip
shouldRender={shouldShowProductTrainingTooltip}
anchorAlignment={{
horizontal: isNarrowScreenOnWeb ? CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.CENTER : CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
}}
style={[styles.h100, styles.bottomTabBarItem]}
accessibilityLabel={accessibilityLabel}
onPress={toggleFabAction}
onLongPress={() => {}}
role={role}
shouldUseHapticsOnLongPress={false}
shouldUseOverlay
shiftHorizontal={isNarrowScreenOnWeb ? 0 : variables.fabTooltipShiftHorizontal}
renderTooltipContent={renderProductTrainingTooltip}
wrapperStyle={styles.productTrainingTooltipWrapper}
onHideTooltip={hideProductTrainingTooltip}
>
<Animated.View style={[styles.floatingActionButton, animatedStyle]}>
<Svg
width={variables.iconSizeNormal}
height={variables.iconSizeNormal}
>
<AnimatedPath
d="M12,3c0-1.1-0.9-2-2-2C8.9,1,8,1.9,8,3v5H3c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2h5v5c0,1.1,0.9,2,2,2c1.1,0,2-0.9,2-2v-5h5c1.1,0,2-0.9,2-2c0-1.1-0.9-2-2-2h-5V3z"
animatedProps={animatedProps}
/>
</Svg>
</Animated.View>
</PressableWithoutFeedback>
<PressableWithoutFeedback
ref={(el) => {
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}
>
<Animated.View style={[styles.floatingActionButton, animatedStyle]}>
<Svg
width={variables.iconSizeNormal}
height={variables.iconSizeNormal}
>
<AnimatedPath
d="M12,3c0-1.1-0.9-2-2-2C8.9,1,8,1.9,8,3v5H3c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2h5v5c0,1.1,0.9,2,2,2c1.1,0,2-0.9,2-2v-5h5c1.1,0,2-0.9,2-2c0-1.1-0.9-2-2-2h-5V3z"
animatedProps={animatedProps}
/>
</Svg>
</Animated.View>
</PressableWithoutFeedback>
</EducationalTooltip>
);
}

Expand Down
33 changes: 18 additions & 15 deletions src/components/LHNOptionsList/OptionRowLHN.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useFocusEffect} from '@react-navigation/native';
import React, {useCallback, useRef, useState} from 'react';
import React, {useCallback, useMemo, useRef, useState} from 'react';
import type {GestureResponderEvent, ViewStyle} from 'react-native';
import {StyleSheet, View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
Expand Down Expand Up @@ -47,19 +47,21 @@ 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 [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
const session = useSession();

// Guides are assigned for the MANAGE_TEAM onboarding action, except for emails that have a '+'.
const isOnboardingGuideAssigned = introSelected?.choice === CONST.ONBOARDING_CHOICES.MANAGE_TEAM && !session?.email?.includes('+');
const shouldShowToooltipOnThisReport = isOnboardingGuideAssigned ? ReportUtils.isAdminRoom(report) : ReportUtils.isConciergeChatReport(report);
const shouldShowGetStartedTooltip = isOnboardingGuideAssigned ? ReportUtils.isAdminRoom(report) : ReportUtils.isConciergeChatReport(report);

const shouldShowGetStartedTooltip = shouldShowToooltipOnThisReport && isScreenFocused;
const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.CONCEIRGE_LHN_GBR,
shouldShowGetStartedTooltip,
);
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]);

const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(tooltipToRender, shouldShowTooltip);
const {translate} = useLocalize();
const [isContextMenuActive, setIsContextMenuActive] = useState(false);

Expand Down Expand Up @@ -156,17 +158,18 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti
needsOffscreenAlphaCompositing
>
<EducationalTooltip
shouldRender={shouldShowProductTrainingTooltip}
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
shouldRender={shouldShowProductTrainingTooltip && (isActiveWorkspaceChat || shouldShowGetStartedTooltip)}
renderTooltipContent={renderProductTrainingTooltip}
anchorAlignment={{
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
horizontal: isActiveWorkspaceChat ? CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT : CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
}}
shouldUseOverlay
shiftHorizontal={variables.gbrTooltipShiftHorizontal}
shiftHorizontal={isActiveWorkspaceChat ? variables.workspaceLHNtooltipShiftHorizontal : variables.gbrTooltipShiftHorizontal}
shiftVertical={isActiveWorkspaceChat ? 0 : variables.composerTooltipShiftVertical}
onHideTooltip={hideProductTrainingTooltip}
shiftVertical={variables.composerTooltipShiftVertical}
wrapperStyle={styles.quickActionTooltipWrapper}
wrapperStyle={styles.productTrainingTooltipWrapper}
>
<View>
<Hoverable>
Expand Down

This file was deleted.

118 changes: 118 additions & 0 deletions src/components/ProductTrainingContext/TOOLTIPS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
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<typeof CONST.PRODUCT_TRAINING_TOOLTIP_NAMES>;

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<ProductTrainingTooltipName, TooltipData> = {
[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};
Loading

0 comments on commit 12de96f

Please sign in to comment.