-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
[TS migration] Migrate Taskpreview.js component to TypeScript #33852
[TS migration] Migrate Taskpreview.js component to TypeScript #33852
Conversation
@hoangzinh Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
…rate/ReportActionItemTaskPreview
According to this issue #31971 It looks like @thesahindia is C+ for this PR. @tgolen can you help to assign him and unassign me? Thanks |
Sure, I think that should do it. |
/** The role of current user */ | ||
role: PropTypes.string, | ||
}), | ||
rootParentReportpolicy: OnyxEntry<{role: string}>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you extract this type {role: string}
to seperate type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just added a new type. Please review again.
type TaskPreviewProps = WithCurrentUserPersonalDetailsProps & | ||
TaskPreviewOnyxProps & { | ||
/** The ID of the associated policy */ | ||
// eslint-disable-next-line |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this is needed ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lint error that shows policyId is defined but not used anywhere
so I added it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few things:
- If the prop is not used anywhere, remove it
- If the eslint-disable-next-line needs to stay, disable the specific rule instead of all rules and also add a code comment for why the prop needs to be there even though it isn't used anywhere
I believe the reason policyID
is here is because it is used in withOnyx
to fetch rootParentReportpolicy
. Since ESLint won't detect it's usage in withOnyx
, that's why it throws the error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do one of the options I posted in my previous comment, I don't see that either of them were followed.
|
||
function TaskPreview(props) { | ||
function TaskPreview(props: TaskPreviewProps) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please destructure props
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please review again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm!
…rate/ReportActionItemTaskPreview
type TaskPreviewProps = WithCurrentUserPersonalDetailsProps & | ||
TaskPreviewOnyxProps & { | ||
/** The ID of the associated policy */ | ||
// eslint-disable-next-line |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few things:
- If the prop is not used anywhere, remove it
- If the eslint-disable-next-line needs to stay, disable the specific rule instead of all rules and also add a code comment for why the prop needs to be there even though it isn't used anywhere
I believe the reason policyID
is here is because it is used in withOnyx
to fetch rootParentReportpolicy
. Since ESLint won't detect it's usage in withOnyx
, that's why it throws the error.
const taskTitle = Str.htmlEncode(TaskUtils.getTaskTitle(taskReportID, action?.childReportName ?? '')); | ||
const taskAssigneeAccountID = Task.getTaskAssigneeAccountID(taskReport ?? {}) ?? action?.childManagerAccountID ?? ''; | ||
const assigneeLogin = taskAssigneeAccountID ? personalDetails[taskAssigneeAccountID]?.login ?? '' : ''; | ||
const assigneeDisplayName = taskAssigneeAccountID ? personalDetails[taskAssigneeAccountID]?.displayName ?? '' : ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand that we've said in these migrations that lodash and underscore should be removed, but I can't help but think that the end result is so much less readable and understandable than it was before. These four variables are perfect examples where it appears very confusing and the lodash implementation was much better.
I'd like to open up a discussion about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const taskTitle = Str.htmlEncode(TaskUtils.getTaskTitle(taskReportID, action?.childReportName ?? '')); | |
const taskAssigneeAccountID = Task.getTaskAssigneeAccountID(taskReport ?? {}) ?? action?.childManagerAccountID ?? ''; | |
const assigneeLogin = taskAssigneeAccountID ? personalDetails[taskAssigneeAccountID]?.login ?? '' : ''; | |
const assigneeDisplayName = taskAssigneeAccountID ? personalDetails[taskAssigneeAccountID]?.displayName ?? '' : ''; | |
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 ?? ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks better, thanks for the suggestion!
…rate/ReportActionItemTaskPreview
Kind request, change PR title so it reflects issue title: [TS migration] Migrate 'X.js' component to TypeScript |
/> | ||
</PressableWithoutFeedback> | ||
</View> | ||
); | ||
} | ||
|
||
TaskPreview.propTypes = propTypes; | ||
TaskPreview.defaultProps = defaultProps; | ||
TaskPreview.displayName = 'TaskPreview'; | ||
|
||
export default compose( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please refer to TS guidelines, unfortunately we have to remove compose
here, as it isn't working as expected. link
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just updated.
> | ||
<View style={[styles.flex1, styles.flexRow, styles.alignItemsStart]}> | ||
<Checkbox | ||
style={[styles.mr2]} | ||
containerStyle={[styles.taskCheckbox]} | ||
isChecked={isTaskCompleted} | ||
disabled={!Task.canModifyTask(props.taskReport, props.currentUserPersonalDetails.accountID, lodashGet(props.rootParentReportpolicy, 'role', ''))} | ||
disabled={!Task.canModifyTask(taskReport ?? {}, currentUserPersonalDetails.accountID, rootParentReportpolicy ? rootParentReportpolicy.role : '')} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
disabled={!Task.canModifyTask(taskReport ?? {}, currentUserPersonalDetails.accountID, rootParentReportpolicy ? rootParentReportpolicy.role : '')} | |
disabled={!Task.canModifyTask(taskReport ?? {}, currentUserPersonalDetails.accountID, rootParentReportpolicy?.role ?? '')} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just applied.
/** The linked reportAction */ | ||
action: PropTypes.shape(reportActionPropTypes).isRequired, | ||
type PolicyRole = { | ||
role: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like some comments are getting dropped. I find the comments very helpful, is it a standard process to remove them? I'd like to keep them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tgolen We preserve all comments, and sometimes we even add new ones for better clarity :)
/** AccountID of the creator of this iou report */ | ||
ownerAccountID: PropTypes.number, | ||
}), | ||
taskReport: OnyxEntry<Report>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment for this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
type TaskPreviewProps = WithCurrentUserPersonalDetailsProps & | ||
TaskPreviewOnyxProps & { | ||
/** The ID of the associated policy */ | ||
// eslint-disable-next-line |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do one of the options I posted in my previous comment, I don't see that either of them were followed.
function TaskPreview({ | ||
taskReport, | ||
taskReportID, | ||
action, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@blazejkustra Is there a general rule about when to use destructuring with defaults and when not to? It feels to me like it would make the code easier to follow if we used defaults in the destructuring. The only case I think it won't work is when you need to know if the value was undefined
or null
, but a simple fasly check like action ?? {}
should be fine, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so may I update the code to use default value in destructuring if possible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rule of thumb is to avoid unnecessary default values such as undefined, null, {}, [], '' and () => {} - when we started migration we left some of these, but we can clean them as a follow up once whole TS migration is finished.
Two examples for useful default values:
function Avatar({
size = CONST.AVATAR_SIZE.DEFAULT,
fallbackIcon = Expensicons.FallbackAvatar,
type = CONST.ICON_TYPE_AVATAR,
}: AvatarProps) {}
function GenericPressable(
{
shouldUseHapticsOnLongPress = false,
shouldUseHapticsOnPress = false,
shouldUseAutoHitSlop = false,
enableInScreenReaderStates = CONST.SCREEN_READER_STATES.ALL,
accessible = true,
...rest
}: PressableProps) {}
contextMenuAnchor, | ||
chatReportID, | ||
checkIfContextMenuActive, | ||
isHovered, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing default value here:
isHovered, | |
isHovered = false, |
function TaskPreview({ | ||
taskReport, | ||
taskReportID, | ||
action, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rule of thumb is to avoid unnecessary default values such as undefined, null, {}, [], '' and () => {} - when we started migration we left some of these, but we can clean them as a follow up once whole TS migration is finished.
Two examples for useful default values:
function Avatar({
size = CONST.AVATAR_SIZE.DEFAULT,
fallbackIcon = Expensicons.FallbackAvatar,
type = CONST.ICON_TYPE_AVATAR,
}: AvatarProps) {}
function GenericPressable(
{
shouldUseHapticsOnLongPress = false,
shouldUseHapticsOnPress = false,
shouldUseAutoHitSlop = false,
enableInScreenReaderStates = CONST.SCREEN_READER_STATES.ALL,
accessible = true,
...rest
}: PressableProps) {}
const taskAssigneeAccountID = Task.getTaskAssigneeAccountID(props.taskReport) || props.action.childManagerAccountID; | ||
const assigneeLogin = lodashGet(personalDetails, [taskAssigneeAccountID, 'login'], ''); | ||
const assigneeDisplayName = lodashGet(personalDetails, [taskAssigneeAccountID, 'displayName'], ''); | ||
const isTaskCompleted = isNotEmptyObject(taskReport) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We want to deprecate isNotEmptyObject
, let's use !isEmptyObject
instead
const isTaskCompleted = isNotEmptyObject(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 ?? '')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make sure these implementations give the same result:
const taskTitle = _.escape(TaskUtils.getTaskTitle(props.taskReportID, props.action.childReportName));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this has conflicts. Do those just need to be cleaned up and then this can be merged? I don't think I was officially included on the original reviewer list. |
CLA Assistant is failing @unicorndev-727 |
I have read the CLA Document and I hereby sign the CLA |
…rate/ReportActionItemTaskPreview
…rate/ReportActionItemTaskPreview
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
🚀 Deployed to staging by https://github.com/tgolen in version: 1.4.25-0 🚀
|
🚀 Deployed to production by https://github.com/mountiny in version: 1.4.25-10 🚀
|
Details
Fixed Issues
$ #31791
PROPOSAL:
Tests
Offline tests
QA Steps
PR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)myBool && <MyComponent />
.src/languages/*
files and using the translation methodWaiting for Copy
label for a copy review on the original GH to get the correct copy.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)Design
label so the design team can review the changes.ScrollView
component to make it scrollable when more elements are added to the page.main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
android-web.mp4
iOS: Native
Simulator.Screen.Recording.-.iPhone.15.-.2024-01-02.at.12.40.20.mp4
iOS: mWeb Safari
Simulator.Screen.Recording.-.iPhone.15.-.2024-01-02.at.12.43.35.mp4
MacOS: Chrome / Safari
desktop-web.webm
MacOS: Desktop
screen-capture.6.webm