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

[Hold #54924] Show Product tooltip for Workspace participant on create expense #56041

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6693,6 +6693,7 @@ const CONST = {
LHN_WORKSPACE_CHAT_TOOLTIP: 'workspaceChatLHNTooltip',
GLOBAL_CREATE_TOOLTIP: 'globalCreateTooltip',
SCAN_TEST_TOOLTIP: 'scanTestTooltip',
WORKSPACE_EXPENSE_SUBMIT: 'workspaceExpenseSubmit',
SCAN_TEST_TOOLTIP_MANAGER: 'scanTestTooltipManager',
SCAN_TEST_CONFIRMATION: 'scanTestConfirmation',
},
Expand Down
17 changes: 17 additions & 0 deletions src/components/ProductTrainingContext/TOOLTIPS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const {
LHN_WORKSPACE_CHAT_TOOLTIP,
GLOBAL_CREATE_TOOLTIP,
SCAN_TEST_TOOLTIP,
WORKSPACE_EXPENSE_SUBMIT,
SCAN_TEST_TOOLTIP_MANAGER,
SCAN_TEST_CONFIRMATION,
} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;
Expand All @@ -29,6 +30,7 @@ type TooltipData = {
name: ProductTrainingTooltipName;
priority: number;
shouldShow: (props: ShouldShowConditionProps) => boolean;
isModalTooltip?: boolean;
shouldRenderActionButtons?: boolean;
};

Expand Down Expand Up @@ -73,6 +75,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: QUICK_ACTION_BUTTON,
priority: 1150,
shouldShow: () => true,
isModalTooltip: true,
},
[WORKSAPCE_CHAT_CREATE]: {
content: [
Expand Down Expand Up @@ -127,6 +130,18 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
priority: 900,
shouldShow: () => true,
shouldRenderActionButtons: true,
isModalTooltip: true,
},
[WORKSPACE_EXPENSE_SUBMIT]: {
content: [
{text: 'productTrainingTooltip.workspaceExpenseSubmit.part1', isBold: true},
{text: 'productTrainingTooltip.workspaceExpenseSubmit.part2', isBold: false},
],
onHideTooltip: () => dismissProductTraining(WORKSPACE_EXPENSE_SUBMIT),
name: WORKSPACE_EXPENSE_SUBMIT,
priority: 200,
shouldShow: () => true,
isModalTooltip: true,
},
[SCAN_TEST_TOOLTIP_MANAGER]: {
content: [
Expand All @@ -138,6 +153,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: SCAN_TEST_TOOLTIP_MANAGER,
priority: 1000,
shouldShow: () => true,
isModalTooltip: true,
},
[SCAN_TEST_CONFIRMATION]: {
content: [
Expand All @@ -149,6 +165,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: SCAN_TEST_CONFIRMATION,
priority: 1100,
shouldShow: () => true,
isModalTooltip: true,
},
};

Expand Down
10 changes: 2 additions & 8 deletions src/components/ProductTrainingContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,8 @@ 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 &&
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP &&
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP_MANAGER &&
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_CONFIRMATION &&
isModalVisible
) {
// We need to make an exception if tooltip is shown in a modal, otherwise it would be hidden if a modal is visible
if (!tooltipConfig.isModalTooltip && isModalVisible) {
return false;
}

Expand Down
5 changes: 4 additions & 1 deletion src/components/SelectionList/BaseSelectionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ function BaseSelectionList<TItem extends ListItem>(
listItemTitleStyles,
initialNumToRender = 12,
listItemTitleContainerStyles,
shouldShowEducationalTooltip = () => false,
isScreenFocused = false,
shouldSubscribeToArrowKeyEvents = true,
}: BaseSelectionListProps<TItem>,
Expand Down Expand Up @@ -538,7 +539,8 @@ function BaseSelectionList<TItem extends ListItem>(
</>
);

const renderItem = ({item, index, section}: SectionListRenderItemInfo<TItem, SectionWithIndexOffset<TItem>>) => {
const renderItem = (data: SectionListRenderItemInfo<TItem, SectionWithIndexOffset<TItem>>) => {
const {item, index, section} = data;
const normalizedIndex = index + (section?.indexOffset ?? 0);
const isDisabled = !!section.isDisabled || item.isDisabled;
const isItemFocused = (!isDisabled || item.isSelected) && focusedIndex === normalizedIndex;
Expand Down Expand Up @@ -576,6 +578,7 @@ function BaseSelectionList<TItem extends ListItem>(
shouldHighlightSelectedItem={shouldHighlightSelectedItem}
singleExecution={singleExecution}
titleContainerStyles={listItemTitleContainerStyles}
shouldShowEducationalTooltip={shouldShowEducationalTooltip(data)}
/>
</View>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type BaseSelectionListItemRendererProps<TItem extends ListItem> = Omit<BaseListI
singleExecution: ReturnType<typeof useSingleExecution>['singleExecution'];
titleStyles?: StyleProp<TextStyle>;
titleContainerStyles?: StyleProp<ViewStyle>;
shouldShowEducationalTooltip?: boolean;
};

function BaseSelectionListItemRenderer<TItem extends ListItem>({
Expand Down Expand Up @@ -44,6 +45,7 @@ function BaseSelectionListItemRenderer<TItem extends ListItem>({
titleStyles,
singleExecution,
titleContainerStyles,
shouldShowEducationalTooltip,
}: BaseSelectionListItemRendererProps<TItem>) {
const handleOnCheckboxPress = () => {
if (isReportListItemType(item)) {
Expand Down Expand Up @@ -94,6 +96,7 @@ function BaseSelectionListItemRenderer<TItem extends ListItem>({
wrapperStyle={wrapperStyle}
titleStyles={titleStyles}
titleContainerStyles={titleContainerStyles}
shouldShowEducationalTooltip={shouldShowEducationalTooltip}
/>
{item.footerContent && item.footerContent}
</>
Expand Down
32 changes: 28 additions & 4 deletions src/components/SelectionList/InviteMemberListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Str} from 'expensify-common';
import React, {useCallback} from 'react';
import React, {useCallback, useMemo} from 'react';
import {View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import {FallbackAvatar} from '@components/Icon/Expensicons';
Expand All @@ -17,6 +17,7 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import {getIsUserSubmittedExpenseOrScannedReceipt, isSelectedManagerMcTest} from '@libs/OptionsListUtils';
import Permissions from '@libs/Permissions';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Icon} from '@src/types/onyx/OnyxCommon';
Expand All @@ -43,6 +44,7 @@ function InviteMemberListItem<TItem extends ListItem>({
onFocus,
shouldSyncFocus,
shouldHighlightSelectedItem,
shouldShowEducationalTooltip = false,
}: InviteMemberListItemProps<TItem>) {
const styles = useThemeStyles();
const theme = useTheme();
Expand All @@ -60,6 +62,12 @@ function InviteMemberListItem<TItem extends ListItem>({

const shouldShowCheckBox = canSelectMultiple && !item.isDisabled;

const {
renderProductTrainingTooltip: renderExpenseSubmitTooltip,
shouldShowProductTrainingTooltip: shouldShowExpenseSubmitTooltip,
hideProductTrainingTooltip: hideExpenseSubmitTooltip,
} = useProductTrainingContext(CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.WORKSPACE_EXPENSE_SUBMIT, shouldShowEducationalTooltip);

const handleCheckboxPress = useCallback(() => {
if (onCheckboxPress) {
onCheckboxPress(item);
Expand All @@ -68,6 +76,23 @@ function InviteMemberListItem<TItem extends ListItem>({
}
}, [item, onCheckboxPress, onSelectRow]);

const educationalTooltipProps = useMemo(() => {
if (shouldShowExpenseSubmitTooltip) {
return {
shouldRender: shouldShowExpenseSubmitTooltip,
shiftHorizontal: variables.rhnOptionsTooltipShiftHorizontal,
shiftVertical: variables.rhnOptionsTooltipShiftVertical,
renderTooltipContent: renderExpenseSubmitTooltip,
onTooltipPress: hideExpenseSubmitTooltip,
};
}
return {
shouldRender: shouldShowProductTrainingTooltip,
renderTooltipContent: renderProductTrainingTooltip,
shouldHideOnNavigate: true,
};
}, [hideExpenseSubmitTooltip, renderExpenseSubmitTooltip, renderProductTrainingTooltip, shouldShowExpenseSubmitTooltip, shouldShowProductTrainingTooltip]);

return (
<BaseListItem
pressableStyle={[[shouldHighlightSelectedItem && item.isSelected && styles.activeComponentBG]]}
Expand Down Expand Up @@ -96,14 +121,13 @@ function InviteMemberListItem<TItem extends ListItem>({
>
{(hovered?: boolean) => (
<EducationalTooltip
shouldRender={shouldShowProductTrainingTooltip}
renderTooltipContent={renderProductTrainingTooltip}
anchorAlignment={{
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
}}
shouldHideOnNavigate
wrapperStyle={styles.productTrainingTooltipWrapper}
// eslint-disable-next-line react/jsx-props-no-spreading
{...educationalTooltipProps}
>
<View style={[styles.flexRow, styles.alignItemsCenter, styles.flex1]}>
{!!item.icons &&
Expand Down
9 changes: 8 additions & 1 deletion src/components/SelectionList/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
NativeScrollEvent,
NativeSyntheticEvent,
SectionListData,
SectionListRenderItemInfo,
StyleProp,
TargetedEvent,
TextInput,
Expand Down Expand Up @@ -344,7 +345,10 @@ type UserListItemProps<TItem extends ListItem> = ListItemProps<TItem> & {
FooterComponent?: ReactElement;
};

type InviteMemberListItemProps<TItem extends ListItem> = UserListItemProps<TItem>;
type InviteMemberListItemProps<TItem extends ListItem> = UserListItemProps<TItem> & {
/** Whether to show the educational tooltip */
shouldShowEducationalTooltip?: boolean;
};

type RadioListItemProps<TItem extends ListItem> = ListItemProps<TItem>;

Expand Down Expand Up @@ -666,6 +670,9 @@ type BaseSelectionListProps<TItem extends ListItem> = Partial<ChildrenProps> & {
/** Initial number of items to render */
initialNumToRender?: number;

/** Should we show the workspace expense tooltip on the listItem */
shouldShowEducationalTooltip?: (data: SectionListRenderItemInfo<TItem, SectionWithIndexOffset<TItem>>) => boolean;

/** Whether the screen is focused or not. (useIsFocused state does not work in tab screens, e.g. SearchPageBottomTab) */
isScreenFocused?: boolean;
} & TRightHandSideComponent<TItem>;
Expand Down
4 changes: 4 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5955,6 +5955,10 @@ const translations = {
tryItOut: 'Try it out',
noThanks: 'No thanks',
},
workspaceExpenseSubmit: {
part1: 'Submit expenses',
part2: ' to your company here',
},
},
discardChangesConfirmation: {
title: 'Discard changes?',
Expand Down
4 changes: 4 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6477,6 +6477,10 @@ const translations = {
tryItOut: 'Prueba esto',
noThanks: 'No, gracias',
},
workspaceExpenseSubmit: {
part1: 'Envía gastos',
part2: ' a tu empresa aquí',
},
},
discardChangesConfirmation: {
title: '¿Descartar cambios?',
Expand Down
17 changes: 16 additions & 1 deletion src/pages/iou/request/MoneyRequestParticipantsSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import lodashIsEqual from 'lodash/isEqual';
import lodashPick from 'lodash/pick';
import lodashReject from 'lodash/reject';
import React, {memo, useCallback, useEffect, useMemo} from 'react';
import type {GestureResponderEvent} from 'react-native';
import type {GestureResponderEvent, SectionListRenderItemInfo} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import Button from '@components/Button';
import EmptySelectionListContent from '@components/EmptySelectionListContent';
Expand All @@ -12,6 +12,7 @@ import {useOptionsList} from '@components/OptionListContextProvider';
import ReferralProgramCTA from '@components/ReferralProgramCTA';
import SelectionList from '@components/SelectionList';
import InviteMemberListItem from '@components/SelectionList/InviteMemberListItem';
import type {SectionWithIndexOffset} from '@components/SelectionList/types';
import useDebouncedState from '@hooks/useDebouncedState';
import useDismissedReferralBanners from '@hooks/useDismissedReferralBanners';
import useLocalize from '@hooks/useLocalize';
Expand Down Expand Up @@ -440,6 +441,19 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF
[isIOUSplit, addParticipantToSelection, addSingleParticipant],
);

const showCreateExpenseTooltip = useCallback(
({index, section}: SectionListRenderItemInfo<Participant, SectionWithIndexOffset<Participant>>) => {
const expenseIOUActions: IOUAction[] = [CONST.IOU.ACTION.CREATE];
const expenseIOUTypes: IOUType[] = [CONST.IOU.TYPE.CREATE];
if (!expenseIOUActions.includes(action) || !expenseIOUTypes.includes(iouType)) {
return false;
}

return section.title === translate('workspace.common.workspace') && index === 0 && section.indexOffset === 0;
},
[translate, action, iouType],
);

return (
<SelectionList
onConfirm={handleConfirmSelection}
Expand All @@ -450,6 +464,7 @@ function MoneyRequestParticipantsSelector({participants = CONST.EMPTY_ARRAY, onF
textInputHint={offlineMessage}
onChangeText={setSearchTerm}
shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()}
shouldShowEducationalTooltip={showCreateExpenseTooltip}
onSelectRow={onSelectRow}
shouldSingleExecuteRowSelect
footerContent={footerContent}
Expand Down
2 changes: 2 additions & 0 deletions src/styles/variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ export default {
searchFiltersTooltipShiftHorizontalNarrow: -10,
searchFiltersTooltipShiftVerticalNarrow: 5,
bottomTabInboxTooltipShiftHorizontal: 36,
rhnOptionsTooltipShiftHorizontal: 4,
rhnOptionsTooltipShiftVertical: -10,

inlineImagePreviewMinSize: 64,
inlineImagePreviewMaxSize: 148,
Expand Down
6 changes: 6 additions & 0 deletions src/types/onyx/DismissedProductTraining.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const {
LHN_WORKSPACE_CHAT_TOOLTIP,
GLOBAL_CREATE_TOOLTIP,
SCAN_TEST_TOOLTIP,
WORKSPACE_EXPENSE_SUBMIT,
SCAN_TEST_TOOLTIP_MANAGER,
SCAN_TEST_CONFIRMATION,
} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;
Expand Down Expand Up @@ -67,6 +68,11 @@ type DismissedProductTraining = {
*/
[SCAN_TEST_TOOLTIP]: string;

/**
* When user dismisses the workspaceExpenseTooltip product training tooltip, we store the timestamp here.
*/
[WORKSPACE_EXPENSE_SUBMIT]: string;

/**
* When user dismisses the test manager tooltip product training tooltip, we store the timestamp here.
*/
Expand Down