-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Implement get all ancestor of the thread #34640
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
Changes from all commits
e96ce99
dc794ea
07ccc0c
ce57da7
dbdb166
44337c1
40693fb
c0f27d5
6a876e4
bfffe59
c1725c9
850ba24
88e294b
56d5d2c
c374042
7df2fb7
d13b954
8077847
518aec7
44e36c6
9b9d8aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -402,6 +402,18 @@ type OnyxDataTaskAssigneeChat = { | |
optimisticChatCreatedReportAction?: OptimisticCreatedReportAction; | ||
}; | ||
|
||
type Ancestor = { | ||
report: Report; | ||
reportAction: ReportAction; | ||
shouldDisplayNewMarker: boolean; | ||
shouldHideThreadDividerLine: boolean; | ||
}; | ||
|
||
type AncestorIDs = { | ||
reportIDs: string[]; | ||
reportActionsIDs: string[]; | ||
}; | ||
|
||
let currentUserEmail: string | undefined; | ||
let currentUserAccountID: number | undefined; | ||
let isAnonymousUser = false; | ||
|
@@ -4663,6 +4675,78 @@ function shouldDisableThread(reportAction: OnyxEntry<ReportAction>, reportID: st | |
); | ||
} | ||
|
||
function getAllAncestorReportActions(report: Report | null | undefined, shouldHideThreadDividerLine: boolean): Ancestor[] { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR caused an issue - #41519 Detailed root cause here - #41519 (comment) |
||
if (!report) { | ||
marcaaron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return []; | ||
} | ||
const allAncestors: Ancestor[] = []; | ||
let parentReportID = report.parentReportID; | ||
let parentReportActionID = report.parentReportActionID; | ||
|
||
// Store the child of parent report | ||
marcaaron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let currentReport = report; | ||
let currentUnread = shouldHideThreadDividerLine; | ||
|
||
while (parentReportID) { | ||
const parentReport = getReport(parentReportID); | ||
const parentReportAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID ?? '0'); | ||
|
||
if (!parentReportAction || ReportActionsUtils.isTransactionThread(parentReportAction) || !parentReport) { | ||
marcaaron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
break; | ||
} | ||
|
||
const isParentReportActionUnread = ReportActionsUtils.isCurrentActionUnread(parentReport, parentReportAction); | ||
allAncestors.push({ | ||
report: currentReport, | ||
reportAction: parentReportAction, | ||
shouldDisplayNewMarker: isParentReportActionUnread, | ||
// We should hide the thread divider line if the previous ancestor action is unread | ||
shouldHideThreadDividerLine: currentUnread, | ||
marcaaron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}); | ||
parentReportID = parentReport?.parentReportID; | ||
parentReportActionID = parentReport?.parentReportActionID; | ||
if (!isEmptyObject(parentReport)) { | ||
currentReport = parentReport; | ||
currentUnread = isParentReportActionUnread; | ||
} | ||
} | ||
|
||
return allAncestors.reverse(); | ||
} | ||
|
||
function getAllAncestorReportActionIDs(report: Report | null | undefined): AncestorIDs { | ||
if (!report) { | ||
return { | ||
reportIDs: [], | ||
reportActionsIDs: [], | ||
}; | ||
} | ||
|
||
const allAncestorIDs: AncestorIDs = { | ||
reportIDs: [], | ||
reportActionsIDs: [], | ||
}; | ||
let parentReportID = report.parentReportID; | ||
let parentReportActionID = report.parentReportActionID; | ||
|
||
while (parentReportID) { | ||
const parentReport = getReport(parentReportID); | ||
const parentReportAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID ?? '0'); | ||
|
||
if (!parentReportAction || ReportActionsUtils.isTransactionThread(parentReportAction) || !parentReport) { | ||
break; | ||
} | ||
|
||
allAncestorIDs.reportIDs.push(parentReportID ?? ''); | ||
allAncestorIDs.reportActionsIDs.push(parentReportActionID ?? ''); | ||
|
||
parentReportID = parentReport?.parentReportID; | ||
parentReportActionID = parentReport?.parentReportActionID; | ||
} | ||
|
||
return allAncestorIDs; | ||
} | ||
|
||
function canBeAutoReimbursed(report: OnyxEntry<Report>, policy: OnyxEntry<Policy> = null): boolean { | ||
if (!policy) { | ||
return false; | ||
|
@@ -4860,11 +4944,13 @@ export { | |
shouldDisableThread, | ||
doesReportBelongToWorkspace, | ||
getChildReportNotificationPreference, | ||
getAllAncestorReportActions, | ||
isReportParticipant, | ||
isValidReport, | ||
isReportFieldOfTypeTitle, | ||
isReportFieldDisabled, | ||
getAvailableReportFields, | ||
getAllAncestorReportActionIDs, | ||
}; | ||
|
||
export type { | ||
|
@@ -4876,4 +4962,5 @@ export type { | |
OptimisticAddCommentReportAction, | ||
OptimisticCreatedReportAction, | ||
OptimisticClosedReportAction, | ||
Ancestor, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +1,103 @@ | ||
import React from 'react'; | ||
import React, {useEffect, useRef, useState} from 'react'; | ||
import {View} from 'react-native'; | ||
import {withOnyx} from 'react-native-onyx'; | ||
import type {OnyxEntry} from 'react-native-onyx'; | ||
import OfflineWithFeedback from '@components/OfflineWithFeedback'; | ||
import useStyleUtils from '@hooks/useStyleUtils'; | ||
import useThemeStyles from '@hooks/useThemeStyles'; | ||
import useWindowDimensions from '@hooks/useWindowDimensions'; | ||
import * as ReportActionsUtils from '@libs/ReportActionsUtils'; | ||
import Navigation from '@libs/Navigation/Navigation'; | ||
import onyxSubscribe from '@libs/onyxSubscribe'; | ||
import * as ReportUtils from '@libs/ReportUtils'; | ||
import * as Report from '@userActions/Report'; | ||
import ONYXKEYS from '@src/ONYXKEYS'; | ||
import ROUTES from '@src/ROUTES'; | ||
import type * as OnyxTypes from '@src/types/onyx'; | ||
import AnimatedEmptyStateBackground from './AnimatedEmptyStateBackground'; | ||
import ReportActionItem from './ReportActionItem'; | ||
|
||
type ReportActionItemParentActionOnyxProps = { | ||
/** The report currently being looked at */ | ||
/** The current report is displayed */ | ||
report: OnyxEntry<OnyxTypes.Report>; | ||
|
||
/** The actions from the parent report */ | ||
parentReportActions: OnyxEntry<OnyxTypes.ReportActions>; | ||
}; | ||
|
||
type ReportActionItemParentActionProps = ReportActionItemParentActionOnyxProps & { | ||
/** Flag to show, hide the thread divider line */ | ||
shouldHideThreadDividerLine?: boolean; | ||
|
||
/** Flag to display the new marker on top of the comment */ | ||
shouldDisplayNewMarker: boolean; | ||
|
||
/** Position index of the report parent action in the overall report FlatList view */ | ||
index: number; | ||
|
||
/** The id of the report */ | ||
// eslint-disable-next-line react/no-unused-prop-types | ||
reportID: string; | ||
|
||
/** The id of the parent report */ | ||
// eslint-disable-next-line react/no-unused-prop-types | ||
parentReportID: string; | ||
}; | ||
|
||
function ReportActionItemParentAction({report, parentReportActions = {}, index = 0, shouldHideThreadDividerLine = false, shouldDisplayNewMarker}: ReportActionItemParentActionProps) { | ||
function ReportActionItemParentAction({report, index = 0, shouldHideThreadDividerLine = false}: ReportActionItemParentActionProps) { | ||
const styles = useThemeStyles(); | ||
const StyleUtils = useStyleUtils(); | ||
const {isSmallScreenWidth} = useWindowDimensions(); | ||
const parentReportAction = parentReportActions?.[`${report?.parentReportActionID ?? ''}`] ?? null; | ||
const ancestorIDs = useRef(ReportUtils.getAllAncestorReportActionIDs(report)); | ||
const [allAncestors, setAllAncestors] = useState<ReportUtils.Ancestor[]>([]); | ||
|
||
useEffect(() => { | ||
const unsubscribeReports: Array<() => void> = []; | ||
const unsubscribeReportActions: Array<() => void> = []; | ||
ancestorIDs.current.reportIDs.forEach((ancestorReportID) => { | ||
unsubscribeReports.push( | ||
onyxSubscribe({ | ||
key: `${ONYXKEYS.COLLECTION.REPORT}${ancestorReportID}`, | ||
callback: () => { | ||
setAllAncestors(ReportUtils.getAllAncestorReportActions(report, shouldHideThreadDividerLine)); | ||
}, | ||
}), | ||
Comment on lines
+48
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not follow our Onyx practices. Components should use withOnyx and not Onyx.connect There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could possibly have been a performance optimization? If we can explore getting rid of it that would be 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Or |
||
); | ||
unsubscribeReportActions.push( | ||
onyxSubscribe({ | ||
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${ancestorReportID}`, | ||
callback: () => { | ||
setAllAncestors(ReportUtils.getAllAncestorReportActions(report, shouldHideThreadDividerLine)); | ||
}, | ||
}), | ||
); | ||
}); | ||
|
||
return () => { | ||
unsubscribeReports.forEach((unsubscribeReport) => unsubscribeReport()); | ||
unsubscribeReportActions.forEach((unsubscribeReportAction) => unsubscribeReportAction()); | ||
}; | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
|
||
// In case of transaction threads, we do not want to render the parent report action. | ||
if (ReportActionsUtils.isTransactionThread(parentReportAction)) { | ||
marcaaron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return null; | ||
} | ||
marcaaron marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return ( | ||
<OfflineWithFeedback | ||
shouldDisableOpacity={Boolean(parentReportAction?.pendingAction ?? false)} | ||
pendingAction={report?.pendingFields?.addWorkspaceRoom ?? report?.pendingFields?.createChat} | ||
errors={report?.errorFields?.addWorkspaceRoom ?? report?.errorFields?.createChat} | ||
errorRowStyles={[styles.ml10, styles.mr2]} | ||
onClose={() => Report.navigateToConciergeChatAndDeleteReport(report?.reportID ?? '0')} | ||
> | ||
<View style={StyleUtils.getReportWelcomeContainerStyle(isSmallScreenWidth)}> | ||
<> | ||
<View style={[StyleUtils.getReportWelcomeContainerStyle(isSmallScreenWidth), styles.justifyContentEnd]}> | ||
<AnimatedEmptyStateBackground /> | ||
<View style={[styles.p5, StyleUtils.getReportWelcomeTopMarginStyle(isSmallScreenWidth)]} /> | ||
{parentReportAction && ( | ||
<ReportActionItem | ||
// @ts-expect-error TODO: Remove the comment after ReportActionItem is migrated to TypeScript. | ||
report={report} | ||
action={parentReportAction} | ||
displayAsGroup={false} | ||
isMostRecentIOUReportAction={false} | ||
shouldDisplayNewMarker={shouldDisplayNewMarker} | ||
index={index} | ||
/> | ||
)} | ||
{allAncestors.map((ancestor) => ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Quick gut check here - could this change have any impact on Comment Linking? cc @perunt @roryabraham |
||
<OfflineWithFeedback | ||
key={ancestor.reportAction.reportActionID} | ||
shouldDisableOpacity={Boolean(ancestor.reportAction?.pendingAction)} | ||
pendingAction={ancestor.report?.pendingFields?.addWorkspaceRoom ?? ancestor.report?.pendingFields?.createChat} | ||
errors={ancestor.report?.errorFields?.addWorkspaceRoom ?? ancestor.report?.errorFields?.createChat} | ||
errorRowStyles={[styles.ml10, styles.mr2]} | ||
onClose={() => Report.navigateToConciergeChatAndDeleteReport(ancestor.report.reportID)} | ||
> | ||
<ReportActionItem | ||
// @ts-expect-error TODO: Remove this once ReportActionItem (https://github.com/Expensify/App/issues/31982) is migrated to TypeScript. | ||
onPress={() => Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID))} | ||
report={ancestor.report} | ||
action={ancestor.reportAction} | ||
displayAsGroup={false} | ||
isMostRecentIOUReportAction={false} | ||
shouldDisplayNewMarker={ancestor.shouldDisplayNewMarker} | ||
index={index} | ||
dukenv0307 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/> | ||
{!ancestor.shouldHideThreadDividerLine && <View style={[styles.threadDividerLine]} />} | ||
</OfflineWithFeedback> | ||
))} | ||
</View> | ||
{!shouldHideThreadDividerLine && <View style={[styles.threadDividerLine]} />} | ||
</OfflineWithFeedback> | ||
</> | ||
); | ||
} | ||
|
||
|
@@ -84,8 +107,4 @@ export default withOnyx<ReportActionItemParentActionProps, ReportActionItemParen | |
report: { | ||
key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, | ||
}, | ||
parentReportActions: { | ||
key: ({parentReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, | ||
canEvict: false, | ||
}, | ||
})(ReportActionItemParentAction); |
Uh oh!
There was an error while loading. Please reload this page.