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

Show Product tooltip for Workspace participant on create expense #56041

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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 @@ -6517,6 +6517,7 @@ const CONST = {
LHN_WORKSPACE_CHAT_TOOLTIP: 'workspaceChatLHNTooltip',
GLOBAL_CREATE_TOOLTIP: 'globalCreateTooltip',
SCAN_TEST_TOOLTIP: 'scanTestTooltip',
WORKSPACE_EXPENSE: 'workspaceExpenseTooltip',
},
SMART_BANNER_HEIGHT: 152,
TRAVEL: {
Expand Down
22 changes: 22 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,
} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;

type ProductTrainingTooltipName = ValueOf<typeof CONST.PRODUCT_TRAINING_TOOLTIP_NAMES>;
Expand All @@ -27,6 +28,7 @@ type TooltipData = {
name: ProductTrainingTooltipName;
priority: number;
shouldShow: (props: ShouldShowConditionProps) => boolean;
isModalTooltip: boolean;
};

const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
Expand All @@ -39,6 +41,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: CONCEIRGE_LHN_GBR,
priority: 1300,
shouldShow: ({shouldUseNarrowLayout}) => !!shouldUseNarrowLayout,
isModalTooltip: false,
},
[RENAME_SAVED_SEARCH]: {
content: [
Expand All @@ -49,6 +52,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: RENAME_SAVED_SEARCH,
priority: 1250,
shouldShow: ({shouldUseNarrowLayout}) => !shouldUseNarrowLayout,
isModalTooltip: false,
},
[GLOBAL_CREATE_TOOLTIP]: {
content: [
Expand All @@ -60,6 +64,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: GLOBAL_CREATE_TOOLTIP,
priority: 1200,
shouldShow: () => true,
isModalTooltip: false,
},
[QUICK_ACTION_BUTTON]: {
content: [
Expand All @@ -70,6 +75,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: QUICK_ACTION_BUTTON,
priority: 1150,
shouldShow: () => true,
isModalTooltip: true,
},
[WORKSAPCE_CHAT_CREATE]: {
content: [
Expand All @@ -81,6 +87,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: WORKSAPCE_CHAT_CREATE,
priority: 1100,
shouldShow: () => true,
isModalTooltip: false,
},
[SEARCH_FILTER_BUTTON_TOOLTIP]: {
content: [
Expand All @@ -91,6 +98,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: SEARCH_FILTER_BUTTON_TOOLTIP,
priority: 1000,
shouldShow: () => true,
isModalTooltip: false,
},
[BOTTOM_NAV_INBOX_TOOLTIP]: {
content: [
Expand All @@ -102,6 +110,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: BOTTOM_NAV_INBOX_TOOLTIP,
priority: 900,
shouldShow: () => true,
isModalTooltip: false,
},
[LHN_WORKSPACE_CHAT_TOOLTIP]: {
content: [
Expand All @@ -113,6 +122,7 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: LHN_WORKSPACE_CHAT_TOOLTIP,
priority: 800,
shouldShow: () => true,
isModalTooltip: false,
},
[SCAN_TEST_TOOLTIP]: {
content: [
Expand All @@ -129,6 +139,18 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
name: SCAN_TEST_TOOLTIP,
priority: 900,
shouldShow: () => false,
isModalTooltip: false,
},
[WORKSPACE_EXPENSE]: {
content: [
{text: 'productTrainingTooltip.workspaceExpenseTooltip.part1', isBold: true},
{text: 'productTrainingTooltip.workspaceExpenseTooltip.part2', isBold: false},
],
onHideTooltip: () => dismissProductTraining(WORKSPACE_EXPENSE),
name: WORKSPACE_EXPENSE,
priority: 200,
shouldShow: () => true,
isModalTooltip: true,
},
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/ProductTrainingContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ function ProductTrainingContextProvider({children}: ChildrenProps) {
}

// 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) {
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 @@ -122,6 +122,7 @@ function BaseSelectionList<TItem extends ListItem>(
listItemTitleStyles,
initialNumToRender = 12,
listItemTitleContainerStyles,
shouldShowEducationalTooltip = () => false,
}: BaseSelectionListProps<TItem>,
ref: ForwardedRef<SelectionListHandle>,
) {
Expand Down Expand Up @@ -517,7 +518,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 @@ -555,6 +557,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
193 changes: 109 additions & 84 deletions src/components/SelectionList/InviteMemberListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import {View} from 'react-native';
import {FallbackAvatar} from '@components/Icon/Expensicons';
import MultipleAvatars from '@components/MultipleAvatars';
import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
import {useProductTrainingContext} from '@components/ProductTrainingContext';
import SelectCircle from '@components/SelectCircle';
import SubscriptAvatar from '@components/SubscriptAvatar';
import Text from '@components/Text';
import TextWithTooltip from '@components/TextWithTooltip';
import EducationalTooltip from '@components/Tooltip/EducationalTooltip';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import type {Icon} from '@src/types/onyx/OnyxCommon';
import BaseListItem from './BaseListItem';
Expand All @@ -37,6 +40,7 @@ function InviteMemberListItem<TItem extends ListItem>({
onFocus,
shouldSyncFocus,
shouldHighlightSelectedItem,
shouldShowEducationalTooltip = false,
}: InviteMemberListItemProps<TItem>) {
const styles = useThemeStyles();
const theme = useTheme();
Expand All @@ -49,6 +53,11 @@ function InviteMemberListItem<TItem extends ListItem>({

const shouldShowCheckBox = canSelectMultiple && !item.isDisabled;

const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.WORKSPACE_EXPENSE,
shouldShowEducationalTooltip,
);

const handleCheckboxPress = useCallback(() => {
if (onCheckboxPress) {
onCheckboxPress(item);
Expand All @@ -58,92 +67,108 @@ function InviteMemberListItem<TItem extends ListItem>({
}, [item, onCheckboxPress, onSelectRow]);

return (
<BaseListItem
pressableStyle={[[shouldHighlightSelectedItem && item.isSelected && styles.activeComponentBG]]}
item={item}
wrapperStyle={[styles.flex1, styles.justifyContentBetween, styles.sidebarLinkInner, styles.userSelectNone, styles.peopleRow]}
isFocused={isFocused}
isDisabled={isDisabled}
showTooltip={showTooltip}
canSelectMultiple={canSelectMultiple}
onSelectRow={onSelectRow}
onDismissError={onDismissError}
rightHandSideComponent={rightHandSideComponent}
errors={item.errors}
pendingAction={item.pendingAction}
FooterComponent={
item.invitedSecondaryLogin ? (
<Text style={[styles.ml9, styles.ph5, styles.pb3, styles.textLabelSupporting]}>
{translate('workspace.people.invitedBySecondaryLogin', {secondaryLogin: item.invitedSecondaryLogin})}
</Text>
) : undefined
}
keyForList={item.keyForList}
onFocus={onFocus}
shouldSyncFocus={shouldSyncFocus}
shouldDisplayRBR={!shouldShowCheckBox}
<EducationalTooltip
shouldRender={shouldShowProductTrainingTooltip}
anchorAlignment={{
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
}}
shiftHorizontal={variables.workspaceLHNtooltipShiftHorizontal}
shiftVertical={variables.composerTooltipShiftVertical}
wrapperStyle={styles.productTrainingTooltipWrapper}
renderTooltipContent={renderProductTrainingTooltip}
onTooltipPress={hideProductTrainingTooltip}
>
{(hovered?: boolean) => (
<>
{!!item.icons &&
(item.shouldShowSubscript ? (
<SubscriptAvatar
mainAvatar={item.icons.at(0) ?? fallbackIcon}
secondaryAvatar={item.icons.at(1)}
showTooltip={showTooltip}
backgroundColor={hovered && !isFocused ? hoveredBackgroundColor : subscriptAvatarBorderColor}
/>
) : (
<MultipleAvatars
icons={item.icons}
shouldShowTooltip={showTooltip}
secondAvatarStyle={[
StyleUtils.getBackgroundAndBorderStyle(theme.sidebar),
isFocused ? StyleUtils.getBackgroundAndBorderStyle(focusedBackgroundColor) : undefined,
hovered && !isFocused ? StyleUtils.getBackgroundAndBorderStyle(hoveredBackgroundColor) : undefined,
]}
/>
))}
<View style={[styles.flex1, styles.flexColumn, styles.justifyContentCenter, styles.alignItemsStretch, styles.optionRow]}>
<View style={[styles.flexRow, styles.alignItemsCenter]}>
<TextWithTooltip
shouldShowTooltip={showTooltip}
text={Str.removeSMSDomain(item.text ?? '')}
style={[
styles.optionDisplayName,
isFocused ? styles.sidebarLinkActiveText : styles.sidebarLinkText,
item.isBold !== false && styles.sidebarLinkTextBold,
styles.pre,
item.alternateText ? styles.mb1 : null,
]}
/>
</View>
{!!item.alternateText && (
<TextWithTooltip
shouldShowTooltip={showTooltip}
text={Str.removeSMSDomain(item.alternateText ?? '')}
style={[styles.textLabelSupporting, styles.lh16, styles.pre]}
/>
)}
</View>
{!!item.rightElement && item.rightElement}
{!!shouldShowCheckBox && (
<PressableWithFeedback
onPress={handleCheckboxPress}
disabled={isDisabled}
role={CONST.ROLE.BUTTON}
accessibilityLabel={item.text ?? ''}
style={[styles.ml2, styles.optionSelectCircle]}
>
<SelectCircle
isChecked={item.isSelected ?? false}
selectCircleStyles={styles.ml0}
/>
</PressableWithFeedback>
<View>
<BaseListItem
pressableStyle={[[shouldHighlightSelectedItem && item.isSelected && styles.activeComponentBG]]}
item={item}
wrapperStyle={[styles.flex1, styles.justifyContentBetween, styles.sidebarLinkInner, styles.userSelectNone, styles.peopleRow]}
isFocused={isFocused}
isDisabled={isDisabled}
showTooltip={showTooltip}
canSelectMultiple={canSelectMultiple}
onSelectRow={onSelectRow}
onDismissError={onDismissError}
rightHandSideComponent={rightHandSideComponent}
errors={item.errors}
pendingAction={item.pendingAction}
FooterComponent={
item.invitedSecondaryLogin ? (
<Text style={[styles.ml9, styles.ph5, styles.pb3, styles.textLabelSupporting]}>
{translate('workspace.people.invitedBySecondaryLogin', {secondaryLogin: item.invitedSecondaryLogin})}
</Text>
) : undefined
}
keyForList={item.keyForList}
onFocus={onFocus}
shouldSyncFocus={shouldSyncFocus}
shouldDisplayRBR={!shouldShowCheckBox}
>
{(hovered?: boolean) => (
<>
{!!item.icons &&
(item.shouldShowSubscript ? (
<SubscriptAvatar
mainAvatar={item.icons.at(0) ?? fallbackIcon}
secondaryAvatar={item.icons.at(1)}
showTooltip={showTooltip}
backgroundColor={hovered && !isFocused ? hoveredBackgroundColor : subscriptAvatarBorderColor}
/>
) : (
<MultipleAvatars
icons={item.icons}
shouldShowTooltip={showTooltip}
secondAvatarStyle={[
StyleUtils.getBackgroundAndBorderStyle(theme.sidebar),
isFocused ? StyleUtils.getBackgroundAndBorderStyle(focusedBackgroundColor) : undefined,
hovered && !isFocused ? StyleUtils.getBackgroundAndBorderStyle(hoveredBackgroundColor) : undefined,
]}
/>
))}

<View style={[styles.flex1, styles.flexColumn, styles.justifyContentCenter, styles.alignItemsStretch, styles.optionRow]}>
<View style={[styles.flexRow, styles.alignItemsCenter]}>
<TextWithTooltip
shouldShowTooltip={showTooltip}
text={Str.removeSMSDomain(item.text ?? '')}
style={[
styles.optionDisplayName,
isFocused ? styles.sidebarLinkActiveText : styles.sidebarLinkText,
item.isBold !== false && styles.sidebarLinkTextBold,
styles.pre,
item.alternateText ? styles.mb1 : null,
]}
/>
</View>
{!!item.alternateText && (
<TextWithTooltip
shouldShowTooltip={showTooltip}
text={Str.removeSMSDomain(item.alternateText ?? '')}
style={[styles.textLabelSupporting, styles.lh16, styles.pre]}
/>
)}
</View>
{!!item.rightElement && item.rightElement}
{!!shouldShowCheckBox && (
<PressableWithFeedback
onPress={handleCheckboxPress}
disabled={isDisabled}
role={CONST.ROLE.BUTTON}
accessibilityLabel={item.text ?? ''}
style={[styles.ml2, styles.optionSelectCircle]}
>
<SelectCircle
isChecked={item.isSelected ?? false}
selectCircleStyles={styles.ml0}
/>
</PressableWithFeedback>
)}
</>
)}
</>
)}
</BaseListItem>
</BaseListItem>
</View>
</EducationalTooltip>
);
}

Expand Down
Loading
Loading