Skip to content

Commit

Permalink
feat: add proper permissions & style system messages
Browse files Browse the repository at this point in the history
  • Loading branch information
BartoszGrajdek committed Jan 8, 2024
1 parent eb332d6 commit 62ee823
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 61 deletions.
2 changes: 2 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ const CONST = {
CHRONOSOOOLIST: 'CHRONOSOOOLIST',
CLOSED: 'CLOSED',
CREATED: 'CREATED',
HOLD: 'HOLD',
IOU: 'IOU',
MARKEDREIMBURSED: 'MARKEDREIMBURSED',
MODIFIEDEXPENSE: 'MODIFIEDEXPENSE',
Expand Down Expand Up @@ -594,6 +595,7 @@ const CONST = {
REMOVE_FROM_ROOM: 'REMOVEFROMROOM',
JOIN_ROOM: 'JOINROOM',
},
UNHOLD: 'UNHOLD',
},
THREAD_DISABLED: ['CREATED'],
},
Expand Down
33 changes: 26 additions & 7 deletions src/components/MoneyRequestHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction,
const isOnHold = TransactionUtils.isOnHold(transaction);
const {isSmallScreenWidth, windowWidth} = useWindowDimensions();

console.log('report: ', report);
console.log('parentReport: ', parentReport);
console.log('parentReportAction: ', parentReportAction);
console.log('transaction: ', transaction);
console.log("lodashGet(policy, 'role'): ", lodashGet(policy, 'role'));
console.log("lodashGet(policy, 'type'): ", lodashGet(policy, 'type'));

// Only the requestor can take delete the request, admins can only edit it.
const isActionOwner = lodashGet(parentReportAction, 'actorAccountID') === lodashGet(session, 'accountID', null);
const isPolicyAdmin = lodashGet(policy, 'role') === CONST.POLICY.ROLE.ADMIN;
Expand All @@ -88,7 +95,8 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction,
const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction);
const isPending = TransactionUtils.isExpensifyCardTransaction(transaction) && TransactionUtils.isPending(transaction);

const canModifyRequest = isActionOwner && !isSettled && !isApproved && !ReportActionsUtils.isDeletedAction(parentReportAction);
const isRequestModifiable = !isSettled && !isApproved && !ReportActionsUtils.isDeletedAction(parentReportAction);

This comment has been minimized.

Copy link
@rojiphil

rojiphil Jun 21, 2024

Contributor

Requests (like Hold) are not modifiable when the report itself is closed/archived. We missed adding that condition here thereby resulting in #42202

const canModifyRequest = isActionOwner && isRequestModifiable;

const changeMoneyRequestStatus = () => {
if (!isOnHold) {
Expand All @@ -113,14 +121,25 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction,

setIsDeleteModalVisible(false);
}, [canModifyRequest]);

const threeDotsMenuItems = [HeaderUtils.getPinMenuItem(report)];
if ((isPolicyAdmin || isActionOwner) && !isSettled && !isApproved && !ReportActionsUtils.isDeletedAction(parentReportAction)) {
threeDotsMenuItems.push({
icon: Expensicons.Stopwatch,
text: !isOnHold ? translate('iou.holdRequest') : translate('iou.unholdRequest'),
onSelected: () => changeMoneyRequestStatus(),
});
if (isRequestModifiable) {
if (isOnHold && (ReportUtils.isHoldCreator(transaction, lodashGet(report, 'reportID')) || isPolicyAdmin)) {
threeDotsMenuItems.push({
icon: Expensicons.Stopwatch,
text: translate('iou.unholdRequest'),
onSelected: () => changeMoneyRequestStatus(),
});
}
if (!isOnHold && (lodashGet(parentReport, 'type') === 'iou' || isPolicyAdmin || isActionOwner)) {
threeDotsMenuItems.push({
icon: Expensicons.Stopwatch,
text: translate('iou.holdRequest'),
onSelected: () => changeMoneyRequestStatus(),
});
}
}

if (canModifyRequest) {
if (!TransactionUtils.hasReceipt(transaction)) {
threeDotsMenuItems.push({
Expand Down
2 changes: 1 addition & 1 deletion src/components/TextPill.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type TextPillProps = {
function TextPill({color, children}: TextPillProps) {
const styles = useThemeStyles();

return <Text style={[{backgroundColor: color ?? colors.red, borderRadius: 6}, styles.overflowHidden, styles.textStrong, styles.ph2, styles.pv1]}>{children}</Text>;
return <Text style={[{backgroundColor: color ?? colors.red, borderRadius: 6}, styles.overflowHidden, styles.textStrong, styles.ph2, styles.pv1, styles.flexShrink0]}>{children}</Text>;
}

TextPill.displayName = 'TextPill';
Expand Down
61 changes: 21 additions & 40 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3097,79 +3097,52 @@ function buildOptimisticCreatedReportAction(emailCreatingAction: string, created
* Returns the necessary reportAction onyx data to indicate that the transaction has been put on hold optimistically
* @param [created] - Action created time
*/
function buildOptimisticHoldReportAction(created = DateUtils.getDBTime()): OptimisticSubmittedReportAction {
function buildOptimisticHoldReportAction(comment: string, created = DateUtils.getDBTime()): OptimisticSubmittedReportAction {
return {
reportActionID: NumberUtils.rand64(),
actionName: CONST.REPORT.ACTIONS.TYPE.SUBMITTED,
actionName: CONST.REPORT.ACTIONS.TYPE.HOLD,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
actorAccountID: currentUserAccountID,
message: [
{
type: CONST.REPORT.MESSAGE.TYPE.TEXT,
style: 'normal',
text: `held this request`,
text: `held this money request with the comment: ${comment}`,
},
],
person: [
{
type: CONST.REPORT.MESSAGE.TYPE.TEXT,
style: 'normal',
text: allPersonalDetails?.[currentUserAccountID ?? '']?.displayName ?? currentUserEmail,
},
],
automatic: true,
avatar: allPersonalDetails?.[currentUserAccountID ?? '']?.avatar ?? UserUtils.getDefaultAvatarURL(currentUserAccountID),
created,
shouldShow: true,
};
}

/**
* Returns the necessary reportAction onyx data to indicate that the transaction has been removed from hold optimistically
* @param [created] - Action created time
*/
function buildOptimisticUnHoldReportAction(created = DateUtils.getDBTime()): OptimisticSubmittedReportAction {
return {
reportActionID: NumberUtils.rand64(),
actionName: CONST.REPORT.ACTIONS.TYPE.SUBMITTED,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
actorAccountID: currentUserAccountID,
message: [
{
type: CONST.REPORT.MESSAGE.TYPE.TEXT,
style: 'normal',
text: `unheld this request`,
type: CONST.REPORT.MESSAGE.TYPE.COMMENT,
text: comment,
},
],
person: [
{
type: CONST.REPORT.MESSAGE.TYPE.TEXT,
style: 'normal',
style: 'strong',
text: allPersonalDetails?.[currentUserAccountID ?? '']?.displayName ?? currentUserEmail,
},
],
automatic: true,
automatic: false,
avatar: allPersonalDetails?.[currentUserAccountID ?? '']?.avatar ?? UserUtils.getDefaultAvatarURL(currentUserAccountID),
created,
shouldShow: true,
};
}

/**
* Returns the necessary reportAction user comment user provided to put on hold optimistically
* Returns the necessary reportAction onyx data to indicate that the transaction has been removed from hold optimistically
* @param [created] - Action created time
*/
function buildOptimisticHoldReportActionComment(comment: string, created = DateUtils.getDBTime()): OptimisticSubmittedReportAction {
function buildOptimisticUnHoldReportAction(created = DateUtils.getDBTime()): OptimisticSubmittedReportAction {
return {
reportActionID: NumberUtils.rand64(),
actionName: CONST.REPORT.ACTIONS.TYPE.SUBMITTED,
actionName: CONST.REPORT.ACTIONS.TYPE.UNHOLD,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
actorAccountID: currentUserAccountID,
message: [
{
type: CONST.REPORT.MESSAGE.TYPE.TEXT,
style: 'normal',
text: `${comment}`,
text: `unheld this money request`,
},
],
person: [
Expand All @@ -3179,7 +3152,7 @@ function buildOptimisticHoldReportActionComment(comment: string, created = DateU
text: allPersonalDetails?.[currentUserAccountID ?? '']?.displayName ?? currentUserEmail,
},
],
automatic: true,
automatic: false,
avatar: allPersonalDetails?.[currentUserAccountID ?? '']?.avatar ?? UserUtils.getDefaultAvatarURL(currentUserAccountID),
created,
shouldShow: true,
Expand Down Expand Up @@ -4333,6 +4306,14 @@ function navigateToPrivateNotes(report: Report, session: Session) {
Navigation.navigate(ROUTES.PRIVATE_NOTES_LIST.getRoute(report.reportID));
}

/**
* Check if Report has any held expenses
*/
function isHoldCreator(transaction: Transaction, reportID: string): boolean {
const holdReportAction = ReportActionsUtils.getReportAction(reportID, `${transaction.comment?.hold}`);
return isActionCreator(holdReportAction);
}

/**
* Check if Report has any held expenses
*/
Expand Down Expand Up @@ -4563,13 +4544,13 @@ export {
shouldDisableWelcomeMessage,
navigateToPrivateNotes,
canEditWriteCapability,
isHoldCreator,
hasHeldExpenses,
hasOnlyHeldExpenses,
getNonHeldAndFullAmount,
hasSmartscanError,
shouldAutoFocusOnKeyPress,
buildOptimisticHoldReportAction,
buildOptimisticHoldReportActionComment,
buildOptimisticUnHoldReportAction,
shouldDisableThread,
};
Expand Down
23 changes: 19 additions & 4 deletions src/libs/actions/IOU.js
Original file line number Diff line number Diff line change
Expand Up @@ -3457,8 +3457,7 @@ function getIOUReportID(iou, route) {
*/
function putOnHold(transactionID, comment, reportID) {
const createdDate = new Date();
const createdReportAction = ReportUtils.buildOptimisticHoldReportAction(createdDate);
const createdCommentReportAction = ReportUtils.buildOptimisticHoldReportActionComment(comment, new Date(createdDate.getTime() + 1));
const createdReportAction = ReportUtils.buildOptimisticHoldReportAction(comment, DateUtils.getDBTime(createdDate));
const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`];
const transactionDetails = ReportUtils.getTransactionDetails(transaction);

Expand All @@ -3468,7 +3467,6 @@ function putOnHold(transactionID, comment, reportID) {
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: {
[createdReportAction.reportActionID]: createdReportAction,
[createdCommentReportAction.reportActionID]: createdCommentReportAction,
},
},
{
Expand All @@ -3482,6 +3480,16 @@ function putOnHold(transactionID, comment, reportID) {
},
];

const successData = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: {
[createdReportAction.reportActionID]: null,
},
},
];

const failureData = [
{
onyxMethod: Onyx.METHOD.MERGE,
Expand All @@ -3501,7 +3509,7 @@ function putOnHold(transactionID, comment, reportID) {
transactionID,
comment,
},
{optimisticData, successData: [], failureData},
{optimisticData, successData, failureData},
);
}

Expand Down Expand Up @@ -3535,6 +3543,13 @@ function unholdRequest(transactionID, reportID) {
];

const successData = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: {
[createdReportAction.reportActionID]: null,
},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
Expand Down
35 changes: 27 additions & 8 deletions src/pages/home/report/ReportActionItemFragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const propTypes = {
/** Whether the report action type is 'APPROVED' or 'SUBMITTED'. Used to style system messages from Old Dot */
isApprovedOrSubmittedReportAction: PropTypes.bool,

/** Whether the report action type is 'UNHOLD' or 'HOLD'. Used to style messages related to hold requests */
isHoldReportAction: PropTypes.bool,

/** Used to format RTL display names in Old Dot system messages e.g. Arabic */
isFragmentContainingDisplayName: PropTypes.bool,

Expand All @@ -89,6 +92,7 @@ const defaultProps = {
actorIcon: {},
isThreadParentMessage: false,
isApprovedOrSubmittedReportAction: false,
isHoldReportAction: false,
isFragmentContainingDisplayName: false,
displayAsGroup: false,
};
Expand Down Expand Up @@ -131,14 +135,29 @@ function ReportActionItemFragment(props) {
);
}
case 'TEXT': {
return props.isApprovedOrSubmittedReportAction ? (
<Text
numberOfLines={props.isSingleLine ? 1 : undefined}
style={[styles.chatItemMessage, styles.colorMuted]}
>
{props.isFragmentContainingDisplayName ? convertToLTR(props.fragment.text) : props.fragment.text}
</Text>
) : (
if (props.isApprovedOrSubmittedReportAction) {
return (
<Text
numberOfLines={props.isSingleLine ? 1 : undefined}
style={[styles.chatItemMessage, styles.colorMuted]}
>
{props.isFragmentContainingDisplayName ? convertToLTR(props.fragment.text) : props.fragment.text}
</Text>
);
}

if (props.isHoldReportAction) {
return (
<Text
numberOfLines={props.isSingleLine ? 1 : undefined}
style={[styles.chatItemMessage]}
>
{props.isFragmentContainingDisplayName ? convertToLTR(props.fragment.text) : props.fragment.text}
</Text>
);
}

return (
<UserDetailsTooltip
accountID={props.accountID}
delegateAccountID={props.delegateAccountID}
Expand Down
3 changes: 3 additions & 0 deletions src/pages/home/report/ReportActionItemMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ function ReportActionItemMessage({action, displayAsGroup, reportID, style, isHid

const isApprovedOrSubmittedReportAction = [CONST.REPORT.ACTIONS.TYPE.APPROVED, CONST.REPORT.ACTIONS.TYPE.SUBMITTED].some((type) => type === action.actionName);

const isHoldReportAction = [CONST.REPORT.ACTIONS.TYPE.HOLD, CONST.REPORT.ACTIONS.TYPE.UNHOLD].some((type) => type === action.actionName);

/**
* Get the ReportActionItemFragments
* @param shouldWrapInText determines whether the fragments are wrapped in a Text component
Expand All @@ -79,6 +81,7 @@ function ReportActionItemMessage({action, displayAsGroup, reportID, style, isHid
style={style}
displayAsGroup={displayAsGroup}
isApprovedOrSubmittedReportAction={isApprovedOrSubmittedReportAction}
isHoldReportAction={isHoldReportAction}
// Since system messages from Old Dot begin with the person who performed the action,
// the first fragment will contain the person's display name and their email. We'll use this
// to decide if the fragment should be from left to right for RTL display names e.g. Arabic for proper
Expand Down
1 change: 1 addition & 0 deletions src/pages/home/report/ReportActionItemSingle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ function ReportActionItemSingle({
const personalDetails = usePersonalDetails() ?? CONST.EMPTY_OBJECT;
const actorAccountID = action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && iouReport ? iouReport.managerID : action.actorAccountID;
let displayName = ReportUtils.getDisplayNameForParticipant(actorAccountID);
console.log('actionTest', action, displayName);
const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails[actorAccountID ?? -1] ?? {};
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
let actorHint = (login || (displayName ?? '')).replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, '');
Expand Down
2 changes: 1 addition & 1 deletion src/pages/home/report/comment/TextCommentFragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function TextCommentFragment(props) {
const theme = useTheme();
const styles = useThemeStyles();
const {fragment, styleAsDeleted} = props;
const {html, text} = fragment;
const {html = '', text} = fragment;

// If the only difference between fragment.text and fragment.html is <br /> tags
// we render it as text, not as html.
Expand Down
14 changes: 14 additions & 0 deletions src/types/onyx/OriginalMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ type OriginalMessageActionName =
| 'CHRONOSOOOLIST'
| 'CLOSED'
| 'CREATED'
| 'HOLD'
| 'UNHOLD'
| 'IOU'
| 'MODIFIEDEXPENSE'
| 'REIMBURSEMENTQUEUED'
Expand All @@ -26,6 +28,16 @@ type OriginalMessageApproved = {
};
type OriginalMessageSource = 'Chronos' | 'email' | 'ios' | 'android' | 'web' | '';

type OriginalMessageHold = {
actionName: typeof CONST.REPORT.ACTIONS.TYPE.HOLD;
originalMessage: unknown;
};

type OriginalMessageUnHold = {
actionName: typeof CONST.REPORT.ACTIONS.TYPE.UNHOLD;
originalMessage: unknown;
};

type IOUDetails = {
amount: number;
comment?: string;
Expand Down Expand Up @@ -242,6 +254,8 @@ type OriginalMessage =
| OriginalMessageSubmitted
| OriginalMessageClosed
| OriginalMessageCreated
| OriginalMessageHold
| OriginalMessageUnHold
| OriginalMessageRenamed
| OriginalMessageChronosOOOList
| OriginalMessageReportPreview
Expand Down

0 comments on commit 62ee823

Please sign in to comment.