Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d00e200
Add test recipt toolstips to IOU Scan start page
kubabutkiewicz Feb 10, 2025
48e1b1b
add tooltip to manager mctest recipient
kubabutkiewicz Feb 11, 2025
542c3cb
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Feb 11, 2025
70aa35a
added new tooltip for recipents view for trying manager mc test
kubabutkiewicz Feb 11, 2025
f06c76c
removed log
kubabutkiewicz Feb 11, 2025
85cfe40
fix styling
kubabutkiewicz Feb 11, 2025
251ce24
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Feb 12, 2025
d406483
add last tooltip for manager mctest
kubabutkiewicz Feb 12, 2025
df45451
resolve comment
kubabutkiewicz Feb 13, 2025
e3e53aa
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Feb 13, 2025
ff9e9d9
fix navigation issues
kubabutkiewicz Feb 13, 2025
3103933
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Feb 13, 2025
b1a180e
fix test
kubabutkiewicz Feb 13, 2025
d300a34
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Feb 14, 2025
e27157d
resolve comments
kubabutkiewicz Feb 14, 2025
684569d
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Feb 17, 2025
bc1cc21
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Feb 18, 2025
6602c34
Merge branch 'main' of github.com:callstack-internal/Expensify-App in…
kubabutkiewicz Feb 19, 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
2 changes: 2 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6656,6 +6656,8 @@ const CONST = {
LHN_WORKSPACE_CHAT_TOOLTIP: 'workspaceChatLHNTooltip',
GLOBAL_CREATE_TOOLTIP: 'globalCreateTooltip',
SCAN_TEST_TOOLTIP: 'scanTestTooltip',
SCAN_TEST_TOOLTIP_MANAGER: 'scanTestTooltipManager',
SCAN_TEST_CONFIRMATION: 'scanTestConfirmation',
},
SMART_BANNER_HEIGHT: 152,

Expand Down
42 changes: 38 additions & 4 deletions src/components/MoneyRequestConfirmationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import {calculateAmount, insertTagIntoTransactionTagsString, isMovingTransaction
import Log from '@libs/Log';
import {validateAmount} from '@libs/MoneyRequestUtils';
import Navigation from '@libs/Navigation/Navigation';
import {getIOUConfirmationOptionsFromPayeePersonalDetail, hasEnabledOptions} from '@libs/OptionsListUtils';
import {getIOUConfirmationOptionsFromPayeePersonalDetail, hasEnabledOptions, isSelectedManagerMcTest} from '@libs/OptionsListUtils';
import Permissions from '@libs/Permissions';
import {getDistanceRateCustomUnitRate, getTagLists, isTaxTrackingEnabled} from '@libs/PolicyUtils';
import type {OptionData} from '@libs/ReportUtils';
import playSound, {SOUNDS} from '@libs/Sound';
Expand Down Expand Up @@ -65,11 +66,13 @@ import FormHelpMessage from './FormHelpMessage';
import MoneyRequestAmountInput from './MoneyRequestAmountInput';
import MoneyRequestConfirmationListFooter from './MoneyRequestConfirmationListFooter';
import {PressableWithFeedback} from './Pressable';
import {useProductTrainingContext} from './ProductTrainingContext';
import SelectionList from './SelectionList';
import type {SectionListDataType} from './SelectionList/types';
import UserListItem from './SelectionList/UserListItem';
import SettlementButton from './SettlementButton';
import Text from './Text';
import EducationalTooltip from './Tooltip/EducationalTooltip';

type MoneyRequestConfirmationListProps = {
/** Callback to inform parent modal of success */
Expand Down Expand Up @@ -215,6 +218,11 @@ function MoneyRequestConfirmationList({
const [policyCategoriesDraft] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES_DRAFT}${policyID}`);
const [lastSelectedDistanceRates] = useOnyx(ONYXKEYS.NVP_LAST_SELECTED_DISTANCE_RATES);
const [currencyList] = useOnyx(ONYXKEYS.CURRENCY_LIST);
const [betas] = useOnyx(ONYXKEYS.BETAS);
const {shouldShowProductTrainingTooltip, renderProductTrainingTooltip} = useProductTrainingContext(
CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_CONFIRMATION,
Permissions.canUseManagerMcTest(betas) && selectedParticipantsProp.some((participant) => isSelectedManagerMcTest(participant.login)),
);

const policy = policyReal ?? policyDraft;
const policyCategories = policyCategoriesReal ?? policyCategoriesDraft;
Expand Down Expand Up @@ -966,11 +974,37 @@ function MoneyRequestConfirmationList({
message={errorMessage}
/>
)}

{button}
<EducationalTooltip

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NAB: But let's add a condition for more safe

shouldShowProductTrainingTooltip && (<EducationalTooltip....)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I am not sure if this is needed its already handled by shouldShowProductTrainingTooltip so if we add this condition we would basically made the same condition which we are passing to useProductTrainingContext

shouldRender={shouldShowProductTrainingTooltip}
renderTooltipContent={renderProductTrainingTooltip}
anchorAlignment={{
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.CENTER,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM,
}}
wrapperStyle={styles.productTrainingTooltipWrapper}
shouldHideOnNavigate
shiftVertical={-10}
>
<View>{button}</View>
</EducationalTooltip>
</>
);
}, [isReadOnly, iouType, confirm, isConfirmed, bankAccountRoute, iouCurrencyCode, policyID, splitOrRequestOptions, styles.ph1, styles.mb2, errorMessage]);
}, [
isReadOnly,
iouType,
confirm,
bankAccountRoute,
iouCurrencyCode,
policyID,
isConfirmed,
splitOrRequestOptions,
errorMessage,
styles.ph1,
styles.mb2,
styles.productTrainingTooltipWrapper,
shouldShowProductTrainingTooltip,
renderProductTrainingTooltip,
]);

const listFooterContent = (
<MoneyRequestConfirmationListFooter
Expand Down
28 changes: 23 additions & 5 deletions src/components/ProductTrainingContext/TOOLTIPS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const {
LHN_WORKSPACE_CHAT_TOOLTIP,
GLOBAL_CREATE_TOOLTIP,
SCAN_TEST_TOOLTIP,
SCAN_TEST_TOOLTIP_MANAGER,
SCAN_TEST_CONFIRMATION,
} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;

type ProductTrainingTooltipName = ValueOf<typeof CONST.PRODUCT_TRAINING_TOOLTIP_NAMES>;
Expand Down Expand Up @@ -119,18 +121,34 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
content: [
{text: 'productTrainingTooltip.scanTestTooltip.part1', isBold: false},
{text: 'productTrainingTooltip.scanTestTooltip.part2', isBold: true},
],
onHideTooltip: () => dismissProductTraining(SCAN_TEST_TOOLTIP),
name: SCAN_TEST_TOOLTIP,
priority: 900,
shouldShow: () => true,
shouldRenderActionButtons: true,
},
[SCAN_TEST_TOOLTIP_MANAGER]: {
content: [
{text: 'productTrainingTooltip.scanTestTooltip.part3', isBold: false},
{text: 'productTrainingTooltip.scanTestTooltip.part4', isBold: true},
{text: 'productTrainingTooltip.scanTestTooltip.part5', isBold: false},
],
onHideTooltip: () => dismissProductTraining(SCAN_TEST_TOOLTIP_MANAGER),
name: SCAN_TEST_TOOLTIP_MANAGER,
priority: 1000,
shouldShow: () => true,
},
[SCAN_TEST_CONFIRMATION]: {
content: [
{text: 'productTrainingTooltip.scanTestTooltip.part6', isBold: false},
{text: 'productTrainingTooltip.scanTestTooltip.part7', isBold: true},
{text: 'productTrainingTooltip.scanTestTooltip.part8', isBold: false},
],
onHideTooltip: () => dismissProductTraining(SCAN_TEST_TOOLTIP),
name: SCAN_TEST_TOOLTIP,
priority: 900,
shouldShow: () => false,
shouldRenderActionButtons: true,
onHideTooltip: () => dismissProductTraining(SCAN_TEST_CONFIRMATION),
name: SCAN_TEST_CONFIRMATION,
priority: 1100,
shouldShow: () => true,
},
};

Expand Down
10 changes: 7 additions & 3 deletions src/components/ProductTrainingContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,13 @@ 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 (
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
) {
return false;
}

Expand Down Expand Up @@ -131,7 +137,6 @@ function ProductTrainingContextProvider({children}: ChildrenProps) {
return false;
}
const visibleTooltip = determineVisibleTooltip();

// If this is the highest priority visible tooltip, show it
if (tooltipName === visibleTooltip) {
return true;
Expand Down Expand Up @@ -249,7 +254,6 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou
const shouldShowProductTrainingTooltip = useMemo(() => {
return shouldShow && shouldRenderTooltip(tooltipName);
}, [shouldRenderTooltip, tooltipName, shouldShow]);

const hideProductTrainingTooltip = useCallback(() => {
if (!shouldShowProductTrainingTooltip) {
return;
Expand Down
132 changes: 77 additions & 55 deletions src/components/SelectionList/InviteMemberListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import {Str} from 'expensify-common';
import React, {useCallback} from 'react';
import {View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
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 {getIsUserSubmittedExpenseOrScannedReceipt, isSelectedManagerMcTest} from '@libs/OptionsListUtils';
import Permissions from '@libs/Permissions';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Icon} from '@src/types/onyx/OnyxCommon';
import BaseListItem from './BaseListItem';
import type {InviteMemberListItemProps, ListItem} from './types';
Expand Down Expand Up @@ -42,6 +48,11 @@ function InviteMemberListItem<TItem extends ListItem>({
const theme = useTheme();
const StyleUtils = useStyleUtils();
const {translate} = useLocalize();
const [betas] = useOnyx(ONYXKEYS.BETAS);
const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip} = useProductTrainingContext(
CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP_MANAGER,
!getIsUserSubmittedExpenseOrScannedReceipt() && Permissions.canUseManagerMcTest(betas) && isSelectedManagerMcTest(item.login),
);

const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor;
const subscriptAvatarBorderColor = isFocused ? focusedBackgroundColor : theme.sidebar;
Expand Down Expand Up @@ -84,64 +95,75 @@ function InviteMemberListItem<TItem extends ListItem>({
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,
]}
/>
<EducationalTooltip

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NAB: Becasue InviteMemberListItem is used in many places, for more safe, Let's add a condition to make sure that the education tooltips only display on create expense flow

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same here

shouldRender={shouldShowProductTrainingTooltip}
renderTooltipContent={renderProductTrainingTooltip}
anchorAlignment={{
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
}}
shouldHideOnNavigate
wrapperStyle={styles.productTrainingTooltipWrapper}
>
<View style={[styles.flexRow, styles.alignItemsCenter, styles.flex1]}>
{!!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.alternateText && (
<TextWithTooltip
shouldShowTooltip={showTooltip}
text={Str.removeSMSDomain(item.alternateText ?? '')}
style={[styles.textLabelSupporting, styles.lh16, styles.pre]}
/>
{!!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>
{!!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>
)}
</>
</EducationalTooltip>
)}
</BaseListItem>
);
Expand Down
Loading