Skip to content

Commit

Permalink
Merge pull request #47092 from waterim/feat-469590-OpenPolicyEditCard…
Browse files Browse the repository at this point in the history
…LimitTypePage

Feature: Integrate OpenPolicyEditCardLimitTypePage api command to the app
  • Loading branch information
MariaHCD authored Aug 14, 2024
2 parents 612483a + 8819dd3 commit 6c4502a
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 39 deletions.
4 changes: 2 additions & 2 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -460,8 +460,8 @@ const ONYXKEYS = {
SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END: 'sharedNVP_private_billingGracePeriodEnd_',

/**
* Stores the card list for a given fundID and feed in the format: card_<fundID>_<bankName>
* So for example: card_12345_Expensify Card
* Stores the card list for a given fundID and feed in the format: cards_<fundID>_<bankName>
* So for example: cards_12345_Expensify Card
*/
WORKSPACE_CARDS_LIST: 'cards_',

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
type OpenPolicyEditCardLimitTypePageParams = {
policyID: string;
authToken: string | null | undefined;
cardID: number;
};

export default OpenPolicyEditCardLimitTypePageParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ export type {default as EnablePolicyInvoicingParams} from './EnablePolicyInvoici
export type {default as CreateWorkspaceReportFieldListValueParams} from './CreateWorkspaceReportFieldListValueParams';
export type {default as RemoveWorkspaceReportFieldListValueParams} from './RemoveWorkspaceReportFieldListValueParams';
export type {default as OpenPolicyExpensifyCardsPageParams} from './OpenPolicyExpensifyCardsPageParams';
export type {default as OpenPolicyEditCardLimitTypePageParams} from './OpenPolicyEditCardLimitTypePageParams';
export type {default as RequestExpensifyCardLimitIncreaseParams} from './RequestExpensifyCardLimitIncreaseParams';
export type {default as UpdateNetSuiteGenericTypeParams} from './UpdateNetSuiteGenericTypeParams';
export type {default as CancelBillingSubscriptionParams} from './CancelBillingSubscriptionParams';
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ const READ_COMMANDS = {
OPEN_POLICY_TAXES_PAGE: 'OpenPolicyTaxesPage',
OPEN_POLICY_REPORT_FIELDS_PAGE: 'OpenPolicyReportFieldsPage',
OPEN_POLICY_EXPENSIFY_CARDS_PAGE: 'OpenPolicyExpensifyCardsPage',
OPEN_POLICY_EDIT_CARD_LIMIT_TYPE_PAGE: 'OpenPolicyEditCardLimitTypePage',
OPEN_WORKSPACE_INVITE_PAGE: 'OpenWorkspaceInvitePage',
OPEN_DRAFT_WORKSPACE_REQUEST: 'OpenDraftWorkspaceRequest',
OPEN_POLICY_WORKFLOWS_PAGE: 'OpenPolicyWorkflowsPage',
Expand Down Expand Up @@ -773,6 +774,7 @@ type ReadCommandParameters = {
[READ_COMMANDS.OPEN_POLICY_MORE_FEATURES_PAGE]: Parameters.OpenPolicyMoreFeaturesPageParams;
[READ_COMMANDS.OPEN_POLICY_ACCOUNTING_PAGE]: Parameters.OpenPolicyAccountingPageParams;
[READ_COMMANDS.OPEN_POLICY_EXPENSIFY_CARDS_PAGE]: Parameters.OpenPolicyExpensifyCardsPageParams;
[READ_COMMANDS.OPEN_POLICY_EDIT_CARD_LIMIT_TYPE_PAGE]: Parameters.OpenPolicyEditCardLimitTypePageParams;
[READ_COMMANDS.OPEN_POLICY_PROFILE_PAGE]: Parameters.OpenPolicyProfilePageParams;
[READ_COMMANDS.OPEN_POLICY_INITIAL_PAGE]: Parameters.OpenPolicyInitialPageParams;
[READ_COMMANDS.SEARCH]: Parameters.SearchParams;
Expand Down
14 changes: 14 additions & 0 deletions src/libs/actions/Policy/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type {
EnablePolicyWorkflowsParams,
LeavePolicyParams,
OpenDraftWorkspaceRequestParams,
OpenPolicyEditCardLimitTypePageParams,
OpenPolicyExpensifyCardsPageParams,
OpenPolicyInitialPageParams,
OpenPolicyMoreFeaturesPageParams,
Expand Down Expand Up @@ -2076,6 +2077,18 @@ function openPolicyExpensifyCardsPage(policyID: string, workspaceAccountID: numb
API.read(READ_COMMANDS.OPEN_POLICY_EXPENSIFY_CARDS_PAGE, params, {optimisticData, successData, failureData});
}

function openPolicyEditCardLimitTypePage(policyID: string, cardID: number) {
const authToken = NetworkStore.getAuthToken();

const params: OpenPolicyEditCardLimitTypePageParams = {
policyID,
authToken,
cardID,
};

API.read(READ_COMMANDS.OPEN_POLICY_EDIT_CARD_LIMIT_TYPE_PAGE, params);
}

function openWorkspaceInvitePage(policyID: string, clientMemberEmails: string[]) {
if (!policyID || !clientMemberEmails) {
Log.warn('openWorkspaceInvitePage invalid params', {policyID, clientMemberEmails});
Expand Down Expand Up @@ -3346,6 +3359,7 @@ export {
createPolicyExpenseChats,
upgradeToCorporate,
openPolicyExpensifyCardsPage,
openPolicyEditCardLimitTypePage,
requestExpensifyCardLimitIncrease,
getAdminPoliciesConnectedToNetSuite,
getAdminPoliciesConnectedToSageIntacct,
Expand Down
110 changes: 73 additions & 37 deletions src/pages/workspace/expensifyCard/WorkspaceEditCardLimitTypePage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {useFocusEffect} from '@react-navigation/native';
import type {StackScreenProps} from '@react-navigation/stack';
import React, {useMemo, useState} from 'react';
import React, {useCallback, useMemo, useState} from 'react';
import {useOnyx} from 'react-native-onyx';
import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView';
import Button from '@components/Button';
import ConfirmModal from '@components/ConfirmModal';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
Expand All @@ -15,6 +17,7 @@ import * as PolicyUtils from '@libs/PolicyUtils';
import Navigation from '@navigation/Navigation';
import type {SettingsNavigatorParamList} from '@navigation/types';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import * as Policy from '@userActions/Policy/Policy';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
Expand All @@ -38,20 +41,43 @@ function WorkspaceEditCardLimitTypePage({route}: WorkspaceEditCardLimitTypePageP
const defaultLimitType = areApprovalsConfigured ? CONST.EXPENSIFY_CARD.LIMIT_TYPES.SMART : CONST.EXPENSIFY_CARD.LIMIT_TYPES.MONTHLY;
const initialLimitType = card?.nameValuePairs?.limitType ?? defaultLimitType;
const promptTranslationKey =
initialLimitType === CONST.EXPENSIFY_CARD.LIMIT_TYPES.MONTHLY
? 'workspace.expensifyCard.changeCardMonthlyLimitTypeWarning'
: 'workspace.expensifyCard.changeCardSmartLimitTypeWarning';
initialLimitType === CONST.EXPENSIFY_CARD.LIMIT_TYPES.MONTHLY || initialLimitType === CONST.EXPENSIFY_CARD.LIMIT_TYPES.FIXED
? 'workspace.expensifyCard.changeCardSmartLimitTypeWarning'
: 'workspace.expensifyCard.changeCardMonthlyLimitTypeWarning';

const [typeSelected, setTypeSelected] = useState(initialLimitType);
const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false);

const fetchCardLimitTypeData = useCallback(() => {
Policy.openPolicyEditCardLimitTypePage(policyID, Number(cardID));
}, [policyID, cardID]);

useFocusEffect(fetchCardLimitTypeData);

const updateCardLimitType = () => {
// TODO: add API call when it's supported https://github.com/Expensify/Expensify/issues/407833
};

const submit = () => {
// TODO: update the condition of showing confirm warning when requirements are known
const shouldShowConfirmModal = true;
let shouldShowConfirmModal = false;
if (!!card?.unapprovedSpend && card?.nameValuePairs?.unapprovedExpenseLimit) {
// Spends are coming as negative numbers from the backend and we need to make it positive for the correct expression.
const unapprovedSpend = Math.abs(card.unapprovedSpend);
const isUnapprovedSpendOverLimit = unapprovedSpend >= card.nameValuePairs.unapprovedExpenseLimit;

const validCombinations = [
[CONST.EXPENSIFY_CARD.LIMIT_TYPES.MONTHLY, CONST.EXPENSIFY_CARD.LIMIT_TYPES.SMART],
[CONST.EXPENSIFY_CARD.LIMIT_TYPES.SMART, CONST.EXPENSIFY_CARD.LIMIT_TYPES.MONTHLY],
[CONST.EXPENSIFY_CARD.LIMIT_TYPES.FIXED, CONST.EXPENSIFY_CARD.LIMIT_TYPES.SMART],
[CONST.EXPENSIFY_CARD.LIMIT_TYPES.FIXED, CONST.EXPENSIFY_CARD.LIMIT_TYPES.MONTHLY],
];
// Check if the combination exists in validCombinations
const isValidCombination = validCombinations.some(([limitType, selectedType]) => initialLimitType === limitType && typeSelected === selectedType);

if (isValidCombination && isUnapprovedSpendOverLimit) {
shouldShowConfirmModal = true;
}
}

if (shouldShowConfirmModal) {
setIsConfirmModalVisible(true);
Expand All @@ -62,8 +88,17 @@ function WorkspaceEditCardLimitTypePage({route}: WorkspaceEditCardLimitTypePageP

const data = useMemo(() => {
const options = [];
// TODO: update the condition of showing the fixed option when requirements are known
const shouldShowFixedOption = true;
let shouldShowFixedOption = true;

if (card?.totalSpend && card?.nameValuePairs?.unapprovedExpenseLimit) {
const totalSpend = Math.abs(card.totalSpend);
if (
(initialLimitType === CONST.EXPENSIFY_CARD.LIMIT_TYPES.MONTHLY || initialLimitType === CONST.EXPENSIFY_CARD.LIMIT_TYPES.SMART) &&
totalSpend >= card.nameValuePairs?.unapprovedExpenseLimit
) {
shouldShowFixedOption = false;
}
}

if (areApprovalsConfigured) {
options.push({
Expand Down Expand Up @@ -96,7 +131,7 @@ function WorkspaceEditCardLimitTypePage({route}: WorkspaceEditCardLimitTypePageP
}

return options;
}, [translate, typeSelected, areApprovalsConfigured]);
}, [areApprovalsConfigured, card, initialLimitType, translate, typeSelected]);

return (
<AccessOrNotFoundWrapper
Expand All @@ -113,34 +148,35 @@ function WorkspaceEditCardLimitTypePage({route}: WorkspaceEditCardLimitTypePageP
title={translate('workspace.card.issueNewCard.limitType')}
onBackButtonPress={() => Navigation.goBack(ROUTES.WORKSPACE_EXPENSIFY_CARD_DETAILS.getRoute(policyID, cardID))}
/>
<SelectionList
ListItem={RadioListItem}
onSelectRow={({value}) => setTypeSelected(value)}
sections={[{data}]}
shouldUpdateFocusedIndex
shouldSingleExecuteRowSelect
isAlternateTextMultilineSupported
initiallyFocusedOptionKey={typeSelected}
/>
<ConfirmModal
title={translate('workspace.expensifyCard.changeCardLimitType')}
isVisible={isConfirmModalVisible}
onConfirm={updateCardLimitType}
onCancel={() => setIsConfirmModalVisible(false)}
prompt={translate(promptTranslationKey, CurrencyUtils.convertToDisplayString(card?.nameValuePairs?.unapprovedExpenseLimit, CONST.CURRENCY.USD))}
confirmText={translate('workspace.expensifyCard.changeLimitType')}
cancelText={translate('common.cancel')}
danger
shouldEnableNewFocusManagement
/>
<Button
success
large
pressOnEnter
text={translate('common.save')}
onPress={submit}
style={styles.m5}
/>
<FullPageOfflineBlockingView>
<SelectionList
ListItem={RadioListItem}
onSelectRow={({value}) => setTypeSelected(value)}
sections={[{data}]}
shouldUpdateFocusedIndex
isAlternateTextMultilineSupported
initiallyFocusedOptionKey={typeSelected}
/>
<ConfirmModal
title={translate('workspace.expensifyCard.changeCardLimitType')}
isVisible={isConfirmModalVisible}
onConfirm={updateCardLimitType}
onCancel={() => setIsConfirmModalVisible(false)}
prompt={translate(promptTranslationKey, CurrencyUtils.convertToDisplayString(card?.nameValuePairs?.unapprovedExpenseLimit, CONST.CURRENCY.USD))}
confirmText={translate('workspace.expensifyCard.changeLimitType')}
cancelText={translate('common.cancel')}
danger
shouldEnableNewFocusManagement
/>
<Button
success
large
pressOnEnter
text={translate('common.save')}
onPress={submit}
style={styles.m5}
/>
</FullPageOfflineBlockingView>
</ScreenWrapper>
</AccessOrNotFoundWrapper>
);
Expand Down
6 changes: 6 additions & 0 deletions src/types/onyx/Card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ type Card = {
/** Available amount to spend */
availableSpend?: number;

/** Spend that is unapproved on the card (comes as a negative number) */
unapprovedSpend?: number;

/** Total spend on the card (comes as a negative number) */
totalSpend?: number;

/** Domain name */
domainName: string;

Expand Down

0 comments on commit 6c4502a

Please sign in to comment.