From c0e43ef16af48d187589bfddd1e64110109b4e18 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Thu, 18 Jan 2024 08:08:42 +0700 Subject: [PATCH 01/36] Add duration to background image --- .../BackgroundImage/index.android.js | 16 +++++++- .../BackgroundImage/index.ios.js | 4 +- .../SignInPageLayout/BackgroundImage/index.js | 37 +++++++++++++------ .../BackgroundImage/propTypes.js | 3 ++ 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js index 717f9a3e718c..62f94a9dcfcf 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js @@ -4,6 +4,18 @@ import AndroidBackgroundImage from '@assets/images/home-background--android.svg' import useThemeStyles from '@hooks/useThemeStyles'; import defaultPropTypes from './propTypes'; +const defaultProps = { + isSmallScreen: false, + transitionDuration: 1000, +}; + +const propTypes = { + /** Is the window width narrow, like on a mobile device */ + isSmallScreen: PropTypes.bool, + + ...defaultPropTypes, +}; + function BackgroundImage(props) { const styles = useThemeStyles(); return ( @@ -11,11 +23,13 @@ function BackgroundImage(props) { source={AndroidBackgroundImage} pointerEvents={props.pointerEvents} style={[styles.signInBackground, {width: props.width}]} + transition={props.transitionDuration} /> ); } BackgroundImage.displayName = 'BackgroundImage'; -BackgroundImage.propTypes = defaultPropTypes; +BackgroundImage.propTypes = propTypes; +BackgroundImage.defaultProps = defaultProps; export default BackgroundImage; diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js index da6a6b9ee4fb..edfa80358f60 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js @@ -9,6 +9,7 @@ import defaultPropTypes from './propTypes'; const defaultProps = { isSmallScreen: false, + transitionDuration: 1000, }; const propTypes = { @@ -21,11 +22,12 @@ function BackgroundImage(props) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const src = useMemo(() => (props.isSmallScreen ? MobileBackgroundImage : DesktopBackgroundImage), [props.isSmallScreen]); - +console.log('[wildebug] props.transitionDuration', props.transitionDuration) return ( ); } diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.js index ac93ceeb4e2c..6e5113344c3d 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.js @@ -4,9 +4,11 @@ import DesktopBackgroundImage from '@assets/images/home-background--desktop.svg' import MobileBackgroundImage from '@assets/images/home-background--mobile.svg'; import useThemeStyles from '@hooks/useThemeStyles'; import defaultPropTypes from './propTypes'; +import * as Animatable from 'react-native-animatable'; const defaultProps = { isSmallScreen: false, + transitionDuration: 1000, }; const propTypes = { @@ -17,17 +19,30 @@ const propTypes = { }; function BackgroundImage(props) { const styles = useThemeStyles(); - return props.isSmallScreen ? ( - - ) : ( - - ); + const fadeIn = { + from: { + opacity: 0, + }, + to: { + opacity: 1, + }, + }; + + return + {props.isSmallScreen ? ( + + ) : ( + + )}; } BackgroundImage.displayName = 'BackgroundImage'; diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js b/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js index 533d22ad12c5..2cf04d90e771 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js @@ -6,6 +6,9 @@ const propTypes = { /** The width of the image. */ width: PropTypes.number.isRequired, + + /** Tranistion duration in milisecond */ + transitionDuration: PropTypes.number }; export default propTypes; From 4c04f9b3f329a3b082ccb41ca7f634630576a93c Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 18 Jan 2024 12:21:34 +0100 Subject: [PATCH 02/36] [TS migration] Migrate 'SettingsSecurityCloseAccount' page --- ...oseAccountPage.js => CloseAccountPage.tsx} | 91 +++++++++---------- 1 file changed, 44 insertions(+), 47 deletions(-) rename src/pages/settings/Security/{CloseAccountPage.js => CloseAccountPage.tsx} (60%) diff --git a/src/pages/settings/Security/CloseAccountPage.js b/src/pages/settings/Security/CloseAccountPage.tsx similarity index 60% rename from src/pages/settings/Security/CloseAccountPage.js rename to src/pages/settings/Security/CloseAccountPage.tsx index 9aad345d7b3d..4922a536a8e4 100644 --- a/src/pages/settings/Security/CloseAccountPage.js +++ b/src/pages/settings/Security/CloseAccountPage.tsx @@ -1,8 +1,9 @@ +import type {StackScreenProps} from '@react-navigation/stack'; import Str from 'expensify-common/lib/str'; -import PropTypes from 'prop-types'; import React, {useEffect, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx/lib/types'; import ConfirmModal from '@components/ConfirmModal'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; @@ -10,37 +11,36 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; -import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; import * as ValidationUtils from '@libs/ValidationUtils'; +import type {SettingsNavigatorParamList} from '@navigation/types'; import * as CloseAccount from '@userActions/CloseAccount'; import * as User from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; +import type {Session} from '@src/types/onyx'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; -const propTypes = { +type CloseAccountPageOnyxProps = { /** Session of currently logged in user */ - session: PropTypes.shape({ - /** Email address */ - email: PropTypes.string.isRequired, - }), - - ...windowDimensionsPropTypes, - ...withLocalizePropTypes, + session: OnyxEntry; }; -const defaultProps = { - session: { - email: null, - }, +type CloseAccountPageProps = CloseAccountPageOnyxProps & StackScreenProps; + +type CloseAccountFormValues = { + reasonForLeaving: string; + phoneOrEmail: string; }; -function CloseAccountPage(props) { +function CloseAccountPage({session}: CloseAccountPageProps) { const styles = useThemeStyles(); + const {translate, formatPhoneNumber} = useLocalize(); + const [isConfirmModalVisible, setConfirmModalVisibility] = useState(false); const [reasonForLeaving, setReasonForLeaving] = useState(''); @@ -59,21 +59,21 @@ function CloseAccountPage(props) { hideConfirmModal(); }; - const showConfirmModal = (values) => { + const showConfirmModal = (values: CloseAccountFormValues) => { setConfirmModalVisibility(true); setReasonForLeaving(values.reasonForLeaving); }; /** * Removes spaces and transform the input string to lowercase. - * @param {String} phoneOrEmail - The input string to be sanitized. - * @returns {String} The sanitized string + * @param phoneOrEmail - The input string to be sanitized. + * @returns The sanitized string */ - const sanitizePhoneOrEmail = (phoneOrEmail) => phoneOrEmail.replace(/\s+/g, '').toLowerCase(); + const sanitizePhoneOrEmail = (phoneOrEmail: string): string => phoneOrEmail.replace(/\s+/g, '').toLowerCase(); - const validate = (values) => { + const validate = (values: CloseAccountFormValues): Errors => { const requiredFields = ['phoneOrEmail']; - const userEmailOrPhone = props.formatPhoneNumber(props.session.email); + const userEmailOrPhone = formatPhoneNumber(session?.email ?? ''); const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields); if (values.phoneOrEmail && sanitizePhoneOrEmail(userEmailOrPhone) !== sanitizePhoneOrEmail(values.phoneOrEmail)) { @@ -82,7 +82,7 @@ function CloseAccountPage(props) { return errors; }; - const userEmailOrPhone = props.formatPhoneNumber(props.session.email); + const userEmailOrPhone = formatPhoneNumber(session?.email ?? ''); return ( Navigation.goBack(ROUTES.SETTINGS_SECURITY)} /> + {/* @ts-expect-error TODO: Remove this once Form (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript. */} - {props.translate('closeAccountPage.reasonForLeavingPrompt')} + {translate('closeAccountPage.reasonForLeavingPrompt')} - {props.translate('closeAccountPage.enterDefaultContactToConfirm')} {userEmailOrPhone} + {translate('closeAccountPage.enterDefaultContactToConfirm')} {userEmailOrPhone} @@ -144,16 +147,10 @@ function CloseAccountPage(props) { ); } -CloseAccountPage.propTypes = propTypes; -CloseAccountPage.defaultProps = defaultProps; CloseAccountPage.displayName = 'CloseAccountPage'; -export default compose( - withLocalize, - withWindowDimensions, - withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - }), -)(CloseAccountPage); +export default withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, +})(CloseAccountPage); From 68c3497468f965f23d9100c79341564eb6bcd94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Mon, 22 Jan 2024 16:41:47 +0100 Subject: [PATCH 03/36] useSession useCurrentUserPersonalDetails useBetas hook --- src/components/OnyxProvider.tsx | 6 +++- .../withCurrentUserPersonalDetails.tsx | 35 ++++--------------- src/hooks/useCurrentUserPersonalDetails.ts | 21 +++++++++++ 3 files changed, 33 insertions(+), 29 deletions(-) create mode 100644 src/hooks/useCurrentUserPersonalDetails.ts diff --git a/src/components/OnyxProvider.tsx b/src/components/OnyxProvider.tsx index 124f3558df90..d14aec90fa10 100644 --- a/src/components/OnyxProvider.tsx +++ b/src/components/OnyxProvider.tsx @@ -10,11 +10,12 @@ const [withPersonalDetails, PersonalDetailsProvider, , usePersonalDetails] = cre const [withCurrentDate, CurrentDateProvider] = createOnyxContext(ONYXKEYS.CURRENT_DATE); const [withReportActionsDrafts, ReportActionsDraftsProvider] = createOnyxContext(ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS); const [withBlockedFromConcierge, BlockedFromConciergeProvider] = createOnyxContext(ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE); -const [withBetas, BetasProvider, BetasContext] = createOnyxContext(ONYXKEYS.BETAS); +const [withBetas, BetasProvider, BetasContext, useBetas] = createOnyxContext(ONYXKEYS.BETAS); const [withReportCommentDrafts, ReportCommentDraftsProvider] = createOnyxContext(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT); const [withPreferredTheme, PreferredThemeProvider, PreferredThemeContext] = createOnyxContext(ONYXKEYS.PREFERRED_THEME); const [withFrequentlyUsedEmojis, FrequentlyUsedEmojisProvider, , useFrequentlyUsedEmojis] = createOnyxContext(ONYXKEYS.FREQUENTLY_USED_EMOJIS); const [withPreferredEmojiSkinTone, PreferredEmojiSkinToneProvider, PreferredEmojiSkinToneContext] = createOnyxContext(ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE); +const [, SessionProvider, , useSession] = createOnyxContext(ONYXKEYS.SESSION); type OnyxProviderProps = { /** Rendered child component */ @@ -35,6 +36,7 @@ function OnyxProvider(props: OnyxProviderProps) { PreferredThemeProvider, FrequentlyUsedEmojisProvider, PreferredEmojiSkinToneProvider, + SessionProvider, ]} > {props.children} @@ -59,8 +61,10 @@ export { withReportCommentDrafts, withPreferredTheme, PreferredThemeContext, + useBetas, withFrequentlyUsedEmojis, useFrequentlyUsedEmojis, withPreferredEmojiSkinTone, PreferredEmojiSkinToneContext, + useSession, }; diff --git a/src/components/withCurrentUserPersonalDetails.tsx b/src/components/withCurrentUserPersonalDetails.tsx index 9406c8634c1b..313bcad74f35 100644 --- a/src/components/withCurrentUserPersonalDetails.tsx +++ b/src/components/withCurrentUserPersonalDetails.tsx @@ -1,26 +1,17 @@ import type {ComponentType, ForwardedRef, RefAttributes} from 'react'; -import React, {useMemo} from 'react'; -import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import React from 'react'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import getComponentDisplayName from '@libs/getComponentDisplayName'; import personalDetailsPropType from '@pages/personalDetailsPropType'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import type {PersonalDetails, Session} from '@src/types/onyx'; -import {usePersonalDetails} from './OnyxProvider'; +import type {PersonalDetails} from '@src/types/onyx'; type CurrentUserPersonalDetails = PersonalDetails | Record; -type OnyxProps = { - /** Session of the current user */ - session: OnyxEntry; -}; - type HOCProps = { currentUserPersonalDetails: CurrentUserPersonalDetails; }; -type WithCurrentUserPersonalDetailsProps = OnyxProps & HOCProps; +type WithCurrentUserPersonalDetailsProps = HOCProps; // TODO: remove when all components that use it will be migrated to TS const withCurrentUserPersonalDetailsPropTypes = { @@ -33,15 +24,9 @@ const withCurrentUserPersonalDetailsDefaultProps: HOCProps = { export default function ( WrappedComponent: ComponentType>, -): ComponentType & RefAttributes, keyof OnyxProps>> { +): ComponentType & RefAttributes> { function WithCurrentUserPersonalDetails(props: Omit, ref: ForwardedRef) { - const personalDetails = usePersonalDetails() ?? CONST.EMPTY_OBJECT; - const accountID = props.session?.accountID ?? 0; - const accountPersonalDetails = personalDetails?.[accountID]; - const currentUserPersonalDetails: CurrentUserPersonalDetails = useMemo( - () => (accountPersonalDetails ? {...accountPersonalDetails, accountID} : {}) as CurrentUserPersonalDetails, - [accountPersonalDetails, accountID], - ); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); return ( & RefAttributes, OnyxProps>({ - session: { - key: ONYXKEYS.SESSION, - }, - })(withCurrentUserPersonalDetails); + return React.forwardRef(WithCurrentUserPersonalDetails); } export {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps}; diff --git a/src/hooks/useCurrentUserPersonalDetails.ts b/src/hooks/useCurrentUserPersonalDetails.ts new file mode 100644 index 000000000000..da3c2b18bd83 --- /dev/null +++ b/src/hooks/useCurrentUserPersonalDetails.ts @@ -0,0 +1,21 @@ +import {useMemo} from 'react'; +import {usePersonalDetails, useSession} from '@components/OnyxProvider'; +import CONST from '@src/CONST'; +import type {PersonalDetails} from '@src/types/onyx'; + +type CurrentUserPersonalDetails = PersonalDetails | Record; + +function useCurrentUserPersonalDetails() { + const session = useSession(); + const personalDetails = usePersonalDetails() ?? CONST.EMPTY_OBJECT; + const accountID = session?.accountID ?? 0; + const accountPersonalDetails = personalDetails?.[accountID]; + const currentUserPersonalDetails: CurrentUserPersonalDetails = useMemo( + () => (accountPersonalDetails ? {...accountPersonalDetails, accountID} : {}) as CurrentUserPersonalDetails, + [accountPersonalDetails, accountID], + ); + + return currentUserPersonalDetails; +} + +export default useCurrentUserPersonalDetails; From 7a635c6da30d26d8fd8b0f80f145628a2bdda1ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Mon, 22 Jan 2024 16:42:11 +0100 Subject: [PATCH 04/36] moving search logic to outside hook --- src/pages/tasks/TaskAssigneeSelectorModal.js | 153 ++++++++----------- 1 file changed, 61 insertions(+), 92 deletions(-) diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.js b/src/pages/tasks/TaskAssigneeSelectorModal.js index 1a526a9cdd9b..7c98fcdc9343 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.js +++ b/src/pages/tasks/TaskAssigneeSelectorModal.js @@ -1,18 +1,19 @@ /* eslint-disable es/no-optional-chaining */ +import {useRoute} from '@react-navigation/native'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; -import React, {useCallback, useEffect, useMemo, useState} from 'react'; +import React, {useCallback, useMemo, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import {usePersonalDetails} from '@components/OnyxProvider'; -import OptionsSelector from '@components/OptionsSelector'; +import {useBetas, usePersonalDetails, useSession} from '@components/OnyxProvider'; import ScreenWrapper from '@components/ScreenWrapper'; -import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; -import useAutoFocusInput from '@hooks/useAutoFocusInput'; +import SelectionList from '@components/SelectionList'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import useDebouncedState from '@hooks/useDebouncedState'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; @@ -25,29 +26,9 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; const propTypes = { - /** Beta features list */ - betas: PropTypes.arrayOf(PropTypes.string), - /** All reports shared with the user */ reports: PropTypes.objectOf(reportPropTypes), - /** URL Route params */ - route: PropTypes.shape({ - /** Params from the URL path */ - params: PropTypes.shape({ - /** reportID passed via route: /r/:reportID/title */ - reportID: PropTypes.string, - }), - }), - - // /** The report currently being looked at */ - // report: reportPropTypes.isRequired, - - /** Current user session */ - session: PropTypes.shape({ - email: PropTypes.string.isRequired, - }), - /** Grab the Share destination of the Task */ task: PropTypes.shape({ /** Share destination of the Task */ @@ -62,38 +43,26 @@ const propTypes = { /** The role of current user */ role: PropTypes.string, }), - - ...withLocalizePropTypes, }; const defaultProps = { - betas: [], reports: {}, - session: {}, - route: {}, task: {}, rootParentReportPolicy: {}, }; -function TaskAssigneeSelectorModal(props) { - const styles = useThemeStyles(); - const [searchValue, setSearchValue] = useState(''); - const [headerMessage, setHeaderMessage] = useState(''); - const [filteredRecentReports, setFilteredRecentReports] = useState([]); - const [filteredPersonalDetails, setFilteredPersonalDetails] = useState([]); - const [filteredUserToInvite, setFilteredUserToInvite] = useState(null); - const [filteredCurrentUserOption, setFilteredCurrentUserOption] = useState(null); - const [isLoading, setIsLoading] = React.useState(true); +function useOptions({reports}) { const allPersonalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; + const betas = useBetas(); + const [isLoading, setIsLoading] = useState(true); + const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); - const {inputCallbackRef} = useAutoFocusInput(); - - const updateOptions = useCallback(() => { + const options = useMemo(() => { const {recentReports, personalDetails, userToInvite, currentUserOption} = OptionsListUtils.getFilteredOptions( - props.reports, + reports, allPersonalDetails, - props.betas, - searchValue.trim(), + betas, + debouncedSearchValue.trim(), [], CONST.EXPENSIFY_EMAILS, false, @@ -107,35 +76,42 @@ function TaskAssigneeSelectorModal(props) { true, ); - setHeaderMessage(OptionsListUtils.getHeaderMessage(recentReports?.length + personalDetails?.length !== 0 || currentUserOption, Boolean(userToInvite), searchValue)); + const headerMessage = OptionsListUtils.getHeaderMessage(recentReports?.length + personalDetails?.length !== 0 || currentUserOption, Boolean(userToInvite), debouncedSearchValue); - setFilteredUserToInvite(userToInvite); - setFilteredRecentReports(recentReports); - setFilteredPersonalDetails(personalDetails); - setFilteredCurrentUserOption(currentUserOption); if (isLoading) { setIsLoading(false); } - }, [props, searchValue, allPersonalDetails, isLoading]); - useEffect(() => { - const debouncedSearch = _.debounce(updateOptions, 200); - debouncedSearch(); - return () => { - debouncedSearch.cancel(); + return { + userToInvite, + recentReports, + personalDetails, + currentUserOption, + headerMessage, }; - }, [updateOptions]); + }, [debouncedSearchValue, allPersonalDetails, isLoading, betas, reports]); + + return {...options, isLoading, searchValue, debouncedSearchValue, setSearchValue}; +} + +function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { + const styles = useThemeStyles(); + const route = useRoute(); + const {translate} = useLocalize(); + const session = useSession(); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); + const {userToInvite, recentReports, personalDetails, currentUserOption, isLoading, searchValue, setSearchValue, headerMessage} = useOptions({reports, task}); const onChangeText = (newSearchTerm = '') => { setSearchValue(newSearchTerm); }; const report = useMemo(() => { - if (!props.route.params || !props.route.params.reportID) { + if (!route.params || !route.params.reportID) { return null; } - return props.reports[`${ONYXKEYS.COLLECTION.REPORT}${props.route.params.reportID}`]; - }, [props.reports, props.route.params]); + return reports[`${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`]; + }, [reports, route]); if (report && !ReportUtils.isTaskReport(report)) { Navigation.isNavigationReady().then(() => { @@ -147,10 +123,10 @@ function TaskAssigneeSelectorModal(props) { const sectionsList = []; let indexOffset = 0; - if (filteredCurrentUserOption) { + if (currentUserOption) { sectionsList.push({ - title: props.translate('newTaskPage.assignMe'), - data: [filteredCurrentUserOption], + title: translate('newTaskPage.assignMe'), + data: [currentUserOption], shouldShow: true, indexOffset, }); @@ -158,31 +134,31 @@ function TaskAssigneeSelectorModal(props) { } sectionsList.push({ - title: props.translate('common.recents'), - data: filteredRecentReports, - shouldShow: filteredRecentReports?.length > 0, + title: translate('common.recents'), + data: recentReports, + shouldShow: recentReports?.length > 0, indexOffset, }); - indexOffset += filteredRecentReports?.length; + indexOffset += recentReports?.length; sectionsList.push({ - title: props.translate('common.contacts'), - data: filteredPersonalDetails, - shouldShow: filteredPersonalDetails?.length > 0, + title: translate('common.contacts'), + data: personalDetails, + shouldShow: personalDetails?.length > 0, indexOffset, }); - indexOffset += filteredPersonalDetails?.length; + indexOffset += personalDetails?.length; - if (filteredUserToInvite) { + if (userToInvite) { sectionsList.push({ - data: [filteredUserToInvite], + data: [userToInvite], shouldShow: true, indexOffset, }); } return sectionsList; - }, [filteredCurrentUserOption, filteredPersonalDetails, filteredRecentReports, filteredUserToInvite, props]); + }, [currentUserOption, personalDetails, recentReports, userToInvite, translate]); const selectReport = useCallback( (option) => { @@ -196,20 +172,20 @@ function TaskAssigneeSelectorModal(props) { const assigneeChatReport = Task.setAssigneeValue(option.login, option.accountID, report.reportID, OptionsListUtils.isCurrentUser(option)); // Pass through the selected assignee - Task.editTaskAssignee(report, props.session.accountID, option.login, option.accountID, assigneeChatReport); + Task.editTaskAssignee(report, session.accountID, option.login, option.accountID, assigneeChatReport); } Navigation.dismissModal(report.reportID); // If there's no report, we're creating a new task } else if (option.accountID) { - Task.setAssigneeValue(option.login, option.accountID, props.task.shareDestination, OptionsListUtils.isCurrentUser(option)); + Task.setAssigneeValue(option.login, option.accountID, task.shareDestination, OptionsListUtils.isCurrentUser(option)); Navigation.goBack(ROUTES.NEW_TASK); } }, - [props.session.accountID, props.task.shareDestination, report], + [session.accountID, task.shareDestination, report], ); const isOpen = ReportUtils.isOpenTaskReport(report); - const canModifyTask = Task.canModifyTask(report, props.currentUserPersonalDetails.accountID, lodashGet(props.rootParentReportPolicy, 'role', '')); + const canModifyTask = Task.canModifyTask(report, currentUserPersonalDetails.accountID, lodashGet(rootParentReportPolicy, 'role', '')); const isTaskNonEditable = ReportUtils.isTaskReport(report) && (!canModifyTask || !isOpen); return ( @@ -220,21 +196,21 @@ function TaskAssigneeSelectorModal(props) { {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( (lodashGet(props.route.params, 'reportID') ? Navigation.dismissModal() : Navigation.goBack(ROUTES.NEW_TASK))} + title={translate('task.assignee')} + onBackButtonPress={() => (lodashGet(route.params, 'reportID') ? Navigation.dismissModal() : Navigation.goBack(ROUTES.NEW_TASK))} /> - @@ -246,23 +222,16 @@ function TaskAssigneeSelectorModal(props) { TaskAssigneeSelectorModal.displayName = 'TaskAssigneeSelectorModal'; TaskAssigneeSelectorModal.propTypes = propTypes; TaskAssigneeSelectorModal.defaultProps = defaultProps; +TaskAssigneeSelectorModal.whyDidYouRender = true; export default compose( - withLocalize, - withCurrentUserPersonalDetails, withOnyx({ reports: { key: ONYXKEYS.COLLECTION.REPORT, }, - betas: { - key: ONYXKEYS.BETAS, - }, task: { key: ONYXKEYS.TASK, }, - session: { - key: ONYXKEYS.SESSION, - }, }), withOnyx({ rootParentReportPolicy: { From d3afbcd5d9c8fcfa2a43de13b79015a4771b9d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Mon, 22 Jan 2024 17:09:59 +0100 Subject: [PATCH 05/36] further improvements --- src/pages/tasks/TaskAssigneeSelectorModal.js | 26 +++++++++----------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.js b/src/pages/tasks/TaskAssigneeSelectorModal.js index 7c98fcdc9343..14d2867aa1f4 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.js +++ b/src/pages/tasks/TaskAssigneeSelectorModal.js @@ -1,11 +1,11 @@ /* eslint-disable es/no-optional-chaining */ import {useRoute} from '@react-navigation/native'; import lodashGet from 'lodash/get'; +import lodashPick from 'lodash/pick'; import PropTypes from 'prop-types'; import React, {useCallback, useMemo, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import {useBetas, usePersonalDetails, useSession} from '@components/OnyxProvider'; @@ -110,15 +110,14 @@ function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { if (!route.params || !route.params.reportID) { return null; } + if (report && !ReportUtils.isTaskReport(report)) { + Navigation.isNavigationReady().then(() => { + Navigation.dismissModal(report.reportID); + }); + } return reports[`${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`]; }, [reports, route]); - if (report && !ReportUtils.isTaskReport(report)) { - Navigation.isNavigationReady().then(() => { - Navigation.dismissModal(report.reportID); - }); - } - const sections = useMemo(() => { const sectionsList = []; let indexOffset = 0; @@ -184,6 +183,8 @@ function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { [session.accountID, task.shareDestination, report], ); + const handleBackButtonPress = useCallback(() => (lodashGet(route.params, 'reportID') ? Navigation.dismissModal() : Navigation.goBack(ROUTES.NEW_TASK)), [route.params]); + const isOpen = ReportUtils.isOpenTaskReport(report); const canModifyTask = Task.canModifyTask(report, currentUserPersonalDetails.accountID, lodashGet(rootParentReportPolicy, 'role', '')); const isTaskNonEditable = ReportUtils.isTaskReport(report) && (!canModifyTask || !isOpen); @@ -197,20 +198,18 @@ function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { (lodashGet(route.params, 'reportID') ? Navigation.dismissModal() : Navigation.goBack(ROUTES.NEW_TASK))} + onBackButtonPress={handleBackButtonPress} /> @@ -222,7 +221,6 @@ function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { TaskAssigneeSelectorModal.displayName = 'TaskAssigneeSelectorModal'; TaskAssigneeSelectorModal.propTypes = propTypes; TaskAssigneeSelectorModal.defaultProps = defaultProps; -TaskAssigneeSelectorModal.whyDidYouRender = true; export default compose( withOnyx({ @@ -240,7 +238,7 @@ export default compose( const rootParentReport = ReportUtils.getRootParentReport(report); return `${ONYXKEYS.COLLECTION.POLICY}${rootParentReport ? rootParentReport.policyID : '0'}`; }, - selector: (policy) => _.pick(policy, ['role']), + selector: (policy) => lodashPick(policy, ['role']), }, }), )(TaskAssigneeSelectorModal); From 125b37ad83ff6462a21d59998d5793973b66dda6 Mon Sep 17 00:00:00 2001 From: maddylewis <38016013+maddylewis@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:01:29 -0500 Subject: [PATCH 06/36] Delete docs/articles/expensify-classic/getting-started/Security.md This subcategory is empty / let's delete --- docs/articles/expensify-classic/getting-started/Security.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 docs/articles/expensify-classic/getting-started/Security.md diff --git a/docs/articles/expensify-classic/getting-started/Security.md b/docs/articles/expensify-classic/getting-started/Security.md deleted file mode 100644 index 5a0036e3e161..000000000000 --- a/docs/articles/expensify-classic/getting-started/Security.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Security -description: Security ---- -## Resource Coming Soon! From d788f79ecd2cb234f35dc79644681de387c05ff0 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 25 Jan 2024 17:21:15 +0100 Subject: [PATCH 07/36] Remove extra TODOs, add CloseAccountForm type --- src/ONYXKEYS.ts | 4 ++-- src/pages/settings/Security/CloseAccountPage.tsx | 13 +++---------- src/types/onyx/Form.ts | 7 ++++++- src/types/onyx/index.ts | 3 ++- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 7abf6db1769d..e314acd99f8c 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -480,8 +480,8 @@ type OnyxValues = { [ONYXKEYS.FORMS.WORKSPACE_SETTINGS_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.WORKSPACE_RATE_AND_UNIT_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.WORKSPACE_RATE_AND_UNIT_FORM_DRAFT]: OnyxTypes.Form; - [ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM]: OnyxTypes.Form; - [ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM_DRAFT]: OnyxTypes.Form; + [ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM]: OnyxTypes.CloseAccountForm; + [ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM_DRAFT]: OnyxTypes.CloseAccountForm; [ONYXKEYS.FORMS.PROFILE_SETTINGS_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.PROFILE_SETTINGS_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.DISPLAY_NAME_FORM]: OnyxTypes.DisplayNameForm; diff --git a/src/pages/settings/Security/CloseAccountPage.tsx b/src/pages/settings/Security/CloseAccountPage.tsx index 4922a536a8e4..95faa99dff76 100644 --- a/src/pages/settings/Security/CloseAccountPage.tsx +++ b/src/pages/settings/Security/CloseAccountPage.tsx @@ -7,6 +7,7 @@ import type {OnyxEntry} from 'react-native-onyx/lib/types'; import ConfirmModal from '@components/ConfirmModal'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; +import type {OnyxFormValuesFields} from '@components/Form/types'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; @@ -32,11 +33,6 @@ type CloseAccountPageOnyxProps = { type CloseAccountPageProps = CloseAccountPageOnyxProps & StackScreenProps; -type CloseAccountFormValues = { - reasonForLeaving: string; - phoneOrEmail: string; -}; - function CloseAccountPage({session}: CloseAccountPageProps) { const styles = useThemeStyles(); const {translate, formatPhoneNumber} = useLocalize(); @@ -59,7 +55,7 @@ function CloseAccountPage({session}: CloseAccountPageProps) { hideConfirmModal(); }; - const showConfirmModal = (values: CloseAccountFormValues) => { + const showConfirmModal = (values: OnyxFormValuesFields) => { setConfirmModalVisibility(true); setReasonForLeaving(values.reasonForLeaving); }; @@ -71,7 +67,7 @@ function CloseAccountPage({session}: CloseAccountPageProps) { */ const sanitizePhoneOrEmail = (phoneOrEmail: string): string => phoneOrEmail.replace(/\s+/g, '').toLowerCase(); - const validate = (values: CloseAccountFormValues): Errors => { + const validate = (values: OnyxFormValuesFields): Errors => { const requiredFields = ['phoneOrEmail']; const userEmailOrPhone = formatPhoneNumber(session?.email ?? ''); const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields); @@ -93,7 +89,6 @@ function CloseAccountPage({session}: CloseAccountPageProps) { title={translate('closeAccountPage.closeAccount')} onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_SECURITY)} /> - {/* @ts-expect-error TODO: Remove this once Form (https://github.com/Expensify/App/issues/31972) is migrated to TypeScript. */} {translate('closeAccountPage.reasonForLeavingPrompt')} {userEmailOrPhone} ; +type CloseAccountForm = Form<{ + reasonForLeaving: string; + phoneOrEmail: string; +}>; + export default Form; -export type {AddDebitCardForm, DateOfBirthForm, PrivateNotesForm, DisplayNameForm, FormValueType, NewRoomForm, BaseForm, IKnowATeacherForm, IntroSchoolPrincipalForm}; +export type {AddDebitCardForm, DateOfBirthForm, PrivateNotesForm, DisplayNameForm, FormValueType, NewRoomForm, BaseForm, IKnowATeacherForm, IntroSchoolPrincipalForm, CloseAccountForm}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 5b04cae58671..80c65c4b70be 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -9,7 +9,7 @@ import type Credentials from './Credentials'; import type Currency from './Currency'; import type CustomStatusDraft from './CustomStatusDraft'; import type Download from './Download'; -import type {AddDebitCardForm, DateOfBirthForm, DisplayNameForm, IKnowATeacherForm, IntroSchoolPrincipalForm, NewRoomForm, PrivateNotesForm} from './Form'; +import type {AddDebitCardForm, CloseAccountForm, DateOfBirthForm, DisplayNameForm, IKnowATeacherForm, IntroSchoolPrincipalForm, NewRoomForm, PrivateNotesForm} from './Form'; import type Form from './Form'; import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import type {FundList} from './Fund'; @@ -82,6 +82,7 @@ export type { Credentials, Currency, CustomStatusDraft, + CloseAccountForm, DateOfBirthForm, Download, Form, From 71ca4d4454c4c572a6189b07b7e3027b2da92eed Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 26 Jan 2024 06:43:36 +0700 Subject: [PATCH 08/36] run prettier --- .../BackgroundImage/index.ios.js | 2 +- .../SignInPageLayout/BackgroundImage/index.js | 36 ++++++++++--------- .../BackgroundImage/propTypes.js | 2 +- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js index edfa80358f60..e290c9b262dd 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js @@ -22,7 +22,7 @@ function BackgroundImage(props) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const src = useMemo(() => (props.isSmallScreen ? MobileBackgroundImage : DesktopBackgroundImage), [props.isSmallScreen]); -console.log('[wildebug] props.transitionDuration', props.transitionDuration) + console.log('[wildebug] props.transitionDuration', props.transitionDuration); return ( - {props.isSmallScreen ? ( - - ) : ( - - )}; + return ( + + {props.isSmallScreen ? ( + + ) : ( + + )} + + ); } BackgroundImage.displayName = 'BackgroundImage'; diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js b/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js index 2cf04d90e771..395e182f430a 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js @@ -8,7 +8,7 @@ const propTypes = { width: PropTypes.number.isRequired, /** Tranistion duration in milisecond */ - transitionDuration: PropTypes.number + transitionDuration: PropTypes.number, }; export default propTypes; From 54aa7e974d61c2d548d0159c9393f5ad2c116809 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 26 Jan 2024 06:56:56 +0700 Subject: [PATCH 09/36] prettier & lint --- .../SignInPageLayout/BackgroundImage/index.android.js | 6 +++--- .../signin/SignInPageLayout/BackgroundImage/index.ios.js | 4 +++- src/pages/signin/SignInPageLayout/BackgroundImage/index.js | 3 +++ .../signin/SignInPageLayout/BackgroundImage/propTypes.js | 3 --- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js index 62f94a9dcfcf..753fed2b1e70 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js @@ -1,17 +1,17 @@ import {Image} from 'expo-image'; +import PropTypes from 'prop-types'; import React from 'react'; import AndroidBackgroundImage from '@assets/images/home-background--android.svg'; import useThemeStyles from '@hooks/useThemeStyles'; import defaultPropTypes from './propTypes'; const defaultProps = { - isSmallScreen: false, transitionDuration: 1000, }; const propTypes = { - /** Is the window width narrow, like on a mobile device */ - isSmallScreen: PropTypes.bool, + /** Tranistion duration in milisecond */ + transitionDuration: PropTypes.number, ...defaultPropTypes, }; diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js index e290c9b262dd..421ae1305838 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js @@ -16,13 +16,15 @@ const propTypes = { /** Is the window width narrow, like on a mobile device */ isSmallScreen: PropTypes.bool, + /** Tranistion duration in milisecond */ + transitionDuration: PropTypes.number, + ...defaultPropTypes, }; function BackgroundImage(props) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const src = useMemo(() => (props.isSmallScreen ? MobileBackgroundImage : DesktopBackgroundImage), [props.isSmallScreen]); - console.log('[wildebug] props.transitionDuration', props.transitionDuration); return ( Date: Fri, 26 Jan 2024 06:57:32 +0700 Subject: [PATCH 10/36] change default transition duration to 0 --- .../signin/SignInPageLayout/BackgroundImage/index.android.js | 2 +- src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js | 2 +- src/pages/signin/SignInPageLayout/BackgroundImage/index.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js index 753fed2b1e70..bebbfcedded2 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js @@ -6,7 +6,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import defaultPropTypes from './propTypes'; const defaultProps = { - transitionDuration: 1000, + transitionDuration: 0, }; const propTypes = { diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js index 421ae1305838..a73692d6b21a 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js @@ -9,7 +9,7 @@ import defaultPropTypes from './propTypes'; const defaultProps = { isSmallScreen: false, - transitionDuration: 1000, + transitionDuration: 0, }; const propTypes = { diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.js index f929d5a1dd90..19504852d541 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.js @@ -8,7 +8,7 @@ import defaultPropTypes from './propTypes'; const defaultProps = { isSmallScreen: false, - transitionDuration: 1000, + transitionDuration: 0, }; const propTypes = { From f1598cd225f161f897d10799b5cf2d1c5953928a Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Fri, 26 Jan 2024 07:00:33 +0700 Subject: [PATCH 11/36] extract transition duration to CONST --- src/CONST.ts | 1 + src/pages/signin/SignInPageLayout/index.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/CONST.ts b/src/CONST.ts index ff3934c31943..c28d03d7d927 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -46,6 +46,7 @@ const CONST = { IN: 'in', OUT: 'out', }, + BACKGROUND_IMAGE_TRANSITION: 1000, ARROW_HIDE_DELAY: 3000, API_ATTACHMENT_VALIDATIONS: { diff --git a/src/pages/signin/SignInPageLayout/index.js b/src/pages/signin/SignInPageLayout/index.js index e2f9c28f9fcd..08acfaa20948 100644 --- a/src/pages/signin/SignInPageLayout/index.js +++ b/src/pages/signin/SignInPageLayout/index.js @@ -17,6 +17,7 @@ import BackgroundImage from './BackgroundImage'; import Footer from './Footer'; import SignInPageContent from './SignInPageContent'; import scrollViewContentContainerStyles from './signInPageStyles'; +import CONST from '@src/CONST'; const propTypes = { /** The children to show inside the layout */ @@ -127,6 +128,7 @@ function SignInPageLayout(props) { isSmallScreen={false} pointerEvents="none" width={variables.signInHeroBackgroundWidth} + transitionDuration={CONST.BACKGROUND_IMAGE_TRANSITION} /> @@ -166,6 +168,7 @@ function SignInPageLayout(props) { isSmallScreen pointerEvents="none" width={variables.signInHeroBackgroundWidthMobile} + transitionDuration={CONST.BACKGROUND_IMAGE_TRANSITION} /> Date: Fri, 26 Jan 2024 07:01:18 +0700 Subject: [PATCH 12/36] lint --- src/pages/signin/SignInPageLayout/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/signin/SignInPageLayout/index.js b/src/pages/signin/SignInPageLayout/index.js index 08acfaa20948..635f500c4aa3 100644 --- a/src/pages/signin/SignInPageLayout/index.js +++ b/src/pages/signin/SignInPageLayout/index.js @@ -13,11 +13,11 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import compose from '@libs/compose'; import SignInPageHero from '@pages/signin/SignInPageHero'; import variables from '@styles/variables'; +import CONST from '@src/CONST'; import BackgroundImage from './BackgroundImage'; import Footer from './Footer'; import SignInPageContent from './SignInPageContent'; import scrollViewContentContainerStyles from './signInPageStyles'; -import CONST from '@src/CONST'; const propTypes = { /** The children to show inside the layout */ From 8910503c77b97dcac7fe6f29797c4f035f38455c Mon Sep 17 00:00:00 2001 From: Wildan M Date: Mon, 29 Jan 2024 06:56:12 +0700 Subject: [PATCH 13/36] Update src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js Co-authored-by: Eugene Voloshchak --- .../signin/SignInPageLayout/BackgroundImage/index.android.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js index bebbfcedded2..a3ddc3383bc4 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js @@ -10,7 +10,7 @@ const defaultProps = { }; const propTypes = { - /** Tranistion duration in milisecond */ + /** Transition duration in milliseconds */ transitionDuration: PropTypes.number, ...defaultPropTypes, From 894b2fe3ad5d9732fd2941d054069fb9a1542e3b Mon Sep 17 00:00:00 2001 From: Wildan M Date: Mon, 29 Jan 2024 06:56:28 +0700 Subject: [PATCH 14/36] Update src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js Co-authored-by: Eugene Voloshchak --- src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js index a73692d6b21a..20d5a75a8838 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js @@ -16,7 +16,7 @@ const propTypes = { /** Is the window width narrow, like on a mobile device */ isSmallScreen: PropTypes.bool, - /** Tranistion duration in milisecond */ + /** Transition duration in milliseconds */ transitionDuration: PropTypes.number, ...defaultPropTypes, From 89e53cf833d97ea881b824cc5e157c5fdfb19fad Mon Sep 17 00:00:00 2001 From: Wildan M Date: Mon, 29 Jan 2024 07:05:38 +0700 Subject: [PATCH 15/36] Update src/CONST.ts Co-authored-by: Eugene Voloshchak --- src/CONST.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index c28d03d7d927..58bc0c8ad295 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -46,7 +46,7 @@ const CONST = { IN: 'in', OUT: 'out', }, - BACKGROUND_IMAGE_TRANSITION: 1000, + BACKGROUND_IMAGE_TRANSITION_DURATION: 1000, ARROW_HIDE_DELAY: 3000, API_ATTACHMENT_VALIDATIONS: { From fc2ab2b09ec50eb5b15c9f150d53bc54da86aba6 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 29 Jan 2024 17:40:46 +0100 Subject: [PATCH 16/36] Update formatPhoneNumber typing --- src/components/LocaleContextProvider.tsx | 2 +- src/libs/LocalePhoneNumber.ts | 2 +- src/pages/settings/Security/CloseAccountPage.tsx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/LocaleContextProvider.tsx b/src/components/LocaleContextProvider.tsx index 7313bb4aa7bb..48e9aa49d0de 100644 --- a/src/components/LocaleContextProvider.tsx +++ b/src/components/LocaleContextProvider.tsx @@ -45,7 +45,7 @@ type LocaleContextProps = { /** Returns a locally converted phone number for numbers from the same region * and an internationally converted phone number with the country code for numbers from other regions */ - formatPhoneNumber: (phoneNumber: string) => string; + formatPhoneNumber: (phoneNumber: string | undefined) => string; /** Gets the locale digit corresponding to a standard digit */ toLocaleDigit: (digit: string) => string; diff --git a/src/libs/LocalePhoneNumber.ts b/src/libs/LocalePhoneNumber.ts index 933aa7937560..9aacc6968e1e 100644 --- a/src/libs/LocalePhoneNumber.ts +++ b/src/libs/LocalePhoneNumber.ts @@ -13,7 +13,7 @@ Onyx.connect({ * Returns a locally converted phone number for numbers from the same region * and an internationally converted phone number with the country code for numbers from other regions */ -function formatPhoneNumber(number: string): string { +function formatPhoneNumber(number: string | undefined): string { if (!number) { return ''; } diff --git a/src/pages/settings/Security/CloseAccountPage.tsx b/src/pages/settings/Security/CloseAccountPage.tsx index 95faa99dff76..2287752cd786 100644 --- a/src/pages/settings/Security/CloseAccountPage.tsx +++ b/src/pages/settings/Security/CloseAccountPage.tsx @@ -69,7 +69,7 @@ function CloseAccountPage({session}: CloseAccountPageProps) { const validate = (values: OnyxFormValuesFields): Errors => { const requiredFields = ['phoneOrEmail']; - const userEmailOrPhone = formatPhoneNumber(session?.email ?? ''); + const userEmailOrPhone = formatPhoneNumber(session?.email); const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields); if (values.phoneOrEmail && sanitizePhoneOrEmail(userEmailOrPhone) !== sanitizePhoneOrEmail(values.phoneOrEmail)) { @@ -78,7 +78,7 @@ function CloseAccountPage({session}: CloseAccountPageProps) { return errors; }; - const userEmailOrPhone = formatPhoneNumber(session?.email ?? ''); + const userEmailOrPhone = formatPhoneNumber(session?.email); return ( Date: Tue, 30 Jan 2024 11:48:11 +0100 Subject: [PATCH 17/36] Fix Onyx types import --- src/pages/settings/Security/CloseAccountPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Security/CloseAccountPage.tsx b/src/pages/settings/Security/CloseAccountPage.tsx index 2287752cd786..f1a0d064fe0a 100644 --- a/src/pages/settings/Security/CloseAccountPage.tsx +++ b/src/pages/settings/Security/CloseAccountPage.tsx @@ -3,7 +3,7 @@ import Str from 'expensify-common/lib/str'; import React, {useEffect, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx/lib/types'; +import type {OnyxEntry} from 'react-native-onyx'; import ConfirmModal from '@components/ConfirmModal'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; From cfd4286c528a290c55971d72de83542aa590a921 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 31 Jan 2024 07:40:23 +0700 Subject: [PATCH 18/36] move transitionDuration to propTypes, remove default value of transitionDuration, fix incorrect const name --- .../SignInPageLayout/BackgroundImage/index.android.js | 10 +--------- .../SignInPageLayout/BackgroundImage/index.ios.js | 4 ---- .../signin/SignInPageLayout/BackgroundImage/index.js | 4 ---- .../SignInPageLayout/BackgroundImage/propTypes.js | 3 +++ src/pages/signin/SignInPageLayout/index.js | 2 +- 5 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js index a3ddc3383bc4..06784ddef007 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js @@ -9,13 +9,6 @@ const defaultProps = { transitionDuration: 0, }; -const propTypes = { - /** Transition duration in milliseconds */ - transitionDuration: PropTypes.number, - - ...defaultPropTypes, -}; - function BackgroundImage(props) { const styles = useThemeStyles(); return ( @@ -29,7 +22,6 @@ function BackgroundImage(props) { } BackgroundImage.displayName = 'BackgroundImage'; -BackgroundImage.propTypes = propTypes; -BackgroundImage.defaultProps = defaultProps; +BackgroundImage.propTypes = defaultPropTypes; export default BackgroundImage; diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js index 20d5a75a8838..b426a888e8b9 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.ios.js @@ -9,16 +9,12 @@ import defaultPropTypes from './propTypes'; const defaultProps = { isSmallScreen: false, - transitionDuration: 0, }; const propTypes = { /** Is the window width narrow, like on a mobile device */ isSmallScreen: PropTypes.bool, - /** Transition duration in milliseconds */ - transitionDuration: PropTypes.number, - ...defaultPropTypes, }; function BackgroundImage(props) { diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.js index 19504852d541..96406d6f3d31 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.js @@ -8,16 +8,12 @@ import defaultPropTypes from './propTypes'; const defaultProps = { isSmallScreen: false, - transitionDuration: 0, }; const propTypes = { /** Is the window width narrow, like on a mobile device */ isSmallScreen: PropTypes.bool, - /** Tranistion duration in milisecond */ - transitionDuration: PropTypes.number, - ...defaultPropTypes, }; function BackgroundImage(props) { diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js b/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js index 533d22ad12c5..d966b196b725 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/propTypes.js @@ -6,6 +6,9 @@ const propTypes = { /** The width of the image. */ width: PropTypes.number.isRequired, + + /** Transition duration in milliseconds */ + transitionDuration: PropTypes.number, }; export default propTypes; diff --git a/src/pages/signin/SignInPageLayout/index.js b/src/pages/signin/SignInPageLayout/index.js index 635f500c4aa3..fdb7221cbf15 100644 --- a/src/pages/signin/SignInPageLayout/index.js +++ b/src/pages/signin/SignInPageLayout/index.js @@ -128,7 +128,7 @@ function SignInPageLayout(props) { isSmallScreen={false} pointerEvents="none" width={variables.signInHeroBackgroundWidth} - transitionDuration={CONST.BACKGROUND_IMAGE_TRANSITION} + transitionDuration={CONST.BACKGROUND_IMAGE_TRANSITION_DURATION} /> From 3a0f56f557df430809912a2f51e34d169a90ad73 Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 31 Jan 2024 08:04:35 +0700 Subject: [PATCH 19/36] fix incorrect const call --- nextjs-starter-medusa-billplz | 1 + src/pages/signin/SignInPageLayout/index.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 160000 nextjs-starter-medusa-billplz diff --git a/nextjs-starter-medusa-billplz b/nextjs-starter-medusa-billplz new file mode 160000 index 000000000000..af3c68c1557f --- /dev/null +++ b/nextjs-starter-medusa-billplz @@ -0,0 +1 @@ +Subproject commit af3c68c1557f7091cb7d9b8aeeb5e5a9b8e8ba89 diff --git a/src/pages/signin/SignInPageLayout/index.js b/src/pages/signin/SignInPageLayout/index.js index fdb7221cbf15..5465a3189818 100644 --- a/src/pages/signin/SignInPageLayout/index.js +++ b/src/pages/signin/SignInPageLayout/index.js @@ -168,7 +168,7 @@ function SignInPageLayout(props) { isSmallScreen pointerEvents="none" width={variables.signInHeroBackgroundWidthMobile} - transitionDuration={CONST.BACKGROUND_IMAGE_TRANSITION} + transitionDuration={CONST.BACKGROUND_IMAGE_TRANSITION_DURATION} /> Date: Wed, 31 Jan 2024 08:22:33 +0700 Subject: [PATCH 20/36] remove unrelated file --- nextjs-starter-medusa-billplz | 1 - 1 file changed, 1 deletion(-) delete mode 160000 nextjs-starter-medusa-billplz diff --git a/nextjs-starter-medusa-billplz b/nextjs-starter-medusa-billplz deleted file mode 160000 index af3c68c1557f..000000000000 --- a/nextjs-starter-medusa-billplz +++ /dev/null @@ -1 +0,0 @@ -Subproject commit af3c68c1557f7091cb7d9b8aeeb5e5a9b8e8ba89 From 77df109cdabe30afc19c9e510d326fd6a9b78eda Mon Sep 17 00:00:00 2001 From: Wildan Muhlis Date: Wed, 31 Jan 2024 08:27:26 +0700 Subject: [PATCH 21/36] remove unused import and var --- .../signin/SignInPageLayout/BackgroundImage/index.android.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js index 06784ddef007..8d261134baba 100644 --- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js +++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js @@ -1,14 +1,9 @@ import {Image} from 'expo-image'; -import PropTypes from 'prop-types'; import React from 'react'; import AndroidBackgroundImage from '@assets/images/home-background--android.svg'; import useThemeStyles from '@hooks/useThemeStyles'; import defaultPropTypes from './propTypes'; -const defaultProps = { - transitionDuration: 0, -}; - function BackgroundImage(props) { const styles = useThemeStyles(); return ( From 5595560e1b3faf78f9bec4498308e4b47d9565e8 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 31 Jan 2024 09:39:20 -0700 Subject: [PATCH 22/36] show card for corporate cards --- src/components/ReportActionItem/MoneyRequestPreview.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 7b38dcd34109..13f75b9869a0 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -165,7 +165,7 @@ function MoneyRequestPreview(props) { const isScanning = hasReceipt && TransactionUtils.isReceiptBeingScanned(props.transaction); const hasFieldErrors = TransactionUtils.hasMissingSmartscanFields(props.transaction); const isDistanceRequest = TransactionUtils.isDistanceRequest(props.transaction); - const isExpensifyCardTransaction = TransactionUtils.isExpensifyCardTransaction(props.transaction); + const isCardTransaction = TransactionUtils.isCardTransaction(props.transaction); const isSettled = ReportUtils.isSettled(props.iouReport.reportID); const isDeleted = lodashGet(props.action, 'pendingAction', null) === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; @@ -184,7 +184,7 @@ function MoneyRequestPreview(props) { const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(props.transaction)] : []; const getSettledMessage = () => { - if (isExpensifyCardTransaction) { + if (isCardTransaction) { return translate('common.done'); } return translate('iou.settledExpensify'); @@ -207,7 +207,7 @@ function MoneyRequestPreview(props) { return translate('iou.split'); } - if (isExpensifyCardTransaction) { + if (isCardTransaction) { let message = translate('iou.card'); if (TransactionUtils.isPending(props.transaction)) { message += ` • ${translate('iou.pending')}`; From 39ef206b1f26d2b30467dd8535707dccbf1c74ba Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 1 Feb 2024 09:48:54 +0100 Subject: [PATCH 23/36] Lint fix --- src/types/onyx/index.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 64ffddc6935f..c6f8d43c75e1 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -9,7 +9,17 @@ import type Credentials from './Credentials'; import type Currency from './Currency'; import type CustomStatusDraft from './CustomStatusDraft'; import type Download from './Download'; -import type {AddDebitCardForm, CloseAccountForm, DateOfBirthForm, DisplayNameForm, IKnowATeacherForm, IntroSchoolPrincipalForm, NewRoomForm, PrivateNotesForm, ReportFieldEditForm} from './Form'; +import type { + AddDebitCardForm, + CloseAccountForm, + DateOfBirthForm, + DisplayNameForm, + IKnowATeacherForm, + IntroSchoolPrincipalForm, + NewRoomForm, + PrivateNotesForm, + ReportFieldEditForm, +} from './Form'; import type Form from './Form'; import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import type {FundList} from './Fund'; From 1864113b2a695286691c641143559e57055c52ca Mon Sep 17 00:00:00 2001 From: rory Date: Thu, 1 Feb 2024 13:14:13 -0800 Subject: [PATCH 24/36] Improve Google Sign In documentation --- contributingGuides/APPLE_GOOGLE_SIGNIN.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/contributingGuides/APPLE_GOOGLE_SIGNIN.md b/contributingGuides/APPLE_GOOGLE_SIGNIN.md index 43485a28b353..4bb86e31b486 100644 --- a/contributingGuides/APPLE_GOOGLE_SIGNIN.md +++ b/contributingGuides/APPLE_GOOGLE_SIGNIN.md @@ -259,12 +259,33 @@ if (CONFIG.ENVIRONMENT === CONST.ENVIRONMENT.DEV) { } ``` -#### Port requirements +#### Host/Port requirements Google allows the web app to be hosted at localhost, but according to the current Google console configuration for the Expensify client ID, it must be hosted on port 8082. +Also note that you'll need to update the webpack.dev.js config to change `host` from `dev.new.expensify.com` to `localhost` and server type from `https` to `http`. The reason for this is that Google Sign In allows localhost, but `dev.new.expensify.com` is not a registered Google Sign In domain. + +```diff +diff --git a/config/webpack/webpack.dev.js b/config/webpack/webpack.dev.js +index e28383eff5..b14f6f34aa 100644 +--- a/config/webpack/webpack.dev.js ++++ b/config/webpack/webpack.dev.js +@@ -44,9 +44,9 @@ module.exports = (env = {}) => + ...proxySettings, + historyApiFallback: true, + port, +- host: 'dev.new.expensify.com', ++ host: 'localhost', + server: { +- type: 'https', ++ type: 'http', + options: { + key: path.join(__dirname, 'key.pem'), + cert: path.join(__dirname, 'certificate.pem'), +``` + ### Desktop #### Set Environment to something other than "Development" From 1cfc7fb099bcc311cd81f8a22ca713034d469c07 Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Thu, 1 Feb 2024 21:56:56 -0800 Subject: [PATCH 25/36] Revert "Image Web/Desktop: Add support for http headers" --- ...-web+0.19.9+005+image-header-support.patch | 200 ------------------ src/components/Image/BaseImage.native.tsx | 32 --- src/components/Image/BaseImage.tsx | 32 --- src/components/Image/index.js | 52 +++-- src/components/Image/index.native.js | 63 ++++++ src/components/Image/types.ts | 8 - src/pages/DetailsPage.js | 1 + 7 files changed, 98 insertions(+), 290 deletions(-) delete mode 100644 patches/react-native-web+0.19.9+005+image-header-support.patch delete mode 100644 src/components/Image/BaseImage.native.tsx delete mode 100644 src/components/Image/BaseImage.tsx create mode 100644 src/components/Image/index.native.js delete mode 100644 src/components/Image/types.ts diff --git a/patches/react-native-web+0.19.9+005+image-header-support.patch b/patches/react-native-web+0.19.9+005+image-header-support.patch deleted file mode 100644 index 4652e22662f0..000000000000 --- a/patches/react-native-web+0.19.9+005+image-header-support.patch +++ /dev/null @@ -1,200 +0,0 @@ -diff --git a/node_modules/react-native-web/dist/exports/Image/index.js b/node_modules/react-native-web/dist/exports/Image/index.js -index 95355d5..19109fc 100644 ---- a/node_modules/react-native-web/dist/exports/Image/index.js -+++ b/node_modules/react-native-web/dist/exports/Image/index.js -@@ -135,7 +135,22 @@ function resolveAssetUri(source) { - } - return uri; - } --var Image = /*#__PURE__*/React.forwardRef((props, ref) => { -+function raiseOnErrorEvent(uri, _ref) { -+ var onError = _ref.onError, -+ onLoadEnd = _ref.onLoadEnd; -+ if (onError) { -+ onError({ -+ nativeEvent: { -+ error: "Failed to load resource " + uri + " (404)" -+ } -+ }); -+ } -+ if (onLoadEnd) onLoadEnd(); -+} -+function hasSourceDiff(a, b) { -+ return a.uri !== b.uri || JSON.stringify(a.headers) !== JSON.stringify(b.headers); -+} -+var BaseImage = /*#__PURE__*/React.forwardRef((props, ref) => { - var ariaLabel = props['aria-label'], - blurRadius = props.blurRadius, - defaultSource = props.defaultSource, -@@ -236,16 +251,10 @@ var Image = /*#__PURE__*/React.forwardRef((props, ref) => { - } - }, function error() { - updateState(ERRORED); -- if (onError) { -- onError({ -- nativeEvent: { -- error: "Failed to load resource " + uri + " (404)" -- } -- }); -- } -- if (onLoadEnd) { -- onLoadEnd(); -- } -+ raiseOnErrorEvent(uri, { -+ onError, -+ onLoadEnd -+ }); - }); - } - function abortPendingRequest() { -@@ -277,10 +286,78 @@ var Image = /*#__PURE__*/React.forwardRef((props, ref) => { - suppressHydrationWarning: true - }), hiddenImage, createTintColorSVG(tintColor, filterRef.current)); - }); --Image.displayName = 'Image'; -+BaseImage.displayName = 'Image'; -+ -+/** -+ * This component handles specifically loading an image source with headers -+ * default source is never loaded using headers -+ */ -+var ImageWithHeaders = /*#__PURE__*/React.forwardRef((props, ref) => { -+ // $FlowIgnore: This component would only be rendered when `source` matches `ImageSource` -+ var nextSource = props.source; -+ var _React$useState3 = React.useState(''), -+ blobUri = _React$useState3[0], -+ setBlobUri = _React$useState3[1]; -+ var request = React.useRef({ -+ cancel: () => {}, -+ source: { -+ uri: '', -+ headers: {} -+ }, -+ promise: Promise.resolve('') -+ }); -+ var onError = props.onError, -+ onLoadStart = props.onLoadStart, -+ onLoadEnd = props.onLoadEnd; -+ React.useEffect(() => { -+ if (!hasSourceDiff(nextSource, request.current.source)) { -+ return; -+ } -+ -+ // When source changes we want to clean up any old/running requests -+ request.current.cancel(); -+ if (onLoadStart) { -+ onLoadStart(); -+ } -+ -+ // Store a ref for the current load request so we know what's the last loaded source, -+ // and so we can cancel it if a different source is passed through props -+ request.current = ImageLoader.loadWithHeaders(nextSource); -+ request.current.promise.then(uri => setBlobUri(uri)).catch(() => raiseOnErrorEvent(request.current.source.uri, { -+ onError, -+ onLoadEnd -+ })); -+ }, [nextSource, onLoadStart, onError, onLoadEnd]); -+ -+ // Cancel any request on unmount -+ React.useEffect(() => request.current.cancel, []); -+ var propsToPass = _objectSpread(_objectSpread({}, props), {}, { -+ // `onLoadStart` is called from the current component -+ // We skip passing it down to prevent BaseImage raising it a 2nd time -+ onLoadStart: undefined, -+ // Until the current component resolves the request (using headers) -+ // we skip forwarding the source so the base component doesn't attempt -+ // to load the original source -+ source: blobUri ? _objectSpread(_objectSpread({}, nextSource), {}, { -+ uri: blobUri -+ }) : undefined -+ }); -+ return /*#__PURE__*/React.createElement(BaseImage, _extends({ -+ ref: ref -+ }, propsToPass)); -+}); - - // $FlowIgnore: This is the correct type, but casting makes it unhappy since the variables aren't defined yet --var ImageWithStatics = Image; -+var ImageWithStatics = /*#__PURE__*/React.forwardRef((props, ref) => { -+ if (props.source && props.source.headers) { -+ return /*#__PURE__*/React.createElement(ImageWithHeaders, _extends({ -+ ref: ref -+ }, props)); -+ } -+ return /*#__PURE__*/React.createElement(BaseImage, _extends({ -+ ref: ref -+ }, props)); -+}); - ImageWithStatics.getSize = function (uri, success, failure) { - ImageLoader.getSize(uri, success, failure); - }; -diff --git a/node_modules/react-native-web/dist/modules/ImageLoader/index.js b/node_modules/react-native-web/dist/modules/ImageLoader/index.js -index bc06a87..e309394 100644 ---- a/node_modules/react-native-web/dist/modules/ImageLoader/index.js -+++ b/node_modules/react-native-web/dist/modules/ImageLoader/index.js -@@ -76,7 +76,7 @@ var ImageLoader = { - var image = requests["" + requestId]; - if (image) { - var naturalHeight = image.naturalHeight, -- naturalWidth = image.naturalWidth; -+ naturalWidth = image.naturalWidth; - if (naturalHeight && naturalWidth) { - success(naturalWidth, naturalHeight); - complete = true; -@@ -102,11 +102,19 @@ var ImageLoader = { - id += 1; - var image = new window.Image(); - image.onerror = onError; -- image.onload = e => { -+ image.onload = nativeEvent => { - // avoid blocking the main thread -- var onDecode = () => onLoad({ -- nativeEvent: e -- }); -+ var onDecode = () => { -+ // Append `source` to match RN's ImageLoadEvent interface -+ nativeEvent.source = { -+ uri: image.src, -+ width: image.naturalWidth, -+ height: image.naturalHeight -+ }; -+ onLoad({ -+ nativeEvent -+ }); -+ }; - if (typeof image.decode === 'function') { - // Safari currently throws exceptions when decoding svgs. - // We want to catch that error and allow the load handler -@@ -120,6 +128,32 @@ var ImageLoader = { - requests["" + id] = image; - return id; - }, -+ loadWithHeaders(source) { -+ var uri; -+ var abortController = new AbortController(); -+ var request = new Request(source.uri, { -+ headers: source.headers, -+ signal: abortController.signal -+ }); -+ request.headers.append('accept', 'image/*'); -+ var promise = fetch(request).then(response => response.blob()).then(blob => { -+ uri = URL.createObjectURL(blob); -+ return uri; -+ }).catch(error => { -+ if (error.name === 'AbortError') { -+ return ''; -+ } -+ throw error; -+ }); -+ return { -+ promise, -+ source, -+ cancel: () => { -+ abortController.abort(); -+ URL.revokeObjectURL(uri); -+ } -+ }; -+ }, - prefetch(uri) { - return new Promise((resolve, reject) => { - ImageLoader.load(uri, () => { diff --git a/src/components/Image/BaseImage.native.tsx b/src/components/Image/BaseImage.native.tsx deleted file mode 100644 index c517efd04515..000000000000 --- a/src/components/Image/BaseImage.native.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import {Image as ExpoImage} from 'expo-image'; -import type {ImageProps as ExpoImageProps, ImageLoadEventData} from 'expo-image'; -import {useCallback} from 'react'; -import type {BaseImageProps} from './types'; - -function BaseImage({onLoad, ...props}: ExpoImageProps & BaseImageProps) { - const imageLoadedSuccessfully = useCallback( - (event: ImageLoadEventData) => { - if (!onLoad) { - return; - } - - // We override `onLoad`, so both web and native have the same signature - const {width, height} = event.source; - onLoad({nativeEvent: {width, height}}); - }, - [onLoad], - ); - - return ( - - ); -} - -BaseImage.displayName = 'BaseImage'; - -export default BaseImage; diff --git a/src/components/Image/BaseImage.tsx b/src/components/Image/BaseImage.tsx deleted file mode 100644 index ebdd76840267..000000000000 --- a/src/components/Image/BaseImage.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React, {useCallback} from 'react'; -import {Image as RNImage} from 'react-native'; -import type {ImageLoadEventData, ImageProps as WebImageProps} from 'react-native'; -import type {BaseImageProps} from './types'; - -function BaseImage({onLoad, ...props}: WebImageProps & BaseImageProps) { - const imageLoadedSuccessfully = useCallback( - (event: {nativeEvent: ImageLoadEventData}) => { - if (!onLoad) { - return; - } - - // We override `onLoad`, so both web and native have the same signature - const {width, height} = event.nativeEvent.source; - onLoad({nativeEvent: {width, height}}); - }, - [onLoad], - ); - - return ( - - ); -} - -BaseImage.displayName = 'BaseImage'; - -export default BaseImage; diff --git a/src/components/Image/index.js b/src/components/Image/index.js index 8cee1cf95e14..ef1a69e19c12 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -1,35 +1,51 @@ import lodashGet from 'lodash/get'; -import React, {useMemo} from 'react'; +import React, {useEffect, useMemo} from 'react'; +import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import CONST from '@src/CONST'; +import _ from 'underscore'; import ONYXKEYS from '@src/ONYXKEYS'; -import BaseImage from './BaseImage'; import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; -function Image({source: propsSource, isAuthTokenRequired, session, ...forwardedProps}) { - // Update the source to include the auth token if required +function Image(props) { + const {source: propsSource, isAuthTokenRequired, onLoad, session} = props; + /** + * Check if the image source is a URL - if so the `encryptedAuthToken` is appended + * to the source. + */ const source = useMemo(() => { - if (typeof lodashGet(propsSource, 'uri') === 'number') { - return propsSource.uri; + if (isAuthTokenRequired) { + // There is currently a `react-native-web` bug preventing the authToken being passed + // in the headers of the image request so the authToken is added as a query param. + // On native the authToken IS passed in the image request headers + const authToken = lodashGet(session, 'encryptedAuthToken', null); + return {uri: `${propsSource.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; } - if (typeof propsSource !== 'number' && isAuthTokenRequired) { - const authToken = lodashGet(session, 'encryptedAuthToken'); - return { - ...propsSource, - headers: { - [CONST.CHAT_ATTACHMENT_TOKEN_KEY]: authToken, - }, - }; - } - return propsSource; // The session prop is not required, as it causes the image to reload whenever the session changes. For more information, please refer to issue #26034. // eslint-disable-next-line react-hooks/exhaustive-deps }, [propsSource, isAuthTokenRequired]); + /** + * The natural image dimensions are retrieved using the updated source + * and as a result the `onLoad` event needs to be manually invoked to return these dimensions + */ + useEffect(() => { + // If an onLoad callback was specified then manually call it and pass + // the natural image dimensions to match the native API + if (onLoad == null) { + return; + } + RNImage.getSize(source.uri, (width, height) => { + onLoad({nativeEvent: {width, height}}); + }); + }, [onLoad, source]); + + // Omit the props which the underlying RNImage won't use + const forwardedProps = _.omit(props, ['source', 'onLoad', 'session', 'isAuthTokenRequired']); + return ( - { + const {width, height, url} = evt.source; + dimensionsCache.set(url, {width, height}); + if (props.onLoad) { + props.onLoad({nativeEvent: {width, height}}); + } + }} + /> + ); +} + +Image.propTypes = imagePropTypes; +Image.defaultProps = defaultProps; +Image.displayName = 'Image'; +const ImageWithOnyx = withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, +})(Image); +ImageWithOnyx.resizeMode = RESIZE_MODES; +ImageWithOnyx.resolveDimensions = resolveDimensions; + +export default ImageWithOnyx; diff --git a/src/components/Image/types.ts b/src/components/Image/types.ts deleted file mode 100644 index 5a4c94364a46..000000000000 --- a/src/components/Image/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -type BaseImageProps = { - /** Event called with image dimensions when image is loaded */ - onLoad?: (event: {nativeEvent: {width: number; height: number}}) => void; -}; - -export type {BaseImageProps}; - -export default BaseImageProps; diff --git a/src/pages/DetailsPage.js b/src/pages/DetailsPage.js index cdf5dc5a0502..a4cafd59cb73 100755 --- a/src/pages/DetailsPage.js +++ b/src/pages/DetailsPage.js @@ -136,6 +136,7 @@ function DetailsPage(props) { From 7eba6d53d686e583262e1e8897b79a1291f8c752 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Fri, 2 Feb 2024 11:45:45 +0500 Subject: [PATCH 26/36] fix: props not updating --- src/pages/home/ReportScreen.js | 11 +---------- src/pages/home/report/ReportActionsView.js | 8 +------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index f671f14813d2..5ac4dd492bee 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -659,17 +659,8 @@ export default compose( _.isEqual(prevProps.policies, nextProps.policies) && prevProps.accountManagerReportID === nextProps.accountManagerReportID && prevProps.userLeavingStatus === nextProps.userLeavingStatus && - prevProps.report.reportID === nextProps.report.reportID && - prevProps.report.policyID === nextProps.report.policyID && - prevProps.report.managerID === nextProps.report.managerID && - prevProps.report.isOptimisticReport === nextProps.report.isOptimisticReport && - prevProps.report.statusNum === nextProps.report.statusNum && - _.isEqual(prevProps.report.pendingFields, nextProps.report.pendingFields) && + _.isEqual(prevProps.report, nextProps.report) && prevProps.currentReportID === nextProps.currentReportID && - prevProps.report.notificationPreference === nextProps.report.notificationPreference && - prevProps.report.isPinned === nextProps.report.isPinned && - prevProps.report.chatReportID === nextProps.report.chatReportID && - prevProps.report.visibility === nextProps.report.visibility && prevProps.viewportOffsetTop === nextProps.viewportOffsetTop, ), ); diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index e50dcbb99f6b..9b7196583fea 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -315,13 +315,7 @@ function arePropsEqual(oldProps, newProps) { } return ( - oldProps.report.lastReadTime === newProps.report.lastReadTime && - oldProps.report.reportID === newProps.report.reportID && - oldProps.report.policyID === newProps.report.policyID && - oldProps.report.managerID === newProps.report.managerID && - oldProps.report.lastVisibleActionCreated === newProps.report.lastVisibleActionCreated && - oldProps.report.isOptimisticReport === newProps.report.isOptimisticReport && - _.isEqual(oldProps.report.pendingFields, newProps.report.pendingFields) + _.isEqual(oldProps.report, newProps.report) ); } From 77be07c541aab73419ffb464dd1b833d6ebaa171 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Fri, 2 Feb 2024 12:06:33 +0500 Subject: [PATCH 27/36] fix: lint --- src/pages/home/report/ReportActionsView.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index 9b7196583fea..62ff9426b4ae 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -314,9 +314,7 @@ function arePropsEqual(oldProps, newProps) { return false; } - return ( - _.isEqual(oldProps.report, newProps.report) - ); + return _.isEqual(oldProps.report, newProps.report); } const MemoizedReportActionsView = React.memo(ReportActionsView, arePropsEqual); From 3b9b29b0a882592a147c15b436d97747b14c591b Mon Sep 17 00:00:00 2001 From: hurali97 Date: Fri, 2 Feb 2024 12:54:59 +0500 Subject: [PATCH 28/36] fix: add missing report props --- src/pages/home/ReportScreen.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 5ac4dd492bee..108dfc357e8d 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -203,6 +203,9 @@ function ReportScreen({ isPinned: reportProp.isPinned, chatReportID: reportProp.chatReportID, visibility: reportProp.visibility, + oldPolicyName: reportProp.oldPolicyName, + policyName: reportProp.policyName, + isOptimisticReport: reportProp.isOptimisticReport, }), [ reportProp.lastReadTime, @@ -236,6 +239,9 @@ function ReportScreen({ reportProp.isPinned, reportProp.chatReportID, reportProp.visibility, + reportProp.oldPolicyName, + reportProp.policyName, + reportProp.isOptimisticReport, ], ); From d2f71a868303f9a133265be8bb4f5e8b2a02cd08 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 2 Feb 2024 11:07:13 +0100 Subject: [PATCH 29/36] Fix lint error --- src/types/onyx/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 787b9298b011..d0ac2ce395fa 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -11,6 +11,7 @@ import type CustomStatusDraft from './CustomStatusDraft'; import type Download from './Download'; import type { AddDebitCardForm, + CloseAccountForm, DateOfBirthForm, DisplayNameForm, IKnowATeacherForm, @@ -19,7 +20,6 @@ import type { PrivateNotesForm, ReportFieldEditForm, WorkspaceSettingsForm, - CloseAccountForm, } from './Form'; import type Form from './Form'; import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; From 442fea53fb527cb977f3df9e78f7a29106f2fa03 Mon Sep 17 00:00:00 2001 From: hurali97 Date: Fri, 2 Feb 2024 15:59:04 +0500 Subject: [PATCH 30/36] refactor: prefer individual comparison in favor of isEqual --- src/pages/home/ReportScreen.js | 37 ++++++++++++++++++++-- src/pages/home/report/ReportActionsView.js | 20 +++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 108dfc357e8d..6efa0bd0246e 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -665,8 +665,41 @@ export default compose( _.isEqual(prevProps.policies, nextProps.policies) && prevProps.accountManagerReportID === nextProps.accountManagerReportID && prevProps.userLeavingStatus === nextProps.userLeavingStatus && - _.isEqual(prevProps.report, nextProps.report) && prevProps.currentReportID === nextProps.currentReportID && - prevProps.viewportOffsetTop === nextProps.viewportOffsetTop, + prevProps.viewportOffsetTop === nextProps.viewportOffsetTop && + prevProps.report.lastReadTime === nextProps.report.lastReadTime && + prevProps.report.reportID === nextProps.report.reportID && + prevProps.report.policyID === nextProps.report.policyID && + prevProps.report.lastVisibleActionCreated === nextProps.report.lastVisibleActionCreated && + prevProps.report.statusNum === nextProps.report.statusNum && + prevProps.report.stateNum === nextProps.report.stateNum && + prevProps.report.writeCapability === nextProps.report.writeCapability && + prevProps.report.type === nextProps.report.type && + _.isEqual(prevProps.report.errorFields, nextProps.report.errorFields) && + prevProps.report.isPolicyExpenseChat === nextProps.report.isPolicyExpenseChat && + prevProps.report.parentReportID === nextProps.report.parentReportID && + prevProps.report.parentReportActionID === nextProps.report.parentReportActionID && + prevProps.report.chatType === nextProps.report.chatType && + _.isEqual(prevProps.report.pendingFields, nextProps.report.pendingFields) && + prevProps.report.isDeletedParentAction === nextProps.report.isDeletedParentAction && + prevProps.report.reportName === nextProps.report.reportName && + prevProps.report.description === nextProps.report.description && + prevProps.report.managerID === nextProps.report.managerID && + prevProps.report.total === nextProps.report.total && + prevProps.report.nonReimbursableTotal === nextProps.report.nonReimbursableTotal && + _.isEqual(prevProps.report.reportFields, nextProps.report.reportFields) && + prevProps.report.ownerAccountID === nextProps.report.ownerAccountID && + prevProps.report.currency === nextProps.report.currency && + _.isEqual(prevProps.report.participantAccountIDs, nextProps.report.participantAccountIDs) && + prevProps.report.isWaitingOnBankAccount === nextProps.report.isWaitingOnBankAccount && + prevProps.report.iouReportID === nextProps.report.iouReportID && + prevProps.report.isOwnPolicyExpenseChat === nextProps.report.isOwnPolicyExpenseChat && + prevProps.report.notificationPreference === nextProps.report.notificationPreference && + prevProps.report.isPinned === nextProps.report.isPinned && + prevProps.report.chatReportID === nextProps.report.chatReportID && + prevProps.report.visibility === nextProps.report.visibility && + prevProps.report.oldPolicyName === nextProps.report.oldPolicyName && + prevProps.report.policyName === nextProps.report.policyName && + prevProps.report.isOptimisticReport === nextProps.report.isOptimisticReport, ), ); diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index 62ff9426b4ae..b335ce97742f 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -314,7 +314,25 @@ function arePropsEqual(oldProps, newProps) { return false; } - return _.isEqual(oldProps.report, newProps.report); + return ( + oldProps.report.lastReadTime === newProps.report.lastReadTime && + oldProps.report.reportID === newProps.report.reportID && + oldProps.report.policyID === newProps.report.policyID && + oldProps.report.managerID === newProps.report.managerID && + oldProps.report.lastVisibleActionCreated === newProps.report.lastVisibleActionCreated && + oldProps.report.isOptimisticReport === newProps.report.isOptimisticReport && + oldProps.report.total === newProps.report.total && + oldProps.report.statusNum === newProps.report.statusNum && + oldProps.report.stateNum === newProps.report.stateNum && + oldProps.report.reportName === newProps.report.reportName && + oldProps.report.description === newProps.report.description && + oldProps.report.nonReimbursableTotal === newProps.report.nonReimbursableTotal && + oldProps.report.writeCapability === newProps.report.writeCapability && + _.isEqual(oldProps.report.pendingFields, newProps.report.pendingFields) && + _.isEqual(oldProps.report.errorFields, newProps.report.errorFields) && + _.isEqual(oldProps.report.participantAccountIDs, newProps.report.participantAccountIDs) && + _.isEqual(oldProps.report.icons, newProps.report.icons) + ); } const MemoizedReportActionsView = React.memo(ReportActionsView, arePropsEqual); From 04795f9915e39edda75f7613030c7a3bf4e5cfed Mon Sep 17 00:00:00 2001 From: hurali97 Date: Fri, 2 Feb 2024 16:15:22 +0500 Subject: [PATCH 31/36] refactor: use isEqual in favor of individual comparison --- src/pages/home/ReportScreen.js | 35 +--------------------- src/pages/home/report/ReportActionsView.js | 20 +------------ 2 files changed, 2 insertions(+), 53 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 6efa0bd0246e..bfe27910c943 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -667,39 +667,6 @@ export default compose( prevProps.userLeavingStatus === nextProps.userLeavingStatus && prevProps.currentReportID === nextProps.currentReportID && prevProps.viewportOffsetTop === nextProps.viewportOffsetTop && - prevProps.report.lastReadTime === nextProps.report.lastReadTime && - prevProps.report.reportID === nextProps.report.reportID && - prevProps.report.policyID === nextProps.report.policyID && - prevProps.report.lastVisibleActionCreated === nextProps.report.lastVisibleActionCreated && - prevProps.report.statusNum === nextProps.report.statusNum && - prevProps.report.stateNum === nextProps.report.stateNum && - prevProps.report.writeCapability === nextProps.report.writeCapability && - prevProps.report.type === nextProps.report.type && - _.isEqual(prevProps.report.errorFields, nextProps.report.errorFields) && - prevProps.report.isPolicyExpenseChat === nextProps.report.isPolicyExpenseChat && - prevProps.report.parentReportID === nextProps.report.parentReportID && - prevProps.report.parentReportActionID === nextProps.report.parentReportActionID && - prevProps.report.chatType === nextProps.report.chatType && - _.isEqual(prevProps.report.pendingFields, nextProps.report.pendingFields) && - prevProps.report.isDeletedParentAction === nextProps.report.isDeletedParentAction && - prevProps.report.reportName === nextProps.report.reportName && - prevProps.report.description === nextProps.report.description && - prevProps.report.managerID === nextProps.report.managerID && - prevProps.report.total === nextProps.report.total && - prevProps.report.nonReimbursableTotal === nextProps.report.nonReimbursableTotal && - _.isEqual(prevProps.report.reportFields, nextProps.report.reportFields) && - prevProps.report.ownerAccountID === nextProps.report.ownerAccountID && - prevProps.report.currency === nextProps.report.currency && - _.isEqual(prevProps.report.participantAccountIDs, nextProps.report.participantAccountIDs) && - prevProps.report.isWaitingOnBankAccount === nextProps.report.isWaitingOnBankAccount && - prevProps.report.iouReportID === nextProps.report.iouReportID && - prevProps.report.isOwnPolicyExpenseChat === nextProps.report.isOwnPolicyExpenseChat && - prevProps.report.notificationPreference === nextProps.report.notificationPreference && - prevProps.report.isPinned === nextProps.report.isPinned && - prevProps.report.chatReportID === nextProps.report.chatReportID && - prevProps.report.visibility === nextProps.report.visibility && - prevProps.report.oldPolicyName === nextProps.report.oldPolicyName && - prevProps.report.policyName === nextProps.report.policyName && - prevProps.report.isOptimisticReport === nextProps.report.isOptimisticReport, + _.isEqual(prevProps.report, nextProps.report), ), ); diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index b335ce97742f..62ff9426b4ae 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -314,25 +314,7 @@ function arePropsEqual(oldProps, newProps) { return false; } - return ( - oldProps.report.lastReadTime === newProps.report.lastReadTime && - oldProps.report.reportID === newProps.report.reportID && - oldProps.report.policyID === newProps.report.policyID && - oldProps.report.managerID === newProps.report.managerID && - oldProps.report.lastVisibleActionCreated === newProps.report.lastVisibleActionCreated && - oldProps.report.isOptimisticReport === newProps.report.isOptimisticReport && - oldProps.report.total === newProps.report.total && - oldProps.report.statusNum === newProps.report.statusNum && - oldProps.report.stateNum === newProps.report.stateNum && - oldProps.report.reportName === newProps.report.reportName && - oldProps.report.description === newProps.report.description && - oldProps.report.nonReimbursableTotal === newProps.report.nonReimbursableTotal && - oldProps.report.writeCapability === newProps.report.writeCapability && - _.isEqual(oldProps.report.pendingFields, newProps.report.pendingFields) && - _.isEqual(oldProps.report.errorFields, newProps.report.errorFields) && - _.isEqual(oldProps.report.participantAccountIDs, newProps.report.participantAccountIDs) && - _.isEqual(oldProps.report.icons, newProps.report.icons) - ); + return _.isEqual(oldProps.report, newProps.report); } const MemoizedReportActionsView = React.memo(ReportActionsView, arePropsEqual); From 6751c9f842e007ee32498b44ee743b2b241dbb06 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 2 Feb 2024 11:43:06 +0000 Subject: [PATCH 32/36] Update version to 1.4.35-6 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 806fd8d3efda..1042a6674374 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001043505 - versionName "1.4.35-5" + versionCode 1001043506 + versionName "1.4.35-6" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 5dc09b4564bb..4180e3e12ddf 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.35.5 + 1.4.35.6 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 7dcdc2302ec4..75718f88b236 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.35.5 + 1.4.35.6 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index fca74ce93fc0..9a22be19a03b 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.35 CFBundleVersion - 1.4.35.5 + 1.4.35.6 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 57203662f350..0716765ca3cc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.35-5", + "version": "1.4.35-6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.35-5", + "version": "1.4.35-6", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index a6971f881fd3..96293e4ea3ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.35-5", + "version": "1.4.35-6", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From ef0bf6748de9adac69935323d84aeb8a94b6cbfb Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 2 Feb 2024 11:48:50 +0000 Subject: [PATCH 33/36] Update version to 1.4.35-7 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- ios/NotificationServiceExtension/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 1042a6674374..42b24f082784 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001043506 - versionName "1.4.35-6" + versionCode 1001043507 + versionName "1.4.35-7" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 4180e3e12ddf..cb860f7944d0 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.35.6 + 1.4.35.7 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 75718f88b236..670458770c4e 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.35.6 + 1.4.35.7 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 9a22be19a03b..7fb3a7cd6c50 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -13,7 +13,7 @@ CFBundleShortVersionString 1.4.35 CFBundleVersion - 1.4.35.6 + 1.4.35.7 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 0716765ca3cc..2ce5f59e1343 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.35-6", + "version": "1.4.35-7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.35-6", + "version": "1.4.35-7", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 96293e4ea3ff..3721ecea92f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.35-6", + "version": "1.4.35-7", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 1b489fff35b8bb9047d3c0faf3fcca72d9ac373a Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Fri, 2 Feb 2024 15:16:52 +0200 Subject: [PATCH 34/36] Revert "20354 task assignees list refactor" --- src/components/OnyxProvider.tsx | 6 +- .../withCurrentUserPersonalDetails.tsx | 35 +++- src/hooks/useCurrentUserPersonalDetails.ts | 21 --- src/pages/tasks/TaskAssigneeSelectorModal.js | 175 +++++++++++------- 4 files changed, 133 insertions(+), 104 deletions(-) delete mode 100644 src/hooks/useCurrentUserPersonalDetails.ts diff --git a/src/components/OnyxProvider.tsx b/src/components/OnyxProvider.tsx index d14aec90fa10..124f3558df90 100644 --- a/src/components/OnyxProvider.tsx +++ b/src/components/OnyxProvider.tsx @@ -10,12 +10,11 @@ const [withPersonalDetails, PersonalDetailsProvider, , usePersonalDetails] = cre const [withCurrentDate, CurrentDateProvider] = createOnyxContext(ONYXKEYS.CURRENT_DATE); const [withReportActionsDrafts, ReportActionsDraftsProvider] = createOnyxContext(ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS); const [withBlockedFromConcierge, BlockedFromConciergeProvider] = createOnyxContext(ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE); -const [withBetas, BetasProvider, BetasContext, useBetas] = createOnyxContext(ONYXKEYS.BETAS); +const [withBetas, BetasProvider, BetasContext] = createOnyxContext(ONYXKEYS.BETAS); const [withReportCommentDrafts, ReportCommentDraftsProvider] = createOnyxContext(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT); const [withPreferredTheme, PreferredThemeProvider, PreferredThemeContext] = createOnyxContext(ONYXKEYS.PREFERRED_THEME); const [withFrequentlyUsedEmojis, FrequentlyUsedEmojisProvider, , useFrequentlyUsedEmojis] = createOnyxContext(ONYXKEYS.FREQUENTLY_USED_EMOJIS); const [withPreferredEmojiSkinTone, PreferredEmojiSkinToneProvider, PreferredEmojiSkinToneContext] = createOnyxContext(ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE); -const [, SessionProvider, , useSession] = createOnyxContext(ONYXKEYS.SESSION); type OnyxProviderProps = { /** Rendered child component */ @@ -36,7 +35,6 @@ function OnyxProvider(props: OnyxProviderProps) { PreferredThemeProvider, FrequentlyUsedEmojisProvider, PreferredEmojiSkinToneProvider, - SessionProvider, ]} > {props.children} @@ -61,10 +59,8 @@ export { withReportCommentDrafts, withPreferredTheme, PreferredThemeContext, - useBetas, withFrequentlyUsedEmojis, useFrequentlyUsedEmojis, withPreferredEmojiSkinTone, PreferredEmojiSkinToneContext, - useSession, }; diff --git a/src/components/withCurrentUserPersonalDetails.tsx b/src/components/withCurrentUserPersonalDetails.tsx index 313bcad74f35..9406c8634c1b 100644 --- a/src/components/withCurrentUserPersonalDetails.tsx +++ b/src/components/withCurrentUserPersonalDetails.tsx @@ -1,17 +1,26 @@ import type {ComponentType, ForwardedRef, RefAttributes} from 'react'; -import React from 'react'; -import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import React, {useMemo} from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; import getComponentDisplayName from '@libs/getComponentDisplayName'; import personalDetailsPropType from '@pages/personalDetailsPropType'; -import type {PersonalDetails} from '@src/types/onyx'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {PersonalDetails, Session} from '@src/types/onyx'; +import {usePersonalDetails} from './OnyxProvider'; type CurrentUserPersonalDetails = PersonalDetails | Record; +type OnyxProps = { + /** Session of the current user */ + session: OnyxEntry; +}; + type HOCProps = { currentUserPersonalDetails: CurrentUserPersonalDetails; }; -type WithCurrentUserPersonalDetailsProps = HOCProps; +type WithCurrentUserPersonalDetailsProps = OnyxProps & HOCProps; // TODO: remove when all components that use it will be migrated to TS const withCurrentUserPersonalDetailsPropTypes = { @@ -24,9 +33,15 @@ const withCurrentUserPersonalDetailsDefaultProps: HOCProps = { export default function ( WrappedComponent: ComponentType>, -): ComponentType & RefAttributes> { +): ComponentType & RefAttributes, keyof OnyxProps>> { function WithCurrentUserPersonalDetails(props: Omit, ref: ForwardedRef) { - const currentUserPersonalDetails = useCurrentUserPersonalDetails(); + const personalDetails = usePersonalDetails() ?? CONST.EMPTY_OBJECT; + const accountID = props.session?.accountID ?? 0; + const accountPersonalDetails = personalDetails?.[accountID]; + const currentUserPersonalDetails: CurrentUserPersonalDetails = useMemo( + () => (accountPersonalDetails ? {...accountPersonalDetails, accountID} : {}) as CurrentUserPersonalDetails, + [accountPersonalDetails, accountID], + ); return ( & RefAttributes, OnyxProps>({ + session: { + key: ONYXKEYS.SESSION, + }, + })(withCurrentUserPersonalDetails); } export {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps}; diff --git a/src/hooks/useCurrentUserPersonalDetails.ts b/src/hooks/useCurrentUserPersonalDetails.ts deleted file mode 100644 index da3c2b18bd83..000000000000 --- a/src/hooks/useCurrentUserPersonalDetails.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {useMemo} from 'react'; -import {usePersonalDetails, useSession} from '@components/OnyxProvider'; -import CONST from '@src/CONST'; -import type {PersonalDetails} from '@src/types/onyx'; - -type CurrentUserPersonalDetails = PersonalDetails | Record; - -function useCurrentUserPersonalDetails() { - const session = useSession(); - const personalDetails = usePersonalDetails() ?? CONST.EMPTY_OBJECT; - const accountID = session?.accountID ?? 0; - const accountPersonalDetails = personalDetails?.[accountID]; - const currentUserPersonalDetails: CurrentUserPersonalDetails = useMemo( - () => (accountPersonalDetails ? {...accountPersonalDetails, accountID} : {}) as CurrentUserPersonalDetails, - [accountPersonalDetails, accountID], - ); - - return currentUserPersonalDetails; -} - -export default useCurrentUserPersonalDetails; diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.js b/src/pages/tasks/TaskAssigneeSelectorModal.js index 0619fe1abf15..f3627a9bd04d 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.js +++ b/src/pages/tasks/TaskAssigneeSelectorModal.js @@ -1,19 +1,18 @@ /* eslint-disable es/no-optional-chaining */ -import {useRoute} from '@react-navigation/native'; import lodashGet from 'lodash/get'; -import lodashPick from 'lodash/pick'; import PropTypes from 'prop-types'; -import React, {useCallback, useMemo, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import {useBetas, usePersonalDetails, useSession} from '@components/OnyxProvider'; +import {usePersonalDetails} from '@components/OnyxProvider'; +import OptionsSelector from '@components/OptionsSelector'; import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; -import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; -import useDebouncedState from '@hooks/useDebouncedState'; -import useLocalize from '@hooks/useLocalize'; +import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; +import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useThemeStyles from '@hooks/useThemeStyles'; import compose from '@libs/compose'; import Navigation from '@libs/Navigation/Navigation'; @@ -26,9 +25,29 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; const propTypes = { + /** Beta features list */ + betas: PropTypes.arrayOf(PropTypes.string), + /** All reports shared with the user */ reports: PropTypes.objectOf(reportPropTypes), + /** URL Route params */ + route: PropTypes.shape({ + /** Params from the URL path */ + params: PropTypes.shape({ + /** reportID passed via route: /r/:reportID/title */ + reportID: PropTypes.string, + }), + }), + + // /** The report currently being looked at */ + // report: reportPropTypes.isRequired, + + /** Current user session */ + session: PropTypes.shape({ + email: PropTypes.string.isRequired, + }), + /** Grab the Share destination of the Task */ task: PropTypes.shape({ /** Share destination of the Task */ @@ -43,26 +62,38 @@ const propTypes = { /** The role of current user */ role: PropTypes.string, }), + + ...withLocalizePropTypes, }; const defaultProps = { + betas: [], reports: {}, + session: {}, + route: {}, task: {}, rootParentReportPolicy: {}, }; -function useOptions({reports}) { +function TaskAssigneeSelectorModal(props) { + const styles = useThemeStyles(); + const [searchValue, setSearchValue] = useState(''); + const [headerMessage, setHeaderMessage] = useState(''); + const [filteredRecentReports, setFilteredRecentReports] = useState([]); + const [filteredPersonalDetails, setFilteredPersonalDetails] = useState([]); + const [filteredUserToInvite, setFilteredUserToInvite] = useState(null); + const [filteredCurrentUserOption, setFilteredCurrentUserOption] = useState(null); + const [isLoading, setIsLoading] = React.useState(true); const allPersonalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; - const betas = useBetas(); - const [isLoading, setIsLoading] = useState(true); - const [searchValue, debouncedSearchValue, setSearchValue] = useDebouncedState(''); - const options = useMemo(() => { + const {inputCallbackRef} = useAutoFocusInput(); + + const updateOptions = useCallback(() => { const {recentReports, personalDetails, userToInvite, currentUserOption} = OptionsListUtils.getFilteredOptions( - reports, + props.reports, allPersonalDetails, - betas, - debouncedSearchValue.trim(), + props.betas, + searchValue.trim(), [], CONST.EXPENSIFY_EMAILS, false, @@ -76,56 +107,50 @@ function useOptions({reports}) { true, ); - const headerMessage = OptionsListUtils.getHeaderMessage(recentReports?.length + personalDetails?.length !== 0 || currentUserOption, Boolean(userToInvite), debouncedSearchValue); + setHeaderMessage(OptionsListUtils.getHeaderMessage(recentReports?.length + personalDetails?.length !== 0 || currentUserOption, Boolean(userToInvite), searchValue)); + setFilteredUserToInvite(userToInvite); + setFilteredRecentReports(recentReports); + setFilteredPersonalDetails(personalDetails); + setFilteredCurrentUserOption(currentUserOption); if (isLoading) { setIsLoading(false); } + }, [props, searchValue, allPersonalDetails, isLoading]); - return { - userToInvite, - recentReports, - personalDetails, - currentUserOption, - headerMessage, + useEffect(() => { + const debouncedSearch = _.debounce(updateOptions, 200); + debouncedSearch(); + return () => { + debouncedSearch.cancel(); }; - }, [debouncedSearchValue, allPersonalDetails, isLoading, betas, reports]); - - return {...options, isLoading, searchValue, debouncedSearchValue, setSearchValue}; -} - -function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { - const styles = useThemeStyles(); - const route = useRoute(); - const {translate} = useLocalize(); - const session = useSession(); - const currentUserPersonalDetails = useCurrentUserPersonalDetails(); - const {userToInvite, recentReports, personalDetails, currentUserOption, isLoading, searchValue, setSearchValue, headerMessage} = useOptions({reports, task}); + }, [updateOptions]); const onChangeText = (newSearchTerm = '') => { setSearchValue(newSearchTerm); }; const report = useMemo(() => { - if (!route.params || !route.params.reportID) { + if (!props.route.params || !props.route.params.reportID) { return null; } - if (report && !ReportUtils.isTaskReport(report)) { - Navigation.isNavigationReady().then(() => { - Navigation.dismissModal(report.reportID); - }); - } - return reports[`${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`]; - }, [reports, route]); + return props.reports[`${ONYXKEYS.COLLECTION.REPORT}${props.route.params.reportID}`]; + }, [props.reports, props.route.params]); + + if (report && !ReportUtils.isTaskReport(report)) { + Navigation.isNavigationReady().then(() => { + Navigation.dismissModal(report.reportID); + }); + } const sections = useMemo(() => { const sectionsList = []; let indexOffset = 0; - if (currentUserOption) { + if (filteredCurrentUserOption) { sectionsList.push({ - title: translate('newTaskPage.assignMe'), - data: [currentUserOption], + title: props.translate('newTaskPage.assignMe'), + data: [filteredCurrentUserOption], shouldShow: true, indexOffset, }); @@ -133,31 +158,31 @@ function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { } sectionsList.push({ - title: translate('common.recents'), - data: recentReports, - shouldShow: recentReports?.length > 0, + title: props.translate('common.recents'), + data: filteredRecentReports, + shouldShow: filteredRecentReports?.length > 0, indexOffset, }); - indexOffset += recentReports?.length; + indexOffset += filteredRecentReports?.length; sectionsList.push({ - title: translate('common.contacts'), - data: personalDetails, - shouldShow: personalDetails?.length > 0, + title: props.translate('common.contacts'), + data: filteredPersonalDetails, + shouldShow: filteredPersonalDetails?.length > 0, indexOffset, }); - indexOffset += personalDetails?.length; + indexOffset += filteredPersonalDetails?.length; - if (userToInvite) { + if (filteredUserToInvite) { sectionsList.push({ - data: [userToInvite], + data: [filteredUserToInvite], shouldShow: true, indexOffset, }); } return sectionsList; - }, [currentUserOption, personalDetails, recentReports, userToInvite, translate]); + }, [filteredCurrentUserOption, filteredPersonalDetails, filteredRecentReports, filteredUserToInvite, props]); const selectReport = useCallback( (option) => { @@ -171,22 +196,20 @@ function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { const assigneeChatReport = Task.setAssigneeValue(option.login, option.accountID, report.reportID, OptionsListUtils.isCurrentUser(option)); // Pass through the selected assignee - Task.editTaskAssignee(report, session.accountID, option.login, option.accountID, assigneeChatReport); + Task.editTaskAssignee(report, props.session.accountID, option.login, option.accountID, assigneeChatReport); } Navigation.dismissModalWithReport(report); // If there's no report, we're creating a new task } else if (option.accountID) { - Task.setAssigneeValue(option.login, option.accountID, task.shareDestination, OptionsListUtils.isCurrentUser(option)); + Task.setAssigneeValue(option.login, option.accountID, props.task.shareDestination, OptionsListUtils.isCurrentUser(option)); Navigation.goBack(ROUTES.NEW_TASK); } }, - [session.accountID, task.shareDestination, report], + [props.session.accountID, props.task.shareDestination, report], ); - const handleBackButtonPress = useCallback(() => (lodashGet(route.params, 'reportID') ? Navigation.dismissModal() : Navigation.goBack(ROUTES.NEW_TASK)), [route.params]); - const isOpen = ReportUtils.isOpenTaskReport(report); - const canModifyTask = Task.canModifyTask(report, currentUserPersonalDetails.accountID, lodashGet(rootParentReportPolicy, 'role', '')); + const canModifyTask = Task.canModifyTask(report, props.currentUserPersonalDetails.accountID, lodashGet(props.rootParentReportPolicy, 'role', '')); const isTaskNonEditable = ReportUtils.isTaskReport(report) && (!canModifyTask || !isOpen); return ( @@ -197,19 +220,21 @@ function TaskAssigneeSelectorModal({reports, task, rootParentReportPolicy}) { {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( (lodashGet(props.route.params, 'reportID') ? Navigation.dismissModal() : Navigation.goBack(ROUTES.NEW_TASK))} /> - @@ -223,13 +248,21 @@ TaskAssigneeSelectorModal.propTypes = propTypes; TaskAssigneeSelectorModal.defaultProps = defaultProps; export default compose( + withLocalize, + withCurrentUserPersonalDetails, withOnyx({ reports: { key: ONYXKEYS.COLLECTION.REPORT, }, + betas: { + key: ONYXKEYS.BETAS, + }, task: { key: ONYXKEYS.TASK, }, + session: { + key: ONYXKEYS.SESSION, + }, }), withOnyx({ rootParentReportPolicy: { @@ -238,7 +271,7 @@ export default compose( const rootParentReport = ReportUtils.getRootParentReport(report); return `${ONYXKEYS.COLLECTION.POLICY}${rootParentReport ? rootParentReport.policyID : '0'}`; }, - selector: (policy) => lodashPick(policy, ['role']), + selector: (policy) => _.pick(policy, ['role']), }, }), )(TaskAssigneeSelectorModal); From 666a26083b650c18b49edb0d1aa7802dcdd9605a Mon Sep 17 00:00:00 2001 From: Daniel Silva Date: Fri, 2 Feb 2024 15:43:00 +0100 Subject: [PATCH 35/36] setting script to run on staging and adding nonce-random-value --- web/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/index.html b/web/index.html index 49ffd0d0a62f..f0cc320926a7 100644 --- a/web/index.html +++ b/web/index.html @@ -121,16 +121,16 @@ <% if (htmlWebpackPlugin.options.isWeb) { %> - <% if (htmlWebpackPlugin.options.isProduction) { %> + <% if (htmlWebpackPlugin.options.isStaging) { %> - + <% } %> <% } %> - <% if (htmlWebpackPlugin.options.isWeb && htmlWebpackPlugin.options.isProduction) { %> + <% if (htmlWebpackPlugin.options.isWeb && htmlWebpackPlugin.options.isStaging) { %> From e6fee5f073a7e4518db429918b9dc35e6ef65e48 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 2 Feb 2024 15:04:08 +0000 Subject: [PATCH 36/36] Update version to 1.4.36-0 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 4 ++-- ios/NewExpensifyTests/Info.plist | 4 ++-- ios/NotificationServiceExtension/Info.plist | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 42b24f082784..a53c6dfb62af 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001043507 - versionName "1.4.35-7" + versionCode 1001043600 + versionName "1.4.36-0" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index cb860f7944d0..6a6a54e58c49 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.4.35 + 1.4.36 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.35.7 + 1.4.36.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 670458770c4e..763896fd45f1 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.4.35 + 1.4.36 CFBundleSignature ???? CFBundleVersion - 1.4.35.7 + 1.4.36.0 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 7fb3a7cd6c50..a4bef0847c95 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -11,9 +11,9 @@ CFBundleName $(PRODUCT_NAME) CFBundleShortVersionString - 1.4.35 + 1.4.36 CFBundleVersion - 1.4.35.7 + 1.4.36.0 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 2ce5f59e1343..674325508da5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.35-7", + "version": "1.4.36-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.35-7", + "version": "1.4.36-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 3721ecea92f7..0c1105f978c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.35-7", + "version": "1.4.36-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",