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

Tweak UI for deleted message and expense #54804

Merged
merged 30 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1b12787
fix: Tweak UI for deleted message and expense.
Krishna2323 Dec 5, 2024
df91aa1
Merge branch 'Expensify:main' into krishna2323/issue/53617
Krishna2323 Dec 26, 2024
876bb7b
Merge branch 'Expensify:main' into krishna2323/issue/53617
Krishna2323 Dec 31, 2024
e6069b2
add chatbubble slash svg.
Krishna2323 Jan 5, 2025
0c52fb1
update deleted message fragment for tasks.
Krishna2323 Jan 6, 2025
ea91789
update deleted message fragment for iou requests.
Krishna2323 Jan 6, 2025
4ac5653
remove console log.
Krishna2323 Jan 6, 2025
cd95604
Merge branch 'Expensify:main' into krishna2323/issue/53617
Krishna2323 Jan 6, 2025
9954378
use variables size.
Krishna2323 Jan 6, 2025
a121cbc
use delete action renderer for hidden messages also.
Krishna2323 Jan 6, 2025
ee51a02
Merge branch 'Expensify:main' into krishna2323/issue/53617
Krishna2323 Jan 9, 2025
fa8e8c5
use trashcan for all deleted actions.
Krishna2323 Jan 9, 2025
f076e9d
remove DELETED_ACTION_TYPE constant.
Krishna2323 Jan 9, 2025
2ebfcb9
minor fix.
Krishna2323 Jan 9, 2025
92f4a57
use different icons for reversed transaction and hidden message.
Krishna2323 Jan 9, 2025
232b44c
Merge branch 'Expensify:main' into krishna2323/issue/53617
Krishna2323 Jan 9, 2025
c5e2cec
add arrows left-right icon.
Krishna2323 Jan 12, 2025
6c82ea8
Merge branch 'Expensify:main' into krishna2323/issue/53617
Krishna2323 Jan 12, 2025
7ec5eea
fix ESLint issues.
Krishna2323 Jan 12, 2025
576597d
update MoneyRequestAction to use useOnyx.
Krishna2323 Jan 12, 2025
dfbfca7
Merge branch 'Expensify:main' into krishna2323/issue/53617
Krishna2323 Jan 14, 2025
b158c42
Merge branch 'Expensify:main' into krishna2323/issue/53617
Krishna2323 Jan 14, 2025
166d6d9
fix ESLint.
Krishna2323 Jan 14, 2025
f8c41a3
fix ESLint.
Krishna2323 Jan 14, 2025
5d58689
fix ESLint.
Krishna2323 Jan 14, 2025
b90b8c6
Merge branch 'main' into krishna2323/issue/53617
Krishna2323 Jan 17, 2025
2334017
minor fix.
Krishna2323 Jan 17, 2025
737f1f0
Merge branch 'main' into krishna2323/issue/53617
Krishna2323 Jan 24, 2025
10a2bf9
fix lint issues.
Krishna2323 Jan 24, 2025
5f2028c
fix crash.
Krishna2323 Jan 24, 2025
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
6 changes: 6 additions & 0 deletions assets/images/arrows-leftright.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions assets/images/chatbubble-slash.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,9 @@ const CONST = {
MAX_LENGTH: 83,
},

REVERSED_TRANSACTION_ATTRIBUTE: 'is-reversed-transaction',
HIDDEN_MESSAGE_ATTRIBUTE: 'is-hidden-message',

CALENDAR_PICKER: {
// Numbers were arbitrarily picked.
MIN_YEAR: CURRENT_YEAR - 100,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ function BaseHTMLEngineProvider({textSelectable = false, children, enableExperim
mixedUAStyles: {...styles.formError, ...styles.mb0},
contentModel: HTMLContentModel.block,
}),
'deleted-action': HTMLElementModel.fromCustomModel({
tagName: 'alert-text',
mixedUAStyles: {...styles.formError, ...styles.mb0},
contentModel: HTMLContentModel.block,
}),
'muted-text': HTMLElementModel.fromCustomModel({
tagName: 'muted-text',
mixedUAStyles: {...styles.colorMuted, ...styles.mb0},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';
import {View} from 'react-native';
import type {CustomRendererProps, TPhrasing, TText} from 'react-native-render-html';
import {TNodeChildrenRenderer} from 'react-native-render-html';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import Text from '@components/Text';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';

function DeletedActionRenderer({tnode}: CustomRendererProps<TText | TPhrasing>) {
const styles = useThemeStyles();
const theme = useTheme();
const htmlAttribs = tnode.attributes;

const reversedTransactionValue = htmlAttribs[CONST.REVERSED_TRANSACTION_ATTRIBUTE];
const hiddenMessageValue = htmlAttribs[CONST.HIDDEN_MESSAGE_ATTRIBUTE];

const getIcon = () => {
if (reversedTransactionValue === 'true') {
return Expensicons.ArrowsLeftRight;
}
if (hiddenMessageValue === 'true') {
return Expensicons.EyeDisabled;
}
return Expensicons.Trashcan;
};

return (
<View style={[styles.p4, styles.mt1, styles.appBG, styles.border, {borderColor: theme.border}, styles.flexRow, styles.justifyContentCenter, styles.alignItemsCenter, styles.gap2]}>
<Icon
width={variables.iconSizeMedium}
height={variables.iconSizeMedium}
fill={theme.icon}
src={getIcon()}
/>
<TNodeChildrenRenderer
tnode={tnode}
renderChild={(props) => {
const firstChild = props?.childTnode?.children?.at(0);
const data = firstChild && 'data' in firstChild ? firstChild.data : null;

if (typeof data === 'string') {
return <Text style={(styles.textLabelSupporting, styles.textStrong)}>{data}</Text>;
}
return props.childElement;
}}
/>
</View>
);
}

DeletedActionRenderer.displayName = 'DeletedActionRenderer';

export default DeletedActionRenderer;
2 changes: 2 additions & 0 deletions src/components/HTMLEngineProvider/HTMLRenderers/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type {CustomTagRendererRecord} from 'react-native-render-html';
import AnchorRenderer from './AnchorRenderer';
import CodeRenderer from './CodeRenderer';
import DeletedActionRenderer from './DeletedActionRenderer';
import EditedRenderer from './EditedRenderer';
import EmojiRenderer from './EmojiRenderer';
import ImageRenderer from './ImageRenderer';
Expand Down Expand Up @@ -30,6 +31,7 @@ const HTMLEngineProviderComponentList: CustomTagRendererRecord = {
'mention-here': MentionHereRenderer,
emoji: EmojiRenderer,
'next-step-email': NextStepEmailRenderer,
'deleted-action': DeletedActionRenderer,
/* eslint-enable @typescript-eslint/naming-convention */
};

Expand Down
4 changes: 4 additions & 0 deletions src/components/Icon/Expensicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ArrowRightLong from '@assets/images/arrow-right-long.svg';
import ArrowRight from '@assets/images/arrow-right.svg';
import ArrowUpLong from '@assets/images/arrow-up-long.svg';
import UpArrow from '@assets/images/arrow-up.svg';
import ArrowsLeftRight from '@assets/images/arrows-leftright.svg';
import ArrowsUpDown from '@assets/images/arrows-updown.svg';
import AttachmentNotFound from '@assets/images/attachment-not-found.svg';
import AdminRoomAvatar from '@assets/images/avatars/admin-room.svg';
Expand Down Expand Up @@ -43,6 +44,7 @@ import Cash from '@assets/images/cash.svg';
import Chair from '@assets/images/chair.svg';
import ChatBubbleAdd from '@assets/images/chatbubble-add.svg';
import ChatBubbleReply from '@assets/images/chatbubble-reply.svg';
import ChatBubbleSlash from '@assets/images/chatbubble-slash.svg';
import ChatBubbleUnread from '@assets/images/chatbubble-unread.svg';
import ChatBubble from '@assets/images/chatbubble.svg';
import ChatBubbles from '@assets/images/chatbubbles.svg';
Expand Down Expand Up @@ -220,6 +222,7 @@ export {
ArrowRight,
ArrowRightLong,
ArrowsUpDown,
ArrowsLeftRight,
ArrowUpLong,
ArrowDownLong,
AttachmentNotFound,
Expand Down Expand Up @@ -390,6 +393,7 @@ export {
Linkedin,
Instagram,
ChatBubbleAdd,
ChatBubbleSlash,
ChatBubbleUnread,
ChatBubbleReply,
Lightbulb,
Expand Down
68 changes: 24 additions & 44 deletions src/components/ReportActionItem/MoneyRequestAction.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import React from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import RenderHTML from '@components/RenderHTML';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useThemeStyles from '@hooks/useThemeStyles';
import * as IOUUtils from '@libs/IOUUtils';
import {isIOUReportPendingCurrencyConversion} from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import {isDeletedParentAction, isReversedTransaction, isSplitBillAction, isTrackExpenseAction} from '@libs/ReportActionsUtils';
import type {ContextMenuAnchor} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
Expand All @@ -18,18 +17,7 @@ import type * as OnyxTypes from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import MoneyRequestPreview from './MoneyRequestPreview';

type MoneyRequestActionOnyxProps = {
/** Chat report associated with iouReport */
chatReport: OnyxEntry<OnyxTypes.Report>;

/** IOU report data object */
iouReport: OnyxEntry<OnyxTypes.Report>;

/** Report actions for this report */
reportActions: OnyxEntry<OnyxTypes.ReportActions>;
};

type MoneyRequestActionProps = MoneyRequestActionOnyxProps & {
type MoneyRequestActionProps = {
/** All the data of the action */
action: OnyxTypes.ReportAction;

Expand Down Expand Up @@ -72,9 +60,6 @@ function MoneyRequestAction({
isMostRecentIOUReportAction,
contextMenuAnchor,
checkIfContextMenuActive = () => {},
chatReport,
iouReport,
reportActions,
isHovered = false,
style,
isWhisper = false,
Expand All @@ -83,23 +68,29 @@ function MoneyRequestAction({
const styles = useThemeStyles();
const {translate} = useLocalize();
const {isOffline} = useNetwork();
const isSplitBillAction = ReportActionsUtils.isSplitBillAction(action);
const isTrackExpenseAction = ReportActionsUtils.isTrackExpenseAction(action);
const isActionSplitBill = isSplitBillAction(action);
const isActionTrackExpense = isTrackExpenseAction(action);
const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, {canEvict: false});
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`);
const [iouReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${requestReportID}`);

const onMoneyRequestPreviewPressed = () => {
if (isSplitBillAction) {
const reportActionID = action.reportActionID ?? '-1';
if (isActionSplitBill) {
const reportActionID = action.reportActionID;
Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(chatReportID, reportActionID, Navigation.getReportRHPActiveRoute()));
return;
}

const childReportID = action?.childReportID ?? '-1';
const childReportID = action?.childReportID;
if (!childReportID) {
return;
}
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(childReportID));
};

let shouldShowPendingConversionMessage = false;
const isDeletedParentAction = ReportActionsUtils.isDeletedParentAction(action);
const isReversedTransaction = ReportActionsUtils.isReversedTransaction(action);
const isParentActionDeleted = isDeletedParentAction(action);
const isTransactionReveresed = isReversedTransaction(action);
if (
!isEmptyObject(iouReport) &&
!isEmptyObject(reportActions) &&
Expand All @@ -108,25 +99,25 @@ function MoneyRequestAction({
action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD &&
isOffline
) {
shouldShowPendingConversionMessage = IOUUtils.isIOUReportPendingCurrencyConversion(iouReport);
shouldShowPendingConversionMessage = isIOUReportPendingCurrencyConversion(iouReport);
}

if (isDeletedParentAction || isReversedTransaction) {
if (isParentActionDeleted || isTransactionReveresed) {
let message: TranslationPaths;
if (isReversedTransaction) {
if (isTransactionReveresed) {
message = 'parentReportAction.reversedTransaction';
} else {
message = 'parentReportAction.deletedExpense';
}
return <RenderHTML html={`<comment>${translate(message)}</comment>`} />;
return <RenderHTML html={`<deleted-action ${CONST.REVERSED_TRANSACTION_ATTRIBUTE}="${isTransactionReveresed}">${translate(message)}</deleted-action>`} />;
}
return (
<MoneyRequestPreview
iouReportID={requestReportID}
chatReportID={chatReportID}
reportID={reportID}
isBillSplit={isSplitBillAction}
isTrackExpense={isTrackExpenseAction}
isBillSplit={isActionSplitBill}
isTrackExpense={isActionTrackExpense}
action={action}
contextMenuAnchor={contextMenuAnchor}
checkIfContextMenuActive={checkIfContextMenuActive}
Expand All @@ -142,15 +133,4 @@ function MoneyRequestAction({

MoneyRequestAction.displayName = 'MoneyRequestAction';

export default withOnyx<MoneyRequestActionProps, MoneyRequestActionOnyxProps>({
chatReport: {
key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`,
},
iouReport: {
key: ({requestReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${requestReportID}`,
},
reportActions: {
key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`,
canEvict: false,
},
})(MoneyRequestAction);
export default MoneyRequestAction;
30 changes: 15 additions & 15 deletions src/components/ReportActionItem/TaskPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import {checkIfActionIsAllowed} from '@libs/actions/Session';
import {canActionTask, completeTask, getTaskAssigneeAccountID, reopenTask} from '@libs/actions/Task';
import ControlSelection from '@libs/ControlSelection';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import {canUseTouchScreen} from '@libs/DeviceCapabilities';
import getButtonState from '@libs/getButtonState';
import Navigation from '@libs/Navigation/Navigation';
import * as ReportUtils from '@libs/ReportUtils';
import * as TaskUtils from '@libs/TaskUtils';
import {isCanceledTaskReport, isOpenTaskReport, isReportManager} from '@libs/ReportUtils';
import {getTaskTitleFromReport} from '@libs/TaskUtils';
import type {ContextMenuAnchor} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
import * as Session from '@userActions/Session';
import * as Task from '@userActions/Task';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
Expand Down Expand Up @@ -74,27 +74,27 @@ function TaskPreview({taskReportID, action, contextMenuAnchor, chatReportID, che
const isTaskCompleted = !isEmptyObject(taskReport)
? taskReport?.stateNum === CONST.REPORT.STATE_NUM.APPROVED && taskReport.statusNum === CONST.REPORT.STATUS_NUM.APPROVED
: action?.childStateNum === CONST.REPORT.STATE_NUM.APPROVED && action?.childStatusNum === CONST.REPORT.STATUS_NUM.APPROVED;
const taskTitle = Str.htmlEncode(TaskUtils.getTaskTitleFromReport(taskReport, action?.childReportName ?? ''));
const taskAssigneeAccountID = Task.getTaskAssigneeAccountID(taskReport) ?? action?.childManagerAccountID ?? CONST.DEFAULT_NUMBER_ID;
const taskTitle = Str.htmlEncode(getTaskTitleFromReport(taskReport, action?.childReportName ?? ''));
const taskAssigneeAccountID = getTaskAssigneeAccountID(taskReport) ?? action?.childManagerAccountID ?? CONST.DEFAULT_NUMBER_ID;
const taskOwnerAccountID = taskReport?.ownerAccountID ?? action?.actorAccountID ?? CONST.DEFAULT_NUMBER_ID;
const hasAssignee = taskAssigneeAccountID > 0;
const personalDetails = usePersonalDetails();
const avatar = personalDetails?.[taskAssigneeAccountID]?.avatar ?? Expensicons.FallbackAvatar;
const avatarSize = CONST.AVATAR_SIZE.SMALL;
const isDeletedParentAction = ReportUtils.isCanceledTaskReport(taskReport, action);
const isDeletedParentAction = isCanceledTaskReport(taskReport, action);
const iconWrapperStyle = StyleUtils.getTaskPreviewIconWrapper(hasAssignee ? avatarSize : undefined);
const titleStyle = StyleUtils.getTaskPreviewTitleStyle(iconWrapperStyle.height, isTaskCompleted);

const shouldShowGreenDotIndicator = ReportUtils.isOpenTaskReport(taskReport, action) && ReportUtils.isReportManager(taskReport);
const shouldShowGreenDotIndicator = isOpenTaskReport(taskReport, action) && isReportManager(taskReport);
if (isDeletedParentAction) {
return <RenderHTML html={`<comment>${translate('parentReportAction.deletedTask')}</comment>`} />;
return <RenderHTML html={`<deleted-action>${translate('parentReportAction.deletedTask')}</deleted-action>`} />;
}

return (
<View style={[styles.chatItemMessage, !hasAssignee && styles.mv1]}>
<PressableWithoutFeedback
onPress={() => Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(taskReportID))}
onPressIn={() => DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()}
onPressIn={() => canUseTouchScreen() && ControlSelection.block()}
onPressOut={() => ControlSelection.unblock()}
onLongPress={(event) => showContextMenuForReport(event, contextMenuAnchor, chatReportID, action, checkIfContextMenuActive)}
shouldUseHapticsOnLongPress
Expand All @@ -107,12 +107,12 @@ function TaskPreview({taskReportID, action, contextMenuAnchor, chatReportID, che
<Checkbox
style={[styles.mr2]}
isChecked={isTaskCompleted}
disabled={!Task.canActionTask(taskReport, currentUserPersonalDetails.accountID, taskOwnerAccountID, taskAssigneeAccountID)}
onPress={Session.checkIfActionIsAllowed(() => {
disabled={!canActionTask(taskReport, currentUserPersonalDetails.accountID, taskOwnerAccountID, taskAssigneeAccountID)}
onPress={checkIfActionIsAllowed(() => {
if (isTaskCompleted) {
Task.reopenTask(taskReport, taskReportID);
reopenTask(taskReport, taskReportID);
} else {
Task.completeTask(taskReport, taskReportID);
completeTask(taskReport, taskReportID);
}
})}
accessibilityLabel={translate('task.task')}
Expand Down
12 changes: 6 additions & 6 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4943,12 +4943,12 @@ const translations = {
viewAttachment: 'View attachment',
},
parentReportAction: {
deletedReport: '[Deleted report]',
deletedMessage: '[Deleted message]',
deletedExpense: '[Deleted expense]',
reversedTransaction: '[Reversed transaction]',
deletedTask: '[Deleted task]',
hiddenMessage: '[Hidden message]',
deletedReport: 'Deleted report',
deletedMessage: 'Deleted message',
deletedExpense: 'Deleted expense',
reversedTransaction: 'Reversed transaction',
deletedTask: 'Deleted task',
hiddenMessage: 'Hidden message',
},
threads: {
thread: 'Thread',
Expand Down
12 changes: 6 additions & 6 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5455,12 +5455,12 @@ const translations = {
viewAttachment: 'Ver archivo adjunto',
},
parentReportAction: {
deletedReport: '[Informe eliminado]',
deletedMessage: '[Mensaje eliminado]',
deletedExpense: '[Gasto eliminado]',
reversedTransaction: '[Transacción anulada]',
deletedTask: '[Tarea eliminada]',
hiddenMessage: '[Mensaje oculto]',
deletedReport: 'Informe eliminado',
deletedMessage: 'Mensaje eliminado',
deletedExpense: 'Gasto eliminado',
reversedTransaction: 'Transacción anulada',
deletedTask: 'Tarea eliminada',
hiddenMessage: 'Mensaje oculto',
},
threads: {
thread: 'Hilo',
Expand Down
Loading
Loading