diff --git a/src/components/Attachments/AttachmentCarousel/extractAttachments.ts b/src/components/Attachments/AttachmentCarousel/extractAttachments.ts index 536a54926181..642ab9d2d96f 100644 --- a/src/components/Attachments/AttachmentCarousel/extractAttachments.ts +++ b/src/components/Attachments/AttachmentCarousel/extractAttachments.ts @@ -21,12 +21,20 @@ function extractAttachments( parentReportAction, reportActions, report, - }: {privateNotes?: Record; accountID?: number; parentReportAction?: OnyxEntry; reportActions?: OnyxEntry; report: OnyxEntry}, + isReportArchived, + }: { + privateNotes?: Record; + accountID?: number; + parentReportAction?: OnyxEntry; + reportActions?: OnyxEntry; + report: OnyxEntry; + isReportArchived?: boolean; + }, ) { const targetNote = privateNotes?.[Number(accountID)]?.note ?? ''; const description = report?.description ?? ''; const attachments: Attachment[] = []; - const canUserPerformAction = canUserPerformWriteAction(report); + const canUserPerformAction = canUserPerformWriteAction(report, isReportArchived); let currentLink = ''; const htmlParser = new HtmlParser({ diff --git a/src/components/Attachments/AttachmentCarousel/index.tsx b/src/components/Attachments/AttachmentCarousel/index.tsx index 72707a49c198..cabe85c5e279 100644 --- a/src/components/Attachments/AttachmentCarousel/index.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.tsx @@ -4,6 +4,7 @@ import {View} from 'react-native'; import type {Attachment} from '@components/Attachments/types'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import useOnyx from '@hooks/useOnyx'; +import useReportIsArchived from '@hooks/useReportIsArchived'; import useThemeStyles from '@hooks/useThemeStyles'; import {canUseTouchScreen as canUseTouchScreenUtil} from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; @@ -19,6 +20,7 @@ function AttachmentCarousel({report, attachmentID, source, onNavigate, setDownlo const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, {canEvict: false, canBeMissing: true}); const canUseTouchScreen = canUseTouchScreenUtil(); const styles = useThemeStyles(); + const isReportArchived = useReportIsArchived(report.reportID); const [page, setPage] = useState(); const [attachments, setAttachments] = useState([]); @@ -41,11 +43,11 @@ function AttachmentCarousel({report, attachmentID, source, onNavigate, setDownlo const parentReportAction = report.parentReportActionID && parentReportActions ? parentReportActions[report.parentReportActionID] : undefined; let newAttachments: Attachment[] = []; if (type === CONST.ATTACHMENT_TYPE.NOTE && accountID) { - newAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.NOTE, {privateNotes: report.privateNotes, accountID, report}); + newAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.NOTE, {privateNotes: report.privateNotes, accountID, report, isReportArchived}); } else if (type === CONST.ATTACHMENT_TYPE.ONBOARDING) { - newAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.ONBOARDING, {parentReportAction, reportActions: reportActions ?? undefined, report}); + newAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.ONBOARDING, {parentReportAction, reportActions: reportActions ?? undefined, report, isReportArchived}); } else { - newAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.REPORT, {parentReportAction, reportActions: reportActions ?? undefined, report}); + newAttachments = extractAttachments(CONST.ATTACHMENT_TYPE.REPORT, {parentReportAction, reportActions: reportActions ?? undefined, report, isReportArchived}); } if (deepEqual(attachments, newAttachments)) { @@ -84,7 +86,7 @@ function AttachmentCarousel({report, attachmentID, source, onNavigate, setDownlo onNavigate(attachment); } } - }, [reportActions, parentReportActions, compareImage, attachments, setDownloadButtonVisibility, onNavigate, accountID, type, report]); + }, [reportActions, parentReportActions, compareImage, attachments, setDownloadButtonVisibility, onNavigate, accountID, type, report, isReportArchived]); if (page == null) { return ( diff --git a/src/components/LHNOptionsList/OptionRowLHNData.tsx b/src/components/LHNOptionsList/OptionRowLHNData.tsx index f19e2aec9b3a..2c4849407296 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.tsx +++ b/src/components/LHNOptionsList/OptionRowLHNData.tsx @@ -74,6 +74,7 @@ function OptionRowLHNData({ invoiceReceiverPolicy, card, localeCompare, + isReportArchived, }); // eslint-disable-next-line react-compiler/react-compiler if (deepEqual(item, optionItemRef.current)) { @@ -108,6 +109,7 @@ function OptionRowLHNData({ reportAttributes, card, localeCompare, + isReportArchived, ]); return ( diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx index 004f800f9b69..900cd3fa3028 100644 --- a/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx +++ b/src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx @@ -564,6 +564,7 @@ function MoneyRequestReportActionsList({ userBillingFundID, emojiReactions, draftMessage, + isReportArchived, ], ); diff --git a/src/hooks/useIsReportReadyToDisplay.ts b/src/hooks/useIsReportReadyToDisplay.ts index 15cdc5190bb3..2025776f6ffb 100644 --- a/src/hooks/useIsReportReadyToDisplay.ts +++ b/src/hooks/useIsReportReadyToDisplay.ts @@ -3,7 +3,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import {canUserPerformWriteAction} from '@libs/ReportUtils'; import type {Report} from '@src/types/onyx'; -function useIsReportReadyToDisplay(report: OnyxEntry, reportIDFromRoute: string | undefined) { +function useIsReportReadyToDisplay(report: OnyxEntry, reportIDFromRoute: string | undefined, isReportArchived = false) { /** * When false the report is not ready to be fully displayed */ @@ -13,7 +13,10 @@ function useIsReportReadyToDisplay(report: OnyxEntry, reportIDFromRoute: return reportIDFromRoute !== '' && !!report?.reportID && !isTransitioning; }, [report, reportIDFromRoute]); - const isEditingDisabled = useMemo(() => !isCurrentReportLoadedFromOnyx || !canUserPerformWriteAction(report), [isCurrentReportLoadedFromOnyx, report]); + const isEditingDisabled = useMemo( + () => !isCurrentReportLoadedFromOnyx || !canUserPerformWriteAction(report, isReportArchived), + [isCurrentReportLoadedFromOnyx, report, isReportArchived], + ); return { isCurrentReportLoadedFromOnyx, diff --git a/src/hooks/usePaginatedReportActions.ts b/src/hooks/usePaginatedReportActions.ts index 8fb5bf8900db..50724471e627 100644 --- a/src/hooks/usePaginatedReportActions.ts +++ b/src/hooks/usePaginatedReportActions.ts @@ -5,6 +5,7 @@ import {getSortedReportActionsForDisplay} from '@libs/ReportActionsUtils'; import {canUserPerformWriteAction} from '@libs/ReportUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import useOnyx from './useOnyx'; +import useReportIsArchived from './useReportIsArchived'; /** * Get the longest continuous chunk of reportActions including the linked reportAction. If not linking to a specific action, returns the continuous chunk of newest reportActions. @@ -12,7 +13,8 @@ import useOnyx from './useOnyx'; function usePaginatedReportActions(reportID: string | undefined, reportActionID?: string) { const nonEmptyStringReportID = getNonEmptyStringOnyxID(reportID); const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${nonEmptyStringReportID}`, {canBeMissing: true}); - const hasWriteAccess = canUserPerformWriteAction(report); + const isReportArchived = useReportIsArchived(report?.reportID); + const hasWriteAccess = canUserPerformWriteAction(report, isReportArchived); const [sortedAllReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${nonEmptyStringReportID}`, { canEvict: false, diff --git a/src/hooks/useSelectedTransactionsActions.ts b/src/hooks/useSelectedTransactionsActions.ts index ad71022d905e..905b81833553 100644 --- a/src/hooks/useSelectedTransactionsActions.ts +++ b/src/hooks/useSelectedTransactionsActions.ts @@ -280,7 +280,7 @@ function useSelectedTransactionsActions({ return canMoveExpense; }); - const canUserPerformWriteAction = canUserPerformWriteActionReportUtils(report); + const canUserPerformWriteAction = canUserPerformWriteActionReportUtils(report, isReportArchived); if (canSelectedExpensesBeMoved && canUserPerformWriteAction) { options.push({ text: translate('iou.moveExpenses', {count: selectedTransactionIDs.length}), diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index ec39d1e12ed0..3421e99ce04d 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -737,7 +737,7 @@ function getLastMessageTextForReport(report: OnyxEntry, lastActorDetails const lastIOUMoneyReportAction = iouReport?.reportID ? allSortedReportActions[iouReport.reportID]?.find( (reportAction, key): reportAction is ReportAction => - shouldReportActionBeVisible(reportAction, key, canUserPerformWriteAction(report)) && + shouldReportActionBeVisible(reportAction, key, canUserPerformWriteAction(report, isReportArchived)) && reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && isMoneyRequestAction(reportAction), ) @@ -1720,7 +1720,7 @@ function isValidReport(option: SearchOption, config: GetValidReportsConf return false; } - if (!canUserPerformWriteAction(option.item) && !includeReadOnly) { + if (!canUserPerformWriteAction(option.item, !!option.private_isArchived) && !includeReadOnly) { return false; } diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 13bda00f0a3e..55066d8529f6 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -615,6 +615,7 @@ function getOptionData({ invoiceReceiverPolicy, card, localeCompare, + isReportArchived = false, }: { report: OnyxEntry; oneTransactionThreadReport: OnyxEntry; @@ -627,6 +628,7 @@ function getOptionData({ reportAttributes: OnyxEntry; card: Card | undefined; localeCompare: LocaleContextProps['localeCompare']; + isReportArchived?: boolean; }): OptionData | undefined { // When a user signs out, Onyx is cleared. Due to the lazy rendering with a virtual list, it's possible for // this method to be called after the Onyx data has been cleared out. In that case, it's fine to do @@ -703,7 +705,7 @@ function getOptionData({ result.parentReportID = report.parentReportID; result.isWaitingOnBankAccount = report.isWaitingOnBankAccount; result.notificationPreference = getReportNotificationPreference(report); - result.isAllowedToComment = canUserPerformWriteActionUtil(report); + result.isAllowedToComment = canUserPerformWriteActionUtil(report, isReportArchived); result.chatType = report.chatType; result.isDeletedParentAction = report.isDeletedParentAction; result.isSelfDM = isSelfDM(report); diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index ff8f0f3fe71e..915f5a01f7e7 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -1073,7 +1073,7 @@ function getNavigationUrlOnTaskDelete(report: OnyxEntry): stri /** * Cancels a task by setting the report state to SUBMITTED and status to CLOSED */ -function deleteTask(report: OnyxEntry) { +function deleteTask(report: OnyxEntry, isReportArchived: boolean) { if (!report) { return; } @@ -1082,7 +1082,7 @@ function deleteTask(report: OnyxEntry) { const optimisticReportActionID = optimisticCancelReportAction.reportActionID; const parentReportAction = getParentReportAction(report); const parentReport = getParentReport(report); - const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(report); + const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(report, isReportArchived); // If the task report is the last visible action in the parent report, we should navigate back to the parent report const shouldDeleteTaskReport = !ReportActionsUtils.doesReportHaveVisibleActions(report.reportID, canUserPerformWriteAction); diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx index e22e313fd2eb..514c719c2016 100644 --- a/src/pages/ReportDetailsPage.tsx +++ b/src/pages/ReportDetailsPage.tsx @@ -766,7 +766,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail const deleteTransaction = useCallback(() => { if (caseID === CASES.DEFAULT) { - deleteTask(report); + deleteTask(report, isReportArchived); return; } @@ -792,6 +792,7 @@ function ReportDetailsPage({policy, report, route, reportMetadata}: ReportDetail removeTransaction, report, requestParentReportAction, + isReportArchived, ]); // A flag to indicate whether the user chose to delete the transaction or not diff --git a/src/pages/Search/SearchMoneyRequestReportPage.tsx b/src/pages/Search/SearchMoneyRequestReportPage.tsx index dda2da79c44d..c01b9b761484 100644 --- a/src/pages/Search/SearchMoneyRequestReportPage.tsx +++ b/src/pages/Search/SearchMoneyRequestReportPage.tsx @@ -9,6 +9,7 @@ import MoneyRequestReportView from '@components/MoneyRequestReportView/MoneyRequ import ScreenWrapper from '@components/ScreenWrapper'; import useIsReportReadyToDisplay from '@hooks/useIsReportReadyToDisplay'; import useOnyx from '@hooks/useOnyx'; +import useReportIsArchived from '@hooks/useReportIsArchived'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; @@ -46,8 +47,9 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) { const [policies = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {allowStaleData: true, canBeMissing: false}); const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`]; const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP, {canBeMissing: true}); + const isReportArchived = useReportIsArchived(report?.reportID); - const {isEditingDisabled, isCurrentReportLoadedFromOnyx} = useIsReportReadyToDisplay(report, reportIDFromRoute); + const {isEditingDisabled, isCurrentReportLoadedFromOnyx} = useIsReportReadyToDisplay(report, reportIDFromRoute, isReportArchived); const [scrollPosition, setScrollPosition] = useState({}); const flatListRef = useRef(null); diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index 84c7a51ec231..4339318b628d 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -356,7 +356,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, isVisible={isDeleteTaskConfirmModalVisible} onConfirm={() => { setIsDeleteTaskConfirmModalVisible(false); - deleteTask(report); + deleteTask(report, isReportArchived); }} onCancel={() => setIsDeleteTaskConfirmModalVisible(false)} title={translate('task.deleteTask')} diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index 59050e8f7caf..b566b1538b6d 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -406,9 +406,9 @@ function ReportScreen({route, navigation}: ReportScreenProps) { navigation.setParams({reportActionID: ''}); }, [transactionThreadReportID, route?.params?.reportActionID, linkedAction, reportID, navigation, report, childReport]); - const {isEditingDisabled, isCurrentReportLoadedFromOnyx} = useIsReportReadyToDisplay(report, reportIDFromRoute); - const isReportArchived = useReportIsArchived(report?.reportID); + const {isEditingDisabled, isCurrentReportLoadedFromOnyx} = useIsReportReadyToDisplay(report, reportIDFromRoute, isReportArchived); + const isLinkedActionDeleted = useMemo( () => !!linkedAction && !shouldReportActionBeVisible(linkedAction, linkedAction.reportActionID, canUserPerformWriteAction(report, isReportArchived)), [linkedAction, report, isReportArchived],