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

Allow NewDot collect customers to add one third-party card feed #56144

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1370,7 +1370,7 @@ const ROUTES = {
},
WORKSPACE_COMPANY_CARDS_ADD_NEW: {
route: 'settings/workspaces/:policyID/company-cards/add-card-feed',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/company-cards/add-card-feed` as const,
getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`settings/workspaces/${policyID}/company-cards/add-card-feed`, backTo),
},
WORKSPACE_COMPANY_CARDS_SELECT_FEED: {
route: 'settings/workspaces/:policyID/company-cards/select-feed',
Expand Down
4 changes: 2 additions & 2 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4412,8 +4412,8 @@ const translations = {
onlyAvailableOnPlan: 'Tax codes are only available on the Control plan, starting at ',
},
companyCards: {
title: 'Company cards',
description: `Connect your existing corporate cards to Expensify, assign them to employees, and automatically import transactions.`,
title: 'Additional Company cards',
description: `Upgrading lets you import company cards from additional card issuers. You can assign cards to employees, and automatically import transactions across all major card issuers.`,
onlyAvailableOnPlan: 'Company cards are only available on the Control plan, starting at ',
},
rules: {
Expand Down
4 changes: 2 additions & 2 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4478,8 +4478,8 @@ const translations = {
onlyAvailableOnPlan: 'Los código de impuesto mayor solo están disponibles en el plan Controlar, a partir de ',
},
companyCards: {
title: 'Tarjetas de empresa',
description: `Conecta tus tarjetas corporativas existentes a Expensify, asígnalas a empleados e importa transacciones automáticamente.`,
title: 'Tarjetas de empresa adicionales',
description: `La actualización le permite importar tarjetas de empresa de emisores de tarjetas adicionales. Puede asignar tarjetas a empleados e importar automáticamente transacciones de todos los principales emisores de tarjetas.`,
onlyAvailableOnPlan: 'Las tarjetas de empresa solo están disponibles en el plan Controlar, a partir de ',
},
rules: {
Expand Down
1 change: 1 addition & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1532,6 +1532,7 @@ type FullScreenNavigatorParamList = {
};
[SCREENS.WORKSPACE.COMPANY_CARDS_ADD_NEW]: {
policyID: string;
backTo?: Routes;
};
[SCREENS.WORKSPACE.PER_DIEM]: {
policyID: string;
Expand Down
4 changes: 4 additions & 0 deletions src/libs/actions/Policy/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1668,6 +1668,7 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol
ownerAccountID: sessionAccountID,
isPolicyExpenseChatEnabled: true,
areCategoriesEnabled: true,
areCompanyCardsEnabled: true,
outputCurrency,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
customUnits,
Expand Down Expand Up @@ -1762,6 +1763,7 @@ function buildPolicyData(
},
customUnits,
areCategoriesEnabled: true,
areCompanyCardsEnabled: true,
areTagsEnabled: false,
areDistanceRatesEnabled: false,
areWorkflowsEnabled: false,
Expand Down Expand Up @@ -2065,6 +2067,7 @@ function createDraftWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policy
},
customUnits,
areCategoriesEnabled: true,
areCompanyCardsEnabled: true,
areTagsEnabled: false,
areDistanceRatesEnabled: false,
areWorkflowsEnabled: false,
Expand Down Expand Up @@ -2378,6 +2381,7 @@ function createWorkspaceFromIOUPayment(iouReport: OnyxEntry<Report>): WorkspaceF
},
customUnits,
areCategoriesEnabled: true,
areCompanyCardsEnabled: true,
areTagsEnabled: false,
areDistanceRatesEnabled: false,
areWorkflowsEnabled: false,
Expand Down
4 changes: 0 additions & 4 deletions src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,6 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
if (!policyID) {
return;
}
if (isEnabled && !isControlPolicy(policy)) {
Navigation.navigate(ROUTES.WORKSPACE_UPGRADE.getRoute(policyID, CONST.UPGRADE_FEATURE_INTRO_MAPPING.companyCards.alias, ROUTES.WORKSPACE_MORE_FEATURES.getRoute(policyID)));
return;
}
enableCompanyCards(policyID, isEnabled, true);
},
disabledAction: () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/RadioListItem';
import type {ListItem} from '@components/SelectionList/types';
import useLocalize from '@hooks/useLocalize';
import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import {checkIfFeedConnectionIsBroken, getCardFeedIcon, getCompanyFeeds, getCustomOrFormattedFeedName, getSelectedFeed} from '@libs/CardUtils';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import {getWorkspaceAccountID} from '@libs/PolicyUtils';
import {getWorkspaceAccountID, isCollectPolicy} from '@libs/PolicyUtils';
import Navigation from '@navigation/Navigation';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import variables from '@styles/variables';
Expand Down Expand Up @@ -43,6 +44,8 @@ function WorkspaceCompanyCardFeedSelectorPage({route}: WorkspaceCompanyCardFeedS
const [lastSelectedFeed] = useOnyx(`${ONYXKEYS.COLLECTION.LAST_SELECTED_FEED}${policyID}`);
const selectedFeed = getSelectedFeed(lastSelectedFeed, cardFeeds);
const companyFeeds = getCompanyFeeds(cardFeeds);
const policy = usePolicy(policyID);
const isCollect = isCollectPolicy(policy);

const feeds: CardFeedListItem[] = (Object.keys(companyFeeds) as CompanyCardFeed[]).map((feed) => {
const isFeedConnectionBroken = checkIfFeedConnectionIsBroken(allFeedsCards?.[`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${workspaceAccountID}_${feed}`]);
Expand All @@ -66,6 +69,17 @@ function WorkspaceCompanyCardFeedSelectorPage({route}: WorkspaceCompanyCardFeedS
};
});

const onAddCardsPress = () => {
clearAddNewCardFlow();
if (isCollect && feeds.length === 1) {
Navigation.navigate(
ROUTES.WORKSPACE_UPGRADE.getRoute(policyID, CONST.UPGRADE_FEATURE_INTRO_MAPPING.companyCards.alias, ROUTES.WORKSPACE_COMPANY_CARDS_SELECT_FEED.getRoute(policyID)),
);
return;
}
Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_ADD_NEW.getRoute(policyID));
};

const goBack = () => Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS.getRoute(policyID));

const selectFeed = (feed: CardFeedListItem) => {
Expand Down Expand Up @@ -98,10 +112,7 @@ function WorkspaceCompanyCardFeedSelectorPage({route}: WorkspaceCompanyCardFeedS
<MenuItem
title={translate('workspace.companyCards.addCards')}
icon={Expensicons.Plus}
onPress={() => {
clearAddNewCardFlow();
Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_ADD_NEW.getRoute(policyID));
}}
onPress={onAddCardsPress}
/>
}
/>
Expand Down
21 changes: 15 additions & 6 deletions src/pages/workspace/companyCards/addNew/SelectBankStep.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {useRoute} from '@react-navigation/native';
import React, {useEffect, useState} from 'react';
import {View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
Expand All @@ -11,15 +12,19 @@ import RadioListItem from '@components/SelectionList/RadioListItem';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as CardUtils from '@libs/CardUtils';
import {getBankCardDetailsImage, getCorrectStepForSelectedBank} from '@libs/CardUtils';
import Navigation from '@navigation/Navigation';
import type {PlatformStackRouteProp} from '@navigation/PlatformStackNavigation/types';
import type {FullScreenNavigatorParamList} from '@navigation/types';
import variables from '@styles/variables';
import * as CompanyCards from '@userActions/CompanyCards';
import {clearAddNewCardFlow, setAddNewCompanyCardStepAndData} from '@userActions/CompanyCards';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type SCREENS from '@src/SCREENS';

function SelectBankStep() {
const {translate} = useLocalize();
const route = useRoute<PlatformStackRouteProp<FullScreenNavigatorParamList, typeof SCREENS.WORKSPACE.COMPANY_CARDS_ADD_NEW>>();
const styles = useThemeStyles();
const [addNewCard] = useOnyx(ONYXKEYS.ADD_NEW_COMPANY_CARD);
const [bankSelected, setBankSelected] = useState<ValueOf<typeof CONST.COMPANY_CARDS.BANKS>>();
Expand All @@ -31,10 +36,10 @@ function SelectBankStep() {
setHasError(true);
} else {
if (addNewCard?.data.selectedBank !== bankSelected) {
CompanyCards.clearAddNewCardFlow();
clearAddNewCardFlow();
}
CompanyCards.setAddNewCompanyCardStepAndData({
step: CardUtils.getCorrectStepForSelectedBank(bankSelected),
setAddNewCompanyCardStepAndData({
step: getCorrectStepForSelectedBank(bankSelected),
data: {
selectedBank: bankSelected,
cardTitle: !isOtherBankSelected ? bankSelected : undefined,
Expand All @@ -50,6 +55,10 @@ function SelectBankStep() {
}, [addNewCard?.data.selectedBank]);

const handleBackButtonPress = () => {
if (route?.params?.backTo) {
Navigation.navigate(route.params.backTo);
return;
}
Navigation.goBack();
};

Expand All @@ -60,7 +69,7 @@ function SelectBankStep() {
isSelected: bankSelected === bank,
leftElement: (
<Icon
src={CardUtils.getBankCardDetailsImage(bank)}
src={getBankCardDetailsImage(bank)}
height={variables.iconSizeExtraLarge}
width={variables.iconSizeExtraLarge}
additionalStyles={styles.mr3}
Expand Down
42 changes: 22 additions & 20 deletions src/pages/workspace/upgrade/WorkspaceUpgradePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import ScreenWrapper from '@components/ScreenWrapper';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useThemeStyles from '@hooks/useThemeStyles';
import * as QuickbooksOnline from '@libs/actions/connections/QuickbooksOnline';
import * as Xero from '@libs/actions/connections/Xero';
import {updateQuickbooksOnlineSyncClasses, updateQuickbooksOnlineSyncCustomers, updateQuickbooksOnlineSyncLocations} from '@libs/actions/connections/QuickbooksOnline';
import {updateXeroMappings} from '@libs/actions/connections/Xero';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import * as PolicyUtils from '@libs/PolicyUtils';
import {canModifyPlan, getPerDiemCustomUnit, isControlPolicy} from '@libs/PolicyUtils';
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
import * as PerDiem from '@userActions/Policy/PerDiem';
import {enablePerDiem} from '@userActions/Policy/PerDiem';
import CONST from '@src/CONST';
import * as Policy from '@src/libs/actions/Policy/Policy';
import {enableCompanyCards, enablePolicyReportFields, enablePolicyRules, upgradeToCorporate} from '@src/libs/actions/Policy/Policy';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
Expand Down Expand Up @@ -49,10 +49,10 @@ function WorkspaceUpgradePage({route}: WorkspaceUpgradePageProps) {
const qboConfig = policy?.connections?.quickbooksOnline?.config;
const {isOffline} = useNetwork();

const canPerformUpgrade = useMemo(() => PolicyUtils.canModifyPlan(policyID), [policyID]);
const isUpgraded = useMemo(() => PolicyUtils.isControlPolicy(policy), [policy]);
const canPerformUpgrade = useMemo(() => canModifyPlan(policyID), [policyID]);
const isUpgraded = useMemo(() => isControlPolicy(policy), [policy]);

const perDiemCustomUnit = PolicyUtils.getPerDiemCustomUnit(policy);
const perDiemCustomUnit = getPerDiemCustomUnit(policy);
const categoryId = route.params?.categoryId;

const goBack = useCallback(() => {
Expand Down Expand Up @@ -80,8 +80,10 @@ function WorkspaceUpgradePage({route}: WorkspaceUpgradePageProps) {
return;
}
}
case CONST.UPGRADE_FEATURE_INTRO_MAPPING.rules.id:
case CONST.UPGRADE_FEATURE_INTRO_MAPPING.companyCards.id:
Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_ADD_NEW.getRoute(policyID, ROUTES.WORKSPACE_COMPANY_CARDS_SELECT_FEED.getRoute(policyID)));
return;
case CONST.UPGRADE_FEATURE_INTRO_MAPPING.rules.id:
case CONST.UPGRADE_FEATURE_INTRO_MAPPING.perDiem.id:
Navigation.dismissModal();
return Navigation.navigate(ROUTES.WORKSPACE_MORE_FEATURES.getRoute(policyID));
Expand All @@ -91,12 +93,12 @@ function WorkspaceUpgradePage({route}: WorkspaceUpgradePageProps) {
}
}, [feature, policyID, route.params?.backTo, route.params?.featureName]);

const upgradeToCorporate = () => {
const onUpgradeToCorporate = () => {
if (!canPerformUpgrade || !policy) {
return;
}

Policy.upgradeToCorporate(policy.id, feature?.name);
upgradeToCorporate(policy.id, feature?.name);
};

const confirmUpgrade = useCallback(() => {
Expand All @@ -107,39 +109,39 @@ function WorkspaceUpgradePage({route}: WorkspaceUpgradePageProps) {
case CONST.UPGRADE_FEATURE_INTRO_MAPPING.reportFields.id:
switch (route.params.featureName) {
case CONST.REPORT_FIELDS_FEATURE.qbo.classes:
QuickbooksOnline.updateQuickbooksOnlineSyncClasses(policyID, CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD, qboConfig?.syncClasses);
updateQuickbooksOnlineSyncClasses(policyID, CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD, qboConfig?.syncClasses);
break;
case CONST.REPORT_FIELDS_FEATURE.qbo.customers:
QuickbooksOnline.updateQuickbooksOnlineSyncCustomers(policyID, CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD, qboConfig?.syncCustomers);
updateQuickbooksOnlineSyncCustomers(policyID, CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD, qboConfig?.syncCustomers);
break;
case CONST.REPORT_FIELDS_FEATURE.qbo.locations:
QuickbooksOnline.updateQuickbooksOnlineSyncLocations(policyID, CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD, qboConfig?.syncLocations);
updateQuickbooksOnlineSyncLocations(policyID, CONST.INTEGRATION_ENTITY_MAP_TYPES.REPORT_FIELD, qboConfig?.syncLocations);
break;
case CONST.REPORT_FIELDS_FEATURE.xero.mapping: {
const {trackingCategories} = policy?.connections?.xero?.data ?? {};
const currentTrackingCategory = trackingCategories?.find((category) => category.id === categoryId);
const {mappings} = policy?.connections?.xero?.config ?? {};
const currentTrackingCategoryValue = currentTrackingCategory ? mappings?.[`${CONST.XERO_CONFIG.TRACKING_CATEGORY_PREFIX}${currentTrackingCategory.id}`] ?? '' : '';
Xero.updateXeroMappings(
updateXeroMappings(
policyID,
categoryId ? {[`${CONST.XERO_CONFIG.TRACKING_CATEGORY_PREFIX}${categoryId}`]: CONST.XERO_CONFIG.TRACKING_CATEGORY_OPTIONS.REPORT_FIELD} : {},
categoryId ? {[`${CONST.XERO_CONFIG.TRACKING_CATEGORY_PREFIX}${categoryId}`]: currentTrackingCategoryValue} : {},
);
break;
}
default: {
Policy.enablePolicyReportFields(policyID, true, false);
enablePolicyReportFields(policyID, true, false);
}
}
break;
case CONST.UPGRADE_FEATURE_INTRO_MAPPING.rules.id:
Policy.enablePolicyRules(policyID, true, false);
enablePolicyRules(policyID, true, false);
break;
case CONST.UPGRADE_FEATURE_INTRO_MAPPING.companyCards.id:
Policy.enableCompanyCards(policyID, true, false);
enableCompanyCards(policyID, true, false);
break;
case CONST.UPGRADE_FEATURE_INTRO_MAPPING.perDiem.id:
PerDiem.enablePerDiem(policyID, true, perDiemCustomUnit?.customUnitID, false);
enablePerDiem(policyID, true, perDiemCustomUnit?.customUnitID, false);
break;
default:
}
Expand Down Expand Up @@ -197,7 +199,7 @@ function WorkspaceUpgradePage({route}: WorkspaceUpgradePageProps) {
<UpgradeIntro
policyID={policyID}
feature={feature}
onUpgrade={upgradeToCorporate}
onUpgrade={onUpgradeToCorporate}
buttonDisabled={isOffline}
loading={policy?.isPendingUpgrade}
/>
Expand Down