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

feat: Provide education/confirmation before creating workspaces in New Workspace flows #53845

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7f40593
Provide education/confirmation before creating workspaces in New Work…
Krishna2323 Dec 10, 2024
ee98ccd
Provide education/confirmation before creating workspaces in New Work…
Krishna2323 Dec 10, 2024
3b47bb6
Merge branch 'Expensify:main' into krishna2323/issue/52164_pr2
Krishna2323 Dec 10, 2024
0125372
fix: Selected currecy does not appear selected with a green checkmark.
Krishna2323 Dec 11, 2024
50a5a5d
fix: Create workspace - Edit avatar modal is blocking the avatar.
Krishna2323 Dec 11, 2024
1863105
fix: Error message does not have left and right padding.
Krishna2323 Dec 11, 2024
3748621
add param names.
Krishna2323 Dec 11, 2024
59713aa
Merge branch 'Expensify:main' into krishna2323/issue/52164_pr2
Krishna2323 Dec 13, 2024
88960da
Merge branch 'Expensify:main' into krishna2323/issue/52164_pr2
Krishna2323 Dec 13, 2024
113f37b
Merge branch 'Expensify:main' into krishna2323/issue/52164_pr2
Krishna2323 Dec 19, 2024
1757ec8
crash fix.
Krishna2323 Dec 19, 2024
f08311b
Merge branch 'main' into krishna2323/issue/52164_pr2
Krishna2323 Dec 20, 2024
29dbf37
fix: file not cloned correctly.
Krishna2323 Dec 20, 2024
ec414be
fix eslint.
Krishna2323 Dec 20, 2024
60529a7
fix eslint.
Krishna2323 Dec 20, 2024
85bfaaf
minor fix.
Krishna2323 Dec 20, 2024
d9b1f64
Merge branch 'Expensify:main' into krishna2323/issue/52164_pr2
Krishna2323 Dec 23, 2024
4aba5aa
Merge branch 'Expensify:main' into krishna2323/issue/52164_pr2
Krishna2323 Dec 24, 2024
a7ccb88
fix file upload on native platforms.
Krishna2323 Dec 24, 2024
0e3cdef
Merge branch 'Expensify:main' into krishna2323/issue/52164_pr2
Krishna2323 Dec 26, 2024
21a213c
add backTo param in WORKSPACE_CONFIRMATION page.
Krishna2323 Dec 26, 2024
a322dc8
minor fix.
Krishna2323 Dec 26, 2024
4819755
add comments.
Krishna2323 Dec 26, 2024
8c78f70
minor update.
Krishna2323 Dec 27, 2024
4587fc4
Merge branch 'main' into krishna2323/issue/52164_pr2
Krishna2323 Dec 31, 2024
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
3 changes: 3 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,8 @@ const ONYXKEYS = {
ADD_PAYMENT_CARD_FORM_DRAFT: 'addPaymentCardFormDraft',
WORKSPACE_SETTINGS_FORM: 'workspaceSettingsForm',
WORKSPACE_CATEGORY_FORM: 'workspaceCategoryForm',
WORKSPACE_CONFIRMATION_FORM: 'workspaceConfirmationForm',
WORKSPACE_CONFIRMATION_FORM_DRAFT: 'workspaceConfirmationFormDraft',
WORKSPACE_CATEGORY_FORM_DRAFT: 'workspaceCategoryFormDraft',
WORKSPACE_CATEGORY_DESCRIPTION_HINT_FORM: 'workspaceCategoryDescriptionHintForm',
WORKSPACE_CATEGORY_DESCRIPTION_HINT_FORM_DRAFT: 'workspaceCategoryDescriptionHintFormDraft',
Expand Down Expand Up @@ -732,6 +734,7 @@ type OnyxFormValuesMapping = {
[ONYXKEYS.FORMS.ADD_PAYMENT_CARD_FORM]: FormTypes.AddPaymentCardForm;
[ONYXKEYS.FORMS.WORKSPACE_SETTINGS_FORM]: FormTypes.WorkspaceSettingsForm;
[ONYXKEYS.FORMS.WORKSPACE_CATEGORY_FORM]: FormTypes.WorkspaceCategoryForm;
[ONYXKEYS.FORMS.WORKSPACE_CONFIRMATION_FORM]: FormTypes.WorkspaceConfirmationForm;
[ONYXKEYS.FORMS.WORKSPACE_TAG_FORM]: FormTypes.WorkspaceTagForm;
[ONYXKEYS.FORMS.WORKSPACE_TAX_CUSTOM_NAME]: FormTypes.WorkspaceTaxCustomName;
[ONYXKEYS.FORMS.WORKSPACE_COMPANY_CARD_FEED_NAME]: FormTypes.WorkspaceCompanyCardFeedName;
Expand Down
4 changes: 4 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,10 @@ const ROUTES = {
},
WELCOME_VIDEO_ROOT: 'onboarding/welcome-video',
EXPLANATION_MODAL_ROOT: 'onboarding/explanation',
WORKSPACE_CONFIRMATION: {
route: 'workspace/confirmation',
getRoute: (backTo?: string) => getUrlWithBackToParam(`workspace/confirmation`, backTo),
},
MIGRATED_USER_WELCOME_MODAL: 'onboarding/migrated-user-welcome',

TRANSACTION_RECEIPT: {
Expand Down
3 changes: 3 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ const SCREENS = {
DETAILS: 'Details',
PROFILE: 'Profile',
REPORT_DETAILS: 'Report_Details',
WORKSPACE_CONFIRMATION: 'Workspace_Confirmation',
REPORT_SETTINGS: 'Report_Settings',
REPORT_DESCRIPTION: 'Report_Description',
PARTICIPANTS: 'Participants',
Expand Down Expand Up @@ -319,6 +320,8 @@ const SCREENS = {
EXPORT: 'Report_Details_Export',
},

WORKSPACE_CONFIRMATION: {ROOT: 'Workspace_Confirmation_Root'},

WORKSPACE: {
ACCOUNTING: {
ROOT: 'Policy_Accounting',
Expand Down
89 changes: 89 additions & 0 deletions src/components/CurrencyPicker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, {forwardRef, useState} from 'react';
import type {ForwardedRef} from 'react';
import {View} from 'react-native';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import CurrencySelectionListWithOnyx from './CurrencySelectionList';
import HeaderWithBackButton from './HeaderWithBackButton';
import MenuItemWithTopDescription from './MenuItemWithTopDescription';
import Modal from './Modal';
import ScreenWrapper from './ScreenWrapper';
import type {ValuePickerItem, ValuePickerProps} from './ValuePicker/types';

type CurrencyPickerProps = {
selectedCurrency?: string;
};
function CurrencyPicker({selectedCurrency, label = '', errorText = '', value, onInputChange, furtherDetails}: ValuePickerProps & CurrencyPickerProps, forwardedRef: ForwardedRef<View>) {
const StyleUtils = useStyleUtils();
const styles = useThemeStyles();
const [isPickerVisible, setIsPickerVisible] = useState(false);
const {translate} = useLocalize();

const showPickerModal = () => {
setIsPickerVisible(true);
};

const hidePickerModal = () => {
setIsPickerVisible(false);
};

const updateInput = (item: ValuePickerItem) => {
if (item.value !== selectedCurrency) {
onInputChange?.(item.value);
}
hidePickerModal();
};

const descStyle = !selectedCurrency || selectedCurrency.length === 0 ? StyleUtils.getFontSizeStyle(variables.fontSizeLabel) : null;

return (
<View>
<MenuItemWithTopDescription
ref={forwardedRef}
shouldShowRightIcon
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
title={value || ''}
descriptionTextStyle={descStyle}
description={label}
onPress={showPickerModal}
furtherDetails={furtherDetails}
brickRoadIndicator={errorText ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined}
errorText={errorText}
/>

<Modal
type={CONST.MODAL.MODAL_TYPE.RIGHT_DOCKED}
isVisible={isPickerVisible}
onClose={() => hidePickerModal}
onModalHide={hidePickerModal}
hideModalContentWhileAnimating
useNativeDriver
onBackdropPress={hidePickerModal}
>
<ScreenWrapper
style={styles.pb0}
includePaddingTop={false}
includeSafeAreaPaddingBottom={false}
testID={label}
>
<HeaderWithBackButton
title={label}
onBackButtonPress={hidePickerModal}
/>
<CurrencySelectionListWithOnyx
onSelect={(item) => updateInput({value: item.currencyCode})}
searchInputLabel={translate('common.currency')}
initiallySelectedCurrencyCode={selectedCurrency}
/>
</ScreenWrapper>
</Modal>
</View>
);
}

CurrencyPicker.displayName = 'CurrencyPicker';

export default forwardRef(CurrencyPicker);
3 changes: 2 additions & 1 deletion src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3777,7 +3777,7 @@ const translations = {
},
emptyWorkspace: {
title: 'Create a workspace',
subtitle: 'Create a workspace to track receipts, reimburse expenses, send invoices, and more -- all at the speed of chat.',
subtitle: 'Create a workspace to track receipts, reimburse expenses, send invoices, and more all at the speed of chat.',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
subtitle: 'Create a workspace to track receipts, reimburse expenses, send invoices, and more — all at the speed of chat.',
subtitle: 'Create a workspace to track receipts, reimburse expenses, manage travel, send invoices, and more — all at the speed of chat.',

Update the copy as per #53753 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this update can be made in this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, thanks

createAWorkspaceCTA: 'Get Started',
features: {
trackAndCollect: 'Track and collect receipts',
Expand All @@ -3795,6 +3795,7 @@ const translations = {
new: {
newWorkspace: 'New workspace',
getTheExpensifyCardAndMore: 'Get the Expensify Card and more',
confirmWorkspace: 'Confirm Workspace',
},
people: {
genericFailureMessage: 'An error occurred removing a member from the workspace, please try again.',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3839,6 +3839,7 @@ const translations = {
new: {
newWorkspace: 'Nuevo espacio de trabajo',
getTheExpensifyCardAndMore: 'Consigue la Tarjeta Expensify y más',
confirmWorkspace: 'Confirmar espacio de trabajo',
},
people: {
genericFailureMessage: 'Se ha producido un error al intentar eliminar a un miembro del espacio de trabajo. Por favor, inténtalo más tarde.',
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/parameters/CreateWorkspaceParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ type CreateWorkspaceParams = {
customUnitID: string;
customUnitRateID: string;
engagementChoice?: string;
currency: string;
file?: File;
};

export default CreateWorkspaceParams;
7 changes: 7 additions & 0 deletions src/libs/CurrencyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Onyx from 'react-native-onyx';
import CONST from '@src/CONST';
import type {OnyxValues} from '@src/ONYXKEYS';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Currency} from '@src/types/onyx';
import BaseLocaleListener from './Localize/LocaleListener/BaseLocaleListener';
import * as NumberFormatUtils from './NumberFormatUtils';

Expand Down Expand Up @@ -30,6 +31,11 @@ function getCurrencyDecimals(currency: string = CONST.CURRENCY.USD): number {
return decimals ?? 2;
}

function getCurrency(currency: string = CONST.CURRENCY.USD): Currency | null {
const currencyItem = currencyList?.[currency];
return currencyItem;
}

/**
* Returns the currency's minor unit quantity
* e.g. Cent in USD
Expand Down Expand Up @@ -216,5 +222,6 @@ export {
convertToDisplayStringWithoutCurrency,
isValidCurrencyCode,
convertToShortDisplayString,
getCurrency,
sanitizeCurrencyCode,
};
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import type {
TransactionDuplicateNavigatorParamList,
TravelNavigatorParamList,
WalletStatementNavigatorParamList,
WorkspaceConfirmationNavigatorParamList,
} from '@navigation/types';
import type {Screen} from '@src/SCREENS';
import SCREENS from '@src/SCREENS';
Expand Down Expand Up @@ -131,6 +132,10 @@ const ReportSettingsModalStackNavigator = createModalStackNavigator<ReportSettin
[SCREENS.REPORT_SETTINGS.VISIBILITY]: () => require<ReactComponentModule>('../../../../pages/settings/Report/VisibilityPage').default,
});

const WorkspaceConfirmationModalStackNavigator = createModalStackNavigator<WorkspaceConfirmationNavigatorParamList>({
[SCREENS.WORKSPACE_CONFIRMATION.ROOT]: () => require<ReactComponentModule>('../../../../pages/workspace/WorkspaceConfirmationPage').default,
});

const TaskModalStackNavigator = createModalStackNavigator<TaskDetailsNavigatorParamList>({
[SCREENS.TASK.TITLE]: () => require<ReactComponentModule>('../../../../pages/tasks/TaskTitlePage').default,
[SCREENS.TASK.ASSIGNEE]: () => require<ReactComponentModule>('../../../../pages/tasks/TaskAssigneeSelectorModal').default,
Expand Down Expand Up @@ -724,4 +729,5 @@ export {
SearchSavedSearchModalStackNavigator,
MissingPersonalDetailsModalStackNavigator,
DebugModalStackNavigator,
WorkspaceConfirmationModalStackNavigator,
};
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
name={SCREENS.RIGHT_MODAL.MONEY_REQUEST}
component={ModalStackNavigators.MoneyRequestModalStackNavigator}
/>
<Stack.Screen
name={SCREENS.RIGHT_MODAL.WORKSPACE_CONFIRMATION}
component={ModalStackNavigators.WorkspaceConfirmationModalStackNavigator}
/>
<Stack.Screen
name={SCREENS.RIGHT_MODAL.NEW_TASK}
component={ModalStackNavigators.NewTaskModalStackNavigator}
Expand Down
5 changes: 5 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1176,6 +1176,11 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
},
},
},
[SCREENS.RIGHT_MODAL.WORKSPACE_CONFIRMATION]: {
screens: {
[SCREENS.WORKSPACE_CONFIRMATION.ROOT]: ROUTES.WORKSPACE_CONFIRMATION.route,
},
},
[SCREENS.RIGHT_MODAL.NEW_TASK]: {
screens: {
[SCREENS.NEW_TASK.ROOT]: ROUTES.NEW_TASK.route,
Expand Down
8 changes: 8 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,12 @@ type MoneyRequestNavigatorParamList = {
};
};

type WorkspaceConfirmationNavigatorParamList = {
[SCREENS.WORKSPACE_CONFIRMATION.ROOT]: {
backTo?: Routes;
};
};

type NewTaskNavigatorParamList = {
[SCREENS.NEW_TASK.ROOT]: {
backTo?: Routes;
Expand Down Expand Up @@ -1409,6 +1415,7 @@ type RightModalNavigatorParamList = {
[SCREENS.RIGHT_MODAL.PARTICIPANTS]: NavigatorScreenParams<ParticipantsNavigatorParamList>;
[SCREENS.RIGHT_MODAL.ROOM_MEMBERS]: NavigatorScreenParams<RoomMembersNavigatorParamList>;
[SCREENS.RIGHT_MODAL.MONEY_REQUEST]: NavigatorScreenParams<MoneyRequestNavigatorParamList>;
[SCREENS.RIGHT_MODAL.WORKSPACE_CONFIRMATION]: NavigatorScreenParams<WorkspaceConfirmationNavigatorParamList>;
[SCREENS.RIGHT_MODAL.NEW_TASK]: NavigatorScreenParams<NewTaskNavigatorParamList>;
[SCREENS.RIGHT_MODAL.TEACHERS_UNITE]: NavigatorScreenParams<TeachersUniteNavigatorParamList>;
[SCREENS.RIGHT_MODAL.TASK_DETAILS]: NavigatorScreenParams<TaskDetailsNavigatorParamList>;
Expand Down Expand Up @@ -1816,4 +1823,5 @@ export type {
MissingPersonalDetailsParamList,
DebugParamList,
MigratedUserModalNavigatorParamList,
WorkspaceConfirmationNavigatorParamList,
};
7 changes: 5 additions & 2 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7402,8 +7402,11 @@ function getWorkspaceChats(policyID: string, accountIDs: number[], reports: Onyx
*
* @param policyID - the workspace ID to get all associated reports
*/
function getAllWorkspaceReports(policyID: string): Array<OnyxEntry<Report>> {
return Object.values(allReports ?? {}).filter((report) => (report?.policyID ?? '-1') === policyID);
function getAllWorkspaceReports(policyID?: string): Array<OnyxEntry<Report>> {
if (!policyID) {
return [];
}
return Object.values(allReports ?? {}).filter((report) => report?.policyID && report?.policyID === policyID);
}

/**
Expand Down
28 changes: 21 additions & 7 deletions src/libs/actions/App.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,19 +376,31 @@ function endSignOnTransition() {
* @param [transitionFromOldDot] Optional, if the user is transitioning from old dot
* @param [makeMeAdmin] Optional, leave the calling account as an admin on the policy
* @param [backTo] An optional return path. If provided, it will be URL-encoded and appended to the resulting URL.
* @param [policyID] Optional, Policy id.
* @param [currency] Optional, selected currency for the workspace
* @param [file], avatar file for workspace
*/
function createWorkspaceWithPolicyDraftAndNavigateToIt(policyOwnerEmail = '', policyName = '', transitionFromOldDot = false, makeMeAdmin = false, backTo = '') {
const policyID = Policy.generatePolicyID();
Policy.createDraftInitialWorkspace(policyOwnerEmail, policyName, policyID, makeMeAdmin);
function createWorkspaceWithPolicyDraftAndNavigateToIt(
policyOwnerEmail = '',
policyName = '',
transitionFromOldDot = false,
makeMeAdmin = false,
backTo = '',
policyID = '',
currency?: string,
file?: File,
) {
const policyIDWithDefault = policyID || Policy.generatePolicyID();
Policy.createDraftInitialWorkspace(policyOwnerEmail, policyName, policyIDWithDefault, makeMeAdmin, currency, file);

Navigation.isNavigationReady()
.then(() => {
if (transitionFromOldDot) {
// We must call goBack() to remove the /transition route from history
Navigation.goBack();
}
savePolicyDraftByNewWorkspace(policyID, policyName, policyOwnerEmail, makeMeAdmin);
Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID, backTo));
savePolicyDraftByNewWorkspace(policyIDWithDefault, policyName, policyOwnerEmail, makeMeAdmin, currency, file);
Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyIDWithDefault, backTo));
})
.then(endSignOnTransition);
}
Expand All @@ -400,9 +412,11 @@ function createWorkspaceWithPolicyDraftAndNavigateToIt(policyOwnerEmail = '', po
* @param [policyName] custom policy name we will use for created workspace
* @param [policyOwnerEmail] Optional, the email of the account to make the owner of the policy
* @param [makeMeAdmin] Optional, leave the calling account as an admin on the policy
* @param [currency] Optional, selected currency for the workspace
* @param [file] Optional, avatar file for workspace
*/
function savePolicyDraftByNewWorkspace(policyID?: string, policyName?: string, policyOwnerEmail = '', makeMeAdmin = false) {
Policy.createWorkspace(policyOwnerEmail, makeMeAdmin, policyName, policyID);
function savePolicyDraftByNewWorkspace(policyID?: string, policyName?: string, policyOwnerEmail = '', makeMeAdmin = false, currency = '', file?: File) {
Policy.createWorkspace(policyOwnerEmail, makeMeAdmin, policyName, policyID, '', currency, file);
}

/**
Expand Down
Loading
Loading