From 92a6c1e308636ed90a308ec387a02a64a5b41bcc Mon Sep 17 00:00:00 2001 From: Eduardo Date: Wed, 11 Oct 2023 07:46:17 +0200 Subject: [PATCH 1/5] Transition from Workspace list to Init screen using Policy Draft info --- src/ONYXKEYS.ts | 2 + src/libs/actions/App.js | 21 +++++++++ src/libs/actions/Policy.js | 46 +++++++++++++++++++ src/pages/workspace/WorkspaceInitialPage.js | 20 ++++++-- src/pages/workspace/WorkspacesListPage.js | 4 +- src/pages/workspace/withPolicy.js | 6 +++ .../withPolicyAndFullscreenLoading.js | 7 +-- 7 files changed, 97 insertions(+), 9 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 0a17d3a1d2f7..14c4aaa80447 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -232,6 +232,8 @@ const ONYXKEYS = { DOWNLOAD: 'download_', POLICY: 'policy_', POLICY_MEMBERS: 'policyMembers_', + POLICY_DRAFTS: 'policyDrafts_', + POLICY_MEMBERS_DRAFTS: 'policyMembersDrafts_', POLICY_CATEGORIES: 'policyCategories_', POLICY_RECENTLY_USED_CATEGORIES: 'policyRecentlyUsedCategories_', POLICY_TAGS: 'policyTags_', diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 7500af6d829e..ae53dec2831b 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -336,6 +336,25 @@ function createWorkspaceAndNavigateToIt(policyOwnerEmail = '', makeMeAdmin = fal .then(endSignOnTransition); } +function createWorkspaceWithPolicyDraftAndNavigateToIt(policyOwnerEmail = '', policyName = '', transitionFromOldDot = false) { + const policyID = Policy.generatePolicyID(); + Policy.createDraftInitialWorkspace(policyOwnerEmail, policyName, policyID); + + Navigation.isNavigationReady() + .then(() => { + if (transitionFromOldDot) { + // We must call goBack() to remove the /transition route from history + Navigation.goBack(ROUTES.HOME); + } + Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); + }) + .then(endSignOnTransition); +} + +function savePolicyDraftByNewWorkspace(policyID, policyName, policyOwnerEmail = '', makeMeAdmin = false, transitionFromOldDot = false, shouldNavigateToAdminChat = true) { + Policy.createWorkspace(policyOwnerEmail, makeMeAdmin, policyName, policyID); +} + /** * This action runs when the Navigator is ready and the current route changes * @@ -513,4 +532,6 @@ export { createWorkspaceAndNavigateToIt, getMissingOnyxUpdates, finalReconnectAppAfterActivatingReliableUpdates, + savePolicyDraftByNewWorkspace, + createWorkspaceWithPolicyDraftAndNavigateToIt, }; diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 1a73b148e100..484b49403ad2 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -909,6 +909,40 @@ function buildOptimisticCustomUnits() { }; } +function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', policyID = generatePolicyID()) { + const workspaceName = policyName || generateDefaultWorkspaceName(policyOwnerEmail); + const {customUnits} = buildOptimisticCustomUnits(); + + const optimisticData = [ + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`, + value: { + id: policyID, + type: CONST.POLICY.TYPE.FREE, + name: workspaceName, + role: CONST.POLICY.ROLE.ADMIN, + owner: sessionEmail, + isPolicyExpenseChatEnabled: true, + outputCurrency: lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD), + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + customUnits, + }, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS}${policyID}`, + value: { + [sessionAccountID]: { + role: CONST.POLICY.ROLE.ADMIN, + errors: {}, + }, + }, + }, + ]; + Onyx.update(optimisticData); +} + /** * Optimistically creates a new workspace and default workspace chats * @@ -957,6 +991,16 @@ function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName }, { optimisticData: [ + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`, + value: null, + }, { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, @@ -1131,6 +1175,7 @@ function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName ], }, ); + return adminsChatReportID; } @@ -1259,4 +1304,5 @@ export { clearErrors, openDraftWorkspaceRequest, buildOptimisticPolicyRecentlyUsedCategories, + createDraftInitialWorkspace, }; diff --git a/src/pages/workspace/WorkspaceInitialPage.js b/src/pages/workspace/WorkspaceInitialPage.js index 567aef1274e1..8b459e774d63 100644 --- a/src/pages/workspace/WorkspaceInitialPage.js +++ b/src/pages/workspace/WorkspaceInitialPage.js @@ -11,6 +11,7 @@ import Tooltip from '../../components/Tooltip'; import Text from '../../components/Text'; import ConfirmModal from '../../components/ConfirmModal'; import * as Expensicons from '../../components/Icon/Expensicons'; +import * as App from '../../libs/actions/App'; import ScreenWrapper from '../../components/ScreenWrapper'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import MenuItem from '../../components/MenuItem'; @@ -31,6 +32,7 @@ import * as ReimbursementAccountProps from '../ReimbursementAccount/reimbursemen import * as ReportUtils from '../../libs/ReportUtils'; import withWindowDimensions from '../../components/withWindowDimensions'; import PressableWithoutFeedback from '../../components/Pressable/PressableWithoutFeedback'; +import useWindowDimensions from '../../hooks/useWindowDimensions'; const propTypes = { ...policyPropTypes, @@ -65,9 +67,10 @@ function dismissError(policyID) { } function WorkspaceInitialPage(props) { - const policy = props.policy; + const policy = props.policyDraft && props.policyDraft.id ? props.policyDraft : props.policy; const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isCurrencyModalOpen, setIsCurrencyModalOpen] = useState(false); + const {isSmallScreenWidth} = useWindowDimensions(); const hasPolicyCreationError = Boolean(policy.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD && policy.errors); /** @@ -81,6 +84,17 @@ function WorkspaceInitialPage(props) { Navigation.goBack(ROUTES.SETTINGS_WORKSPACES); }, [props.reports, policy]); + useEffect(() => { + const policyDraftId = lodashGet(props.policyDraft, 'id', null); + if (!policyDraftId) { + return; + } + + App.savePolicyDraftByNewWorkspace(props.policyDraft.id, props.policyDraft.name, '', false, '', !isSmallScreenWidth); + // I only care when the component renders the first time + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useEffect(() => { if (!isCurrencyModalOpen || policy.outputCurrency !== CONST.CURRENCY.USD) { return; @@ -189,8 +203,8 @@ function WorkspaceInitialPage(props) { {({safeAreaPaddingBottomStyle}) => ( Navigation.goBack(ROUTES.SETTINGS_WORKSPACES)} - shouldShow={_.isEmpty(props.policy) || !PolicyUtils.isPolicyAdmin(props.policy) || PolicyUtils.isPendingDeletePolicy(props.policy)} - subtitleKey={_.isEmpty(props.policy) ? undefined : 'workspace.common.notAuthorized'} + shouldShow={_.isEmpty(policy) || !PolicyUtils.isPolicyAdmin(policy) || PolicyUtils.isPendingDeletePolicy(policy)} + subtitleKey={_.isEmpty(policy) ? undefined : 'workspace.common.notAuthorized'} > App.createWorkspaceAndNavigateToIt('', false, '', false, !isSmallScreenWidth)} + onPress={() => App.createWorkspaceWithPolicyDraftAndNavigateToIt()} /> } > diff --git a/src/pages/workspace/withPolicy.js b/src/pages/workspace/withPolicy.js index b1659ea2b7a6..6ca0ca67fce1 100644 --- a/src/pages/workspace/withPolicy.js +++ b/src/pages/workspace/withPolicy.js @@ -120,6 +120,12 @@ export default function (WrappedComponent) { policyMembers: { key: (props) => `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${getPolicyIDFromRoute(props.route)}`, }, + policyDraft: { + key: (props) => `${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${getPolicyIDFromRoute(props.route)}`, + }, + policyMembersDraft: { + key: (props) => `${ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS}${getPolicyIDFromRoute(props.route)}`, + }, })(withPolicy); } diff --git a/src/pages/workspace/withPolicyAndFullscreenLoading.js b/src/pages/workspace/withPolicyAndFullscreenLoading.js index 29f1424a26f6..72f8b51b1f60 100644 --- a/src/pages/workspace/withPolicyAndFullscreenLoading.js +++ b/src/pages/workspace/withPolicyAndFullscreenLoading.js @@ -1,7 +1,8 @@ import PropTypes from 'prop-types'; import React from 'react'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; +import isEmpty from 'underscore/modules/isEmpty'; +import omit from 'underscore/modules/omit'; import compose from '../../libs/compose'; import ONYXKEYS from '../../ONYXKEYS'; import withPolicy, {policyPropTypes, policyDefaultProps} from './withPolicy'; @@ -27,11 +28,11 @@ export default function (WrappedComponent) { }; function WithPolicyAndFullscreenLoading(props) { - if (props.isLoadingReportData && _.isEmpty(props.policy)) { + if (props.isLoadingReportData && isEmpty(props.policy) && isEmpty(props.policyDraft)) { return ; } - const rest = _.omit(props, ['forwardedRef']); + const rest = omit(props, ['forwardedRef']); return ( Date: Wed, 11 Oct 2023 10:58:03 +0200 Subject: [PATCH 2/5] removed unused variables --- src/libs/actions/App.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index ae53dec2831b..3f484528af07 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -351,7 +351,7 @@ function createWorkspaceWithPolicyDraftAndNavigateToIt(policyOwnerEmail = '', po .then(endSignOnTransition); } -function savePolicyDraftByNewWorkspace(policyID, policyName, policyOwnerEmail = '', makeMeAdmin = false, transitionFromOldDot = false, shouldNavigateToAdminChat = true) { +function savePolicyDraftByNewWorkspace(policyID, policyName, policyOwnerEmail = '', makeMeAdmin = false) { Policy.createWorkspace(policyOwnerEmail, makeMeAdmin, policyName, policyID); } From 11b9490220cf3760cfc083b83a10544c9b5c8441 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Wed, 11 Oct 2023 13:14:20 +0200 Subject: [PATCH 3/5] updated by comments --- src/libs/actions/App.js | 15 +++++++++++++++ src/libs/actions/Policy.js | 8 ++++++++ .../workspace/withPolicyAndFullscreenLoading.js | 4 ++-- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 3f484528af07..71900b2ec6bc 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -336,6 +336,13 @@ function createWorkspaceAndNavigateToIt(policyOwnerEmail = '', makeMeAdmin = fal .then(endSignOnTransition); } +/** + * Create a new Draft workspace and navigate to it + * + * @param {String} [policyOwnerEmail] Optional, the email of the account to make the owner of the policy + * @param {String} [policyName] Optional, custom policy name we will use for created workspace + * @param {Boolean} [transitionFromOldDot] Optional, if the user is transitioning from old dot + */ function createWorkspaceWithPolicyDraftAndNavigateToIt(policyOwnerEmail = '', policyName = '', transitionFromOldDot = false) { const policyID = Policy.generatePolicyID(); Policy.createDraftInitialWorkspace(policyOwnerEmail, policyName, policyID); @@ -351,6 +358,14 @@ function createWorkspaceWithPolicyDraftAndNavigateToIt(policyOwnerEmail = '', po .then(endSignOnTransition); } +/** + * Create a new workspace and delete the draft + * + * @param {String} [policyID] the ID of the policy to use + * @param {String} [policyName] custom policy name we will use for created workspace + * @param {String} [policyOwnerEmail] Optional, the email of the account to make the owner of the policy + * @param {Boolean} [makeMeAdmin] Optional, leave the calling account as an admin on the policy + */ function savePolicyDraftByNewWorkspace(policyID, policyName, policyOwnerEmail = '', makeMeAdmin = false) { Policy.createWorkspace(policyOwnerEmail, makeMeAdmin, policyName, policyID); } diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 484b49403ad2..efb13f3ebdc9 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -909,6 +909,13 @@ function buildOptimisticCustomUnits() { }; } +/** + * Optimistically creates a Policy Draft for a new workspace + * + * @param {String} [policyOwnerEmail] Optional, the email of the account to make the owner of the policy + * @param {String} [policyName] Optional, custom policy name we will use for created workspace + * @param {String} [policyID] Optional, custom policy id we will use for created workspace + */ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', policyID = generatePolicyID()) { const workspaceName = policyName || generateDefaultWorkspaceName(policyOwnerEmail); const {customUnits} = buildOptimisticCustomUnits(); @@ -940,6 +947,7 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol }, }, ]; + Onyx.update(optimisticData); } diff --git a/src/pages/workspace/withPolicyAndFullscreenLoading.js b/src/pages/workspace/withPolicyAndFullscreenLoading.js index 72f8b51b1f60..8265169434a3 100644 --- a/src/pages/workspace/withPolicyAndFullscreenLoading.js +++ b/src/pages/workspace/withPolicyAndFullscreenLoading.js @@ -1,8 +1,8 @@ import PropTypes from 'prop-types'; import React from 'react'; import {withOnyx} from 'react-native-onyx'; -import isEmpty from 'underscore/modules/isEmpty'; -import omit from 'underscore/modules/omit'; +import isEmpty from 'lodash/isEmpty'; +import omit from 'lodash/omit'; import compose from '../../libs/compose'; import ONYXKEYS from '../../ONYXKEYS'; import withPolicy, {policyPropTypes, policyDefaultProps} from './withPolicy'; From 3228ac5615b93c5402c0abf3b500aee8d0ff389f Mon Sep 17 00:00:00 2001 From: Eduardo Date: Thu, 12 Oct 2023 08:54:08 +0200 Subject: [PATCH 4/5] Rephrase comment --- src/pages/workspace/WorkspaceInitialPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspaceInitialPage.js b/src/pages/workspace/WorkspaceInitialPage.js index 8b459e774d63..01efcff4a2c2 100644 --- a/src/pages/workspace/WorkspaceInitialPage.js +++ b/src/pages/workspace/WorkspaceInitialPage.js @@ -91,7 +91,7 @@ function WorkspaceInitialPage(props) { } App.savePolicyDraftByNewWorkspace(props.policyDraft.id, props.policyDraft.name, '', false, '', !isSmallScreenWidth); - // I only care when the component renders the first time + // We only care when the component renders the first time // eslint-disable-next-line react-hooks/exhaustive-deps }, []); From 8fdbc4e4428567316e8906b1b3d958a9ab80be05 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Fri, 13 Oct 2023 10:56:32 +0200 Subject: [PATCH 5/5] Fixed comments --- src/libs/actions/App.js | 2 +- src/libs/actions/Policy.js | 20 ++++++++++---------- src/pages/workspace/WorkspaceInitialPage.js | 4 +--- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 71900b2ec6bc..e6b1c029f14f 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -337,7 +337,7 @@ function createWorkspaceAndNavigateToIt(policyOwnerEmail = '', makeMeAdmin = fal } /** - * Create a new Draft workspace and navigate to it + * Create a new draft workspace and navigate to it * * @param {String} [policyOwnerEmail] Optional, the email of the account to make the owner of the policy * @param {String} [policyName] Optional, custom policy name we will use for created workspace diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index efb13f3ebdc9..53753e193fb1 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -999,16 +999,6 @@ function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName }, { optimisticData: [ - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`, - value: null, - }, - { - onyxMethod: Onyx.METHOD.SET, - key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`, - value: null, - }, { onyxMethod: Onyx.METHOD.SET, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, @@ -1079,6 +1069,16 @@ function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseChatReportID}`, value: expenseReportActionData, }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_DRAFTS}${policyID}`, + value: null, + }, + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS}${policyID}`, + value: null, + }, ], successData: [ { diff --git a/src/pages/workspace/WorkspaceInitialPage.js b/src/pages/workspace/WorkspaceInitialPage.js index 01efcff4a2c2..d275b7f0dd10 100644 --- a/src/pages/workspace/WorkspaceInitialPage.js +++ b/src/pages/workspace/WorkspaceInitialPage.js @@ -32,7 +32,6 @@ import * as ReimbursementAccountProps from '../ReimbursementAccount/reimbursemen import * as ReportUtils from '../../libs/ReportUtils'; import withWindowDimensions from '../../components/withWindowDimensions'; import PressableWithoutFeedback from '../../components/Pressable/PressableWithoutFeedback'; -import useWindowDimensions from '../../hooks/useWindowDimensions'; const propTypes = { ...policyPropTypes, @@ -70,7 +69,6 @@ function WorkspaceInitialPage(props) { const policy = props.policyDraft && props.policyDraft.id ? props.policyDraft : props.policy; const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [isCurrencyModalOpen, setIsCurrencyModalOpen] = useState(false); - const {isSmallScreenWidth} = useWindowDimensions(); const hasPolicyCreationError = Boolean(policy.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD && policy.errors); /** @@ -90,7 +88,7 @@ function WorkspaceInitialPage(props) { return; } - App.savePolicyDraftByNewWorkspace(props.policyDraft.id, props.policyDraft.name, '', false, '', !isSmallScreenWidth); + App.savePolicyDraftByNewWorkspace(props.policyDraft.id, props.policyDraft.name, '', false); // We only care when the component renders the first time // eslint-disable-next-line react-hooks/exhaustive-deps }, []);