Skip to content

Commit

Permalink
add tasks for new user first workspace
Browse files Browse the repository at this point in the history
  • Loading branch information
ishpaul777 committed Jan 9, 2025
1 parent 5fb81d6 commit a72f482
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 91 deletions.
32 changes: 16 additions & 16 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ PODS:
- Airship/Core
- AirshipFrameworkProxy (7.1.2):
- Airship (= 18.7.2)
- AirshipServiceExtension (18.7.2)
- AppAuth (1.7.5):
- AppAuth/Core (= 1.7.5)
- AppAuth/ExternalUserAgent (= 1.7.5)
- AppAuth/Core (1.7.5)
- AppAuth/ExternalUserAgent (1.7.5):
- AirshipServiceExtension (18.14.1)
- AppAuth (1.7.6):
- AppAuth/Core (= 1.7.6)
- AppAuth/ExternalUserAgent (= 1.7.6)
- AppAuth/Core (1.7.6)
- AppAuth/ExternalUserAgent (1.7.6):
- AppAuth/Core
- AppLogs (0.1.0)
- boost (1.84.0)
Expand Down Expand Up @@ -311,7 +311,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- Plaid (5.6.0)
- Plaid (5.6.1)
- PromisesObjC (2.4.0)
- RCT-Folly (2024.01.01.00):
- boost
Expand Down Expand Up @@ -1775,7 +1775,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-keyboard-controller (1.15.2):
- react-native-keyboard-controller (1.15.0):
- DoubleConversion
- glog
- hermes-engine
Expand Down Expand Up @@ -2785,9 +2785,9 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- SDWebImage (5.19.4):
- SDWebImage/Core (= 5.19.4)
- SDWebImage/Core (5.19.4)
- SDWebImage (5.19.7):
- SDWebImage/Core (= 5.19.7)
- SDWebImage/Core (5.19.7)
- SDWebImageAVIFCoder (0.11.0):
- libavif/core (>= 0.11.0)
- SDWebImage (~> 5.10)
Expand Down Expand Up @@ -3221,8 +3221,8 @@ CHECKOUT OPTIONS:
SPEC CHECKSUMS:
Airship: bb32ff2c5a811352da074480357d9f02dbb8f327
AirshipFrameworkProxy: dbd862dc6fb21b13e8b196458d626123e2a43a50
AirshipServiceExtension: 9c73369f426396d9fb9ff222d86d842fac76ba46
AppAuth: 501c04eda8a8d11f179dbe8637b7a91bb7e5d2fa
AirshipServiceExtension: f6cd7d0bde857ed1e54e83289ebe4d6affc8497e
AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73
AppLogs: 3bc4e9b141dbf265b9464409caaa40416a9ee0e0
boost: d7090b1a93a9798c029277a8288114f2948f471c
DoubleConversion: f16ae600a246532c4020132d54af21d0ddb2a385
Expand Down Expand Up @@ -3267,7 +3267,7 @@ SPEC CHECKSUMS:
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
Onfido: f3af62ea1c9a419589c133e3e511e5d2c4f3f8af
onfido-react-native-sdk: 4ccfdeb10f9ccb4a5799d2555cdbc2a068a42c0d
Plaid: c32f22ffce5ec67c9e6147eaf6c4d7d5f8086d89
Plaid: 93c9e80b93f5cea960a1120047ef2b689394ff91
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
RCT-Folly: bf5c0376ffe4dd2cf438dcf86db385df9fdce648
RCTDeprecation: 2c5e1000b04ab70b53956aa498bf7442c3c6e497
Expand Down Expand Up @@ -3307,7 +3307,7 @@ SPEC CHECKSUMS:
react-native-geolocation: b9bd12beaf0ebca61a01514517ca8455bd26fa06
react-native-image-picker: ba5067f7d833b9081102c0a33dd0188eb21d92dc
react-native-key-command: aae312752fcdfaa2240be9a015fc41ce54087546
react-native-keyboard-controller: dbd7fb6a233505f937c9242d6d8bb5ebe659ec32
react-native-keyboard-controller: 3428e4761623fd6a242d9bf3573112f8ebe92238
react-native-launch-arguments: 5f41e0abf88a15e3c5309b8875d6fd5ac43df49d
react-native-netinfo: fb5112b1fa754975485884ae85a3fb6a684f49d5
react-native-pager-view: abc5ef92699233eb726442c7f452cac82f73d0cb
Expand Down Expand Up @@ -3368,7 +3368,7 @@ SPEC CHECKSUMS:
RNShare: bd4fe9b95d1ee89a200778cc0753ebe650154bb0
RNSound: 6c156f925295bdc83e8e422e7d8b38d33bc71852
RNSVG: b2fbe96b2bb3887752f8abc1f495953847e90384
SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3
SDWebImageAVIFCoder: 00310d246aab3232ce77f1d8f0076f8c4b021d90
SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
Expand Down
125 changes: 84 additions & 41 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ const selectableOnboardingChoices = {
const backendOnboardingChoices = {
ADMIN: 'newDotAdmin',
SUBMIT: 'newDotSubmit',
TRACK_WORKSPACE: 'newDotTrackWorkspace',
} as const;

const onboardingChoices = {
Expand All @@ -98,6 +99,50 @@ const selfGuidedTourTask: OnboardingTask = {
description: ({navatticURL}) => `[Take a self-guided product tour](${navatticURL}) and learn about everything Expensify has to offer.`,
};

const createWorkspaceTask: OnboardingTask = {
type: 'createWorkspace',
autoCompleted: true,
title: 'Create a workspace',
description:
'*Create a workspace* to track expenses, scan receipts, chat, and more.\n' +
'\n' +
'Here’s how to create a workspace:\n' +
'\n' +
'1. Click the settings tab.\n' +
'2. Click *Workspaces* > *New workspace*.\n' +
'\n' +
'*Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.*',
};

const meetGuideTask: OnboardingTask = {
type: 'meetGuide',
autoCompleted: false,
title: 'Meet your setup specialist',
description: ({adminsRoomLink}) =>
`Meet your setup specialist, who can answer any questions as you get started with Expensify. Yes, a real human!\n` +
'\n' +
`Chat with the specialist in your [#admins room](${adminsRoomLink}).`,
};

const setupCategoriesTask: OnboardingTask = {
type: 'setupCategories',
autoCompleted: false,
title: 'Set up categories',
description: ({workspaceCategoriesLink}) =>
'*Set up categories* so your team can code expenses for easy reporting.\n' +
'\n' +
'Here’s how to set up categories:\n' +
'\n' +
'1. Click the settings tab.\n' +
'2. Go to *Workspaces*.\n' +
'3. Select your workspace.\n' +
'4. Click *Categories*.\n' +
"5. Disable any categories you don't need.\n" +
'6. Add your own categories in the top right.\n' +
'\n' +
`[Take me to workspace category settings](${workspaceCategoriesLink}).`,
};

const onboardingEmployerOrSubmitMessage: OnboardingMessage = {
message: 'Getting paid back is as easy as sending a message. Let’s go over the basics.',
video: {
Expand Down Expand Up @@ -5014,30 +5059,9 @@ const CONST = {
height: 960,
},
tasks: [
{
type: 'createWorkspace',
autoCompleted: true,
title: 'Create a workspace',
description:
'*Create a workspace* to track expenses, scan receipts, chat, and more.\n' +
'\n' +
'Here’s how to create a workspace:\n' +
'\n' +
'1. Click the settings tab.\n' +
'2. Click *Workspaces* > *New workspace*.\n' +
'\n' +
'*Your new workspace is ready! It’ll keep all of your spend (and chats) in one place.*',
},
createWorkspaceTask,
selfGuidedTourTask,
{
type: 'meetGuide',
autoCompleted: false,
title: 'Meet your setup specialist',
description: ({adminsRoomLink}) =>
`Meet your setup specialist, who can answer any questions as you get started with Expensify. Yes, a real human!\n` +
'\n' +
`Chat with the specialist in your [#admins room](${adminsRoomLink}).`,
},
meetGuideTask,
{
type: 'setupCategoriesAndTags',
autoCompleted: false,
Expand All @@ -5047,24 +5071,7 @@ const CONST = {
'\n' +
`Import them automatically by [connecting your accounting software](${workspaceAccountingLink}), or set them up manually in your [workspace settings](${workspaceSettingsLink}).`,
},
{
type: 'setupCategories',
autoCompleted: false,
title: 'Set up categories',
description: ({workspaceCategoriesLink}) =>
'*Set up categories* so your team can code expenses for easy reporting.\n' +
'\n' +
'Here’s how to set up categories:\n' +
'\n' +
'1. Click the settings tab.\n' +
'2. Go to *Workspaces*.\n' +
'3. Select your workspace.\n' +
'4. Click *Categories*.\n' +
"5. Disable any categories you don't need.\n" +
'6. Add your own categories in the top right.\n' +
'\n' +
`[Take me to workspace category settings](${workspaceCategoriesLink}).`,
},
setupCategoriesTask,
{
type: 'setupTags',
autoCompleted: false,
Expand Down Expand Up @@ -5141,6 +5148,42 @@ const CONST = {
},
],
},
[onboardingChoices.TRACK_WORKSPACE]: {
message: 'Here are some important tasks to help get your workspace set up.',
video: {
url: `${CLOUDFRONT_URL}/videos/guided-setup-manage-team-v2.mp4`,
thumbnailUrl: `${CLOUDFRONT_URL}/images/guided-setup-manage-team.jpg`,
duration: 55,
width: 1280,
height: 960,
},
tasks: [
createWorkspaceTask,
meetGuideTask,
setupCategoriesTask,
{
type: 'inviteAccountant',
autoCompleted: false,
title: 'Invite your accountant',
description: ({workspaceMembersLink}) =>
'*Invite your accountant to Expensify and share your expenses with them to make tax time easier.\n' +
'\n' +
'Here’s how to invite your accountant:\n' +
'\n' +
'1. Click your profile picture.\n' +
'2. Go to *Workspaces*.\n' +
'3. Select your workspace.\n' +
'4. Click *Members* > Invite member.\n' +
'5. Enter their email or phone number.\n' +
'6. Add an invite message if you’d like.\n' +
'7. You’ll be set as the expense approver. You can change this to any admin once you invite your team.\n' +
'\n' +
'That’s it, happy expensing! 😄\n' +
'\n' +
`[View your workspace members](${workspaceMembersLink}).`,
},
],
},
[onboardingChoices.PERSONAL_SPEND]: onboardingPersonalSpendMessage,
[onboardingChoices.CHAT_SPLIT]: {
message: 'Splitting bills with friends is as easy as sending a message. Here’s how.',
Expand Down
1 change: 1 addition & 0 deletions src/libs/API/parameters/CreateWorkspaceParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type CreateWorkspaceParams = {
customUnitID: string;
customUnitRateID: string;
engagementChoice?: string;
guidedSetupData?: string;
};

export default CreateWorkspaceParams;
6 changes: 5 additions & 1 deletion src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2642,7 +2642,7 @@ function getTrackExpenseInformation(
let createdWorkspaceParams: CreateWorkspaceParams | undefined;

if (isDraftReport) {
const workspaceData = Policy.buildPolicyData(undefined, policy?.makeMeAdmin, policy?.name, policy?.id, chatReport?.reportID);
const workspaceData = Policy.buildPolicyData(undefined, policy?.makeMeAdmin, policy?.name, policy?.id, chatReport?.reportID, CONST.ONBOARDING_CHOICES.TRACK_WORKSPACE);
createdWorkspaceParams = workspaceData.params;
optimisticData.push(...workspaceData.optimisticData);
successData.push(...workspaceData.successData);
Expand Down Expand Up @@ -3821,6 +3821,8 @@ function categorizeTrackedExpense(trackedExpenseParams: CategorizeTrackedExpense
policyExpenseCreatedReportActionID: createdWorkspaceParams?.expenseCreatedReportActionID,
adminsChatReportID: createdWorkspaceParams?.adminsChatReportID,
adminsCreatedReportActionID: createdWorkspaceParams?.adminsCreatedReportActionID,
engagementChoice: createdWorkspaceParams?.engagementChoice,
guidedSetupData: createdWorkspaceParams?.guidedSetupData,
};

API.write(WRITE_COMMANDS.CATEGORIZE_TRACKED_EXPENSE, parameters, {optimisticData, successData, failureData});
Expand Down Expand Up @@ -3902,6 +3904,8 @@ function shareTrackedExpense(
policyExpenseCreatedReportActionID: createdWorkspaceParams?.expenseCreatedReportActionID,
adminsChatReportID: createdWorkspaceParams?.adminsChatReportID,
adminsCreatedReportActionID: createdWorkspaceParams?.adminsCreatedReportActionID,
engagementChoice: createdWorkspaceParams?.engagementChoice,
guidedSetupData: createdWorkspaceParams?.guidedSetupData,
};

API.write(WRITE_COMMANDS.SHARE_TRACKED_EXPENSE, parameters, {optimisticData, successData, failureData});
Expand Down
36 changes: 33 additions & 3 deletions src/libs/actions/Policy/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {NullishDeep, OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-nat
import Onyx from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import type {ReportExportType} from '@components/ButtonWithDropdownMenu/types';
import {prepareOnboardingOnyxData} from '@libs/actions/Report';
import * as API from '@libs/API';
import type {
AddBillingCardAndRequestWorkspaceOwnerChangeParams,
Expand Down Expand Up @@ -78,9 +79,11 @@ import * as TransactionUtils from '@libs/TransactionUtils';
import type {PolicySelector} from '@pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover';
import * as PaymentMethods from '@userActions/PaymentMethods';
import * as PersistedRequests from '@userActions/PersistedRequests';
import type {OnboardingPurpose} from '@src/CONST';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {
IntroSelected,
InvitedEmailsToAccountIDs,
PersonalDetailsList,
Policy,
Expand Down Expand Up @@ -1676,6 +1679,12 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol
Onyx.update(optimisticData);
}

let introSelected: OnyxEntry<IntroSelected>;
Onyx.connect({
key: ONYXKEYS.NVP_INTRO_SELECTED,
callback: (value) => (introSelected = value),
});

/**
* Generates onyx data for creating a new workspace
*
Expand All @@ -1685,7 +1694,7 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol
* @param [policyID] custom policy id we will use for created workspace
* @param [expenseReportId] the reportID of the expense report that is being used to create the workspace
*/
function buildPolicyData(policyOwnerEmail = '', makeMeAdmin = false, policyName = '', policyID = generatePolicyID(), expenseReportId?: string, engagementChoice?: string) {
function buildPolicyData(policyOwnerEmail = '', makeMeAdmin = false, policyName = '', policyID = generatePolicyID(), expenseReportId?: string, engagementChoice?: OnboardingPurpose) {
const workspaceName = policyName || generateDefaultWorkspaceName(policyOwnerEmail);

const {customUnits, customUnitID, customUnitRateID, outputCurrency} = buildOptimisticDistanceRateCustomUnits();
Expand Down Expand Up @@ -1947,9 +1956,24 @@ function buildPolicyData(policyOwnerEmail = '', makeMeAdmin = false, policyName
expenseCreatedReportActionID,
customUnitID,
customUnitRateID,
engagementChoice,
};

if (!introSelected?.createWorkspace && engagementChoice) {
const {
guidedSetupData,
optimisticData: taskOptimisticData,
successData: taskSuccessData,
failureData: taskFailureData,
} = prepareOnboardingOnyxData(engagementChoice, CONST.ONBOARDING_MESSAGES[engagementChoice], expenseChatReportID, policyID);

params.guidedSetupData = JSON.stringify(guidedSetupData);
params.engagementChoice = engagementChoice;

optimisticData.push(...taskOptimisticData);
successData.push(...taskSuccessData);
failureData.push(...taskFailureData);
}

return {successData, optimisticData, failureData, params};
}

Expand All @@ -1962,7 +1986,13 @@ function buildPolicyData(policyOwnerEmail = '', makeMeAdmin = false, policyName
* @param [policyID] custom policy id we will use for created workspace
* @param [engagementChoice] Purpose of using application selected by user in guided setup flow
*/
function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName = '', policyID = generatePolicyID(), engagementChoice = ''): CreateWorkspaceParams {
function createWorkspace(
policyOwnerEmail = '',
makeMeAdmin = false,
policyName = '',
policyID = generatePolicyID(),
engagementChoice = CONST.ONBOARDING_CHOICES.MANAGE_TEAM,
): CreateWorkspaceParams {
const {optimisticData, failureData, successData, params} = buildPolicyData(policyOwnerEmail, makeMeAdmin, policyName, policyID, undefined, engagementChoice);
API.write(WRITE_COMMANDS.CREATE_WORKSPACE, params, {optimisticData, successData, failureData});

Expand Down
Loading

0 comments on commit a72f482

Please sign in to comment.