Skip to content
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
64 changes: 8 additions & 56 deletions src/components/LHNOptionsList/OptionRowLHN/OptionRowLHNCore.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,28 @@
import React, {useRef} from 'react';
import type {ViewStyle} from 'react-native';
import {StyleSheet, View} from 'react-native';
import DisplayNames from '@components/DisplayNames';
import Icon from '@components/Icon';
import {useLHNTooltipContext} from '@components/LHNOptionsList/LHNTooltipContext';
import type {OptionRowLHNProps} from '@components/LHNOptionsList/types';
import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
import getContextMenuAccessibilityHint from '@components/utils/getContextMenuAccessibilityHint';
import getContextMenuAccessibilityProps from '@components/utils/getContextMenuAccessibilityProps';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useEnvironment from '@hooks/useEnvironment';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import DateUtils from '@libs/DateUtils';
import FS from '@libs/Fullstory';
import {shouldUseBoldText} from '@libs/OptionsListUtils';
import {isChatUsedForOnboarding as isChatUsedForOnboardingReportUtils, isGroupChat, isOneOnOneChat, isSystemChat} from '@libs/ReportUtils';
import FreeTrial from '@pages/settings/Subscription/FreeTrial';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import OptionRowAlternateText from './OptionRowAlternateText';
import OptionRowAvatar from './OptionRowAvatar';
import OptionRowErrorBadge from './OptionRowErrorBadge';
import OptionRowInfoBadge from './OptionRowInfoBadge';
import OptionRowPressable from './OptionRowPressable';
import OptionRowTitleWithStatus from './OptionRowTitleWithStatus';
import OptionRowTooltipLayer from './OptionRowTooltipLayer';

function OptionRowLHN({
Expand All @@ -52,12 +44,9 @@ function OptionRowLHN({
const StyleUtils = useStyleUtils();
const expensifyIcons = useMemoizedLazyExpensifyIcons(['Pencil', 'Pin']);

const {onboardingPurpose, onboarding, isScreenFocused} = useLHNTooltipContext();
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
const isChatUsedForOnboarding = isChatUsedForOnboardingReportUtils(report, onboarding, conciergeReportID, onboardingPurpose);
const {isScreenFocused} = useLHNTooltipContext();

const {translate} = useLocalize();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const isInFocusMode = viewMode === CONST.OPTION_MODE.COMPACT;
const sidebarInnerRowStyle = StyleSheet.flatten<ViewStyle>(
isInFocusMode
Expand All @@ -83,19 +72,8 @@ function OptionRowLHN({
const hoveredBackgroundColor = !!styles.sidebarLinkHover && 'backgroundColor' in styles.sidebarLinkHover ? styles.sidebarLinkHover.backgroundColor : theme.sidebar;
const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor;

const emojiCode = optionItem.status?.emojiCode ?? '';
const statusText = optionItem.status?.text ?? '';
const statusClearAfterDate = optionItem.status?.clearAfter ?? '';
const currentSelectedTimezone = currentUserPersonalDetails?.timezone?.selected ?? CONST.DEFAULT_TIME_ZONE.selected;
const formattedDate = DateUtils.getStatusUntilDate(translate, statusClearAfterDate, optionItem?.timezone?.selected ?? CONST.DEFAULT_TIME_ZONE.selected, currentSelectedTimezone);
const statusContent = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText;
const isStatusVisible = !!emojiCode && isOneOnOneChat(!isEmptyObject(report) ? report : undefined);

const subscriptAvatarBorderColor = isOptionFocused ? focusedBackgroundColor : theme.sidebar;

// This is used to ensure that we display the text exactly as the user entered it when displaying LHN title, instead of parsing their text to HTML.
const shouldParseFullTitle = optionItem?.parentReportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT && !isGroupChat(report);

const accessibilityLabel = [
`${translate('accessibilityHints.navigatesToChat')} ${optionItem.text}`,
optionItem.isUnread ? translate('common.unread') : '',
Expand Down Expand Up @@ -145,38 +123,12 @@ function OptionRowLHN({
singleAvatarContainerStyle={singleAvatarContainerStyle}
/>
<View style={contentContainerStyles}>
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mw100, styles.overflowHidden]}>
<DisplayNames
accessibilityLabel={translate('accessibilityHints.chatUserDisplayNames')}
fullTitle={optionItem.text ?? ''}
shouldParseFullTitle={shouldParseFullTitle}
displayNamesWithTooltips={optionItem.displayNamesWithTooltips ?? []}
tooltipEnabled
numberOfLines={1}
textStyles={displayNameStyle}
shouldUseFullTitle={
!!optionItem.isChatRoom ||
!!optionItem.isPolicyExpenseChat ||
!!optionItem.isTaskReport ||
!!optionItem.isThread ||
!!optionItem.isMoneyRequestReport ||
!!optionItem.isInvoiceReport ||
!!optionItem.private_isArchived ||
isGroupChat(report) ||
isSystemChat(report)
}
testID={testID}
/>
{isChatUsedForOnboarding && <FreeTrial badgeStyles={[styles.mnh0, styles.pl2, styles.pr2, styles.ml1, styles.flexShrink1]} />}
{isStatusVisible && (
<Tooltip
text={statusContent}
shiftVertical={-4}
>
<Text style={styles.ml1}>{emojiCode}</Text>
</Tooltip>
)}
</View>
<OptionRowTitleWithStatus
optionItem={optionItem}
report={report}
displayNameStyle={displayNameStyle}
testID={testID}
/>
<OptionRowAlternateText
alternateText={optionItem.alternateText}
report={report}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from 'react';
import type {StyleProp, TextStyle} from 'react-native';
import {View} from 'react-native';
import DisplayNames from '@components/DisplayNames';
import {useLHNTooltipContext} from '@components/LHNOptionsList/LHNTooltipContext';
import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useThemeStyles from '@hooks/useThemeStyles';
import DateUtils from '@libs/DateUtils';
import type {OptionData} from '@libs/ReportUtils';
import {isChatUsedForOnboarding as isChatUsedForOnboardingReportUtils, isGroupChat, isOneOnOneChat, isSystemChat} from '@libs/ReportUtils';
import FreeTrial from '@pages/settings/Subscription/FreeTrial';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Report} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';

type OptionRowTitleWithStatusProps = {
/** Option row data used for the title, tooltips, and status emoji */
optionItem: OptionData;

/** Report backing this row (drives group/system checks and status visibility) */
report?: Report;

/** Styles applied to the primary display name */
displayNameStyle: StyleProp<TextStyle>;

/** Row test id forwarded to DisplayNames */
testID: number;
};

function OptionRowTitleWithStatus({optionItem, report, displayNameStyle, testID}: OptionRowTitleWithStatusProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const {onboarding, onboardingPurpose} = useLHNTooltipContext();
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
const isChatUsedForOnboarding = isChatUsedForOnboardingReportUtils(report, onboarding, conciergeReportID, onboardingPurpose);

const emojiCode = optionItem.status?.emojiCode ?? '';
const isStatusVisible = !!emojiCode && isOneOnOneChat(!isEmptyObject(report) ? report : undefined);

const statusText = optionItem.status?.text ?? '';
const statusClearAfterDate = optionItem.status?.clearAfter ?? '';
const currentSelectedTimezone = currentUserPersonalDetails?.timezone?.selected ?? CONST.DEFAULT_TIME_ZONE.selected;
const formattedDate = isStatusVisible
? DateUtils.getStatusUntilDate(translate, statusClearAfterDate, optionItem?.timezone?.selected ?? CONST.DEFAULT_TIME_ZONE.selected, currentSelectedTimezone)
: '';
const statusContent = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText;

const shouldParseFullTitle = optionItem?.parentReportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT && !isGroupChat(report);
const shouldUseFullTitle =
!!optionItem.isChatRoom ||
!!optionItem.isPolicyExpenseChat ||
!!optionItem.isTaskReport ||
!!optionItem.isThread ||
!!optionItem.isMoneyRequestReport ||
!!optionItem.isInvoiceReport ||
!!optionItem.private_isArchived ||
isGroupChat(report) ||
isSystemChat(report);

return (
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mw100, styles.overflowHidden]}>
<DisplayNames
accessibilityLabel={translate('accessibilityHints.chatUserDisplayNames')}
fullTitle={optionItem.text ?? ''}
shouldParseFullTitle={shouldParseFullTitle}
displayNamesWithTooltips={optionItem.displayNamesWithTooltips ?? []}
tooltipEnabled
numberOfLines={1}
textStyles={displayNameStyle}
shouldUseFullTitle={shouldUseFullTitle}
testID={testID}
/>
{isChatUsedForOnboarding && <FreeTrial badgeStyles={[styles.mnh0, styles.pl2, styles.pr2, styles.ml1, styles.flexShrink1]} />}
{isStatusVisible && (
<Tooltip
text={statusContent}
shiftVertical={-4}
>
<Text style={styles.ml1}>{emojiCode}</Text>
</Tooltip>
)}
</View>
);
}

OptionRowTitleWithStatus.displayName = 'OptionRowTitleWithStatus';

export default OptionRowTitleWithStatus;
Loading