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..e6b1c029f14f 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -336,6 +336,40 @@ 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); + + 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); +} + +/** + * 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); +} + /** * This action runs when the Navigator is ready and the current route changes * @@ -513,4 +547,6 @@ export { createWorkspaceAndNavigateToIt, getMissingOnyxUpdates, finalReconnectAppAfterActivatingReliableUpdates, + savePolicyDraftByNewWorkspace, + createWorkspaceWithPolicyDraftAndNavigateToIt, }; diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 1a73b148e100..53753e193fb1 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -909,6 +909,48 @@ 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(); + + 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 * @@ -1027,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: [ { @@ -1131,6 +1183,7 @@ function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName ], }, ); + return adminsChatReportID; } @@ -1259,4 +1312,5 @@ export { clearErrors, openDraftWorkspaceRequest, buildOptimisticPolicyRecentlyUsedCategories, + createDraftInitialWorkspace, }; diff --git a/src/pages/workspace/WorkspaceInitialPage.js b/src/pages/workspace/WorkspaceInitialPage.js index 567aef1274e1..d275b7f0dd10 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'; @@ -65,7 +66,7 @@ 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 hasPolicyCreationError = Boolean(policy.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD && policy.errors); @@ -81,6 +82,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); + // We 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 +201,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..8265169434a3 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 'lodash/isEmpty'; +import omit from 'lodash/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 (