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

[No QA] 1-6 Card Flow UI #44741

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
4216e95
feat: add selection list to assignee step
koko57 Jun 26, 2024
93de31b
feat: UI for card name step
koko57 Jun 26, 2024
c27e5ef
feat: UI for limit step
koko57 Jun 26, 2024
c3ea4e3
feat: limit type step UI
koko57 Jun 26, 2024
a38ad57
feat: card type step UI
koko57 Jun 26, 2024
a6ef082
feat: confirmation step UI, card type step improvements
koko57 Jun 27, 2024
966e1e9
feat: apply the proper routing for expensify card pages
koko57 Jun 27, 2024
0f6898c
Merge branch 'main' into feature/44309-issue-new-card-flow-steps
koko57 Jul 1, 2024
899a78a
feat: [wip] assignee list
koko57 Jul 1, 2024
169a0d3
feat: implement search
koko57 Jul 1, 2024
98dc915
fix: resolve conflicts
koko57 Jul 2, 2024
ece0ee0
fix: remove duplicates
koko57 Jul 2, 2024
7d74daa
feat: connect all the steps
koko57 Jul 2, 2024
f97a457
feat: flow improvements
koko57 Jul 2, 2024
992d2fb
fix: resolve conflicts
koko57 Jul 3, 2024
79f6d02
fix: minor improvements
koko57 Jul 3, 2024
7e621e1
fix: show saved name and limit as default values when editing
koko57 Jul 3, 2024
6623cc7
fix: minor fix
koko57 Jul 3, 2024
de38131
fix: wrap confirmation step items in scrollview
koko57 Jul 3, 2024
1b5302e
fix: add autofocus, fix confirmation step button styles
koko57 Jul 3, 2024
804ed05
fix: remove unnecessary line
koko57 Jul 3, 2024
0946e49
fix: fix styles for limit step form
koko57 Jul 4, 2024
bbbb91e
fix: enable going to the next step when offline
koko57 Jul 4, 2024
e0094ab
fix: resolve conflicts
koko57 Jul 4, 2024
6f12b11
fix: change icon
koko57 Jul 4, 2024
f60d52e
fix: remove permission
koko57 Jul 4, 2024
aa72999
fix: filter deleted employees, apply requested changes
koko57 Jul 4, 2024
b303307
fix: autofocus, code improvements
koko57 Jul 4, 2024
8e95e15
refactor: move isDeletedPolicyEmployee to PolicyUtils
koko57 Jul 4, 2024
768641f
fix: resolve conflicts
koko57 Jul 4, 2024
b58b364
feat: code improvements
koko57 Jul 4, 2024
8d81d1d
feat: add validation to limit step
koko57 Jul 4, 2024
1023fd6
fix: lint
koko57 Jul 4, 2024
255d899
Merge branch 'main' into feature/44309-issue-new-card-flow-steps
koko57 Jul 7, 2024
947e3c0
Merge branch 'main' into feature/44309-issue-new-card-flow-steps
koko57 Jul 8, 2024
bb7b3dc
feat: implement editing flow
koko57 Jul 8, 2024
4e3d445
fix: apply requested changes
koko57 Jul 8, 2024
5fe7e81
fix: minor fix
koko57 Jul 8, 2024
8624227
fix: minor fix
koko57 Jul 8, 2024
2c3a8c1
fix: minor fix
koko57 Jul 8, 2024
c514207
fix: resolve conflicts
koko57 Jul 9, 2024
b689e39
fix: add a whitespace
koko57 Jul 9, 2024
12b2fa7
fix: remove unnecessary line
koko57 Jul 9, 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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2130,6 +2130,10 @@ const CONST = {
CARD_NAME: 'CardName',
CONFIRMATION: 'Confirmation',
},
CARD_TYPE: {
PHYSICAL: 'physical',
VIRTUAL: 'virtual',
},
},
AVATAR_ROW_SIZE: {
DEFAULT: 4,
Expand Down
4 changes: 2 additions & 2 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -556,8 +556,8 @@ const ONYXKEYS = {
NEW_CHAT_NAME_FORM_DRAFT: 'newChatNameFormDraft',
SUBSCRIPTION_SIZE_FORM: 'subscriptionSizeForm',
SUBSCRIPTION_SIZE_FORM_DRAFT: 'subscriptionSizeFormDraft',
ISSUE_NEW_EXPENSIFY_CARD_FORM: 'issueNewExpensifyCardForm',
ISSUE_NEW_EXPENSIFY_CARD_FORM_DRAFT: 'issueNewExpensifyCardFormDraft',
ISSUE_NEW_EXPENSIFY_CARD_FORM: 'issueNewExpensifyCard',
ISSUE_NEW_EXPENSIFY_CARD_FORM_DRAFT: 'issueNewExpensifyCardDraft',
Copy link
Contributor

Choose a reason for hiding this comment

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

NAB: ISSUE_NEW_EXPENSIFY_CARD_FORM_DRAFT isn't used in anywhere

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's how it's implemented for the other forms - TS would complain if I removed it 😅

SAGE_INTACCT_CREDENTIALS_FORM: 'sageIntacctCredentialsForm',
SAGE_INTACCT_CREDENTIALS_FORM_DRAFT: 'sageIntacctCredentialsFormDraft',
NETSUITE_TOKEN_INPUT_FORM: 'netsuiteTokenInputForm',
Expand Down
11 changes: 4 additions & 7 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -815,13 +815,10 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/expensify-card',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/expensify-card` as const,
},
// TODO: uncomment after development is done
// WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW: {
// route: 'settings/workspaces/:policyID/expensify-card/issues-new',
// getRoute: (policyID: string) => `settings/workspaces/${policyID}/expensify-card/issue-new` as const,
// },
// TODO: remove after development is done - this one is for testing purposes
WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW: 'settings/workspaces/expensify-card/issue-new',
WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW: {
route: 'settings/workspaces/:policyID/expensify-card/issue-new',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/expensify-card/issue-new` as const,
},
WORKSPACE_DISTANCE_RATES: {
route: 'settings/workspaces/:policyID/distance-rates',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/distance-rates` as const,
Expand Down
2 changes: 2 additions & 0 deletions src/components/Icon/Illustrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ import ThumbsUpStars from '@assets/images/simple-illustrations/simple-illustrati
import TrackShoe from '@assets/images/simple-illustrations/simple-illustration__track-shoe.svg';
import TrashCan from '@assets/images/simple-illustrations/simple-illustration__trashcan.svg';
import TreasureChest from '@assets/images/simple-illustrations/simple-illustration__treasurechest.svg';
import VirtualCard from '@assets/images/simple-illustrations/simple-illustration__virtualcard.svg';
import WalletAlt from '@assets/images/simple-illustrations/simple-illustration__wallet-alt.svg';
import Workflows from '@assets/images/simple-illustrations/simple-illustration__workflows.svg';
import ExpensifyApprovedLogoLight from '@assets/images/subscription-details__approvedlogo--light.svg';
Expand Down Expand Up @@ -196,4 +197,5 @@ export {
CheckmarkCircle,
CreditCardEyes,
LockClosedOrange,
VirtualCard,
};
4 changes: 2 additions & 2 deletions src/libs/CurrencyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ function convertToFrontendAmountAsInteger(amountAsInt: number, currency: string
*
* @note we do not support any currencies with more than two decimal places.
*/
function convertToFrontendAmountAsString(amountAsInt: number | null | undefined, currency: string = CONST.CURRENCY.USD): string {
function convertToFrontendAmountAsString(amountAsInt: number | null | undefined, currency: string = CONST.CURRENCY.USD, withDecimals = true): string {
if (amountAsInt === null || amountAsInt === undefined) {
return '';
}
const decimals = getCurrencyDecimals(currency);
const decimals = withDecimals ? getCurrencyDecimals(currency) : 0;
return convertToFrontendAmountAsInteger(amountAsInt, currency).toFixed(decimals);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial<Record<FullScreenName, string[]>> = {
SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS,
SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE,
],
[SCREENS.WORKSPACE.EXPENSIFY_CARD]: [],
[SCREENS.WORKSPACE.EXPENSIFY_CARD]: [SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW],
};

export default FULL_SCREEN_TO_RHP_MAPPING;
2 changes: 1 addition & 1 deletion src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
path: ROUTES.WORKSPACE_PROFILE_SHARE.route,
},
[SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW]: {
path: ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW,
path: ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW.route,
},
[SCREENS.WORKSPACE.RATE_AND_UNIT]: {
path: ROUTES.WORKSPACE_RATE_AND_UNIT.route,
Expand Down
7 changes: 6 additions & 1 deletion src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,9 @@ type SettingsNavigatorParamList = {
policyID: string;
taxID: string;
};
[SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW]: {
policyID: string;
};
} & ReimbursementAccountNavigatorParamList;

type NewChatNavigatorParamList = {
Expand Down Expand Up @@ -993,7 +996,6 @@ type FullScreenNavigatorParamList = {
[SCREENS.WORKSPACE.DISTANCE_RATES]: {
policyID: string;
};

[SCREENS.WORKSPACE.ACCOUNTING.ROOT]: {
policyID: string;
};
Expand All @@ -1006,6 +1008,9 @@ type FullScreenNavigatorParamList = {
[SCREENS.WORKSPACE.ACCOUNTING.QUICKBOOKS_ONLINE_INVOICE_ACCOUNT_SELECTOR]: {
policyID: string;
};
[SCREENS.WORKSPACE.EXPENSIFY_CARD]: {
policyID: string;
};
};

type OnboardingModalNavigatorParamList = {
Expand Down
9 changes: 9 additions & 0 deletions src/libs/OptionsListUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ type FilterOptionsConfig = Pick<
'sortByReportTypeInSearch' | 'canInviteUser' | 'betas' | 'selectedOptions' | 'excludeUnknownUsers' | 'excludeLogins' | 'maxRecentReportsToShow'
> & {preferChatroomsOverThreads?: boolean};

type HasText = {
text?: string;
};

/**
* OptionsListUtils is used to build a list options passed to the OptionsList component. Several different UI views can
* be configured to display different results based on the options passed to the private getOptions() method. Public
Expand Down Expand Up @@ -2559,6 +2563,10 @@ function filterOptions(options: Options, searchInputValue: string, config?: Filt
};
}

function sortItemsAlphabetically<T extends HasText>(membersList: T[]): T[] {
return membersList.sort((a, b) => (a.text ?? '').toLowerCase().localeCompare((b.text ?? '').toLowerCase()));
}

export {
getAvatarsForAccountIDs,
isCurrentUser,
Expand All @@ -2584,6 +2592,7 @@ export {
getEnabledCategoriesCount,
hasEnabledOptions,
sortCategories,
sortItemsAlphabetically,
sortTags,
getCategoryOptionTree,
hasEnabledTags,
Expand Down
9 changes: 9 additions & 0 deletions src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ function getTagListName(policyTagList: OnyxEntry<PolicyTagList>, orderWeight: nu

return Object.values(policyTagList).find((tag) => tag.orderWeight === orderWeight)?.name ?? '';
}

/**
* Gets all tag lists of a policy
*/
Expand Down Expand Up @@ -657,6 +658,13 @@ function getCurrentConnectionName(policy: Policy | undefined): string | undefine
return connectionKey ? CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connectionKey] : undefined;
}

/**
* Check if the policy member is deleted from the workspace
*/
function isDeletedPolicyEmployee(policyEmployee: PolicyEmployee, isOffline: boolean) {
return !isOffline && policyEmployee.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && isEmptyObject(policyEmployee.errors);
}

export {
canEditTaxRate,
extractPolicyIDFromPath,
Expand Down Expand Up @@ -690,6 +698,7 @@ export {
hasPolicyErrorFields,
hasTaxRateError,
isExpensifyTeam,
isDeletedPolicyEmployee,
isFreeGroupPolicy,
isInstantSubmitEnabled,
isPaidGroupPolicy,
Expand Down
34 changes: 30 additions & 4 deletions src/libs/actions/Card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@ import type {ActivatePhysicalExpensifyCardParams, ReportVirtualExpensifyCardFrau
import {SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {ExpensifyCardDetails, IssueNewCardStep} from '@src/types/onyx/Card';
import type {ExpensifyCardDetails, IssueNewCardData, IssueNewCardStep} from '@src/types/onyx/Card';

type ReplacementReason = 'damaged' | 'stolen';

type IssueNewCardFlowData = {
/** Step to be set in Onyx */
step?: IssueNewCardStep;

/** Whether the user is editing step */
isEditing?: boolean;

/** Data required to be sent to issue a new card */
data?: Partial<IssueNewCardData>;
};

function reportVirtualExpensifyCardFraud(cardID: number) {
const optimisticData: OnyxUpdate[] = [
{
Expand Down Expand Up @@ -185,9 +196,24 @@ function revealVirtualCardDetails(cardID: number): Promise<ExpensifyCardDetails>
});
}

function setIssueNewCardStep(step: IssueNewCardStep | null) {
Onyx.merge(ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD, {currentStep: step});
function setIssueNewCardStepAndData({data, isEditing, step}: IssueNewCardFlowData) {
Onyx.merge(ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD, {data, isEditing, currentStep: step});
}

function clearIssueNewCardFlow() {
Onyx.set(ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD, {
currentStep: null,
data: {},
});
}

export {requestReplacementExpensifyCard, activatePhysicalExpensifyCard, clearCardListErrors, reportVirtualExpensifyCardFraud, revealVirtualCardDetails, setIssueNewCardStep};
export {
requestReplacementExpensifyCard,
activatePhysicalExpensifyCard,
clearCardListErrors,
reportVirtualExpensifyCardFraud,
revealVirtualCardDetails,
setIssueNewCardStepAndData,
clearIssueNewCardFlow,
};
export type {ReplacementReason};
16 changes: 4 additions & 12 deletions src/pages/workspace/WorkspaceMembersPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {InvitedEmailsToAccountIDs, PersonalDetailsList, PolicyEmployee, PolicyEmployeeList, Session} from '@src/types/onyx';
import type {InvitedEmailsToAccountIDs, PersonalDetailsList, PolicyEmployeeList, Session} from '@src/types/onyx';
import type {Errors, PendingAction} from '@src/types/onyx/OnyxCommon';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type {WithPolicyAndFullscreenLoadingProps} from './withPolicyAndFullscreenLoading';
Expand Down Expand Up @@ -304,14 +304,6 @@ function WorkspaceMembersPage({personalDetails, invitedEmailsToAccountIDsDraft,
[route.params.policyID],
);

/**
* Check if the policy member is deleted from the workspace
*/
const isDeletedPolicyEmployee = useCallback(
(policyEmployee: PolicyEmployee): boolean => !isOffline && policyEmployee.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && isEmptyObject(policyEmployee.errors),
[isOffline],
);

const policyOwner = policy?.owner;
const currentUserLogin = currentUserPersonalDetails.login;
const invitedPrimaryToSecondaryLogins = invertObject(policy?.primaryLoginsInvited ?? {});
Expand All @@ -320,7 +312,7 @@ function WorkspaceMembersPage({personalDetails, invitedEmailsToAccountIDsDraft,

Object.entries(policy?.employeeList ?? {}).forEach(([email, policyEmployee]) => {
const accountID = Number(policyMemberEmailsToAccountIDs[email] ?? '');
if (isDeletedPolicyEmployee(policyEmployee)) {
if (PolicyUtils.isDeletedPolicyEmployee(policyEmployee, isOffline)) {
return;
}

Expand Down Expand Up @@ -375,13 +367,13 @@ function WorkspaceMembersPage({personalDetails, invitedEmailsToAccountIDsDraft,
invitedSecondaryLogin: details?.login ? invitedPrimaryToSecondaryLogins[details.login] ?? '' : '',
});
});
result = result.sort((a, b) => (a.text ?? '').toLowerCase().localeCompare((b.text ?? '').toLowerCase()));
result = OptionsListUtils.sortItemsAlphabetically(result);
return result;
}, [
isOffline,
currentUserLogin,
formatPhoneNumber,
invitedPrimaryToSecondaryLogins,
isDeletedPolicyEmployee,
isPolicyAdmin,
personalDetails,
policy?.owner,
Expand Down
Loading
Loading