Skip to content

Commit e5cef39

Browse files
authored
Merge pull request Expensify#90158 from callstack-internal/refactor/option-row-lhn-drop-report-prop
[No QA] refactor: drop redundant report and reportID props from OptionRowLHN tree
2 parents 7a4e5dd + d0a9ba7 commit e5cef39

8 files changed

Lines changed: 30 additions & 62 deletions

File tree

src/components/LHNOptionsList/OptionRowLHN/OptionRowAlternateText.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,24 @@ import useLocalize from '@hooks/useLocalize';
66
import useThemeStyles from '@hooks/useThemeStyles';
77
import {containsCustomEmoji as containsCustomEmojiUtils, containsOnlyCustomEmoji} from '@libs/EmojiUtils';
88
import FS from '@libs/Fullstory';
9+
import type {OptionData} from '@libs/ReportUtils';
910
import TextWithEmojiFragment from '@pages/inbox/report/comment/TextWithEmojiFragment';
1011
import CONST from '@src/CONST';
11-
import type {Report} from '@src/types/onyx';
1212

1313
type OptionMode = ValueOf<typeof CONST.OPTION_MODE>;
1414

1515
type OptionRowAlternateTextProps = {
16-
alternateText: string | undefined;
17-
report?: Report;
16+
optionItem: OptionData;
1817
viewMode: OptionMode;
1918
isOptionFocused: boolean;
2019
style?: StyleProp<TextStyle>;
2120
};
2221

23-
function OptionRowAlternateText({alternateText, report, viewMode, isOptionFocused, style}: OptionRowAlternateTextProps) {
22+
function OptionRowAlternateText({optionItem, viewMode, isOptionFocused, style}: OptionRowAlternateTextProps) {
2423
const {translate} = useLocalize();
2524
const styles = useThemeStyles();
2625

26+
const alternateText = optionItem.alternateText;
2727
if (!alternateText) {
2828
return null;
2929
}
@@ -33,7 +33,7 @@ function OptionRowAlternateText({alternateText, report, viewMode, isOptionFocuse
3333
const alternateTextStyle = isInFocusMode
3434
? [textStyle, styles.textLabelSupporting, styles.optionAlternateTextCompact, styles.ml2, style]
3535
: [textStyle, styles.optionAlternateText, styles.textLabelSupporting, style];
36-
const alternateTextFSClass = FS.getChatFSClass(report);
36+
const alternateTextFSClass = FS.getChatFSClass(optionItem);
3737

3838
const containsCustomEmojiWithText = containsCustomEmojiUtils(alternateText) && !containsOnlyCustomEmoji(alternateText);
3939

src/components/LHNOptionsList/OptionRowLHN/OptionRowAvatar.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,29 @@
11
import React from 'react';
22
import type {ColorValue, ViewStyle} from 'react-native';
3-
import type {OnyxEntry} from 'react-native-onyx';
43
import LHNAvatar from '@components/LHNOptionsList/LHNAvatar';
54
import {usePersonalDetails} from '@components/OnyxListItemProvider';
65
import {shouldOptionShowTooltip} from '@libs/OptionsListUtils';
76
import {getDelegateAccountIDFromReportAction} from '@libs/ReportActionsUtils';
87
import type {OptionData} from '@libs/ReportUtils';
98
import CONST from '@src/CONST';
10-
import type {Report} from '@src/types/onyx';
119

1210
type OptionRowAvatarProps = {
1311
optionItem: OptionData;
14-
report: OnyxEntry<Report>;
1512
isInFocusMode: boolean;
1613
subscriptAvatarBorderColor: ColorValue;
1714
secondaryAvatarBackgroundColor: ColorValue;
1815
singleAvatarContainerStyle: ViewStyle[];
1916
};
2017

21-
function OptionRowAvatarInner({optionItem, report, isInFocusMode, subscriptAvatarBorderColor, secondaryAvatarBackgroundColor, singleAvatarContainerStyle}: OptionRowAvatarProps) {
18+
function OptionRowAvatarInner({optionItem, isInFocusMode, subscriptAvatarBorderColor, secondaryAvatarBackgroundColor, singleAvatarContainerStyle}: OptionRowAvatarProps) {
2219
const personalDetails = usePersonalDetails();
2320

2421
const delegateAccountID = getDelegateAccountIDFromReportAction(optionItem?.parentReportAction);
2522

2623
// Match the header's delegate avatar logic: when a delegate exists on the
2724
// parent report action, the header (useReportActionAvatars) shows the
2825
// delegate's avatar as primary instead of the report owner's.
29-
const skipDelegate = report?.type === CONST.REPORT.TYPE.INVOICE || (optionItem?.isTaskReport && !report?.chatReportID);
26+
const skipDelegate = optionItem?.type === CONST.REPORT.TYPE.INVOICE || (optionItem?.isTaskReport && !optionItem?.chatReportID);
3027

3128
let icons = optionItem?.icons ?? [];
3229
if (!skipDelegate && delegateAccountID && personalDetails && icons.length > 0) {
@@ -69,15 +66,14 @@ function OptionRowAvatarInner({optionItem, report, isInFocusMode, subscriptAvata
6966

7067
OptionRowAvatarInner.displayName = 'OptionRowAvatarInner';
7168

72-
function OptionRowAvatar({optionItem, report, isInFocusMode, subscriptAvatarBorderColor, secondaryAvatarBackgroundColor, singleAvatarContainerStyle}: OptionRowAvatarProps) {
69+
function OptionRowAvatar({optionItem, isInFocusMode, subscriptAvatarBorderColor, secondaryAvatarBackgroundColor, singleAvatarContainerStyle}: OptionRowAvatarProps) {
7370
// Bail out before subscribing to personal details when the row has no avatar to render.
7471
if (!optionItem.icons?.length || !optionItem.icons.at(0)) {
7572
return null;
7673
}
7774
return (
7875
<OptionRowAvatarInner
7976
optionItem={optionItem}
80-
report={report}
8177
isInFocusMode={isInFocusMode}
8278
subscriptAvatarBorderColor={subscriptAvatarBorderColor}
8379
secondaryAvatarBackgroundColor={secondaryAvatarBackgroundColor}

src/components/LHNOptionsList/OptionRowLHN/OptionRowLHNCore.tsx

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,11 @@ import useThemeStyles from '@hooks/useThemeStyles';
2020
import DateUtils from '@libs/DateUtils';
2121
import FS from '@libs/Fullstory';
2222
import {shouldUseBoldText} from '@libs/OptionsListUtils';
23-
import {isChatUsedForOnboarding as isChatUsedForOnboardingReportUtils, isGroupChat, isOneOnOneChat, isSystemChat} from '@libs/ReportUtils';
23+
import {isChatUsedForOnboarding as isChatUsedForOnboardingReportUtils, isGroupChat, isSystemChat} from '@libs/ReportUtils';
2424
import FreeTrial from '@pages/settings/Subscription/FreeTrial';
2525
import variables from '@styles/variables';
2626
import CONST from '@src/CONST';
2727
import ONYXKEYS from '@src/ONYXKEYS';
28-
import {isEmptyObject} from '@src/types/utils/EmptyObject';
2928
import DraftIndicator from './OptionRow/DraftIndicator';
3029
import OptionRowAlternateText from './OptionRowAlternateText';
3130
import OptionRowAvatar from './OptionRowAvatar';
@@ -34,18 +33,7 @@ import OptionRowInfoBadge from './OptionRowInfoBadge';
3433
import OptionRowPressable from './OptionRowPressable';
3534
import OptionRowTooltipLayer from './OptionRowTooltipLayer';
3635

37-
function OptionRowLHN({
38-
reportID,
39-
report,
40-
isOptionFocused = false,
41-
onSelectRow = () => {},
42-
optionItem,
43-
viewMode = 'default',
44-
style,
45-
onLayout = () => {},
46-
hasDraftComment,
47-
testID,
48-
}: OptionRowLHNProps) {
36+
function OptionRowLHN({isOptionFocused = false, onSelectRow = () => {}, optionItem, viewMode = 'default', style, onLayout = () => {}, hasDraftComment, testID}: OptionRowLHNProps) {
4937
const {isProduction} = useEnvironment();
5038
const theme = useTheme();
5139
const styles = useThemeStyles();
@@ -55,7 +43,7 @@ function OptionRowLHN({
5543

5644
const {onboardingPurpose, onboarding, isScreenFocused} = useLHNTooltipContext();
5745
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
58-
const isChatUsedForOnboarding = isChatUsedForOnboardingReportUtils(report, onboarding, conciergeReportID, onboardingPurpose);
46+
const isChatUsedForOnboarding = isChatUsedForOnboardingReportUtils(optionItem, onboarding, conciergeReportID, onboardingPurpose);
5947

6048
const {translate} = useLocalize();
6149
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
@@ -90,12 +78,12 @@ function OptionRowLHN({
9078
const currentSelectedTimezone = currentUserPersonalDetails?.timezone?.selected ?? CONST.DEFAULT_TIME_ZONE.selected;
9179
const formattedDate = DateUtils.getStatusUntilDate(translate, statusClearAfterDate, optionItem?.timezone?.selected ?? CONST.DEFAULT_TIME_ZONE.selected, currentSelectedTimezone);
9280
const statusContent = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText;
93-
const isStatusVisible = !!emojiCode && isOneOnOneChat(!isEmptyObject(report) ? report : undefined);
81+
const isStatusVisible = !!emojiCode && !!optionItem.isOneOnOneChat;
9482

9583
const subscriptAvatarBorderColor = isOptionFocused ? focusedBackgroundColor : theme.sidebar;
9684

9785
// 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.
98-
const shouldParseFullTitle = optionItem?.parentReportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT && !isGroupChat(report);
86+
const shouldParseFullTitle = optionItem?.parentReportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT && !isGroupChat(optionItem);
9987

10088
const accessibilityLabel = [
10189
`${translate('accessibilityHints.navigatesToChat')} ${optionItem.text}`,
@@ -114,7 +102,6 @@ function OptionRowLHN({
114102

115103
const renderPressableRow = () => (
116104
<OptionRowPressable
117-
reportID={reportID}
118105
optionItem={optionItem}
119106
isOptionFocused={isOptionFocused}
120107
isScreenFocused={isScreenFocused}
@@ -139,7 +126,6 @@ function OptionRowLHN({
139126
<View style={[styles.flexRow, styles.alignItemsCenter]}>
140127
<OptionRowAvatar
141128
optionItem={optionItem}
142-
report={report}
143129
isInFocusMode={isInFocusMode}
144130
subscriptAvatarBorderColor={hovered && !isOptionFocused ? hoveredBackgroundColor : subscriptAvatarBorderColor}
145131
secondaryAvatarBackgroundColor={secondaryAvatarBgColor}
@@ -163,8 +149,8 @@ function OptionRowLHN({
163149
!!optionItem.isMoneyRequestReport ||
164150
!!optionItem.isInvoiceReport ||
165151
!!optionItem.private_isArchived ||
166-
isGroupChat(report) ||
167-
isSystemChat(report)
152+
isGroupChat(optionItem) ||
153+
isSystemChat(optionItem)
168154
}
169155
testID={testID}
170156
/>
@@ -179,8 +165,7 @@ function OptionRowLHN({
179165
)}
180166
</View>
181167
<OptionRowAlternateText
182-
alternateText={optionItem.alternateText}
183-
report={report}
168+
optionItem={optionItem}
184169
viewMode={viewMode}
185170
isOptionFocused={isOptionFocused}
186171
style={style}
@@ -189,7 +174,7 @@ function OptionRowLHN({
189174
{optionItem?.descriptiveText ? (
190175
<View
191176
style={[styles.flexWrap]}
192-
fsClass={FS.getChatFSClass(report)}
177+
fsClass={FS.getChatFSClass(optionItem)}
193178
>
194179
<Text style={[styles.textLabel]}>{optionItem.descriptiveText}</Text>
195180
</View>
@@ -232,8 +217,6 @@ function OptionRowLHN({
232217

233218
return (
234219
<OptionRowTooltipLayer
235-
reportID={reportID}
236-
report={report}
237220
optionItem={optionItem}
238221
renderChildren={renderPressableRow}
239222
/>

src/components/LHNOptionsList/OptionRowLHN/OptionRowLHNData.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ function OptionRowLHNData({
3838
policy,
3939
invoiceReceiverPolicy,
4040
viewMode = 'default',
41+
reportID,
4142
...propsToForward
4243
}: OptionRowLHNDataProps) {
4344
const styles = useThemeStyles();
44-
const reportID = propsToForward.reportID;
4545
const {currentReportID: currentReportIDValue} = useCurrentReportIDState();
4646
const isReportFocused = isOptionFocused && currentReportIDValue === reportID;
4747
const {translate, localeCompare} = useLocalize();
@@ -197,7 +197,6 @@ function OptionRowLHNData({
197197
viewMode={viewMode}
198198
isOptionFocused={isReportFocused}
199199
optionItem={finalOptionItem}
200-
report={fullReport}
201200
hasDraftComment={hasDraftComment}
202201
/>
203202
);

src/components/LHNOptionsList/OptionRowLHN/OptionRowPressable.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import CONST from '@src/CONST';
1717
import useLHNRowProductTrainingTooltip from './useLHNRowProductTrainingTooltip';
1818

1919
type OptionRowPressableProps = {
20-
reportID: string;
2120
optionItem: OptionData;
2221
isOptionFocused: boolean;
2322
isScreenFocused: boolean;
@@ -31,7 +30,6 @@ type OptionRowPressableProps = {
3130
};
3231

3332
function OptionRowPressable({
34-
reportID,
3533
optionItem,
3634
isOptionFocused,
3735
isScreenFocused,
@@ -44,6 +42,7 @@ function OptionRowPressable({
4442
children,
4543
}: OptionRowPressableProps) {
4644
const {hideProductTrainingTooltip} = useLHNRowProductTrainingTooltip();
45+
const reportID = optionItem.reportID;
4746
const onPress = (event: GestureResponderEvent | KeyboardEvent | undefined) => {
4847
hideProductTrainingTooltip();
4948
startSpan(`${CONST.TELEMETRY.SPAN_OPEN_REPORT}_${reportID}`, {

src/components/LHNOptionsList/OptionRowLHN/OptionRowTooltipLayer.tsx

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import React from 'react';
2-
import type {OnyxEntry} from 'react-native-onyx';
32
import {useLHNTooltipContext} from '@components/LHNOptionsList/LHNTooltipContext';
43
import OfflineWithFeedback from '@components/OfflineWithFeedback';
54
import {useSession} from '@components/OnyxListItemProvider';
@@ -11,17 +10,10 @@ import type {OptionData} from '@libs/ReportUtils';
1110
import variables from '@styles/variables';
1211
import CONST from '@src/CONST';
1312
import ONYXKEYS from '@src/ONYXKEYS';
14-
import type {Report} from '@src/types/onyx';
1513
import useLHNRowProductTrainingTooltip from './useLHNRowProductTrainingTooltip';
1614

1715
type OptionRowTooltipLayerProps = {
18-
/** Report ID of the row */
19-
reportID: string;
20-
21-
/** Report data of the row, used to determine onboarding eligibility */
22-
report: OnyxEntry<Report>;
23-
24-
/** Option data, used to forward pendingAction and errors to OfflineWithFeedback */
16+
/** Option data, drives onboarding eligibility checks and forwards pendingAction/errors to OfflineWithFeedback */
2517
optionItem: OptionData;
2618

2719
/** Renders the row content. */
@@ -57,15 +49,15 @@ function OptionRowTooltipLayerInner({renderChildren}: OptionRowTooltipLayerInner
5749

5850
OptionRowTooltipLayerInner.displayName = 'OptionRowTooltipLayerInner';
5951

60-
function OptionRowTooltipLayer({reportID, report, optionItem, renderChildren}: OptionRowTooltipLayerProps) {
52+
function OptionRowTooltipLayer({optionItem, renderChildren}: OptionRowTooltipLayerProps) {
6153
const {firstReportIDWithGBRorRBR, onboardingPurpose, onboarding} = useLHNTooltipContext();
6254
const session = useSession();
6355
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
6456

65-
const shouldShowRBRorGBRTooltip = firstReportIDWithGBRorRBR === reportID;
57+
const shouldShowRBRorGBRTooltip = firstReportIDWithGBRorRBR === optionItem.reportID;
6658
const isOnboardingGuideAssigned = onboardingPurpose === CONST.ONBOARDING_CHOICES.MANAGE_TEAM && !session?.email?.includes('+');
67-
const isChatUsedForOnboarding = isChatUsedForOnboardingReportUtils(report, onboarding, conciergeReportID, onboardingPurpose);
68-
const shouldShowGetStartedTooltip = isOnboardingGuideAssigned ? isAdminRoom(report) && isChatUsedForOnboarding : isConciergeChatReport(report);
59+
const isChatUsedForOnboarding = isChatUsedForOnboardingReportUtils(optionItem, onboarding, conciergeReportID, onboardingPurpose);
60+
const shouldShowGetStartedTooltip = isOnboardingGuideAssigned ? isAdminRoom(optionItem) && isChatUsedForOnboarding : isConciergeChatReport(optionItem);
6961

7062
// Skip the inner component (and its heavy hooks) entirely when the row can never show a tooltip.
7163
const shouldEvaluateTooltip = shouldShowRBRorGBRTooltip || shouldShowGetStartedTooltip;

src/components/LHNOptionsList/types.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,6 @@ type OptionRowLHNDataProps = {
7676
};
7777

7878
type OptionRowLHNProps = {
79-
/** The ID of the report that the option is for */
80-
reportID: string;
81-
82-
/** The report for this option */
83-
report?: Report;
84-
8579
/** Whether this option is currently in focus so we can modify its style */
8680
isOptionFocused?: boolean;
8781

src/libs/SidebarUtils.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,7 @@ function getOptionData({
861861
result.ownerAccountID = report.ownerAccountID;
862862
result.managerID = report.managerID;
863863
result.reportID = report.reportID;
864+
result.chatReportID = report.chatReportID;
864865
result.policyID = report.policyID;
865866
result.stateNum = report.stateNum;
866867
result.statusNum = report.statusNum;
@@ -873,6 +874,7 @@ function getOptionData({
873874
result.keyForList = String(report.reportID);
874875
result.hasOutstandingChildRequest = report.hasOutstandingChildRequest;
875876
result.parentReportID = report.parentReportID;
877+
result.parentReportActionID = report.parentReportActionID;
876878
result.isWaitingOnBankAccount = report.isWaitingOnBankAccount;
877879
result.notificationPreference = getReportNotificationPreference(report);
878880
result.isAllowedToComment = canUserPerformWriteActionUtil(report, isReportArchived);
@@ -891,8 +893,11 @@ function getOptionData({
891893

892894
const status = personalDetail?.status ?? '';
893895

896+
const isOneOnOneChatReport = isOneOnOneChat(report);
897+
result.isOneOnOneChat = isOneOnOneChatReport;
898+
894899
// For 1:1 DMs, add the other participant's selected timezone
895-
if (isOneOnOneChat(report)) {
900+
if (isOneOnOneChatReport) {
896901
const recipientPersonalDetail = participantPersonalDetailListExcludeCurrentUser.at(0);
897902
result.timezone = recipientPersonalDetail?.timezone;
898903
}

0 commit comments

Comments
 (0)