From 6df33c539861c75d866768ca4ab1d143dbc80f47 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Fri, 31 May 2024 09:30:12 +0200 Subject: [PATCH 01/96] Fix types name typo --- src/pages/workspace/WorkspaceProfilePage.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index be6143ff6240..c45270ba59e0 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -35,12 +35,12 @@ import withPolicy from './withPolicy'; import type {WithPolicyProps} from './withPolicy'; import WorkspacePageWithSections from './WorkspacePageWithSections'; -type WorkSpaceProfilePageOnyxProps = { +type WorkspaceProfilePageOnyxProps = { /** Constant, list of available currencies */ currencyList: OnyxEntry; }; -type WorkSpaceProfilePageProps = WithPolicyProps & WorkSpaceProfilePageOnyxProps; +type WorkSpaceProfilePageProps = WithPolicyProps & WorkspaceProfilePageOnyxProps; const parser = new ExpensiMark(); @@ -274,7 +274,7 @@ function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfi WorkspaceProfilePage.displayName = 'WorkspaceProfilePage'; export default withPolicy( - withOnyx({ + withOnyx({ currencyList: {key: ONYXKEYS.CURRENCY_LIST}, })(WorkspaceProfilePage), ); From 725dbbc677b5c9da2009e9a3d398136e34c87130 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Fri, 31 May 2024 11:14:55 +0200 Subject: [PATCH 02/96] Add a new open policy profile API command --- .../parameters/OpenPolicyProfilePageParams.ts | 5 ++++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 ++ src/libs/actions/Policy/Policy.ts | 8 ++++++ src/pages/workspace/WorkspaceInitialPage.tsx | 18 +++++++++++-- src/pages/workspace/WorkspaceProfilePage.tsx | 25 ++++++++++++++++--- 6 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 src/libs/API/parameters/OpenPolicyProfilePageParams.ts diff --git a/src/libs/API/parameters/OpenPolicyProfilePageParams.ts b/src/libs/API/parameters/OpenPolicyProfilePageParams.ts new file mode 100644 index 000000000000..55dce33a3dac --- /dev/null +++ b/src/libs/API/parameters/OpenPolicyProfilePageParams.ts @@ -0,0 +1,5 @@ +type OpenPolicyProfilePageParams = { + policyID: string; +}; + +export default OpenPolicyProfilePageParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index c9e2e342c5ae..4fe04fba4e97 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -192,6 +192,7 @@ export type {default as OpenPolicyDistanceRatesPageParams} from './OpenPolicyDis export type {default as OpenPolicyTaxesPageParams} from './OpenPolicyTaxesPageParams'; export type {default as EnablePolicyTaxesParams} from './EnablePolicyTaxesParams'; export type {default as OpenPolicyMoreFeaturesPageParams} from './OpenPolicyMoreFeaturesPageParams'; +export type {default as OpenPolicyProfilePageParams} from './OpenPolicyProfilePageParams'; export type {default as CreatePolicyDistanceRateParams} from './CreatePolicyDistanceRateParams'; export type {default as SetPolicyDistanceRatesUnitParams} from './SetPolicyDistanceRatesUnitParams'; export type {default as SetPolicyDistanceRatesDefaultCategoryParams} from './SetPolicyDistanceRatesDefaultCategoryParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 40deec85bc47..f3bb917d7f54 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -479,6 +479,7 @@ const READ_COMMANDS = { OPEN_POLICY_WORKFLOWS_PAGE: 'OpenPolicyWorkflowsPage', OPEN_POLICY_DISTANCE_RATES_PAGE: 'OpenPolicyDistanceRatesPage', OPEN_POLICY_MORE_FEATURES_PAGE: 'OpenPolicyMoreFeaturesPage', + OPEN_POLICY_PROFILE_PAGE: 'OpenPolicyProfilePage', OPEN_POLICY_ACCOUNTING_PAGE: 'OpenPolicyAccountingPage', SEARCH: 'Search', } as const; @@ -526,6 +527,7 @@ type ReadCommandParameters = { [READ_COMMANDS.OPEN_POLICY_WORKFLOWS_PAGE]: Parameters.OpenPolicyWorkflowsPageParams; [READ_COMMANDS.OPEN_POLICY_DISTANCE_RATES_PAGE]: Parameters.OpenPolicyDistanceRatesPageParams; [READ_COMMANDS.OPEN_POLICY_MORE_FEATURES_PAGE]: Parameters.OpenPolicyMoreFeaturesPageParams; + [READ_COMMANDS.OPEN_POLICY_PROFILE_PAGE]: Parameters.OpenPolicyProfilePageParams; [READ_COMMANDS.OPEN_POLICY_ACCOUNTING_PAGE]: Parameters.OpenPolicyAccountingPageParams; [READ_COMMANDS.SEARCH]: Parameters.SearchParams; }; diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index fc2a8ad7970e..0be1d783ac3c 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -26,6 +26,7 @@ import type { OpenDraftWorkspaceRequestParams, OpenPolicyDistanceRatesPageParams, OpenPolicyMoreFeaturesPageParams, + OpenPolicyProfilePageParams, OpenPolicyTaxesPageParams, OpenPolicyWorkflowsPageParams, OpenWorkspaceInvitePageParams, @@ -3588,6 +3589,12 @@ function openPolicyMoreFeaturesPage(policyID: string) { API.read(READ_COMMANDS.OPEN_POLICY_MORE_FEATURES_PAGE, params); } +function openPolicyProfilePage(policyID: string) { + const params: OpenPolicyProfilePageParams = {policyID}; + + API.read(READ_COMMANDS.OPEN_POLICY_PROFILE_PAGE, params); +} + function createPolicyDistanceRate(policyID: string, customUnitID: string, customUnitRate: Rate) { const optimisticData: OnyxUpdate[] = [ { @@ -4219,6 +4226,7 @@ export { enablePolicyWorkflows, openPolicyDistanceRatesPage, openPolicyMoreFeaturesPage, + openPolicyProfilePage, generateCustomUnitID, createPolicyDistanceRate, clearCreateDistanceRateItemAndError, diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index cbcc3c88fb2c..fdfc4f02f40d 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -1,4 +1,4 @@ -import {useNavigationState} from '@react-navigation/native'; +import {useFocusEffect, useNavigationState} from '@react-navigation/native'; import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; import {View} from 'react-native'; @@ -85,7 +85,7 @@ function dismissError(policyID: string, pendingAction: PendingAction | undefined } } -function WorkspaceInitialPage({policyDraft, policy: policyProp, reimbursementAccount, policyCategories}: WorkspaceInitialPageProps) { +function WorkspaceInitialPage({policyDraft, policy: policyProp, reimbursementAccount, policyCategories, route}: WorkspaceInitialPageProps) { const styles = useThemeStyles(); const policy = policyDraft?.id ? policyDraft : policyProp; const [isCurrencyModalOpen, setIsCurrencyModalOpen] = useState(false); @@ -132,6 +132,20 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, reimbursementAcc setIsCurrencyModalOpen(false); }, [policy?.outputCurrency, isCurrencyModalOpen]); + // We have the same focus effect in the WorkspaceProfilePage, this way we can get the policy data in narrow + // as well as in the wide layout when looking at policy settings. + const fetchPolicyData = useCallback(() => { + Policy.openPolicyProfilePage(route.params.policyID); + }, [route.params.policyID]); + + useNetwork({onReconnect: fetchPolicyData}); + + useFocusEffect( + useCallback(() => { + fetchPolicyData(); + }, [fetchPolicyData]), + ); + /** Call update workspace currency and hide the modal */ const confirmCurrencyChangeAndHideModal = useCallback(() => { Policy.updateGeneralSettings(policyID, policyName, CONST.CURRENCY.USD); diff --git a/src/pages/workspace/WorkspaceProfilePage.tsx b/src/pages/workspace/WorkspaceProfilePage.tsx index c45270ba59e0..d58cd568a9f8 100644 --- a/src/pages/workspace/WorkspaceProfilePage.tsx +++ b/src/pages/workspace/WorkspaceProfilePage.tsx @@ -1,3 +1,5 @@ +import {useFocusEffect} from '@react-navigation/native'; +import type {StackScreenProps} from '@react-navigation/stack'; import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import React, {useCallback, useState} from 'react'; import type {ImageStyle, StyleProp} from 'react-native'; @@ -15,12 +17,14 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback'; import Section from '@components/Section'; import useActiveWorkspace from '@hooks/useActiveWorkspace'; import useLocalize from '@hooks/useLocalize'; +import useNetwork from '@hooks/useNetwork'; import usePermissions from '@hooks/usePermissions'; import useThemeIllustrations from '@hooks/useThemeIllustrations'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; +import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; @@ -29,6 +33,7 @@ import * as Policy from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import withPolicy from './withPolicy'; @@ -40,11 +45,11 @@ type WorkspaceProfilePageOnyxProps = { currencyList: OnyxEntry; }; -type WorkSpaceProfilePageProps = WithPolicyProps & WorkspaceProfilePageOnyxProps; +type WorkspaceProfilePageProps = WithPolicyProps & WorkspaceProfilePageOnyxProps & StackScreenProps; const parser = new ExpensiMark(); -function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfilePageProps) { +function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkspaceProfilePageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {isSmallScreenWidth} = useWindowDimensions(); @@ -82,6 +87,20 @@ function WorkspaceProfilePage({policy, currencyList = {}, route}: WorkSpaceProfi const imageStyle: StyleProp = isSmallScreenWidth ? [styles.mhv12, styles.mhn5, styles.mbn5] : [styles.mhv8, styles.mhn8, styles.mbn5]; const shouldShowAddress = !readOnly || formattedAddress; + const fetchPolicyData = useCallback(() => { + Policy.openPolicyProfilePage(route.params.policyID); + }, [route.params.policyID]); + + useNetwork({onReconnect: fetchPolicyData}); + + // We have the same focus effect in the WorkspaceInitialPage, this way we can get the policy data in narrow + // as well as in the wide layout when looking at policy settings. + useFocusEffect( + useCallback(() => { + fetchPolicyData(); + }, [fetchPolicyData]), + ); + const DefaultAvatar = useCallback( () => ( ({ + withOnyx({ currencyList: {key: ONYXKEYS.CURRENCY_LIST}, })(WorkspaceProfilePage), ); From d3221c2eba0cc34b372f3b55545eb439cc708286 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Fri, 31 May 2024 11:19:32 +0200 Subject: [PATCH 03/96] Add policy profile route to the policy routes --- src/pages/workspace/withPolicy.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index 56ad756194a0..efb8a710a649 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -22,6 +22,7 @@ type PolicyRoute = RouteProp< NavigatorsParamList, | typeof SCREENS.REIMBURSEMENT_ACCOUNT_ROOT | typeof SCREENS.WORKSPACE.INITIAL + | typeof SCREENS.WORKSPACE.PROFILE | typeof SCREENS.WORKSPACE.BILLS | typeof SCREENS.WORKSPACE.MORE_FEATURES | typeof SCREENS.WORKSPACE.MEMBERS From a07d7c8c447cbf5ba888b8d89aa5748a480d33cd Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Fri, 31 May 2024 11:29:02 +0200 Subject: [PATCH 04/96] Add a new OpenPolicyInitialPage command --- src/libs/API/parameters/OpenPolicyInitialPageParams.ts | 5 +++++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 ++ src/libs/actions/Policy/Policy.ts | 8 ++++++++ src/pages/workspace/WorkspaceInitialPage.tsx | 4 +--- 5 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 src/libs/API/parameters/OpenPolicyInitialPageParams.ts diff --git a/src/libs/API/parameters/OpenPolicyInitialPageParams.ts b/src/libs/API/parameters/OpenPolicyInitialPageParams.ts new file mode 100644 index 000000000000..764abe9a6a77 --- /dev/null +++ b/src/libs/API/parameters/OpenPolicyInitialPageParams.ts @@ -0,0 +1,5 @@ +type OpenPolicyInitialPageParams = { + policyID: string; +}; + +export default OpenPolicyInitialPageParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 4fe04fba4e97..ef1be1e3dc93 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -193,6 +193,7 @@ export type {default as OpenPolicyTaxesPageParams} from './OpenPolicyTaxesPagePa export type {default as EnablePolicyTaxesParams} from './EnablePolicyTaxesParams'; export type {default as OpenPolicyMoreFeaturesPageParams} from './OpenPolicyMoreFeaturesPageParams'; export type {default as OpenPolicyProfilePageParams} from './OpenPolicyProfilePageParams'; +export type {default as OpenPolicyInitialPageParams} from './OpenPolicyInitialPageParams'; export type {default as CreatePolicyDistanceRateParams} from './CreatePolicyDistanceRateParams'; export type {default as SetPolicyDistanceRatesUnitParams} from './SetPolicyDistanceRatesUnitParams'; export type {default as SetPolicyDistanceRatesDefaultCategoryParams} from './SetPolicyDistanceRatesDefaultCategoryParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index f3bb917d7f54..dbe244a9dfea 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -480,6 +480,7 @@ const READ_COMMANDS = { OPEN_POLICY_DISTANCE_RATES_PAGE: 'OpenPolicyDistanceRatesPage', OPEN_POLICY_MORE_FEATURES_PAGE: 'OpenPolicyMoreFeaturesPage', OPEN_POLICY_PROFILE_PAGE: 'OpenPolicyProfilePage', + OPEN_POLICY_INITIAL_PAGE: 'OpenPolicyInitialPage', OPEN_POLICY_ACCOUNTING_PAGE: 'OpenPolicyAccountingPage', SEARCH: 'Search', } as const; @@ -528,6 +529,7 @@ type ReadCommandParameters = { [READ_COMMANDS.OPEN_POLICY_DISTANCE_RATES_PAGE]: Parameters.OpenPolicyDistanceRatesPageParams; [READ_COMMANDS.OPEN_POLICY_MORE_FEATURES_PAGE]: Parameters.OpenPolicyMoreFeaturesPageParams; [READ_COMMANDS.OPEN_POLICY_PROFILE_PAGE]: Parameters.OpenPolicyProfilePageParams; + [READ_COMMANDS.OPEN_POLICY_INITIAL_PAGE]: Parameters.OpenPolicyInitialPageParams; [READ_COMMANDS.OPEN_POLICY_ACCOUNTING_PAGE]: Parameters.OpenPolicyAccountingPageParams; [READ_COMMANDS.SEARCH]: Parameters.SearchParams; }; diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 0be1d783ac3c..adb57af601db 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -27,6 +27,7 @@ import type { OpenPolicyDistanceRatesPageParams, OpenPolicyMoreFeaturesPageParams, OpenPolicyProfilePageParams, + OpenPolicyInitialPageParams, OpenPolicyTaxesPageParams, OpenPolicyWorkflowsPageParams, OpenWorkspaceInvitePageParams, @@ -3595,6 +3596,12 @@ function openPolicyProfilePage(policyID: string) { API.read(READ_COMMANDS.OPEN_POLICY_PROFILE_PAGE, params); } +function openPolicyInitialPage(policyID: string) { + const params: OpenPolicyInitialPageParams = {policyID}; + + API.read(READ_COMMANDS.OPEN_POLICY_INITIAL_PAGE, params); +} + function createPolicyDistanceRate(policyID: string, customUnitID: string, customUnitRate: Rate) { const optimisticData: OnyxUpdate[] = [ { @@ -4227,6 +4234,7 @@ export { openPolicyDistanceRatesPage, openPolicyMoreFeaturesPage, openPolicyProfilePage, + openPolicyInitialPage, generateCustomUnitID, createPolicyDistanceRate, clearCreateDistanceRateItemAndError, diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx index fdfc4f02f40d..a789a482135e 100644 --- a/src/pages/workspace/WorkspaceInitialPage.tsx +++ b/src/pages/workspace/WorkspaceInitialPage.tsx @@ -132,10 +132,8 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, reimbursementAcc setIsCurrencyModalOpen(false); }, [policy?.outputCurrency, isCurrencyModalOpen]); - // We have the same focus effect in the WorkspaceProfilePage, this way we can get the policy data in narrow - // as well as in the wide layout when looking at policy settings. const fetchPolicyData = useCallback(() => { - Policy.openPolicyProfilePage(route.params.policyID); + Policy.openPolicyInitialPage(route.params.policyID); }, [route.params.policyID]); useNetwork({onReconnect: fetchPolicyData}); From b74985b5b7ebcdfaf6b17762034f0215e80b281d Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Fri, 31 May 2024 18:38:38 +0200 Subject: [PATCH 05/96] prettier --- src/libs/actions/Policy/Policy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index adb57af601db..880b6c062e13 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -25,9 +25,9 @@ import type { LeavePolicyParams, OpenDraftWorkspaceRequestParams, OpenPolicyDistanceRatesPageParams, + OpenPolicyInitialPageParams, OpenPolicyMoreFeaturesPageParams, OpenPolicyProfilePageParams, - OpenPolicyInitialPageParams, OpenPolicyTaxesPageParams, OpenPolicyWorkflowsPageParams, OpenWorkspaceInvitePageParams, From 61abbb9c9df6363e3704a4c24dbbee120a42d093 Mon Sep 17 00:00:00 2001 From: ShridharGoel <35566748+ShridharGoel@users.noreply.github.com> Date: Mon, 10 Jun 2024 23:46:35 +0530 Subject: [PATCH 06/96] Use workspace's default currency when submitting expense --- src/libs/actions/IOU.ts | 2 +- src/libs/actions/Policy/Policy.ts | 6 +++--- src/libs/actions/TeachersUnite.ts | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 1bd4de43acfb..8b63cee54492 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -332,7 +332,7 @@ function initMoneyRequest(reportID: string, policy: OnyxEntry, amount: 0, comment, created, - currency: currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, + currency: policy?.outputCurrency ?? currentUserPersonalDetails.localCurrencyCode ?? CONST.CURRENCY.USD, iouRequestType, reportID, transactionID: newTransactionID, diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 0e168f973078..422bbcf49cac 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -1390,8 +1390,8 @@ function generateCustomUnitID(): string { return NumberUtils.generateHexadecimalValue(13); } -function buildOptimisticCustomUnits(): OptimisticCustomUnits { - const currency = allPersonalDetails?.[sessionAccountID]?.localCurrencyCode ?? CONST.CURRENCY.USD; +function buildOptimisticCustomUnits(reportCurrency?: string): OptimisticCustomUnits { + const currency = reportCurrency ?? allPersonalDetails?.[sessionAccountID]?.localCurrencyCode ?? CONST.CURRENCY.USD; const customUnitID = generateCustomUnitID(); const customUnitRateID = generateCustomUnitID(); @@ -2069,7 +2069,7 @@ function createWorkspaceFromIOUPayment(iouReport: Report | EmptyObject): string const workspaceName = generateDefaultWorkspaceName(sessionEmail); const employeeAccountID = iouReport.ownerAccountID; const employeeEmail = iouReport.ownerEmail ?? ''; - const {customUnits, customUnitID, customUnitRateID} = buildOptimisticCustomUnits(); + const {customUnits, customUnitID, customUnitRateID} = buildOptimisticCustomUnits(iouReport.currency); const oldPersonalPolicyID = iouReport.policyID; const iouReportID = iouReport.reportID; diff --git a/src/libs/actions/TeachersUnite.ts b/src/libs/actions/TeachersUnite.ts index 36fd9d340aeb..5377e0dead29 100644 --- a/src/libs/actions/TeachersUnite.ts +++ b/src/libs/actions/TeachersUnite.ts @@ -10,6 +10,7 @@ import type {OptimisticCreatedReportAction} from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PersonalDetailsList} from '@src/types/onyx'; +import {getPolicy} from "@libs/PolicyUtils"; type CreationData = { reportID: string; @@ -95,7 +96,7 @@ function addSchoolPrincipal(firstName: string, partnerUserID: string, lastName: name: policyName, role: CONST.POLICY.ROLE.USER, owner: sessionEmail, - outputCurrency: allPersonalDetails?.[sessionAccountID]?.localCurrencyCode ?? CONST.CURRENCY.USD, + outputCurrency: getPolicy(policyID)?.outputCurrency ?? allPersonalDetails?.[sessionAccountID]?.localCurrencyCode ?? CONST.CURRENCY.USD, employeeList: { [sessionEmail]: { role: CONST.POLICY.ROLE.USER, From f47a633b8663df34507383a875b5bee30a09a2e9 Mon Sep 17 00:00:00 2001 From: dominictb Date: Thu, 13 Jun 2024 15:32:39 +0700 Subject: [PATCH 07/96] fix: default notification to be hidden for new chat Signed-off-by: dominictb --- src/libs/ReportUtils.ts | 10 ++++++++-- src/libs/actions/Report.ts | 15 +++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 914c653b6f91..d8d2d6cda404 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4602,7 +4602,13 @@ function buildOptimisticChatReport( return optimisticChatReport; } -function buildOptimisticGroupChatReport(participantAccountIDs: number[], reportName: string, avatarUri: string, optimisticReportID?: string) { +function buildOptimisticGroupChatReport( + participantAccountIDs: number[], + reportName: string, + avatarUri: string, + optimisticReportID?: string, + notificationPreference?: NotificationPreference, +) { return buildOptimisticChatReport( participantAccountIDs, reportName, @@ -4613,7 +4619,7 @@ function buildOptimisticGroupChatReport(participantAccountIDs: number[], reportN undefined, undefined, undefined, - undefined, + notificationPreference, undefined, undefined, undefined, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 3adf48046936..c3d52e1c85f0 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -975,9 +975,20 @@ function navigateToAndOpenReport( if (isEmptyObject(chat)) { if (isGroupChat) { // If we are creating a group chat then participantAccountIDs is expected to contain currentUserAccountID - newChat = ReportUtils.buildOptimisticGroupChatReport(participantAccountIDs, reportName ?? '', avatarUri ?? '', optimisticReportID); + newChat = ReportUtils.buildOptimisticGroupChatReport(participantAccountIDs, reportName ?? '', avatarUri ?? '', optimisticReportID, CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); } else { - newChat = ReportUtils.buildOptimisticChatReport([...participantAccountIDs, currentUserAccountID]); + newChat = ReportUtils.buildOptimisticChatReport( + [...participantAccountIDs, currentUserAccountID], + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + ); } } const report = isEmptyObject(chat) ? newChat : chat; From 20dc2ded09fd7891a97678cf5a997956814c9d3e Mon Sep 17 00:00:00 2001 From: truph01 Date: Thu, 13 Jun 2024 18:51:54 +0700 Subject: [PATCH 08/96] Feat: Implement loading skeleton small screen width --- src/CONST.ts | 1 + .../Skeletons/ItemListSkeletonView.tsx | 29 +++--- .../Skeletons/TableListItemSkeleton.tsx | 88 ++++++++++++++++++- 3 files changed, 104 insertions(+), 14 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 6a936bc97087..8423df11739a 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1252,6 +1252,7 @@ const CONST = { }, CENTRAL_PANE_ANIMATION_HEIGHT: 200, LHN_SKELETON_VIEW_ITEM_HEIGHT: 64, + SEARCH_SKELETON_VIEW_ITEM_HEIGHT: 90, EXPENSIFY_PARTNER_NAME: 'expensify.com', EMAIL: { ACCOUNTING: 'accounting@expensify.com', diff --git a/src/components/Skeletons/ItemListSkeletonView.tsx b/src/components/Skeletons/ItemListSkeletonView.tsx index 5c46dbdddbfc..52501113d1d1 100644 --- a/src/components/Skeletons/ItemListSkeletonView.tsx +++ b/src/components/Skeletons/ItemListSkeletonView.tsx @@ -1,5 +1,5 @@ import React, {useMemo, useState} from 'react'; -import {View} from 'react-native'; +import {StyleProp, View, ViewStyle} from 'react-native'; import SkeletonViewContentLoader from '@components/SkeletonViewContentLoader'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -9,9 +9,11 @@ type ListItemSkeletonProps = { shouldAnimate?: boolean; renderSkeletonItem: (args: {itemIndex: number}) => React.ReactNode; fixedNumItems?: number; + itemViewStyle?: StyleProp; + itemViewHeight?: number; }; -function ItemListSkeletonView({shouldAnimate = true, renderSkeletonItem, fixedNumItems}: ListItemSkeletonProps) { +function ItemListSkeletonView({shouldAnimate = true, renderSkeletonItem, fixedNumItems, itemViewStyle = {}, itemViewHeight = CONST.LHN_SKELETON_VIEW_ITEM_HEIGHT}: ListItemSkeletonProps) { const theme = useTheme(); const themeStyles = useThemeStyles(); @@ -20,16 +22,17 @@ function ItemListSkeletonView({shouldAnimate = true, renderSkeletonItem, fixedNu const items = []; for (let i = 0; i < numItems; i++) { items.push( - - {renderSkeletonItem({itemIndex: i})} - , + + + {renderSkeletonItem({itemIndex: i})} + + , ); } return items; @@ -43,7 +46,7 @@ function ItemListSkeletonView({shouldAnimate = true, renderSkeletonItem, fixedNu return; } - const newNumItems = Math.ceil(event.nativeEvent.layout.height / CONST.LHN_SKELETON_VIEW_ITEM_HEIGHT); + const newNumItems = Math.ceil(event.nativeEvent.layout.height / itemViewHeight); if (newNumItems === numItems) { return; } diff --git a/src/components/Skeletons/TableListItemSkeleton.tsx b/src/components/Skeletons/TableListItemSkeleton.tsx index 4b2c214921d0..62116f063d64 100644 --- a/src/components/Skeletons/TableListItemSkeleton.tsx +++ b/src/components/Skeletons/TableListItemSkeleton.tsx @@ -1,5 +1,8 @@ import React from 'react'; -import {Rect} from 'react-native-svg'; +import {Circle, Rect} from 'react-native-svg'; +import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; +import CONST from '@src/CONST'; import ItemListSkeletonView from './ItemListSkeletonView'; type TableListItemSkeletonProps = { @@ -7,11 +10,94 @@ type TableListItemSkeletonProps = { fixedNumItems?: number; }; +const circleRadius = 8; +const padding = 12; const barHeight = '10'; const shortBarWidth = '40'; const longBarWidth = '120'; function TableListItemSkeleton({shouldAnimate = true, fixedNumItems}: TableListItemSkeletonProps) { + const styles = useThemeStyles(); + const {windowWidth, isSmallScreenWidth} = useWindowDimensions(); + if (isSmallScreenWidth) { + return ( + ( + <> + + + + + + + + + + + + + + + )} + /> + ); + } return ( Date: Thu, 13 Jun 2024 19:04:53 +0700 Subject: [PATCH 09/96] Fix: Lint --- src/components/Skeletons/ItemListSkeletonView.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Skeletons/ItemListSkeletonView.tsx b/src/components/Skeletons/ItemListSkeletonView.tsx index 52501113d1d1..43df591000c1 100644 --- a/src/components/Skeletons/ItemListSkeletonView.tsx +++ b/src/components/Skeletons/ItemListSkeletonView.tsx @@ -1,5 +1,6 @@ import React, {useMemo, useState} from 'react'; -import {StyleProp, View, ViewStyle} from 'react-native'; +import {View} from 'react-native'; +import type {StyleProp, ViewStyle} from 'react-native'; import SkeletonViewContentLoader from '@components/SkeletonViewContentLoader'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; From db3f19ea25ef9201edda62964c8723093b7c5e3b Mon Sep 17 00:00:00 2001 From: truph01 Date: Thu, 13 Jun 2024 19:13:58 +0700 Subject: [PATCH 10/96] Fix: Lint --- src/components/Skeletons/ItemListSkeletonView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Skeletons/ItemListSkeletonView.tsx b/src/components/Skeletons/ItemListSkeletonView.tsx index 43df591000c1..7df68a943a9f 100644 --- a/src/components/Skeletons/ItemListSkeletonView.tsx +++ b/src/components/Skeletons/ItemListSkeletonView.tsx @@ -37,7 +37,7 @@ function ItemListSkeletonView({shouldAnimate = true, renderSkeletonItem, fixedNu ); } return items; - }, [numItems, shouldAnimate, theme, themeStyles, renderSkeletonItem]); + }, [numItems, shouldAnimate, theme, themeStyles, renderSkeletonItem, itemViewHeight, itemViewStyle]); return ( Date: Fri, 14 Jun 2024 18:32:13 +0700 Subject: [PATCH 11/96] Fix: Update SEARCH_SKELETON_VIEW_ITEM_HEIGHT to 100 --- src/CONST.ts | 2 +- src/components/Skeletons/TableListItemSkeleton.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 8423df11739a..5ff88365b70e 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1252,7 +1252,7 @@ const CONST = { }, CENTRAL_PANE_ANIMATION_HEIGHT: 200, LHN_SKELETON_VIEW_ITEM_HEIGHT: 64, - SEARCH_SKELETON_VIEW_ITEM_HEIGHT: 90, + SEARCH_SKELETON_VIEW_ITEM_HEIGHT: 100, EXPENSIFY_PARTNER_NAME: 'expensify.com', EMAIL: { ACCOUNTING: 'accounting@expensify.com', diff --git a/src/components/Skeletons/TableListItemSkeleton.tsx b/src/components/Skeletons/TableListItemSkeleton.tsx index 62116f063d64..d3491fcb717c 100644 --- a/src/components/Skeletons/TableListItemSkeleton.tsx +++ b/src/components/Skeletons/TableListItemSkeleton.tsx @@ -37,7 +37,7 @@ function TableListItemSkeleton({shouldAnimate = true, fixedNumItems}: TableListI Date: Fri, 14 Jun 2024 19:00:30 +0700 Subject: [PATCH 12/96] Fix: Update row gap to 12px --- src/components/Skeletons/TableListItemSkeleton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Skeletons/TableListItemSkeleton.tsx b/src/components/Skeletons/TableListItemSkeleton.tsx index d3491fcb717c..7b1b364930f2 100644 --- a/src/components/Skeletons/TableListItemSkeleton.tsx +++ b/src/components/Skeletons/TableListItemSkeleton.tsx @@ -23,7 +23,7 @@ function TableListItemSkeleton({shouldAnimate = true, fixedNumItems}: TableListI return ( ( From c90fb0b774abe3dba2acc5c824b0069ca6430ed9 Mon Sep 17 00:00:00 2001 From: dominictb Date: Mon, 17 Jun 2024 14:51:31 +0700 Subject: [PATCH 13/96] chore: default "always" noti pref for created group chat Signed-off-by: dominictb --- src/libs/ReportUtils.ts | 3 +-- src/libs/actions/Report.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 36d2ebcf7c68..f59f2ebf6087 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4607,7 +4607,6 @@ function buildOptimisticGroupChatReport( reportName: string, avatarUri: string, optimisticReportID?: string, - notificationPreference?: NotificationPreference, ) { return buildOptimisticChatReport( participantAccountIDs, @@ -4619,7 +4618,7 @@ function buildOptimisticGroupChatReport( undefined, undefined, undefined, - notificationPreference, + undefined, undefined, undefined, undefined, diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 5902bd0af835..78df6fd4d9e0 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -975,7 +975,7 @@ function navigateToAndOpenReport( if (isEmptyObject(chat)) { if (isGroupChat) { // If we are creating a group chat then participantAccountIDs is expected to contain currentUserAccountID - newChat = ReportUtils.buildOptimisticGroupChatReport(participantAccountIDs, reportName ?? '', avatarUri ?? '', optimisticReportID, CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN); + newChat = ReportUtils.buildOptimisticGroupChatReport(participantAccountIDs, reportName ?? '', avatarUri ?? '', optimisticReportID); } else { newChat = ReportUtils.buildOptimisticChatReport( [...participantAccountIDs, currentUserAccountID], From 18d54d95590db663084655dd17112dc039136d6b Mon Sep 17 00:00:00 2001 From: dominictb Date: Mon, 17 Jun 2024 14:52:30 +0700 Subject: [PATCH 14/96] fix: prettier Signed-off-by: dominictb --- src/libs/ReportUtils.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index f59f2ebf6087..5cdc9e71c54e 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4602,12 +4602,7 @@ function buildOptimisticChatReport( return optimisticChatReport; } -function buildOptimisticGroupChatReport( - participantAccountIDs: number[], - reportName: string, - avatarUri: string, - optimisticReportID?: string, -) { +function buildOptimisticGroupChatReport(participantAccountIDs: number[], reportName: string, avatarUri: string, optimisticReportID?: string) { return buildOptimisticChatReport( participantAccountIDs, reportName, From 295813001e0df15826e311c731fe9390deb16733 Mon Sep 17 00:00:00 2001 From: Jan Nowakowski Date: Mon, 17 Jun 2024 15:31:25 +0200 Subject: [PATCH 15/96] Do not trap focus on troubleshoot and save the world pages --- src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts b/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts index 5f10a7293457..9add10463a95 100644 --- a/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts +++ b/src/components/FocusTrap/WIDE_LAYOUT_INACTIVE_SCREENS.ts @@ -32,6 +32,8 @@ const WIDE_LAYOUT_INACTIVE_SCREENS: string[] = [ SCREENS.WORKSPACE.TAXES, SCREENS.WORKSPACE.DISTANCE_RATES, SCREENS.SEARCH.CENTRAL_PANE, + SCREENS.SETTINGS.TROUBLESHOOT, + SCREENS.SETTINGS.SAVE_THE_WORLD, ]; export default WIDE_LAYOUT_INACTIVE_SCREENS; From 284e32ae1aca15f9a64c07df8ebaee9af07ade06 Mon Sep 17 00:00:00 2001 From: truph01 Date: Mon, 17 Jun 2024 22:43:28 +0700 Subject: [PATCH 16/96] Fix: Comment --- .../Skeletons/TableListItemSkeleton.tsx | 72 +++++++++---------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/src/components/Skeletons/TableListItemSkeleton.tsx b/src/components/Skeletons/TableListItemSkeleton.tsx index 7b1b364930f2..5f2a3096c0be 100644 --- a/src/components/Skeletons/TableListItemSkeleton.tsx +++ b/src/components/Skeletons/TableListItemSkeleton.tsx @@ -10,8 +10,6 @@ type TableListItemSkeletonProps = { fixedNumItems?: number; }; -const circleRadius = 8; -const padding = 12; const barHeight = '10'; const shortBarWidth = '40'; const longBarWidth = '120'; @@ -29,69 +27,69 @@ function TableListItemSkeleton({shouldAnimate = true, fixedNumItems}: TableListI renderSkeletonItem={() => ( <> )} From fc1a1fa1e6f1c6a9ef8848330c5b7ee8a02ea1bb Mon Sep 17 00:00:00 2001 From: truph01 Date: Mon, 17 Jun 2024 22:55:49 +0700 Subject: [PATCH 17/96] Fix: Update radius --- src/components/Skeletons/TableListItemSkeleton.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Skeletons/TableListItemSkeleton.tsx b/src/components/Skeletons/TableListItemSkeleton.tsx index 5f2a3096c0be..4cfbe902f830 100644 --- a/src/components/Skeletons/TableListItemSkeleton.tsx +++ b/src/components/Skeletons/TableListItemSkeleton.tsx @@ -64,8 +64,8 @@ function TableListItemSkeleton({shouldAnimate = true, fixedNumItems}: TableListI y={48} width={36} height={40} - rx={6} - ry={6} + rx={4} + ry={4} /> Date: Mon, 17 Jun 2024 18:40:55 +0100 Subject: [PATCH 18/96] feature: add workspace restricted action screen --- ...simple-illustration__lockclosed_orange.svg | 52 ++++++++++++++ src/ROUTES.ts | 4 ++ src/SCREENS.ts | 2 + src/components/Icon/Illustrations.ts | 2 + src/languages/en.ts | 12 ++++ src/languages/es.ts | 12 ++++ .../ModalStackNavigators/index.tsx | 5 ++ .../Navigators/RightModalNavigator.tsx | 4 ++ src/libs/Navigation/linkingConfig/config.ts | 5 ++ src/libs/Navigation/types.ts | 8 +++ src/libs/ReportUtils.ts | 6 ++ .../WorkspaceAdminRestrictedAction.tsx | 68 ++++++++++++++++++ .../WorkspaceOwnerRestrictedAction.tsx | 69 +++++++++++++++++++ .../WorkspaceRestrictedActionPage.tsx | 38 ++++++++++ .../WorkspaceUserRestrictedAction.tsx | 68 ++++++++++++++++++ 15 files changed, 355 insertions(+) create mode 100644 assets/images/simple-illustrations/simple-illustration__lockclosed_orange.svg create mode 100644 src/pages/RestrictedAction/Workspace/WorkspaceAdminRestrictedAction.tsx create mode 100644 src/pages/RestrictedAction/Workspace/WorkspaceOwnerRestrictedAction.tsx create mode 100644 src/pages/RestrictedAction/Workspace/WorkspaceRestrictedActionPage.tsx create mode 100644 src/pages/RestrictedAction/Workspace/WorkspaceUserRestrictedAction.tsx diff --git a/assets/images/simple-illustrations/simple-illustration__lockclosed_orange.svg b/assets/images/simple-illustrations/simple-illustration__lockclosed_orange.svg new file mode 100644 index 000000000000..91af173f0357 --- /dev/null +++ b/assets/images/simple-illustrations/simple-illustration__lockclosed_orange.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ROUTES.ts b/src/ROUTES.ts index c1fdd68951fa..5fd4d2e88645 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -908,6 +908,10 @@ const ROUTES = { route: 'settings/workspaces/:policyID/accounting/quickbooks-online/import/taxes', getRoute: (policyID: string) => `settings/workspaces/${policyID}/accounting/quickbooks-online/import/taxes` as const, }, + RESTRICTED_ACTION: { + route: 'restricted-action/workspace/:policyID', + getRoute: (policyID: string) => `restricted-action/workspace/${policyID}` as const, + }, } as const; /** diff --git a/src/SCREENS.ts b/src/SCREENS.ts index f884cca94ef5..270799810fb6 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -141,6 +141,7 @@ const SCREENS = { TRAVEL: 'Travel', SEARCH_REPORT: 'SearchReport', SETTINGS_CATEGORIES: 'SettingsCategories', + RESTRICTED_ACTION: 'RestrictedAction', }, ONBOARDING_MODAL: { ONBOARDING: 'Onboarding', @@ -378,6 +379,7 @@ const SCREENS = { KEYBOARD_SHORTCUTS: 'KeyboardShortcuts', TRANSACTION_RECEIPT: 'TransactionReceipt', FEATURE_TRAINING_ROOT: 'FeatureTraining_Root', + RESTRICTED_ACTION_ROOT: 'RestrictedAction_Root', } as const; type Screen = DeepValueOf; diff --git a/src/components/Icon/Illustrations.ts b/src/components/Icon/Illustrations.ts index 3fe36239d631..1cec6eed496a 100644 --- a/src/components/Icon/Illustrations.ts +++ b/src/components/Icon/Illustrations.ts @@ -94,6 +94,7 @@ import WalletAlt from '@assets/images/simple-illustrations/simple-illustration__ import Workflows from '@assets/images/simple-illustrations/simple-illustration__workflows.svg'; import ExpensifyApprovedLogoLight from '@assets/images/subscription-details__approvedlogo--light.svg'; import ExpensifyApprovedLogo from '@assets/images/subscription-details__approvedlogo.svg'; +import LockClosedOrange from '@assets/images/simple-illustrations/simple-illustration__lockclosed_orange.svg' export { Abracadabra, @@ -192,4 +193,5 @@ export { SendMoney, CheckmarkCircle, CreditCardEyes, + LockClosedOrange, }; diff --git a/src/languages/en.ts b/src/languages/en.ts index bf3803c7606d..3fb446536c9c 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -2683,6 +2683,18 @@ export default { errorDescriptionPartTwo: 'reach out to Concierge', errorDescriptionPartThree: 'for help.', }, + restrictedAction: { + restricted: 'Restricted', + expensesAreCurrentlyRestricted: ({workspaceName}) => `Expenses to ${workspaceName} are currently restricted`, + workspaceOwnerWillNeedToAddOrUpdatePaymentCard: ({workspaceOwnerName}) => `Workspace owner, ${workspaceOwnerName} will need to add or update the payment card on file to unlock new workspace activity.`, + youWillNeedToAddOrUpdatePaymentCard: 'You\'ll need to add or update the payment card on file to unlock new workspace activity.', + addPaymentCardToUnlock: 'Add a payment card to unlock', + addPaymentCardToContinueUsingWorkspace: 'Add a payment card to continue using this workspace', + pleaseReachOutToYourWorkspaceAdmin: 'Please reach out to your workspace admin for any questions.', + chatWithYourAdmin: 'Chat with your admin', + chatInAdmins: 'Chat in #admins', + addPaymentCard: 'Add payment card', + } }, getAssistancePage: { title: 'Get assistance', diff --git a/src/languages/es.ts b/src/languages/es.ts index 4c900e23acc5..ac2a135d1055 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2721,6 +2721,18 @@ export default { errorDescriptionPartTwo: 'contacta con el conserje', errorDescriptionPartThree: 'por ayuda.', }, + restrictedAction: { + restricted: 'Restringido', + expensesAreCurrentlyRestricted: ({ workspaceName }) => `Los gastos para ${workspaceName} están actualmente restringidos`, + pleaseReachOutToYourWorkspaceAdmin: 'Si tienes alguna pregunta, ponte en contacto con el administrador de su espacio de trabajo.', + chatWithYourAdmin: 'Chatea con tu administrador', + workspaceOwnerWillNeedToAddOrUpdatePaymentCard: ({workspaceOwnerName}) => `El propietario del espacio de trabajo, ${workspaceOwnerName} tendrá que añadir o actualizar la tarjeta de pago registrada para desbloquear nueva actividad en el espacio de trabajo.`, + youWillNeedToAddOrUpdatePaymentCard: 'Debes añadir o actualizar la tarjeta de pago registrada para desbloquear nueva actividad en el espacio de trabajo.', + addPaymentCardToUnlock: 'Añade una tarjeta de pago para desbloquearlo', + addPaymentCardToContinueUsingWorkspace: 'Añade una tarjeta de pago para seguir utilizando este espacio de trabajo', + chatInAdmins: 'Chatea en #admins', + addPaymentCard: 'Agregar tarjeta de pago' + } }, getAssistancePage: { title: 'Obtener ayuda', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 0577fdcfc5aa..a6efe5fa5aed 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -372,6 +372,10 @@ const SearchReportModalStackNavigator = createModalStackNavigator require('../../../../pages/home/ReportScreen').default as React.ComponentType, }); +const RestrictedActionModalStackNavigator = createModalStackNavigator({ + [SCREENS.RESTRICTED_ACTION_ROOT]: () => require('../../../../pages/RestrictedAction/Workspace/WorkspaceRestrictedActionPage').default as React.ComponentType, +}); + export { AddPersonalBankAccountModalStackNavigator, EditRequestStackNavigator, @@ -400,4 +404,5 @@ export { TaskModalStackNavigator, WalletStatementStackNavigator, SearchReportModalStackNavigator, + RestrictedActionModalStackNavigator, }; diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx index be23969417f7..e58a895b6024 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx @@ -144,6 +144,10 @@ function RightModalNavigator({navigation}: RightModalNavigatorProps) { name={SCREENS.RIGHT_MODAL.SEARCH_REPORT} component={ModalStackNavigators.SearchReportModalStackNavigator} /> + diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 1b4288a9b3a9..a8751ca0ba84 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -740,6 +740,11 @@ const config: LinkingOptions['config'] = { [SCREENS.SEARCH.REPORT_RHP]: ROUTES.SEARCH_REPORT.route, }, }, + [SCREENS.RIGHT_MODAL.RESTRICTED_ACTION]: { + screens: { + [SCREENS.RESTRICTED_ACTION_ROOT]: ROUTES.RESTRICTED_ACTION.route, + }, + }, }, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index f90a91fe0f19..06cb8d805850 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -770,6 +770,7 @@ type RightModalNavigatorParamList = { [SCREENS.RIGHT_MODAL.PRIVATE_NOTES]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.TRAVEL]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.SEARCH_REPORT]: NavigatorScreenParams; + [SCREENS.RIGHT_MODAL.RESTRICTED_ACTION]: NavigatorScreenParams; }; type TravelNavigatorParamList = { @@ -943,6 +944,12 @@ type SearchReportParamList = { }; }; +type RestrictedActionParamList = { + [SCREENS.RESTRICTED_ACTION_ROOT]: { + policyID: string; + }; +}; + type RootStackParamList = PublicScreensParamList & AuthScreensParamList & LeftModalNavigatorParamList; type BottomTabName = keyof BottomTabNavigatorParamList; @@ -1007,4 +1014,5 @@ export type { WalletStatementNavigatorParamList, WelcomeVideoModalNavigatorParamList, SearchReportParamList, + RestrictedActionParamList, }; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index a02b24c20e35..746f8f4483af 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -6964,6 +6964,11 @@ function shouldShowMerchantColumn(transactions: Transaction[]) { return transactions.some((transaction) => isExpenseReport(allReports?.[transaction.reportID] ?? {})); } +function findPolicyExpenseChatByPolicyID(policyID: string): OnyxEntry { + return Object.values(allReports ?? {}).find((report) => report?.isPolicyExpenseChat && report.policyID === policyID); +} + + export { addDomainToShortMention, areAllRequestsBeingSmartScanned, @@ -7236,6 +7241,7 @@ export { isDraftReport, changeMoneyRequestHoldStatus, createDraftWorkspaceAndNavigateToConfirmationScreen, + findPolicyExpenseChatByPolicyID, }; export type { diff --git a/src/pages/RestrictedAction/Workspace/WorkspaceAdminRestrictedAction.tsx b/src/pages/RestrictedAction/Workspace/WorkspaceAdminRestrictedAction.tsx new file mode 100644 index 000000000000..31c6ae37186d --- /dev/null +++ b/src/pages/RestrictedAction/Workspace/WorkspaceAdminRestrictedAction.tsx @@ -0,0 +1,68 @@ +import React, {useCallback} from 'react'; +import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import Button from '@components/Button'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import * as Illustrations from '@components/Icon/Illustrations'; +import ImageSVG from '@components/ImageSVG'; +import ScreenWrapper from '@components/ScreenWrapper'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as Report from '@libs/actions/Report'; +import Navigation from '@libs/Navigation/Navigation'; +import * as PolicyUtils from '@libs/PolicyUtils'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; + +type WorkspaceUserRestrictedActionProps = { + policyID: string; +}; + +function WorkspaceUserRestrictedAction({policyID}: WorkspaceUserRestrictedActionProps) { + const {translate} = useLocalize(); + const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`); + const styles = useThemeStyles(); + + const onPress = useCallback(() => { + const reportID = `${PolicyUtils.getPolicy(policyID)?.chatReportIDAdmins}` ?? '-1'; + Report.openReport(reportID); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportID)); + }, [policyID]); + + return ( + + Navigation.goBack()} + /> + + + + + {translate('workspace.restrictedAction.expensesAreCurrentlyRestricted', {workspaceName: policy?.name})} + + + {translate('workspace.restrictedAction.workspaceOwnerWillNeedToAddOrUpdatePaymentCard', {workspaceOwnerName: policy?.owner})} + + +