Skip to content

Commit

Permalink
Merge pull request #33852 from unicorndev-727/migrate/ReportActionIte…
Browse files Browse the repository at this point in the history
…mTaskPreview

 [TS migration] Migrate Taskpreview.js component to TypeScript
  • Loading branch information
tgolen authored Jan 11, 2024
2 parents 31aeaae + 825b702 commit 6aa4540
Showing 1 changed file with 74 additions and 84 deletions.
Original file line number Diff line number Diff line change
@@ -1,167 +1,157 @@
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import Str from 'expensify-common/lib/str';
import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import type {OnyxEntry} from 'react-native-onyx';
import Checkbox from '@components/Checkbox';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import {usePersonalDetails} from '@components/OnyxProvider';
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
import refPropTypes from '@components/refPropTypes';
import RenderHTML from '@components/RenderHTML';
import {showContextMenuForReport} from '@components/ShowContextMenuContext';
import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import compose from '@libs/compose';
import ControlSelection from '@libs/ControlSelection';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import getButtonState from '@libs/getButtonState';
import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
import Navigation from '@libs/Navigation/Navigation';
import * as ReportUtils from '@libs/ReportUtils';
import * as TaskUtils from '@libs/TaskUtils';
import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
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';
import type {Policy, Report, ReportAction} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';

const propTypes = {
/** The ID of the associated taskReport */
taskReportID: PropTypes.string.isRequired,

/** Whether the task preview is hovered so we can modify its style */
isHovered: PropTypes.bool,

/** The linked reportAction */
action: PropTypes.shape(reportActionPropTypes).isRequired,
type PolicyRole = {
/** The role of current user */
role: string;
};

type TaskPreviewOnyxProps = {
/* Onyx Props */

taskReport: PropTypes.shape({
/** Title of the task */
reportName: PropTypes.string,

/** AccountID of the manager in this iou report */
managerID: PropTypes.number,

/** AccountID of the creator of this iou report */
ownerAccountID: PropTypes.number,
}),
/* current report of TaskPreview */
taskReport: OnyxEntry<Report>;

/** The policy of root parent report */
rootParentReportpolicy: PropTypes.shape({
/** The role of current user */
role: PropTypes.string,
}),

/** The chat report associated with taskReport */
chatReportID: PropTypes.string.isRequired,

/** Popover context menu anchor, used for showing context menu */
contextMenuAnchor: refPropTypes,

/** Callback for updating context menu active state, used for showing context menu */
checkIfContextMenuActive: PropTypes.func,

/* Onyx Props */
...withLocalizePropTypes,

...withCurrentUserPersonalDetailsPropTypes,
};

const defaultProps = {
...withCurrentUserPersonalDetailsDefaultProps,
taskReport: {},
rootParentReportpolicy: {},
isHovered: false,
rootParentReportpolicy: OnyxEntry<PolicyRole>;
};

function TaskPreview(props) {
type TaskPreviewProps = WithCurrentUserPersonalDetailsProps &
TaskPreviewOnyxProps & {
/** The ID of the associated policy */
// eslint-disable-next-line react/no-unused-prop-types
policyID: string;
/** The ID of the associated taskReport */
taskReportID: string;

/** Whether the task preview is hovered so we can modify its style */
isHovered: boolean;

/** The linked reportAction */
action: OnyxEntry<ReportAction>;

/** The chat report associated with taskReport */
chatReportID: string;

/** Popover context menu anchor, used for showing context menu */
contextMenuAnchor: Element;

/** Callback for updating context menu active state, used for showing context menu */
checkIfContextMenuActive: () => void;
};

function TaskPreview({
taskReport,
taskReportID,
action,
contextMenuAnchor,
chatReportID,
checkIfContextMenuActive,
currentUserPersonalDetails,
rootParentReportpolicy,
isHovered = false,
}: TaskPreviewProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT;
const {translate} = useLocalize();
// The reportAction might not contain details regarding the taskReport
// Only the direct parent reportAction will contain details about the taskReport
// Other linked reportActions will only contain the taskReportID and we will grab the details from there
const isTaskCompleted = !_.isEmpty(props.taskReport)
? props.taskReport.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && props.taskReport.statusNum === CONST.REPORT.STATUS.APPROVED
: props.action.childStateNum === CONST.REPORT.STATE_NUM.SUBMITTED && props.action.childStatusNum === CONST.REPORT.STATUS.APPROVED;
const taskTitle = _.escape(TaskUtils.getTaskTitle(props.taskReportID, props.action.childReportName));
const taskAssigneeAccountID = Task.getTaskAssigneeAccountID(props.taskReport) || props.action.childManagerAccountID;
const assigneeLogin = lodashGet(personalDetails, [taskAssigneeAccountID, 'login'], '');
const assigneeDisplayName = lodashGet(personalDetails, [taskAssigneeAccountID, 'displayName'], '');
const isTaskCompleted = !isEmptyObject(taskReport)
? taskReport?.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && taskReport.statusNum === CONST.REPORT.STATUS.APPROVED
: action?.childStateNum === CONST.REPORT.STATE_NUM.SUBMITTED && action?.childStatusNum === CONST.REPORT.STATUS.APPROVED;
const taskTitle = Str.htmlEncode(TaskUtils.getTaskTitle(taskReportID, action?.childReportName ?? ''));
const taskAssigneeAccountID = Task.getTaskAssigneeAccountID(taskReport ?? {}) ?? action?.childManagerAccountID ?? '';
const assigneeLogin = personalDetails[taskAssigneeAccountID]?.login ?? '';
const assigneeDisplayName = personalDetails[taskAssigneeAccountID]?.displayName ?? '';
const taskAssignee = assigneeDisplayName || LocalePhoneNumber.formatPhoneNumber(assigneeLogin);
const htmlForTaskPreview =
taskAssignee && taskAssigneeAccountID !== 0
? `<comment><mention-user accountid="${taskAssigneeAccountID}">@${taskAssignee}</mention-user> ${taskTitle}</comment>`
: `<comment>${taskTitle}</comment>`;
const isDeletedParentAction = ReportUtils.isCanceledTaskReport(props.taskReport, props.action);
const isDeletedParentAction = ReportUtils.isCanceledTaskReport(taskReport, action);

if (isDeletedParentAction) {
return <RenderHTML html={`<comment>${props.translate('parentReportAction.deletedTask')}</comment>`} />;
return <RenderHTML html={`<comment>${translate('parentReportAction.deletedTask')}</comment>`} />;
}

return (
<View style={[styles.chatItemMessage]}>
<PressableWithoutFeedback
onPress={() => Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(props.taskReportID))}
onPress={() => Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(taskReportID))}
onPressIn={() => DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()}
onPressOut={() => ControlSelection.unblock()}
onLongPress={(event) => showContextMenuForReport(event, props.contextMenuAnchor, props.chatReportID, props.action, props.checkIfContextMenuActive)}
onLongPress={(event) => showContextMenuForReport(event, contextMenuAnchor, chatReportID, action ?? {}, checkIfContextMenuActive)}
style={[styles.flexRow, styles.justifyContentBetween]}
role={CONST.ROLE.BUTTON}
accessibilityLabel={props.translate('task.task')}
accessibilityLabel={translate('task.task')}
>
<View style={[styles.flex1, styles.flexRow, styles.alignItemsStart]}>
<Checkbox
style={[styles.mr2]}
containerStyle={[styles.taskCheckbox]}
isChecked={isTaskCompleted}
disabled={
_.isEmpty(props.taskReport) ||
!Task.canModifyTask(props.taskReport, props.currentUserPersonalDetails.accountID, lodashGet(props.rootParentReportpolicy, 'role', ''))
}
disabled={!Task.canModifyTask(taskReport ?? {}, currentUserPersonalDetails.accountID, rootParentReportpolicy?.role ?? '')}
onPress={Session.checkIfActionIsAllowed(() => {
if (isTaskCompleted) {
Task.reopenTask(props.taskReport);
Task.reopenTask(taskReport ?? {});
} else {
Task.completeTask(props.taskReport);
Task.completeTask(taskReport ?? {});
}
})}
accessibilityLabel={props.translate('task.task')}
accessibilityLabel={translate('task.task')}
/>
<RenderHTML html={htmlForTaskPreview} />
</View>
<Icon
src={Expensicons.ArrowRight}
fill={StyleUtils.getIconFillColor(getButtonState(props.isHovered))}
fill={StyleUtils.getIconFillColor(getButtonState(isHovered))}
/>
</PressableWithoutFeedback>
</View>
);
}

TaskPreview.propTypes = propTypes;
TaskPreview.defaultProps = defaultProps;
TaskPreview.displayName = 'TaskPreview';

export default compose(
withLocalize,
withCurrentUserPersonalDetails,
withOnyx({
export default withCurrentUserPersonalDetails(
withOnyx<TaskPreviewProps, TaskPreviewOnyxProps>({
taskReport: {
key: ({taskReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${taskReportID}`,
initialValue: {},
},
rootParentReportpolicy: {
key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID || '0'}`,
selector: (policy) => _.pick(policy, ['role']),
key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID ?? '0'}`,
selector: (policy: Policy | null) => ({role: policy?.role ?? ''}),
},
}),
)(TaskPreview);
})(TaskPreview),
);

0 comments on commit 6aa4540

Please sign in to comment.