Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add tasks for new user first workspace #55017

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 85 additions & 50 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 = {
ishpaul777 marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -5015,30 +5060,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 @@ -5048,24 +5072,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 @@ -5142,6 +5149,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 Expand Up @@ -5200,15 +5243,7 @@ const CONST = {
height: 960,
},
tasks: [
{
type: 'meetSetupSpecialist',
autoCompleted: false,
title: 'Meet your setup specialist',
description:
'*Meet your setup specialist* who can answer any questions as you get started with Expensify. Yes, a real human!' +
'\n' +
'Chat with them in your #admins room or schedule a call today.',
},
meetGuideTask,
{
type: 'reviewWorkspaceSettings',
autoCompleted: false,
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 @@ -2641,7 +2641,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 @@ -3818,6 +3818,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 @@ -3897,6 +3899,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 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 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 @@
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 @@
* @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 @@
expenseCreatedReportActionID,
customUnitID,
customUnitRateID,
engagementChoice,
};

if (!introSelected?.createWorkspace && engagementChoice) {
const {
guidedSetupData,
ishpaul777 marked this conversation as resolved.
Show resolved Hide resolved
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 @@
* @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 Expand Up @@ -2266,7 +2296,7 @@
*
* @returns policyID of the workspace we have created
*/
function createWorkspaceFromIOUPayment(iouReport: OnyxEntry<Report>): WorkspaceFromIOUCreationData | undefined {

Check failure on line 2299 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / ESLint check

Calling actions from inside other actions is forbidden. If an action needs to call another action combine the two actions into a singular API call instead

Check failure on line 2299 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Calling actions from inside other actions is forbidden. If an action needs to call another action combine the two actions into a singular API call instead
// This flow only works for IOU reports
if (!ReportUtils.isIOUReportUsingReport(iouReport)) {
return;
Expand Down
Loading
Loading