From 107f84cde8e3b3b8be70a51f79ecf8fb8201eab7 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 2 Feb 2024 15:32:38 +0100 Subject: [PATCH 001/402] implement isPolicyOwner --- src/libs/PolicyUtils.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index b6ee4ab3a353..80f23fd3c9ab 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -111,6 +111,11 @@ const isPolicyAdmin = (policy: OnyxEntry): boolean => policy?.role === C const isPolicyMember = (policyID: string, policies: Record): boolean => Object.values(policies).some((policy) => policy?.id === policyID); +/** + * Checks if the current user is an owner (creator) of the policy. + */ +const isPolicyOwner = (policy: OnyxEntry, currentUserAccountID: number): boolean => policy?.ownerAccountID === currentUserAccountID; + /** * Create an object mapping member emails to their accountIDs. Filter for members without errors, and get the login email from the personalDetail object using the accountID. * @@ -244,6 +249,7 @@ export { getCleanedTagName, isPendingDeletePolicy, isPolicyMember, + isPolicyOwner, isPaidGroupPolicy, extractPolicyIDFromPath, getPathWithoutPolicyID, From 41110392095b4762c020f66bd4baebeeb57ad171 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 2 Feb 2024 15:32:46 +0100 Subject: [PATCH 002/402] implement isReportOwner --- src/libs/ReportUtils.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 5f3efcbcdbb0..33ef7982af3c 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4679,6 +4679,10 @@ function canBeAutoReimbursed(report: OnyxEntry, policy: OnyxEntry): boolean { + return report?.ownerAccountID === currentUserPersonalDetails?.accountID; +} + export { getReportParticipantsTitle, isReportMessageAttachment, @@ -4865,6 +4869,7 @@ export { isReportFieldOfTypeTitle, isReportFieldDisabled, getAvailableReportFields, + isReportOwner, }; export type { From 52b16ceb740c3f21c4b9c3629643db1ef4b8e52b Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 2 Feb 2024 15:45:47 +0100 Subject: [PATCH 003/402] implement draft types for leave API --- src/libs/API/parameters/LeavePolicyExpenseChatParams.ts | 6 ++++++ src/libs/API/parameters/LeaveWorkspaceParams.ts | 6 ++++++ src/libs/API/parameters/index.ts | 2 ++ src/libs/API/types.ts | 5 +++++ 4 files changed, 19 insertions(+) create mode 100644 src/libs/API/parameters/LeavePolicyExpenseChatParams.ts create mode 100644 src/libs/API/parameters/LeaveWorkspaceParams.ts diff --git a/src/libs/API/parameters/LeavePolicyExpenseChatParams.ts b/src/libs/API/parameters/LeavePolicyExpenseChatParams.ts new file mode 100644 index 000000000000..665b28b9e0a2 --- /dev/null +++ b/src/libs/API/parameters/LeavePolicyExpenseChatParams.ts @@ -0,0 +1,6 @@ +type LeavePolicyExpenseChatParams = { + // TODO: Clarify + reportID: string; +}; + +export default LeavePolicyExpenseChatParams; diff --git a/src/libs/API/parameters/LeaveWorkspaceParams.ts b/src/libs/API/parameters/LeaveWorkspaceParams.ts new file mode 100644 index 000000000000..b28fa3e5aed9 --- /dev/null +++ b/src/libs/API/parameters/LeaveWorkspaceParams.ts @@ -0,0 +1,6 @@ +type LeaveWorkspaceParams = { + // TODO: Clarify + policyID: string; +}; + +export default LeaveWorkspaceParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 8c0c2fde17cf..9e877fffbd2e 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -89,7 +89,9 @@ export type {default as AddWorkspaceRoomParams} from './AddWorkspaceRoomParams'; export type {default as UpdatePolicyRoomNameParams} from './UpdatePolicyRoomNameParams'; export type {default as AddEmojiReactionParams} from './AddEmojiReactionParams'; export type {default as RemoveEmojiReactionParams} from './RemoveEmojiReactionParams'; +export type {default as LeavePolicyExpenseChatParams} from './LeavePolicyExpenseChatParams'; export type {default as LeaveRoomParams} from './LeaveRoomParams'; +export type {default as LeaveWorkspaceParams} from './LeaveWorkspaceParams'; export type {default as InviteToRoomParams} from './InviteToRoomParams'; export type {default as RemoveFromRoomParams} from './RemoveFromRoomParams'; export type {default as FlagCommentParams} from './FlagCommentParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 05b658ee0702..37ed746ea5b6 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -115,6 +115,9 @@ const WRITE_COMMANDS = { SET_NAME_VALUE_PAIR: 'SetNameValuePair', SET_REPORT_FIELD: 'Report_SetFields', SET_REPORT_NAME: 'RenameReport', + // TODO: Clarify + LEAVE_WORKSPACE: 'LeaveWorkspace', + LEAVE_POLICY_EXPENSE_CHAT: 'LeaveWorkspaceExpenseChat', } as const; type WriteCommand = ValueOf; @@ -227,6 +230,8 @@ type WriteCommandParameters = { [WRITE_COMMANDS.SET_NAME_VALUE_PAIR]: Parameters.SetNameValuePairParams; [WRITE_COMMANDS.SET_REPORT_FIELD]: Parameters.SetReportFieldParams; [WRITE_COMMANDS.SET_REPORT_NAME]: Parameters.SetReportNameParams; + [WRITE_COMMANDS.LEAVE_WORKSPACE]: Parameters.LeaveWorkspaceParams; + [WRITE_COMMANDS.LEAVE_POLICY_EXPENSE_CHAT]: Parameters.LeavePolicyExpenseChatParams; }; const READ_COMMANDS = { From 5788e867e4ebd40cde8099d19f72332206842a92 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 2 Feb 2024 15:46:04 +0100 Subject: [PATCH 004/402] implement draft for leave API --- src/libs/actions/Policy.ts | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 0c3a8afc1576..c68bd947faf9 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import {PUBLIC_DOMAINS} from 'expensify-common/lib/CONST'; import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import Str from 'expensify-common/lib/str'; @@ -14,6 +15,8 @@ import type { DeleteMembersFromWorkspaceParams, DeleteWorkspaceAvatarParams, DeleteWorkspaceParams, + LeavePolicyExpenseChatParams, + LeaveWorkspaceParams, OpenDraftWorkspaceRequestParams, OpenWorkspaceInvitePageParams, OpenWorkspaceMembersPageParams, @@ -1984,6 +1987,48 @@ function createWorkspaceFromIOUPayment(iouReport: Report): string | undefined { return policyID; } +/** + * TODO: Comment + */ +function leaveWorkspace(policyID: string) { + const optimisticData: OnyxUpdate[] = []; + const successData: OnyxUpdate[] = []; + const failureData: OnyxUpdate[] = []; + + const parameters: LeaveWorkspaceParams = { + policyID, + }; + + console.group('leaveWorkspace'); + console.log('policyID', policyID); + console.log('parameters', parameters); + console.log('{optimisticData, successData, failureData}', {optimisticData, successData, failureData}); + console.groupEnd(); + return; + API.write(WRITE_COMMANDS.LEAVE_WORKSPACE, parameters, {optimisticData, successData, failureData}); +} + +/** + * TODO: Comment + */ +function leavePolicyExpenseChat(reportID: string) { + const optimisticData: OnyxUpdate[] = []; + const successData: OnyxUpdate[] = []; + const failureData: OnyxUpdate[] = []; + + const parameters: LeavePolicyExpenseChatParams = { + reportID, + }; + + console.group('leaveWorkspace'); + console.log('reportID', reportID); + console.log('parameters', parameters); + console.log('{optimisticData, successData, failureData}', {optimisticData, successData, failureData}); + console.groupEnd(); + return; + API.write(WRITE_COMMANDS.LEAVE_POLICY_EXPENSE_CHAT, parameters, {optimisticData, successData, failureData}); +} + export { removeMembers, addMembersToWorkspace, @@ -2020,4 +2065,6 @@ export { buildOptimisticPolicyRecentlyUsedTags, createDraftInitialWorkspace, setWorkspaceInviteMessageDraft, + leaveWorkspace, + leavePolicyExpenseChat, }; From 2114adb61d998fb729101975b9a7d765355f9d57 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 2 Feb 2024 15:46:23 +0100 Subject: [PATCH 005/402] implement draft for leave a workspace chat --- src/pages/home/HeaderView.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index ca4c90b2df55..0ea2f92d3cce 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -29,10 +29,12 @@ import {getGroupChatName} from '@libs/GroupChatUtils'; import * as HeaderUtils from '@libs/HeaderUtils'; import reportWithoutHasDraftSelector from '@libs/OnyxSelectors/reportWithoutHasDraftSelector'; import * as OptionsListUtils from '@libs/OptionsListUtils'; +import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import reportPropTypes from '@pages/reportPropTypes'; import * as Link from '@userActions/Link'; +import * as Policy from '@userActions/Policy'; import * as Report from '@userActions/Report'; import * as Session from '@userActions/Session'; import * as Task from '@userActions/Task'; @@ -118,6 +120,8 @@ function HeaderView(props) { const isUserCreatedPolicyRoom = ReportUtils.isUserCreatedPolicyRoom(props.report); const isPolicyMember = useMemo(() => !_.isEmpty(props.policy), [props.policy]); const canLeaveRoom = ReportUtils.canLeaveRoom(props.report, isPolicyMember); + const canLeavePolicyExpenseChat = + isPolicyExpenseChat && !(PolicyUtils.isPolicyAdmin(props.policy) || PolicyUtils.isPolicyOwner(props.policy, props.session.accountID) || ReportUtils.isReportOwner(props.report)); const isArchivedRoom = ReportUtils.isArchivedRoom(props.report); // We hide the button when we are chatting with an automated Expensify account since it's not possible to contact @@ -156,9 +160,9 @@ function HeaderView(props) { ), ); - const canJoinOrLeave = isChatThread || isUserCreatedPolicyRoom || canLeaveRoom; + const canJoinOrLeave = isChatThread || isUserCreatedPolicyRoom || canLeaveRoom || canLeavePolicyExpenseChat; const canJoin = canJoinOrLeave && !isWhisperAction && props.report.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; - const canLeave = canJoinOrLeave && ((isChatThread && props.report.notificationPreference.length) || isUserCreatedPolicyRoom || canLeaveRoom); + const canLeave = canJoinOrLeave && ((isChatThread && props.report.notificationPreference.length) || isUserCreatedPolicyRoom || canLeaveRoom || canLeavePolicyExpenseChat); if (canJoin) { threeDotMenuItems.push({ icon: Expensicons.ChatBubbles, @@ -167,10 +171,11 @@ function HeaderView(props) { }); } else if (canLeave) { const isWorkspaceMemberLeavingWorkspaceRoom = !isChatThread && lodashGet(props.report, 'visibility', '') === CONST.REPORT.VISIBILITY.RESTRICTED && isPolicyMember; + const action = isPolicyExpenseChat ? () => Policy.leavePolicyExpenseChat(props.reportID) : () => Report.leaveRoom(props.reportID, isWorkspaceMemberLeavingWorkspaceRoom); threeDotMenuItems.push({ icon: Expensicons.ChatBubbles, text: translate('common.leave'), - onSelected: Session.checkIfActionIsAllowed(() => Report.leaveRoom(props.reportID, isWorkspaceMemberLeavingWorkspaceRoom)), + onSelected: Session.checkIfActionIsAllowed(action), }); } @@ -360,7 +365,7 @@ export default memo( }, policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, - selector: (policy) => _.pick(policy, ['name', 'avatar', 'pendingAction']), + selector: (policy) => _.pick(policy, ['name', 'avatar', 'pendingAction', 'role', 'ownerAccountID']), }, rootParentReportPolicy: { key: ({report}) => { From eb6299247215dff7c64c877273acb0f3949552aa Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 2 Feb 2024 15:46:31 +0100 Subject: [PATCH 006/402] implement draft for leave a workspace --- src/pages/workspace/WorkspacesListPage.tsx | 23 +++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index 9b763120b30d..c8e518429557 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -28,11 +28,12 @@ import * as ReportUtils from '@libs/ReportUtils'; import type {AvatarSource} from '@libs/UserUtils'; import * as App from '@userActions/App'; import * as Policy from '@userActions/Policy'; +import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; -import type {PolicyMembers, Policy as PolicyType, ReimbursementAccount, Report} from '@src/types/onyx'; +import type {PolicyMembers, Policy as PolicyType, ReimbursementAccount, Report, Session as SessionType} from '@src/types/onyx'; import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading'; @@ -74,6 +75,9 @@ type WorkspaceListPageOnyxProps = { /** All reports shared with the user (coming from Onyx) */ reports: OnyxCollection; + + /** Session info for the currently logged in user. */ + session: OnyxEntry; }; type WorkspaceListPageProps = WithPolicyAndFullscreenLoadingProps & WorkspaceListPageOnyxProps; @@ -109,7 +113,7 @@ function dismissWorkspaceError(policyID: string, pendingAction: OnyxCommon.Pendi throw new Error('Not implemented'); } -function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, reports}: WorkspaceListPageProps) { +function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, reports, session}: WorkspaceListPageProps) { const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -135,6 +139,7 @@ function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, r const getMenuItem = useCallback( ({item, index}: GetMenuItem) => { const isAdmin = item.role === CONST.POLICY.ROLE.ADMIN; + const isOwner = item.ownerAccountID === session?.accountID; // Menu options to navigate to the chat report of #admins and #announce room. // For navigation, the chat report ids may be unavailable due to the missing chat reports in Onyx. // In such cases, let us use the available chat report ids from the policy. @@ -168,6 +173,15 @@ function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, r }); } + if (!(isAdmin || isOwner)) { + threeDotsMenuItems.push({ + icon: Expensicons.ChatBubbles, + text: translate('common.leave'), + // TODO: Integrate a handler + onSelected: Session.checkIfActionIsAllowed(() => Policy.leaveWorkspace(item.policyID ?? '')), + }); + } + return ( ); }, - [isSmallScreenWidth, styles.mb3, styles.mh5, styles.ph5, styles.hoveredComponentBG, translate], + [session?.accountID, styles.ph5, styles.mh5, styles.mb3, styles.hoveredComponentBG, translate, isSmallScreenWidth], ); const listHeaderComponent = useCallback(() => { @@ -409,5 +423,8 @@ export default withPolicyAndFullscreenLoading( reports: { key: ONYXKEYS.COLLECTION.REPORT, }, + session: { + key: ONYXKEYS.SESSION, + }, })(WorkspacesListPage), ); From 3775ad084b4ed838a7b4ad32793c2d9568ecc9e1 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 2 Feb 2024 17:53:42 +0100 Subject: [PATCH 007/402] integrate draft api data --- .../AppNavigator/ReportScreenIDSetter.ts | 26 ++------- src/libs/ReportUtils.ts | 48 +++++++++++++++- src/libs/actions/Policy.ts | 56 +++++++++++++++---- src/libs/actions/Report.ts | 42 +------------- 4 files changed, 95 insertions(+), 77 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts b/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts index b4bb56262860..927e4c57d66b 100644 --- a/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts +++ b/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts @@ -7,7 +7,7 @@ import {getPolicyMembersByIdWithoutCurrentUser} from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as App from '@userActions/App'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Policy, PolicyMembers, Report, ReportMetadata} from '@src/types/onyx'; +import type {Policy, PolicyMembers, Report} from '@src/types/onyx'; import type {ReportScreenWrapperProps} from './ReportScreenWrapper'; type ReportScreenIDSetterComponentProps = { @@ -23,9 +23,6 @@ type ReportScreenIDSetterComponentProps = { /** Whether user is a new user */ isFirstTimeNewExpensifyUser: OnyxEntry; - /** The report metadata */ - reportMetadata: OnyxCollection; - /** The accountID of the current user */ accountID?: number; }; @@ -41,25 +38,15 @@ const getLastAccessedReportID = ( policies: OnyxCollection, isFirstTimeNewExpensifyUser: OnyxEntry, openOnAdminRoom: boolean, - reportMetadata: OnyxCollection, policyID?: string, policyMemberAccountIDs?: number[], ): string | undefined => { - const lastReport = ReportUtils.findLastAccessedReport( - reports, - ignoreDefaultRooms, - policies, - !!isFirstTimeNewExpensifyUser, - openOnAdminRoom, - reportMetadata, - policyID, - policyMemberAccountIDs, - ); + const lastReport = ReportUtils.findLastAccessedReport(reports, ignoreDefaultRooms, policies, !!isFirstTimeNewExpensifyUser, openOnAdminRoom, policyID, policyMemberAccountIDs); return lastReport?.reportID; }; // This wrapper is reponsible for opening the last accessed report if there is no reportID specified in the route params -function ReportScreenIDSetter({route, reports, policies, policyMembers = {}, navigation, isFirstTimeNewExpensifyUser = false, reportMetadata, accountID}: ReportScreenIDSetterProps) { +function ReportScreenIDSetter({route, reports, policies, policyMembers = {}, navigation, isFirstTimeNewExpensifyUser = false, accountID}: ReportScreenIDSetterProps) { const {canUseDefaultRooms} = usePermissions(); const {activeWorkspaceID} = useActiveWorkspace(); @@ -84,7 +71,6 @@ function ReportScreenIDSetter({route, reports, policies, policyMembers = {}, nav policies, isFirstTimeNewExpensifyUser, !!reports?.params?.openOnAdminRoom, - reportMetadata, activeWorkspaceID, policyMemberAccountIDs, ); @@ -96,7 +82,7 @@ function ReportScreenIDSetter({route, reports, policies, policyMembers = {}, nav } else { App.confirmReadyToOpenApp(); } - }, [route, navigation, reports, canUseDefaultRooms, policies, isFirstTimeNewExpensifyUser, reportMetadata, activeWorkspaceID, policyMembers, accountID]); + }, [route, navigation, reports, canUseDefaultRooms, policies, isFirstTimeNewExpensifyUser, activeWorkspaceID, policyMembers, accountID]); // The ReportScreen without the reportID set will display a skeleton // until the reportID is loaded and set in the route param @@ -122,10 +108,6 @@ export default withOnyx session?.accountID, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 33ef7982af3c..3f48f550a077 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -491,6 +491,13 @@ Onyx.connect({ }, }); +let reportMetadata: OnyxCollection = {}; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT_METADATA, + waitForCollectionCallback: true, + callback: (value) => (reportMetadata = value), +}); + function getChatType(report: OnyxEntry): ValueOf | undefined { return report?.chatType; } @@ -911,7 +918,7 @@ function filterReportsByPolicyIDAndMemberAccountIDs(reports: Report[], policyMem /** * Given an array of reports, return them sorted by the last read timestamp. */ -function sortReportsByLastRead(reports: Report[], reportMetadata: OnyxCollection): Array> { +function sortReportsByLastRead(reports: Report[]): Array> { return reports .filter((report) => !!report?.reportID && !!(reportMetadata?.[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report.reportID}`]?.lastVisitTime ?? report?.lastReadTime)) .sort((a, b) => { @@ -991,7 +998,6 @@ function findLastAccessedReport( policies: OnyxCollection, isFirstTimeNewExpensifyUser: boolean, openOnAdminRoom = false, - reportMetadata: OnyxCollection = {}, policyID?: string, policyMemberAccountIDs: number[] = [], ): OnyxEntry { @@ -1007,7 +1013,7 @@ function findLastAccessedReport( reportsValues = filterReportsByPolicyIDAndMemberAccountIDs(reportsValues, policyMemberAccountIDs, policyID); } - let sortedReports = sortReportsByLastRead(reportsValues, reportMetadata); + let sortedReports = sortReportsByLastRead(reportsValues); let adminReport: OnyxEntry | undefined; if (openOnAdminRoom) { @@ -4683,6 +4689,41 @@ function isReportOwner(report: OnyxEntry): boolean { return report?.ownerAccountID === currentUserPersonalDetails?.accountID; } +function navigateUserOnceLeaveReport(reportID: string) { + const sortedReportsByLastRead = sortReportsByLastRead(Object.values(allReports ?? {}) as Report[]); + + // We want to filter out the current report, hidden reports and empty chats + const filteredReportsByLastRead = sortedReportsByLastRead.filter( + (sortedReport) => + sortedReport?.reportID !== reportID && + sortedReport?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN && + shouldReportBeInOptionList({ + report: sortedReport, + currentReportId: '', + isInGSDMode: false, + betas: [], + policies: {}, + excludeEmptyChats: true, + doesReportHaveViolations: false, + }), + ); + const lastAccessedReportID = filteredReportsByLastRead.at(-1)?.reportID; + + if (lastAccessedReportID) { + // We should call Navigation.goBack to pop the current route first before navigating to Concierge. + Navigation.goBack(ROUTES.HOME); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID)); + } else { + const participantAccountIDs = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE]); + const chat = getChatByParticipants(participantAccountIDs); + if (chat?.reportID) { + // We should call Navigation.goBack to pop the current route first before navigating to Concierge. + Navigation.goBack(ROUTES.HOME); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(chat.reportID)); + } + } +} + export { getReportParticipantsTitle, isReportMessageAttachment, @@ -4870,6 +4911,7 @@ export { isReportFieldDisabled, getAvailableReportFields, isReportOwner, + navigateUserOnceLeaveReport, }; export type { diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index c68bd947faf9..929318ed9856 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -1991,30 +1991,60 @@ function createWorkspaceFromIOUPayment(iouReport: Report): string | undefined { * TODO: Comment */ function leaveWorkspace(policyID: string) { - const optimisticData: OnyxUpdate[] = []; - const successData: OnyxUpdate[] = []; - const failureData: OnyxUpdate[] = []; - + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + avatar: '', + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + errors: null, + }, + }, + ]; const parameters: LeaveWorkspaceParams = { policyID, }; console.group('leaveWorkspace'); console.log('policyID', policyID); - console.log('parameters', parameters); - console.log('{optimisticData, successData, failureData}', {optimisticData, successData, failureData}); + console.log('{parameters, optimisticData}', {parameters, optimisticData}); console.groupEnd(); - return; - API.write(WRITE_COMMANDS.LEAVE_WORKSPACE, parameters, {optimisticData, successData, failureData}); + + API.write(WRITE_COMMANDS.LEAVE_WORKSPACE, parameters, {optimisticData}); } /** * TODO: Comment */ function leavePolicyExpenseChat(reportID: string) { - const optimisticData: OnyxUpdate[] = []; - const successData: OnyxUpdate[] = []; - const failureData: OnyxUpdate[] = []; + const report = ReportUtils.getReport(reportID); + + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + }, + }, + ]; + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + }, + }, + ]; + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: report, + }, + ]; const parameters: LeavePolicyExpenseChatParams = { reportID, @@ -2025,8 +2055,10 @@ function leavePolicyExpenseChat(reportID: string) { console.log('parameters', parameters); console.log('{optimisticData, successData, failureData}', {optimisticData, successData, failureData}); console.groupEnd(); - return; + API.write(WRITE_COMMANDS.LEAVE_POLICY_EXPENSE_CHAT, parameters, {optimisticData, successData, failureData}); + + ReportUtils.navigateUserOnceLeaveReport(reportID); } export { diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 782cf2b174c2..27cc7a2af4a7 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -66,7 +66,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; -import type {PersonalDetails, PersonalDetailsList, PolicyReportField, RecentlyUsedReportFields, ReportActionReactions, ReportMetadata, ReportUserIsTyping} from '@src/types/onyx'; +import type {PersonalDetails, PersonalDetailsList, PolicyReportField, RecentlyUsedReportFields, ReportActionReactions, ReportUserIsTyping} from '@src/types/onyx'; import type {Decision, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; import type {NotificationPreference, WriteCapability} from '@src/types/onyx/Report'; import type Report from '@src/types/onyx/Report'; @@ -159,13 +159,6 @@ Onyx.connect({ }, }); -let reportMetadata: OnyxCollection = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT_METADATA, - waitForCollectionCallback: true, - callback: (value) => (reportMetadata = value), -}); - const allReports: OnyxCollection = {}; let conciergeChatReportID: string | undefined; const typingWatchTimers: Record = {}; @@ -2248,38 +2241,7 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal API.write(WRITE_COMMANDS.LEAVE_ROOM, parameters, {optimisticData, successData, failureData}); - const sortedReportsByLastRead = ReportUtils.sortReportsByLastRead(Object.values(allReports ?? {}) as Report[], reportMetadata); - - // We want to filter out the current report, hidden reports and empty chats - const filteredReportsByLastRead = sortedReportsByLastRead.filter( - (sortedReport) => - sortedReport?.reportID !== reportID && - sortedReport?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN && - ReportUtils.shouldReportBeInOptionList({ - report: sortedReport, - currentReportId: '', - isInGSDMode: false, - betas: [], - policies: {}, - excludeEmptyChats: true, - doesReportHaveViolations: false, - }), - ); - const lastAccessedReportID = filteredReportsByLastRead.at(-1)?.reportID; - - if (lastAccessedReportID) { - // We should call Navigation.goBack to pop the current route first before navigating to Concierge. - Navigation.goBack(ROUTES.HOME); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID)); - } else { - const participantAccountIDs = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE]); - const chat = ReportUtils.getChatByParticipants(participantAccountIDs); - if (chat?.reportID) { - // We should call Navigation.goBack to pop the current route first before navigating to Concierge. - Navigation.goBack(ROUTES.HOME); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(chat.reportID)); - } - } + ReportUtils.navigateUserOnceLeaveReport(reportID); } /** Invites people to a room */ From 95b8741eb659e4e9b83776fdc40545a523585953 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 5 Feb 2024 17:48:58 +0100 Subject: [PATCH 008/402] use real api for leaving workspaces --- .../LeavePolicyExpenseChatParams.ts | 6 - .../API/parameters/LeaveWorkspaceParams.ts | 6 - src/libs/API/parameters/index.ts | 2 - src/libs/API/types.ts | 5 - src/libs/actions/Policy.ts | 126 ++++++------------ src/pages/home/HeaderView.js | 4 +- src/pages/workspace/WorkspacesListPage.tsx | 3 +- 7 files changed, 46 insertions(+), 106 deletions(-) delete mode 100644 src/libs/API/parameters/LeavePolicyExpenseChatParams.ts delete mode 100644 src/libs/API/parameters/LeaveWorkspaceParams.ts diff --git a/src/libs/API/parameters/LeavePolicyExpenseChatParams.ts b/src/libs/API/parameters/LeavePolicyExpenseChatParams.ts deleted file mode 100644 index 665b28b9e0a2..000000000000 --- a/src/libs/API/parameters/LeavePolicyExpenseChatParams.ts +++ /dev/null @@ -1,6 +0,0 @@ -type LeavePolicyExpenseChatParams = { - // TODO: Clarify - reportID: string; -}; - -export default LeavePolicyExpenseChatParams; diff --git a/src/libs/API/parameters/LeaveWorkspaceParams.ts b/src/libs/API/parameters/LeaveWorkspaceParams.ts deleted file mode 100644 index b28fa3e5aed9..000000000000 --- a/src/libs/API/parameters/LeaveWorkspaceParams.ts +++ /dev/null @@ -1,6 +0,0 @@ -type LeaveWorkspaceParams = { - // TODO: Clarify - policyID: string; -}; - -export default LeaveWorkspaceParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index a41227a60507..b7c3dff7c342 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -90,9 +90,7 @@ export type {default as AddWorkspaceRoomParams} from './AddWorkspaceRoomParams'; export type {default as UpdatePolicyRoomNameParams} from './UpdatePolicyRoomNameParams'; export type {default as AddEmojiReactionParams} from './AddEmojiReactionParams'; export type {default as RemoveEmojiReactionParams} from './RemoveEmojiReactionParams'; -export type {default as LeavePolicyExpenseChatParams} from './LeavePolicyExpenseChatParams'; export type {default as LeaveRoomParams} from './LeaveRoomParams'; -export type {default as LeaveWorkspaceParams} from './LeaveWorkspaceParams'; export type {default as InviteToRoomParams} from './InviteToRoomParams'; export type {default as RemoveFromRoomParams} from './RemoveFromRoomParams'; export type {default as FlagCommentParams} from './FlagCommentParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index aa1f601ed575..c011fa395f0f 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -116,9 +116,6 @@ const WRITE_COMMANDS = { SET_NAME_VALUE_PAIR: 'SetNameValuePair', SET_REPORT_FIELD: 'Report_SetFields', SET_REPORT_NAME: 'RenameReport', - // TODO: Clarify - LEAVE_WORKSPACE: 'LeaveWorkspace', - LEAVE_POLICY_EXPENSE_CHAT: 'LeaveWorkspaceExpenseChat', } as const; type WriteCommand = ValueOf; @@ -232,8 +229,6 @@ type WriteCommandParameters = { [WRITE_COMMANDS.SET_NAME_VALUE_PAIR]: Parameters.SetNameValuePairParams; [WRITE_COMMANDS.SET_REPORT_FIELD]: Parameters.SetReportFieldParams; [WRITE_COMMANDS.SET_REPORT_NAME]: Parameters.SetReportNameParams; - [WRITE_COMMANDS.LEAVE_WORKSPACE]: Parameters.LeaveWorkspaceParams; - [WRITE_COMMANDS.LEAVE_POLICY_EXPENSE_CHAT]: Parameters.LeavePolicyExpenseChatParams; }; const READ_COMMANDS = { diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 929318ed9856..d718fcd1b88a 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -15,8 +15,6 @@ import type { DeleteMembersFromWorkspaceParams, DeleteWorkspaceAvatarParams, DeleteWorkspaceParams, - LeavePolicyExpenseChatParams, - LeaveWorkspaceParams, OpenDraftWorkspaceRequestParams, OpenWorkspaceInvitePageParams, OpenWorkspaceMembersPageParams, @@ -41,6 +39,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetailsList, Policy, PolicyMember, PolicyTags, RecentlyUsedCategories, RecentlyUsedTags, ReimbursementAccount, Report, ReportAction, Transaction} from '@src/types/onyx'; import type {Errors} from '@src/types/onyx/OnyxCommon'; import type {CustomUnit} from '@src/types/onyx/Policy'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; type AnnounceRoomMembersOnyxData = { @@ -354,8 +353,8 @@ function buildAnnounceRoomMembersOnyxData(policyID: string, accountIDs: number[] /** * Build optimistic data for removing users from the announcement room */ -function removeOptimisticAnnounceRoomMembers(policyID: string, accountIDs: number[]): AnnounceRoomMembersOnyxData { - const announceReport = ReportUtils.getRoom(CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, policyID); +function removeOptimisticAnnounceRoomMembers(policy: Policy | EmptyObject, accountIDs: number[]): AnnounceRoomMembersOnyxData { + const announceReport = ReportUtils.getRoom(CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, policy.id); const announceRoomMembers: AnnounceRoomMembersOnyxData = { onyxOptimisticData: [], onyxFailureData: [], @@ -367,21 +366,37 @@ function removeOptimisticAnnounceRoomMembers(policyID: string, accountIDs: numbe if (announceReport?.participantAccountIDs) { const remainUsers = announceReport.participantAccountIDs.filter((e) => !accountIDs.includes(e)); + announceRoomMembers.onyxOptimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport.reportID}`, value: { participantAccountIDs: [...remainUsers], visibleChatMemberAccountIDs: [...remainUsers], + ...(accountIDs.includes(sessionAccountID) + ? { + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + oldPolicyName: policy.name, + hasDraft: false, + } + : {}), }, }); - announceRoomMembers.onyxFailureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${announceReport.reportID}`, value: { participantAccountIDs: announceReport.participantAccountIDs, visibleChatMemberAccountIDs: announceReport.visibleChatMemberAccountIDs, + ...(accountIDs.includes(sessionAccountID) + ? { + statusNum: announceReport.statusNum, + stateNum: announceReport.stateNum, + oldPolicyName: announceReport.oldPolicyName, + hasDraft: announceReport.hasDraft, + } + : {}), }, }); } @@ -404,7 +419,7 @@ function removeMembers(accountIDs: number[], policyID: string) { const workspaceChats = ReportUtils.getWorkspaceChats(policyID, accountIDs); const optimisticClosedReportActions = workspaceChats.map(() => ReportUtils.buildOptimisticClosedReportAction(sessionEmail, policy.name, CONST.REPORT.ARCHIVE_REASON.REMOVED_FROM_POLICY)); - const announceRoomMembers = removeOptimisticAnnounceRoomMembers(policyID, accountIDs); + const announceRoomMembers = removeOptimisticAnnounceRoomMembers(policy, accountIDs); const optimisticMembersState: OnyxCollection = {}; const successMembersState: OnyxCollection = {}; @@ -507,11 +522,34 @@ function removeMembers(accountIDs: number[], policyID: string) { }); }); + if (accountIDs.includes(sessionAccountID)) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + }, + }); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + value: { + pendingAction: policy.pendingAction, + }, + }); + } + const params: DeleteMembersFromWorkspaceParams = { emailList: accountIDs.map((accountID) => allPersonalDetails?.[accountID]?.login).join(','), policyID, }; + console.log('WRITE_COMMANDS.DELETE_MEMBERS_FROM_WORKSPACE, params, {optimisticData, successData, failureData}', WRITE_COMMANDS.DELETE_MEMBERS_FROM_WORKSPACE, params, { + optimisticData, + successData, + failureData, + }); + API.write(WRITE_COMMANDS.DELETE_MEMBERS_FROM_WORKSPACE, params, {optimisticData, successData, failureData}); } @@ -1987,80 +2025,6 @@ function createWorkspaceFromIOUPayment(iouReport: Report): string | undefined { return policyID; } -/** - * TODO: Comment - */ -function leaveWorkspace(policyID: string) { - const optimisticData: OnyxUpdate[] = [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - value: { - avatar: '', - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, - errors: null, - }, - }, - ]; - const parameters: LeaveWorkspaceParams = { - policyID, - }; - - console.group('leaveWorkspace'); - console.log('policyID', policyID); - console.log('{parameters, optimisticData}', {parameters, optimisticData}); - console.groupEnd(); - - API.write(WRITE_COMMANDS.LEAVE_WORKSPACE, parameters, {optimisticData}); -} - -/** - * TODO: Comment - */ -function leavePolicyExpenseChat(reportID: string) { - const report = ReportUtils.getReport(reportID); - - const optimisticData: OnyxUpdate[] = [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - value: { - notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, - }, - }, - ]; - const successData: OnyxUpdate[] = [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - value: { - notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, - }, - }, - ]; - const failureData: OnyxUpdate[] = [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, - value: report, - }, - ]; - - const parameters: LeavePolicyExpenseChatParams = { - reportID, - }; - - console.group('leaveWorkspace'); - console.log('reportID', reportID); - console.log('parameters', parameters); - console.log('{optimisticData, successData, failureData}', {optimisticData, successData, failureData}); - console.groupEnd(); - - API.write(WRITE_COMMANDS.LEAVE_POLICY_EXPENSE_CHAT, parameters, {optimisticData, successData, failureData}); - - ReportUtils.navigateUserOnceLeaveReport(reportID); -} - export { removeMembers, addMembersToWorkspace, @@ -2097,6 +2061,4 @@ export { buildOptimisticPolicyRecentlyUsedTags, createDraftInitialWorkspace, setWorkspaceInviteMessageDraft, - leaveWorkspace, - leavePolicyExpenseChat, }; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index e957c70ed5cc..9cd78b47271b 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -34,7 +34,6 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import reportPropTypes from '@pages/reportPropTypes'; import * as Link from '@userActions/Link'; -import * as Policy from '@userActions/Policy'; import * as Report from '@userActions/Report'; import * as Session from '@userActions/Session'; import * as Task from '@userActions/Task'; @@ -164,11 +163,10 @@ function HeaderView(props) { }); } else if (canLeave) { const isWorkspaceMemberLeavingWorkspaceRoom = !isChatThread && lodashGet(props.report, 'visibility', '') === CONST.REPORT.VISIBILITY.RESTRICTED && isPolicyMember; - const action = isPolicyExpenseChat ? () => Policy.leavePolicyExpenseChat(props.reportID) : () => Report.leaveRoom(props.reportID, isWorkspaceMemberLeavingWorkspaceRoom); threeDotMenuItems.push({ icon: Expensicons.ChatBubbles, text: translate('common.leave'), - onSelected: Session.checkIfActionIsAllowed(action), + onSelected: Session.checkIfActionIsAllowed(() => Report.leaveRoom(props.reportID, isWorkspaceMemberLeavingWorkspaceRoom)), }); } diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index c8e518429557..bda81eee0011 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -177,8 +177,7 @@ function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, r threeDotsMenuItems.push({ icon: Expensicons.ChatBubbles, text: translate('common.leave'), - // TODO: Integrate a handler - onSelected: Session.checkIfActionIsAllowed(() => Policy.leaveWorkspace(item.policyID ?? '')), + onSelected: Session.checkIfActionIsAllowed(() => Policy.removeMembers([session?.accountID ?? 0], item.policyID ?? '')), }); } From af8c733a9e824b07f3accc4131994fc4a0f579fe Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 5 Feb 2024 17:51:55 +0100 Subject: [PATCH 009/402] Revert "integrate draft api data" This reverts commit 3775ad084b4ed838a7b4ad32793c2d9568ecc9e1. --- .../AppNavigator/ReportScreenIDSetter.ts | 26 ++++++++-- src/libs/ReportUtils.ts | 48 ++----------------- src/libs/actions/Report.ts | 42 +++++++++++++++- 3 files changed, 65 insertions(+), 51 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts b/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts index 927e4c57d66b..b4bb56262860 100644 --- a/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts +++ b/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.ts @@ -7,7 +7,7 @@ import {getPolicyMembersByIdWithoutCurrentUser} from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as App from '@userActions/App'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Policy, PolicyMembers, Report} from '@src/types/onyx'; +import type {Policy, PolicyMembers, Report, ReportMetadata} from '@src/types/onyx'; import type {ReportScreenWrapperProps} from './ReportScreenWrapper'; type ReportScreenIDSetterComponentProps = { @@ -23,6 +23,9 @@ type ReportScreenIDSetterComponentProps = { /** Whether user is a new user */ isFirstTimeNewExpensifyUser: OnyxEntry; + /** The report metadata */ + reportMetadata: OnyxCollection; + /** The accountID of the current user */ accountID?: number; }; @@ -38,15 +41,25 @@ const getLastAccessedReportID = ( policies: OnyxCollection, isFirstTimeNewExpensifyUser: OnyxEntry, openOnAdminRoom: boolean, + reportMetadata: OnyxCollection, policyID?: string, policyMemberAccountIDs?: number[], ): string | undefined => { - const lastReport = ReportUtils.findLastAccessedReport(reports, ignoreDefaultRooms, policies, !!isFirstTimeNewExpensifyUser, openOnAdminRoom, policyID, policyMemberAccountIDs); + const lastReport = ReportUtils.findLastAccessedReport( + reports, + ignoreDefaultRooms, + policies, + !!isFirstTimeNewExpensifyUser, + openOnAdminRoom, + reportMetadata, + policyID, + policyMemberAccountIDs, + ); return lastReport?.reportID; }; // This wrapper is reponsible for opening the last accessed report if there is no reportID specified in the route params -function ReportScreenIDSetter({route, reports, policies, policyMembers = {}, navigation, isFirstTimeNewExpensifyUser = false, accountID}: ReportScreenIDSetterProps) { +function ReportScreenIDSetter({route, reports, policies, policyMembers = {}, navigation, isFirstTimeNewExpensifyUser = false, reportMetadata, accountID}: ReportScreenIDSetterProps) { const {canUseDefaultRooms} = usePermissions(); const {activeWorkspaceID} = useActiveWorkspace(); @@ -71,6 +84,7 @@ function ReportScreenIDSetter({route, reports, policies, policyMembers = {}, nav policies, isFirstTimeNewExpensifyUser, !!reports?.params?.openOnAdminRoom, + reportMetadata, activeWorkspaceID, policyMemberAccountIDs, ); @@ -82,7 +96,7 @@ function ReportScreenIDSetter({route, reports, policies, policyMembers = {}, nav } else { App.confirmReadyToOpenApp(); } - }, [route, navigation, reports, canUseDefaultRooms, policies, isFirstTimeNewExpensifyUser, activeWorkspaceID, policyMembers, accountID]); + }, [route, navigation, reports, canUseDefaultRooms, policies, isFirstTimeNewExpensifyUser, reportMetadata, activeWorkspaceID, policyMembers, accountID]); // The ReportScreen without the reportID set will display a skeleton // until the reportID is loaded and set in the route param @@ -108,6 +122,10 @@ export default withOnyx session?.accountID, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 045ed1d6a1e2..7594d9db0fdd 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -503,13 +503,6 @@ Onyx.connect({ }, }); -let reportMetadata: OnyxCollection = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.REPORT_METADATA, - waitForCollectionCallback: true, - callback: (value) => (reportMetadata = value), -}); - function getChatType(report: OnyxEntry): ValueOf | undefined { return report?.chatType; } @@ -930,7 +923,7 @@ function filterReportsByPolicyIDAndMemberAccountIDs(reports: Report[], policyMem /** * Given an array of reports, return them sorted by the last read timestamp. */ -function sortReportsByLastRead(reports: Report[]): Array> { +function sortReportsByLastRead(reports: Report[], reportMetadata: OnyxCollection): Array> { return reports .filter((report) => !!report?.reportID && !!(reportMetadata?.[`${ONYXKEYS.COLLECTION.REPORT_METADATA}${report.reportID}`]?.lastVisitTime ?? report?.lastReadTime)) .sort((a, b) => { @@ -1010,6 +1003,7 @@ function findLastAccessedReport( policies: OnyxCollection, isFirstTimeNewExpensifyUser: boolean, openOnAdminRoom = false, + reportMetadata: OnyxCollection = {}, policyID?: string, policyMemberAccountIDs: number[] = [], ): OnyxEntry { @@ -1025,7 +1019,7 @@ function findLastAccessedReport( reportsValues = filterReportsByPolicyIDAndMemberAccountIDs(reportsValues, policyMemberAccountIDs, policyID); } - let sortedReports = sortReportsByLastRead(reportsValues); + let sortedReports = sortReportsByLastRead(reportsValues, reportMetadata); let adminReport: OnyxEntry | undefined; if (openOnAdminRoom) { @@ -4771,41 +4765,6 @@ function isReportOwner(report: OnyxEntry): boolean { return report?.ownerAccountID === currentUserPersonalDetails?.accountID; } -function navigateUserOnceLeaveReport(reportID: string) { - const sortedReportsByLastRead = sortReportsByLastRead(Object.values(allReports ?? {}) as Report[]); - - // We want to filter out the current report, hidden reports and empty chats - const filteredReportsByLastRead = sortedReportsByLastRead.filter( - (sortedReport) => - sortedReport?.reportID !== reportID && - sortedReport?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN && - shouldReportBeInOptionList({ - report: sortedReport, - currentReportId: '', - isInGSDMode: false, - betas: [], - policies: {}, - excludeEmptyChats: true, - doesReportHaveViolations: false, - }), - ); - const lastAccessedReportID = filteredReportsByLastRead.at(-1)?.reportID; - - if (lastAccessedReportID) { - // We should call Navigation.goBack to pop the current route first before navigating to Concierge. - Navigation.goBack(ROUTES.HOME); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID)); - } else { - const participantAccountIDs = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE]); - const chat = getChatByParticipants(participantAccountIDs); - if (chat?.reportID) { - // We should call Navigation.goBack to pop the current route first before navigating to Concierge. - Navigation.goBack(ROUTES.HOME); - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(chat.reportID)); - } - } -} - export { getReportParticipantsTitle, isReportMessageAttachment, @@ -4994,7 +4953,6 @@ export { isReportFieldDisabled, getAvailableReportFields, isReportOwner, - navigateUserOnceLeaveReport, getAllAncestorReportActionIDs, }; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index c07b330b5a68..4bff826ceb3a 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -66,7 +66,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; -import type {PersonalDetails, PersonalDetailsList, PolicyReportField, RecentlyUsedReportFields, ReportActionReactions, ReportUserIsTyping} from '@src/types/onyx'; +import type {PersonalDetails, PersonalDetailsList, PolicyReportField, RecentlyUsedReportFields, ReportActionReactions, ReportMetadata, ReportUserIsTyping} from '@src/types/onyx'; import type {Decision, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; import type {NotificationPreference, WriteCapability} from '@src/types/onyx/Report'; import type Report from '@src/types/onyx/Report'; @@ -159,6 +159,13 @@ Onyx.connect({ }, }); +let reportMetadata: OnyxCollection = {}; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.REPORT_METADATA, + waitForCollectionCallback: true, + callback: (value) => (reportMetadata = value), +}); + const allReports: OnyxCollection = {}; let conciergeChatReportID: string | undefined; const typingWatchTimers: Record = {}; @@ -2241,7 +2248,38 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal API.write(WRITE_COMMANDS.LEAVE_ROOM, parameters, {optimisticData, successData, failureData}); - ReportUtils.navigateUserOnceLeaveReport(reportID); + const sortedReportsByLastRead = ReportUtils.sortReportsByLastRead(Object.values(allReports ?? {}) as Report[], reportMetadata); + + // We want to filter out the current report, hidden reports and empty chats + const filteredReportsByLastRead = sortedReportsByLastRead.filter( + (sortedReport) => + sortedReport?.reportID !== reportID && + sortedReport?.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN && + ReportUtils.shouldReportBeInOptionList({ + report: sortedReport, + currentReportId: '', + isInGSDMode: false, + betas: [], + policies: {}, + excludeEmptyChats: true, + doesReportHaveViolations: false, + }), + ); + const lastAccessedReportID = filteredReportsByLastRead.at(-1)?.reportID; + + if (lastAccessedReportID) { + // We should call Navigation.goBack to pop the current route first before navigating to Concierge. + Navigation.goBack(ROUTES.HOME); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(lastAccessedReportID)); + } else { + const participantAccountIDs = PersonalDetailsUtils.getAccountIDsByLogins([CONST.EMAIL.CONCIERGE]); + const chat = ReportUtils.getChatByParticipants(participantAccountIDs); + if (chat?.reportID) { + // We should call Navigation.goBack to pop the current route first before navigating to Concierge. + Navigation.goBack(ROUTES.HOME); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(chat.reportID)); + } + } } /** Invites people to a room */ From 8a3473f35c8ed37cef7ab45dbeed45467d32c04e Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 5 Feb 2024 17:54:11 +0100 Subject: [PATCH 010/402] minor fix --- src/libs/actions/Policy.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index d718fcd1b88a..d012fba90ef0 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ import {PUBLIC_DOMAINS} from 'expensify-common/lib/CONST'; import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import Str from 'expensify-common/lib/str'; @@ -39,7 +38,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetailsList, Policy, PolicyMember, PolicyTags, RecentlyUsedCategories, RecentlyUsedTags, ReimbursementAccount, Report, ReportAction, Transaction} from '@src/types/onyx'; import type {Errors} from '@src/types/onyx/OnyxCommon'; import type {CustomUnit} from '@src/types/onyx/Policy'; -import type {EmptyObject} from '@src/types/utils/EmptyObject'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; type AnnounceRoomMembersOnyxData = { @@ -353,8 +351,8 @@ function buildAnnounceRoomMembersOnyxData(policyID: string, accountIDs: number[] /** * Build optimistic data for removing users from the announcement room */ -function removeOptimisticAnnounceRoomMembers(policy: Policy | EmptyObject, accountIDs: number[]): AnnounceRoomMembersOnyxData { - const announceReport = ReportUtils.getRoom(CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, policy.id); +function removeOptimisticAnnounceRoomMembers(policyID: string, policyName: string, accountIDs: number[]): AnnounceRoomMembersOnyxData { + const announceReport = ReportUtils.getRoom(CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, policyID); const announceRoomMembers: AnnounceRoomMembersOnyxData = { onyxOptimisticData: [], onyxFailureData: [], @@ -377,7 +375,7 @@ function removeOptimisticAnnounceRoomMembers(policy: Policy | EmptyObject, accou ? { statusNum: CONST.REPORT.STATUS_NUM.CLOSED, stateNum: CONST.REPORT.STATE_NUM.APPROVED, - oldPolicyName: policy.name, + oldPolicyName: policyName, hasDraft: false, } : {}), @@ -419,7 +417,7 @@ function removeMembers(accountIDs: number[], policyID: string) { const workspaceChats = ReportUtils.getWorkspaceChats(policyID, accountIDs); const optimisticClosedReportActions = workspaceChats.map(() => ReportUtils.buildOptimisticClosedReportAction(sessionEmail, policy.name, CONST.REPORT.ARCHIVE_REASON.REMOVED_FROM_POLICY)); - const announceRoomMembers = removeOptimisticAnnounceRoomMembers(policy, accountIDs); + const announceRoomMembers = removeOptimisticAnnounceRoomMembers(policy.id, policy.name, accountIDs); const optimisticMembersState: OnyxCollection = {}; const successMembersState: OnyxCollection = {}; @@ -544,12 +542,6 @@ function removeMembers(accountIDs: number[], policyID: string) { policyID, }; - console.log('WRITE_COMMANDS.DELETE_MEMBERS_FROM_WORKSPACE, params, {optimisticData, successData, failureData}', WRITE_COMMANDS.DELETE_MEMBERS_FROM_WORKSPACE, params, { - optimisticData, - successData, - failureData, - }); - API.write(WRITE_COMMANDS.DELETE_MEMBERS_FROM_WORKSPACE, params, {optimisticData, successData, failureData}); } From 0ce1db13f56356cba7434de0603a1e0601c7b156 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 6 Feb 2024 15:28:32 +0100 Subject: [PATCH 011/402] move button to top --- src/pages/workspace/WorkspacesListPage.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pages/workspace/WorkspacesListPage.tsx b/src/pages/workspace/WorkspacesListPage.tsx index bda81eee0011..b51e14adbe9e 100755 --- a/src/pages/workspace/WorkspacesListPage.tsx +++ b/src/pages/workspace/WorkspacesListPage.tsx @@ -157,6 +157,14 @@ function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, r }); } + if (!(isAdmin || isOwner)) { + threeDotsMenuItems.push({ + icon: Expensicons.ChatBubbles, + text: translate('common.leave'), + onSelected: Session.checkIfActionIsAllowed(() => Policy.removeMembers([session?.accountID ?? 0], item.policyID ?? '')), + }); + } + if (isAdmin && item.adminRoom) { threeDotsMenuItems.push({ icon: Expensicons.Hashtag, @@ -173,14 +181,6 @@ function WorkspacesListPage({policies, allPolicyMembers, reimbursementAccount, r }); } - if (!(isAdmin || isOwner)) { - threeDotsMenuItems.push({ - icon: Expensicons.ChatBubbles, - text: translate('common.leave'), - onSelected: Session.checkIfActionIsAllowed(() => Policy.removeMembers([session?.accountID ?? 0], item.policyID ?? '')), - }); - } - return ( Date: Thu, 22 Feb 2024 11:04:54 +0700 Subject: [PATCH 012/402] add can edit billable --- .../ReportActionItem/MoneyRequestView.tsx | 2 + src/components/Switch.tsx | 6 ++- src/libs/ReportUtils.ts | 42 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index d3c86698f910..b34a4c5a7365 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -125,6 +125,7 @@ function MoneyRequestView({ const canEditDate = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.DATE); const canEditReceipt = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.RECEIPT); const canEditDistance = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.DISTANCE); + const canEditBillable = ReportUtils.canEditBillable(parentReportAction); // A flag for verifying that the current report is a sub-report of a workspace chat // if the policy of the report is either Collect or Control, then this report must be tied to workspace chat @@ -427,6 +428,7 @@ function MoneyRequestView({ accessibilityLabel={translate('common.billable')} isOn={!!transactionBillable} onToggle={saveBillable} + disabled={!canEditBillable} /> )} diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx index fd9d9ae315ff..9a5ee1d7a6ea 100644 --- a/src/components/Switch.tsx +++ b/src/components/Switch.tsx @@ -14,6 +14,8 @@ type SwitchProps = { /** Accessibility label for the switch */ accessibilityLabel: string; + + disabled?: boolean; }; const OFFSET_X = { @@ -21,7 +23,7 @@ const OFFSET_X = { ON: 20, }; -function Switch({isOn, onToggle, accessibilityLabel}: SwitchProps) { +function Switch({isOn, onToggle, accessibilityLabel, disabled}: SwitchProps) { const styles = useThemeStyles(); const offsetX = useRef(new Animated.Value(isOn ? OFFSET_X.ON : OFFSET_X.OFF)); @@ -35,7 +37,7 @@ function Switch({isOn, onToggle, accessibilityLabel}: SwitchProps) { return ( onToggle(!isOn)} onLongPress={() => onToggle(!isOn)} role={CONST.ROLE.SWITCH} diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 05e2db66d629..45056c22a44d 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2147,6 +2147,47 @@ function canEditMoneyRequest(reportAction: OnyxEntry): boolean { return !isReportApproved(moneyRequestReport) && !isSettled(moneyRequestReport?.reportID) && isRequestor; } +function canEditBillable(reportAction: OnyxEntry): boolean { + const isDeleted = ReportActionsUtils.isDeletedAction(reportAction); + + if (isDeleted) { + return false; + } + + // If the report action is not IOU type, return true early + if (reportAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { + return true; + } + + if (reportAction.originalMessage.type !== CONST.IOU.REPORT_ACTION_TYPE.CREATE) { + return false; + } + + const moneyRequestReportID = reportAction?.originalMessage?.IOUReportID ?? 0; + + if (!moneyRequestReportID) { + return false; + } + + const moneyRequestReport = getReport(String(moneyRequestReportID)); + const isRequestor = currentUserAccountID === reportAction?.actorAccountID; + + if (isIOUReport(moneyRequestReport)) { + return isProcessingReport(moneyRequestReport) && isRequestor; + } + + const policy = getPolicy(moneyRequestReport?.policyID ?? ''); + const isAdmin = policy.role === CONST.POLICY.ROLE.ADMIN; + const isManager = currentUserAccountID === moneyRequestReport?.managerID; + + // Admin & managers can always edit coding fields such as tag, category, billable, etc. As long as the report has a state higher than OPEN. + if ((isAdmin || isManager) && !isDraftExpenseReport(moneyRequestReport)) { + return true; + } + + return isRequestor; +} + /** * Checks if the current user can edit the provided property of a money request * @@ -5217,6 +5258,7 @@ export { getAllAncestorReportActionIDs, canEditPolicyDescription, getPolicyDescriptionText, + canEditBillable, }; export type { From 7e15f959f533d797ede647823507e0d676a31054 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 22 Feb 2024 11:27:53 +0700 Subject: [PATCH 013/402] handle interactive for switch --- .../ReportActionItem/MoneyRequestView.tsx | 2 +- src/components/Switch.tsx | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index b34a4c5a7365..5d9973a0db59 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -428,7 +428,7 @@ function MoneyRequestView({ accessibilityLabel={translate('common.billable')} isOn={!!transactionBillable} onToggle={saveBillable} - disabled={!canEditBillable} + interactive={canEditBillable} /> )} diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx index 9a5ee1d7a6ea..4fbca927c95f 100644 --- a/src/components/Switch.tsx +++ b/src/components/Switch.tsx @@ -15,7 +15,8 @@ type SwitchProps = { /** Accessibility label for the switch */ accessibilityLabel: string; - disabled?: boolean; + /** Whether the menu item should be interactive at all */ + interactive?: boolean; }; const OFFSET_X = { @@ -23,7 +24,7 @@ const OFFSET_X = { ON: 20, }; -function Switch({isOn, onToggle, accessibilityLabel, disabled}: SwitchProps) { +function Switch({isOn, onToggle, accessibilityLabel, interactive = true}: SwitchProps) { const styles = useThemeStyles(); const offsetX = useRef(new Animated.Value(isOn ? OFFSET_X.ON : OFFSET_X.OFF)); @@ -35,11 +36,19 @@ function Switch({isOn, onToggle, accessibilityLabel, disabled}: SwitchProps) { }).start(); }, [isOn]); + const onPressOrLongPressAction = () => { + if (!interactive) { + return; + } + + onToggle(!isOn); + } + return ( onToggle(!isOn)} - onLongPress={() => onToggle(!isOn)} + style={[styles.switchTrack, !isOn && styles.switchInactive && styles.cursorDefault, !interactive && styles.cursorDefault]} + onPress={onPressOrLongPressAction} + onLongPress={onPressOrLongPressAction} role={CONST.ROLE.SWITCH} aria-checked={isOn} accessibilityLabel={accessibilityLabel} From 05764aafc0359e05ff1ae913032bcd06cae3ce33 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Thu, 22 Feb 2024 11:46:54 +0700 Subject: [PATCH 014/402] run prettier --- src/components/Switch.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx index 4fbca927c95f..ceec4016a0c5 100644 --- a/src/components/Switch.tsx +++ b/src/components/Switch.tsx @@ -42,7 +42,7 @@ function Switch({isOn, onToggle, accessibilityLabel, interactive = true}: Switch } onToggle(!isOn); - } + }; return ( Date: Sun, 25 Feb 2024 15:20:43 +0530 Subject: [PATCH 015/402] Convert to typescript --- ...aryForRefactorRequestConfirmationList.tsx} | 201 +++++++++++++----- 1 file changed, 153 insertions(+), 48 deletions(-) rename src/components/{MoneyTemporaryForRefactorRequestConfirmationList.js => MoneyTemporaryForRefactorRequestConfirmationList.tsx} (88%) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx similarity index 88% rename from src/components/MoneyTemporaryForRefactorRequestConfirmationList.js rename to src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index 1c0f58e706a4..371cbb192fd5 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -1,16 +1,20 @@ import {useIsFocused} from '@react-navigation/native'; import {format} from 'date-fns'; -import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react'; +import type {PersonalDetails, Policy, PolicyCategories, PolicyTags, Session, Transaction} from '@src/types/onyx'; import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; +import { withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import type { PolicyTaxRate } from '@src/types/onyx/PolicyTaxRates'; +import type { Participant } from '@src/types/onyx/IOU'; +import type { ValueOf } from 'type-fest'; import _ from 'underscore'; +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import DistanceRequestUtils from '@libs/DistanceRequestUtils'; import * as IOUUtils from '@libs/IOUUtils'; @@ -27,6 +31,7 @@ import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type Route from '@src/ROUTES' import Button from './Button'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import categoryPropTypes from './categoryPropTypes'; @@ -46,6 +51,7 @@ import Text from './Text'; import transactionPropTypes from './transactionPropTypes'; import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from './withCurrentUserPersonalDetails'; + const propTypes = { /** Callback to inform parent modal of success */ onConfirm: PropTypes.func, @@ -204,6 +210,110 @@ const defaultProps = { policyTaxRates: {}, }; + +type DropdownOption = { + value: PaymentType; + text: string; + icon: IconAsset; + iconWidth?: number; + iconHeight?: number; + iconDescription?: string; +}; + +type MoneyTemporaryForRefactorRequestConfirmationListProps = { + bankAccountRoute?: Route, + + canModifyParticipants: boolean, + + currentUserPersonalDetails: OnyxEntry, + + + hasMultipleParticipants: boolean, + + hasSmartScanFailed: boolean, + + iouAmount: number, + + iouCategory: string, + + iouComment: string, + + iouCreated: string, + + iouCurrencyCode: string, + + iouIsBillable: boolean, + + iouMerchant: string, + + iouTag: string, + + iouType: ValueOf, + + isDistanceRequest: boolean, + + isEditingSplitBill: boolean, + + isPolicyExpenseChat: boolean, + + isReadOnly: boolean, + + isScanRequest: boolean, + + listStyles: Record | Array>, + + mileageRate: { + /** Unit used to represent distance */ + unit: typeof CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES | typeof CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS; + + /** Rate used to calculate the distance request amount */ + rate: number; + + /** The currency of the rate */ + currency: string; + }; + + onConfirm: () => void, + + onSelectParticipant: (option: string) => void, + + onSendMoney: (paymentMethod: string) => void, + + onToggleBillable: () => void, + + policyCategories: OnyxEntry, + + policyID: string, + + policyTags: OnyxEntry, + + receiptFilename: string, + + receiptPath: string, + + reportID: string, + + session: Session, + + shouldShowSmartScanFields: boolean, + + transaction: Transaction, + + policyTaxRates: PolicyTaxRate, + + reportActionID: string, + + policy: OnyxEntry + + + + + + + +} + + function MoneyTemporaryForRefactorRequestConfirmationList({ bankAccountRoute, canModifyParticipants, @@ -244,7 +354,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ shouldShowSmartScanFields, transaction, policyTaxRates, -}) { +}: MoneyTemporaryForRefactorRequestConfirmationListProps) { const theme = useTheme(); const styles = useThemeStyles(); const {translate, toLocaleDigit} = useLocalize(); @@ -255,12 +365,11 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const isTypeSend = iouType === CONST.IOU.TYPE.SEND; const {unit, rate, currency} = mileageRate; - const distance = lodashGet(transaction, 'routes.route0.distance', 0); + const distance = transaction?.routes?.route0?.distance ?? 0; const shouldCalculateDistanceAmount = isDistanceRequest && iouAmount === 0; // A flag for showing the categories field - const shouldShowCategories = isPolicyExpenseChat && (iouCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories))); - + const shouldShowCategories = isPolicyExpenseChat && (iouCategory || (policyCategories && OptionsListUtils.hasEnabledOptions(Object.values(policyCategories)))); // A flag and a toggler for showing the rest of the form fields const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); @@ -272,17 +381,18 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ // Fetches the first tag list of the policy const policyTag = PolicyUtils.getTag(policyTags); - const policyTagList = lodashGet(policyTag, 'tags', {}); - const policyTagListName = lodashGet(policyTag, 'name', translate('common.tag')); + const policyTagList = policyTags?.tags ?? {}; + + const policyTagListName = policyTag?.name ?? translate('common.tag'); // A flag for showing the tags field - const shouldShowTags = isPolicyExpenseChat && OptionsListUtils.hasEnabledOptions(_.values(policyTagList)); + const shouldShowTags = isPolicyExpenseChat && (policyTagList && OptionsListUtils.hasEnabledOptions(Object.values(policyTagList))); // A flag for showing tax rate - const shouldShowTax = isPolicyExpenseChat && policy && policy.isTaxTrackingEnabled; + const shouldShowTax = isPolicyExpenseChat && policy?.isTaxTrackingEnabled; // A flag for showing the billable field - const shouldShowBillable = !lodashGet(policy, 'disabledFields.defaultBillable', true); + const shouldShowBillable = !(policy?.disabledFields?.defaultBillable ?? true); const hasRoute = TransactionUtils.hasRoute(transaction); const isDistanceRequestWithPendingRoute = isDistanceRequest && (!hasRoute || !rate); @@ -294,9 +404,11 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ ); const formattedTaxAmount = CurrencyUtils.convertToDisplayString(transaction.taxAmount, iouCurrencyCode); - const defaultTaxKey = policyTaxRates.defaultExternalID; - const defaultTaxName = (defaultTaxKey && `${policyTaxRates.taxes[defaultTaxKey].name} (${policyTaxRates.taxes[defaultTaxKey].value}) • ${translate('common.default')}`) || ''; - const taxRateTitle = (transaction.taxRate && transaction.taxRate.text) || defaultTaxName; + const defaultTaxKey = policyTaxRates?.defaultExternalID; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const defaultTaxName = (defaultTaxKey && `${policyTaxRates?.taxes[defaultTaxKey].name} (${policyTaxRates.taxes[defaultTaxKey].value}) • ${translate('common.default')}`) || ''; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const taxRateTitle = (transaction?.taxRate?.text) || defaultTaxName; const isFocused = useIsFocused(); const [formError, setFormError] = useState(''); @@ -317,8 +429,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const isMerchantEmpty = !iouMerchant || iouMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; const isMerchantRequired = isPolicyExpenseChat && !isScanRequest && shouldShowMerchant; - const isCategoryRequired = canUseViolations && lodashGet(policy, 'requiresCategory', false); - const isTagRequired = canUseViolations && lodashGet(policy, 'requiresTag', false); + const isCategoryRequired = canUseViolations && (policy?.requiresCategory ?? false); + const isTagRequired = canUseViolations && (policy?.requiresTag ?? false); useEffect(() => { if ((!isMerchantRequired && isMerchantEmpty) || !merchantError) { @@ -364,7 +476,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ * @returns {Array} */ const getParticipantsWithAmount = useCallback( - (participantsList) => { + (participantsList: Participant[]) => { const amount = IOUUtils.calculateAmount(participantsList.length, iouAmount, iouCurrencyCode); return OptionsListUtils.getIOUConfirmationOptionsFromParticipants(participantsList, amount > 0 ? CurrencyUtils.convertToDisplayString(amount, iouCurrencyCode) : ''); }, @@ -383,7 +495,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ } else if ((receiptPath && isTypeRequest) || isDistanceRequestWithPendingRoute) { text = translate('iou.request'); if (iouAmount !== 0) { - text = translate('iou.requestAmount', {amount: formattedAmount}); + text = translate('iou.requestAmount', {amount: Number(formattedAmount)}); } } else { const translationKey = isTypeSplit ? 'iou.splitAmount' : 'iou.requestAmount'; @@ -397,7 +509,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ ]; }, [isTypeSplit, isTypeRequest, iouType, iouAmount, receiptPath, formattedAmount, isDistanceRequestWithPendingRoute, translate]); - const selectedParticipants = useMemo(() => _.filter(pickedParticipants, (participant) => participant.selected), [pickedParticipants]); + const selectedParticipants = useMemo(() => pickedParticipants.filter(participant => participant.selected), [pickedParticipants]); const personalDetailsOfPayee = useMemo(() => payeePersonalDetails || currentUserPersonalDetails, [payeePersonalDetails, currentUserPersonalDetails]); const userCanModifyParticipants = useRef(!isReadOnly && canModifyParticipants && hasMultipleParticipants); useEffect(() => { @@ -407,17 +519,18 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const optionSelectorSections = useMemo(() => { const sections = []; - const unselectedParticipants = _.filter(pickedParticipants, (participant) => !participant.selected); + const unselectedParticipants = pickedParticipants.filter(participant => !participant.selected); if (hasMultipleParticipants) { const formattedSelectedParticipants = getParticipantsWithAmount(selectedParticipants); let formattedParticipantsList = _.union(formattedSelectedParticipants, unselectedParticipants); if (!userCanModifyParticipants.current) { - formattedParticipantsList = _.map(formattedParticipantsList, (participant) => ({ + formattedParticipantsList = formattedParticipantsList.map(participant => ({ ...participant, isDisabled: ReportUtils.isOptimisticPersonalDetail(participant.accountID), })); } + const myIOUAmount = IOUUtils.calculateAmount(selectedParticipants.length, iouAmount, iouCurrencyCode, true); const formattedPayeeOption = OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail( @@ -441,10 +554,10 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }, ); } else { - const formattedSelectedParticipants = _.map(selectedParticipants, (participant) => ({ + const formattedSelectedParticipants = selectedParticipants.map(participant => ({ ...participant, isDisabled: !participant.isPolicyExpenseChat && ReportUtils.isOptimisticPersonalDetail(participant.accountID), - })); + })); sections.push({ title: translate('common.to'), data: formattedSelectedParticipants, @@ -493,7 +606,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ * @param {Object} option */ const selectParticipant = useCallback( - (option) => { + (option: string) => { // Return early if selected option is currently logged in user. if (option.accountID === accountID) { return; @@ -517,11 +630,9 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ } }; - /** - * @param {String} paymentMethod - */ + const confirm = useCallback( - (paymentMethod) => { + (paymentMethod?: PaymentMethodType) => { if (_.isEmpty(selectedParticipants)) { return; } @@ -608,7 +719,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ confirm(value)} + onPress={(event, value) => confirm(value)} options={splitOrRequestOptions} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.LARGE} enterKeyEventListenerPriority={1} @@ -790,7 +901,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ { item: ( Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()))} @@ -837,15 +948,14 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }, ]; - const primaryFields = _.map( - _.filter(classifiedFields, (classifiedField) => classifiedField.shouldShow && !classifiedField.isSupplementary), - (primaryField) => primaryField.item, - ); + const primaryFields = classifiedFields + .filter(classifiedField => classifiedField.shouldShow && !classifiedField.isSupplementary) + .map(primaryField => primaryField.item); + +const supplementaryFields = classifiedFields + .filter(classifiedField => classifiedField.shouldShow && classifiedField.isSupplementary) + .map(supplementaryField => supplementaryField.item); - const supplementaryFields = _.map( - _.filter(classifiedFields, (classifiedField) => classifiedField.shouldShow && classifiedField.isSupplementary), - (supplementaryField) => supplementaryField.item, - ); const {image: receiptImage, thumbnail: receiptThumbnail} = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction, receiptPath, receiptFilename) : {}; return ( @@ -916,13 +1026,9 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ ); } -MoneyTemporaryForRefactorRequestConfirmationList.propTypes = propTypes; -MoneyTemporaryForRefactorRequestConfirmationList.defaultProps = defaultProps; MoneyTemporaryForRefactorRequestConfirmationList.displayName = 'MoneyTemporaryForRefactorRequestConfirmationList'; -export default compose( - withCurrentUserPersonalDetails, - withOnyx({ +export default withOnyx({ session: { key: ONYXKEYS.SESSION, }, @@ -942,5 +1048,4 @@ export default compose( policyTaxRates: { key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_TAX_RATE}${policyID}`, }, - }), -)(MoneyTemporaryForRefactorRequestConfirmationList); + })(MoneyTemporaryForRefactorRequestConfirmationList); From a8e69fdd471b6d4f3ae5f890fda0a434ccdd0196 Mon Sep 17 00:00:00 2001 From: RohanSasne Date: Tue, 27 Feb 2024 00:45:52 +0530 Subject: [PATCH 016/402] Fix RBR error --- ...eyTemporaryForRefactorRequestConfirmationList.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index d76b7499d36b..d7bd650279bc 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -295,7 +295,7 @@ type MoneyTemporaryForRefactorRequestConfirmationListProps = { transaction: Transaction, - policyTaxRates: PolicyTaxRate, + policyTaxRates: Policy, reportActionID: string, @@ -380,7 +380,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const shouldShowTags = useMemo(() => isPolicyExpenseChat && OptionsListUtils.hasEnabledTags(policyTagLists), [isPolicyExpenseChat, policyTagLists]); // A flag for showing tax rate - const shouldShowTax = isPolicyExpenseChat && policy && lodashGet(policy, 'tax.trackingEnabled', policy.isTaxTrackingEnabled); + const shouldShowTax = isPolicyExpenseChat && policy && (policy?.tax?.trackingEnabled ?? policy?.isTaxTrackingEnabled); // A flag for showing the billable field const shouldShowBillable = !(policy?.disabledFields?.defaultBillable ?? true); @@ -755,7 +755,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} disabled={didConfirm} - brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction) ? translate('common.error.enterAmount') : ''} /> ), @@ -818,7 +818,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }} disabled={didConfirm} interactive={!isReadOnly} - brickRoadIndicator={merchantError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={merchantError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={merchantError ? translate('common.error.fieldRequired') : ''} rightLabel={isMerchantRequired ? translate('common.required') : ''} /> @@ -842,7 +842,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }} disabled={didConfirm} interactive={!isReadOnly} - brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? translate('common.error.enterDate') : ''} /> ), @@ -872,7 +872,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ shouldShow: shouldShowCategories, isSupplementary: !isCategoryRequired, }, - ..._.map(policyTagLists, ({name}, index) => ({ + ...policyTagLists.map(({ name }, index) => ({ item: ( Date: Tue, 27 Feb 2024 01:56:35 +0530 Subject: [PATCH 017/402] Migrate to typescript --- ...raryForRefactorRequestConfirmationList.tsx | 229 ++++++++---------- 1 file changed, 104 insertions(+), 125 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index 858b338d652d..8d996fcaad03 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -1,20 +1,17 @@ import {useIsFocused} from '@react-navigation/native'; import {format} from 'date-fns'; +import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {Fragment, useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react'; -import type {PersonalDetails, Policy, PolicyCategories, PolicyTags, Session, Transaction} from '@src/types/onyx'; import {View} from 'react-native'; -import { withOnyx} from 'react-native-onyx'; +import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; -import type { PolicyTaxRate } from '@src/types/onyx/PolicyTaxRates'; -import type { Participant } from '@src/types/onyx/IOU'; -import type { ValueOf } from 'type-fest'; import _ from 'underscore'; -import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import DistanceRequestUtils from '@libs/DistanceRequestUtils'; import * as IOUUtils from '@libs/IOUUtils'; @@ -32,7 +29,7 @@ import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type Route from '@src/ROUTES' +import type * as OnyxTypes from '@src/types/onyx'; import Button from './Button'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import categoryPropTypes from './categoryPropTypes'; @@ -51,7 +48,6 @@ import Text from './Text'; import transactionPropTypes from './transactionPropTypes'; import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from './withCurrentUserPersonalDetails'; - const propTypes = { /** Callback to inform parent modal of success */ onConfirm: PropTypes.func, @@ -206,109 +202,91 @@ const defaultProps = { isPolicyExpenseChat: false, }; +type MoneyTemporaryForRefactorRequestConfirmationListOnyxProps = { + session: OnyxEntry; -type DropdownOption = { - value: PaymentType; - text: string; - icon: IconAsset; - iconWidth?: number; - iconHeight?: number; - iconDescription?: string; -}; - -type MoneyTemporaryForRefactorRequestConfirmationListProps = { - bankAccountRoute?: Route, - - canModifyParticipants: boolean, - - currentUserPersonalDetails: OnyxEntry, - + policyCategories: OnyxEntry; - hasMultipleParticipants: boolean, + policyTags: OnyxEntry; - hasSmartScanFailed: boolean, - - iouAmount: number, - - iouCategory: string, - - iouComment: string, - - iouCreated: string, - - iouCurrencyCode: string, + policy: OnyxEntry; +}; - iouIsBillable: boolean, +type MoneyTemporaryForRefactorRequestConfirmationListProps = { + onConfirm: () => void; - iouMerchant: string, + onSendMoney: () => void; - iouTag: string, + onSelectParticipant: () => void; - iouType: ValueOf, + hasMultipleParticipants: boolean; - isDistanceRequest: boolean, + iouAmount: number; - isEditingSplitBill: boolean, + iouComment: string; - isPolicyExpenseChat: boolean, + iouCurrencyCode: string; - isReadOnly: boolean, + iouType: string; - isScanRequest: boolean, + iouCreated: string; - listStyles: Record | Array>, + iouMerchant: string; - mileageRate: { - /** Unit used to represent distance */ - unit: typeof CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES | typeof CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS; - - /** Rate used to calculate the distance request amount */ - rate: number; - - /** The currency of the rate */ - currency: string; - }; + iouCategory: string; - onConfirm: () => void, + iouIsBillable: boolean; - onSelectParticipant: (option: string) => void, + onToggleBillable: () => void; - onSendMoney: (paymentMethod: string) => void, + selectedParticipants: optionPropTypes[]; - onToggleBillable: () => void, + payeePersonalDetails: optionPropTypes; - policyCategories: OnyxEntry, + canModifyParticipants: boolean; - policyID: string, + isReadOnly: boolean; - policyTags: OnyxEntry, + isScanRequest: boolean; - receiptFilename: string, + bankAccountRoute: string; - receiptPath: string, + session: OnyxTypes.Session; - reportID: string, + policyCategories: OnyxTypes.PolicyCategories; - session: Session, + policyTags: OnyxTypes.PolicyTags; - shouldShowSmartScanFields: boolean, + policy: OnyxTypes.Policy; - transaction: Transaction, + receiptPath: string; - policyTaxRates: Policy, + receiptFilename: string; - reportActionID: string, + listStyles: object | object[]; - policy: OnyxEntry + transactionID: string; + mileageRate: { + unit: string; + rate: number; + currency: string; + }; + isDistanceRequest: boolean; + isEditingSplitBill: boolean; + shouldShowSmartScanFields: boolean; + isPolicyExpenseChat: boolean; + transaction: OnyxTypes.Transaction; -} + policyID: string; +}; +type MoneyTemporaryForRefactorRequestConfirmationList = MoneyTemporaryForRefactorRequestConfirmationListOnyxProps & MoneyTemporaryForRefactorRequestConfirmationListProps; function MoneyTemporaryForRefactorRequestConfirmationList({ bankAccountRoute, @@ -348,9 +326,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ session: {accountID}, shouldShowSmartScanFields, transaction, - policyTaxRates, -}: MoneyTemporaryForRefactorRequestConfirmationListProps) { - +}: MoneyTemporaryForRefactorRequestConfirmationList) { const theme = useTheme(); const styles = useThemeStyles(); const {translate, toLocaleDigit} = useLocalize(); @@ -361,12 +337,13 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const isTypeSend = iouType === CONST.IOU.TYPE.SEND; const {unit, rate, currency} = mileageRate; - const distance = transaction?.routes?.route0?.distance ?? 0; + const distance = lodashGet(transaction, 'routes.route0.distance', 0); const shouldCalculateDistanceAmount = isDistanceRequest && iouAmount === 0; const taxRates = lodashGet(policy, 'taxRates', {}); // A flag for showing the categories field - const shouldShowCategories = isPolicyExpenseChat && (iouCategory || (policyCategories && OptionsListUtils.hasEnabledOptions(Object.values(policyCategories)))); + const shouldShowCategories = isPolicyExpenseChat && (iouCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories))); + // A flag and a toggler for showing the rest of the form fields const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); @@ -382,10 +359,10 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const shouldShowTags = useMemo(() => isPolicyExpenseChat && OptionsListUtils.hasEnabledTags(policyTagLists), [isPolicyExpenseChat, policyTagLists]); // A flag for showing tax rate - const shouldShowTax = isPolicyExpenseChat && policy && (policy?.tax?.trackingEnabled ?? policy?.isTaxTrackingEnabled); + const shouldShowTax = isPolicyExpenseChat && policy && lodashGet(policy, 'tax.trackingEnabled', policy.isTaxTrackingEnabled); // A flag for showing the billable field - const shouldShowBillable = !(policy?.disabledFields?.defaultBillable ?? true); + const shouldShowBillable = !lodashGet(policy, 'disabledFields.defaultBillable', true); const hasRoute = TransactionUtils.hasRoute(transaction); const isDistanceRequestWithPendingRoute = isDistanceRequest && (!hasRoute || !rate); @@ -397,7 +374,6 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ ); const formattedTaxAmount = CurrencyUtils.convertToDisplayString(transaction.taxAmount, iouCurrencyCode); - const defaultTaxKey = taxRates.defaultExternalID; const defaultTaxName = (defaultTaxKey && `${taxRates.taxes[defaultTaxKey].name} (${taxRates.taxes[defaultTaxKey].value}) • ${translate('common.default')}`) || ''; const taxRateTitle = (transaction.taxRate && transaction.taxRate.text) || defaultTaxName; @@ -421,8 +397,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const isMerchantEmpty = !iouMerchant || iouMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; const isMerchantRequired = isPolicyExpenseChat && !isScanRequest && shouldShowMerchant; - const isCategoryRequired = canUseViolations && (policy?.requiresCategory ?? false); - const isTagRequired = canUseViolations && (policy?.requiresTag ?? false); + const isCategoryRequired = canUseViolations && lodashGet(policy, 'requiresCategory', false); + const isTagRequired = canUseViolations && lodashGet(policy, 'requiresTag', false); useEffect(() => { if ((!isMerchantRequired && isMerchantEmpty) || !merchantError) { @@ -468,7 +444,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ * @returns {Array} */ const getParticipantsWithAmount = useCallback( - (participantsList: Participant[]) => { + (participantsList) => { const amount = IOUUtils.calculateAmount(participantsList.length, iouAmount, iouCurrencyCode); return OptionsListUtils.getIOUConfirmationOptionsFromParticipants(participantsList, amount > 0 ? CurrencyUtils.convertToDisplayString(amount, iouCurrencyCode) : ''); }, @@ -487,7 +463,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ } else if ((receiptPath && isTypeRequest) || isDistanceRequestWithPendingRoute) { text = translate('iou.request'); if (iouAmount !== 0) { - text = translate('iou.requestAmount', {amount: Number(formattedAmount)}); + text = translate('iou.requestAmount', {amount: formattedAmount}); } } else { const translationKey = isTypeSplit ? 'iou.splitAmount' : 'iou.requestAmount'; @@ -501,7 +477,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ ]; }, [isTypeSplit, isTypeRequest, iouType, iouAmount, receiptPath, formattedAmount, isDistanceRequestWithPendingRoute, translate]); - const selectedParticipants = useMemo(() => pickedParticipants.filter(participant => participant.selected), [pickedParticipants]); + const selectedParticipants = useMemo(() => _.filter(pickedParticipants, (participant) => participant.selected), [pickedParticipants]); const personalDetailsOfPayee = useMemo(() => payeePersonalDetails || currentUserPersonalDetails, [payeePersonalDetails, currentUserPersonalDetails]); const userCanModifyParticipants = useRef(!isReadOnly && canModifyParticipants && hasMultipleParticipants); useEffect(() => { @@ -511,18 +487,17 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const optionSelectorSections = useMemo(() => { const sections = []; - const unselectedParticipants = pickedParticipants.filter(participant => !participant.selected); + const unselectedParticipants = _.filter(pickedParticipants, (participant) => !participant.selected); if (hasMultipleParticipants) { const formattedSelectedParticipants = getParticipantsWithAmount(selectedParticipants); let formattedParticipantsList = _.union(formattedSelectedParticipants, unselectedParticipants); if (!userCanModifyParticipants.current) { - formattedParticipantsList = formattedParticipantsList.map(participant => ({ + formattedParticipantsList = _.map(formattedParticipantsList, (participant) => ({ ...participant, isDisabled: ReportUtils.isOptimisticPersonalDetail(participant.accountID), })); } - const myIOUAmount = IOUUtils.calculateAmount(selectedParticipants.length, iouAmount, iouCurrencyCode, true); const formattedPayeeOption = OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail( @@ -546,10 +521,10 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }, ); } else { - const formattedSelectedParticipants = selectedParticipants.map(participant => ({ + const formattedSelectedParticipants = _.map(selectedParticipants, (participant) => ({ ...participant, isDisabled: !participant.isPolicyExpenseChat && ReportUtils.isOptimisticPersonalDetail(participant.accountID), - })); + })); sections.push({ title: translate('common.to'), data: formattedSelectedParticipants, @@ -598,7 +573,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ * @param {Object} option */ const selectParticipant = useCallback( - (option: string) => { + (option) => { // Return early if selected option is currently logged in user. if (option.accountID === accountID) { return; @@ -622,9 +597,11 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ } }; - + /** + * @param {String} paymentMethod + */ const confirm = useCallback( - (paymentMethod?: PaymentMethodType) => { + (paymentMethod) => { if (_.isEmpty(selectedParticipants)) { return; } @@ -711,7 +688,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ confirm(value)} + onPress={(_event, value) => confirm(value)} options={splitOrRequestOptions} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.LARGE} enterKeyEventListenerPriority={1} @@ -756,7 +733,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} disabled={didConfirm} - brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} + brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} error={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction) ? translate('common.error.enterAmount') : ''} /> ), @@ -819,7 +796,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }} disabled={didConfirm} interactive={!isReadOnly} - brickRoadIndicator={merchantError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} + brickRoadIndicator={merchantError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} error={merchantError ? translate('common.error.fieldRequired') : ''} rightLabel={isMerchantRequired ? translate('common.required') : ''} /> @@ -843,7 +820,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }} disabled={didConfirm} interactive={!isReadOnly} - brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} + brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} error={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? translate('common.error.enterDate') : ''} /> ), @@ -873,7 +850,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ shouldShow: shouldShowCategories, isSupplementary: !isCategoryRequired, }, - ...policyTagLists.map(({ name }, index) => ({ + ..._.map(policyTagLists, ({name}, index) => ({ item: ( classifiedField.shouldShow && !classifiedField.isSupplementary) - .map(primaryField => primaryField.item); - -const supplementaryFields = classifiedFields - .filter(classifiedField => classifiedField.shouldShow && classifiedField.isSupplementary) - .map(supplementaryField => supplementaryField.item); + const primaryFields = _.map( + _.filter(classifiedFields, (classifiedField) => classifiedField.shouldShow && !classifiedField.isSupplementary), + (primaryField) => primaryField.item, + ); + const supplementaryFields = _.map( + _.filter(classifiedFields, (classifiedField) => classifiedField.shouldShow && classifiedField.isSupplementary), + (supplementaryField) => supplementaryField.item, + ); const {image: receiptImage, thumbnail: receiptThumbnail} = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction, receiptPath, receiptFilename) : {}; return ( @@ -1023,24 +1001,25 @@ const supplementaryFields = classifiedFields ); } +MoneyTemporaryForRefactorRequestConfirmationList.propTypes = propTypes; +MoneyTemporaryForRefactorRequestConfirmationList.defaultProps = defaultProps; MoneyTemporaryForRefactorRequestConfirmationList.displayName = 'MoneyTemporaryForRefactorRequestConfirmationList'; -export default withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - policyCategories: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, - }, - policyTags: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, - }, - mileageRate: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - selector: DistanceRequestUtils.getDefaultMileageRate, - }, - policy: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - }, - }), -)(MoneyTemporaryForRefactorRequestConfirmationList); +export default withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + policyCategories: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, + }, + policyTags: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, + }, + mileageRate: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + selector: DistanceRequestUtils.getDefaultMileageRate, + }, + policy: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + }, +})(MoneyTemporaryForRefactorRequestConfirmationList); From 1029becfd23a5455c56045783c7212620486909a Mon Sep 17 00:00:00 2001 From: RohanSasne Date: Tue, 27 Feb 2024 02:18:35 +0530 Subject: [PATCH 018/402] Working with onyx --- .../MoneyTemporaryForRefactorRequestConfirmationList.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index 8d996fcaad03..d505586f9571 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -245,6 +245,8 @@ type MoneyTemporaryForRefactorRequestConfirmationListProps = { canModifyParticipants: boolean; + hasSmartScanFailed: boolean; + isReadOnly: boolean; isScanRequest: boolean; @@ -284,6 +286,10 @@ type MoneyTemporaryForRefactorRequestConfirmationListProps = { transaction: OnyxTypes.Transaction; policyID: string; + + reportID: string; + + reportActionID: string; }; type MoneyTemporaryForRefactorRequestConfirmationList = MoneyTemporaryForRefactorRequestConfirmationListOnyxProps & MoneyTemporaryForRefactorRequestConfirmationListProps; From 66a4e318399f1040dfa517fa936f32f660299e6a Mon Sep 17 00:00:00 2001 From: RohanSasne Date: Tue, 27 Feb 2024 02:50:47 +0530 Subject: [PATCH 019/402] fix props --- ...TemporaryForRefactorRequestConfirmationList.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index d505586f9571..982883a349e1 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -270,7 +270,7 @@ type MoneyTemporaryForRefactorRequestConfirmationListProps = { transactionID: string; mileageRate: { - unit: string; + unit: typeof CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES | typeof CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS; rate: number; currency: string; }; @@ -292,7 +292,7 @@ type MoneyTemporaryForRefactorRequestConfirmationListProps = { reportActionID: string; }; -type MoneyTemporaryForRefactorRequestConfirmationList = MoneyTemporaryForRefactorRequestConfirmationListOnyxProps & MoneyTemporaryForRefactorRequestConfirmationListProps; +type MoneyTemporaryForRefactorRequestConfirmation = MoneyTemporaryForRefactorRequestConfirmationListOnyxProps & MoneyTemporaryForRefactorRequestConfirmationListProps; function MoneyTemporaryForRefactorRequestConfirmationList({ bankAccountRoute, @@ -332,7 +332,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ session: {accountID}, shouldShowSmartScanFields, transaction, -}: MoneyTemporaryForRefactorRequestConfirmationList) { +}: MoneyTemporaryForRefactorRequestConfirmation) { const theme = useTheme(); const styles = useThemeStyles(); const {translate, toLocaleDigit} = useLocalize(); @@ -345,10 +345,11 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const {unit, rate, currency} = mileageRate; const distance = lodashGet(transaction, 'routes.route0.distance', 0); const shouldCalculateDistanceAmount = isDistanceRequest && iouAmount === 0; - const taxRates = lodashGet(policy, 'taxRates', {}); + const taxRates = policy?.taxRates ?? {}; // A flag for showing the categories field - const shouldShowCategories = isPolicyExpenseChat && (iouCategory || OptionsListUtils.hasEnabledOptions(_.values(policyCategories))); + const shouldShowCategories = isPolicyExpenseChat && (iouCategory || (OptionsListUtils.hasEnabledOptions(Object.values(policyCategories)))); + // A flag and a toggler for showing the rest of the form fields const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); @@ -1007,8 +1008,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ ); } -MoneyTemporaryForRefactorRequestConfirmationList.propTypes = propTypes; -MoneyTemporaryForRefactorRequestConfirmationList.defaultProps = defaultProps; + MoneyTemporaryForRefactorRequestConfirmationList.displayName = 'MoneyTemporaryForRefactorRequestConfirmationList'; export default withOnyx({ From aae1a41d56ef7f89ba1569620f0a611d98923a72 Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Thu, 29 Feb 2024 04:42:17 +0530 Subject: [PATCH 020/402] Migrate to typescript --- ...raryForRefactorRequestConfirmationList.tsx | 533 +++++++----------- 1 file changed, 217 insertions(+), 316 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index 161f1ff27897..c6248165b797 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -1,338 +1,231 @@ import {useIsFocused} from '@react-navigation/native'; import {format} from 'date-fns'; -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React, {Fragment, useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react'; +import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; -import _ from 'underscore'; +import {withOnyx} from 'react-native-onyx'; +import type {ValueOf} from 'type-fest'; import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import DistanceRequestUtils from '@libs/DistanceRequestUtils'; import * as IOUUtils from '@libs/IOUUtils'; import Log from '@libs/Log'; +import playSound, {SOUNDS} from '@libs/Sound'; import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReceiptUtils from '@libs/ReceiptUtils'; import * as ReportUtils from '@libs/ReportUtils'; -import playSound, {SOUNDS} from '@libs/Sound'; import * as TransactionUtils from '@libs/TransactionUtils'; -import {policyPropTypes} from '@pages/workspace/withPolicy'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; +import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; -import Button from './Button'; +import type {Participant} from '@src/types/onyx/IOU'; +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; +import type {MileageRate} from '@src/types/onyx/Policy'; +import type DeepValueOf from '@src/types/utils/DeepValueOf'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; -import categoryPropTypes from './categoryPropTypes'; import ConfirmedRoute from './ConfirmedRoute'; import FormHelpMessage from './FormHelpMessage'; -import * as Expensicons from './Icon/Expensicons'; import Image from './Image'; import MenuItemWithTopDescription from './MenuItemWithTopDescription'; -import optionPropTypes from './optionPropTypes'; import OptionsSelector from './OptionsSelector'; import ReceiptEmptyState from './ReceiptEmptyState'; import SettlementButton from './SettlementButton'; +import ShowMoreButton from './ShowMoreButton'; import Switch from './Switch'; -import tagPropTypes from './tagPropTypes'; import Text from './Text'; -import transactionPropTypes from './transactionPropTypes'; -import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from './withCurrentUserPersonalDetails'; - -const propTypes = { - /** Callback to inform parent modal of success */ - onConfirm: PropTypes.func, - - /** Callback to parent modal to send money */ - onSendMoney: PropTypes.func, - - /** Callback to inform a participant is selected */ - onSelectParticipant: PropTypes.func, - - /** Should we request a single or multiple participant selection from user */ - hasMultipleParticipants: PropTypes.bool.isRequired, - - /** IOU amount */ - iouAmount: PropTypes.number.isRequired, - - /** IOU comment */ - iouComment: PropTypes.string, - - /** IOU currency */ - iouCurrencyCode: PropTypes.string, - - /** IOU type */ - iouType: PropTypes.string, - - /** IOU date */ - iouCreated: PropTypes.string, - - /** IOU merchant */ - iouMerchant: PropTypes.string, - - /** IOU category */ - iouCategory: PropTypes.string, - - /** IOU isBillable */ - iouIsBillable: PropTypes.bool, - - /** Callback to toggle the billable state */ - onToggleBillable: PropTypes.func, - - /** Selected participants from MoneyRequestModal with login / accountID */ - selectedParticipants: PropTypes.arrayOf(optionPropTypes).isRequired, - - /** Payee of the money request with login */ - payeePersonalDetails: optionPropTypes, - - /** Can the participants be modified or not */ - canModifyParticipants: PropTypes.bool, - - /** Should the list be read only, and not editable? */ - isReadOnly: PropTypes.bool, - - /** Whether the money request is a scan request */ - isScanRequest: PropTypes.bool, - - /** Depending on expense report or personal IOU report, respective bank account route */ - bankAccountRoute: PropTypes.string, - - ...withCurrentUserPersonalDetailsPropTypes, - - /** Current user session */ - session: PropTypes.shape({ - email: PropTypes.string.isRequired, - }), - - /** The policyID of the request */ - policyID: PropTypes.string, - - /** The reportID of the request */ - reportID: PropTypes.string, +import type {WithCurrentUserPersonalDetailsProps} from './withCurrentUserPersonalDetails'; +import withCurrentUserPersonalDetails from './withCurrentUserPersonalDetails'; +import Button from './Button'; - /** File path of the receipt */ - receiptPath: PropTypes.string, +type DropdownOption = { + text: string; + value: DeepValueOf; +}; - /** File name of the receipt */ - receiptFilename: PropTypes.string, +type Option = Partial; - /** List styles for OptionsSelector */ - listStyles: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), +type CategorySection = { + title: string | undefined; + shouldShow: boolean; + indexOffset: number; + data: Option[]; +}; - /** ID of the transaction that represents the money request */ - transactionID: PropTypes.string, +type MoneyRequestConfirmationListOnyxProps = { + /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ + iou: OnyxEntry; /** Unit and rate used for if the money request is a distance request */ - mileageRate: PropTypes.shape({ - /** Unit used to represent distance */ - unit: PropTypes.oneOf([CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES, CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS]), - - /** Rate used to calculate the distance request amount */ - rate: PropTypes.number, - - /** The currency of the rate */ - currency: PropTypes.string, - }), + mileageRate: OnyxEntry; - /** Whether the money request is a distance request */ - isDistanceRequest: PropTypes.bool, - - /** Whether we're editing a split bill */ - isEditingSplitBill: PropTypes.bool, - - /** Whether we should show the amount, date, and merchant fields. */ - shouldShowSmartScanFields: PropTypes.bool, - - /** A flag for verifying that the current report is a sub-report of a workspace chat */ - isPolicyExpenseChat: PropTypes.bool, - - /* Onyx Props */ /** Collection of categories attached to a policy */ - policyCategories: PropTypes.objectOf(categoryPropTypes), - - /** Collection of tags attached to a policy */ - policyTags: tagPropTypes, - - /* Onyx Props */ - /** The policy of the report */ - policy: policyPropTypes.policy, - - /** Transaction that represents the money request */ - transaction: transactionPropTypes, -}; - -const defaultProps = { - onConfirm: () => {}, - onSendMoney: () => {}, - onSelectParticipant: () => {}, - iouType: CONST.IOU.TYPE.REQUEST, - iouCategory: '', - iouIsBillable: false, - onToggleBillable: () => {}, - payeePersonalDetails: null, - canModifyParticipants: false, - isReadOnly: false, - bankAccountRoute: '', - session: { - email: null, - }, - policyID: '', - reportID: '', - ...withCurrentUserPersonalDetailsDefaultProps, - receiptPath: '', - receiptFilename: '', - listStyles: [], - policy: {}, - policyCategories: {}, - policyTags: {}, - transactionID: '', - transaction: {}, - mileageRate: {unit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES, rate: 0, currency: 'USD'}, - isDistanceRequest: false, - shouldShowSmartScanFields: true, - isPolicyExpenseChat: false, -}; - -type MoneyTemporaryForRefactorRequestConfirmationListOnyxProps = { - session: OnyxEntry; - policyCategories: OnyxEntry; + /** Collection of tags attached to a policy */ policyTags: OnyxEntry; + /** The policy of root parent report */ policy: OnyxEntry; -}; - -type MoneyTemporaryForRefactorRequestConfirmationListProps = { - onConfirm: () => void; - - onSendMoney: () => void; - - onSelectParticipant: () => void; - hasMultipleParticipants: boolean; + /** The session of the logged in user */ + session: OnyxEntry; +}; - iouAmount: number; +type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps & + WithCurrentUserPersonalDetailsProps & { + /** Callback to inform parent modal of success */ + onConfirm?: (selectedParticipants: Participant[]) => void; - iouComment: string; + /** Callback to parent modal to send money */ + onSendMoney?: (paymentMethod: PaymentMethodType) => void; - iouCurrencyCode: string; + /** Callback to inform a participant is selected */ + onSelectParticipant?: (option: Participant) => void; - iouType: string; + /** Should we request a single or multiple participant selection from user */ + hasMultipleParticipants: boolean; - iouCreated: string; + /** IOU amount */ + iouAmount: number; - iouMerchant: string; + /** IOU comment */ + iouComment?: string; - iouCategory: string; + /** IOU currency */ + iouCurrencyCode?: string; - iouIsBillable: boolean; + /** IOU type */ + iouType?: ValueOf; - onToggleBillable: () => void; + /** IOU date */ + iouCreated?: string; - selectedParticipants: optionPropTypes[]; + /** IOU merchant */ + iouMerchant?: string; - payeePersonalDetails: optionPropTypes; + /** IOU Category */ + iouCategory?: string; - canModifyParticipants: boolean; + /** IOU Tag */ + iouTag?: string; - hasSmartScanFailed: boolean; + /** IOU isBillable */ + iouIsBillable?: boolean; - isReadOnly: boolean; + /** Callback to toggle the billable state */ + onToggleBillable?: () => void; - isScanRequest: boolean; + /** Selected participants from MoneyRequestModal with login / accountID */ + pickedParticipants: Participant[]; - bankAccountRoute: string; + /** Payee of the money request with login */ + payeePersonalDetails?: OnyxEntry; - session: OnyxTypes.Session; + /** Can the participants be modified or not */ + canModifyParticipants?: boolean; - policyCategories: OnyxTypes.PolicyCategories; + /** Should the list be read only, and not editable? */ + isReadOnly?: boolean; - policyTags: OnyxTypes.PolicyTags; + /** Depending on expense report or personal IOU report, respective bank account route */ + bankAccountRoute?: Route; - policy: OnyxTypes.Policy; + /** The policyID of the request */ + policyID?: string; - receiptPath: string; + /** The reportID of the request */ + reportID: string; - receiptFilename: string; + /** File path of the receipt */ + receiptPath?: string; - listStyles: object | object[]; + /** File name of the receipt */ + receiptFilename?: string; - transactionID: string; + /** List styles for OptionsSelector */ + listStyles?: StyleProp; - mileageRate: { - unit: typeof CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES | typeof CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS; - rate: number; - currency: string; - }; + /** ID of the transaction that represents the money request */ + transactionID?: string; - isDistanceRequest: boolean; + /** Whether the money request is a distance request */ + isDistanceRequest?: boolean; - isEditingSplitBill: boolean; + /** Whether the money request is a scan request */ + isScanRequest?: boolean; - shouldShowSmartScanFields: boolean; + /** Whether we're editing a split bill */ + isEditingSplitBill?: boolean; - isPolicyExpenseChat: boolean; + /** Whether we should show the amount, date, and merchant fields. */ + shouldShowSmartScanFields?: boolean; - transaction: OnyxTypes.Transaction; + /** A flag for verifying that the current report is a sub-report of a workspace chat */ + isPolicyExpenseChat?: boolean; - policyID: string; + /** Whether there is smartscan failed */ + hasSmartScanFailed?: boolean; - reportID: string; + /** ID of the report action */ + reportActionID: string; - reportActionID: string; -}; - -type MoneyTemporaryForRefactorRequestConfirmation = MoneyTemporaryForRefactorRequestConfirmationListOnyxProps & MoneyTemporaryForRefactorRequestConfirmationListProps; + /** Transaction object */ + transaction: OnyxTypes.Transaction; + }; function MoneyTemporaryForRefactorRequestConfirmationList({ + onConfirm = () => {}, + onSendMoney = () => {}, + onSelectParticipant = () => {}, + iouType = CONST.IOU.TYPE.REQUEST, + iouCategory = '', + iouTag = '', + iouIsBillable = false, + onToggleBillable = () => {}, + payeePersonalDetails, + canModifyParticipants = false, + isReadOnly = false, bankAccountRoute, - canModifyParticipants, - currentUserPersonalDetails, - hasMultipleParticipants, - hasSmartScanFailed, + policyID, + reportID, + receiptPath, + receiptFilename, + transactionID, + mileageRate, + isDistanceRequest = false, + isScanRequest = false, + shouldShowSmartScanFields = true, + isPolicyExpenseChat = false, + transaction, iouAmount, - iouCategory, - iouComment, - iouCreated, + policyTags, + policyCategories, + policy, iouCurrencyCode, - iouIsBillable, - iouMerchant, - iouType, - isDistanceRequest, isEditingSplitBill, - isPolicyExpenseChat, - isReadOnly, - isScanRequest, - listStyles, - mileageRate, - onConfirm, - onSelectParticipant, - onSendMoney, - onToggleBillable, - payeePersonalDetails, - policy, - policyCategories, - policyID, - policyTags, - receiptFilename, - receiptPath, + hasSmartScanFailed, + iouMerchant, + currentUserPersonalDetails, + hasMultipleParticipants, + pickedParticipants, + session, + iou, reportActionID, - reportID, - selectedParticipants: pickedParticipants, - session: {accountID}, - shouldShowSmartScanFields, - transaction, -}: MoneyTemporaryForRefactorRequestConfirmation) { + iouCreated, + listStyles, + iouComment, +}: MoneyRequestConfirmationListProps) { const theme = useTheme(); const styles = useThemeStyles(); const {translate, toLocaleDigit} = useLocalize(); @@ -343,12 +236,12 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const isTypeSend = iouType === CONST.IOU.TYPE.SEND; const {unit, rate, currency} = mileageRate; - const distance = lodashGet(transaction, 'routes.route0.distance', 0); + const distance = transaction?.routes?.route0.distance ?? 0; const shouldCalculateDistanceAmount = isDistanceRequest && iouAmount === 0; - const taxRates = policy?.taxRates ?? {}; + const taxRates = policy?.taxRates ?? null; // A flag for showing the categories field - const shouldShowCategories = isPolicyExpenseChat && (iouCategory || (OptionsListUtils.hasEnabledOptions(Object.values(policyCategories)))); + const shouldShowCategories = isPolicyExpenseChat && (iouCategory || OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {}))); // A flag and a toggler for showing the rest of the form fields @@ -366,10 +259,10 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const shouldShowTags = useMemo(() => isPolicyExpenseChat && OptionsListUtils.hasEnabledTags(policyTagLists), [isPolicyExpenseChat, policyTagLists]); // A flag for showing tax rate - const shouldShowTax = isPolicyExpenseChat && policy && lodashGet(policy, 'tax.trackingEnabled', policy.isTaxTrackingEnabled); + const shouldShowTax = isPolicyExpenseChat && (policy?.tax?.trackingEnabled ?? policy?.isTaxTrackingEnabled); // A flag for showing the billable field - const shouldShowBillable = !lodashGet(policy, 'disabledFields.defaultBillable', true); + const shouldShowBillable = !policy?.disabledFields?.defaultBillable ?? true; const hasRoute = TransactionUtils.hasRoute(transaction); const isDistanceRequestWithPendingRoute = isDistanceRequest && (!hasRoute || !rate); @@ -379,11 +272,12 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ shouldCalculateDistanceAmount ? DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate) : iouAmount, isDistanceRequest ? currency : iouCurrencyCode, ); - const formattedTaxAmount = CurrencyUtils.convertToDisplayString(transaction.taxAmount, iouCurrencyCode); + const formattedTaxAmount = CurrencyUtils.convertToDisplayString(transaction?.taxAmount, iouCurrencyCode); - const defaultTaxKey = taxRates.defaultExternalID; + const defaultTaxKey = taxRates?.defaultExternalID; const defaultTaxName = (defaultTaxKey && `${taxRates.taxes[defaultTaxKey].name} (${taxRates.taxes[defaultTaxKey].value}) • ${translate('common.default')}`) || ''; - const taxRateTitle = (transaction.taxRate && transaction.taxRate.text) || defaultTaxName; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const taxRateTitle = (transaction?.taxRate?.text) || defaultTaxName; const isFocused = useIsFocused(); const [formError, setFormError] = useState(''); @@ -398,14 +292,14 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ return false; } - return (hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction)) || (didConfirmSplit && TransactionUtils.areRequiredFieldsEmpty(transaction)); + return (!!hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction ?? null)) || (didConfirmSplit && TransactionUtils.areRequiredFieldsEmpty(transaction ?? null)); }, [isEditingSplitBill, hasSmartScanFailed, transaction, didConfirmSplit]); const isMerchantEmpty = !iouMerchant || iouMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; const isMerchantRequired = isPolicyExpenseChat && !isScanRequest && shouldShowMerchant; - const isCategoryRequired = canUseViolations && lodashGet(policy, 'requiresCategory', false); - const isTagRequired = canUseViolations && lodashGet(policy, 'requiresTag', false); + const isCategoryRequired = canUseViolations && (policy?.requiresCategory ?? false); + const isTagRequired = canUseViolations && (policy?.requiresTag ?? false); useEffect(() => { if ((!isMerchantRequired && isMerchantEmpty) || !merchantError) { @@ -442,18 +336,19 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ } const amount = DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate); - IOU.setMoneyRequestAmount_temporaryForRefactor(transaction.transactionID, amount, currency); + IOU.setMoneyRequestAmount_temporaryForRefactor(transaction?.transactionID, amount, currency); }, [shouldCalculateDistanceAmount, distance, rate, unit, transaction, currency]); /** * Returns the participants with amount - * @param {Array} participants - * @returns {Array} */ const getParticipantsWithAmount = useCallback( - (participantsList) => { - const amount = IOUUtils.calculateAmount(participantsList.length, iouAmount, iouCurrencyCode); - return OptionsListUtils.getIOUConfirmationOptionsFromParticipants(participantsList, amount > 0 ? CurrencyUtils.convertToDisplayString(amount, iouCurrencyCode) : ''); + (participantsList: Participant[]) => { + const calculatedIouAmount = IOUUtils.calculateAmount(participantsList.length, iouAmount, iouCurrencyCode ?? ''); + return OptionsListUtils.getIOUConfirmationOptionsFromParticipants( + participantsList, + calculatedIouAmount > 0 ? CurrencyUtils.convertToDisplayString(calculatedIouAmount, iouCurrencyCode) : '', + ); }, [iouAmount, iouCurrencyCode], ); @@ -463,10 +358,11 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ setDidConfirm(false); } - const splitOrRequestOptions = useMemo(() => { + const splitOrRequestOptions: DropdownOption[] = useMemo(() => { let text; if (isTypeSplit && iouAmount === 0) { text = translate('iou.split'); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing } else if ((receiptPath && isTypeRequest) || isDistanceRequestWithPendingRoute) { text = translate('iou.request'); if (iouAmount !== 0) { @@ -484,17 +380,17 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ ]; }, [isTypeSplit, isTypeRequest, iouType, iouAmount, receiptPath, formattedAmount, isDistanceRequestWithPendingRoute, translate]); - const selectedParticipants = useMemo(() => _.filter(pickedParticipants, (participant) => participant.selected), [pickedParticipants]); - const personalDetailsOfPayee = useMemo(() => payeePersonalDetails || currentUserPersonalDetails, [payeePersonalDetails, currentUserPersonalDetails]); + const selectedParticipants = useMemo(() => pickedParticipants.filter((participant) => participant.selected), [pickedParticipants]); + const personalDetailsOfPayee = useMemo(() => payeePersonalDetails ?? currentUserPersonalDetails, [payeePersonalDetails, currentUserPersonalDetails]); const userCanModifyParticipants = useRef(!isReadOnly && canModifyParticipants && hasMultipleParticipants); useEffect(() => { userCanModifyParticipants.current = !isReadOnly && canModifyParticipants && hasMultipleParticipants; }, [isReadOnly, canModifyParticipants, hasMultipleParticipants]); const shouldDisablePaidBySection = userCanModifyParticipants.current; - const optionSelectorSections = useMemo(() => { + const optionSelectorSections: CategorySection[] = useMemo(() => { const sections = []; - const unselectedParticipants = _.filter(pickedParticipants, (participant) => !participant.selected); + cosnt unselectedParticipants = pickedParticipants.filter((participant) => !participant.selected); if (hasMultipleParticipants) { const formattedSelectedParticipants = getParticipantsWithAmount(selectedParticipants); let formattedParticipantsList = _.union(formattedSelectedParticipants, unselectedParticipants); @@ -502,11 +398,11 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ if (!userCanModifyParticipants.current) { formattedParticipantsList = _.map(formattedParticipantsList, (participant) => ({ ...participant, - isDisabled: ReportUtils.isOptimisticPersonalDetail(participant.accountID), + isDisabled: ReportUtils.isOptimisticPersonalDetail(participant.accountID ?? -1), })); } - const myIOUAmount = IOUUtils.calculateAmount(selectedParticipants.length, iouAmount, iouCurrencyCode, true); + const myIOUAmount = IOUUtils.calculateAmount(selectedParticipants.length, iouAmount, iouCurrencyCode ?? '', true); const formattedPayeeOption = OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail( personalDetailsOfPayee, iouAmount > 0 ? CurrencyUtils.convertToDisplayString(myIOUAmount, iouCurrencyCode) : '', @@ -557,7 +453,10 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ if (!hasMultipleParticipants) { return []; } - return [...selectedParticipants, OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetailsOfPayee)]; + return [ + ...selectedParticipants, + OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetailsOfPayee, CurrencyUtils.convertToDisplayString(myIOUAmount, iouCurrencyCode)) + ]; }, [selectedParticipants, hasMultipleParticipants, personalDetailsOfPayee]); useEffect(() => { @@ -576,31 +475,27 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ IOU.setMoneyRequestMerchant(transaction.transactionID, distanceMerchant, true); }, [isDistanceRequestWithPendingRoute, hasRoute, distance, unit, rate, currency, translate, toLocaleDigit, isDistanceRequest, transaction]); - /** - * @param {Object} option - */ const selectParticipant = useCallback( - (option) => { + (option: Participant) => { // Return early if selected option is currently logged in user. - if (option.accountID === accountID) { + if (option.accountID === session?.accountID) { return; } onSelectParticipant(option); }, - [accountID, onSelectParticipant], + [session?.accountID, onSelectParticipant], ); /** * Navigate to report details or profile of selected user - * @param {Object} option */ - const navigateToReportOrUserDetail = (option) => { - const activeRoute = Navigation.getActiveRouteWithoutParams(); + const navigateToReportOrUserDetail = (option: Participant | OnyxTypes.Report) => { + if ('accountID' in option && option.accountID) { + const activeRoute = Navigation.getActiveRouteWithoutParams(); - if (option.accountID) { Navigation.navigate(ROUTES.PROFILE.getRoute(option.accountID, activeRoute)); - } else if (option.reportID) { - Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(option.reportID, activeRoute)); + } else if ('reportID' in option && option.reportID) { + Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(option.reportID)); } }; @@ -608,8 +503,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ * @param {String} paymentMethod */ const confirm = useCallback( - (paymentMethod) => { - if (_.isEmpty(selectedParticipants)) { + (paymentMethod: PaymentMethodType | undefined) => { + if (selectedParticipants.length === 0) { return; } if ((isMerchantRequired && isMerchantEmpty) || (shouldDisplayFieldError && TransactionUtils.isMerchantMissing(transaction))) { @@ -695,7 +590,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ confirm(value)} + onPress={(_, value) => confirm(value as PaymentMethodType)} options={splitOrRequestOptions} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.LARGE} enterKeyEventListenerPriority={1} @@ -740,7 +635,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} disabled={didConfirm} - brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction) ? translate('common.error.enterAmount') : ''} /> ), @@ -803,7 +698,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }} disabled={didConfirm} interactive={!isReadOnly} - brickRoadIndicator={merchantError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={merchantError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={merchantError ? translate('common.error.fieldRequired') : ''} rightLabel={isMerchantRequired ? translate('common.required') : ''} /> @@ -827,7 +722,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }} disabled={didConfirm} interactive={!isReadOnly} - brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? translate('common.error.enterDate') : ''} /> ), @@ -882,10 +777,10 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ { item: ( Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_RATE.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()))} @@ -899,10 +794,10 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ { item: ( Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()))} @@ -939,7 +834,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ (supplementaryField) => supplementaryField.item, ); - const {image: receiptImage, thumbnail: receiptThumbnail} = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction, receiptPath, receiptFilename) : {}; + const receiptData = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction ?? null, receiptPath, receiptFilename) : null; return ( )} - {receiptImage || receiptThumbnail ? ( + {receiptData?.image ?? receiptData?.thumbnail ? ( ) : ( // The empty receipt component should only show for IOU Requests of a paid policy ("Team" or "Corporate") @@ -1011,21 +906,27 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ MoneyTemporaryForRefactorRequestConfirmationList.displayName = 'MoneyTemporaryForRefactorRequestConfirmationList'; -export default withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, - policyCategories: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, - }, - policyTags: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, - }, - mileageRate: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - selector: DistanceRequestUtils.getDefaultMileageRate, - }, - policy: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - }, -})(MoneyTemporaryForRefactorRequestConfirmationList); + +export default withCurrentUserPersonalDetails( + withOnyx({ + policyCategories: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, + }, + policyTags: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, + }, + mileageRate: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + selector: DistanceRequestUtils.getDefaultMileageRate, + }, + policy: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + }, + iou: { + key: ONYXKEYS.IOU, + }, + session: { + key: ONYXKEYS.SESSION, + }, + })(MoneyTemporaryForRefactorRequestConfirmationList), +); \ No newline at end of file From 9da2bc7fcdf4da0902bf59ccc2bcba0556115b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Tue, 5 Mar 2024 14:12:33 +0100 Subject: [PATCH 021/402] added style and onDismiss props to ReferralProgramCTA --- src/components/ReferralProgramCTA.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/ReferralProgramCTA.tsx b/src/components/ReferralProgramCTA.tsx index 6db37ce1320a..7b8a05cb2a45 100644 --- a/src/components/ReferralProgramCTA.tsx +++ b/src/components/ReferralProgramCTA.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import {ViewStyle} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; @@ -25,15 +26,18 @@ type ReferralProgramCTAProps = ReferralProgramCTAOnyxProps & { | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND; + style?: ViewStyle; + onDismiss?: () => void; }; -function ReferralProgramCTA({referralContentType, dismissedReferralBanners}: ReferralProgramCTAProps) { +function ReferralProgramCTA({referralContentType, dismissedReferralBanners, style, onDismiss}: ReferralProgramCTAProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const theme = useTheme(); const handleDismissCallToAction = () => { User.dismissReferralBanner(referralContentType); + onDismiss?.(); }; if (!referralContentType || dismissedReferralBanners[referralContentType]) { @@ -45,7 +49,7 @@ function ReferralProgramCTA({referralContentType, dismissedReferralBanners}: Ref onPress={() => { Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(referralContentType, Navigation.getActiveRouteWithoutParams())); }} - style={[styles.w100, styles.br2, styles.highlightBG, styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter, {gap: 10, padding: 10}, styles.pl5]} + style={[styles.w100, styles.br2, styles.highlightBG, styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter, {gap: 10, padding: 10}, styles.pl5, style]} accessibilityLabel="referral" role={CONST.ACCESSIBILITY_ROLE.BUTTON} > From 3e8ff507ecd532af567a46646d513990bd25698a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Tue, 5 Mar 2024 17:02:29 +0100 Subject: [PATCH 022/402] removed containers of referral banner and moved their styles to banner --- src/components/OptionsSelector/BaseOptionsSelector.js | 7 ++++--- src/pages/SearchPage/SearchPageFooter.tsx | 8 ++++---- ...oneyTemporaryForRefactorRequestParticipantsSelector.js | 7 ++++--- .../MoneyRequestParticipantsSelector.js | 7 ++++--- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js index c0258f1252ef..53933219f26b 100755 --- a/src/components/OptionsSelector/BaseOptionsSelector.js +++ b/src/components/OptionsSelector/BaseOptionsSelector.js @@ -654,9 +654,10 @@ class BaseOptionsSelector extends Component { )} {this.props.shouldShowReferralCTA && ( - - - + )} {shouldShowFooter && ( diff --git a/src/pages/SearchPage/SearchPageFooter.tsx b/src/pages/SearchPage/SearchPageFooter.tsx index 3d5ebfd2c193..ccfc7867da75 100644 --- a/src/pages/SearchPage/SearchPageFooter.tsx +++ b/src/pages/SearchPage/SearchPageFooter.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import {View} from 'react-native'; import ReferralProgramCTA from '@components/ReferralProgramCTA'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; @@ -8,9 +7,10 @@ function SearchPageFooter() { const themeStyles = useThemeStyles(); return ( - - - + ); } diff --git a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js index 95dda131eab7..2b56d9e3318a 100644 --- a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js +++ b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js @@ -271,9 +271,10 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ () => ( {!dismissedReferralBanners[referralContentType] && ( - - - + )} {shouldShowSplitBillErrorMessage && ( diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js index 3fde970327d7..2607fa49c927 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js @@ -286,9 +286,10 @@ function MoneyRequestParticipantsSelector({ () => ( {!dismissedReferralBanners[referralContentType] && ( - - - + )} {shouldShowSplitBillErrorMessage && ( From a5ea45a256b6924a374ff0879ec40036df008154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Wed, 6 Mar 2024 15:52:15 +0100 Subject: [PATCH 023/402] refactorings --- ios/Podfile.lock | 4 ++-- src/components/FixedFooter.tsx | 3 +++ src/components/ReferralProgramCTA.tsx | 15 ++++++++++--- .../SelectionList/BaseSelectionList.tsx | 4 ++-- src/pages/SearchPage/index.js | 22 ++++++++++++++----- 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 12c0c99c0d9a..829cecbf8da2 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1997,8 +1997,8 @@ SPEC CHECKSUMS: SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a - Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047 + Yoga: 13c8ef87792450193e117976337b8527b49e8c03 PODFILE CHECKSUM: 0ccbb4f2406893c6e9f266dc1e7470dcd72885d2 -COCOAPODS: 1.13.0 +COCOAPODS: 1.15.2 diff --git a/src/components/FixedFooter.tsx b/src/components/FixedFooter.tsx index 35fa4d02f5e0..115714285f74 100644 --- a/src/components/FixedFooter.tsx +++ b/src/components/FixedFooter.tsx @@ -14,6 +14,9 @@ type FixedFooterProps = { function FixedFooter({style, children}: FixedFooterProps) { const styles = useThemeStyles(); + if (!children) { + return null; + } return {children}; } diff --git a/src/components/ReferralProgramCTA.tsx b/src/components/ReferralProgramCTA.tsx index 7b8a05cb2a45..c57d2fa344d4 100644 --- a/src/components/ReferralProgramCTA.tsx +++ b/src/components/ReferralProgramCTA.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import {ViewStyle} from 'react-native'; +import React, {useEffect} from 'react'; +import type {ViewStyle} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; @@ -40,7 +40,16 @@ function ReferralProgramCTA({referralContentType, dismissedReferralBanners, styl onDismiss?.(); }; - if (!referralContentType || dismissedReferralBanners[referralContentType]) { + const shouldShowBanner = referralContentType && !dismissedReferralBanners[referralContentType]; + + useEffect(() => { + if (shouldShowBanner) { + return; + } + onDismiss?.(); + }, [onDismiss, shouldShowBanner]); + + if (!shouldShowBanner) { return null; } diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 9cd37709552b..7778af23112f 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -14,6 +14,7 @@ import Text from '@components/Text'; import TextInput from '@components/TextInput'; import useActiveElementRole from '@hooks/useActiveElementRole'; import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; +import useKeyboardState from '@hooks/useKeyboardState'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -21,7 +22,6 @@ import Log from '@libs/Log'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; -import type {BaseSelectionListProps, ButtonOrCheckBoxRoles, FlattenedSectionsReturn, ListItem, Section, SectionListDataType} from './types'; function BaseSelectionList( { @@ -52,7 +52,6 @@ function BaseSelectionList( showConfirmButton = false, shouldPreventDefaultFocusOnSelectRow = false, containerStyle, - isKeyboardShown = false, disableKeyboardShortcuts = false, children, shouldStopPropagation = false, @@ -78,6 +77,7 @@ function BaseSelectionList( const isFocused = useIsFocused(); const [maxToRenderPerBatch, setMaxToRenderPerBatch] = useState(shouldUseDynamicMaxToRenderPerBatch ? 0 : CONST.MAX_TO_RENDER_PER_BATCH.DEFAULT); const [isInitialSectionListRender, setIsInitialSectionListRender] = useState(true); + const {isKeyboardShown} = useKeyboardState(); /** * Iterates through the sections and items inside each section, and builds 3 arrays along the way: diff --git a/src/pages/SearchPage/index.js b/src/pages/SearchPage/index.js index 1957b19abeb6..0938517f7131 100644 --- a/src/pages/SearchPage/index.js +++ b/src/pages/SearchPage/index.js @@ -5,6 +5,7 @@ import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import {usePersonalDetails} from '@components/OnyxProvider'; +import ReferralProgramCTA from '@components/ReferralProgramCTA'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import UserListItem from '@components/SelectionList/UserListItem'; @@ -21,7 +22,6 @@ import * as Report from '@userActions/Report'; import Timing from '@userActions/Timing'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import SearchPageFooter from './SearchPageFooter'; const propTypes = { /* Onyx Props */ @@ -47,8 +47,6 @@ const setPerformanceTimersEnd = () => { Performance.markEnd(CONST.TIMING.SEARCH_RENDER); }; -const SearchPageFooterInstance = ; - function SearchPage({betas, reports, isSearchingForReports}) { const [isScreenTransitionEnd, setIsScreenTransitionEnd] = useState(false); const {translate} = useLocalize(); @@ -139,6 +137,18 @@ function SearchPage({betas, reports, isSearchingForReports}) { }; const isOptionsDataReady = useMemo(() => ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(personalDetails), [personalDetails]); + const [showFooter, setShowFooter] = useState(true); + + const SearchPageFooter = useMemo( + () => ( + setShowFooter(false)} + /> + ), + [themeStyles], + ); return ( - {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( + {({didScreenTransitionEnd}) => ( <> - + From 2a59f2b2bc0b6e3dedef55f078580cc050ca756f Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Thu, 7 Mar 2024 01:23:45 +0530 Subject: [PATCH 024/402] migrate to typescript --- ...raryForRefactorRequestConfirmationList.tsx | 464 +++++++++--------- src/libs/DistanceRequestUtils.ts | 2 + 2 files changed, 221 insertions(+), 245 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index cfabc8f2b0b6..600e2ccc44ec 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -1,254 +1,258 @@ import {useIsFocused} from '@react-navigation/native'; import {format} from 'date-fns'; -import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react'; -import type {StyleProp, ViewStyle} from 'react-native'; import Str from 'expensify-common/lib/str'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react'; import {View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import type {ValueOf} from 'type-fest'; +import _ from 'underscore'; import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; -import DistanceRequestUtils from '@libs/DistanceRequestUtils'; +import type {StyleProp, ViewStyle} from 'react-native'; +import DistanceRequestUtils, { DefaultMileageRate } from '@libs/DistanceRequestUtils'; import * as IOUUtils from '@libs/IOUUtils'; import Log from '@libs/Log'; -import playSound, {SOUNDS} from '@libs/Sound'; import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReceiptUtils from '@libs/ReceiptUtils'; import * as ReportUtils from '@libs/ReportUtils'; +import playSound, {SOUNDS} from '@libs/Sound'; import * as TransactionUtils from '@libs/TransactionUtils'; +import {policyPropTypes} from '@pages/workspace/withPolicy'; +import type {DropdownOption} from './ButtonWithDropdownMenu/types'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; -import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; -import type * as OnyxTypes from '@src/types/onyx'; -import type {Participant} from '@src/types/onyx/IOU'; -import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; -import type {MileageRate} from '@src/types/onyx/Policy'; -import type DeepValueOf from '@src/types/utils/DeepValueOf'; +import Button from './Button'; +import type {AllRoutes} from '@src/ROUTES'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; +import categoryPropTypes from './categoryPropTypes'; import ConfirmedRoute from './ConfirmedRoute'; import ConfirmModal from './ConfirmModal'; import FormHelpMessage from './FormHelpMessage'; +import * as Expensicons from './Icon/Expensicons'; import Image from './Image'; import MenuItemWithTopDescription from './MenuItemWithTopDescription'; +import optionPropTypes from './optionPropTypes'; import OptionsSelector from './OptionsSelector'; import PDFThumbnail from './PDFThumbnail'; import ReceiptEmptyState from './ReceiptEmptyState'; import SettlementButton from './SettlementButton'; -import ShowMoreButton from './ShowMoreButton'; import Switch from './Switch'; +import tagPropTypes from './tagPropTypes'; import Text from './Text'; -import type {WithCurrentUserPersonalDetailsProps} from './withCurrentUserPersonalDetails'; -import withCurrentUserPersonalDetails from './withCurrentUserPersonalDetails'; -import Button from './Button'; - -type DropdownOption = { - text: string; - value: DeepValueOf; -}; - -type Option = Partial; - -type CategorySection = { - title: string | undefined; - shouldShow: boolean; - indexOffset: number; - data: Option[]; -}; +import transactionPropTypes from './transactionPropTypes'; +import type {OnyxEntry} from 'react-native-onyx'; +import type * as OnyxTypes from '@src/types/onyx'; +import type {Participant} from '@src/types/onyx/IOU'; +import type {ValueOf} from 'type-fest'; +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; +import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from './withCurrentUserPersonalDetails'; type MoneyRequestConfirmationListOnyxProps = { - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: OnyxEntry; - - /** Unit and rate used for if the money request is a distance request */ - mileageRate: OnyxEntry; - /** Collection of categories attached to a policy */ policyCategories: OnyxEntry; /** Collection of tags attached to a policy */ policyTags: OnyxEntry; - /** The policy of root parent report */ + /** The policy of the report */ policy: OnyxEntry; + /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ + iou: OnyxEntry; + /** The session of the logged in user */ session: OnyxEntry; + + /** Unit and rate used for if the money request is a distance request */ + mileageRate: OnyxEntry; }; -type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps & - WithCurrentUserPersonalDetailsProps & { - /** Callback to inform parent modal of success */ - onConfirm?: (selectedParticipants: Participant[]) => void; +type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps & { + /** Callback to inform parent modal of success */ + onConfirm?: (selectedParticipants: Participant[]) => void; - /** Callback to parent modal to send money */ - onSendMoney?: (paymentMethod: PaymentMethodType) => void; + /** Callback to parent modal to send money */ + onSendMoney?: (paymentMethod: PaymentMethodType | undefined) => void; - /** Callback to inform a participant is selected */ - onSelectParticipant?: (option: Participant) => void; + /** Callback to inform a participant is selected */ + onSelectParticipant?: (option: Participant) => void; - /** Should we request a single or multiple participant selection from user */ - hasMultipleParticipants: boolean; + /** Should we request a single or multiple participant selection from user */ + hasMultipleParticipants: boolean; - /** IOU amount */ - iouAmount: number; + /** IOU amount */ + iouAmount: number; - /** IOU comment */ - iouComment?: string; + /** IOU comment */ + iouComment?: string; - /** IOU currency */ - iouCurrencyCode?: string; + /** IOU currency */ + iouCurrencyCode?: string; - /** IOU type */ - iouType?: ValueOf; + /** IOU type */ + iouType?: ValueOf; - /** IOU date */ - iouCreated?: string; + /** IOU date */ + iouCreated?: string; - /** IOU merchant */ - iouMerchant?: string; + /** IOU merchant */ + iouMerchant?: string; - /** IOU Category */ - iouCategory?: string; + /** IOU Category */ + iouCategory?: string; - /** IOU Tag */ - iouTag?: string; + /** IOU Tag */ + iouTag?: string; - /** IOU isBillable */ - iouIsBillable?: boolean; + /** IOU isBillable */ + iouIsBillable?: boolean; - /** Callback to toggle the billable state */ - onToggleBillable?: () => void; + /** Callback to toggle the billable state */ + onToggleBillable?: (isOn: boolean) => void; - /** Selected participants from MoneyRequestModal with login / accountID */ - pickedParticipants: Participant[]; + /** Selected participants from MoneyRequestModal with login / accountID */ + selectedParticipants: Participant[]; - /** Payee of the money request with login */ - payeePersonalDetails?: OnyxEntry; + /** Payee of the money request with login */ + payeePersonalDetails?: OnyxTypes.PersonalDetails; - /** Can the participants be modified or not */ - canModifyParticipants?: boolean; + /** Can the participants be modified or not */ + canModifyParticipants?: boolean; - /** Should the list be read only, and not editable? */ - isReadOnly?: boolean; + /** Should the list be read only, and not editable? */ + isReadOnly?: boolean; - /** Depending on expense report or personal IOU report, respective bank account route */ - bankAccountRoute?: Route; + /** Depending on expense report or personal IOU report, respective bank account route */ + bankAccountRoute?: AllRoutes; - /** The policyID of the request */ - policyID?: string; + /** The policyID of the request */ + policyID?: string; - /** The reportID of the request */ - reportID: string; + /** The reportID of the request */ + reportID?: string; - /** File path of the receipt */ - receiptPath?: string; + /** File path of the receipt */ + receiptPath?: string; - /** File name of the receipt */ - receiptFilename?: string; + /** File name of the receipt */ + receiptFilename?: string; - /** List styles for OptionsSelector */ - listStyles?: StyleProp; + /** List styles for OptionsSelector */ + listStyles?: StyleProp; - /** ID of the transaction that represents the money request */ - transactionID?: string; + /** ID of the transaction that represents the money request */ + transactionID?: string; - /** Whether the money request is a distance request */ - isDistanceRequest?: boolean; + /** Transaction that represents the money request */ + transaction?: OnyxEntry; - /** Whether the money request is a scan request */ - isScanRequest?: boolean; + /** Whether the money request is a distance request */ + isDistanceRequest?: boolean; - /** Whether we're editing a split bill */ - isEditingSplitBill?: boolean; + /** Whether the money request is a scan request */ + isScanRequest?: boolean; - /** Whether we should show the amount, date, and merchant fields. */ - shouldShowSmartScanFields?: boolean; + /** Whether we're editing a split bill */ + isEditingSplitBill?: boolean; - /** A flag for verifying that the current report is a sub-report of a workspace chat */ - isPolicyExpenseChat?: boolean; + /** Whether we should show the amount, date, and merchant fields. */ + shouldShowSmartScanFields?: boolean; - /** Whether there is smartscan failed */ - hasSmartScanFailed?: boolean; + /** A flag for verifying that the current report is a sub-report of a workspace chat */ + isPolicyExpenseChat?: boolean; - /** ID of the report action */ - reportActionID: string; + /** Whether smart scan failed */ + hasSmartScanFailed?: boolean; + + reportActionID?: string; +}; - /** Transaction object */ - transaction: OnyxTypes.Transaction; - }; function MoneyTemporaryForRefactorRequestConfirmationList({ - onConfirm = () => {}, - onSendMoney = () => {}, - onSelectParticipant = () => {}, + transaction, + onSendMoney, + onConfirm, + onSelectParticipant, iouType = CONST.IOU.TYPE.REQUEST, - iouCategory = '', - iouTag = '', - iouIsBillable = false, - onToggleBillable = () => {}, - payeePersonalDetails, - canModifyParticipants = false, - isReadOnly = false, - bankAccountRoute, - policyID, - reportID, - receiptPath, - receiptFilename, - transactionID, - mileageRate, - isDistanceRequest = false, isScanRequest = false, - shouldShowSmartScanFields = true, - isPolicyExpenseChat = false, - transaction, iouAmount, - policyTags, policyCategories, + mileageRate, + isDistanceRequest = false, policy, - iouCurrencyCode, + isPolicyExpenseChat = false, + iouCategory = '', + shouldShowSmartScanFields = true, isEditingSplitBill, - hasSmartScanFailed, + policyTags, + iouCurrencyCode, iouMerchant, - currentUserPersonalDetails, hasMultipleParticipants, - pickedParticipants, + selectedParticipants: pickedParticipants, + payeePersonalDetails: payeePersonalDetails, + iou = { + id: '', + amount: 0, + currency: CONST.CURRENCY.USD, + comment: '', + merchant: '', + category: '', + tag: '', + billable: false, + created: '', + participants: [], + receiptPath: '', + }, + canModifyParticipants: canModifyParticipants = false, session, - iou, - reportActionID, - iouCreated, - listStyles, + isReadOnly = false, + bankAccountRoute = '', + policyID = '', + reportID = '', + receiptPath = '', iouComment, + receiptFilename = '', + listStyles, + iouCreated, + iouIsBillable = false, + onToggleBillable, + iouTag = '', + transactionID = '', + hasSmartScanFailed, + reportActionID, }: MoneyRequestConfirmationListProps) { const theme = useTheme(); const styles = useThemeStyles(); const {translate, toLocaleDigit} = useLocalize(); const {canUseViolations} = usePermissions(); + const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const isTypeRequest = iouType === CONST.IOU.TYPE.REQUEST; const isTypeSplit = iouType === CONST.IOU.TYPE.SPLIT; const isTypeSend = iouType === CONST.IOU.TYPE.SEND; - const {unit, rate, currency} = mileageRate; + const {unit, rate, currency} = mileageRate ?? { + unit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES, + rate: 0, + currency: 'USD', + }; const distance = transaction?.routes?.route0.distance ?? 0; const shouldCalculateDistanceAmount = isDistanceRequest && iouAmount === 0; - const taxRates = policy?.taxRates ?? null; + const taxRates = policy?.taxRates; // A flag for showing the categories field - const shouldShowCategories = isPolicyExpenseChat && (iouCategory || OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {}))); - + const shouldShowCategories = isPolicyExpenseChat && (!!iouCategory || OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {}))); // A flag and a toggler for showing the rest of the form fields const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); @@ -268,22 +272,21 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const shouldShowTax = isPolicyExpenseChat && (policy?.tax?.trackingEnabled ?? policy?.isTaxTrackingEnabled); // A flag for showing the billable field - const shouldShowBillable = !policy?.disabledFields?.defaultBillable ?? true; + const shouldShowBillable = !(policy?.disabledFields?.defaultBillable ?? true); - const hasRoute = TransactionUtils.hasRoute(transaction); + const hasRoute = transaction ? TransactionUtils.hasRoute(transaction) : false; const isDistanceRequestWithPendingRoute = isDistanceRequest && (!hasRoute || !rate); const formattedAmount = isDistanceRequestWithPendingRoute ? '' : CurrencyUtils.convertToDisplayString( - shouldCalculateDistanceAmount ? DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate) : iouAmount, + shouldCalculateDistanceAmount ? DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate ?? 0) : iouAmount, isDistanceRequest ? currency : iouCurrencyCode, ); const formattedTaxAmount = CurrencyUtils.convertToDisplayString(transaction?.taxAmount, iouCurrencyCode); const defaultTaxKey = taxRates?.defaultExternalID; - const defaultTaxName = (defaultTaxKey && `${taxRates.taxes[defaultTaxKey].name} (${taxRates.taxes[defaultTaxKey].value}) • ${translate('common.default')}`) || ''; - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const taxRateTitle = (transaction?.taxRate?.text) || defaultTaxName; + const defaultTaxName = (defaultTaxKey && `${taxRates?.taxes[defaultTaxKey].name} (${taxRates?.taxes[defaultTaxKey].value}) • ${translate('common.default')}`) || ''; + const taxRateTitle = transaction?.taxRate?.text || defaultTaxName; const isFocused = useIsFocused(); const [formError, setFormError] = useState(''); @@ -296,7 +299,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false); const navigateBack = () => { - Navigation.goBack(ROUTES.MONEY_REQUEST_CREATE_TAB_SCAN.getRoute(iouType, transaction.transactionID, reportID)); + Navigation.goBack(ROUTES.MONEY_REQUEST_CREATE_TAB_SCAN.getRoute(iouType, transactionID ?? '', reportID)); }; const shouldDisplayFieldError = useMemo(() => { @@ -304,14 +307,14 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ return false; } - return (!!hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction ?? null)) || (didConfirmSplit && TransactionUtils.areRequiredFieldsEmpty(transaction ?? null)); + return (hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction ?? null)) || (didConfirmSplit && TransactionUtils.areRequiredFieldsEmpty(transaction)); }, [isEditingSplitBill, hasSmartScanFailed, transaction, didConfirmSplit]); const isMerchantEmpty = !iouMerchant || iouMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; const isMerchantRequired = isPolicyExpenseChat && !isScanRequest && shouldShowMerchant; - const isCategoryRequired = canUseViolations && (policy?.requiresCategory ?? false); - const isTagRequired = canUseViolations && (policy?.requiresTag ?? false); + const isCategoryRequired = canUseViolations && lodashGet(policy, 'requiresCategory', false); + const isTagRequired = canUseViolations && lodashGet(policy, 'requiresTag', false); useEffect(() => { if ((!isMerchantRequired && isMerchantEmpty) || !merchantError) { @@ -347,8 +350,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ return; } - const amount = DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate); - IOU.setMoneyRequestAmount_temporaryForRefactor(transaction?.transactionID, amount, currency); + const amount = DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate ?? 0) ; + IOU.setMoneyRequestAmount_temporaryForRefactor(transactionID ?? '', amount, currency ?? ''); }, [shouldCalculateDistanceAmount, distance, rate, unit, transaction, currency]); /** @@ -356,11 +359,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ */ const getParticipantsWithAmount = useCallback( (participantsList: Participant[]) => { - const calculatedIouAmount = IOUUtils.calculateAmount(participantsList.length, iouAmount, iouCurrencyCode ?? ''); - return OptionsListUtils.getIOUConfirmationOptionsFromParticipants( - participantsList, - calculatedIouAmount > 0 ? CurrencyUtils.convertToDisplayString(calculatedIouAmount, iouCurrencyCode) : '', - ); + const amount = IOUUtils.calculateAmount(participantsList.length, iouAmount, iouCurrencyCode ?? 'USD'); + return OptionsListUtils.getIOUConfirmationOptionsFromParticipants(participantsList, amount > 0 ? CurrencyUtils.convertToDisplayString(amount, iouCurrencyCode) : ''); }, [iouAmount, iouCurrencyCode], ); @@ -370,11 +370,10 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ setDidConfirm(false); } - const splitOrRequestOptions: DropdownOption[] = useMemo(() => { + const splitOrRequestOptions: Array> = useMemo(() => { let text; if (isTypeSplit && iouAmount === 0) { text = translate('iou.split'); - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing } else if ((receiptPath && isTypeRequest) || isDistanceRequestWithPendingRoute) { text = translate('iou.request'); if (iouAmount !== 0) { @@ -382,7 +381,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ } } else { const translationKey = isTypeSplit ? 'iou.splitAmount' : 'iou.requestAmount'; - text = translate(translationKey, {amount: formattedAmount}); + text = translate(translationKey, {amount: Number(formattedAmount)}); } return [ { @@ -393,16 +392,16 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }, [isTypeSplit, isTypeRequest, iouType, iouAmount, receiptPath, formattedAmount, isDistanceRequestWithPendingRoute, translate]); const selectedParticipants = useMemo(() => pickedParticipants.filter((participant) => participant.selected), [pickedParticipants]); - const personalDetailsOfPayee = useMemo(() => payeePersonalDetails ?? currentUserPersonalDetails, [payeePersonalDetails, currentUserPersonalDetails]); + const personalDetailsOfPayee = useMemo(() => payeePersonalDetails || currentUserPersonalDetails, [payeePersonalDetails, currentUserPersonalDetails]); const userCanModifyParticipants = useRef(!isReadOnly && canModifyParticipants && hasMultipleParticipants); useEffect(() => { userCanModifyParticipants.current = !isReadOnly && canModifyParticipants && hasMultipleParticipants; }, [isReadOnly, canModifyParticipants, hasMultipleParticipants]); const shouldDisablePaidBySection = userCanModifyParticipants.current; - const optionSelectorSections: CategorySection[] = useMemo(() => { + const optionSelectorSections = useMemo(() => { const sections = []; - cosnt unselectedParticipants = pickedParticipants.filter((participant) => !participant.selected); + const unselectedParticipants = _.filter(pickedParticipants, (participant) => !participant.selected); if (hasMultipleParticipants) { const formattedSelectedParticipants = getParticipantsWithAmount(selectedParticipants); let formattedParticipantsList = _.union(formattedSelectedParticipants, unselectedParticipants); @@ -438,7 +437,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ } else { const formattedSelectedParticipants = _.map(selectedParticipants, (participant) => ({ ...participant, - isDisabled: !participant.isPolicyExpenseChat && ReportUtils.isOptimisticPersonalDetail(participant.accountID), + isDisabled: !participant.isPolicyExpenseChat && ReportUtils.isOptimisticPersonalDetail(participant.accountID ?? -1), })); sections.push({ title: translate('common.to'), @@ -465,10 +464,10 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ if (!hasMultipleParticipants) { return []; } - return [ - ...selectedParticipants, - OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetailsOfPayee, CurrencyUtils.convertToDisplayString(myIOUAmount, iouCurrencyCode)) - ]; + return [...selectedParticipants, OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail( + personalDetailsOfPayee, + iouAmount > 0 ? CurrencyUtils.convertToDisplayString(myIOUAmount, iouCurrencyCode) : '', + )]; }, [selectedParticipants, hasMultipleParticipants, personalDetailsOfPayee]); useEffect(() => { @@ -481,33 +480,36 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ When the user completes the initial steps of the IOU flow offline and then goes online on the confirmation page. In this scenario, the route will be fetched from the server, and the waypoints will no longer be pending. */ - IOU.setMoneyRequestPendingFields(transaction.transactionID, {waypoints: isDistanceRequestWithPendingRoute ? CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD : null}); + IOU.setMoneyRequestPendingFields(transactionID, {waypoints: isDistanceRequestWithPendingRoute ? CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD : null}); - const distanceMerchant = DistanceRequestUtils.getDistanceMerchant(hasRoute, distance, unit, rate, currency, translate, toLocaleDigit); - IOU.setMoneyRequestMerchant(transaction.transactionID, distanceMerchant, true); + const distanceMerchant = DistanceRequestUtils.getDistanceMerchant(hasRoute, distance, unit, rate ?? 0, currency ?? 'USD', translate, toLocaleDigit); + IOU.setMoneyRequestMerchant(transactionID, distanceMerchant, true); }, [isDistanceRequestWithPendingRoute, hasRoute, distance, unit, rate, currency, translate, toLocaleDigit, isDistanceRequest, transaction]); + /** + */ const selectParticipant = useCallback( (option: Participant) => { // Return early if selected option is currently logged in user. if (option.accountID === session?.accountID) { return; } - onSelectParticipant(option); + onSelectParticipant?.(option); }, [session?.accountID, onSelectParticipant], ); /** * Navigate to report details or profile of selected user + * @param {Object} option */ - const navigateToReportOrUserDetail = (option: Participant | OnyxTypes.Report) => { - if ('accountID' in option && option.accountID) { - const activeRoute = Navigation.getActiveRouteWithoutParams(); + const navigateToReportOrUserDetail = (option: ReportUtils.OptionData) => { + const activeRoute = Navigation.getActiveRouteWithoutParams(); + if (option.accountID) { Navigation.navigate(ROUTES.PROFILE.getRoute(option.accountID, activeRoute)); - } else if ('reportID' in option && option.reportID) { - Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(option.reportID)); + } else if (option.reportID) { + Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(option.reportID, activeRoute)); } }; @@ -516,7 +518,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ */ const confirm = useCallback( (paymentMethod: PaymentMethodType | undefined) => { - if (selectedParticipants.length === 0) { + if (_.isEmpty(selectedParticipants)) { return; } if ((isMerchantRequired && isMerchantEmpty) || (shouldDisplayFieldError && TransactionUtils.isMerchantMissing(transaction))) { @@ -532,7 +534,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ setDidConfirm(true); Log.info(`[IOU] Sending money via: ${paymentMethod}`); - onSendMoney(paymentMethod); + onSendMoney?.(paymentMethod); } else { // validate the amount for distance requests const decimals = CurrencyUtils.getCurrencyDecimals(iouCurrencyCode); @@ -541,7 +543,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ return; } - if (isEditingSplitBill && TransactionUtils.areRequiredFieldsEmpty(transaction)) { + if (isEditingSplitBill && TransactionUtils.areRequiredFieldsEmpty(transaction ?? null)) { setDidConfirmSplit(true); setFormError('iou.error.genericSmartscanFailureMessage'); return; @@ -549,7 +551,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ playSound(SOUNDS.DONE); setDidConfirm(true); - onConfirm(selectedParticipants); + onConfirm?.(selectedParticipants); } }, [ @@ -603,7 +605,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ success pressOnEnter isDisabled={shouldDisableButton} - onPress={(_, value) => confirm(value as PaymentMethodType)} + onPress={(_event, value) => confirm(value as PaymentMethodType)} options={splitOrRequestOptions} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.LARGE} enterKeyEventListenerPriority={1} @@ -640,16 +642,16 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ return; } if (isEditingSplitBill) { - Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(reportID, reportActionID, CONST.EDIT_REQUEST_FIELD.AMOUNT)); + Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(reportID, reportActionID ?? '', CONST.EDIT_REQUEST_FIELD.AMOUNT)); return; } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams())); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams())); }} style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} disabled={didConfirm} - brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} - error={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction) ? translate('common.error.enterAmount') : ''} + brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction ?? null) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + error={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction ?? null) ? translate('common.error.enterAmount') : ''} /> ), shouldShow: shouldShowSmartScanFields, @@ -665,7 +667,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ description={translate('common.description')} onPress={() => { Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams()), ); }} style={[styles.moneyRequestMenuItem]} @@ -711,7 +713,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }} disabled={didConfirm} interactive={!isReadOnly} - brickRoadIndicator={merchantError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} + brickRoadIndicator={merchantError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} error={merchantError ? translate('common.error.fieldRequired') : ''} rightLabel={isMerchantRequired ? translate('common.required') : ''} /> @@ -735,7 +737,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }} disabled={didConfirm} interactive={!isReadOnly} - brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} + brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} error={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? translate('common.error.enterDate') : ''} /> ), @@ -752,7 +754,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ numberOfLinesTitle={2} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), ) } style={[styles.moneyRequestMenuItem]} @@ -775,7 +777,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ numberOfLinesTitle={2} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.CREATE, iouType, index, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.CREATE, iouType, index, transaction?.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), ) } style={[styles.moneyRequestMenuItem]} @@ -807,10 +809,10 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ { item: ( Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()))} @@ -847,8 +849,6 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ (supplementaryField) => supplementaryField.item, ); - const receiptData = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction ?? null, receiptPath, receiptFilename) : null; - const { image: receiptImage, thumbnail: receiptThumbnail, @@ -902,29 +902,6 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ )} - {receiptData?.image ?? receiptData?.thumbnail ? ( - - ) : ( - // The empty receipt component should only show for IOU Requests of a paid policy ("Team" or "Corporate") - PolicyUtils.isPaidGroupPolicy(policy) && - !isDistanceRequest && - iouType === CONST.IOU.TYPE.REQUEST && ( - - Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), - ) - } - /> - ) - )} {receiptImage || receiptThumbnail ? receiptThumbnailContent : // The empty receipt component should only show for IOU Requests of a paid policy ("Team" or "Corporate") @@ -970,29 +947,26 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ } -MoneyTemporaryForRefactorRequestConfirmationList.displayName = 'MoneyTemporaryForRefactorRequestConfirmationList'; - - -export default withCurrentUserPersonalDetails( - withOnyx({ - policyCategories: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, - }, - policyTags: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, - }, - mileageRate: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - selector: DistanceRequestUtils.getDefaultMileageRate, - }, - policy: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - }, - iou: { - key: ONYXKEYS.IOU, - }, - session: { - key: ONYXKEYS.SESSION, - }, - })(MoneyTemporaryForRefactorRequestConfirmationList), -); \ No newline at end of file +MoneyTemporaryForRefactorRequestConfirmationList.displayName = 'MoneyRequestConfirmationList'; + +export default withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + policyCategories: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, + }, + policyTags: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, + }, + mileageRate: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + selector: DistanceRequestUtils.getDefaultMileageRate, + }, + policy: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + }, + iou: { + key: ONYXKEYS.IOU, + }, +})(MoneyTemporaryForRefactorRequestConfirmationList); \ No newline at end of file diff --git a/src/libs/DistanceRequestUtils.ts b/src/libs/DistanceRequestUtils.ts index a42cb6a8f756..7a98351bb4e6 100644 --- a/src/libs/DistanceRequestUtils.ts +++ b/src/libs/DistanceRequestUtils.ts @@ -125,3 +125,5 @@ function getDistanceRequestAmount(distance: number, unit: Unit, rate: number): n } export default {getDefaultMileageRate, getDistanceMerchant, getDistanceRequestAmount}; + +export type {DefaultMileageRate}; \ No newline at end of file From 4e06aac89868862de833391217c015ab943d3c02 Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Thu, 7 Mar 2024 02:10:05 +0530 Subject: [PATCH 025/402] Migrate to typescript --- .../ButtonWithDropdownMenu/types.ts | 4 +- ...raryForRefactorRequestConfirmationList.tsx | 83 +++++++++---------- src/libs/TransactionUtils.ts | 18 ++-- 3 files changed, 49 insertions(+), 56 deletions(-) diff --git a/src/components/ButtonWithDropdownMenu/types.ts b/src/components/ButtonWithDropdownMenu/types.ts index 9975c10c13c3..1ad4f9f66a1b 100644 --- a/src/components/ButtonWithDropdownMenu/types.ts +++ b/src/components/ButtonWithDropdownMenu/types.ts @@ -13,7 +13,7 @@ type WorkspaceMemberBulkActionType = DeepValueOf = { value: TValueType; text: string; - icon: IconAsset; + icon?: IconAsset; iconWidth?: number; iconHeight?: number; iconDescription?: string; @@ -56,7 +56,7 @@ type ButtonWithDropdownMenuProps = { anchorAlignment?: AnchorAlignment; /* ref for the button */ - buttonRef: RefObject; + buttonRef?: RefObject; /** The priority to assign the enter key event listener to buttons. 0 is the highest priority. */ enterKeyEventListenerPriority?: number; diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index 600e2ccc44ec..fa8d97fa1ec3 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -1,8 +1,6 @@ import {useIsFocused} from '@react-navigation/native'; import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; @@ -35,28 +33,23 @@ import ROUTES from '@src/ROUTES'; import Button from './Button'; import type {AllRoutes} from '@src/ROUTES'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; -import categoryPropTypes from './categoryPropTypes'; import ConfirmedRoute from './ConfirmedRoute'; import ConfirmModal from './ConfirmModal'; import FormHelpMessage from './FormHelpMessage'; import * as Expensicons from './Icon/Expensicons'; import Image from './Image'; import MenuItemWithTopDescription from './MenuItemWithTopDescription'; -import optionPropTypes from './optionPropTypes'; import OptionsSelector from './OptionsSelector'; import PDFThumbnail from './PDFThumbnail'; import ReceiptEmptyState from './ReceiptEmptyState'; import SettlementButton from './SettlementButton'; import Switch from './Switch'; -import tagPropTypes from './tagPropTypes'; import Text from './Text'; -import transactionPropTypes from './transactionPropTypes'; import type {OnyxEntry} from 'react-native-onyx'; import type * as OnyxTypes from '@src/types/onyx'; import type {Participant} from '@src/types/onyx/IOU'; import type {ValueOf} from 'type-fest'; import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; -import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from './withCurrentUserPersonalDetails'; type MoneyRequestConfirmationListOnyxProps = { /** Collection of categories attached to a policy */ @@ -299,7 +292,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false); const navigateBack = () => { - Navigation.goBack(ROUTES.MONEY_REQUEST_CREATE_TAB_SCAN.getRoute(iouType, transactionID ?? '', reportID)); + Navigation.goBack(ROUTES.MONEY_REQUEST_CREATE_TAB_SCAN.getRoute(iouType, transaction?.transactionID ?? '', reportID)); }; const shouldDisplayFieldError = useMemo(() => { @@ -307,14 +300,14 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ return false; } - return (hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction ?? null)) || (didConfirmSplit && TransactionUtils.areRequiredFieldsEmpty(transaction)); + return (hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction ?? null)) || (didConfirmSplit && TransactionUtils.areRequiredFieldsEmpty(transaction ?? null)); }, [isEditingSplitBill, hasSmartScanFailed, transaction, didConfirmSplit]); const isMerchantEmpty = !iouMerchant || iouMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; const isMerchantRequired = isPolicyExpenseChat && !isScanRequest && shouldShowMerchant; - const isCategoryRequired = canUseViolations && lodashGet(policy, 'requiresCategory', false); - const isTagRequired = canUseViolations && lodashGet(policy, 'requiresTag', false); + const isCategoryRequired = canUseViolations && (policy?.requiresCategory ?? false); + const isTagRequired = canUseViolations && (policy?.requiresTag ?? false); useEffect(() => { if ((!isMerchantRequired && isMerchantEmpty) || !merchantError) { @@ -350,8 +343,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ return; } - const amount = DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate ?? 0) ; - IOU.setMoneyRequestAmount_temporaryForRefactor(transactionID ?? '', amount, currency ?? ''); + const amount = DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate ?? 0); + IOU.setMoneyRequestAmount_temporaryForRefactor(transaction?.transactionID ?? '', amount, currency ?? ''); }, [shouldCalculateDistanceAmount, distance, rate, unit, transaction, currency]); /** @@ -381,7 +374,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ } } else { const translationKey = isTypeSplit ? 'iou.splitAmount' : 'iou.requestAmount'; - text = translate(translationKey, {amount: Number(formattedAmount)}); + text = translate(translationKey, {amount: formattedAmount}); } return [ { @@ -480,10 +473,10 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ When the user completes the initial steps of the IOU flow offline and then goes online on the confirmation page. In this scenario, the route will be fetched from the server, and the waypoints will no longer be pending. */ - IOU.setMoneyRequestPendingFields(transactionID, {waypoints: isDistanceRequestWithPendingRoute ? CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD : null}); + IOU.setMoneyRequestPendingFields(transaction?.transactionID ?? '', {waypoints: isDistanceRequestWithPendingRoute ? CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD : null}); const distanceMerchant = DistanceRequestUtils.getDistanceMerchant(hasRoute, distance, unit, rate ?? 0, currency ?? 'USD', translate, toLocaleDigit); - IOU.setMoneyRequestMerchant(transactionID, distanceMerchant, true); + IOU.setMoneyRequestMerchant(transaction?.transactionID ?? '', distanceMerchant, true); }, [isDistanceRequestWithPendingRoute, hasRoute, distance, unit, rate, currency, translate, toLocaleDigit, isDistanceRequest, transaction]); /** @@ -521,7 +514,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ if (_.isEmpty(selectedParticipants)) { return; } - if ((isMerchantRequired && isMerchantEmpty) || (shouldDisplayFieldError && TransactionUtils.isMerchantMissing(transaction))) { + if ((isMerchantRequired && isMerchantEmpty) || (shouldDisplayFieldError && TransactionUtils.isMerchantMissing(transaction ?? null))) { setMerchantError(true); return; } @@ -645,12 +638,12 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(reportID, reportActionID ?? '', CONST.EDIT_REQUEST_FIELD.AMOUNT)); return; } - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams())); + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_AMOUNT.getRoute(iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams())); }} style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} disabled={didConfirm} - brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction ?? null) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction ?? null) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={shouldDisplayFieldError && TransactionUtils.isAmountMissing(transaction ?? null) ? translate('common.error.enterAmount') : ''} /> ), @@ -667,7 +660,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ description={translate('common.description')} onPress={() => { Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), ); }} style={[styles.moneyRequestMenuItem]} @@ -689,7 +682,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ description={translate('common.distance')} style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} - onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()))} + onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()))} disabled={didConfirm || !isTypeRequest} interactive={!isReadOnly} /> @@ -708,12 +701,12 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ titleStyle={styles.flex1} onPress={() => { Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), ); }} disabled={didConfirm} interactive={!isReadOnly} - brickRoadIndicator={merchantError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={merchantError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={merchantError ? translate('common.error.fieldRequired') : ''} rightLabel={isMerchantRequired ? translate('common.required') : ''} /> @@ -732,12 +725,12 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ titleStyle={styles.flex1} onPress={() => { Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_DATE.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_DATE.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), ); }} disabled={didConfirm} interactive={!isReadOnly} - brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + brickRoadIndicator={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} error={shouldDisplayFieldError && TransactionUtils.isCreatedMissing(transaction) ? translate('common.error.enterDate') : ''} /> ), @@ -754,7 +747,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ numberOfLinesTitle={2} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), ) } style={[styles.moneyRequestMenuItem]} @@ -772,12 +765,12 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.CREATE, iouType, index, transaction?.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.CREATE, iouType, index, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), ) } style={[styles.moneyRequestMenuItem]} @@ -798,7 +791,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ description={taxRates?.name} style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} - onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_RATE.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()))} + onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_RATE.getRoute(iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()))} disabled={didConfirm} interactive={!isReadOnly} /> @@ -809,13 +802,13 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ { item: ( Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()))} + onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()))} disabled={didConfirm} interactive={!isReadOnly} /> @@ -830,7 +823,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ onToggleBillable?.(isOn)} /> ), @@ -839,21 +832,21 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }, ]; - const primaryFields = _.map( - _.filter(classifiedFields, (classifiedField) => classifiedField.shouldShow && !classifiedField.isSupplementary), - (primaryField) => primaryField.item, - ); + const primaryFields = classifiedFields + .filter(classifiedField => classifiedField.shouldShow && !classifiedField.isSupplementary) + .map(primaryField => primaryField.item); + + + const supplementaryFields = classifiedFields + .filter(classifiedField => classifiedField.shouldShow && classifiedField.isSupplementary) + .map(supplementaryField => supplementaryField.item); - const supplementaryFields = _.map( - _.filter(classifiedFields, (classifiedField) => classifiedField.shouldShow && classifiedField.isSupplementary), - (supplementaryField) => supplementaryField.item, - ); const { image: receiptImage, thumbnail: receiptThumbnail, isLocalFile, - } = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction, receiptPath, receiptFilename) : {}; + } = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction ?? null, receiptPath, receiptFilename) : {}; const receiptThumbnailContent = useMemo( () => @@ -899,7 +892,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ > {isDistanceRequest && ( - + )} {receiptImage || receiptThumbnail @@ -911,7 +904,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), ) } /> @@ -947,7 +940,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ } -MoneyTemporaryForRefactorRequestConfirmationList.displayName = 'MoneyRequestConfirmationList'; +MoneyTemporaryForRefactorRequestConfirmationList.displayName = 'MoneyTemporaryForRefactorRequestConfirmationList'; export default withOnyx({ session: { diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 8a98fe0f2cdc..c1b7573a8188 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -140,11 +140,11 @@ function hasReceipt(transaction: Transaction | undefined | null): boolean { return !!transaction?.receipt?.state || hasEReceipt(transaction); } -function isMerchantMissing(transaction: Transaction) { - if (transaction.modifiedMerchant && transaction.modifiedMerchant !== '') { +function isMerchantMissing(transaction: OnyxEntry) { + if (transaction?.modifiedMerchant && transaction.modifiedMerchant !== '') { return transaction.modifiedMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; } - const isMerchantEmpty = transaction.merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || transaction.merchant === ''; + const isMerchantEmpty = transaction?.merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || transaction?.merchant === ''; return isMerchantEmpty; } @@ -156,18 +156,18 @@ function isPartialMerchant(merchant: string): boolean { return merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; } -function isAmountMissing(transaction: Transaction) { - return transaction.amount === 0 && (!transaction.modifiedAmount || transaction.modifiedAmount === 0); +function isAmountMissing(transaction: OnyxEntry) { + return transaction?.amount === 0 && (!transaction.modifiedAmount || transaction.modifiedAmount === 0); } -function isCreatedMissing(transaction: Transaction) { - return transaction.created === '' && (!transaction.created || transaction.modifiedCreated === ''); +function isCreatedMissing(transaction: OnyxEntry | undefined) { + return transaction?.created === '' && (!transaction.created || transaction.modifiedCreated === ''); } -function areRequiredFieldsEmpty(transaction: Transaction): boolean { +function areRequiredFieldsEmpty(transaction: OnyxEntry): boolean { const parentReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`] ?? null; const isFromExpenseReport = parentReport?.type === CONST.REPORT.TYPE.EXPENSE; - const isSplitPolicyExpenseChat = !!transaction.comment?.splits?.some((participant) => allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]?.isOwnPolicyExpenseChat); + const isSplitPolicyExpenseChat = !!transaction?.comment?.splits?.some((participant) => allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]?.isOwnPolicyExpenseChat); const isMerchantRequired = isFromExpenseReport || isSplitPolicyExpenseChat; return (isMerchantRequired && isMerchantMissing(transaction)) || isAmountMissing(transaction) || isCreatedMissing(transaction); } From 4b2e38e4ffd8aecf04fbe6fad349334883a40071 Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Thu, 7 Mar 2024 02:33:48 +0530 Subject: [PATCH 026/402] Migrate to typescript --- ...raryForRefactorRequestConfirmationList.tsx | 120 ++++++++++++------ src/libs/DistanceRequestUtils.ts | 2 +- src/libs/OptionsListUtils.ts | 2 +- 3 files changed, 81 insertions(+), 43 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index fa8d97fa1ec3..e78b8aeeaa68 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -3,17 +3,19 @@ import {format} from 'date-fns'; import Str from 'expensify-common/lib/str'; import React, {useCallback, useEffect, useMemo, useReducer, useRef, useState} from 'react'; import {View} from 'react-native'; +import type {StyleProp, ViewStyle} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import type {ValueOf} from 'type-fest'; import _ from 'underscore'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; -import type {StyleProp, ViewStyle} from 'react-native'; -import DistanceRequestUtils, { DefaultMileageRate } from '@libs/DistanceRequestUtils'; +import DistanceRequestUtils, {DefaultMileageRate} from '@libs/DistanceRequestUtils'; import * as IOUUtils from '@libs/IOUUtils'; import Log from '@libs/Log'; import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; @@ -25,14 +27,17 @@ import * as ReportUtils from '@libs/ReportUtils'; import playSound, {SOUNDS} from '@libs/Sound'; import * as TransactionUtils from '@libs/TransactionUtils'; import {policyPropTypes} from '@pages/workspace/withPolicy'; -import type {DropdownOption} from './ButtonWithDropdownMenu/types'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import Button from './Button'; import type {AllRoutes} from '@src/ROUTES'; +import type * as OnyxTypes from '@src/types/onyx'; +import type {Participant} from '@src/types/onyx/IOU'; +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; +import Button from './Button'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; +import type {DropdownOption} from './ButtonWithDropdownMenu/types'; import ConfirmedRoute from './ConfirmedRoute'; import ConfirmModal from './ConfirmModal'; import FormHelpMessage from './FormHelpMessage'; @@ -45,11 +50,6 @@ import ReceiptEmptyState from './ReceiptEmptyState'; import SettlementButton from './SettlementButton'; import Switch from './Switch'; import Text from './Text'; -import type {OnyxEntry} from 'react-native-onyx'; -import type * as OnyxTypes from '@src/types/onyx'; -import type {Participant} from '@src/types/onyx/IOU'; -import type {ValueOf} from 'type-fest'; -import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; type MoneyRequestConfirmationListOnyxProps = { /** Collection of categories attached to a policy */ @@ -171,7 +171,6 @@ type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps & reportActionID?: string; }; - function MoneyTemporaryForRefactorRequestConfirmationList({ transaction, onSendMoney, @@ -394,13 +393,13 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const optionSelectorSections = useMemo(() => { const sections = []; - const unselectedParticipants = _.filter(pickedParticipants, (participant) => !participant.selected); + const unselectedParticipants = pickedParticipants.filter((participant) => !participant.selected); if (hasMultipleParticipants) { const formattedSelectedParticipants = getParticipantsWithAmount(selectedParticipants); - let formattedParticipantsList = _.union(formattedSelectedParticipants, unselectedParticipants); + let formattedParticipantsList = [...new Set([...formattedSelectedParticipants, ...unselectedParticipants])]; - if (!userCanModifyParticipants.current) { - formattedParticipantsList = _.map(formattedParticipantsList, (participant) => ({ + if (!canModifyParticipants) { + formattedParticipantsList = formattedParticipantsList.map((participant) => ({ ...participant, isDisabled: ReportUtils.isOptimisticPersonalDetail(participant.accountID ?? -1), })); @@ -457,10 +456,15 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ if (!hasMultipleParticipants) { return []; } - return [...selectedParticipants, OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail( - personalDetailsOfPayee, - iouAmount > 0 ? CurrencyUtils.convertToDisplayString(myIOUAmount, iouCurrencyCode) : '', - )]; + + const myIOUAmount = IOUUtils.calculateAmount(selectedParticipants.length, iouAmount, iouCurrencyCode ?? '', true); + return [ + ...selectedParticipants, + OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail( + personalDetailsOfPayee, + iouAmount > 0 ? CurrencyUtils.convertToDisplayString(myIOUAmount, iouCurrencyCode) : '', + ), + ]; }, [selectedParticipants, hasMultipleParticipants, personalDetailsOfPayee]); useEffect(() => { @@ -607,13 +611,14 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ return ( <> - {!_.isEmpty(formError) && ( + {formError && ( )} + {button} ); @@ -660,7 +665,13 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ description={translate('common.description')} onPress={() => { Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.getRoute( + CONST.IOU.ACTION.CREATE, + iouType, + transaction?.transactionID ?? '', + reportID, + Navigation.getActiveRouteWithoutParams(), + ), ); }} style={[styles.moneyRequestMenuItem]} @@ -682,7 +693,9 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ description={translate('common.distance')} style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} - onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()))} + onPress={() => + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams())) + } disabled={didConfirm || !isTypeRequest} interactive={!isReadOnly} /> @@ -701,7 +714,13 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ titleStyle={styles.flex1} onPress={() => { Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_MERCHANT.getRoute( + CONST.IOU.ACTION.CREATE, + iouType, + transaction?.transactionID ?? '', + reportID, + Navigation.getActiveRouteWithoutParams(), + ), ); }} disabled={didConfirm} @@ -747,7 +766,13 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ numberOfLinesTitle={2} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute( + CONST.IOU.ACTION.CREATE, + iouType, + transaction?.transactionID ?? '', + reportID, + Navigation.getActiveRouteWithoutParams(), + ), ) } style={[styles.moneyRequestMenuItem]} @@ -770,7 +795,14 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ numberOfLinesTitle={2} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.CREATE, iouType, index, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute( + CONST.IOU.ACTION.CREATE, + iouType, + index, + transaction?.transactionID ?? '', + reportID, + Navigation.getActiveRouteWithoutParams(), + ), ) } style={[styles.moneyRequestMenuItem]} @@ -791,7 +823,9 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ description={taxRates?.name} style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} - onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_RATE.getRoute(iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()))} + onPress={() => + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_RATE.getRoute(iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams())) + } disabled={didConfirm} interactive={!isReadOnly} /> @@ -808,7 +842,9 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ description={taxRates?.name} style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} - onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()))} + onPress={() => + Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams())) + } disabled={didConfirm} interactive={!isReadOnly} /> @@ -832,27 +868,23 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }, ]; - const primaryFields = classifiedFields - .filter(classifiedField => classifiedField.shouldShow && !classifiedField.isSupplementary) - .map(primaryField => primaryField.item); - + const primaryFields = classifiedFields.filter((classifiedField) => classifiedField.shouldShow && !classifiedField.isSupplementary).map((primaryField) => primaryField.item); const supplementaryFields = classifiedFields - .filter(classifiedField => classifiedField.shouldShow && classifiedField.isSupplementary) - .map(supplementaryField => supplementaryField.item); - + .filter((classifiedField) => classifiedField.shouldShow && classifiedField.isSupplementary) + .map((supplementaryField) => supplementaryField.item); const { image: receiptImage, thumbnail: receiptThumbnail, isLocalFile, - } = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction ?? null, receiptPath, receiptFilename) : {}; + } = receiptPath && receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(transaction ?? null, receiptPath, receiptFilename) : ({} as ReceiptUtils.ThumbnailAndImageURI); const receiptThumbnailContent = useMemo( () => isLocalFile && Str.isPDF(receiptFilename) ? ( ), [receiptFilename, receiptImage, styles, receiptThumbnail, isLocalFile, isAttachmentInvalid], ); return ( + // @ts-expect-error This component is deprecated and will not be migrated to TypeScript (context: https://expensify.slack.com/archives/C01GTK53T8Q/p1709232289899589?thread_ts=1709156803.359359&cid=C01GTK53T8Q) Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute( + CONST.IOU.ACTION.CREATE, + iouType, + transaction?.transactionID ?? '', + reportID, + Navigation.getActiveRouteWithoutParams(), + ), ) } /> @@ -939,7 +978,6 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ ); } - MoneyTemporaryForRefactorRequestConfirmationList.displayName = 'MoneyTemporaryForRefactorRequestConfirmationList'; export default withOnyx({ @@ -962,4 +1000,4 @@ export default withOnyx, personalDetails: On /** * Build the IOUConfirmation options for showing the payee personalDetail */ -function getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetail: PersonalDetails, amountText: string): PayeePersonalDetails { +function getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetail: PersonalDetails | EmptyObject, amountText: string): PayeePersonalDetails { const formattedLogin = LocalePhoneNumber.formatPhoneNumber(personalDetail.login ?? ''); return { text: PersonalDetailsUtils.getDisplayNameOrDefault(personalDetail, formattedLogin), From 352b991de4b4c3d7b9605f8cf5ab1cba900f264b Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Thu, 7 Mar 2024 03:06:36 +0530 Subject: [PATCH 027/402] Lint fix --- ...raryForRefactorRequestConfirmationList.tsx | 35 +++++-------------- src/components/PopoverMenu.tsx | 2 +- src/libs/OptionsListUtils.ts | 1 + 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index 0b50b1ca8c8b..25b6ee579af6 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -7,15 +7,14 @@ import type {StyleProp, ViewStyle} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; -import _ from 'underscore'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; -import DistanceRequestUtils, {DefaultMileageRate} from '@libs/DistanceRequestUtils'; +import DistanceRequestUtils from '@libs/DistanceRequestUtils'; +import type {DefaultMileageRate} from '@libs/DistanceRequestUtils'; import * as IOUUtils from '@libs/IOUUtils'; import Log from '@libs/Log'; import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; @@ -26,7 +25,6 @@ import * as ReceiptUtils from '@libs/ReceiptUtils'; import * as ReportUtils from '@libs/ReportUtils'; import playSound, {SOUNDS} from '@libs/Sound'; import * as TransactionUtils from '@libs/TransactionUtils'; -import {policyPropTypes} from '@pages/workspace/withPolicy'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -192,21 +190,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ iouMerchant, hasMultipleParticipants, selectedParticipants: pickedParticipants, - payeePersonalDetails: payeePersonalDetails, - iou = { - id: '', - amount: 0, - currency: CONST.CURRENCY.USD, - comment: '', - merchant: '', - category: '', - tag: '', - billable: false, - created: '', - participants: [], - receiptPath: '', - }, - canModifyParticipants: canModifyParticipants = false, + payeePersonalDetails, + canModifyParticipants = false, session, isReadOnly = false, bankAccountRoute = '', @@ -219,15 +204,12 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ iouCreated, iouIsBillable = false, onToggleBillable, - iouTag = '', - transactionID = '', hasSmartScanFailed, reportActionID, }: MoneyRequestConfirmationListProps) { const theme = useTheme(); const styles = useThemeStyles(); const {translate, toLocaleDigit} = useLocalize(); - const {canUseViolations} = usePermissions(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const {canUseP2PDistanceRequests, canUseViolations} = usePermissions(); const isTypeRequest = iouType === CONST.IOU.TYPE.REQUEST; @@ -428,7 +410,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }, ); } else { - const formattedSelectedParticipants = _.map(selectedParticipants, (participant) => ({ + const formattedSelectedParticipants = selectedParticipants.map((participant) => ({ ...participant, isDisabled: !participant.isPolicyExpenseChat && ReportUtils.isOptimisticPersonalDetail(participant.accountID ?? -1), })); @@ -451,6 +433,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ translate, shouldDisablePaidBySection, userCanModifyParticipants, + canModifyParticipants, ]); const selectedOptions = useMemo(() => { @@ -482,7 +465,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const distanceMerchant = DistanceRequestUtils.getDistanceMerchant(hasRoute, distance, unit, rate ?? 0, currency ?? 'USD', translate, toLocaleDigit); IOU.setMoneyRequestMerchant(transaction?.transactionID ?? '', distanceMerchant, true); - }, [isDistanceRequestWithPendingRoute, hasRoute, distance, unit, rate, currency, translate, toLocaleDigit, isDistanceRequest, transaction]); + }, [isDistanceRequestWithPendingRoute, hasRoute, distance, unit, rate, currency, translate, toLocaleDigit, isDistanceRequest, transaction, iouAmount, iouCurrencyCode]); /** */ @@ -516,7 +499,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ */ const confirm = useCallback( (paymentMethod: PaymentMethodType | undefined) => { - if (_.isEmpty(selectedParticipants)) { + if (selectedParticipants.length === 0) { return; } if ((isMerchantRequired && isMerchantEmpty) || (shouldDisplayFieldError && TransactionUtils.isMerchantMissing(transaction ?? null))) { @@ -787,7 +770,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ shouldShow: shouldShowCategories, isSupplementary: !isCategoryRequired, }, - ..._.map(policyTagLists, ({name}, index) => ({ + ...policyTagLists.map(({name}, index) => ({ item: ( Date: Thu, 7 Mar 2024 03:25:34 +0530 Subject: [PATCH 028/402] Lint fix --- ...raryForRefactorRequestConfirmationList.tsx | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index 25b6ee579af6..7b0da116b196 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -59,9 +59,6 @@ type MoneyRequestConfirmationListOnyxProps = { /** The policy of the report */ policy: OnyxEntry; - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: OnyxEntry; - /** The session of the logged in user */ session: OnyxEntry; @@ -103,9 +100,6 @@ type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps & /** IOU Category */ iouCategory?: string; - /** IOU Tag */ - iouTag?: string; - /** IOU isBillable */ iouIsBillable?: boolean; @@ -260,8 +254,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const formattedTaxAmount = CurrencyUtils.convertToDisplayString(transaction?.taxAmount, iouCurrencyCode); const defaultTaxKey = taxRates?.defaultExternalID; - const defaultTaxName = (defaultTaxKey && `${taxRates?.taxes[defaultTaxKey].name} (${taxRates?.taxes[defaultTaxKey].value}) • ${translate('common.default')}`) || ''; - const taxRateTitle = transaction?.taxRate?.text || defaultTaxName; + const defaultTaxName = (defaultTaxKey && `${taxRates?.taxes[defaultTaxKey].name} (${taxRates?.taxes[defaultTaxKey].value}) • ${translate('common.default')}`) ?? ''; + const taxRateTitle = transaction?.taxRate?.text ?? defaultTaxName; const isFocused = useIsFocused(); const [formError, setFormError] = useState(''); @@ -282,7 +276,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ return false; } - return (hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction ?? null)) || (didConfirmSplit && TransactionUtils.areRequiredFieldsEmpty(transaction ?? null)); + return (hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction ?? null)) ?? (didConfirmSplit && TransactionUtils.areRequiredFieldsEmpty(transaction ?? null)); }, [isEditingSplitBill, hasSmartScanFailed, transaction, didConfirmSplit]); const isMerchantEmpty = !iouMerchant || iouMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; @@ -367,7 +361,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ }, [isTypeSplit, isTypeRequest, iouType, iouAmount, receiptPath, formattedAmount, isDistanceRequestWithPendingRoute, translate]); const selectedParticipants = useMemo(() => pickedParticipants.filter((participant) => participant.selected), [pickedParticipants]); - const personalDetailsOfPayee = useMemo(() => payeePersonalDetails || currentUserPersonalDetails, [payeePersonalDetails, currentUserPersonalDetails]); + const personalDetailsOfPayee = useMemo(() => payeePersonalDetails ?? currentUserPersonalDetails, [payeePersonalDetails, currentUserPersonalDetails]); const userCanModifyParticipants = useRef(!isReadOnly && canModifyParticipants && hasMultipleParticipants); useEffect(() => { userCanModifyParticipants.current = !isReadOnly && canModifyParticipants && hasMultipleParticipants; @@ -432,7 +426,6 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ personalDetailsOfPayee, translate, shouldDisablePaidBySection, - userCanModifyParticipants, canModifyParticipants, ]); @@ -449,7 +442,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ iouAmount > 0 ? CurrencyUtils.convertToDisplayString(myIOUAmount, iouCurrencyCode) : '', ), ]; - }, [selectedParticipants, hasMultipleParticipants, personalDetailsOfPayee]); + }, [selectedParticipants, hasMultipleParticipants, personalDetailsOfPayee, iouAmount, iouCurrencyCode]); useEffect(() => { if (!isDistanceRequest) { @@ -465,7 +458,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const distanceMerchant = DistanceRequestUtils.getDistanceMerchant(hasRoute, distance, unit, rate ?? 0, currency ?? 'USD', translate, toLocaleDigit); IOU.setMoneyRequestMerchant(transaction?.transactionID ?? '', distanceMerchant, true); - }, [isDistanceRequestWithPendingRoute, hasRoute, distance, unit, rate, currency, translate, toLocaleDigit, isDistanceRequest, transaction, iouAmount, iouCurrencyCode]); + }, [isDistanceRequestWithPendingRoute, hasRoute, distance, unit, rate, currency, translate, toLocaleDigit, isDistanceRequest, transaction]); /** */ @@ -482,7 +475,6 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ /** * Navigate to report details or profile of selected user - * @param {Object} option */ const navigateToReportOrUserDetail = (option: ReportUtils.OptionData) => { const activeRoute = Navigation.getActiveRouteWithoutParams(); @@ -586,7 +578,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ success pressOnEnter isDisabled={shouldDisableButton} - onPress={(_event, value) => confirm(value as PaymentMethodType)} + onPress={(event, value) => confirm(value as PaymentMethodType)} options={splitOrRequestOptions} buttonSize={CONST.DROPDOWN_BUTTON_SIZE.LARGE} enterKeyEventListenerPriority={1} @@ -723,7 +715,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, }, - iou: { - key: ONYXKEYS.IOU, - }, })(MoneyTemporaryForRefactorRequestConfirmationList); From 9f07370908dd9a0f5b66781b6b756c3c92d882a9 Mon Sep 17 00:00:00 2001 From: Nathalie Kuoch Date: Mon, 4 Mar 2024 16:13:12 +0100 Subject: [PATCH 029/402] Clean up vbba code and save each substep --- src/hooks/useSubStep/index.ts | 6 ++- src/hooks/useSubStep/types.ts | 3 ++ .../AcceptACHContractForBankAccount.ts | 2 +- .../parameters/ConnectBankAccountParams.ts | 1 - .../OpenReimbursementAccountPageParams.ts | 1 - ...ateBeneficialOwnersForBankAccountParams.ts | 4 +- ...eCompanyInformationForBankAccountParams.ts | 2 +- ...PersonalInformationForBankAccountParams.ts | 2 +- .../VerifyIdentityForBankAccountParams.ts | 1 - src/libs/actions/BankAccounts.ts | 18 ++++----- .../BusinessInfo/BusinessInfo.tsx | 38 ++++++++++++------- .../PersonalInfo/PersonalInfo.tsx | 19 ++++++++-- 12 files changed, 60 insertions(+), 37 deletions(-) diff --git a/src/hooks/useSubStep/index.ts b/src/hooks/useSubStep/index.ts index ad4cf032858d..2d9069abff88 100644 --- a/src/hooks/useSubStep/index.ts +++ b/src/hooks/useSubStep/index.ts @@ -6,8 +6,9 @@ import type {SubStepProps, UseSubStep} from './types'; * @param bodyContent - array of components to display in particular step * @param onFinished - callback triggered after finish last step * @param startFrom - initial index for bodyContent array + * @param onNextSubStep - callback triggered after finish each step */ -export default function useSubStep({bodyContent, onFinished, startFrom = 0}: UseSubStep) { +export default function useSubStep({bodyContent, onFinished, startFrom = 0, onNextSubStep = () => {}}: UseSubStep) { const [screenIndex, setScreenIndex] = useState(startFrom); const isEditing = useRef(false); @@ -35,9 +36,10 @@ export default function useSubStep({bodyContent, on if (nextScreenIndex === bodyContent.length) { onFinished(); } else { + onNextSubStep(); setScreenIndex(nextScreenIndex); } - }, [screenIndex, bodyContent.length, onFinished]); + }, [screenIndex, bodyContent.length, onFinished, onNextSubStep]); const moveTo = useCallback((step: number) => { isEditing.current = true; diff --git a/src/hooks/useSubStep/types.ts b/src/hooks/useSubStep/types.ts index ffdee5825197..f3b7939502a8 100644 --- a/src/hooks/useSubStep/types.ts +++ b/src/hooks/useSubStep/types.ts @@ -21,6 +21,9 @@ type UseSubStep = { /** array of components that will become sub steps */ bodyContent: Array>; + /** called after each sub step */ + onNextSubStep?: () => void; + /** called on last sub step */ onFinished: () => void; diff --git a/src/libs/API/parameters/AcceptACHContractForBankAccount.ts b/src/libs/API/parameters/AcceptACHContractForBankAccount.ts index de4ce4e86857..11ea73bd3a34 100644 --- a/src/libs/API/parameters/AcceptACHContractForBankAccount.ts +++ b/src/libs/API/parameters/AcceptACHContractForBankAccount.ts @@ -1,5 +1,5 @@ import type {ACHContractStepProps} from '@src/types/form/ReimbursementAccountForm'; -type AcceptACHContractForBankAccount = ACHContractStepProps & {bankAccountID: number; policyID: string; canUseNewVbbaFlow?: boolean}; +type AcceptACHContractForBankAccount = ACHContractStepProps & {bankAccountID: number; policyID: string}; export default AcceptACHContractForBankAccount; diff --git a/src/libs/API/parameters/ConnectBankAccountParams.ts b/src/libs/API/parameters/ConnectBankAccountParams.ts index fb0e3422d08c..b4a4f1d71150 100644 --- a/src/libs/API/parameters/ConnectBankAccountParams.ts +++ b/src/libs/API/parameters/ConnectBankAccountParams.ts @@ -8,7 +8,6 @@ type ConnectBankAccountParams = { plaidMask?: string; isSavings?: boolean; policyID?: string; - canUseNewVbbaFlow?: boolean; }; export default ConnectBankAccountParams; diff --git a/src/libs/API/parameters/OpenReimbursementAccountPageParams.ts b/src/libs/API/parameters/OpenReimbursementAccountPageParams.ts index 31eb443ce80e..8e4ae5208a2e 100644 --- a/src/libs/API/parameters/OpenReimbursementAccountPageParams.ts +++ b/src/libs/API/parameters/OpenReimbursementAccountPageParams.ts @@ -7,7 +7,6 @@ type OpenReimbursementAccountPageParams = { stepToOpen: ReimbursementAccountStep; subStep: ReimbursementAccountSubStep; localCurrentStep: ReimbursementAccountStep; - canUseNewVbbaFlow?: boolean; policyID: string; }; diff --git a/src/libs/API/parameters/UpdateBeneficialOwnersForBankAccountParams.ts b/src/libs/API/parameters/UpdateBeneficialOwnersForBankAccountParams.ts index dedc45d0365f..310565573454 100644 --- a/src/libs/API/parameters/UpdateBeneficialOwnersForBankAccountParams.ts +++ b/src/libs/API/parameters/UpdateBeneficialOwnersForBankAccountParams.ts @@ -1,5 +1,5 @@ -import type {ACHContractStepProps} from '@src/types/form/ReimbursementAccountForm'; +import type {BeneficialOwnersStepProps} from '@src/types/form/ReimbursementAccountForm'; -type UpdateBeneficialOwnersForBankAccountParams = Partial & {bankAccountID: number; policyID: string; canUseNewVbbaFlow?: boolean}; +type UpdateBeneficialOwnersForBankAccountParams = Partial & {bankAccountID: number; policyID: string}; export default UpdateBeneficialOwnersForBankAccountParams; diff --git a/src/libs/API/parameters/UpdateCompanyInformationForBankAccountParams.ts b/src/libs/API/parameters/UpdateCompanyInformationForBankAccountParams.ts index 6421fe02f571..c427e26d6c92 100644 --- a/src/libs/API/parameters/UpdateCompanyInformationForBankAccountParams.ts +++ b/src/libs/API/parameters/UpdateCompanyInformationForBankAccountParams.ts @@ -2,6 +2,6 @@ import type {BankAccountStepProps, CompanyStepProps, ReimbursementAccountProps} type BankAccountCompanyInformation = BankAccountStepProps & CompanyStepProps & ReimbursementAccountProps; -type UpdateCompanyInformationForBankAccountParams = Partial & {bankAccountID: number; policyID: string; canUseNewVbbaFlow?: boolean}; +type UpdateCompanyInformationForBankAccountParams = Partial & {bankAccountID: number; policyID: string; confirm: boolean}; export default UpdateCompanyInformationForBankAccountParams; diff --git a/src/libs/API/parameters/UpdatePersonalInformationForBankAccountParams.ts b/src/libs/API/parameters/UpdatePersonalInformationForBankAccountParams.ts index c1a29ddd9cec..4b4876b2863f 100644 --- a/src/libs/API/parameters/UpdatePersonalInformationForBankAccountParams.ts +++ b/src/libs/API/parameters/UpdatePersonalInformationForBankAccountParams.ts @@ -1,5 +1,5 @@ import type {RequestorStepProps} from '@src/types/form/ReimbursementAccountForm'; -type UpdatePersonalInformationForBankAccountParams = RequestorStepProps & {bankAccountID: number; policyID: string; canUseNewVbbaFlow: boolean}; +type UpdatePersonalInformationForBankAccountParams = RequestorStepProps & {bankAccountID: number; policyID: string; confirm: boolean}; export default UpdatePersonalInformationForBankAccountParams; diff --git a/src/libs/API/parameters/VerifyIdentityForBankAccountParams.ts b/src/libs/API/parameters/VerifyIdentityForBankAccountParams.ts index c11aec9be239..6ef6b3712439 100644 --- a/src/libs/API/parameters/VerifyIdentityForBankAccountParams.ts +++ b/src/libs/API/parameters/VerifyIdentityForBankAccountParams.ts @@ -2,6 +2,5 @@ type VerifyIdentityForBankAccountParams = { bankAccountID: number; onfidoData: string; policyID: string; - canUseNewVbbaFlow?: boolean; }; export default VerifyIdentityForBankAccountParams; diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts index 0f4e1aed36a7..367826e4e644 100644 --- a/src/libs/actions/BankAccounts.ts +++ b/src/libs/actions/BankAccounts.ts @@ -160,7 +160,6 @@ function connectBankAccountWithPlaid(bankAccountID: number, selectedPlaidBankAcc plaidAccessToken: selectedPlaidBankAccount.plaidAccessToken, plaidMask: selectedPlaidBankAccount.mask, isSavings: selectedPlaidBankAccount.isSavings, - canUseNewVbbaFlow: true, policyID, }; @@ -254,15 +253,17 @@ function deletePaymentBankAccount(bankAccountID: number) { * This action is called by the requestor step in the Verified Bank Account flow * @param bankAccountID - ID for bank account * @param params - User personal data + * @param policyID - ID of the policy we're setting the bank account on + * @param isConfirmPage - If we're submitting from the confirmation substep, to trigger all external checks */ -function updatePersonalInformationForBankAccount(bankAccountID: number, params: RequestorStepProps, policyID: string) { +function updatePersonalInformationForBankAccount(bankAccountID: number, params: RequestorStepProps, policyID: string, isConfirmPage: boolean) { API.write( WRITE_COMMANDS.UPDATE_PERSONAL_INFORMATION_FOR_BANK_ACCOUNT, { ...params, bankAccountID, policyID, - canUseNewVbbaFlow: true, + confirm: isConfirmPage, }, getVBBADataForOnyx(CONST.BANK_ACCOUNT.STEP.REQUESTOR), ); @@ -356,7 +357,6 @@ function openReimbursementAccountPage(stepToOpen: ReimbursementAccountStep, subS subStep, localCurrentStep, policyID, - canUseNewVbbaFlow: true, }; return API.read(READ_COMMANDS.OPEN_REIMBURSEMENT_ACCOUNT_PAGE, parameters, onyxData); @@ -365,15 +365,17 @@ function openReimbursementAccountPage(stepToOpen: ReimbursementAccountStep, subS /** * Updates the bank account in the database with the company step data * @param params - Business step form data + * @param policyID - ID of the policy we're setting the bank account on + * @param isConfirmPage - If we're submitting from the confirmation substep, to trigger all external checks */ -function updateCompanyInformationForBankAccount(bankAccountID: number, params: Partial, policyID: string) { +function updateCompanyInformationForBankAccount(bankAccountID: number, params: Partial, policyID: string, isConfirmPage: boolean) { API.write( WRITE_COMMANDS.UPDATE_COMPANY_INFORMATION_FOR_BANK_ACCOUNT, { ...params, bankAccountID, policyID, - canUseNewVbbaFlow: true, + confirm: isConfirmPage, }, getVBBADataForOnyx(CONST.BANK_ACCOUNT.STEP.COMPANY), ); @@ -390,7 +392,6 @@ function updateBeneficialOwnersForBankAccount(bankAccountID: number, params: Par ...params, bankAccountID, policyID, - canUseNewVbbaFlow: true, }, getVBBADataForOnyx(), ); @@ -407,7 +408,6 @@ function acceptACHContractForBankAccount(bankAccountID: number, params: ACHContr ...params, bankAccountID, policyID, - canUseNewVbbaFlow: true, }, getVBBADataForOnyx(), ); @@ -426,7 +426,6 @@ function connectBankAccountManually(bankAccountID: number, bankAccount: PlaidBan plaidAccessToken: bankAccount.plaidAccessToken, plaidMask: bankAccount.mask, isSavings: bankAccount.isSavings, - canUseNewVbbaFlow: true, policyID, }; @@ -441,7 +440,6 @@ function verifyIdentityForBankAccount(bankAccountID: number, onfidoData: Record< bankAccountID, onfidoData: JSON.stringify(onfidoData), policyID, - canUseNewVbbaFlow: true, }; API.write(WRITE_COMMANDS.VERIFY_IDENTITY_FOR_BANK_ACCOUNT, parameters, getVBBADataForOnyx()); diff --git a/src/pages/ReimbursementAccount/BusinessInfo/BusinessInfo.tsx b/src/pages/ReimbursementAccount/BusinessInfo/BusinessInfo.tsx index f63cf72f8a4f..593408b60589 100644 --- a/src/pages/ReimbursementAccount/BusinessInfo/BusinessInfo.tsx +++ b/src/pages/ReimbursementAccount/BusinessInfo/BusinessInfo.tsx @@ -71,22 +71,34 @@ function BusinessInfo({reimbursementAccount, reimbursementAccountDraft, onBackBu const policyID = reimbursementAccount?.achData?.policyID ?? ''; const values = useMemo(() => getSubstepValues(BUSINESS_INFO_STEP_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]); - const submit = useCallback(() => { - BankAccounts.updateCompanyInformationForBankAccount( - Number(reimbursementAccount?.achData?.bankAccountID ?? '0'), - { - ...values, - ...getBankAccountFields(['routingNumber', 'accountNumber', 'bankName', 'plaidAccountID', 'plaidAccessToken', 'isSavings']), - companyTaxID: values.companyTaxID?.replace(CONST.REGEX.NON_NUMERIC, ''), - companyPhone: parsePhoneNumber(values.companyPhone ?? '', {regionCode: CONST.COUNTRY.US}).number?.significant, - }, - policyID, - ); - }, [reimbursementAccount, values, getBankAccountFields, policyID]); + const submit = useCallback( + (isConfirmPage: boolean) => { + BankAccounts.updateCompanyInformationForBankAccount( + Number(reimbursementAccount?.achData?.bankAccountID ?? '0'), + { + ...values, + ...getBankAccountFields(['routingNumber', 'accountNumber', 'bankName', 'plaidAccountID', 'plaidAccessToken', 'isSavings']), + companyTaxID: values.companyTaxID?.replace(CONST.REGEX.NON_NUMERIC, ''), + companyPhone: parsePhoneNumber(values.companyPhone ?? '', {regionCode: CONST.COUNTRY.US}).number?.significant, + }, + policyID, + isConfirmPage, + ); + }, + [reimbursementAccount, values, getBankAccountFields, policyID], + ); const startFrom = useMemo(() => getInitialSubstepForBusinessInfo(values), [values]); - const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo, goToTheLastStep} = useSubStep({bodyContent, startFrom, onFinished: submit}); + const { + componentToRender: SubStep, + isEditing, + screenIndex, + nextScreen, + prevScreen, + moveTo, + goToTheLastStep, + } = useSubStep({bodyContent, startFrom, onFinished: () => submit(true), onNextSubStep: () => submit(false)}); const handleBackButtonPress = () => { if (isEditing) { diff --git a/src/pages/ReimbursementAccount/PersonalInfo/PersonalInfo.tsx b/src/pages/ReimbursementAccount/PersonalInfo/PersonalInfo.tsx index ce37cd4aa4e2..41c08ddc95dd 100644 --- a/src/pages/ReimbursementAccount/PersonalInfo/PersonalInfo.tsx +++ b/src/pages/ReimbursementAccount/PersonalInfo/PersonalInfo.tsx @@ -46,12 +46,23 @@ function PersonalInfo({reimbursementAccount, reimbursementAccountDraft, onBackBu const policyID = reimbursementAccount?.achData?.policyID ?? ''; const values = useMemo(() => getSubstepValues(PERSONAL_INFO_STEP_KEYS, reimbursementAccountDraft, reimbursementAccount), [reimbursementAccount, reimbursementAccountDraft]); const bankAccountID = Number(reimbursementAccount?.achData?.bankAccountID ?? '0'); - const submit = useCallback(() => { - BankAccounts.updatePersonalInformationForBankAccount(bankAccountID, {...values}, policyID); - }, [values, bankAccountID, policyID]); + const submit = useCallback( + (isConfirmPage: boolean) => { + BankAccounts.updatePersonalInformationForBankAccount(bankAccountID, {...values}, policyID, isConfirmPage); + }, + [values, bankAccountID, policyID], + ); const startFrom = useMemo(() => getInitialSubstepForPersonalInfo(values), [values]); - const {componentToRender: SubStep, isEditing, screenIndex, nextScreen, prevScreen, moveTo, goToTheLastStep} = useSubStep({bodyContent, startFrom, onFinished: submit}); + const { + componentToRender: SubStep, + isEditing, + screenIndex, + nextScreen, + prevScreen, + moveTo, + goToTheLastStep, + } = useSubStep({bodyContent, startFrom, onFinished: () => submit(true), onNextSubStep: () => submit(false)}); const handleBackButtonPress = () => { if (isEditing) { From fff37fd547ea412fefb8178e90b5c1dbb6254d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Fri, 8 Mar 2024 17:30:52 +0100 Subject: [PATCH 030/402] refactorings --- ios/NewExpensify.xcodeproj/project.pbxproj | 336 +++++++++--------- ios/Podfile | 3 +- ios/Podfile.lock | 102 +----- src/components/FixedFooter.tsx | 10 +- src/components/OnyxProvider.tsx | 3 + src/components/ReferralProgramCTA.tsx | 27 +- src/hooks/useDismissedReferralBanners.ts | 28 ++ src/pages/SearchPage/index.js | 57 ++- ...yForRefactorRequestParticipantsSelector.js | 79 ++-- .../step/IOURequestStepParticipants.js | 2 +- .../MoneyRequestParticipantsSelector.js | 26 +- 11 files changed, 275 insertions(+), 398 deletions(-) create mode 100644 src/hooks/useDismissedReferralBanners.ts diff --git a/ios/NewExpensify.xcodeproj/project.pbxproj b/ios/NewExpensify.xcodeproj/project.pbxproj index acfc4d933954..ce65dd95943e 100644 --- a/ios/NewExpensify.xcodeproj/project.pbxproj +++ b/ios/NewExpensify.xcodeproj/project.pbxproj @@ -22,20 +22,20 @@ 1246A3EF20E54E7A9494C8B9 /* ExpensifyNeue-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = F4F8A052A22040339996324B /* ExpensifyNeue-Regular.otf */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 18D050E0262400AF000D658B /* BridgingFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18D050DF262400AF000D658B /* BridgingFile.swift */; }; + 2239AF82201DDCACD764BB13 /* libPods-NotificationServiceExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FBC515608ED5B1C9BB3BBE1E /* libPods-NotificationServiceExtension.a */; }; 26AF3C3540374A9FACB6C19E /* ExpensifyMono-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = DCF33E34FFEC48128CDD41D4 /* ExpensifyMono-Bold.otf */; }; 2A9F8CDA983746B0B9204209 /* ExpensifyNeue-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 52796131E6554494B2DDB056 /* ExpensifyNeue-Bold.otf */; }; 30581EA8AAFD4FCE88C5D191 /* ExpensifyNeue-Italic.otf in Resources */ = {isa = PBXBuildFile; fileRef = BF6A4C5167244B9FB8E4D4E3 /* ExpensifyNeue-Italic.otf */; }; 374FB8D728A133FE000D84EF /* OriginImageRequestHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 374FB8D628A133FE000D84EF /* OriginImageRequestHandler.mm */; }; - 5B8996A7D8B007ECC41919E1 /* libPods-NewExpensify.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00D7E69E5ADD16FD4C44221B /* libPods-NewExpensify.a */; }; + 5F93148A4BA62318A8A7C645 /* libPods-NewExpensify.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 693BF633137EC7920817D909 /* libPods-NewExpensify.a */; }; 7041848526A8E47D00E09F4D /* RCTStartupTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7041848426A8E47D00E09F4D /* RCTStartupTimer.m */; }; 7041848626A8E47D00E09F4D /* RCTStartupTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7041848426A8E47D00E09F4D /* RCTStartupTimer.m */; }; 70CF6E82262E297300711ADC /* BootSplash.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 70CF6E81262E297300711ADC /* BootSplash.storyboard */; }; - 716815DBCE9F49D420334791 /* libPods-NewExpensify-NewExpensifyTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B68AEB9429D8BB73F25A188C /* libPods-NewExpensify-NewExpensifyTests.a */; }; + 7E087A75A723CA54A1A24B29 /* libPods-NewExpensify-NewExpensifyTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AF7D26E85173CA31D45150D2 /* libPods-NewExpensify-NewExpensifyTests.a */; }; 7F5E81F06BCCF61AD02CEA06 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCD444BEDDB0AF1745B39049 /* ExpoModulesProvider.swift */; }; 7F9DD8DA2B2A445B005E3AFA /* ExpError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F9DD8D92B2A445B005E3AFA /* ExpError.swift */; }; 7FD73C9E2B23CE9500420AF3 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FD73C9D2B23CE9500420AF3 /* NotificationService.swift */; }; 7FD73CA22B23CE9500420AF3 /* NotificationServiceExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 7FD73C9B2B23CE9500420AF3 /* NotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - B8A1CD44D011AD7AE180DE14 /* libPods-NotificationServiceExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B944D5699A54FD5197A63866 /* libPods-NotificationServiceExtension.a */; }; BDB853621F354EBB84E619C2 /* ExpensifyNewKansas-MediumItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = D2AFB39EC1D44BF9B91D3227 /* ExpensifyNewKansas-MediumItalic.otf */; }; DD79042B2792E76D004484B4 /* RCTBootSplash.m in Sources */ = {isa = PBXBuildFile; fileRef = DD79042A2792E76D004484B4 /* RCTBootSplash.m */; }; DDCB2E57F334C143AC462B43 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D20D83B0E39BA6D21761E72 /* ExpoModulesProvider.swift */; }; @@ -79,10 +79,8 @@ /* Begin PBXFileReference section */ 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; - 00D7E69E5ADD16FD4C44221B /* libPods-NewExpensify.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NewExpensify.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356EE1AD99517003FC87E /* NewExpensifyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NewExpensifyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 030F99CEB3AEF1F11B001798 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig"; sourceTree = ""; }; 083353E72B5AB22900C603C0 /* attention.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = attention.mp3; path = ../assets/sounds/attention.mp3; sourceTree = ""; }; 083353E82B5AB22900C603C0 /* done.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = done.mp3; path = ../assets/sounds/done.mp3; sourceTree = ""; }; 083353E92B5AB22900C603C0 /* receive.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = receive.mp3; path = ../assets/sounds/receive.mp3; sourceTree = ""; }; @@ -92,55 +90,57 @@ 0F5BE0CD252686320097D869 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 0F5E534E263B73D5004CA14F /* EnvironmentChecker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EnvironmentChecker.h; sourceTree = ""; }; 0F5E534F263B73FD004CA14F /* EnvironmentChecker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EnvironmentChecker.m; sourceTree = ""; }; - 0FF2BC0D01CA2C62CE94229E /* Pods-NewExpensify.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugdevelopment.xcconfig"; sourceTree = ""; }; - 11B2BA236BB72A603FBB7B99 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releasedevelopment.xcconfig"; sourceTree = ""; }; - 12EB734390650799DB8AC627 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugdevelopment.xcconfig"; sourceTree = ""; }; + 118316C3ED3B8AF1B8DDB462 /* Pods-NewExpensify.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releaseproduction.xcconfig"; sourceTree = ""; }; + 1326323F1F0F6464B455D650 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releasedevelopment.xcconfig"; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* New Expensify Dev.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "New Expensify Dev.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = NewExpensify/AppDelegate.h; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = NewExpensify/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = NewExpensify/main.m; sourceTree = ""; }; 18D050DF262400AF000D658B /* BridgingFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BridgingFile.swift; sourceTree = ""; }; - 3328C9B8861CA667C42B47F3 /* Pods-NewExpensify.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugproduction.xcconfig"; sourceTree = ""; }; + 28D3313BDBBA720056DD2D1D /* Pods-NewExpensify.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugdevelopment.xcconfig"; sourceTree = ""; }; + 2C134EA1A00BF7EE88676822 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugproduction.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugproduction.xcconfig"; sourceTree = ""; }; + 2E51C885FF70D2D7A54456E6 /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig"; sourceTree = ""; }; 374FB8D528A133A7000D84EF /* OriginImageRequestHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OriginImageRequestHandler.h; path = NewExpensify/OriginImageRequestHandler.h; sourceTree = ""; }; 374FB8D628A133FE000D84EF /* OriginImageRequestHandler.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = OriginImageRequestHandler.mm; path = NewExpensify/OriginImageRequestHandler.mm; sourceTree = ""; }; + 3ADC0A6CC754720C1DC37C70 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugdevelopment.xcconfig"; sourceTree = ""; }; 44BF435285B94E5B95F90994 /* ExpensifyNewKansas-Medium.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNewKansas-Medium.otf"; path = "../assets/fonts/native/ExpensifyNewKansas-Medium.otf"; sourceTree = ""; }; - 466D03D63F4B48E009C04FA3 /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig"; sourceTree = ""; }; + 487DEEE877D99104D2B59897 /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig"; sourceTree = ""; }; 4D20D83B0E39BA6D21761E72 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-NewExpensify/ExpoModulesProvider.swift"; sourceTree = ""; }; 52796131E6554494B2DDB056 /* ExpensifyNeue-Bold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNeue-Bold.otf"; path = "../assets/fonts/native/ExpensifyNeue-Bold.otf"; sourceTree = ""; }; - 5A1F158A9A6CBE170EC19D9C /* Pods-NewExpensify.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugadhoc.xcconfig"; sourceTree = ""; }; + 5AD4EA6C51AF26EE4290EDDF /* Pods-NewExpensify.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releasedevelopment.xcconfig"; sourceTree = ""; }; + 693BF633137EC7920817D909 /* libPods-NewExpensify.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NewExpensify.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 7041848326A8E40900E09F4D /* RCTStartupTimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RCTStartupTimer.h; path = NewExpensify/RCTStartupTimer.h; sourceTree = ""; }; 7041848426A8E47D00E09F4D /* RCTStartupTimer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RCTStartupTimer.m; path = NewExpensify/RCTStartupTimer.m; sourceTree = ""; }; 70CF6E81262E297300711ADC /* BootSplash.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = BootSplash.storyboard; path = NewExpensify/BootSplash.storyboard; sourceTree = ""; }; - 7312B334B72E8BE41A811FAB /* Pods-NewExpensify.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releaseadhoc.xcconfig"; sourceTree = ""; }; + 7815BCDA0F80A5988AE4FE23 /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig"; sourceTree = ""; }; + 7A64A8F5BD1DA6D2B1C999A6 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig"; sourceTree = ""; }; 7F9DD8D92B2A445B005E3AFA /* ExpError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpError.swift; sourceTree = ""; }; 7FD73C9B2B23CE9500420AF3 /* NotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 7FD73C9D2B23CE9500420AF3 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; 7FD73C9F2B23CE9500420AF3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 802CB9E7554756F188C79554 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugadhoc.xcconfig"; sourceTree = ""; }; + 895D008CD95C08405C079218 /* Pods-NewExpensify.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugproduction.xcconfig"; sourceTree = ""; }; 8B28D84EF339436DBD42A203 /* ExpensifyNeue-BoldItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNeue-BoldItalic.otf"; path = "../assets/fonts/native/ExpensifyNeue-BoldItalic.otf"; sourceTree = ""; }; - 96ADA7C82BA6A08C4A56344A /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releaseproduction.xcconfig"; sourceTree = ""; }; - 972584042DB4782F830B063A /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig"; sourceTree = ""; }; - 9EADA69D62F2E7B3D96E5B1C /* Pods-NewExpensify.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releaseproduction.xcconfig"; sourceTree = ""; }; - AC9422F6C8A49AE701481721 /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releaseadhoc.xcconfig"; sourceTree = ""; }; - B4CF7147C89747459BAC5BB7 /* Pods-NewExpensify.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releasedevelopment.xcconfig"; sourceTree = ""; }; - B68AEB9429D8BB73F25A188C /* libPods-NewExpensify-NewExpensifyTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NewExpensify-NewExpensifyTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - B944D5699A54FD5197A63866 /* libPods-NotificationServiceExtension.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NotificationServiceExtension.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + A672C55E4E62105209DA6787 /* Pods-NewExpensify.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugadhoc.xcconfig"; sourceTree = ""; }; + AF7D26E85173CA31D45150D2 /* libPods-NewExpensify-NewExpensifyTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NewExpensify-NewExpensifyTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + BCAF64296F330579F0E7B41B /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig"; sourceTree = ""; }; BCD444BEDDB0AF1745B39049 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-NewExpensify-NewExpensifyTests/ExpoModulesProvider.swift"; sourceTree = ""; }; BF6A4C5167244B9FB8E4D4E3 /* ExpensifyNeue-Italic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNeue-Italic.otf"; path = "../assets/fonts/native/ExpensifyNeue-Italic.otf"; sourceTree = ""; }; - CB32BB7E082E2450F04DA6E7 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugproduction.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugproduction.xcconfig"; sourceTree = ""; }; - D15262BE5F713CDB4DA576AE /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig"; sourceTree = ""; }; + C4BB00AA2BEAE6FCE6E069CA /* Pods-NewExpensify.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releaseadhoc.xcconfig"; sourceTree = ""; }; + CCE8C26BA229E4E25F239908 /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releaseproduction.xcconfig"; sourceTree = ""; }; D2AFB39EC1D44BF9B91D3227 /* ExpensifyNewKansas-MediumItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNewKansas-MediumItalic.otf"; path = "../assets/fonts/native/ExpensifyNewKansas-MediumItalic.otf"; sourceTree = ""; }; + D9EBB16906B99F38BCCDD92C /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releaseadhoc.xcconfig"; sourceTree = ""; }; DCF33E34FFEC48128CDD41D4 /* ExpensifyMono-Bold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyMono-Bold.otf"; path = "../assets/fonts/native/ExpensifyMono-Bold.otf"; sourceTree = ""; }; DD7904292792E76D004484B4 /* RCTBootSplash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTBootSplash.h; path = NewExpensify/RCTBootSplash.h; sourceTree = ""; }; DD79042A2792E76D004484B4 /* RCTBootSplash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTBootSplash.m; path = NewExpensify/RCTBootSplash.m; sourceTree = ""; }; + E4BC28C56B6C1763152D4F93 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugadhoc.xcconfig"; sourceTree = ""; }; E704648954784DDFBAADF568 /* ExpensifyMono-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyMono-Regular.otf"; path = "../assets/fonts/native/ExpensifyMono-Regular.otf"; sourceTree = ""; }; - E750C93A45B47BDC5149C5AA /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig"; sourceTree = ""; }; E9DF872C2525201700607FDC /* AirshipConfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = AirshipConfig.plist; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; }; F0C450E92705020500FD2970 /* colors.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = colors.json; path = ../colors.json; sourceTree = ""; }; F4F8A052A22040339996324B /* ExpensifyNeue-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNeue-Regular.otf"; path = "../assets/fonts/native/ExpensifyNeue-Regular.otf"; sourceTree = ""; }; - F98306ABF3F272DF04DF65CC /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig"; sourceTree = ""; }; + F82148F45FC67E2D0CCB54DB /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig"; sourceTree = ""; }; + FBC515608ED5B1C9BB3BBE1E /* libPods-NotificationServiceExtension.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NotificationServiceExtension.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -148,7 +148,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 716815DBCE9F49D420334791 /* libPods-NewExpensify-NewExpensifyTests.a in Frameworks */, + 7E087A75A723CA54A1A24B29 /* libPods-NewExpensify-NewExpensifyTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -158,7 +158,7 @@ files = ( E51DC681C7DEE40AEBDDFBFE /* BuildFile in Frameworks */, E51DC681C7DEE40AEBDDFBFE /* BuildFile in Frameworks */, - 5B8996A7D8B007ECC41919E1 /* libPods-NewExpensify.a in Frameworks */, + 5F93148A4BA62318A8A7C645 /* libPods-NewExpensify.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -166,7 +166,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - B8A1CD44D011AD7AE180DE14 /* libPods-NotificationServiceExtension.a in Frameworks */, + 2239AF82201DDCACD764BB13 /* libPods-NotificationServiceExtension.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -212,9 +212,9 @@ children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, ED2971642150620600B7C4FE /* JavaScriptCore.framework */, - 00D7E69E5ADD16FD4C44221B /* libPods-NewExpensify.a */, - B68AEB9429D8BB73F25A188C /* libPods-NewExpensify-NewExpensifyTests.a */, - B944D5699A54FD5197A63866 /* libPods-NotificationServiceExtension.a */, + 693BF633137EC7920817D909 /* libPods-NewExpensify.a */, + AF7D26E85173CA31D45150D2 /* libPods-NewExpensify-NewExpensifyTests.a */, + FBC515608ED5B1C9BB3BBE1E /* libPods-NotificationServiceExtension.a */, ); name = Frameworks; sourceTree = ""; @@ -319,24 +319,24 @@ EC29677F0A49C2946A495A33 /* Pods */ = { isa = PBXGroup; children = ( - 0FF2BC0D01CA2C62CE94229E /* Pods-NewExpensify.debugdevelopment.xcconfig */, - 5A1F158A9A6CBE170EC19D9C /* Pods-NewExpensify.debugadhoc.xcconfig */, - B4CF7147C89747459BAC5BB7 /* Pods-NewExpensify.releasedevelopment.xcconfig */, - 7312B334B72E8BE41A811FAB /* Pods-NewExpensify.releaseadhoc.xcconfig */, - 9EADA69D62F2E7B3D96E5B1C /* Pods-NewExpensify.releaseproduction.xcconfig */, - E750C93A45B47BDC5149C5AA /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */, - F98306ABF3F272DF04DF65CC /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */, - 972584042DB4782F830B063A /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */, - D15262BE5F713CDB4DA576AE /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */, - 466D03D63F4B48E009C04FA3 /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */, - 12EB734390650799DB8AC627 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */, - 802CB9E7554756F188C79554 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */, - CB32BB7E082E2450F04DA6E7 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */, - 11B2BA236BB72A603FBB7B99 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */, - AC9422F6C8A49AE701481721 /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */, - 96ADA7C82BA6A08C4A56344A /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */, - 3328C9B8861CA667C42B47F3 /* Pods-NewExpensify.debugproduction.xcconfig */, - 030F99CEB3AEF1F11B001798 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */, + 28D3313BDBBA720056DD2D1D /* Pods-NewExpensify.debugdevelopment.xcconfig */, + A672C55E4E62105209DA6787 /* Pods-NewExpensify.debugadhoc.xcconfig */, + 895D008CD95C08405C079218 /* Pods-NewExpensify.debugproduction.xcconfig */, + 5AD4EA6C51AF26EE4290EDDF /* Pods-NewExpensify.releasedevelopment.xcconfig */, + C4BB00AA2BEAE6FCE6E069CA /* Pods-NewExpensify.releaseadhoc.xcconfig */, + 118316C3ED3B8AF1B8DDB462 /* Pods-NewExpensify.releaseproduction.xcconfig */, + BCAF64296F330579F0E7B41B /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */, + 7815BCDA0F80A5988AE4FE23 /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */, + 7A64A8F5BD1DA6D2B1C999A6 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */, + 2E51C885FF70D2D7A54456E6 /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */, + 487DEEE877D99104D2B59897 /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */, + F82148F45FC67E2D0CCB54DB /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */, + 3ADC0A6CC754720C1DC37C70 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */, + E4BC28C56B6C1763152D4F93 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */, + 2C134EA1A00BF7EE88676822 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */, + 1326323F1F0F6464B455D650 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */, + D9EBB16906B99F38BCCDD92C /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */, + CCE8C26BA229E4E25F239908 /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */, ); path = Pods; sourceTree = ""; @@ -348,13 +348,13 @@ isa = PBXNativeTarget; buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "NewExpensifyTests" */; buildPhases = ( - D128CAF2A1070B0F2B3F12E4 /* [CP] Check Pods Manifest.lock */, + 7E80618A74B6DCA69B2235B0 /* [CP] Check Pods Manifest.lock */, 04B99F6AA578E2A877802F05 /* [Expo] Configure project */, 00E356EA1AD99517003FC87E /* Sources */, 00E356EB1AD99517003FC87E /* Frameworks */, 00E356EC1AD99517003FC87E /* Resources */, - CE4668E6E6809DEA0626B5B3 /* [CP] Copy Pods Resources */, - 47778FAEB28E5E04DCCD0D39 /* [CP] Embed Pods Frameworks */, + A1F6CDF530E0E676103C87B8 /* [CP] Embed Pods Frameworks */, + 0BA8C24A2E3B4744463F5218 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -370,7 +370,7 @@ isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "NewExpensify" */; buildPhases = ( - 5DDD2A7C43E9B381CD68A232 /* [CP] Check Pods Manifest.lock */, + 0A069F4A42921D0ABD687724 /* [CP] Check Pods Manifest.lock */, FD10A7F022414F080027D42C /* Start Packager */, 5CF45ABA52C0BB0D7B9D139A /* [Expo] Configure project */, 13B07F871A680F5B00A75B9A /* Sources */, @@ -378,10 +378,10 @@ 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - 50067B6C26F88BAB5F0B478A /* [CP] Embed Pods Frameworks */, - 4E1386759AEE7859543483C9 /* [CP] Copy Pods Resources */, - EEA310C4723D0EF8581FAA1D /* [CP-User] [RNFB] Core Configuration */, - A9A9BDEB11952C562415526C /* [CP-User] [RNFB] Crashlytics Configuration */, + 4EA6523186EFC3CCB644579C /* [CP] Embed Pods Frameworks */, + 48E1EC426A7897E0987A036D /* [CP] Copy Pods Resources */, + 404E26EB01AE2A3634C7D371 /* [CP-User] [RNFB] Core Configuration */, + 6177438839C568C34E791D22 /* [CP-User] [RNFB] Crashlytics Configuration */, ); buildRules = ( ); @@ -397,7 +397,7 @@ isa = PBXNativeTarget; buildConfigurationList = 7FD73CAA2B23CE9500420AF3 /* Build configuration list for PBXNativeTarget "NotificationServiceExtension" */; buildPhases = ( - 7B34459944ACFD30D85D5F85 /* [CP] Check Pods Manifest.lock */, + 7762969E03A5E5E9207F0678 /* [CP] Check Pods Manifest.lock */, 7FD73C972B23CE9500420AF3 /* Sources */, 7FD73C982B23CE9500420AF3 /* Frameworks */, 7FD73C992B23CE9500420AF3 /* Resources */, @@ -534,45 +534,74 @@ shellPath = /bin/sh; shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-NewExpensify-NewExpensifyTests/expo-configure-project.sh\"\n"; }; - 47778FAEB28E5E04DCCD0D39 /* [CP] Embed Pods Frameworks */ = { + 0A069F4A42921D0ABD687724 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/MapboxMaps/MapboxMaps.framework", - "${BUILT_PRODUCTS_DIR}/Turf/Turf.framework", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCommon/MapboxCommon.framework/MapboxCommon", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCoreMaps/MapboxCoreMaps.framework/MapboxCoreMaps", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxMobileEvents/MapboxMobileEvents.framework/MapboxMobileEvents", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Onfido/Onfido.framework/Onfido", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Plaid/LinkKit.framework/LinkKit", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( ); - name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMaps.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Turf.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCommon.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCoreMaps.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMobileEvents.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Onfido.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LinkKit.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", + "$(DERIVED_FILE_DIR)/Pods-NewExpensify-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 0BA8C24A2E3B4744463F5218 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipAutomationResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipCoreResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipExtendedActionsResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipMessageCenterResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipPreferenceCenterResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/GoogleSignIn/GoogleSignIn.bundle", + "${PODS_ROOT}/../../node_modules/@expensify/react-native-live-markdown/parser/react-native-live-markdown-parser.js", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipAutomationResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipCoreResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipExtendedActionsResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipMessageCenterResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipPreferenceCenterResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/react-native-live-markdown-parser.js", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 4E1386759AEE7859543483C9 /* [CP] Copy Pods Resources */ = { + 404E26EB01AE2A3634C7D371 /* [CP-User] [RNFB] Core Configuration */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", + ); + name = "[CP-User] [RNFB] Core Configuration"; + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n _JSON_OUTPUT_BASE64=$(python -c 'import json,sys,base64;print(base64.b64encode(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"').read())['${_JSON_ROOT}'])))' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; + }; + 48E1EC426A7897E0987A036D /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -604,7 +633,7 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify/Pods-NewExpensify-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 50067B6C26F88BAB5F0B478A /* [CP] Embed Pods Frameworks */ = { + 4EA6523186EFC3CCB644579C /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -613,13 +642,10 @@ "${PODS_ROOT}/Target Support Files/Pods-NewExpensify/Pods-NewExpensify-frameworks.sh", "${BUILT_PRODUCTS_DIR}/MapboxMaps/MapboxMaps.framework", "${BUILT_PRODUCTS_DIR}/Turf/Turf.framework", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog", "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCommon/MapboxCommon.framework/MapboxCommon", "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCoreMaps/MapboxCoreMaps.framework/MapboxCoreMaps", "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxMobileEvents/MapboxMobileEvents.framework/MapboxMobileEvents", "${PODS_XCFRAMEWORKS_BUILD_DIR}/Onfido/Onfido.framework/Onfido", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL", "${PODS_XCFRAMEWORKS_BUILD_DIR}/Plaid/LinkKit.framework/LinkKit", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); @@ -627,13 +653,10 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMaps.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Turf.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCommon.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCoreMaps.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMobileEvents.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Onfido.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LinkKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); @@ -661,29 +684,21 @@ shellPath = /bin/sh; shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-NewExpensify/expo-configure-project.sh\"\n"; }; - 5DDD2A7C43E9B381CD68A232 /* [CP] Check Pods Manifest.lock */ = { + 6177438839C568C34E791D22 /* [CP-User] [RNFB] Crashlytics Configuration */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - ); inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-NewExpensify-checkManifestLockResult.txt", + "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}", + "$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", ); + name = "[CP-User] [RNFB] Crashlytics Configuration"; runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; + shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\nif [[ ${PODS_ROOT} ]]; then\n echo \"info: Exec FirebaseCrashlytics Run from Pods\"\n \"${PODS_ROOT}/FirebaseCrashlytics/run\"\nelse\n echo \"info: Exec FirebaseCrashlytics Run from framework\"\n \"${PROJECT_DIR}/FirebaseCrashlytics.framework/run\"\nfi\n"; }; - 7B34459944ACFD30D85D5F85 /* [CP] Check Pods Manifest.lock */ = { + 7762969E03A5E5E9207F0678 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -705,53 +720,7 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - A9A9BDEB11952C562415526C /* [CP-User] [RNFB] Crashlytics Configuration */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}", - "$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", - ); - name = "[CP-User] [RNFB] Crashlytics Configuration"; - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\nif [[ ${PODS_ROOT} ]]; then\n echo \"info: Exec FirebaseCrashlytics Run from Pods\"\n \"${PODS_ROOT}/FirebaseCrashlytics/run\"\nelse\n echo \"info: Exec FirebaseCrashlytics Run from framework\"\n \"${PROJECT_DIR}/FirebaseCrashlytics.framework/run\"\nfi\n"; - }; - CE4668E6E6809DEA0626B5B3 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipAutomationResources.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipCoreResources.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipExtendedActionsResources.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipMessageCenterResources.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipPreferenceCenterResources.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/GoogleSignIn/GoogleSignIn.bundle", - "${PODS_ROOT}/../../node_modules/@expensify/react-native-live-markdown/parser/react-native-live-markdown-parser.js", - "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle", - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipAutomationResources.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipCoreResources.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipExtendedActionsResources.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipMessageCenterResources.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipPreferenceCenterResources.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/react-native-live-markdown-parser.js", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - D128CAF2A1070B0F2B3F12E4 /* [CP] Check Pods Manifest.lock */ = { + 7E80618A74B6DCA69B2235B0 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -773,18 +742,37 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - EEA310C4723D0EF8581FAA1D /* [CP-User] [RNFB] Core Configuration */ = { + A1F6CDF530E0E676103C87B8 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", + "${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/MapboxMaps/MapboxMaps.framework", + "${BUILT_PRODUCTS_DIR}/Turf/Turf.framework", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCommon/MapboxCommon.framework/MapboxCommon", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCoreMaps/MapboxCoreMaps.framework/MapboxCoreMaps", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxMobileEvents/MapboxMobileEvents.framework/MapboxMobileEvents", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/Onfido/Onfido.framework/Onfido", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/Plaid/LinkKit.framework/LinkKit", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMaps.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Turf.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCommon.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCoreMaps.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMobileEvents.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Onfido.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LinkKit.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); - name = "[CP-User] [RNFB] Core Configuration"; runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n _JSON_OUTPUT_BASE64=$(python -c 'import json,sys,base64;print(base64.b64encode(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"').read())['${_JSON_ROOT}'])))' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; }; FD10A7F022414F080027D42C /* Start Packager */ = { isa = PBXShellScriptBuildPhase; @@ -861,7 +849,7 @@ /* Begin XCBuildConfiguration section */ 00E356F61AD99517003FC87E /* DebugDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E750C93A45B47BDC5149C5AA /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */; + baseConfigurationReference = BCAF64296F330579F0E7B41B /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -891,7 +879,7 @@ }; 00E356F71AD99517003FC87E /* ReleaseDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 972584042DB4782F830B063A /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */; + baseConfigurationReference = 2E51C885FF70D2D7A54456E6 /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -918,7 +906,7 @@ }; 13B07F941A680F5B00A75B9A /* DebugDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 0FF2BC0D01CA2C62CE94229E /* Pods-NewExpensify.debugdevelopment.xcconfig */; + baseConfigurationReference = 28D3313BDBBA720056DD2D1D /* Pods-NewExpensify.debugdevelopment.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDev; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -957,7 +945,7 @@ }; 13B07F951A680F5B00A75B9A /* ReleaseDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = B4CF7147C89747459BAC5BB7 /* Pods-NewExpensify.releasedevelopment.xcconfig */; + baseConfigurationReference = 5AD4EA6C51AF26EE4290EDDF /* Pods-NewExpensify.releasedevelopment.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDev; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -994,7 +982,7 @@ }; 7FD73CA42B23CE9500420AF3 /* DebugDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 12EB734390650799DB8AC627 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */; + baseConfigurationReference = 3ADC0A6CC754720C1DC37C70 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1080,7 +1068,7 @@ }; 7FD73CA52B23CE9500420AF3 /* DebugAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 802CB9E7554756F188C79554 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */; + baseConfigurationReference = E4BC28C56B6C1763152D4F93 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1165,7 +1153,7 @@ }; 7FD73CA62B23CE9500420AF3 /* DebugProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = CB32BB7E082E2450F04DA6E7 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */; + baseConfigurationReference = 2C134EA1A00BF7EE88676822 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1251,7 +1239,7 @@ }; 7FD73CA72B23CE9500420AF3 /* ReleaseDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 11B2BA236BB72A603FBB7B99 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */; + baseConfigurationReference = 1326323F1F0F6464B455D650 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1330,7 +1318,7 @@ }; 7FD73CA82B23CE9500420AF3 /* ReleaseAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = AC9422F6C8A49AE701481721 /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */; + baseConfigurationReference = D9EBB16906B99F38BCCDD92C /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1408,7 +1396,7 @@ }; 7FD73CA92B23CE9500420AF3 /* ReleaseProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 96ADA7C82BA6A08C4A56344A /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */; + baseConfigurationReference = CCE8C26BA229E4E25F239908 /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1703,7 +1691,7 @@ }; CF9AF93F29EE9276001FA527 /* DebugProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 3328C9B8861CA667C42B47F3 /* Pods-NewExpensify.debugproduction.xcconfig */; + baseConfigurationReference = 895D008CD95C08405C079218 /* Pods-NewExpensify.debugproduction.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -1741,7 +1729,7 @@ }; CF9AF94029EE9276001FA527 /* DebugProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 030F99CEB3AEF1F11B001798 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */; + baseConfigurationReference = 7A64A8F5BD1DA6D2B1C999A6 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -1845,7 +1833,7 @@ }; CF9AF94529EE927A001FA527 /* DebugAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5A1F158A9A6CBE170EC19D9C /* Pods-NewExpensify.debugadhoc.xcconfig */; + baseConfigurationReference = A672C55E4E62105209DA6787 /* Pods-NewExpensify.debugadhoc.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIconAdHoc; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -1883,7 +1871,7 @@ }; CF9AF94629EE927A001FA527 /* DebugAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = F98306ABF3F272DF04DF65CC /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */; + baseConfigurationReference = 7815BCDA0F80A5988AE4FE23 /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -1981,7 +1969,7 @@ }; CF9AF94829EE928E001FA527 /* ReleaseProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9EADA69D62F2E7B3D96E5B1C /* Pods-NewExpensify.releaseproduction.xcconfig */; + baseConfigurationReference = 118316C3ED3B8AF1B8DDB462 /* Pods-NewExpensify.releaseproduction.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -2017,7 +2005,7 @@ }; CF9AF94929EE928E001FA527 /* ReleaseProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 466D03D63F4B48E009C04FA3 /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */; + baseConfigurationReference = F82148F45FC67E2D0CCB54DB /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -2113,7 +2101,7 @@ }; CF9AF94E29EE9293001FA527 /* ReleaseAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7312B334B72E8BE41A811FAB /* Pods-NewExpensify.releaseadhoc.xcconfig */; + baseConfigurationReference = C4BB00AA2BEAE6FCE6E069CA /* Pods-NewExpensify.releaseadhoc.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIconAdHoc; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -2149,7 +2137,7 @@ }; CF9AF94F29EE9293001FA527 /* ReleaseAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D15262BE5F713CDB4DA576AE /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */; + baseConfigurationReference = 487DEEE877D99104D2B59897 /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; diff --git a/ios/Podfile b/ios/Podfile index aa87c3e295f3..e4bfed79b685 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -35,7 +35,8 @@ setup_permissions([ # dependencies: { # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), # ``` -flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled(['DebugProduction', 'DebugDevelopment', 'DebugAdHoc']) +# flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled(['DebugProduction', 'DebugDevelopment', 'DebugAdHoc']) +flipper_config = FlipperConfiguration.disabled linkage = ENV['USE_FRAMEWORKS'] if linkage != nil diff --git a/ios/Podfile.lock b/ios/Podfile.lock index cac0499df2d4..4028461f7648 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -30,7 +30,6 @@ PODS: - boost (1.83.0) - BVLinearGradient (2.8.1): - React-Core - - CocoaAsyncSocket (7.6.5) - DoubleConversion (1.1.6) - EXAV (13.10.4): - ExpoModulesCore @@ -133,62 +132,6 @@ PODS: - FirebaseInstallations (~> 8.0) - GoogleUtilities/Environment (~> 7.7) - "GoogleUtilities/NSData+zlib (~> 7.7)" - - Flipper (0.201.0): - - Flipper-Folly (~> 2.6) - - Flipper-Boost-iOSX (1.76.0.1.11) - - Flipper-DoubleConversion (3.2.0.1) - - Flipper-Fmt (7.1.7) - - Flipper-Folly (2.6.10): - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt (= 7.1.7) - - Flipper-Glog - - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - - Flipper-Glog (0.5.0.5) - - Flipper-PeerTalk (0.0.4) - - FlipperKit (0.201.0): - - FlipperKit/Core (= 0.201.0) - - FlipperKit/Core (0.201.0): - - Flipper (~> 0.201.0) - - FlipperKit/CppBridge - - FlipperKit/FBCxxFollyDynamicConvert - - FlipperKit/FBDefines - - FlipperKit/FKPortForwarding - - SocketRocket (~> 0.6.0) - - FlipperKit/CppBridge (0.201.0): - - Flipper (~> 0.201.0) - - FlipperKit/FBCxxFollyDynamicConvert (0.201.0): - - Flipper-Folly (~> 2.6) - - FlipperKit/FBDefines (0.201.0) - - FlipperKit/FKPortForwarding (0.201.0): - - CocoaAsyncSocket (~> 7.6) - - Flipper-PeerTalk (~> 0.0.4) - - FlipperKit/FlipperKitHighlightOverlay (0.201.0) - - FlipperKit/FlipperKitLayoutHelpers (0.201.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutTextSearchable - - FlipperKit/FlipperKitLayoutIOSDescriptors (0.201.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - FlipperKit/FlipperKitLayoutPlugin (0.201.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - FlipperKit/FlipperKitLayoutIOSDescriptors - - FlipperKit/FlipperKitLayoutTextSearchable - - FlipperKit/FlipperKitLayoutTextSearchable (0.201.0) - - FlipperKit/FlipperKitNetworkPlugin (0.201.0): - - FlipperKit/Core - - FlipperKit/FlipperKitReactPlugin (0.201.0): - - FlipperKit/Core - - FlipperKit/FlipperKitUserDefaultsPlugin (0.201.0): - - FlipperKit/Core - - FlipperKit/SKIOSNetworkPlugin (0.201.0): - - FlipperKit/Core - - FlipperKit/FlipperKitNetworkPlugin - fmt (6.2.1) - glog (0.3.5) - GoogleAppMeasurement (8.8.0): @@ -290,7 +233,6 @@ PODS: - onfido-react-native-sdk (10.6.0): - Onfido (~> 29.6.0) - React - - OpenSSL-Universal (1.1.1100) - Plaid (4.7.0) - PromisesObjC (2.3.1) - RCT-Folly (2022.05.16.00): @@ -1486,32 +1428,11 @@ DEPENDENCIES: - ExpoModulesCore (from `../node_modules/expo-modules-core`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - - Flipper (= 0.201.0) - - Flipper-Boost-iOSX (= 1.76.0.1.11) - - Flipper-DoubleConversion (= 3.2.0.1) - - Flipper-Fmt (= 7.1.7) - - Flipper-Folly (= 2.6.10) - - Flipper-Glog (= 0.5.0.5) - - Flipper-PeerTalk (= 0.0.4) - - FlipperKit (= 0.201.0) - - FlipperKit/Core (= 0.201.0) - - FlipperKit/CppBridge (= 0.201.0) - - FlipperKit/FBCxxFollyDynamicConvert (= 0.201.0) - - FlipperKit/FBDefines (= 0.201.0) - - FlipperKit/FKPortForwarding (= 0.201.0) - - FlipperKit/FlipperKitHighlightOverlay (= 0.201.0) - - FlipperKit/FlipperKitLayoutPlugin (= 0.201.0) - - FlipperKit/FlipperKitLayoutTextSearchable (= 0.201.0) - - FlipperKit/FlipperKitNetworkPlugin (= 0.201.0) - - FlipperKit/FlipperKitReactPlugin (= 0.201.0) - - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.201.0) - - FlipperKit/SKIOSNetworkPlugin (= 0.201.0) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - libevent (~> 2.1.12) - lottie-react-native (from `../node_modules/lottie-react-native`) - "onfido-react-native-sdk (from `../node_modules/@onfido/react-native-sdk`)" - - OpenSSL-Universal (= 1.1.1100) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) @@ -1520,7 +1441,6 @@ DEPENDENCIES: - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - React-Codegen (from `build/generated/ios`) - React-Core (from `../node_modules/react-native/`) - - React-Core/DevSupport (from `../node_modules/react-native/`) - React-Core/RCTWebSocket (from `../node_modules/react-native/`) - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) @@ -1607,7 +1527,6 @@ SPEC REPOS: - AirshipFrameworkProxy - AirshipServiceExtension - AppAuth - - CocoaAsyncSocket - Firebase - FirebaseABTesting - FirebaseAnalytics @@ -1617,14 +1536,6 @@ SPEC REPOS: - FirebaseInstallations - FirebasePerformance - FirebaseRemoteConfig - - Flipper - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt - - Flipper-Folly - - Flipper-Glog - - Flipper-PeerTalk - - FlipperKit - fmt - GoogleAppMeasurement - GoogleDataTransport @@ -1644,7 +1555,6 @@ SPEC REPOS: - MapboxMobileEvents - nanopb - Onfido - - OpenSSL-Universal - Plaid - PromisesObjC - SDWebImage @@ -1864,7 +1774,6 @@ SPEC CHECKSUMS: AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570 boost: d3f49c53809116a5d38da093a8aa78bf551aed09 BVLinearGradient: 421743791a59d259aec53f4c58793aad031da2ca - CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953 EXAV: 09a4d87fa6b113fbb0ada3aade6799f78271cb44 EXImageLoader: 55080616b2fe9da19ef8c7f706afd9814e279b6b @@ -1883,14 +1792,6 @@ SPEC CHECKSUMS: FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd FirebasePerformance: 0c01a7a496657d7cea86d40c0b1725259d164c6c FirebaseRemoteConfig: 2d6e2cfdb49af79535c8af8a80a4a5009038ec2b - Flipper: c7a0093234c4bdd456e363f2f19b2e4b27652d44 - Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c - Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 - Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b - Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 - Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 - Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 - FlipperKit: 37525a5d056ef9b93d1578e04bc3ea1de940094f fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 GoogleAppMeasurement: 5ba1164e3c844ba84272555e916d0a6d3d977e91 @@ -1914,7 +1815,6 @@ SPEC CHECKSUMS: nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 Onfido: c52e797b10cc9e6d29ba91996cb62e501000bfdd onfido-react-native-sdk: 4e7f0a7a986ed93cb906d2e0b67a6aab9202de0b - OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c Plaid: 431ef9be5314a1345efb451bc5e6b067bfb3b4c6 PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0 @@ -2009,6 +1909,6 @@ SPEC CHECKSUMS: VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a Yoga: 13c8ef87792450193e117976337b8527b49e8c03 -PODFILE CHECKSUM: 0ccbb4f2406893c6e9f266dc1e7470dcd72885d2 +PODFILE CHECKSUM: e1c79a65c8850178491c6a63dbce41f6ea21005d COCOAPODS: 1.15.2 diff --git a/src/components/FixedFooter.tsx b/src/components/FixedFooter.tsx index 115714285f74..2f09b27f3067 100644 --- a/src/components/FixedFooter.tsx +++ b/src/components/FixedFooter.tsx @@ -2,6 +2,8 @@ import type {ReactNode} from 'react'; import React from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; +import useKeyboardState from '@hooks/useKeyboardState'; +import useSafeAreaInsets from '@hooks/useSafeAreaInsets'; import useThemeStyles from '@hooks/useThemeStyles'; type FixedFooterProps = { @@ -13,11 +15,17 @@ type FixedFooterProps = { }; function FixedFooter({style, children}: FixedFooterProps) { + const {isKeyboardShown} = useKeyboardState(); + const insets = useSafeAreaInsets(); const styles = useThemeStyles(); + if (!children) { return null; } - return {children}; + + const shouldAddBottomPadding = isKeyboardShown || !insets.bottom; + + return {children}; } FixedFooter.displayName = 'FixedFooter'; diff --git a/src/components/OnyxProvider.tsx b/src/components/OnyxProvider.tsx index d14aec90fa10..c15362844440 100644 --- a/src/components/OnyxProvider.tsx +++ b/src/components/OnyxProvider.tsx @@ -16,6 +16,7 @@ const [withPreferredTheme, PreferredThemeProvider, PreferredThemeContext] = crea 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); +const [, AccountProvider, , useAccount] = createOnyxContext(ONYXKEYS.ACCOUNT); type OnyxProviderProps = { /** Rendered child component */ @@ -37,6 +38,7 @@ function OnyxProvider(props: OnyxProviderProps) { FrequentlyUsedEmojisProvider, PreferredEmojiSkinToneProvider, SessionProvider, + AccountProvider, ]} > {props.children} @@ -67,4 +69,5 @@ export { withPreferredEmojiSkinTone, PreferredEmojiSkinToneContext, useSession, + useAccount, }; diff --git a/src/components/ReferralProgramCTA.tsx b/src/components/ReferralProgramCTA.tsx index c57d2fa344d4..0588f31a0a8c 100644 --- a/src/components/ReferralProgramCTA.tsx +++ b/src/components/ReferralProgramCTA.tsx @@ -1,26 +1,19 @@ import React, {useEffect} from 'react'; import type {ViewStyle} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; +import useDismissedReferralBanners from '@hooks/useDismissedReferralBanners'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as User from '@userActions/User'; import CONST from '@src/CONST'; import Navigation from '@src/libs/Navigation/Navigation'; -import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {DismissedReferralBanners} from '@src/types/onyx/Account'; import Icon from './Icon'; import {Close} from './Icon/Expensicons'; import {PressableWithoutFeedback} from './Pressable'; import Text from './Text'; import Tooltip from './Tooltip'; -type ReferralProgramCTAOnyxProps = { - dismissedReferralBanners: DismissedReferralBanners; -}; - -type ReferralProgramCTAProps = ReferralProgramCTAOnyxProps & { +type ReferralProgramCTAProps = { referralContentType: | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT @@ -30,17 +23,18 @@ type ReferralProgramCTAProps = ReferralProgramCTAOnyxProps & { onDismiss?: () => void; }; -function ReferralProgramCTA({referralContentType, dismissedReferralBanners, style, onDismiss}: ReferralProgramCTAProps) { +function ReferralProgramCTA({referralContentType, style, onDismiss}: ReferralProgramCTAProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const theme = useTheme(); + const {isDismissed, setAsDismissed} = useDismissedReferralBanners({referralContentType}); const handleDismissCallToAction = () => { - User.dismissReferralBanner(referralContentType); + setAsDismissed(); onDismiss?.(); }; - const shouldShowBanner = referralContentType && !dismissedReferralBanners[referralContentType]; + const shouldShowBanner = referralContentType && !isDismissed; useEffect(() => { if (shouldShowBanner) { @@ -58,7 +52,7 @@ function ReferralProgramCTA({referralContentType, dismissedReferralBanners, styl onPress={() => { Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(referralContentType, Navigation.getActiveRouteWithoutParams())); }} - style={[styles.w100, styles.br2, styles.highlightBG, styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter, {gap: 10, padding: 10}, styles.pl5, style]} + style={[styles.br2, styles.highlightBG, styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter, {gap: 10, padding: 10}, styles.pl5, style]} accessibilityLabel="referral" role={CONST.ACCESSIBILITY_ROLE.BUTTON} > @@ -93,9 +87,4 @@ function ReferralProgramCTA({referralContentType, dismissedReferralBanners, styl ); } -export default withOnyx({ - dismissedReferralBanners: { - key: ONYXKEYS.ACCOUNT, - selector: (data) => data?.dismissedReferralBanners ?? {}, - }, -})(ReferralProgramCTA); +export default ReferralProgramCTA; diff --git a/src/hooks/useDismissedReferralBanners.ts b/src/hooks/useDismissedReferralBanners.ts new file mode 100644 index 000000000000..7f3042bf422a --- /dev/null +++ b/src/hooks/useDismissedReferralBanners.ts @@ -0,0 +1,28 @@ +import {useAccount} from '@components/OnyxProvider'; +import * as User from '@userActions/User'; +import type CONST from '@src/CONST'; + +type UseDismissedReferralBannersProps = { + referralContentType: + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND; +}; + +function useDismissedReferralBanners({referralContentType}: UseDismissedReferralBannersProps): {isDismissed: boolean; setAsDismissed: () => void} { + const {dismissedReferralBanners} = useAccount(); + const isDismissed = dismissedReferralBanners?.[referralContentType] ?? false; + + const setAsDismissed = () => { + if (!referralContentType) { + return; + } + // Set the banner as dismissed + User.dismissReferralBanner(referralContentType); + }; + + return {isDismissed, setAsDismissed}; +} + +export default useDismissedReferralBanners; diff --git a/src/pages/SearchPage/index.js b/src/pages/SearchPage/index.js index 502235066b24..8cae43df9147 100644 --- a/src/pages/SearchPage/index.js +++ b/src/pages/SearchPage/index.js @@ -1,18 +1,16 @@ import PropTypes from 'prop-types'; import React, {useEffect, useMemo, useState} from 'react'; -import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import {usePersonalDetails} from '@components/OnyxProvider'; -import ReferralProgramCTA from '@components/ReferralProgramCTA'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import UserListItem from '@components/SelectionList/UserListItem'; import useDebouncedState from '@hooks/useDebouncedState'; +import useDismissedReferralBanners from '@hooks/useDismissedReferralBanners'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; -import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import Performance from '@libs/Performance'; @@ -22,10 +20,9 @@ import * as Report from '@userActions/Report'; import Timing from '@userActions/Timing'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import SearchPageFooter from './SearchPageFooter'; const propTypes = { - /* Onyx Props */ - /** Beta features list */ betas: PropTypes.arrayOf(PropTypes.string), @@ -55,11 +52,12 @@ const setPerformanceTimersEnd = () => { Performance.markEnd(CONST.TIMING.SEARCH_RENDER); }; -function SearchPage({betas, reports, isSearchingForReports}) { +const SerachPageFooterInstance = ; + +function SearchPage({betas, reports, isSearchingForReports, navigation}) { const [isScreenTransitionEnd, setIsScreenTransitionEnd] = useState(false); const {translate} = useLocalize(); const {isOffline} = useNetwork(); - const themeStyles = useThemeStyles(); const personalDetails = usePersonalDetails(); const offlineMessage = isOffline ? [`${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}`, {isTranslated: true}] : ''; @@ -145,18 +143,7 @@ function SearchPage({betas, reports, isSearchingForReports}) { }; const isOptionsDataReady = useMemo(() => ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(personalDetails), [personalDetails]); - const [showFooter, setShowFooter] = useState(true); - - const SearchPageFooter = useMemo( - () => ( - setShowFooter(false)} - /> - ), - [themeStyles], - ); + const {isDismissed} = useDismissedReferralBanners({referralContentType: CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND}); return ( - - - + )} diff --git a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js index 2b56d9e3318a..f83ee3bcc274 100644 --- a/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js +++ b/src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js @@ -1,7 +1,6 @@ import lodashGet from 'lodash/get'; 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 Button from '@components/Button'; @@ -12,6 +11,7 @@ import ReferralProgramCTA from '@components/ReferralProgramCTA'; import SelectCircle from '@components/SelectCircle'; import SelectionList from '@components/SelectionList'; import UserListItem from '@components/SelectionList/UserListItem'; +import useDismissedReferralBanners from '@hooks/useDismissedReferralBanners'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useSearchTermAndSearch from '@hooks/useSearchTermAndSearch'; @@ -27,9 +27,6 @@ const propTypes = { /** Beta features list */ betas: PropTypes.arrayOf(PropTypes.string), - /** An object that holds data about which referral banners have been dismissed */ - dismissedReferralBanners: PropTypes.objectOf(PropTypes.bool), - /** Callback to request parent modal to go to next step, which should be split */ onFinish: PropTypes.func.isRequired, @@ -50,9 +47,6 @@ const propTypes = { /** All reports shared with the user */ reports: PropTypes.objectOf(reportPropTypes), - /** Padding bottom style of safe area */ - safeAreaPaddingBottomStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), - /** The type of IOU report, i.e. bill, request, send */ iouType: PropTypes.oneOf(_.values(CONST.IOU.TYPE)).isRequired, @@ -65,31 +59,19 @@ const propTypes = { const defaultProps = { participants: [], - safeAreaPaddingBottomStyle: {}, reports: {}, betas: [], - dismissedReferralBanners: {}, didScreenTransitionEnd: false, }; -function MoneyTemporaryForRefactorRequestParticipantsSelector({ - betas, - participants, - reports, - onFinish, - onParticipantsAdded, - safeAreaPaddingBottomStyle, - iouType, - iouRequestType, - dismissedReferralBanners, - didScreenTransitionEnd, -}) { +function MoneyTemporaryForRefactorRequestParticipantsSelector({betas, participants, reports, onFinish, onParticipantsAdded, iouType, iouRequestType, didScreenTransitionEnd}) { const {translate} = useLocalize(); const styles = useThemeStyles(); const [searchTerm, setSearchTerm] = useState(''); const referralContentType = iouType === CONST.IOU.TYPE.SEND ? CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY : CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST; const {isOffline} = useNetwork(); const personalDetails = usePersonalDetails(); + const {isDismissed} = useDismissedReferralBanners({referralContentType}); const offlineMessage = isOffline ? [`${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}`, {isTranslated: true}] : ''; @@ -267,10 +249,14 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ onFinish(CONST.IOU.TYPE.SPLIT); }, [shouldShowSplitBillErrorMessage, onFinish]); - const footerContent = useMemo( - () => ( - - {!dismissedReferralBanners[referralContentType] && ( + const footerContent = useMemo(() => { + if (isDismissed && !shouldShowSplitBillErrorMessage && !participants.length) { + return; + } + + return ( + <> + {!isDismissed && ( )} - - ), - [handleConfirmSelection, participants.length, dismissedReferralBanners, referralContentType, shouldShowSplitBillErrorMessage, styles, translate], - ); + + ); + }, [handleConfirmSelection, participants.length, isDismissed, referralContentType, shouldShowSplitBillErrorMessage, styles, translate]); const itemRightSideComponent = useCallback( (item) => { @@ -336,23 +321,21 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({ const isOptionsDataReady = useMemo(() => ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(personalDetails), [personalDetails]); return ( - 0 ? safeAreaPaddingBottomStyle : {}]}> - - + ); } @@ -361,10 +344,6 @@ MoneyTemporaryForRefactorRequestParticipantsSelector.defaultProps = defaultProps MoneyTemporaryForRefactorRequestParticipantsSelector.displayName = 'MoneyTemporaryForRefactorRequestParticipantsSelector'; export default withOnyx({ - dismissedReferralBanners: { - key: ONYXKEYS.ACCOUNT, - selector: (data) => data.dismissedReferralBanners || {}, - }, reports: { key: ONYXKEYS.COLLECTION.REPORT, }, diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.js b/src/pages/iou/request/step/IOURequestStepParticipants.js index b2f5cbb68cd1..69ee5fede7e2 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.js +++ b/src/pages/iou/request/step/IOURequestStepParticipants.js @@ -127,7 +127,7 @@ function IOURequestStepParticipants({ onBackButtonPress={navigateBack} shouldShowWrapper testID={IOURequestStepParticipants.displayName} - includeSafeAreaPaddingBottom + includeSafeAreaPaddingBottom={false} > {({didScreenTransitionEnd}) => ( ( + const {isDismissed} = useDismissedReferralBanners({referralContentType}); + + const footerContent = useMemo(() => { + if (isDismissed && !shouldShowSplitBillErrorMessage && !participants.length) { + return null; + } + return ( - {!dismissedReferralBanners[referralContentType] && ( + {!isDismissed && ( )} - ), - [handleConfirmSelection, participants.length, dismissedReferralBanners, referralContentType, shouldShowSplitBillErrorMessage, styles, translate], - ); + ); + }, [handleConfirmSelection, participants.length, isDismissed, referralContentType, shouldShowSplitBillErrorMessage, styles, translate]); const itemRightSideComponent = useCallback( (item) => { @@ -371,10 +371,6 @@ MoneyRequestParticipantsSelector.displayName = 'MoneyRequestParticipantsSelector MoneyRequestParticipantsSelector.defaultProps = defaultProps; export default withOnyx({ - dismissedReferralBanners: { - key: ONYXKEYS.ACCOUNT, - selector: (data) => data.dismissedReferralBanners || {}, - }, reports: { key: ONYXKEYS.COLLECTION.REPORT, }, From 0a49f41d65e8b9c64bd4a81e904eaef09df1d6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Fri, 8 Mar 2024 17:42:19 +0100 Subject: [PATCH 031/402] added missing types to BaseSelectionList --- src/components/SelectionList/BaseSelectionList.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 4710326fa8bc..7e19de71a7fb 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -22,6 +22,7 @@ import Log from '@libs/Log'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import type {BaseSelectionListProps, ButtonOrCheckBoxRoles, FlattenedSectionsReturn, ListItem, Section, SectionListDataType} from './types'; function BaseSelectionList( { From 66c6a9ec09cefaa1b192f506498c4842aabc3169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Fri, 8 Mar 2024 18:25:52 +0100 Subject: [PATCH 032/402] safe area bottom padding fix --- src/components/FormAlertWithSubmitButton.tsx | 2 +- src/pages/RoomInvitePage.tsx | 1 + .../request/step/IOURequestStepCurrency.js | 1 + src/pages/workspace/WorkspaceInvitePage.tsx | 30 +++++++++++-------- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/components/FormAlertWithSubmitButton.tsx b/src/components/FormAlertWithSubmitButton.tsx index 9968bb0e0772..3954ddc12fc6 100644 --- a/src/components/FormAlertWithSubmitButton.tsx +++ b/src/components/FormAlertWithSubmitButton.tsx @@ -79,7 +79,7 @@ function FormAlertWithSubmitButton({ return ( optionsSelectorRef.current && optionsSelectorRef.current.focus()} shouldShowWrapper testID={IOURequestStepCurrency.displayName} + includeSafeAreaPaddingBottom={false} > {({didScreenTransitionEnd}) => ( 0, searchValue); }, [excludedUsers, translate, searchTerm, policyName, usersToInvite, personalDetails.length]); + const footerContent = useMemo( + () => ( + + ), + [inviteUser, policy?.alertMessage, selectedOptions.length, shouldShowAlertPrompt, styles, translate], + ); + return ( - - - ); From 7a833b8c0eda6f75855fd32d6c67e896106c3bd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Mon, 11 Mar 2024 13:12:40 +0100 Subject: [PATCH 033/402] linting --- src/pages/workspace/WorkspaceInvitePage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/workspace/WorkspaceInvitePage.tsx b/src/pages/workspace/WorkspaceInvitePage.tsx index dc10757390af..b85463997955 100644 --- a/src/pages/workspace/WorkspaceInvitePage.tsx +++ b/src/pages/workspace/WorkspaceInvitePage.tsx @@ -2,7 +2,6 @@ import {useNavigation} from '@react-navigation/native'; import type {StackNavigationProp, StackScreenProps} from '@react-navigation/stack'; import React, {useEffect, useMemo, useState} from 'react'; import type {SectionListData} from 'react-native'; -import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; From 88fdafd92d812551f313ff971461219a0ea35d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Mon, 11 Mar 2024 15:25:20 +0100 Subject: [PATCH 034/402] podfile revert --- ios/NewExpensify.xcodeproj/project.pbxproj | 12 +++ ios/Podfile | 3 +- ios/Podfile.lock | 102 ++++++++++++++++++++- 3 files changed, 114 insertions(+), 3 deletions(-) diff --git a/ios/NewExpensify.xcodeproj/project.pbxproj b/ios/NewExpensify.xcodeproj/project.pbxproj index ce65dd95943e..8503a435e4ed 100644 --- a/ios/NewExpensify.xcodeproj/project.pbxproj +++ b/ios/NewExpensify.xcodeproj/project.pbxproj @@ -642,10 +642,13 @@ "${PODS_ROOT}/Target Support Files/Pods-NewExpensify/Pods-NewExpensify-frameworks.sh", "${BUILT_PRODUCTS_DIR}/MapboxMaps/MapboxMaps.framework", "${BUILT_PRODUCTS_DIR}/Turf/Turf.framework", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog", "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCommon/MapboxCommon.framework/MapboxCommon", "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCoreMaps/MapboxCoreMaps.framework/MapboxCoreMaps", "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxMobileEvents/MapboxMobileEvents.framework/MapboxMobileEvents", "${PODS_XCFRAMEWORKS_BUILD_DIR}/Onfido/Onfido.framework/Onfido", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL", "${PODS_XCFRAMEWORKS_BUILD_DIR}/Plaid/LinkKit.framework/LinkKit", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); @@ -653,10 +656,13 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMaps.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Turf.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCommon.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCoreMaps.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMobileEvents.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Onfido.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LinkKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); @@ -751,10 +757,13 @@ "${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/MapboxMaps/MapboxMaps.framework", "${BUILT_PRODUCTS_DIR}/Turf/Turf.framework", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog", "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCommon/MapboxCommon.framework/MapboxCommon", "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCoreMaps/MapboxCoreMaps.framework/MapboxCoreMaps", "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxMobileEvents/MapboxMobileEvents.framework/MapboxMobileEvents", "${PODS_XCFRAMEWORKS_BUILD_DIR}/Onfido/Onfido.framework/Onfido", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL", "${PODS_XCFRAMEWORKS_BUILD_DIR}/Plaid/LinkKit.framework/LinkKit", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); @@ -762,10 +771,13 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMaps.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Turf.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCommon.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCoreMaps.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMobileEvents.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Onfido.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LinkKit.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", ); diff --git a/ios/Podfile b/ios/Podfile index e4bfed79b685..aa87c3e295f3 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -35,8 +35,7 @@ setup_permissions([ # dependencies: { # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), # ``` -# flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled(['DebugProduction', 'DebugDevelopment', 'DebugAdHoc']) -flipper_config = FlipperConfiguration.disabled +flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled(['DebugProduction', 'DebugDevelopment', 'DebugAdHoc']) linkage = ENV['USE_FRAMEWORKS'] if linkage != nil diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 4028461f7648..cac0499df2d4 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -30,6 +30,7 @@ PODS: - boost (1.83.0) - BVLinearGradient (2.8.1): - React-Core + - CocoaAsyncSocket (7.6.5) - DoubleConversion (1.1.6) - EXAV (13.10.4): - ExpoModulesCore @@ -132,6 +133,62 @@ PODS: - FirebaseInstallations (~> 8.0) - GoogleUtilities/Environment (~> 7.7) - "GoogleUtilities/NSData+zlib (~> 7.7)" + - Flipper (0.201.0): + - Flipper-Folly (~> 2.6) + - Flipper-Boost-iOSX (1.76.0.1.11) + - Flipper-DoubleConversion (3.2.0.1) + - Flipper-Fmt (7.1.7) + - Flipper-Folly (2.6.10): + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt (= 7.1.7) + - Flipper-Glog + - libevent (~> 2.1.12) + - OpenSSL-Universal (= 1.1.1100) + - Flipper-Glog (0.5.0.5) + - Flipper-PeerTalk (0.0.4) + - FlipperKit (0.201.0): + - FlipperKit/Core (= 0.201.0) + - FlipperKit/Core (0.201.0): + - Flipper (~> 0.201.0) + - FlipperKit/CppBridge + - FlipperKit/FBCxxFollyDynamicConvert + - FlipperKit/FBDefines + - FlipperKit/FKPortForwarding + - SocketRocket (~> 0.6.0) + - FlipperKit/CppBridge (0.201.0): + - Flipper (~> 0.201.0) + - FlipperKit/FBCxxFollyDynamicConvert (0.201.0): + - Flipper-Folly (~> 2.6) + - FlipperKit/FBDefines (0.201.0) + - FlipperKit/FKPortForwarding (0.201.0): + - CocoaAsyncSocket (~> 7.6) + - Flipper-PeerTalk (~> 0.0.4) + - FlipperKit/FlipperKitHighlightOverlay (0.201.0) + - FlipperKit/FlipperKitLayoutHelpers (0.201.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutTextSearchable + - FlipperKit/FlipperKitLayoutIOSDescriptors (0.201.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - FlipperKit/FlipperKitLayoutPlugin (0.201.0): + - FlipperKit/Core + - FlipperKit/FlipperKitHighlightOverlay + - FlipperKit/FlipperKitLayoutHelpers + - FlipperKit/FlipperKitLayoutIOSDescriptors + - FlipperKit/FlipperKitLayoutTextSearchable + - FlipperKit/FlipperKitLayoutTextSearchable (0.201.0) + - FlipperKit/FlipperKitNetworkPlugin (0.201.0): + - FlipperKit/Core + - FlipperKit/FlipperKitReactPlugin (0.201.0): + - FlipperKit/Core + - FlipperKit/FlipperKitUserDefaultsPlugin (0.201.0): + - FlipperKit/Core + - FlipperKit/SKIOSNetworkPlugin (0.201.0): + - FlipperKit/Core + - FlipperKit/FlipperKitNetworkPlugin - fmt (6.2.1) - glog (0.3.5) - GoogleAppMeasurement (8.8.0): @@ -233,6 +290,7 @@ PODS: - onfido-react-native-sdk (10.6.0): - Onfido (~> 29.6.0) - React + - OpenSSL-Universal (1.1.1100) - Plaid (4.7.0) - PromisesObjC (2.3.1) - RCT-Folly (2022.05.16.00): @@ -1428,11 +1486,32 @@ DEPENDENCIES: - ExpoModulesCore (from `../node_modules/expo-modules-core`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) + - Flipper (= 0.201.0) + - Flipper-Boost-iOSX (= 1.76.0.1.11) + - Flipper-DoubleConversion (= 3.2.0.1) + - Flipper-Fmt (= 7.1.7) + - Flipper-Folly (= 2.6.10) + - Flipper-Glog (= 0.5.0.5) + - Flipper-PeerTalk (= 0.0.4) + - FlipperKit (= 0.201.0) + - FlipperKit/Core (= 0.201.0) + - FlipperKit/CppBridge (= 0.201.0) + - FlipperKit/FBCxxFollyDynamicConvert (= 0.201.0) + - FlipperKit/FBDefines (= 0.201.0) + - FlipperKit/FKPortForwarding (= 0.201.0) + - FlipperKit/FlipperKitHighlightOverlay (= 0.201.0) + - FlipperKit/FlipperKitLayoutPlugin (= 0.201.0) + - FlipperKit/FlipperKitLayoutTextSearchable (= 0.201.0) + - FlipperKit/FlipperKitNetworkPlugin (= 0.201.0) + - FlipperKit/FlipperKitReactPlugin (= 0.201.0) + - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.201.0) + - FlipperKit/SKIOSNetworkPlugin (= 0.201.0) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - libevent (~> 2.1.12) - lottie-react-native (from `../node_modules/lottie-react-native`) - "onfido-react-native-sdk (from `../node_modules/@onfido/react-native-sdk`)" + - OpenSSL-Universal (= 1.1.1100) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) @@ -1441,6 +1520,7 @@ DEPENDENCIES: - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - React-Codegen (from `build/generated/ios`) - React-Core (from `../node_modules/react-native/`) + - React-Core/DevSupport (from `../node_modules/react-native/`) - React-Core/RCTWebSocket (from `../node_modules/react-native/`) - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) @@ -1527,6 +1607,7 @@ SPEC REPOS: - AirshipFrameworkProxy - AirshipServiceExtension - AppAuth + - CocoaAsyncSocket - Firebase - FirebaseABTesting - FirebaseAnalytics @@ -1536,6 +1617,14 @@ SPEC REPOS: - FirebaseInstallations - FirebasePerformance - FirebaseRemoteConfig + - Flipper + - Flipper-Boost-iOSX + - Flipper-DoubleConversion + - Flipper-Fmt + - Flipper-Folly + - Flipper-Glog + - Flipper-PeerTalk + - FlipperKit - fmt - GoogleAppMeasurement - GoogleDataTransport @@ -1555,6 +1644,7 @@ SPEC REPOS: - MapboxMobileEvents - nanopb - Onfido + - OpenSSL-Universal - Plaid - PromisesObjC - SDWebImage @@ -1774,6 +1864,7 @@ SPEC CHECKSUMS: AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570 boost: d3f49c53809116a5d38da093a8aa78bf551aed09 BVLinearGradient: 421743791a59d259aec53f4c58793aad031da2ca + CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953 EXAV: 09a4d87fa6b113fbb0ada3aade6799f78271cb44 EXImageLoader: 55080616b2fe9da19ef8c7f706afd9814e279b6b @@ -1792,6 +1883,14 @@ SPEC CHECKSUMS: FirebaseInstallations: 40bd9054049b2eae9a2c38ef1c3dd213df3605cd FirebasePerformance: 0c01a7a496657d7cea86d40c0b1725259d164c6c FirebaseRemoteConfig: 2d6e2cfdb49af79535c8af8a80a4a5009038ec2b + Flipper: c7a0093234c4bdd456e363f2f19b2e4b27652d44 + Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c + Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 + Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b + Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 + Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 + Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 + FlipperKit: 37525a5d056ef9b93d1578e04bc3ea1de940094f fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 GoogleAppMeasurement: 5ba1164e3c844ba84272555e916d0a6d3d977e91 @@ -1815,6 +1914,7 @@ SPEC CHECKSUMS: nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 Onfido: c52e797b10cc9e6d29ba91996cb62e501000bfdd onfido-react-native-sdk: 4e7f0a7a986ed93cb906d2e0b67a6aab9202de0b + OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c Plaid: 431ef9be5314a1345efb451bc5e6b067bfb3b4c6 PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0 @@ -1909,6 +2009,6 @@ SPEC CHECKSUMS: VisionCamera: 0a6794d1974aed5d653d0d0cb900493e2583e35a Yoga: 13c8ef87792450193e117976337b8527b49e8c03 -PODFILE CHECKSUM: e1c79a65c8850178491c6a63dbce41f6ea21005d +PODFILE CHECKSUM: 0ccbb4f2406893c6e9f266dc1e7470dcd72885d2 COCOAPODS: 1.15.2 From bbe03bbf049fdbe9a0cfe87b5e894adde031aa40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Mon, 11 Mar 2024 15:25:32 +0100 Subject: [PATCH 035/402] inviteUser fix --- src/pages/workspace/WorkspaceInvitePage.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/WorkspaceInvitePage.tsx b/src/pages/workspace/WorkspaceInvitePage.tsx index b85463997955..508daeb0208e 100644 --- a/src/pages/workspace/WorkspaceInvitePage.tsx +++ b/src/pages/workspace/WorkspaceInvitePage.tsx @@ -1,6 +1,6 @@ import {useNavigation} from '@react-navigation/native'; import type {StackNavigationProp, StackScreenProps} from '@react-navigation/stack'; -import React, {useEffect, useMemo, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; import type {SectionListData} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; @@ -244,7 +244,7 @@ function WorkspaceInvitePage({ return isEmptyObject(errors); }; - const inviteUser = () => { + const inviteUser = useCallback(() => { if (!validate()) { return; } @@ -260,7 +260,7 @@ function WorkspaceInvitePage({ }); Policy.setWorkspaceInviteMembersDraft(route.params.policyID, invitedEmailsToAccountIDs); Navigation.navigate(ROUTES.WORKSPACE_INVITE_MESSAGE.getRoute(route.params.policyID)); - }; + }, [route.params.policyID, selectedOptions, validate]); const [policyName, shouldShowAlertPrompt] = useMemo(() => [policy?.name ?? '', !isEmptyObject(policy?.errors) || !!policy?.alertMessage], [policy]); From c7fabe44ad987ab1a5d4f63bf9d14b527d41e425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Mon, 11 Mar 2024 15:32:31 +0100 Subject: [PATCH 036/402] even move linting --- src/pages/workspace/WorkspaceInvitePage.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/pages/workspace/WorkspaceInvitePage.tsx b/src/pages/workspace/WorkspaceInvitePage.tsx index 508daeb0208e..ce5328298e59 100644 --- a/src/pages/workspace/WorkspaceInvitePage.tsx +++ b/src/pages/workspace/WorkspaceInvitePage.tsx @@ -234,18 +234,16 @@ function WorkspaceInvitePage({ setSelectedOptions(newSelectedOptions); }; - const validate = (): boolean => { + const inviteUser = useCallback(() => { const errors: Errors = {}; if (selectedOptions.length <= 0) { errors.noUserSelected = 'true'; } Policy.setWorkspaceErrors(route.params.policyID, errors); - return isEmptyObject(errors); - }; + const isValid = isEmptyObject(errors); - const inviteUser = useCallback(() => { - if (!validate()) { + if (!isValid) { return; } @@ -260,7 +258,7 @@ function WorkspaceInvitePage({ }); Policy.setWorkspaceInviteMembersDraft(route.params.policyID, invitedEmailsToAccountIDs); Navigation.navigate(ROUTES.WORKSPACE_INVITE_MESSAGE.getRoute(route.params.policyID)); - }, [route.params.policyID, selectedOptions, validate]); + }, [route.params.policyID, selectedOptions]); const [policyName, shouldShowAlertPrompt] = useMemo(() => [policy?.name ?? '', !isEmptyObject(policy?.errors) || !!policy?.alertMessage], [policy]); From ca19777b910b48a270dd49c097d7ab4700892c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Mon, 11 Mar 2024 16:25:30 +0100 Subject: [PATCH 037/402] podfile update --- Gemfile.lock | 16 +++++++++++----- ios/Podfile.lock | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index beb2c1762936..48e2baf4494e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,11 +3,12 @@ GEM specs: CFPropertyList (3.0.6) rexml - activesupport (7.0.8) + activesupport (6.1.7.7) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) @@ -80,7 +81,8 @@ GEM declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.6.20240107) + domain_name (0.5.20190701) + unf (>= 0.0.5, < 1.0.0) dotenv (2.8.1) emoji_regex (3.2.3) escape (0.0.4) @@ -187,11 +189,11 @@ GEM google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) google-cloud-errors (1.3.1) - google-cloud-storage (1.47.0) + google-cloud-storage (1.37.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.31.0) + google-apis-storage_v1 (~> 0.1) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) @@ -260,6 +262,9 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) + unf (0.1.4) + unf_ext + unf_ext (0.0.9.1) unicode-display_width (2.5.0) word_wrap (1.0.0) xcodeproj (1.23.0) @@ -273,6 +278,7 @@ GEM rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) + zeitwerk (2.6.13) PLATFORMS arm64-darwin-21 @@ -292,4 +298,4 @@ RUBY VERSION ruby 2.6.10p210 BUNDLED WITH - 2.4.19 + 2.4.13 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 58982e5f9223..bb26b37d4015 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2017,4 +2017,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 0ccbb4f2406893c6e9f266dc1e7470dcd72885d2 -COCOAPODS: 1.15.2 +COCOAPODS: 1.13.0 From ca4a7d2b2f6d46ce959a5983ffc0371ec3384a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Mon, 11 Mar 2024 18:16:31 +0100 Subject: [PATCH 038/402] tests fixes --- tests/perf-test/SearchPage.perf-test.js | 11 ++++++++++- tests/perf-test/SelectionList.perf-test.tsx | 10 +++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/perf-test/SearchPage.perf-test.js b/tests/perf-test/SearchPage.perf-test.js index be6b6a5d78f9..02c9c8b865be 100644 --- a/tests/perf-test/SearchPage.perf-test.js +++ b/tests/perf-test/SearchPage.perf-test.js @@ -4,6 +4,7 @@ import Onyx from 'react-native-onyx'; import {measurePerformance} from 'reassure'; import _ from 'underscore'; import {LocaleContextProvider} from '@components/LocaleContextProvider'; +import {KeyboardStateProvider} from '@components/withKeyboardState'; import SearchPage from '@pages/SearchPage'; import ComposeProviders from '../../src/components/ComposeProviders'; import OnyxProvider from '../../src/components/OnyxProvider'; @@ -68,6 +69,14 @@ jest.mock('../../src/components/withNavigationFocus', () => (Component) => { return WithNavigationFocus; }); +// mock of useDismissedReferralBanners +jest.mock('../../src/hooks/useDismissedReferralBanners', () => ({ + __esModule: true, // This property is crucial for mocking default exports + default: jest.fn(() => ({ + isDismissed: false, + setAsDismissed: () => {}, + })), +})); const getMockedReports = (length = 100) => createCollection( @@ -110,7 +119,7 @@ afterEach(() => { function SearchPageWrapper(args) { return ( - + ({ createNavigationContainerRef: jest.fn(), })); +jest.mock('../../src/hooks/useKeyboardState', () => ({ + __esModule: true, // This property is crucial for mocking default exports + default: jest.fn(() => ({ + isKeyboardShown: false, + keyboardHeight: 0, + })), +})); + function SelectionListWrapper({canSelectMultiple}: SelectionListWrapperProps) { const [selectedIds, setSelectedIds] = useState([]); From 57dfaf48277196e527e6e6a08fa4b480771b715c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Mon, 11 Mar 2024 18:28:27 +0100 Subject: [PATCH 039/402] test linting fixes --- tests/perf-test/SearchPage.perf-test.js | 3 ++- tests/perf-test/SelectionList.perf-test.tsx | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/perf-test/SearchPage.perf-test.js b/tests/perf-test/SearchPage.perf-test.js index 02c9c8b865be..d9dc4370386a 100644 --- a/tests/perf-test/SearchPage.perf-test.js +++ b/tests/perf-test/SearchPage.perf-test.js @@ -71,7 +71,8 @@ jest.mock('../../src/components/withNavigationFocus', () => (Component) => { }); // mock of useDismissedReferralBanners jest.mock('../../src/hooks/useDismissedReferralBanners', () => ({ - __esModule: true, // This property is crucial for mocking default exports + // eslint-disable-next-line @typescript-eslint/naming-convention + __esModule: true, default: jest.fn(() => ({ isDismissed: false, setAsDismissed: () => {}, diff --git a/tests/perf-test/SelectionList.perf-test.tsx b/tests/perf-test/SelectionList.perf-test.tsx index 148d5170fc7b..d5a35a1e3124 100644 --- a/tests/perf-test/SelectionList.perf-test.tsx +++ b/tests/perf-test/SelectionList.perf-test.tsx @@ -6,7 +6,7 @@ import {measurePerformance} from 'reassure'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; import type {ListItem} from '@components/SelectionList/types'; -import {type KeyboardStateContextValue} from '@components/withKeyboardState'; +import type {KeyboardStateContextValue} from '@components/withKeyboardState'; import type {WithLocalizeProps} from '@components/withLocalize'; import variables from '@styles/variables'; @@ -64,7 +64,8 @@ jest.mock('@react-navigation/native', () => ({ })); jest.mock('../../src/hooks/useKeyboardState', () => ({ - __esModule: true, // This property is crucial for mocking default exports + // eslint-disable-next-line @typescript-eslint/naming-convention + __esModule: true, default: jest.fn(() => ({ isKeyboardShown: false, keyboardHeight: 0, From fa716a984c7cfccf788e4262151ad2b54f9cc3c2 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 12 Mar 2024 15:30:49 -1000 Subject: [PATCH 040/402] Add Onyx key to allow remotely resetting client data --- src/ONYXKEYS.ts | 4 ++ src/libs/actions/App.ts | 37 +++++++++++++++++++ .../settings/AboutPage/TroubleshootPage.tsx | 18 +-------- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 8c48cbad561f..26af65ea1029 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -271,6 +271,9 @@ const ONYXKEYS = { /** Indicates whether an forced upgrade is required */ UPDATE_REQUIRED: 'updateRequired', + /** Indicates whether an forced reset is required a.k.a. clear Oynx data without signing the user out */ + RESET_REQUIRED: 'resetRequired', + /** Stores the logs of the app for debugging purposes */ LOGS: 'logs', @@ -583,6 +586,7 @@ type OnyxValuesMapping = { [ONYXKEYS.LAST_VISITED_PATH]: string | undefined; [ONYXKEYS.RECENTLY_USED_REPORT_FIELDS]: OnyxTypes.RecentlyUsedReportFields; [ONYXKEYS.UPDATE_REQUIRED]: boolean; + [ONYXKEYS.RESET_REQUIRED]: boolean; [ONYXKEYS.PLAID_CURRENT_EVENT]: string; [ONYXKEYS.LOGS]: Record; [ONYXKEYS.SHOULD_STORE_LOGS]: boolean; diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts index 302e4048d0e8..6d4c79fc8843 100644 --- a/src/libs/actions/App.ts +++ b/src/libs/actions/App.ts @@ -31,6 +31,7 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {SelectedTimezone} from '@src/types/onyx/PersonalDetails'; import type {OnyxData} from '@src/types/onyx/Request'; +import type {OnyxKey} from '@src/ONYXKEYS'; import * as Policy from './Policy'; import * as Session from './Session'; import Timing from './Timing'; @@ -77,6 +78,41 @@ Onyx.connect({ }, }); +const KEYS_TO_PRESERVE: OnyxKey[] = [ + ONYXKEYS.ACCOUNT, + ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, + ONYXKEYS.IS_LOADING_APP, + ONYXKEYS.IS_SIDEBAR_LOADED, + ONYXKEYS.MODAL, + ONYXKEYS.NETWORK, + ONYXKEYS.SESSION, + ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT, + ONYXKEYS.NVP_TRY_FOCUS_MODE, + ONYXKEYS.PREFERRED_THEME, + ONYXKEYS.NVP_PREFERRED_LOCALE, + ONYXKEYS.CREDENTIALS, +]; + +let previousResetRequired: boolean|null = false; +Onyx.connect({ + key: ONYXKEYS.RESET_REQUIRED, + callback: (isResetRequired) => { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + if (previousResetRequired || !isResetRequired) { + return; + } + + previousResetRequired = isResetRequired; + Onyx.clear(KEYS_TO_PRESERVE).then(() => { + // Set this to false to reset the flag for this client + Onyx.set(ONYXKEYS.RESET_REQUIRED, false); + + // eslint-disable-next-line @typescript-eslint/no-use-before-define + openApp(); + }); + }, +}); + let resolveIsReadyPromise: () => void; const isReadyToOpenApp = new Promise((resolve) => { resolveIsReadyPromise = resolve; @@ -529,4 +565,5 @@ export { savePolicyDraftByNewWorkspace, createWorkspaceWithPolicyDraftAndNavigateToIt, updateLastVisitedPath, + KEYS_TO_PRESERVE, }; diff --git a/src/pages/settings/AboutPage/TroubleshootPage.tsx b/src/pages/settings/AboutPage/TroubleshootPage.tsx index 9bc756df03cb..5f7dfbc33323 100644 --- a/src/pages/settings/AboutPage/TroubleshootPage.tsx +++ b/src/pages/settings/AboutPage/TroubleshootPage.tsx @@ -24,25 +24,9 @@ import * as App from '@userActions/App'; import * as Report from '@userActions/Report'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {OnyxKey} from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import SCREENS from '@src/SCREENS'; -const keysToPreserve: OnyxKey[] = [ - ONYXKEYS.ACCOUNT, - ONYXKEYS.IS_CHECKING_PUBLIC_ROOM, - ONYXKEYS.IS_LOADING_APP, - ONYXKEYS.IS_SIDEBAR_LOADED, - ONYXKEYS.MODAL, - ONYXKEYS.NETWORK, - ONYXKEYS.SESSION, - ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT, - ONYXKEYS.NVP_TRY_FOCUS_MODE, - ONYXKEYS.PREFERRED_THEME, - ONYXKEYS.NVP_PREFERRED_LOCALE, - ONYXKEYS.CREDENTIALS, -]; - type BaseMenuItem = { translationKey: TranslationPaths; icon: React.FC; @@ -136,7 +120,7 @@ function TroubleshootPage({shouldStoreLogs}: TroubleshootPageProps) { isVisible={isConfirmationModalVisible} onConfirm={() => { setIsConfirmationModalVisible(false); - Onyx.clear(keysToPreserve).then(() => { + Onyx.clear(App.KEYS_TO_PRESERVE).then(() => { App.openApp(); }); }} From 9076b8ce2fa63f9f78d656d560fecebf44bb02ae Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Thu, 14 Mar 2024 00:37:09 +0530 Subject: [PATCH 041/402] prettier --- src/components/PopoverMenu.tsx | 1 - src/libs/OptionsListUtils.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index 1da7e899d3b2..4ee070e19893 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -16,7 +16,6 @@ import PopoverWithMeasuredContent from './PopoverWithMeasuredContent'; import Text from './Text'; type PopoverMenuItem = MenuItemProps & { - /** Text label */ text: string; diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 6027579211cc..3de3d1622405 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1775,7 +1775,7 @@ function getShareLogOptions(reports: OnyxCollection, personalDetails: On /** * Build the IOUConfirmation options for showing the payee personalDetail */ -function getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetail: PersonalDetails, amountText: string): PayeePersonalDetails { +function getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetail: PersonalDetails | EmptyObject, amountText?: string): PayeePersonalDetails { const formattedLogin = LocalePhoneNumber.formatPhoneNumber(personalDetail.login ?? ''); return { text: PersonalDetailsUtils.getDisplayNameOrDefault(personalDetail, formattedLogin), From 771d177346a6a43095639bd0f73bd0da3e4dd565 Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Thu, 14 Mar 2024 01:07:51 +0530 Subject: [PATCH 042/402] Migrate to typescript --- .../MoneyTemporaryForRefactorRequestConfirmationList.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index c93d16119c6a..30fed2d7df3b 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -136,9 +136,6 @@ type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps & /** List styles for OptionsSelector */ listStyles?: StyleProp; - /** ID of the transaction that represents the money request */ - transactionID?: string; - /** Transaction that represents the money request */ transaction?: OnyxEntry; @@ -164,7 +161,7 @@ type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps & }; function MoneyTemporaryForRefactorRequestConfirmationList({ - transaction, + transaction=null, onSendMoney, onConfirm, onSelectParticipant, @@ -462,7 +459,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ // Auto select the category if there is only one enabled category and it is required useEffect(() => { - const enabledCategories = _.filter(policyCategories, (category) => category.enabled); + const enabledCategories = policyCategories.filter((category: policyCategory) => category.enabled); if (iouCategory || !shouldShowCategories || enabledCategories.length !== 1 || !isCategoryRequired) { return; } @@ -481,7 +478,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ updatedTagsString = IOUUtils.insertTagIntoTransactionTagsString(updatedTagsString, enabledTags[0] ? enabledTags[0].name : '', index); }); if (updatedTagsString !== TransactionUtils.getTag(transaction) && updatedTagsString) { - IOU.setMoneyRequestTag(transaction.transactionID, updatedTagsString); + IOU.setMoneyRequestTag(transaction?.transactionID ?? '', updatedTagsString); } }, [policyTagLists, transaction, policyTags, isTagRequired, canUseViolations]); From b761e9f776c46f6ffc7de9a0fc66691c09d6631f Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Thu, 14 Mar 2024 01:33:03 +0530 Subject: [PATCH 043/402] Migrate to typescript --- ...raryForRefactorRequestConfirmationList.tsx | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index 30fed2d7df3b..600623aba286 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -161,7 +161,7 @@ type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps & }; function MoneyTemporaryForRefactorRequestConfirmationList({ - transaction=null, + transaction = null, onSendMoney, onConfirm, onSelectParticipant, @@ -430,16 +430,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ if (!hasMultipleParticipants) { return []; } - - const myIOUAmount = IOUUtils.calculateAmount(selectedParticipants.length, iouAmount, iouCurrencyCode ?? '', true); - return [ - ...selectedParticipants, - OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail( - personalDetailsOfPayee, - iouAmount > 0 ? CurrencyUtils.convertToDisplayString(myIOUAmount, iouCurrencyCode) : '', - ), - ]; - }, [selectedParticipants, hasMultipleParticipants, personalDetailsOfPayee, iouAmount, iouCurrencyCode]); + return [...selectedParticipants, OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail(personalDetailsOfPayee)]; + }, [selectedParticipants, hasMultipleParticipants, personalDetailsOfPayee]); useEffect(() => { if (!isDistanceRequest) { @@ -459,19 +451,19 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ // Auto select the category if there is only one enabled category and it is required useEffect(() => { - const enabledCategories = policyCategories.filter((category: policyCategory) => category.enabled); + const enabledCategories = Object.values(policyCategories ?? {}).filter((category) => category.enabled); if (iouCategory || !shouldShowCategories || enabledCategories.length !== 1 || !isCategoryRequired) { return; } - IOU.setMoneyRequestCategory(transaction.transactionID, enabledCategories[0].name); + IOU.setMoneyRequestCategory(transaction?.transactionID ?? '', enabledCategories[0].name); }, [iouCategory, shouldShowCategories, policyCategories, transaction, isCategoryRequired]); // Auto select the tag if there is only one enabled tag and it is required useEffect(() => { let updatedTagsString = TransactionUtils.getTag(transaction); policyTagLists.forEach((tagList, index) => { - const enabledTags = _.filter(tagList.tags, (tag) => tag.enabled); - const isTagListRequired = isUndefined(tagList.required) ? false : tagList.required && canUseViolations; + const enabledTags = Object.values(tagList.tags).filter((tag) => tag.enabled); + const isTagListRequired = tagList.required === undefined ? false : tagList.required && canUseViolations; if (!isTagListRequired || enabledTags.length !== 1 || TransactionUtils.getTag(transaction, index)) { return; } @@ -609,7 +601,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ return ( <> - {formError && ( + {!!formError && ( From 17b23615440e855c5601e4d78456405b205b13e4 Mon Sep 17 00:00:00 2001 From: Gandalf Date: Mon, 18 Mar 2024 04:29:07 +0530 Subject: [PATCH 044/402] Apply suggestions from code review Co-authored-by: Vinh Hoang --- .../MoneyTemporaryForRefactorRequestConfirmationList.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index fad46d47962c..515a64b03c8d 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -238,9 +238,9 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const shouldShowTax = isPolicyExpenseChat && (policy?.tax?.trackingEnabled ?? policy?.isTaxTrackingEnabled); // A flag for showing the billable field - const shouldShowBillable = !(policy?.disabledFields?.defaultBillable ?? true); + const shouldShowBillable = policy?.disabledFields?.defaultBillable === false; - const hasRoute = transaction ? TransactionUtils.hasRoute(transaction) : false; + const hasRoute = TransactionUtils.hasRoute(transaction); const isDistanceRequestWithPendingRoute = isDistanceRequest && (!hasRoute || !rate); const formattedAmount = isDistanceRequestWithPendingRoute ? '' @@ -279,8 +279,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const isMerchantEmpty = !iouMerchant || iouMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; const isMerchantRequired = isPolicyExpenseChat && !isScanRequest && shouldShowMerchant; - const isCategoryRequired = canUseViolations && (policy?.requiresCategory ?? false); - const isTagRequired = canUseViolations && (policy?.requiresTag ?? false); + const isCategoryRequired = canUseViolations && !!policy?.requiresCategory; + const isTagRequired = canUseViolations && !!policy?.requiresTag; useEffect(() => { if ((!isMerchantRequired && isMerchantEmpty) || !merchantError) { From 3cd8027689f3bd1e2ee3149906854d831826f697 Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Wed, 20 Mar 2024 18:17:31 +0530 Subject: [PATCH 045/402] Fix null assertions --- ...emporaryForRefactorRequestConfirmationList.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index 627a3b6ed934..cccc0b1ca6a7 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -252,7 +252,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ const defaultTaxKey = taxRates?.defaultExternalID; const defaultTaxName = (defaultTaxKey && `${taxRates?.taxes[defaultTaxKey].name} (${taxRates?.taxes[defaultTaxKey].value}) • ${translate('common.default')}`) ?? ''; - const taxRateTitle = transaction?.taxRate?.text ?? defaultTaxName; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- nullish coalescing is not working when a left hand side value is '' + const taxRateTitle = transaction?.taxRate?.text || defaultTaxName; const isFocused = useIsFocused(); const [formError, setFormError] = useState(''); @@ -268,12 +269,12 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ Navigation.goBack(ROUTES.MONEY_REQUEST_CREATE_TAB_SCAN.getRoute(iouType, transaction?.transactionID ?? '', reportID)); }; - const shouldDisplayFieldError = useMemo(() => { + const shouldDisplayFieldError: boolean = useMemo(() => { if (!isEditingSplitBill) { return false; } - return (hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction ?? null)) ?? (didConfirmSplit && TransactionUtils.areRequiredFieldsEmpty(transaction ?? null)); + return (!!hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction)) || (didConfirmSplit && TransactionUtils.areRequiredFieldsEmpty(transaction)); }, [isEditingSplitBill, hasSmartScanFailed, transaction, didConfirmSplit]); const isMerchantEmpty = !iouMerchant || iouMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; @@ -325,7 +326,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ */ const getParticipantsWithAmount = useCallback( (participantsList: Participant[]) => { - const amount = IOUUtils.calculateAmount(participantsList.length, iouAmount, iouCurrencyCode ?? 'USD'); + const amount = IOUUtils.calculateAmount(participantsList.length, iouAmount, iouCurrencyCode ?? ''); return OptionsListUtils.getIOUConfirmationOptionsFromParticipants(participantsList, amount > 0 ? CurrencyUtils.convertToDisplayString(amount, iouCurrencyCode) : ''); }, [iouAmount, iouCurrencyCode], @@ -729,7 +730,8 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ Date: Thu, 21 Mar 2024 13:13:05 +0100 Subject: [PATCH 046/402] added dismissedReferralBanners field to Account type --- src/types/onyx/Account.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index 98ce460a7669..5b9470c6ca6f 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -1,5 +1,6 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; +import type DismissedReferralBanners from './DismissedReferralBanners'; import type * as OnyxCommon from './OnyxCommon'; type TwoFactorAuthStep = ValueOf | ''; @@ -60,6 +61,7 @@ type Account = { success?: string; codesAreCopied?: boolean; twoFactorAuthStep?: TwoFactorAuthStep; + dismissedReferralBanners?: DismissedReferralBanners; }; export default Account; From fcaca2271601bc0fc2b6d0e16ccd15c0f432cd92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Thu, 21 Mar 2024 15:35:58 +0100 Subject: [PATCH 047/402] restored ios project file and Gemfile.lock --- Gemfile.lock | 16 +- ios/NewExpensify.xcodeproj/project.pbxproj | 296 ++++++++++----------- 2 files changed, 150 insertions(+), 162 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 48e2baf4494e..beb2c1762936 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,12 +3,11 @@ GEM specs: CFPropertyList (3.0.6) rexml - activesupport (6.1.7.7) + activesupport (7.0.8) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - zeitwerk (~> 2.3) addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) @@ -81,8 +80,7 @@ GEM declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) + domain_name (0.6.20240107) dotenv (2.8.1) emoji_regex (3.2.3) escape (0.0.4) @@ -189,11 +187,11 @@ GEM google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) google-cloud-errors (1.3.1) - google-cloud-storage (1.37.0) + google-cloud-storage (1.47.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.31.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) @@ -262,9 +260,6 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.9.1) unicode-display_width (2.5.0) word_wrap (1.0.0) xcodeproj (1.23.0) @@ -278,7 +273,6 @@ GEM rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) - zeitwerk (2.6.13) PLATFORMS arm64-darwin-21 @@ -298,4 +292,4 @@ RUBY VERSION ruby 2.6.10p210 BUNDLED WITH - 2.4.13 + 2.4.19 diff --git a/ios/NewExpensify.xcodeproj/project.pbxproj b/ios/NewExpensify.xcodeproj/project.pbxproj index 25791f333fe8..e39542ef0303 100644 --- a/ios/NewExpensify.xcodeproj/project.pbxproj +++ b/ios/NewExpensify.xcodeproj/project.pbxproj @@ -22,20 +22,20 @@ 1246A3EF20E54E7A9494C8B9 /* ExpensifyNeue-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = F4F8A052A22040339996324B /* ExpensifyNeue-Regular.otf */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 18D050E0262400AF000D658B /* BridgingFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18D050DF262400AF000D658B /* BridgingFile.swift */; }; - 2239AF82201DDCACD764BB13 /* libPods-NotificationServiceExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FBC515608ED5B1C9BB3BBE1E /* libPods-NotificationServiceExtension.a */; }; 26AF3C3540374A9FACB6C19E /* ExpensifyMono-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = DCF33E34FFEC48128CDD41D4 /* ExpensifyMono-Bold.otf */; }; 2A9F8CDA983746B0B9204209 /* ExpensifyNeue-Bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 52796131E6554494B2DDB056 /* ExpensifyNeue-Bold.otf */; }; 30581EA8AAFD4FCE88C5D191 /* ExpensifyNeue-Italic.otf in Resources */ = {isa = PBXBuildFile; fileRef = BF6A4C5167244B9FB8E4D4E3 /* ExpensifyNeue-Italic.otf */; }; 374FB8D728A133FE000D84EF /* OriginImageRequestHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 374FB8D628A133FE000D84EF /* OriginImageRequestHandler.mm */; }; - 5F93148A4BA62318A8A7C645 /* libPods-NewExpensify.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 693BF633137EC7920817D909 /* libPods-NewExpensify.a */; }; + 5B8996A7D8B007ECC41919E1 /* libPods-NewExpensify.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00D7E69E5ADD16FD4C44221B /* libPods-NewExpensify.a */; }; 7041848526A8E47D00E09F4D /* RCTStartupTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7041848426A8E47D00E09F4D /* RCTStartupTimer.m */; }; 7041848626A8E47D00E09F4D /* RCTStartupTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7041848426A8E47D00E09F4D /* RCTStartupTimer.m */; }; 70CF6E82262E297300711ADC /* BootSplash.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 70CF6E81262E297300711ADC /* BootSplash.storyboard */; }; - 7E087A75A723CA54A1A24B29 /* libPods-NewExpensify-NewExpensifyTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AF7D26E85173CA31D45150D2 /* libPods-NewExpensify-NewExpensifyTests.a */; }; + 716815DBCE9F49D420334791 /* libPods-NewExpensify-NewExpensifyTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B68AEB9429D8BB73F25A188C /* libPods-NewExpensify-NewExpensifyTests.a */; }; 7F5E81F06BCCF61AD02CEA06 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCD444BEDDB0AF1745B39049 /* ExpoModulesProvider.swift */; }; 7F9DD8DA2B2A445B005E3AFA /* ExpError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F9DD8D92B2A445B005E3AFA /* ExpError.swift */; }; 7FD73C9E2B23CE9500420AF3 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FD73C9D2B23CE9500420AF3 /* NotificationService.swift */; }; 7FD73CA22B23CE9500420AF3 /* NotificationServiceExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 7FD73C9B2B23CE9500420AF3 /* NotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + B8A1CD44D011AD7AE180DE14 /* libPods-NotificationServiceExtension.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B944D5699A54FD5197A63866 /* libPods-NotificationServiceExtension.a */; }; BDB853621F354EBB84E619C2 /* ExpensifyNewKansas-MediumItalic.otf in Resources */ = {isa = PBXBuildFile; fileRef = D2AFB39EC1D44BF9B91D3227 /* ExpensifyNewKansas-MediumItalic.otf */; }; DD79042B2792E76D004484B4 /* RCTBootSplash.m in Sources */ = {isa = PBXBuildFile; fileRef = DD79042A2792E76D004484B4 /* RCTBootSplash.m */; }; DDCB2E57F334C143AC462B43 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D20D83B0E39BA6D21761E72 /* ExpoModulesProvider.swift */; }; @@ -79,8 +79,10 @@ /* Begin PBXFileReference section */ 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; + 00D7E69E5ADD16FD4C44221B /* libPods-NewExpensify.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NewExpensify.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356EE1AD99517003FC87E /* NewExpensifyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NewExpensifyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 030F99CEB3AEF1F11B001798 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig"; sourceTree = ""; }; 083353E72B5AB22900C603C0 /* attention.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = attention.mp3; path = ../assets/sounds/attention.mp3; sourceTree = ""; }; 083353E82B5AB22900C603C0 /* done.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = done.mp3; path = ../assets/sounds/done.mp3; sourceTree = ""; }; 083353E92B5AB22900C603C0 /* receive.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = receive.mp3; path = ../assets/sounds/receive.mp3; sourceTree = ""; }; @@ -90,57 +92,55 @@ 0F5BE0CD252686320097D869 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 0F5E534E263B73D5004CA14F /* EnvironmentChecker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EnvironmentChecker.h; sourceTree = ""; }; 0F5E534F263B73FD004CA14F /* EnvironmentChecker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EnvironmentChecker.m; sourceTree = ""; }; - 118316C3ED3B8AF1B8DDB462 /* Pods-NewExpensify.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releaseproduction.xcconfig"; sourceTree = ""; }; - 1326323F1F0F6464B455D650 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releasedevelopment.xcconfig"; sourceTree = ""; }; + 0FF2BC0D01CA2C62CE94229E /* Pods-NewExpensify.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugdevelopment.xcconfig"; sourceTree = ""; }; + 11B2BA236BB72A603FBB7B99 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releasedevelopment.xcconfig"; sourceTree = ""; }; + 12EB734390650799DB8AC627 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugdevelopment.xcconfig"; sourceTree = ""; }; 13B07F961A680F5B00A75B9A /* New Expensify Dev.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "New Expensify Dev.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = NewExpensify/AppDelegate.h; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = NewExpensify/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = NewExpensify/main.m; sourceTree = ""; }; 18D050DF262400AF000D658B /* BridgingFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BridgingFile.swift; sourceTree = ""; }; - 28D3313BDBBA720056DD2D1D /* Pods-NewExpensify.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugdevelopment.xcconfig"; sourceTree = ""; }; - 2C134EA1A00BF7EE88676822 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugproduction.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugproduction.xcconfig"; sourceTree = ""; }; - 2E51C885FF70D2D7A54456E6 /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig"; sourceTree = ""; }; + 3328C9B8861CA667C42B47F3 /* Pods-NewExpensify.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugproduction.xcconfig"; sourceTree = ""; }; 374FB8D528A133A7000D84EF /* OriginImageRequestHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OriginImageRequestHandler.h; path = NewExpensify/OriginImageRequestHandler.h; sourceTree = ""; }; 374FB8D628A133FE000D84EF /* OriginImageRequestHandler.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = OriginImageRequestHandler.mm; path = NewExpensify/OriginImageRequestHandler.mm; sourceTree = ""; }; - 3ADC0A6CC754720C1DC37C70 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugdevelopment.xcconfig"; sourceTree = ""; }; 44BF435285B94E5B95F90994 /* ExpensifyNewKansas-Medium.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNewKansas-Medium.otf"; path = "../assets/fonts/native/ExpensifyNewKansas-Medium.otf"; sourceTree = ""; }; - 487DEEE877D99104D2B59897 /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig"; sourceTree = ""; }; + 466D03D63F4B48E009C04FA3 /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig"; sourceTree = ""; }; 4D20D83B0E39BA6D21761E72 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-NewExpensify/ExpoModulesProvider.swift"; sourceTree = ""; }; 52796131E6554494B2DDB056 /* ExpensifyNeue-Bold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNeue-Bold.otf"; path = "../assets/fonts/native/ExpensifyNeue-Bold.otf"; sourceTree = ""; }; - 5AD4EA6C51AF26EE4290EDDF /* Pods-NewExpensify.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releasedevelopment.xcconfig"; sourceTree = ""; }; - 693BF633137EC7920817D909 /* libPods-NewExpensify.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NewExpensify.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5A1F158A9A6CBE170EC19D9C /* Pods-NewExpensify.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugadhoc.xcconfig"; sourceTree = ""; }; 7041848326A8E40900E09F4D /* RCTStartupTimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RCTStartupTimer.h; path = NewExpensify/RCTStartupTimer.h; sourceTree = ""; }; 7041848426A8E47D00E09F4D /* RCTStartupTimer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RCTStartupTimer.m; path = NewExpensify/RCTStartupTimer.m; sourceTree = ""; }; 70CF6E81262E297300711ADC /* BootSplash.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = BootSplash.storyboard; path = NewExpensify/BootSplash.storyboard; sourceTree = ""; }; - 7815BCDA0F80A5988AE4FE23 /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig"; sourceTree = ""; }; - 7A64A8F5BD1DA6D2B1C999A6 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig"; sourceTree = ""; }; + 7312B334B72E8BE41A811FAB /* Pods-NewExpensify.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releaseadhoc.xcconfig"; sourceTree = ""; }; 7F9DD8D92B2A445B005E3AFA /* ExpError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpError.swift; sourceTree = ""; }; 7FD73C9B2B23CE9500420AF3 /* NotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 7FD73C9D2B23CE9500420AF3 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; 7FD73C9F2B23CE9500420AF3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 895D008CD95C08405C079218 /* Pods-NewExpensify.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugproduction.xcconfig"; sourceTree = ""; }; + 802CB9E7554756F188C79554 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugadhoc.xcconfig"; sourceTree = ""; }; 8B28D84EF339436DBD42A203 /* ExpensifyNeue-BoldItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNeue-BoldItalic.otf"; path = "../assets/fonts/native/ExpensifyNeue-BoldItalic.otf"; sourceTree = ""; }; - A672C55E4E62105209DA6787 /* Pods-NewExpensify.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.debugadhoc.xcconfig"; sourceTree = ""; }; - AF7D26E85173CA31D45150D2 /* libPods-NewExpensify-NewExpensifyTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NewExpensify-NewExpensifyTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - BCAF64296F330579F0E7B41B /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig"; sourceTree = ""; }; + 96ADA7C82BA6A08C4A56344A /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releaseproduction.xcconfig"; sourceTree = ""; }; + 972584042DB4782F830B063A /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig"; sourceTree = ""; }; + 9EADA69D62F2E7B3D96E5B1C /* Pods-NewExpensify.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releaseproduction.xcconfig"; sourceTree = ""; }; + AC9422F6C8A49AE701481721 /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releaseadhoc.xcconfig"; sourceTree = ""; }; + B4CF7147C89747459BAC5BB7 /* Pods-NewExpensify.releasedevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releasedevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releasedevelopment.xcconfig"; sourceTree = ""; }; + B68AEB9429D8BB73F25A188C /* libPods-NewExpensify-NewExpensifyTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NewExpensify-NewExpensifyTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + B944D5699A54FD5197A63866 /* libPods-NotificationServiceExtension.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NotificationServiceExtension.a"; sourceTree = BUILT_PRODUCTS_DIR; }; BCD444BEDDB0AF1745B39049 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-NewExpensify-NewExpensifyTests/ExpoModulesProvider.swift"; sourceTree = ""; }; BF6A4C5167244B9FB8E4D4E3 /* ExpensifyNeue-Italic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNeue-Italic.otf"; path = "../assets/fonts/native/ExpensifyNeue-Italic.otf"; sourceTree = ""; }; - C4BB00AA2BEAE6FCE6E069CA /* Pods-NewExpensify.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify/Pods-NewExpensify.releaseadhoc.xcconfig"; sourceTree = ""; }; - CCE8C26BA229E4E25F239908 /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releaseproduction.xcconfig"; sourceTree = ""; }; + CB32BB7E082E2450F04DA6E7 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugproduction.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugproduction.xcconfig"; sourceTree = ""; }; + D15262BE5F713CDB4DA576AE /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig"; sourceTree = ""; }; D2AFB39EC1D44BF9B91D3227 /* ExpensifyNewKansas-MediumItalic.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNewKansas-MediumItalic.otf"; path = "../assets/fonts/native/ExpensifyNewKansas-MediumItalic.otf"; sourceTree = ""; }; - D9EBB16906B99F38BCCDD92C /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.releaseadhoc.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.releaseadhoc.xcconfig"; sourceTree = ""; }; DCF33E34FFEC48128CDD41D4 /* ExpensifyMono-Bold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyMono-Bold.otf"; path = "../assets/fonts/native/ExpensifyMono-Bold.otf"; sourceTree = ""; }; DD7904292792E76D004484B4 /* RCTBootSplash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTBootSplash.h; path = NewExpensify/RCTBootSplash.h; sourceTree = ""; }; DD79042A2792E76D004484B4 /* RCTBootSplash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RCTBootSplash.m; path = NewExpensify/RCTBootSplash.m; sourceTree = ""; }; - E4BC28C56B6C1763152D4F93 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationServiceExtension.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NotificationServiceExtension/Pods-NotificationServiceExtension.debugadhoc.xcconfig"; sourceTree = ""; }; E704648954784DDFBAADF568 /* ExpensifyMono-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyMono-Regular.otf"; path = "../assets/fonts/native/ExpensifyMono-Regular.otf"; sourceTree = ""; }; + E750C93A45B47BDC5149C5AA /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig"; sourceTree = ""; }; E9DF872C2525201700607FDC /* AirshipConfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = AirshipConfig.plist; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED2971642150620600B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS12.0.sdk/System/Library/Frameworks/JavaScriptCore.framework; sourceTree = DEVELOPER_DIR; }; F0C450E92705020500FD2970 /* colors.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = colors.json; path = ../colors.json; sourceTree = ""; }; F4F8A052A22040339996324B /* ExpensifyNeue-Regular.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyNeue-Regular.otf"; path = "../assets/fonts/native/ExpensifyNeue-Regular.otf"; sourceTree = ""; }; - F82148F45FC67E2D0CCB54DB /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig"; sourceTree = ""; }; - FBC515608ED5B1C9BB3BBE1E /* libPods-NotificationServiceExtension.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-NotificationServiceExtension.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + F98306ABF3F272DF04DF65CC /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig"; path = "Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -148,7 +148,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7E087A75A723CA54A1A24B29 /* libPods-NewExpensify-NewExpensifyTests.a in Frameworks */, + 716815DBCE9F49D420334791 /* libPods-NewExpensify-NewExpensifyTests.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -158,7 +158,7 @@ files = ( E51DC681C7DEE40AEBDDFBFE /* BuildFile in Frameworks */, E51DC681C7DEE40AEBDDFBFE /* BuildFile in Frameworks */, - 5F93148A4BA62318A8A7C645 /* libPods-NewExpensify.a in Frameworks */, + 5B8996A7D8B007ECC41919E1 /* libPods-NewExpensify.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -166,7 +166,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 2239AF82201DDCACD764BB13 /* libPods-NotificationServiceExtension.a in Frameworks */, + B8A1CD44D011AD7AE180DE14 /* libPods-NotificationServiceExtension.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -212,9 +212,9 @@ children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, ED2971642150620600B7C4FE /* JavaScriptCore.framework */, - 693BF633137EC7920817D909 /* libPods-NewExpensify.a */, - AF7D26E85173CA31D45150D2 /* libPods-NewExpensify-NewExpensifyTests.a */, - FBC515608ED5B1C9BB3BBE1E /* libPods-NotificationServiceExtension.a */, + 00D7E69E5ADD16FD4C44221B /* libPods-NewExpensify.a */, + B68AEB9429D8BB73F25A188C /* libPods-NewExpensify-NewExpensifyTests.a */, + B944D5699A54FD5197A63866 /* libPods-NotificationServiceExtension.a */, ); name = Frameworks; sourceTree = ""; @@ -319,24 +319,24 @@ EC29677F0A49C2946A495A33 /* Pods */ = { isa = PBXGroup; children = ( - 28D3313BDBBA720056DD2D1D /* Pods-NewExpensify.debugdevelopment.xcconfig */, - A672C55E4E62105209DA6787 /* Pods-NewExpensify.debugadhoc.xcconfig */, - 895D008CD95C08405C079218 /* Pods-NewExpensify.debugproduction.xcconfig */, - 5AD4EA6C51AF26EE4290EDDF /* Pods-NewExpensify.releasedevelopment.xcconfig */, - C4BB00AA2BEAE6FCE6E069CA /* Pods-NewExpensify.releaseadhoc.xcconfig */, - 118316C3ED3B8AF1B8DDB462 /* Pods-NewExpensify.releaseproduction.xcconfig */, - BCAF64296F330579F0E7B41B /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */, - 7815BCDA0F80A5988AE4FE23 /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */, - 7A64A8F5BD1DA6D2B1C999A6 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */, - 2E51C885FF70D2D7A54456E6 /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */, - 487DEEE877D99104D2B59897 /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */, - F82148F45FC67E2D0CCB54DB /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */, - 3ADC0A6CC754720C1DC37C70 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */, - E4BC28C56B6C1763152D4F93 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */, - 2C134EA1A00BF7EE88676822 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */, - 1326323F1F0F6464B455D650 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */, - D9EBB16906B99F38BCCDD92C /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */, - CCE8C26BA229E4E25F239908 /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */, + 0FF2BC0D01CA2C62CE94229E /* Pods-NewExpensify.debugdevelopment.xcconfig */, + 5A1F158A9A6CBE170EC19D9C /* Pods-NewExpensify.debugadhoc.xcconfig */, + B4CF7147C89747459BAC5BB7 /* Pods-NewExpensify.releasedevelopment.xcconfig */, + 7312B334B72E8BE41A811FAB /* Pods-NewExpensify.releaseadhoc.xcconfig */, + 9EADA69D62F2E7B3D96E5B1C /* Pods-NewExpensify.releaseproduction.xcconfig */, + E750C93A45B47BDC5149C5AA /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */, + F98306ABF3F272DF04DF65CC /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */, + 972584042DB4782F830B063A /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */, + D15262BE5F713CDB4DA576AE /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */, + 466D03D63F4B48E009C04FA3 /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */, + 12EB734390650799DB8AC627 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */, + 802CB9E7554756F188C79554 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */, + CB32BB7E082E2450F04DA6E7 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */, + 11B2BA236BB72A603FBB7B99 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */, + AC9422F6C8A49AE701481721 /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */, + 96ADA7C82BA6A08C4A56344A /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */, + 3328C9B8861CA667C42B47F3 /* Pods-NewExpensify.debugproduction.xcconfig */, + 030F99CEB3AEF1F11B001798 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */, ); path = Pods; sourceTree = ""; @@ -348,13 +348,13 @@ isa = PBXNativeTarget; buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "NewExpensifyTests" */; buildPhases = ( - 7E80618A74B6DCA69B2235B0 /* [CP] Check Pods Manifest.lock */, + D128CAF2A1070B0F2B3F12E4 /* [CP] Check Pods Manifest.lock */, 04B99F6AA578E2A877802F05 /* [Expo] Configure project */, 00E356EA1AD99517003FC87E /* Sources */, 00E356EB1AD99517003FC87E /* Frameworks */, 00E356EC1AD99517003FC87E /* Resources */, - A1F6CDF530E0E676103C87B8 /* [CP] Embed Pods Frameworks */, - 0BA8C24A2E3B4744463F5218 /* [CP] Copy Pods Resources */, + CE4668E6E6809DEA0626B5B3 /* [CP] Copy Pods Resources */, + 47778FAEB28E5E04DCCD0D39 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -370,7 +370,7 @@ isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "NewExpensify" */; buildPhases = ( - 0A069F4A42921D0ABD687724 /* [CP] Check Pods Manifest.lock */, + 5DDD2A7C43E9B381CD68A232 /* [CP] Check Pods Manifest.lock */, FD10A7F022414F080027D42C /* Start Packager */, 5CF45ABA52C0BB0D7B9D139A /* [Expo] Configure project */, 13B07F871A680F5B00A75B9A /* Sources */, @@ -378,10 +378,10 @@ 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - 4EA6523186EFC3CCB644579C /* [CP] Embed Pods Frameworks */, - 48E1EC426A7897E0987A036D /* [CP] Copy Pods Resources */, - 404E26EB01AE2A3634C7D371 /* [CP-User] [RNFB] Core Configuration */, - 6177438839C568C34E791D22 /* [CP-User] [RNFB] Crashlytics Configuration */, + 50067B6C26F88BAB5F0B478A /* [CP] Embed Pods Frameworks */, + 4E1386759AEE7859543483C9 /* [CP] Copy Pods Resources */, + EEA310C4723D0EF8581FAA1D /* [CP-User] [RNFB] Core Configuration */, + A9A9BDEB11952C562415526C /* [CP-User] [RNFB] Crashlytics Configuration */, ); buildRules = ( ); @@ -397,7 +397,7 @@ isa = PBXNativeTarget; buildConfigurationList = 7FD73CAA2B23CE9500420AF3 /* Build configuration list for PBXNativeTarget "NotificationServiceExtension" */; buildPhases = ( - 7762969E03A5E5E9207F0678 /* [CP] Check Pods Manifest.lock */, + 7B34459944ACFD30D85D5F85 /* [CP] Check Pods Manifest.lock */, 7FD73C972B23CE9500420AF3 /* Sources */, 7FD73C982B23CE9500420AF3 /* Frameworks */, 7FD73C992B23CE9500420AF3 /* Resources */, @@ -534,29 +534,7 @@ shellPath = /bin/sh; shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-NewExpensify-NewExpensifyTests/expo-configure-project.sh\"\n"; }; - 0A069F4A42921D0ABD687724 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-NewExpensify-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 0BA8C24A2E3B4744463F5218 /* [CP] Copy Pods Resources */ = { + 47778FAEB28E5E04DCCD0D39 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -572,7 +550,7 @@ "${PODS_XCFRAMEWORKS_BUILD_DIR}/Plaid/LinkKit.framework/LinkKit", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", ); - name = "[CP] Copy Pods Resources"; + name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMaps.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Turf.framework", @@ -585,23 +563,10 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-resources.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 404E26EB01AE2A3634C7D371 /* [CP-User] [RNFB] Core Configuration */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", - ); - name = "[CP-User] [RNFB] Core Configuration"; - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n _JSON_OUTPUT_BASE64=$(python -c 'import json,sys,base64;print(base64.b64encode(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"').read())['${_JSON_ROOT}'])))' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; - }; - 48E1EC426A7897E0987A036D /* [CP] Copy Pods Resources */ = { + 4E1386759AEE7859543483C9 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -633,7 +598,7 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify/Pods-NewExpensify-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 4EA6523186EFC3CCB644579C /* [CP] Embed Pods Frameworks */ = { + 50067B6C26F88BAB5F0B478A /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -684,21 +649,29 @@ shellPath = /bin/sh; shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-NewExpensify/expo-configure-project.sh\"\n"; }; - 6177438839C568C34E791D22 /* [CP-User] [RNFB] Crashlytics Configuration */ = { + 5DDD2A7C43E9B381CD68A232 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( - "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}", - "$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-NewExpensify-checkManifestLockResult.txt", ); - name = "[CP-User] [RNFB] Crashlytics Configuration"; runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\nif [[ ${PODS_ROOT} ]]; then\n echo \"info: Exec FirebaseCrashlytics Run from Pods\"\n \"${PODS_ROOT}/FirebaseCrashlytics/run\"\nelse\n echo \"info: Exec FirebaseCrashlytics Run from framework\"\n \"${PROJECT_DIR}/FirebaseCrashlytics.framework/run\"\nfi\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; }; - 7762969E03A5E5E9207F0678 /* [CP] Check Pods Manifest.lock */ = { + 7B34459944ACFD30D85D5F85 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -720,7 +693,53 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 7E80618A74B6DCA69B2235B0 /* [CP] Check Pods Manifest.lock */ = { + A9A9BDEB11952C562415526C /* [CP-User] [RNFB] Crashlytics Configuration */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}", + "$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", + ); + name = "[CP-User] [RNFB] Crashlytics Configuration"; + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\nif [[ ${PODS_ROOT} ]]; then\n echo \"info: Exec FirebaseCrashlytics Run from Pods\"\n \"${PODS_ROOT}/FirebaseCrashlytics/run\"\nelse\n echo \"info: Exec FirebaseCrashlytics Run from framework\"\n \"${PROJECT_DIR}/FirebaseCrashlytics.framework/run\"\nfi\n"; + }; + CE4668E6E6809DEA0626B5B3 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipAutomationResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipCoreResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipExtendedActionsResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipMessageCenterResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/Airship/AirshipPreferenceCenterResources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/GoogleSignIn/GoogleSignIn.bundle", + "${PODS_ROOT}/../../node_modules/@expensify/react-native-live-markdown/parser/react-native-live-markdown-parser.js", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipAutomationResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipCoreResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipExtendedActionsResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipMessageCenterResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AirshipPreferenceCenterResources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/react-native-live-markdown-parser.js", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + D128CAF2A1070B0F2B3F12E4 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -742,43 +761,18 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - A1F6CDF530E0E676103C87B8 /* [CP] Embed Pods Frameworks */ = { + EEA310C4723D0EF8581FAA1D /* [CP-User] [RNFB] Core Configuration */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/MapboxMaps/MapboxMaps.framework", - "${BUILT_PRODUCTS_DIR}/Turf/Turf.framework", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-DoubleConversion/double-conversion.framework/double-conversion", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Flipper-Glog/glog.framework/glog", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCommon/MapboxCommon.framework/MapboxCommon", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCoreMaps/MapboxCoreMaps.framework/MapboxCoreMaps", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxMobileEvents/MapboxMobileEvents.framework/MapboxMobileEvents", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Onfido/Onfido.framework/Onfido", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/OpenSSL-Universal/OpenSSL.framework/OpenSSL", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/Plaid/LinkKit.framework/LinkKit", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMaps.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Turf.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/double-conversion.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCommon.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCoreMaps.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMobileEvents.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Onfido.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/LinkKit.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", + "$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", ); + name = "[CP-User] [RNFB] Core Configuration"; runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "#!/usr/bin/env bash\n#\n# Copyright (c) 2016-present Invertase Limited & Contributors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this library except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\nset -e\n\n_MAX_LOOKUPS=2;\n_SEARCH_RESULT=''\n_RN_ROOT_EXISTS=''\n_CURRENT_LOOKUPS=1\n_JSON_ROOT=\"'react-native'\"\n_JSON_FILE_NAME='firebase.json'\n_JSON_OUTPUT_BASE64='e30=' # { }\n_CURRENT_SEARCH_DIR=${PROJECT_DIR}\n_PLIST_BUDDY=/usr/libexec/PlistBuddy\n_TARGET_PLIST=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n_DSYM_PLIST=\"${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist\"\n\n# plist arrays\n_PLIST_ENTRY_KEYS=()\n_PLIST_ENTRY_TYPES=()\n_PLIST_ENTRY_VALUES=()\n\nfunction setPlistValue {\n echo \"info: setting plist entry '$1' of type '$2' in file '$4'\"\n ${_PLIST_BUDDY} -c \"Add :$1 $2 '$3'\" $4 || echo \"info: '$1' already exists\"\n}\n\nfunction getFirebaseJsonKeyValue () {\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$1'); puts output[$_JSON_ROOT]['$2']\"\n else\n echo \"\"\n fi;\n}\n\nfunction jsonBoolToYesNo () {\n if [[ $1 == \"false\" ]]; then\n echo \"NO\"\n elif [[ $1 == \"true\" ]]; then\n echo \"YES\"\n else echo \"NO\"\n fi\n}\n\necho \"info: -> RNFB build script started\"\necho \"info: 1) Locating ${_JSON_FILE_NAME} file:\"\n\nif [[ -z ${_CURRENT_SEARCH_DIR} ]]; then\n _CURRENT_SEARCH_DIR=$(pwd)\nfi;\n\nwhile true; do\n _CURRENT_SEARCH_DIR=$(dirname \"$_CURRENT_SEARCH_DIR\")\n if [[ \"$_CURRENT_SEARCH_DIR\" == \"/\" ]] || [[ ${_CURRENT_LOOKUPS} -gt ${_MAX_LOOKUPS} ]]; then break; fi;\n echo \"info: ($_CURRENT_LOOKUPS of $_MAX_LOOKUPS) Searching in '$_CURRENT_SEARCH_DIR' for a ${_JSON_FILE_NAME} file.\"\n _SEARCH_RESULT=$(find \"$_CURRENT_SEARCH_DIR\" -maxdepth 2 -name ${_JSON_FILE_NAME} -print | /usr/bin/head -n 1)\n if [[ ${_SEARCH_RESULT} ]]; then\n echo \"info: ${_JSON_FILE_NAME} found at $_SEARCH_RESULT\"\n break;\n fi;\n _CURRENT_LOOKUPS=$((_CURRENT_LOOKUPS+1))\ndone\n\nif [[ ${_SEARCH_RESULT} ]]; then\n _JSON_OUTPUT_RAW=$(cat \"${_SEARCH_RESULT}\")\n _RN_ROOT_EXISTS=$(ruby -e \"require 'rubygems';require 'json'; output=JSON.parse('$_JSON_OUTPUT_RAW'); puts output[$_JSON_ROOT]\" || echo '')\n\n if [[ ${_RN_ROOT_EXISTS} ]]; then\n _JSON_OUTPUT_BASE64=$(python -c 'import json,sys,base64;print(base64.b64encode(json.dumps(json.loads(open('\"'${_SEARCH_RESULT}'\"').read())['${_JSON_ROOT}'])))' || echo \"e30=\")\n fi\n\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n\n # config.app_data_collection_default_enabled\n _APP_DATA_COLLECTION_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_data_collection_default_enabled\")\n if [[ $_APP_DATA_COLLECTION_ENABLED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseDataCollectionDefaultEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_DATA_COLLECTION_ENABLED\")\")\n fi\n\n # config.analytics_auto_collection_enabled\n _ANALYTICS_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_auto_collection_enabled\")\n if [[ $_ANALYTICS_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_AUTO_COLLECTION\")\")\n fi\n\n # config.analytics_collection_deactivated\n _ANALYTICS_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_collection_deactivated\")\n if [[ $_ANALYTICS_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_DEACTIVATED\")\")\n fi\n\n # config.analytics_idfv_collection_enabled\n _ANALYTICS_IDFV_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_idfv_collection_enabled\")\n if [[ $_ANALYTICS_IDFV_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_IDFV_COLLECTION\")\")\n fi\n\n # config.analytics_default_allow_ad_personalization_signals\n _ANALYTICS_PERSONALIZATION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"analytics_default_allow_ad_personalization_signals\")\n if [[ $_ANALYTICS_PERSONALIZATION ]]; then\n _PLIST_ENTRY_KEYS+=(\"GOOGLE_ANALYTICS_DEFAULT_ALLOW_AD_PERSONALIZATION_SIGNALS\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_ANALYTICS_PERSONALIZATION\")\")\n fi\n\n # config.perf_auto_collection_enabled\n _PERF_AUTO_COLLECTION=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_auto_collection_enabled\")\n if [[ $_PERF_AUTO_COLLECTION ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_enabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_AUTO_COLLECTION\")\")\n fi\n\n # config.perf_collection_deactivated\n _PERF_DEACTIVATED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"perf_collection_deactivated\")\n if [[ $_PERF_DEACTIVATED ]]; then\n _PLIST_ENTRY_KEYS+=(\"firebase_performance_collection_deactivated\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_PERF_DEACTIVATED\")\")\n fi\n\n # config.messaging_auto_init_enabled\n _MESSAGING_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"messaging_auto_init_enabled\")\n if [[ $_MESSAGING_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseMessagingAutoInitEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_MESSAGING_AUTO_INIT\")\")\n fi\n\n # config.in_app_messaging_auto_colllection_enabled\n _FIAM_AUTO_INIT=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"in_app_messaging_auto_collection_enabled\")\n if [[ $_FIAM_AUTO_INIT ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseInAppMessagingAutomaticDataCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_FIAM_AUTO_INIT\")\")\n fi\n\n # config.app_check_token_auto_refresh\n _APP_CHECK_TOKEN_AUTO_REFRESH=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"app_check_token_auto_refresh\")\n if [[ $_APP_CHECK_TOKEN_AUTO_REFRESH ]]; then\n _PLIST_ENTRY_KEYS+=(\"FirebaseAppCheckTokenAutoRefreshEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"$(jsonBoolToYesNo \"$_APP_CHECK_TOKEN_AUTO_REFRESH\")\")\n fi\n\n # config.crashlytics_disable_auto_disabler - undocumented for now - mainly for debugging, document if becomes useful\n _CRASHLYTICS_AUTO_DISABLE_ENABLED=$(getFirebaseJsonKeyValue \"$_JSON_OUTPUT_RAW\" \"crashlytics_disable_auto_disabler\")\n if [[ $_CRASHLYTICS_AUTO_DISABLE_ENABLED == \"true\" ]]; then\n echo \"Disabled Crashlytics auto disabler.\" # do nothing\n else\n _PLIST_ENTRY_KEYS+=(\"FirebaseCrashlyticsCollectionEnabled\")\n _PLIST_ENTRY_TYPES+=(\"bool\")\n _PLIST_ENTRY_VALUES+=(\"NO\")\n fi\nelse\n _PLIST_ENTRY_KEYS+=(\"firebase_json_raw\")\n _PLIST_ENTRY_TYPES+=(\"string\")\n _PLIST_ENTRY_VALUES+=(\"$_JSON_OUTPUT_BASE64\")\n echo \"warning: A firebase.json file was not found, whilst this file is optional it is recommended to include it to configure firebase services in React Native Firebase.\"\nfi;\n\necho \"info: 2) Injecting Info.plist entries: \"\n\n# Log out the keys we're adding\nfor i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n echo \" -> $i) ${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\"\ndone\n\nfor plist in \"${_TARGET_PLIST}\" \"${_DSYM_PLIST}\" ; do\n if [[ -f \"${plist}\" ]]; then\n\n # paths with spaces break the call to setPlistValue. temporarily modify\n # the shell internal field separator variable (IFS), which normally\n # includes spaces, to consist only of line breaks\n oldifs=$IFS\n IFS=\"\n\"\n\n for i in \"${!_PLIST_ENTRY_KEYS[@]}\"; do\n setPlistValue \"${_PLIST_ENTRY_KEYS[$i]}\" \"${_PLIST_ENTRY_TYPES[$i]}\" \"${_PLIST_ENTRY_VALUES[$i]}\" \"${plist}\"\n done\n\n # restore the original internal field separator value\n IFS=$oldifs\n else\n echo \"warning: A Info.plist build output file was not found (${plist})\"\n fi\ndone\n\necho \"info: <- RNFB build script finished\"\n"; }; FD10A7F022414F080027D42C /* Start Packager */ = { isa = PBXShellScriptBuildPhase; @@ -855,7 +849,7 @@ /* Begin XCBuildConfiguration section */ 00E356F61AD99517003FC87E /* DebugDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = BCAF64296F330579F0E7B41B /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */; + baseConfigurationReference = E750C93A45B47BDC5149C5AA /* Pods-NewExpensify-NewExpensifyTests.debugdevelopment.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -885,7 +879,7 @@ }; 00E356F71AD99517003FC87E /* ReleaseDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2E51C885FF70D2D7A54456E6 /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */; + baseConfigurationReference = 972584042DB4782F830B063A /* Pods-NewExpensify-NewExpensifyTests.releasedevelopment.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -912,7 +906,7 @@ }; 13B07F941A680F5B00A75B9A /* DebugDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 28D3313BDBBA720056DD2D1D /* Pods-NewExpensify.debugdevelopment.xcconfig */; + baseConfigurationReference = 0FF2BC0D01CA2C62CE94229E /* Pods-NewExpensify.debugdevelopment.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDev; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -951,7 +945,7 @@ }; 13B07F951A680F5B00A75B9A /* ReleaseDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5AD4EA6C51AF26EE4290EDDF /* Pods-NewExpensify.releasedevelopment.xcconfig */; + baseConfigurationReference = B4CF7147C89747459BAC5BB7 /* Pods-NewExpensify.releasedevelopment.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIconDev; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -988,7 +982,7 @@ }; 7FD73CA42B23CE9500420AF3 /* DebugDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 3ADC0A6CC754720C1DC37C70 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */; + baseConfigurationReference = 12EB734390650799DB8AC627 /* Pods-NotificationServiceExtension.debugdevelopment.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1074,7 +1068,7 @@ }; 7FD73CA52B23CE9500420AF3 /* DebugAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E4BC28C56B6C1763152D4F93 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */; + baseConfigurationReference = 802CB9E7554756F188C79554 /* Pods-NotificationServiceExtension.debugadhoc.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1159,7 +1153,7 @@ }; 7FD73CA62B23CE9500420AF3 /* DebugProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2C134EA1A00BF7EE88676822 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */; + baseConfigurationReference = CB32BB7E082E2450F04DA6E7 /* Pods-NotificationServiceExtension.debugproduction.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1245,7 +1239,7 @@ }; 7FD73CA72B23CE9500420AF3 /* ReleaseDevelopment */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 1326323F1F0F6464B455D650 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */; + baseConfigurationReference = 11B2BA236BB72A603FBB7B99 /* Pods-NotificationServiceExtension.releasedevelopment.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1324,7 +1318,7 @@ }; 7FD73CA82B23CE9500420AF3 /* ReleaseAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D9EBB16906B99F38BCCDD92C /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */; + baseConfigurationReference = AC9422F6C8A49AE701481721 /* Pods-NotificationServiceExtension.releaseadhoc.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1402,7 +1396,7 @@ }; 7FD73CA92B23CE9500420AF3 /* ReleaseProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = CCE8C26BA229E4E25F239908 /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */; + baseConfigurationReference = 96ADA7C82BA6A08C4A56344A /* Pods-NotificationServiceExtension.releaseproduction.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1697,7 +1691,7 @@ }; CF9AF93F29EE9276001FA527 /* DebugProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 895D008CD95C08405C079218 /* Pods-NewExpensify.debugproduction.xcconfig */; + baseConfigurationReference = 3328C9B8861CA667C42B47F3 /* Pods-NewExpensify.debugproduction.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -1735,7 +1729,7 @@ }; CF9AF94029EE9276001FA527 /* DebugProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7A64A8F5BD1DA6D2B1C999A6 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */; + baseConfigurationReference = 030F99CEB3AEF1F11B001798 /* Pods-NewExpensify-NewExpensifyTests.debugproduction.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -1839,7 +1833,7 @@ }; CF9AF94529EE927A001FA527 /* DebugAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = A672C55E4E62105209DA6787 /* Pods-NewExpensify.debugadhoc.xcconfig */; + baseConfigurationReference = 5A1F158A9A6CBE170EC19D9C /* Pods-NewExpensify.debugadhoc.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIconAdHoc; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -1877,7 +1871,7 @@ }; CF9AF94629EE927A001FA527 /* DebugAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7815BCDA0F80A5988AE4FE23 /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */; + baseConfigurationReference = F98306ABF3F272DF04DF65CC /* Pods-NewExpensify-NewExpensifyTests.debugadhoc.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -1975,7 +1969,7 @@ }; CF9AF94829EE928E001FA527 /* ReleaseProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 118316C3ED3B8AF1B8DDB462 /* Pods-NewExpensify.releaseproduction.xcconfig */; + baseConfigurationReference = 9EADA69D62F2E7B3D96E5B1C /* Pods-NewExpensify.releaseproduction.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -2011,7 +2005,7 @@ }; CF9AF94929EE928E001FA527 /* ReleaseProduction */ = { isa = XCBuildConfiguration; - baseConfigurationReference = F82148F45FC67E2D0CCB54DB /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */; + baseConfigurationReference = 466D03D63F4B48E009C04FA3 /* Pods-NewExpensify-NewExpensifyTests.releaseproduction.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; @@ -2107,7 +2101,7 @@ }; CF9AF94E29EE9293001FA527 /* ReleaseAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = C4BB00AA2BEAE6FCE6E069CA /* Pods-NewExpensify.releaseadhoc.xcconfig */; + baseConfigurationReference = 7312B334B72E8BE41A811FAB /* Pods-NewExpensify.releaseadhoc.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIconAdHoc; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; @@ -2143,7 +2137,7 @@ }; CF9AF94F29EE9293001FA527 /* ReleaseAdHoc */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 487DEEE877D99104D2B59897 /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */; + baseConfigurationReference = D15262BE5F713CDB4DA576AE /* Pods-NewExpensify-NewExpensifyTests.releaseadhoc.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUNDLE_LOADER = "$(TEST_HOST)"; From f93c3d6f1385bd111f825cada2887054024f8778 Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Thu, 21 Mar 2024 22:02:42 +0530 Subject: [PATCH 048/402] introduce isSelfDM prop --- src/types/onyx/IOU.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index 6bbcb174a617..7e1827f73954 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -21,6 +21,7 @@ type Participant = { phoneNumber?: string; text?: string; isSelected?: boolean; + isSelfDM?: boolean; }; type Split = { From c57e69f4c718da0ed634d2e431faf5219b035d63 Mon Sep 17 00:00:00 2001 From: Rohan Sasne Date: Fri, 22 Mar 2024 20:41:06 +0530 Subject: [PATCH 049/402] Fix Lint --- .../MoneyTemporaryForRefactorRequestConfirmationList.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index b740e0aa0834..5de5ef4590ba 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -694,7 +694,13 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ titleStyle={styles.flex1} onPress={() => Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(CONST.IOU.ACTION.CREATE, iouType, transaction?.transactionID ?? '', reportID, Navigation.getActiveRouteWithoutParams()), + ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute( + CONST.IOU.ACTION.CREATE, + iouType, + transaction?.transactionID ?? '', + reportID, + Navigation.getActiveRouteWithoutParams(), + ), ) } // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing From 89722de94f43bc2de0b0a8477075cbbf55efeb18 Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 26 Mar 2024 16:21:02 +0700 Subject: [PATCH 050/402] fix tag name in RHP is not correct --- src/libs/ModifiedExpenseMessage.ts | 2 +- src/libs/PolicyUtils.ts | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 3b3e24867a4f..a5a925aaf04f 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -194,7 +194,7 @@ function getForReportAction(reportID: string | undefined, reportAction: OnyxEntr const splittedOldTag = TransactionUtils.getTagArrayFromName(oldTransactionTag); const localizedTagListName = Localize.translateLocal('common.tag'); - Object.keys(policyTags).forEach((policyTagKey, index) => { + Object.keys(PolicyUtils.getTagLists(policyTags)).forEach((policyTagKey, index) => { const policyTagListName = PolicyUtils.getTagListName(policyTags, index) || localizedTagListName; const newTag = splittedTag[index] ?? ''; diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 43bda05c9e21..83e37fe0f1a8 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -177,11 +177,7 @@ function getTagListName(policyTagList: OnyxEntry, tagIndex: numbe if (isEmptyObject(policyTagList)) { return ''; } - - const policyTagKeys = Object.keys(policyTagList ?? {}); - const policyTagKey = policyTagKeys[tagIndex] ?? ''; - - return policyTagList?.[policyTagKey]?.name ?? ''; + return getTagList(policyTagList, tagIndex).name; } /** From 043972d5ea6d0db15c07ed88ee6af2a6899a815f Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 26 Mar 2024 16:31:24 +0700 Subject: [PATCH 051/402] fix lint --- src/libs/PolicyUtils.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 83e37fe0f1a8..bcf3496634f2 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -170,6 +170,21 @@ function getIneligibleInvitees(policyMembers: OnyxEntry, personal return memberEmailsToExclude; } +/** + * Gets a tag list of a policy by a tag index + */ +function getTagList(policyTagList: OnyxEntry, tagIndex: number): PolicyTagList[keyof PolicyTagList] { + const tagLists = getTagLists(policyTagList); + + return ( + tagLists[tagIndex] ?? { + name: '', + required: false, + tags: {}, + } + ); +} + /** * Gets a tag name of policy tags based on a tag index. */ @@ -193,21 +208,6 @@ function getTagLists(policyTagList: OnyxEntry): Array tagA.orderWeight - tagB.orderWeight); } -/** - * Gets a tag list of a policy by a tag index - */ -function getTagList(policyTagList: OnyxEntry, tagIndex: number): PolicyTagList[keyof PolicyTagList] { - const tagLists = getTagLists(policyTagList); - - return ( - tagLists[tagIndex] ?? { - name: '', - required: false, - tags: {}, - } - ); -} - /** * Cleans up escaping of colons (used to create multi-level tags, e.g. "Parent: Child") in the tag name we receive from the backend */ From 87840c71996caaee8f39e4eae86d171d9ba42c3a Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 26 Mar 2024 16:33:44 +0700 Subject: [PATCH 052/402] fix lint --- src/libs/PolicyUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index bcf3496634f2..cdb2fae5a242 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -192,7 +192,7 @@ function getTagListName(policyTagList: OnyxEntry, tagIndex: numbe if (isEmptyObject(policyTagList)) { return ''; } - return getTagList(policyTagList, tagIndex).name; + return getTagList(policyTagList, tagIndex)?.name; } /** From e98a44a57200485b38c09e2d4bd107da46554fb9 Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 26 Mar 2024 16:44:42 +0700 Subject: [PATCH 053/402] fix lint --- src/libs/PolicyUtils.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index cdb2fae5a242..b15f2f7bc37e 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -170,6 +170,19 @@ function getIneligibleInvitees(policyMembers: OnyxEntry, personal return memberEmailsToExclude; } +/** + * Gets all tag lists of a policy + */ +function getTagLists(policyTagList: OnyxEntry): Array { + if (isEmptyObject(policyTagList)) { + return []; + } + + return Object.values(policyTagList) + .filter((policyTagListValue) => policyTagListValue !== null) + .sort((tagA, tagB) => tagA.orderWeight - tagB.orderWeight); +} + /** * Gets a tag list of a policy by a tag index */ @@ -195,19 +208,6 @@ function getTagListName(policyTagList: OnyxEntry, tagIndex: numbe return getTagList(policyTagList, tagIndex)?.name; } -/** - * Gets all tag lists of a policy - */ -function getTagLists(policyTagList: OnyxEntry): Array { - if (isEmptyObject(policyTagList)) { - return []; - } - - return Object.values(policyTagList) - .filter((policyTagListValue) => policyTagListValue !== null) - .sort((tagA, tagB) => tagA.orderWeight - tagB.orderWeight); -} - /** * Cleans up escaping of colons (used to create multi-level tags, e.g. "Parent: Child") in the tag name we receive from the backend */ From ea0362330104183037148e50cdfc9ab9a7ab51c4 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 26 Mar 2024 12:51:25 +0100 Subject: [PATCH 054/402] integrate leave policy command --- src/libs/API/parameters/LeavePolicyParams.ts | 7 +++++++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 ++ src/libs/actions/Policy.ts | 15 +++++++++++++++ 4 files changed, 25 insertions(+) create mode 100644 src/libs/API/parameters/LeavePolicyParams.ts diff --git a/src/libs/API/parameters/LeavePolicyParams.ts b/src/libs/API/parameters/LeavePolicyParams.ts new file mode 100644 index 000000000000..bc2962eebb66 --- /dev/null +++ b/src/libs/API/parameters/LeavePolicyParams.ts @@ -0,0 +1,7 @@ +type LeavePolicyParams = { + authToken: string; + policyID: string; + email: string; +}; + +export default LeavePolicyParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 1895c2426e1a..a3a7fc3cd836 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -196,3 +196,4 @@ export type {default as SetPolicyCustomTaxNameParams} from './SetPolicyCustomTax export type {default as SetPolicyForeignCurrencyDefaultParams} from './SetPolicyForeignCurrencyDefaultParams'; export type {default as SetPolicyCurrencyDefaultParams} from './SetPolicyCurrencyDefaultParams'; export type {default as RenamePolicyTaxParams} from './RenamePolicyTaxParams'; +export type {default as LeavePolicyParams} from './LeavePolicyParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 9d6e6b3929b8..f4945821a14a 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -193,6 +193,7 @@ const WRITE_COMMANDS = { UPDATE_POLICY_DISTANCE_RATE_VALUE: 'UpdatePolicyDistanceRateValue', SET_POLICY_DISTANCE_RATES_ENABLED: 'SetPolicyDistanceRatesEnabled', DELETE_POLICY_DISTANCE_RATES: 'DeletePolicyDistanceRates', + LEAVE_POLICY: 'LeavePolicy', } as const; type WriteCommand = ValueOf; @@ -384,6 +385,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.UPDATE_POLICY_DISTANCE_RATE_VALUE]: Parameters.UpdatePolicyDistanceRateValueParams; [WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_ENABLED]: Parameters.SetPolicyDistanceRatesEnabledParams; [WRITE_COMMANDS.DELETE_POLICY_DISTANCE_RATES]: Parameters.DeletePolicyDistanceRatesParams; + [WRITE_COMMANDS.LEAVE_POLICY]: Parameters.LeavePolicyParams; }; const READ_COMMANDS = { diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 4b3dea92ba2e..fd4108bf0e64 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -24,6 +24,7 @@ import type { EnablePolicyTagsParams, EnablePolicyTaxesParams, EnablePolicyWorkflowsParams, + LeavePolicyParams, OpenDraftWorkspaceRequestParams, OpenPolicyCategoriesPageParams, OpenPolicyDistanceRatesPageParams, @@ -194,11 +195,13 @@ Onyx.connect({ let sessionEmail = ''; let sessionAccountID = 0; +let sessionAuthToken = ''; Onyx.connect({ key: ONYXKEYS.SESSION, callback: (val) => { sessionEmail = val?.email ?? ''; sessionAccountID = val?.accountID ?? -1; + sessionAuthToken = val?.authToken ?? ''; }, }); @@ -961,6 +964,17 @@ function removeMembers(accountIDs: number[], policyID: string) { pendingAction: policy.pendingAction, }, }); + + const params: LeavePolicyParams = { + policyID, + email: sessionEmail, + authToken: sessionAuthToken, + }; + + // TODO: Extract into a distinct function + API.write(WRITE_COMMANDS.LEAVE_POLICY, params, {optimisticData, successData, failureData}); + + return; } const params: DeleteMembersFromWorkspaceParams = { @@ -968,6 +982,7 @@ function removeMembers(accountIDs: number[], policyID: string) { policyID, }; + // eslint-disable-next-line rulesdir/no-multiple-api-calls API.write(WRITE_COMMANDS.DELETE_MEMBERS_FROM_WORKSPACE, params, {optimisticData, successData, failureData}); } From 31956791d5afdaaeb3683239bbe418dfd46aae29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20M=C3=B3rawski?= Date: Tue, 26 Mar 2024 18:00:34 +0100 Subject: [PATCH 055/402] removed unused prop type from BaseSelectionList --- src/components/SelectionList/types.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/SelectionList/types.ts b/src/components/SelectionList/types.ts index fac78ee786a0..c2e8f3dfb005 100644 --- a/src/components/SelectionList/types.ts +++ b/src/components/SelectionList/types.ts @@ -265,9 +265,6 @@ type BaseSelectionListProps = Partial & { /** Styles to apply to SelectionList container */ containerStyle?: ViewStyle; - /** Whether keyboard is visible on the screen */ - isKeyboardShown?: boolean; - /** Whether focus event should be delayed */ shouldDelayFocus?: boolean; From c06a5cb3add2383a36ad7fe62798921fe5d5c2c7 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Tue, 26 Mar 2024 11:34:49 -0600 Subject: [PATCH 056/402] Modify optimistic data to support new text+attachment messages --- src/libs/ReportUtils.ts | 22 ++++++++++++++++++---- src/libs/actions/Report.ts | 13 ++++++++++--- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 0bb3b1101b7c..e903ec97de1e 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2964,13 +2964,27 @@ function getPolicyDescriptionText(policy: OnyxEntry): string { function buildOptimisticAddCommentReportAction(text?: string, file?: FileObject, actorAccountID?: number): OptimisticReportAction { const parser = new ExpensiMark(); const commentText = getParsedComment(text ?? ''); + const isAttachmentOnly = file && !text; + const isTextOnly = text && !file; + + let htmlForNewComment; + let textForNewComment; + if (isAttachmentOnly) { + htmlForNewComment = CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML; + textForNewComment = CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML; + } else if (isTextOnly) { + htmlForNewComment = commentText; + textForNewComment = parser.htmlToText(htmlForNewComment); + } else { + htmlForNewComment = `${commentText}\n${CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML}`; + textForNewComment = `${commentText}\n${CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML}`; + } + const isAttachment = !text && file !== undefined; - const attachmentInfo = isAttachment ? file : {}; - const htmlForNewComment = isAttachment ? CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML : commentText; + const attachmentInfo = file ?? {}; const accountID = actorAccountID ?? currentUserAccountID; // Remove HTML from text when applying optimistic offline comment - const textForNewComment = isAttachment ? CONST.ATTACHMENT_MESSAGE_TEXT : parser.htmlToText(htmlForNewComment); return { commentText, reportAction: { @@ -2989,7 +3003,7 @@ function buildOptimisticAddCommentReportAction(text?: string, file?: FileObject, created: DateUtils.getDBTimeWithSkew(), message: [ { - translationKey: isAttachment ? CONST.TRANSLATION_KEYS.ATTACHMENT : '', + translationKey: isAttachmentOnly ? CONST.TRANSLATION_KEYS.ATTACHMENT : '', type: CONST.REPORT.MESSAGE.TYPE.COMMENT, html: htmlForNewComment, text: textForNewComment, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 93154bfff16b..e949fc35bf02 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -363,7 +363,7 @@ function addActions(reportID: string, text = '', file?: FileObject) { let attachmentAction: OptimisticAddCommentReportAction | undefined; let commandName: typeof WRITE_COMMANDS.ADD_COMMENT | typeof WRITE_COMMANDS.ADD_ATTACHMENT = WRITE_COMMANDS.ADD_COMMENT; - if (text) { + if (text && !file) { const reportComment = ReportUtils.buildOptimisticAddCommentReportAction(text); reportCommentAction = reportComment.reportAction; reportCommentText = reportComment.commentText; @@ -373,10 +373,15 @@ function addActions(reportID: string, text = '', file?: FileObject) { // When we are adding an attachment we will call AddAttachment. // It supports sending an attachment with an optional comment and AddComment supports adding a single text comment only. commandName = WRITE_COMMANDS.ADD_ATTACHMENT; - const attachment = ReportUtils.buildOptimisticAddCommentReportAction('', file); + const attachment = ReportUtils.buildOptimisticAddCommentReportAction(text, file); attachmentAction = attachment.reportAction; } + // When there is both text and a file, the text for the report comment needs to be parsed + if (text && file) { + reportCommentText = ReportUtils.getParsedComment(text ?? ''); + } + // Always prefer the file as the last action over text const lastAction = attachmentAction ?? reportCommentAction; const currentTime = DateUtils.getDBTimeWithSkew(); @@ -400,7 +405,9 @@ function addActions(reportID: string, text = '', file?: FileObject) { // Optimistically add the new actions to the store before waiting to save them to the server const optimisticReportActions: OnyxCollection = {}; - if (text && reportCommentAction?.reportActionID) { + + // Only add the reportCommentAction when there is no file attachment. If there is both a file attachment and text, that will all be contained in the attachmentAction. + if (text && reportCommentAction?.reportActionID && !file) { optimisticReportActions[reportCommentAction.reportActionID] = reportCommentAction; } if (file && attachmentAction?.reportActionID) { From 087a34d2bc5e13c5c5bf3185e431e8e227ea6ad0 Mon Sep 17 00:00:00 2001 From: tienifr Date: Wed, 27 Mar 2024 04:28:09 +0700 Subject: [PATCH 057/402] fix use orderWeight instead of tagIndex --- src/ROUTES.ts | 6 +++--- .../ReportActionItem/MoneyRequestView.tsx | 4 ++-- src/libs/ModifiedExpenseMessage.ts | 5 ++--- src/libs/PolicyUtils.ts | 21 ++++++++++--------- .../iou/request/step/IOURequestStepTag.js | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 6302e0ee4683..2e61a87f654e 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -369,16 +369,16 @@ const ROUTES = { getUrlWithBackToParam(`${action}/${iouType}/scan/${transactionID}/${reportID}`, backTo), }, MONEY_REQUEST_STEP_TAG: { - route: ':action/:iouType/tag/:tagIndex/:transactionID/:reportID/:reportActionID?', + route: ':action/:iouType/tag/:orderWeight/:transactionID/:reportID/:reportActionID?', getRoute: ( action: ValueOf, iouType: ValueOf, - tagIndex: number, + orderWeight: number, transactionID: string, reportID: string, backTo = '', reportActionID?: string, - ) => getUrlWithBackToParam(`${action}/${iouType}/tag/${tagIndex}/${transactionID}/${reportID}${reportActionID ? `/${reportActionID}` : ''}`, backTo), + ) => getUrlWithBackToParam(`${action}/${iouType}/tag/${orderWeight}/${transactionID}/${reportID}${reportActionID ? `/${reportActionID}` : ''}`, backTo), }, MONEY_REQUEST_STEP_WAYPOINT: { route: ':action/:iouType/waypoint/:transactionID/:reportID/:pageIndex', diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index bb0308ee4509..1e5721e485b9 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -385,7 +385,7 @@ function MoneyRequestView({ )} {shouldShowTag && - policyTagLists.map(({name}, index) => ( + policyTagLists.map(({name, orderWeight}, index) => ( Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, index, transaction?.transactionID ?? '', report.reportID), + ROUTES.MONEY_REQUEST_STEP_TAG.getRoute(CONST.IOU.ACTION.EDIT, CONST.IOU.TYPE.REQUEST, orderWeight, transaction?.transactionID ?? '', report.reportID), ) } brickRoadIndicator={getErrorForField('tag', {tagListIndex: index, tagListName: name}) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index a5a925aaf04f..583649c271bc 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -194,9 +194,8 @@ function getForReportAction(reportID: string | undefined, reportAction: OnyxEntr const splittedOldTag = TransactionUtils.getTagArrayFromName(oldTransactionTag); const localizedTagListName = Localize.translateLocal('common.tag'); - Object.keys(PolicyUtils.getTagLists(policyTags)).forEach((policyTagKey, index) => { - const policyTagListName = PolicyUtils.getTagListName(policyTags, index) || localizedTagListName; - + PolicyUtils.getTagLists(policyTags).forEach((policyTagList, index) => { + const policyTagListName = PolicyUtils.getTagListName(policyTags, policyTagList?.orderWeight) || localizedTagListName; const newTag = splittedTag[index] ?? ''; const oldTag = splittedOldTag[index] ?? ''; diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index b15f2f7bc37e..70dba0d8c932 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -170,6 +170,17 @@ function getIneligibleInvitees(policyMembers: OnyxEntry, personal return memberEmailsToExclude; } +/** + * Gets a tag name of policy tags based on a tag index. + */ +function getTagListName(policyTagList: OnyxEntry, orderWeight: number): string { + if (isEmptyObject(policyTagList)) { + return ''; + } + + const policyTags = Object.values(policyTagList ?? {}); + return policyTags.find((policy) => policy.orderWeight === orderWeight)?.name ?? ''; +} /** * Gets all tag lists of a policy */ @@ -198,16 +209,6 @@ function getTagList(policyTagList: OnyxEntry, tagIndex: number): ); } -/** - * Gets a tag name of policy tags based on a tag index. - */ -function getTagListName(policyTagList: OnyxEntry, tagIndex: number): string { - if (isEmptyObject(policyTagList)) { - return ''; - } - return getTagList(policyTagList, tagIndex)?.name; -} - /** * Cleans up escaping of colons (used to create multi-level tags, e.g. "Parent: Child") in the tag name we receive from the backend */ diff --git a/src/pages/iou/request/step/IOURequestStepTag.js b/src/pages/iou/request/step/IOURequestStepTag.js index 79ed26b76b19..a28a165c15ae 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.js +++ b/src/pages/iou/request/step/IOURequestStepTag.js @@ -81,7 +81,7 @@ function IOURequestStepTag({ policyTags, report, route: { - params: {action, tagIndex: rawTagIndex, transactionID, backTo, iouType, reportActionID}, + params: {action, orderWeight: rawTagIndex, transactionID, backTo, iouType, reportActionID}, }, transaction, splitDraftTransaction, From a1420c46cab6766abf42a1a31f4ca0a3b0a25276 Mon Sep 17 00:00:00 2001 From: GandalfGwaihir Date: Wed, 27 Mar 2024 05:48:03 +0530 Subject: [PATCH 058/402] fix lint --- ...raryForRefactorRequestConfirmationList.tsx | 46 ++++++++++--------- src/components/ReceiptImage.tsx | 2 +- src/types/onyx/IOU.ts | 1 - 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx index 58a217b0eae9..0ee1dc2594d5 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.tsx @@ -895,6 +895,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({ () => isLocalFile && Str.isPDF(receiptFilename) ? ( )} - {receiptImage || receiptThumbnail - ? receiptThumbnailContent - : // The empty receipt component should only show for IOU Requests of a paid policy ("Team" or "Corporate") - PolicyUtils.isPaidGroupPolicy(policy) && - !isDistanceRequest && - iouType === CONST.IOU.TYPE.REQUEST && ( - - Navigation.navigate( - ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute( - CONST.IOU.ACTION.CREATE, - iouType, - transaction?.transactionID ?? '', - reportID, - Navigation.getActiveRouteWithoutParams(), - ), - ) - } - /> - )} + { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + receiptImage || receiptThumbnail + ? receiptThumbnailContent + : // The empty receipt component should only show for IOU Requests of a paid policy ("Team" or "Corporate") + PolicyUtils.isPaidGroupPolicy(policy) && + !isDistanceRequest && + iouType === CONST.IOU.TYPE.REQUEST && ( + + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_SCAN.getRoute( + CONST.IOU.ACTION.CREATE, + iouType, + transaction?.transactionID ?? '', + reportID, + Navigation.getActiveRouteWithoutParams(), + ), + ) + } + /> + ) + } {primaryFields} {!shouldShowAllFields && ( diff --git a/src/components/ReceiptImage.tsx b/src/components/ReceiptImage.tsx index 08892f11b021..f4aa2de090f7 100644 --- a/src/components/ReceiptImage.tsx +++ b/src/components/ReceiptImage.tsx @@ -46,7 +46,7 @@ type ReceiptImageProps = ( isEReceipt?: boolean; isThumbnail?: boolean; source: string; - isPDFThumbnail: string; + isPDFThumbnail?: string; } ) & { /** Whether we should display the receipt with ThumbnailImage component */ diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index 7e1827f73954..6bbcb174a617 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -21,7 +21,6 @@ type Participant = { phoneNumber?: string; text?: string; isSelected?: boolean; - isSelfDM?: boolean; }; type Split = { From 9f73b2a9666ac7e5befbcb7196199c3b488266a4 Mon Sep 17 00:00:00 2001 From: GandalfGwaihir Date: Wed, 27 Mar 2024 05:49:29 +0530 Subject: [PATCH 059/402] introduce isSelfDM in ONyx --- src/types/onyx/IOU.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index 6bbcb174a617..7e1827f73954 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -21,6 +21,7 @@ type Participant = { phoneNumber?: string; text?: string; isSelected?: boolean; + isSelfDM?: boolean; }; type Split = { From 5ca68a6e77f9fabb67431c7347593414247d722f Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 27 Mar 2024 11:39:37 +0100 Subject: [PATCH 060/402] Add leave policy change log const --- src/CONST.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CONST.ts b/src/CONST.ts index 47caa5e64a90..660bb994b047 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -729,6 +729,7 @@ const CONST = { UPDATE_TAG_NAME: 'POLICYCHANGELOG_UPDATE_TAG_NAME', UPDATE_TIME_ENABLED: 'POLICYCHANGELOG_UPDATE_TIME_ENABLED', UPDATE_TIME_RATE: 'POLICYCHANGELOG_UPDATE_TIME_RATE', + LEAVE_POLICY: 'POLICYCHANGELOG_LEAVE_POLICY', }, ROOMCHANGELOG: { INVITE_TO_ROOM: 'INVITETOROOM', From 532dcacf98ff02b8999695dfc469a06fb4151926 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 27 Mar 2024 12:01:20 +0100 Subject: [PATCH 061/402] refactor all base pages to tsx --- ...e.js => IOURequestRedirectToStartPage.tsx} | 23 +++------- ...stStartPage.js => IOURequestStartPage.tsx} | 0 ...StepAmount.js => IOURequestStepAmount.tsx} | 0 ...Distance.js => IOURequestStepDistance.tsx} | 45 +++++++------------ 4 files changed, 21 insertions(+), 47 deletions(-) rename src/pages/iou/request/{IOURequestRedirectToStartPage.js => IOURequestRedirectToStartPage.tsx} (73%) rename src/pages/iou/request/{IOURequestStartPage.js => IOURequestStartPage.tsx} (100%) rename src/pages/iou/request/step/{IOURequestStepAmount.js => IOURequestStepAmount.tsx} (100%) rename src/pages/iou/request/step/{IOURequestStepDistance.js => IOURequestStepDistance.tsx} (92%) diff --git a/src/pages/iou/request/IOURequestRedirectToStartPage.js b/src/pages/iou/request/IOURequestRedirectToStartPage.tsx similarity index 73% rename from src/pages/iou/request/IOURequestRedirectToStartPage.js rename to src/pages/iou/request/IOURequestRedirectToStartPage.tsx index 2da235743705..c34fa6065028 100644 --- a/src/pages/iou/request/IOURequestRedirectToStartPage.js +++ b/src/pages/iou/request/IOURequestRedirectToStartPage.tsx @@ -1,34 +1,22 @@ import PropTypes from 'prop-types'; import React, {useEffect} from 'react'; -import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import ScreenWrapper from '@components/ScreenWrapper'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; +import type { WithWritableReportOrNotFoundProps } from './step/withWritableReportOrNotFound'; -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: PropTypes.shape({ - /** Route specific parameters used on this screen */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.oneOf(_.values(CONST.IOU.TYPE)).isRequired, - - /** The type of IOU Request, i.e. manual, scan, distance */ - iouRequestType: PropTypes.oneOf(_.values(CONST.IOU.REQUEST_TYPE)).isRequired, - }), - }).isRequired, -}; +type IOURequestRedirectToStartPageProps = WithWritableReportOrNotFoundProps; function IOURequestRedirectToStartPage({ route: { params: {iouType, iouRequestType}, }, -}) { - const isIouTypeValid = _.values(CONST.IOU.TYPE).includes(iouType); - const isIouRequestTypeValid = _.values(CONST.IOU.REQUEST_TYPE).includes(iouRequestType); +}: IOURequestRedirectToStartPageProps) { + const isIouTypeValid = Object.values(CONST.IOU.TYPE).includes(iouType); + const isIouRequestTypeValid = Object.values(CONST.IOU.REQUEST_TYPE).includes(iouRequestType); useEffect(() => { if (!isIouTypeValid || !isIouRequestTypeValid) { @@ -64,6 +52,5 @@ function IOURequestRedirectToStartPage({ } IOURequestRedirectToStartPage.displayName = 'IOURequestRedirectToStartPage'; -IOURequestRedirectToStartPage.propTypes = propTypes; export default IOURequestRedirectToStartPage; diff --git a/src/pages/iou/request/IOURequestStartPage.js b/src/pages/iou/request/IOURequestStartPage.tsx similarity index 100% rename from src/pages/iou/request/IOURequestStartPage.js rename to src/pages/iou/request/IOURequestStartPage.tsx diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.tsx similarity index 100% rename from src/pages/iou/request/step/IOURequestStepAmount.js rename to src/pages/iou/request/step/IOURequestStepAmount.tsx diff --git a/src/pages/iou/request/step/IOURequestStepDistance.js b/src/pages/iou/request/step/IOURequestStepDistance.tsx similarity index 92% rename from src/pages/iou/request/step/IOURequestStepDistance.js rename to src/pages/iou/request/step/IOURequestStepDistance.tsx index dad610cbc636..d725cdfe152f 100644 --- a/src/pages/iou/request/step/IOURequestStepDistance.js +++ b/src/pages/iou/request/step/IOURequestStepDistance.tsx @@ -1,7 +1,8 @@ import lodashGet from 'lodash/get'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import { withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import Button from '@components/Button'; import DistanceRequestFooter from '@components/DistanceRequest/DistanceRequestFooter'; @@ -17,7 +18,6 @@ import compose from '@libs/compose'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as TransactionUtils from '@libs/TransactionUtils'; -import reportPropTypes from '@pages/reportPropTypes'; import variables from '@styles/variables'; import * as IOU from '@userActions/IOU'; import * as MapboxToken from '@userActions/MapboxToken'; @@ -25,50 +25,39 @@ import * as Transaction from '@userActions/Transaction'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; +import type * as OnyxTypes from '@src/types/onyx'; import StepScreenWrapper from './StepScreenWrapper'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; +import type { WithWritableReportOrNotFoundProps } from './withWritableReportOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: IOURequestStepRoutePropTypes.isRequired, - - /* Onyx Props */ - /** The report that the transaction belongs to */ - report: reportPropTypes, - - /** The transaction object being modified in Onyx */ - transaction: transactionPropTypes, - - /** backup version of the original transaction */ - transactionBackup: transactionPropTypes, -}; +type IOURequestStepDistanceOnyxProps = { + transactionBackup?: OnyxEntry, +} -const defaultProps = { - report: {}, - transaction: {}, - transactionBackup: {}, +type IOURequestStepDistanceProps = WithWritableReportOrNotFoundProps & IOURequestStepDistanceOnyxProps & { + report?: OnyxEntry, + transaction?: OnyxEntry, }; function IOURequestStepDistance({ - report, route: { params: {action, iouType, reportID, transactionID, backTo}, }, + report, transaction, transactionBackup, -}) { +}: IOURequestStepDistanceProps) { const styles = useThemeStyles(); const {isOffline} = useNetwork(); const {translate} = useLocalize(); const [optimisticWaypoints, setOptimisticWaypoints] = useState(null); const waypoints = useMemo(() => optimisticWaypoints || lodashGet(transaction, 'comment.waypoints', {waypoint0: {}, waypoint1: {}}), [optimisticWaypoints, transaction]); - const waypointsList = _.keys(waypoints); + const waypointsList = Object.keys(waypoints); const previousWaypoints = usePrevious(waypoints); - const numberOfWaypoints = _.size(waypoints); - const numberOfPreviousWaypoints = _.size(previousWaypoints); + const numberOfWaypoints = Object.keys(waypoints).length; + const numberOfPreviousWaypoints = Object.keys(previousWaypoints).length; const scrollViewRef = useRef(null); const isLoadingRoute = lodashGet(transaction, 'comment.isLoading', false); const isLoading = lodashGet(transaction, 'isLoading', false); @@ -82,7 +71,7 @@ function IOURequestStepDistance({ const [shouldShowAtLeastTwoDifferentWaypointsError, setShouldShowAtLeastTwoDifferentWaypointsError] = useState(false); const nonEmptyWaypointsCount = useMemo(() => _.filter(_.keys(waypoints), (key) => !_.isEmpty(waypoints[key])).length, [waypoints]); const duplicateWaypointsError = useMemo(() => nonEmptyWaypointsCount >= 2 && _.size(validatedWaypoints) !== nonEmptyWaypointsCount, [nonEmptyWaypointsCount, validatedWaypoints]); - const atLeastTwoDifferentWaypointsError = useMemo(() => _.size(validatedWaypoints) < 2, [validatedWaypoints]); + const atLeastTwoDifferentWaypointsError = useMemo(() => Object.keys(validatedWaypoints) < 2, [validatedWaypoints]); const isEditing = action === CONST.IOU.ACTION.EDIT; const isCreatingNewRequest = Navigation.getActiveRoute().includes('start'); @@ -284,8 +273,6 @@ function IOURequestStepDistance({ } IOURequestStepDistance.displayName = 'IOURequestStepDistance'; -IOURequestStepDistance.propTypes = propTypes; -IOURequestStepDistance.defaultProps = defaultProps; export default compose( withWritableReportOrNotFound, From 46e87ba4659fa14216161e82e47f03e9ceaa48d6 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 27 Mar 2024 12:07:15 +0100 Subject: [PATCH 062/402] integrate getReportActionActorAccountID --- src/libs/ReportUtils.ts | 14 ++++++++++++++ src/pages/home/report/ReportActionItemSingle.tsx | 3 ++- src/types/onyx/ReportAction.ts | 3 +++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 0bb3b1101b7c..41988cd5bfbb 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5517,6 +5517,19 @@ function hasActionsWithErrors(reportID: string): boolean { return Object.values(reportActions ?? {}).some((action) => !isEmptyObject(action.errors)); } +function getReportActionActorAccountID(reportAction: OnyxEntry, iouReport: OnyxEntry | undefined): number | undefined { + switch (reportAction?.actionName) { + case CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW: + return iouReport ? iouReport.managerID : reportAction?.actorAccountID; + + case CONST.REPORT.ACTIONS.TYPE.SUBMITTED: + return reportAction?.adminAccountID ?? reportAction?.actorAccountID; + + default: + return reportAction?.actorAccountID; + } +} + export { getReportParticipantsTitle, isReportMessageAttachment, @@ -5735,6 +5748,7 @@ export { shouldCreateNewMoneyRequestReport, isTrackExpenseReport, hasActionsWithErrors, + getReportActionActorAccountID, }; export type { diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 696cd7a7d850..98dfbdc56c89 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -78,7 +78,8 @@ function ReportActionItemSingle({ const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); const personalDetails = usePersonalDetails() ?? CONST.EMPTY_OBJECT; - const actorAccountID = action?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && iouReport ? iouReport.managerID : action?.actorAccountID; + const actorAccountID = ReportUtils.getReportActionActorAccountID(action, iouReport); + let displayName = ReportUtils.getDisplayNameForParticipant(actorAccountID); const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails[actorAccountID ?? -1] ?? {}; // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index 86383a8d0047..c35923849888 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -226,6 +226,9 @@ type ReportActionBase = OnyxCommon.OnyxValueWithOfflineFeedback<{ /** Flag for checking if data is from optimistic data */ isOptimisticAction?: boolean; + + /** The admins's ID */ + adminAccountID?: number; }>; type ReportAction = ReportActionBase & OriginalMessage; From 9f68f82a9901ddad5012226fa009f3128adc6226 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Wed, 27 Mar 2024 15:09:11 +0100 Subject: [PATCH 063/402] add correct props for IOURequestStartPage --- src/pages/iou/request/IOURequestStartPage.tsx | 46 ++++++------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index cb078fac133c..3852e04dfe04 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -1,9 +1,9 @@ import {useFocusEffect, useNavigation} from '@react-navigation/native'; import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; -import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; +import { withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import DragAndDropProvider from '@components/DragAndDrop/Provider'; @@ -11,7 +11,6 @@ import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import TabSelector from '@components/TabSelector/TabSelector'; -import transactionPropTypes from '@components/transactionPropTypes'; import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import usePrevious from '@hooks/usePrevious'; @@ -23,53 +22,34 @@ import Navigation from '@libs/Navigation/Navigation'; import OnyxTabNavigator, {TopTab} from '@libs/Navigation/OnyxTabNavigator'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; -import reportPropTypes from '@pages/reportPropTypes'; +import type * as OnyxTypes from '@src/types/onyx'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import IOURequestStepAmount from './step/IOURequestStepAmount'; import IOURequestStepDistance from './step/IOURequestStepDistance'; -import IOURequestStepRoutePropTypes from './step/IOURequestStepRoutePropTypes'; import IOURequestStepScan from './step/IOURequestStepScan'; +import type { WithWritableReportOrNotFoundProps } from './step/withWritableReportOrNotFound'; -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: IOURequestStepRoutePropTypes.isRequired, - - /* Onyx Props */ - /** The report that holds the transaction */ - report: reportPropTypes, - - /** The policy tied to the report */ - policy: PropTypes.shape({ - /** Type of the policy */ - type: PropTypes.string, - }), - - /** The tab to select by default (whatever the user visited last) */ - selectedTab: PropTypes.oneOf(_.values(CONST.TAB_REQUEST)), - - /** The transaction being modified */ - transaction: transactionPropTypes, +type IOURequestStartPageOnyxProps = { + report?: OnyxEntry, + policy?: OnyxEntry, + selectedTab?: typeof CONST.TAB_REQUEST[keyof typeof CONST.TAB_REQUEST], + transaction?: OnyxEntry, }; -const defaultProps = { - report: {}, - policy: {}, - selectedTab: CONST.TAB_REQUEST.SCAN, - transaction: {}, -}; +type IOURequestStartPageProps = WithWritableReportOrNotFoundProps & IOURequestStartPageOnyxProps; function IOURequestStartPage({ - report, - policy, route, route: { params: {iouType, reportID}, }, + report, + policy, selectedTab, transaction, -}) { +}: IOURequestStartPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const navigation = useNavigation(); From 4b11894ead580896b430914be894c2a0df08a27f Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 28 Mar 2024 16:12:16 +0100 Subject: [PATCH 064/402] Sync keyboard navigation in SelectionList and PopoverMenu --- src/components/MenuItem.tsx | 5 + src/components/PopoverMenu.tsx | 14 +- src/components/PopoverMenuItem.tsx | 29 ++ src/components/SelectionList/BaseListItem.tsx | 25 +- .../SelectionList/BaseSelectionList.tsx | 248 +++++++++--------- .../SelectionList/RadioListItem.tsx | 2 + .../SelectionList/TableListItem.tsx | 2 + src/components/SelectionList/types.ts | 3 + 8 files changed, 198 insertions(+), 130 deletions(-) create mode 100644 src/components/PopoverMenuItem.tsx diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index 110256ba166b..730d4d025d95 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -246,6 +246,9 @@ type MenuItemBaseProps = { /** Adds padding to the left of the text when there is no icon. */ shouldPutLeftPaddingWhenNoIcon?: boolean; + + /** Handles what to do when the item is focused */ + onFocus?: () => void; }; type MenuItemProps = (IconProps | AvatarProps | NoIcon) & MenuItemBaseProps; @@ -317,6 +320,7 @@ function MenuItem( contentFit = 'cover', isPaneMenu = false, shouldPutLeftPaddingWhenNoIcon = false, + onFocus, }: MenuItemProps, ref: ForwardedRef, ) { @@ -447,6 +451,7 @@ function MenuItem( role={CONST.ROLE.MENUITEM} accessibilityLabel={title ? title.toString() : ''} accessible + onFocus={onFocus} > {({pressed}) => ( <> diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index 1fd1c8ef5a3b..c2c8685aa528 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -12,10 +12,11 @@ import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; import * as Expensicons from './Icon/Expensicons'; import type {MenuItemProps} from './MenuItem'; import MenuItem from './MenuItem'; +import PopoverMenuItem from './PopoverMenuItem'; import PopoverWithMeasuredContent from './PopoverWithMeasuredContent'; import Text from './Text'; -type PopoverMenuItem = MenuItemProps & { +type PopoverMenuListItem = MenuItemProps & { /** Text label */ text: string; @@ -23,7 +24,7 @@ type PopoverMenuItem = MenuItemProps & { onSelected?: () => void; /** Sub menu items to be rendered after a menu item is selected */ - subMenuItems?: PopoverMenuItem[]; + subMenuItems?: PopoverMenuListItem[]; /** Determines whether the menu item is disabled or not */ disabled?: boolean; @@ -39,10 +40,10 @@ type PopoverMenuProps = Partial & { isVisible: boolean; /** Callback to fire when a CreateMenu item is selected */ - onItemSelected: (selectedItem: PopoverMenuItem, index: number) => void; + onItemSelected: (selectedItem: PopoverMenuListItem, index: number) => void; /** Menu items to be rendered on the list */ - menuItems: PopoverMenuItem[]; + menuItems: PopoverMenuListItem[]; /** Optional non-interactive text to display as a header for any create menu */ headerText?: string; @@ -193,7 +194,7 @@ function PopoverMenu({ {!!headerText && {headerText}} {enteredSubMenuIndexes.length > 0 && renderBackButtonItem()} {currentMenuItems.map((item, menuIndex) => ( - setFocusedIndex(menuIndex)} /> ))} @@ -225,4 +227,4 @@ function PopoverMenu({ PopoverMenu.displayName = 'PopoverMenu'; export default React.memo(PopoverMenu); -export type {PopoverMenuItem, PopoverMenuProps}; +export type {PopoverMenuListItem, PopoverMenuProps}; diff --git a/src/components/PopoverMenuItem.tsx b/src/components/PopoverMenuItem.tsx new file mode 100644 index 000000000000..ff4e12a2f9b1 --- /dev/null +++ b/src/components/PopoverMenuItem.tsx @@ -0,0 +1,29 @@ +import React, {useLayoutEffect, useRef} from 'react'; +import type {View} from 'react-native'; +import MenuItem from './MenuItem'; +import type {MenuItemProps} from './MenuItem'; + +function PopoverMenuItem(props: MenuItemProps) { + const ref = useRef(null); + + // Sync focus on an item + useLayoutEffect(() => { + if (!props.focused) { + return; + } + + ref?.current?.focus(); + }, [props.focused]); + + return ( + + ); +} + +PopoverMenuItem.displayName = 'PopoverMenuItem'; + +export default PopoverMenuItem; diff --git a/src/components/SelectionList/BaseListItem.tsx b/src/components/SelectionList/BaseListItem.tsx index 42fdc7dc575e..458f05aaef8c 100644 --- a/src/components/SelectionList/BaseListItem.tsx +++ b/src/components/SelectionList/BaseListItem.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useLayoutEffect, useRef} from 'react'; import {View} from 'react-native'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -31,12 +31,16 @@ function BaseListItem({ pendingAction, FooterComponent, children, + isFocused, + onFocus = () => {}, }: BaseListItemProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {hovered, bind} = useHover(); + const pressableRef = useRef(null); + const rightHandSideComponentRender = () => { if (canSelectMultiple || !rightHandSideComponent) { return null; @@ -57,6 +61,15 @@ function BaseListItem({ } }; + // Sync focus on an item + useLayoutEffect(() => { + if (!isFocused) { + return; + } + + pressableRef?.current?.focus(); + }, [isFocused]); + return ( onDismissError(item)} @@ -68,6 +81,7 @@ function BaseListItem({ onSelectRow(item)} disabled={isDisabled} accessibilityLabel={item.text ?? ''} @@ -78,6 +92,7 @@ function BaseListItem({ onMouseDown={shouldPreventDefaultFocusOnSelectRow ? (e) => e.preventDefault() : undefined} nativeID={keyForList ?? ''} style={pressableStyle} + onFocus={onFocus} > {canSelectMultiple && checkmarkPosition === CONST.DIRECTION.LEFT && ( @@ -132,6 +147,14 @@ function BaseListItem({ )} + {!item.isSelected && item.brickRoadIndicator && [CONST.BRICK_ROAD_INDICATOR_STATUS.INFO, CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR].includes(item.brickRoadIndicator) && ( + + + + )} {rightHandSideComponentRender()} {FooterComponent} diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx index 32cd89854cff..b8cd19fe4171 100644 --- a/src/components/SelectionList/BaseSelectionList.tsx +++ b/src/components/SelectionList/BaseSelectionList.tsx @@ -4,7 +4,6 @@ import type {ForwardedRef} from 'react'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import type {LayoutChangeEvent, SectionList as RNSectionList, TextInput as RNTextInput, SectionListRenderItemInfo} from 'react-native'; import {View} from 'react-native'; -import ArrowKeyFocusManager from '@components/ArrowKeyFocusManager'; import Button from '@components/Button'; import Checkbox from '@components/Checkbox'; import FixedFooter from '@components/FixedFooter'; @@ -16,6 +15,7 @@ import ShowMoreButton from '@components/ShowMoreButton'; import Text from '@components/Text'; import TextInput from '@components/TextInput'; import useActiveElementRole from '@hooks/useActiveElementRole'; +import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager'; import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useLocalize from '@hooks/useLocalize'; import usePrevious from '@hooks/usePrevious'; @@ -161,9 +161,6 @@ function BaseSelectionList( }; }, [canSelectMultiple, sections]); - // If `initiallyFocusedOptionKey` is not passed, we fall back to `-1`, to avoid showing the highlight on the first member - const [focusedIndex, setFocusedIndex] = useState(() => flattenedSections.allOptions.findIndex((option) => option.keyForList === initiallyFocusedOptionKey)); - const [slicedSections, ShowMoreButtonInstance] = useMemo(() => { let remainingOptionsLimit = CONST.MAX_OPTIONS_SELECTOR_PAGE_LENGTH * currentPage; const processedSections = sections.map((section) => { @@ -218,6 +215,17 @@ function BaseSelectionList( [flattenedSections.allOptions], ); + // If `initiallyFocusedOptionKey` is not passed, we fall back to `-1`, to avoid showing the highlight on the first member + const [focusedIndex, setFocusedIndex] = useArrowKeyFocusManager({ + initialFocusedIndex: flattenedSections.allOptions.findIndex((option) => option.keyForList === initiallyFocusedOptionKey), + maxIndex: flattenedSections.allOptions.length - 1, + isActive: true, + onFocusedIndexChange: (index: number) => { + setFocusedIndex(index); + scrollToIndex(index, true); + }, + }); + /** * Logic to run when a row is selected, either with click/press or keyboard hotkeys. * @@ -335,6 +343,7 @@ function BaseSelectionList( checkmarkPosition={checkmarkPosition} keyForList={item.keyForList ?? ''} isMultilineSupported={isRowMultilineSupported} + onFocus={() => setFocusedIndex(index)} /> ); }; @@ -473,128 +482,121 @@ function BaseSelectionList( ); return ( - section.data).length - 1} - onFocusedIndexChanged={updateAndScrollToFocusedIndex} - > - - {({safeAreaPaddingBottomStyle}) => ( - - {shouldShowTextInput && ( - - { - innerTextInputRef.current = element as RNTextInput; - - if (!textInputRef) { - return; - } - - // eslint-disable-next-line no-param-reassign - textInputRef.current = element as RNTextInput; - }} - label={textInputLabel} - accessibilityLabel={textInputLabel} - hint={textInputHint} - role={CONST.ROLE.PRESENTATION} - value={textInputValue} - placeholder={textInputPlaceholder} - maxLength={textInputMaxLength} - onChangeText={onChangeText} - inputMode={inputMode} - selectTextOnFocus - spellCheck={false} - onSubmitEditing={selectFocusedOption} - blurOnSubmit={!!flattenedSections.allOptions.length} - isLoading={isLoadingNewOptions} - testID="selection-list-text-input" - /> - - )} - {!!headerMessage && ( - - {headerMessage} - - )} - {!!headerContent && headerContent} - {flattenedSections.allOptions.length === 0 && showLoadingPlaceholder ? ( - - ) : ( - <> - {!headerMessage && canSelectMultiple && shouldShowSelectAll && ( - - - + {({safeAreaPaddingBottomStyle}) => ( + + {shouldShowTextInput && ( + + { + innerTextInputRef.current = element as RNTextInput; + + if (!textInputRef) { + return; + } + + // eslint-disable-next-line no-param-reassign + textInputRef.current = element as RNTextInput; + }} + label={textInputLabel} + accessibilityLabel={textInputLabel} + hint={textInputHint} + role={CONST.ROLE.PRESENTATION} + value={textInputValue} + placeholder={textInputPlaceholder} + maxLength={textInputMaxLength} + onChangeText={onChangeText} + inputMode={inputMode} + selectTextOnFocus + spellCheck={false} + onSubmitEditing={selectFocusedOption} + blurOnSubmit={!!flattenedSections.allOptions.length} + isLoading={isLoadingNewOptions} + testID="selection-list-text-input" + /> + + )} + {!!headerMessage && ( + + {headerMessage} + + )} + {!!headerContent && headerContent} + {flattenedSections.allOptions.length === 0 && showLoadingPlaceholder ? ( + + ) : ( + <> + {!headerMessage && canSelectMultiple && shouldShowSelectAll && ( + + + + {!customListHeader && ( + - {!customListHeader && ( - e.preventDefault() : undefined} - > - {translate('workspace.people.selectAll')} - - )} - - {customListHeader} + dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}} + onMouseDown={shouldPreventDefaultFocusOnSelectRow ? (e) => e.preventDefault() : undefined} + > + {translate('workspace.people.selectAll')} + + )} - )} - {!headerMessage && !canSelectMultiple && customListHeader} - item.keyForList ?? `${index}`} - extraData={focusedIndex} - indicatorStyle="white" - keyboardShouldPersistTaps="always" - showsVerticalScrollIndicator={showScrollIndicator} - initialNumToRender={12} - maxToRenderPerBatch={maxToRenderPerBatch} - windowSize={5} - viewabilityConfig={{viewAreaCoveragePercentThreshold: 95}} - testID="selection-list" - onLayout={onSectionListLayout} - style={(!maxToRenderPerBatch || isInitialSectionListRender) && styles.opacity0} - ListFooterComponent={ShowMoreButtonInstance} - /> - {children} - - )} - {showConfirmButton && ( - -