Skip to content
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

[Audit][Implementation] hasDraft replacement #37281

Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
00c81de
remove hasDraft from Report model
kacper-mikolajczak Feb 27, 2024
d177314
remove reportWithoutHasDraftSelector
kacper-mikolajczak Feb 27, 2024
eeec9ba
use draft comment to calculate hasDraftComment
kacper-mikolajczak Feb 27, 2024
7b8a757
fix shouldREportBeInOptionList
kacper-mikolajczak Feb 28, 2024
9df353b
trim the comment for hasDraftComment calculations
kacper-mikolajczak Feb 28, 2024
8876c08
create draft message store
kacper-mikolajczak Mar 4, 2024
cdef526
split gORIDs into smaller functions
kacper-mikolajczak Mar 4, 2024
2f0555f
fixing complexity
kacper-mikolajczak Mar 5, 2024
74c658a
Revert "fixing complexity"
kacper-mikolajczak Mar 8, 2024
024a50c
Revert "split gORIDs into smaller functions"
kacper-mikolajczak Mar 8, 2024
3330608
invalidate reports order on drafts change
kacper-mikolajczak Mar 8, 2024
bb2da17
remove hasDraft from tests
kacper-mikolajczak Mar 8, 2024
b166c50
fix draftComment computation
kacper-mikolajczak Mar 21, 2024
3fddd59
change name
kacper-mikolajczak Mar 21, 2024
c1214ab
remain ordering of default Option object
kacper-mikolajczak Mar 21, 2024
1b245b4
make saveReportComment delete drafts for empty comments
kacper-mikolajczak Mar 22, 2024
059ea4a
cleanup
kacper-mikolajczak Mar 22, 2024
e599e5b
do not save drafts with spaces only
kacper-mikolajczak Mar 22, 2024
7e2c3c5
prepare draft comment util
kacper-mikolajczak Mar 22, 2024
a3cd97d
waitForCollectionCallback in DraftCommentUtils
kacper-mikolajczak Mar 22, 2024
da1d823
rename draftCommentMap to draftCommentCollection
kacper-mikolajczak Mar 22, 2024
7adfbc9
merge & fix to main
kacper-mikolajczak Mar 22, 2024
67a8736
fix tests
kacper-mikolajczak Mar 22, 2024
eff88de
add draftComments to FlashList extraData
kacper-mikolajczak Mar 22, 2024
4b56f6f
fix minor things
kacper-mikolajczak Mar 22, 2024
c9d75e2
merge main
kacper-mikolajczak Mar 25, 2024
7b2c6bc
merge main
kacper-mikolajczak Mar 27, 2024
fa7415c
fix tests
kacper-mikolajczak Mar 28, 2024
1575de7
merge main
kacper-mikolajczak Apr 2, 2024
b52bb0b
fix list reordering
kacper-mikolajczak Apr 4, 2024
564933c
Merge branch 'main' into audit/implementation/hasDraft-replacement
kacper-mikolajczak Apr 4, 2024
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
5 changes: 3 additions & 2 deletions src/components/LHNOptionsList/LHNOptionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {withOnyx} from 'react-native-onyx';
import withCurrentReportID from '@components/withCurrentReportID';
import usePermissions from '@hooks/usePermissions';
import useThemeStyles from '@hooks/useThemeStyles';
import * as DraftCommentUtils from '@libs/DraftCommentUtils';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -60,7 +61,7 @@ function LHNOptionsList({
const itemPolicy = policy?.[`${ONYXKEYS.COLLECTION.POLICY}${itemFullReport?.policyID}`] ?? null;
const transactionID = itemParentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? itemParentReportAction.originalMessage.IOUTransactionID ?? '' : '';
const itemTransaction = transactions?.[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] ?? null;
const itemComment = draftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`] ?? '';
const hasDraftComment = DraftCommentUtils.isValidDraftComment(draftComments?.[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`]);
const sortedReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(itemReportActions);
const lastReportAction = sortedReportActions[0];

Expand All @@ -87,7 +88,7 @@ function LHNOptionsList({
isFocused={!shouldDisableFocusOptions && reportID === currentReportID}
onSelectRow={onSelectRow}
preferredLocale={preferredLocale}
comment={itemComment}
hasDraftComment={hasDraftComment}
transactionViolations={transactionViolations}
canUseViolations={canUseViolations}
onLayout={onLayoutItem}
Expand Down
4 changes: 2 additions & 2 deletions src/components/LHNOptionsList/OptionRowLHN.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import CONST from '@src/CONST';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type {OptionRowLHNProps} from './types';

function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, optionItem, viewMode = 'default', style, onLayout = () => {}}: OptionRowLHNProps) {
function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, optionItem, viewMode = 'default', style, onLayout = () => {}, hasDraftComment}: OptionRowLHNProps) {
const theme = useTheme();
const styles = useThemeStyles();
const popoverAnchor = useRef<View>(null);
Expand Down Expand Up @@ -256,7 +256,7 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti
/>
</View>
)}
{optionItem.hasDraftComment && optionItem.isAllowedToComment && (
{hasDraftComment && optionItem.isAllowedToComment && (
<View
style={styles.ml2}
accessibilityLabel={translate('sidebarScreen.draftedMessage')}
Expand Down
14 changes: 1 addition & 13 deletions src/components/LHNOptionsList/OptionRowLHNData.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import {deepEqual} from 'fast-equals';
import React, {useEffect, useMemo, useRef} from 'react';
import React, {useMemo, useRef} from 'react';
import * as ReportUtils from '@libs/ReportUtils';
import SidebarUtils from '@libs/SidebarUtils';
import * as Report from '@userActions/Report';
import CONST from '@src/CONST';
import type {OptionData} from '@src/libs/ReportUtils';
import OptionRowLHN from './OptionRowLHN';
Expand All @@ -20,7 +19,6 @@ function OptionRowLHNData({
reportActions,
personalDetails = {},
preferredLocale = CONST.LOCALES.DEFAULT,
comment,
policy,
receiptTransactions,
parentReportAction,
Expand All @@ -30,8 +28,6 @@ function OptionRowLHNData({
canUseViolations,
...propsToForward
}: OptionRowLHNDataProps) {
const reportID = propsToForward.reportID;

const optionItemRef = useRef<OptionData>();

const hasViolations = canUseViolations && ReportUtils.doesTransactionThreadHaveViolations(fullReport, transactionViolations, parentReportAction ?? null);
Expand Down Expand Up @@ -71,14 +67,6 @@ function OptionRowLHNData({
receiptTransactions,
]);

useEffect(() => {
if (!optionItem || !!optionItem.hasDraftComment || !comment || comment.length <= 0 || isFocused) {
return;
}
Report.setReportWithDraft(reportID, true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<OptionRowLHN
// eslint-disable-next-line react/jsx-props-no-spreading
Expand Down
7 changes: 5 additions & 2 deletions src/components/LHNOptionsList/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ type OptionRowLHNDataProps = {
/** The transaction linked to the report's last action */
lastReportActionTransaction?: OnyxEntry<Transaction | EmptyObject>;

/** Comment added to report */
comment: string;
/** Whether a report contains a draft */
hasDraftComment: boolean;

/** The receipt transaction from the parent report action */
receiptTransactions: OnyxCollection<Transaction>;
Expand Down Expand Up @@ -134,6 +134,9 @@ type OptionRowLHNProps = {
/** The item that should be rendered */
optionItem?: OptionData;

/** Whether a report contains a draft */
hasDraftComment: boolean;

onLayout?: (event: LayoutChangeEvent) => void;
};

Expand Down
3 changes: 0 additions & 3 deletions src/components/optionPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ export default PropTypes.shape({
// reportID (only present when there is a matching report)
reportID: PropTypes.string,

// Whether the report has a draft comment or not
hasDraftComment: PropTypes.bool,

// Key used internally by React
keyForList: PropTypes.string,

Expand Down
25 changes: 0 additions & 25 deletions src/libs/ComposerUtils/getDraftComment.ts

This file was deleted.

49 changes: 49 additions & 0 deletions src/libs/DraftCommentUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type {OnyxEntry} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import ONYXKEYS from '@src/ONYXKEYS';

const draftCommentMap: Record<string, OnyxEntry<string>> = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT,
callback: (value, key) => {
if (!key) {
return;
}

const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, '');
draftCommentMap[reportID] = value;
},
});
kacper-mikolajczak marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns a draft comment from the onyx collection for given reportID.
* Note: You should use the HOCs/hooks to get onyx data, instead of using this directly.
* A valid use-case of this function is outside React components, like in utility functions.
*/
function getDraftComment(reportID: string): OnyxEntry<string> {
return draftCommentMap[reportID];
}

/**
* Returns true if the report has a valid draft comment.
* A valid draft comment is a non-empty string.
*/
function isValidDraftComment(comment?: string | null): boolean {
return !!comment?.trim();
}

/**
* Returns true if the report has a valid draft comment.
*/
function hasValidDraftComment(reportID: string): boolean {
return isValidDraftComment(getDraftComment(reportID));
}

/**
* Prepares a draft comment by trimming it and returning null if it's empty.
*/
function prepareDraftComment(comment: string | null) {
return comment?.trim() || null;
}

export {getDraftComment, isValidDraftComment, hasValidDraftComment, prepareDraftComment};
9 changes: 0 additions & 9 deletions src/libs/OnyxSelectors/reportWithoutHasDraftSelector.ts

This file was deleted.

2 changes: 0 additions & 2 deletions src/libs/OptionsListUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,6 @@ function createOption(
login: null,
reportID: '',
phoneNumber: null,
hasDraftComment: false,
keyForList: null,
searchText: null,
isDefaultRoom: false,
Expand Down Expand Up @@ -660,7 +659,6 @@ function createOption(
result.ownerAccountID = report.ownerAccountID;
result.reportID = report.reportID;
result.isUnread = ReportUtils.isUnread(report);
result.hasDraftComment = report.hasDraft;
result.isPinned = report.isPinned;
result.iouReportID = report.iouReportID;
result.keyForList = String(report.reportID);
Expand Down
7 changes: 5 additions & 2 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import type IconAsset from '@src/types/utils/IconAsset';
import * as CollectionUtils from './CollectionUtils';
import * as CurrencyUtils from './CurrencyUtils';
import DateUtils from './DateUtils';
import {hasValidDraftComment} from './DraftCommentUtils';
import isReportMessageAttachment from './isReportMessageAttachment';
import localeCompare from './LocaleCompare';
import * as LocalePhoneNumber from './LocalePhoneNumber';
Expand Down Expand Up @@ -376,7 +377,6 @@ type OptionData = {
phoneNumber?: string | null;
isUnread?: boolean | null;
isUnreadWithMention?: boolean | null;
hasDraftComment?: boolean | null;
keyForList?: string | null;
searchText?: string | null;
isIOUReportOwner?: boolean | null;
Expand Down Expand Up @@ -3935,9 +3935,12 @@ function shouldReportBeInOptionList({
return true;
}

// Retrieve the draft comment for the report and convert it to a boolean
const hasDraftComment = hasValidDraftComment(report.reportID);

// Include reports that are relevant to the user in any view mode. Criteria include having a draft or having a GBR showing.
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
if (report.hasDraft || requiresAttentionFromCurrentUser(report)) {
if (hasDraftComment || requiresAttentionFromCurrentUser(report)) {
return true;
}
const lastVisibleMessage = ReportActionsUtils.getLastVisibleMessage(report.reportID);
Expand Down
5 changes: 2 additions & 3 deletions src/libs/SidebarUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {ReportActions} from '@src/types/onyx/ReportAction';
import type ReportAction from '@src/types/onyx/ReportAction';
import type DeepValueOf from '@src/types/utils/DeepValueOf';
import * as CollectionUtils from './CollectionUtils';
import {hasValidDraftComment} from './DraftCommentUtils';
import localeCompare from './LocaleCompare';
import * as LocalePhoneNumber from './LocalePhoneNumber';
import * as Localize from './Localize';
Expand Down Expand Up @@ -132,7 +133,7 @@ function getOrderedReportIDs(
const reportAction = ReportActionsUtils.getReportAction(report.parentReportID ?? '', report.parentReportActionID ?? '');
if (isPinned || ReportUtils.requiresAttentionFromCurrentUser(report, reportAction)) {
pinnedAndGBRReports.push(report);
} else if (report.hasDraft) {
} else if (hasValidDraftComment(report.reportID)) {
draftReports.push(report);
} else if (ReportUtils.isArchivedRoom(report)) {
archivedReports.push(report);
Expand Down Expand Up @@ -204,7 +205,6 @@ function getOptionData({
phoneNumber: null,
isUnread: null,
isUnreadWithMention: null,
hasDraftComment: false,
keyForList: null,
searchText: null,
isPinned: false,
Expand Down Expand Up @@ -246,7 +246,6 @@ function getOptionData({
// setting it Unread so we add additional condition here to avoid empty chat LHN from being bold.
result.isUnread = ReportUtils.isUnread(report) && !!report.lastActorAccountID;
result.isUnreadWithMention = ReportUtils.isUnreadWithMention(report);
result.hasDraftComment = report.hasDraft;
result.isPinned = report.isPinned;
result.iouReportID = report.iouReportID;
result.keyForList = String(report.reportID);
Expand Down
9 changes: 2 additions & 7 deletions src/libs/actions/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ Onyx.connect({
return;
}
const {reportID} = policyReport;
cleanUpMergeQueries[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] = {hasDraft: false};
cleanUpSetQueries[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`] = null;
cleanUpSetQueries[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}${reportID}`] = null;
});
Expand Down Expand Up @@ -276,7 +275,6 @@ function deleteWorkspace(policyID: string, policyName: string) {
value: {
stateNum: CONST.REPORT.STATE_NUM.APPROVED,
statusNum: CONST.REPORT.STATUS_NUM.CLOSED,
hasDraft: false,
oldPolicyName: allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.name ?? '',
},
});
Expand Down Expand Up @@ -315,14 +313,13 @@ function deleteWorkspace(policyID: string, policyName: string) {
];

reportsToArchive.forEach((report) => {
const {reportID, stateNum, statusNum, hasDraft, oldPolicyName} = report ?? {};
const {reportID, stateNum, statusNum, oldPolicyName} = report ?? {};
failureData.push({
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: {
stateNum,
statusNum,
hasDraft,
oldPolicyName,
},
});
Expand Down Expand Up @@ -547,7 +544,6 @@ function removeMembers(accountIDs: number[], policyID: string) {
statusNum: CONST.REPORT.STATUS_NUM.CLOSED,
stateNum: CONST.REPORT.STATE_NUM.APPROVED,
oldPolicyName: policy.name,
hasDraft: false,
},
});
});
Expand Down Expand Up @@ -602,14 +598,13 @@ function removeMembers(accountIDs: number[], policyID: string) {
...announceRoomMembers.onyxFailureData,
];

filteredWorkspaceChats.forEach(({reportID, stateNum, statusNum, hasDraft, oldPolicyName = null}) => {
filteredWorkspaceChats.forEach(({reportID, stateNum, statusNum, oldPolicyName = null}) => {
failureData.push({
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: {
stateNum,
statusNum,
hasDraft,
oldPolicyName,
},
});
Expand Down
14 changes: 5 additions & 9 deletions src/libs/actions/Report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import type UpdateRoomVisibilityParams from '@libs/API/parameters/UpdateRoomVisi
import {READ_COMMANDS, SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
import * as CollectionUtils from '@libs/CollectionUtils';
import DateUtils from '@libs/DateUtils';
import {prepareDraftComment} from '@libs/DraftCommentUtils';
import * as EmojiUtils from '@libs/EmojiUtils';
import * as Environment from '@libs/Environment/Environment';
import * as ErrorUtils from '@libs/ErrorUtils';
Expand Down Expand Up @@ -1041,21 +1042,17 @@ function togglePinnedState(reportID: string, isPinnedChat: boolean) {
/**
* Saves the comment left by the user as they are typing. By saving this data the user can switch between chats, close
* tab, refresh etc without worrying about loosing what they typed out.
* When empty string or null is passed, it will delete the draft comment from Onyx store.
*/
function saveReportComment(reportID: string, comment: string) {
Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`, comment);
function saveReportDraftComment(reportID: string, comment: string | null) {
Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`, prepareDraftComment(comment));
}

/** Saves the number of lines for the comment */
function saveReportCommentNumberOfLines(reportID: string, numberOfLines: number) {
Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT_NUMBER_OF_LINES}${reportID}`, numberOfLines);
}

/** Immediate indication whether the report has a draft comment. */
function setReportWithDraft(reportID: string, hasDraft: boolean): Promise<void> {
return Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {hasDraft});
}

/** Broadcasts whether or not a user is typing on a report over the report's private pusher channel. */
function broadcastUserIsTyping(reportID: string) {
const privateReportChannelName = getReportChannelName(reportID);
Expand Down Expand Up @@ -2911,7 +2908,7 @@ export {
subscribeToReportLeavingEvents,
unsubscribeFromReportChannel,
unsubscribeFromLeavingRoomReportChannel,
saveReportComment,
saveReportDraftComment,
saveReportCommentNumberOfLines,
broadcastUserIsTyping,
broadcastUserIsLeavingRoom,
Expand All @@ -2923,7 +2920,6 @@ export {
saveReportActionDraftNumberOfLines,
deleteReportComment,
navigateToConciergeChat,
setReportWithDraft,
addPolicyReport,
deleteReport,
navigateToConciergeChatAndDeleteReport,
Expand Down
Loading
Loading