-
Notifications
You must be signed in to change notification settings - Fork 3k
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 'Profile' page to TypeScript #34974
[TS migration] Migrate 'Profile' page to TypeScript #34974
Conversation
const notificationPreference = shouldShowNotificationPreference | ||
? translate(`notificationPreferencesPage.notificationPreferences.${report.notificationPreference}` as TranslationPaths) | ||
: ''; |
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.
Assertion can be escaped if we narrow down the type of notificationPreference
reusing condition from shouldShowNotificationPreference
const, like
const notificationPreference = shouldShowNotificationPreference | |
? translate(`notificationPreferencesPage.notificationPreferences.${report.notificationPreference}` as TranslationPaths) | |
: ''; | |
const notificationPreference = shouldShowNotificationPreference && report.notificationPreference && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN | |
? translate(`notificationPreferencesPage.notificationPreferences.${report.notificationPreference}`) | |
: ''; |
But I'm not sure if it's a better approach
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 think the current is better cause we have a better visualisation of the logic
import * as PersonalDetailsActions from '@userActions/PersonalDetails'; | ||
import * as ReportActions from '@userActions/Report'; | ||
import * as SessionActions from '@userActions/Session'; |
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.
Let's turn this imports back as they was, and update OnyxTypes import to be
import type * as OnyxTypes from '@src/types/onyx';
This way we can use them like OnyxTypes.PersonalDetails
, OnyxTypes.Report
, etc
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 think it is better to import only the needed types
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.
@pasyukevich I agree with @VickyStash comment in this case, by doing your way you had to change the other imports to avoid conflicts, we don't need that if we use OnyxTypes.*
pattern
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.
For me using ReportActions
is way better, since we will see that we are dealing with the actions (not with class/ type)
On hold till this PR is merged |
8e680a9
to
ed0e882
Compare
ed0e882
to
769d6d4
Compare
import * as PersonalDetailsActions from '@userActions/PersonalDetails'; | ||
import * as ReportActions from '@userActions/Report'; | ||
import * as SessionActions from '@userActions/Session'; |
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.
@pasyukevich I agree with @VickyStash comment in this case, by doing your way you had to change the other imports to avoid conflicts, we don't need that if we use OnyxTypes.*
pattern
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 with one nitpick
@DylanDylann 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] |
import * as Report from '@userActions/Report'; | ||
import * as Session from '@userActions/Session'; | ||
import * as PersonalDetailsActions from '@userActions/PersonalDetails'; | ||
import * as ReportActions from '@userActions/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.
A bit confused. Because we also have '@userActions/ReportActions' import in some other places
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 think that using a Report is even more confusing since it does not describe what it is (especially when we are using the ts and have types)
src/pages/ProfilePage.tsx
Outdated
const login = lodashGet(details, 'login', ''); | ||
const timezone = lodashGet(details, 'timezone', {}); | ||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing | ||
const avatar = details?.avatar || UserUtils.getDefaultAvatar(); |
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.
Should we use ?? instead of ||
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 need to use ||
, since we can have an empty string, and in this case, we need to show the default avatar
const avatar = details?.avatar || UserUtils.getDefaultAvatar(); | ||
const fallbackIcon = details?.fallbackIcon ?? ''; | ||
const login = details?.login ?? ''; | ||
const timezone = details?.timezone; |
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.
Should we add a fallback value here?
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 don't think so since we have some statements in code that rely on timezone
undefined / empty value
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.
@pasyukevich We pass the timezone to AutoUpdateTime Component as an Object. If timezone is undefined, we will get the error "can't read the attribute of undefined"
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.
@DylanDylann It is not a problem, since we will render AutoUpdateTime
only if shouldShowLocalTime
is true that s already checks that the timezone is not empty
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.
@pasyukevich Also please help to resolve conflict. This PR has been delayed for a long time. Let's move forward
const reportID = ReportUtils.getChatByParticipants([accountID])?.reportID ?? ''; | ||
|
||
if ((Boolean(session) && Number(session?.accountID) === accountID) || SessionActions.isAnonymousUser() || !reportID) { | ||
return `${ONYXKEYS.COLLECTION.REPORT}0`; |
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.
return
${ONYXKEYS.COLLECTION.REPORT}0;
will return undefined. Why do we need to update from return null;
to
return `${ONYXKEYS.COLLECTION.REPORT}0`;` will return undefined
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 key should be always a key according to our types
The key was updated from null
to string
, the actual result didn't changed
Before - OnyxStorage[null]
- undefined
Now - OnyxStorage[
${ONYXKEYS.COLLECTION.REPORT}0]
- undefined
src/pages/ProfilePage.tsx
Outdated
|
||
const shouldShowNotificationPreference = !_.isEmpty(props.report) && props.report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; | ||
const notificationPreference = shouldShowNotificationPreference ? props.translate(`notificationPreferencesPage.notificationPreferences.${props.report.notificationPreference}`) : ''; | ||
const shouldShowNotificationPreference = !isEmptyObject(report) && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; |
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.
report
could be null/undefined. Even though we have checked !isEmptyObject(report)
I think we still should update to report?.notificationPreference
for safer
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 will read report.notificationPreference
only in the case when the object is not empty
!isEmptyObject(report)
will guarantee that we are dealing with an object
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.
Yepp this is NAB
@pasyukevich Bump on this one |
@pasyukevich One more comment here and also resolve conflict |
Reviewer Checklist
Screenshots/VideosAndroid: NativeScreen.Recording.2024-02-29.at.22.14.08.movAndroid: mWeb ChromeScreen.Recording.2024-02-29.at.22.08.46.moviOS: NativeScreen.Recording.2024-02-29.at.21.22.56.moviOS: mWeb SafariScreen.Recording.2024-02-29.at.21.27.12.movMacOS: Chrome / SafariScreen.Recording.2024-02-29.at.21.25.28.movMacOS: DesktopScreen.Recording.2024-02-29.at.21.27.56.mov |
@pasyukevich Please merge main |
PR is merged and it bumped Onyx version, so TS should be fixed once we merge main here. |
Looks like it's still failing...@fabioh8010 do you think we might have not fixed it fully or we missed a case? error in this PR is:
|
return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`; | ||
}, | ||
export default withOnyx<ProfilePageProps, ProfilePageOnyxProps>({ | ||
reports: { |
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.
@pasyukevich We improved the selector
types but we still have a small issue in this case, that we must specify a selector that returns a non-nullable object (otherwise the types starts failing again), to fix chatReportSelector
, change it to this:
const chatReportSelector = (report: OnyxEntry<Report>): Report =>
(report && {
reportID: report.reportID,
participantAccountIDs: report.participantAccountIDs,
parentReportID: report.parentReportID,
parentReportActionID: report.parentReportActionID,
type: report.type,
chatType: report.chatType,
isPolicyExpenseChat: report.isPolicyExpenseChat,
}) as Report;
cc @youssef-lr
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.
Makes sense, many thanks @fabioh8010!
b8020cf
to
e4d4408
Compare
e4d4408
to
b7f8dae
Compare
@DylanDylann PR updated |
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
We did not find an internal engineer to review this PR, trying to assign a random engineer to #25199 as well as to this PR... Please reach out for help on Slack if no one gets assigned! |
wrapperStyle={styles.breakAll} | ||
shouldShowRightIcon | ||
brickRoadIndicator={Report.hasErrorInPrivateNotes(props.report) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} | ||
brickRoadIndicator={ReportActions.hasErrorInPrivateNotes(report) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} |
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.
Should we fall back to empty string?
Prop definition:
/** The type of brick road indicator to show. */
brickRoadIndicator: PropTypes.oneOf([CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR, CONST.BRICK_ROAD_INDICATOR_STATUS.INFO, ''])
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.
Nope, with TS updates we can have one of the CONST.BRICK_ROAD_INDICATOR_STATUS
values or undefined
@pasyukevich There are some minor comments. Let's address it |
@pasyukevich there is conflict to resolve |
@MonilBhavsar Updated |
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.
Thanks!
✋ 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 production by https://github.com/luacmartins in version: 1.4.50-5 🚀
|
|
||
const shouldShowNotificationPreference = !_.isEmpty(props.report) && !isCurrentUser && props.report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; | ||
const notificationPreference = shouldShowNotificationPreference ? props.translate(`notificationPreferencesPage.notificationPreferences.${props.report.notificationPreference}`) : ''; | ||
const shouldShowNotificationPreference = !isEmptyObject(report) && !isCurrentUser && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; |
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.
this might have caused #39677
Details
Fixed Issues
$ #25199
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-native-converted.webm
Android: mWeb Chrome
android-web-converted.webm
iOS: Native
ios-native-converted.mp4
iOS: mWeb Safari
ios-web-converted.mp4
MacOS: Chrome / Safari
desktop-web-converted.mov
MacOS: Desktop
desktop-native-converted.mov