Skip to content
Merged
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
9 changes: 3 additions & 6 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -808,12 +808,9 @@ const DYNAMIC_ROUTES = {
getRoute: (feed: CompanyCardFeedWithDomainID, cardID: string) => `company-card-details/${encodeURIComponent(feed)}/${encodeURIComponent(cardID)}` as const,
},
WORKSPACE_COMPANY_CARD_EXPORT: {
path: 'edit/export/:cardID?',
entryScreens: [SCREENS.WORKSPACE.DYNAMIC_COMPANY_CARD_DETAILS, SCREENS.WORKSPACE.ACCOUNTING.RILLET_CARD_ACCOUNT_CARD_LIST],

// The cardID param is optional because some entry screens e.g. `SCREENS.WORKSPACE.DYNAMIC_COMPANY_CARD_DETAILS`
// already has the cardID in their path and we don't want to double pass the cardID.
getRoute: (cardID?: string) => `edit/export${cardID ? `/${encodeURIComponent(cardID)}` : ''}` as const,
path: 'edit/export/:feed/:cardID',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@s77rt Why do we need to introduce :feed param here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@MelvinBot Could you explain the purpose of new :feed param?

entryScreens: [SCREENS.WORKSPACE.DYNAMIC_COMPANY_CARD_DETAILS, SCREENS.WORKSPACE.DYNAMIC_EXPENSIFY_CARD_DETAILS, SCREENS.WORKSPACE.ACCOUNTING.RILLET_CARD_ACCOUNT_CARD_LIST],
Comment thread
s77rt marked this conversation as resolved.
getRoute: (feed: CardFeedWithDomainID, cardID: string) => `edit/export/${encodeURIComponent(feed)}/${encodeURIComponent(cardID)}` as const,
},
WORKSPACE_COMPANY_CARDS_ASSIGN_CARD_ASSIGNEE: {
path: 'assign-card/:feed/:cardID/assignee',
Expand Down
1 change: 1 addition & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ const translations: TranslationDeepObject<typeof en> = {
unableToDisplayChart: 'Diagram kann nicht angezeigt werden',
webGLNotSupported: 'Ihr Browser unterstützt WebGL nicht. Bitte aktivieren Sie es oder wechseln Sie den Browser.',
apiKey: 'API-Schlüssel',
exportsTo: 'Exportiert nach',
},
socials: {
podcast: 'Folgen Sie uns auf Podcast',
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ const translations = {
headsUp: 'Heads up!',
submitTo: 'Submit to',
forwardTo: 'Forward to',
exportsTo: 'Exports to',
approvalLimit: 'Approval limit',
overLimitForwardTo: 'Over limit forward to',
merge: 'Merge',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ const translations: TranslationDeepObject<typeof en> = {
tagGLCode: 'Etiquetar código GL',
off: 'Desactivado',
noResultsFoundSubtitle: 'Sin resultados. Intenta ajustar tus filtros o la búsqueda.',
exportsTo: 'Exporta a',
},
socials: {
podcast: 'Síguenos en Podcast',
Expand Down
1 change: 1 addition & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ const translations: TranslationDeepObject<typeof en> = {
unableToDisplayChart: 'Impossible d’afficher le graphique',
webGLNotSupported: 'Votre navigateur ne prend pas en charge WebGL. Veuillez l’activer ou changer de navigateur.',
apiKey: 'Clé API',
exportsTo: 'Exports vers',
},
socials: {
podcast: 'Suivez-nous sur Podcast',
Expand Down
1 change: 1 addition & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ const translations: TranslationDeepObject<typeof en> = {
unableToDisplayChart: 'Impossibile visualizzare il grafico',
webGLNotSupported: 'Il tuo browser non supporta WebGL. Abilitalo oppure passa a un altro browser.',
apiKey: 'Chiave API',
exportsTo: 'Esporta in',
},
socials: {
podcast: 'Seguici su Podcast',
Expand Down
1 change: 1 addition & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ const translations: TranslationDeepObject<typeof en> = {
unableToDisplayChart: 'グラフを表示できません',
webGLNotSupported: 'お使いのブラウザは WebGL に対応していません。有効にするか、別のブラウザに切り替えてください。',
apiKey: 'API キー',
exportsTo: 'エクスポート先',
},
socials: {
podcast: 'ポッドキャストでフォロー',
Expand Down
1 change: 1 addition & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ const translations: TranslationDeepObject<typeof en> = {
unableToDisplayChart: 'Grafiek kan niet worden weergegeven',
webGLNotSupported: 'Je browser ondersteunt WebGL niet. Schakel het in of gebruik een andere browser.',
apiKey: 'API-sleutel',
exportsTo: 'Exporteert naar',
},
socials: {
podcast: 'Volg ons op Podcast',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ const translations: TranslationDeepObject<typeof en> = {
unableToDisplayChart: 'Nie można wyświetlić wykresu',
webGLNotSupported: 'Twoja przeglądarka nie obsługuje WebGL. Włącz ją albo zmień przeglądarkę.',
apiKey: 'Klucz API',
exportsTo: 'Eksporty do',
},
socials: {
podcast: 'Śledź nas na Podcast',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ const translations: TranslationDeepObject<typeof en> = {
unableToDisplayChart: 'Não foi possível exibir o gráfico',
webGLNotSupported: 'Seu navegador não é compatível com WebGL. Ative-o ou mude de navegador.',
apiKey: 'Chave de API',
exportsTo: 'Exportações para',
},
socials: {
podcast: 'Siga-nos no Podcast',
Expand Down
1 change: 1 addition & 0 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,7 @@ const translations: TranslationDeepObject<typeof en> = {
unableToDisplayChart: '无法显示图表',
webGLNotSupported: '您的浏览器不支持 WebGL。请启用该功能或更换浏览器。',
apiKey: 'API 密钥',
exportsTo: '导出到',
},
socials: {
podcast: '在播客上关注我们',
Expand Down
3 changes: 2 additions & 1 deletion src/libs/actions/CompanyCards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import type {
AddNewCardFeedStep,
CardFeedData,
CardFeedDetails,
CardFeedWithNumber,
CompanyCardFeed,
CompanyCardFeedWithDomainID,
CompanyCardFeedWithNumber,
Expand Down Expand Up @@ -965,7 +966,7 @@ function setCompanyCardExportAccount(policyID: string, domainOrWorkspaceAccountI
});
}

function clearCompanyCardErrorField(domainOrWorkspaceAccountID: number, cardID: string, bankName: CompanyCardFeedWithNumber, fieldName: string, isRootLevel?: boolean) {
function clearCompanyCardErrorField(domainOrWorkspaceAccountID: number, cardID: string, bankName: CardFeedWithNumber, fieldName: string, isRootLevel?: boolean) {
if (isRootLevel) {
Onyx.merge(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${domainOrWorkspaceAccountID}_${bankName}`, {
[cardID]: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ function RilletCardAccountCardList({
<MenuItemWithTopDescription
title={cardAccountDisplayName}
description={getCardDescription(card, translate)}
onPress={() => Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.WORKSPACE_COMPANY_CARD_EXPORT.getRoute(String(cardID))))}
onPress={() => Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.WORKSPACE_COMPANY_CARD_EXPORT.getRoute(feedWithDomainID, String(cardID))))}
shouldShowRightIcon
brickRoadIndicator={
areCardsCustomExportInErrorFields(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import useWorkspaceAccountID from '@hooks/useWorkspaceAccountID';

import {setCompanyCardExportAccount} from '@libs/actions/CompanyCards';
import {getCompanyCardFeed, getCompanyFeeds, getDomainOrWorkspaceAccountID} from '@libs/CardUtils';
import {getCompanyCardFeed, getDomainOrWorkspaceAccountID, isExpensifyCard as isExpensifyCardUtil} from '@libs/CardUtils';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import {getConnectedIntegration, getCurrentConnectionName} from '@libs/PolicyUtils';
import tokenizedSearch from '@libs/tokenizedSearch';
Expand Down Expand Up @@ -64,8 +64,12 @@ function DynamicWorkspaceCompanyCardAccountSelectCardPage({route}: DynamicWorksp
const illustrations = useMemoizedLazyIllustrations(['Telescope']);

const [cardFeeds] = useCardFeeds(policyID);
const companyFeeds = getCompanyFeeds(cardFeeds);
const domainOrWorkspaceAccountID = getDomainOrWorkspaceAccountID(workspaceAccountID, companyFeeds[feed]);
const domainOrWorkspaceAccountID = getDomainOrWorkspaceAccountID(workspaceAccountID, cardFeeds?.[feed]);

// This page is a dynamic page and is used by both Expensify Cards and Company Cards
const isExpensifyCard = isExpensifyCardUtil(card);
const featureName = isExpensifyCard ? CONST.POLICY.MORE_FEATURES.ARE_EXPENSIFY_CARDS_ENABLED : CONST.POLICY.MORE_FEATURES.ARE_COMPANY_CARDS_ENABLED;
const policyFeature = isExpensifyCard ? CONST.POLICY.POLICY_FEATURE.EXPENSIFY_CARD : CONST.POLICY.POLICY_FEATURE.COMPANY_CARDS;

const searchedListOptions = tokenizedSearch(exportMenuItem?.data ?? [], searchText, (option) => [option.text ?? option.value]);

Expand Down Expand Up @@ -94,8 +98,8 @@ function DynamicWorkspaceCompanyCardAccountSelectCardPage({route}: DynamicWorksp
return (
<AccessOrNotFoundWrapper
policyID={policyID}
featureName={CONST.POLICY.MORE_FEATURES.ARE_COMPANY_CARDS_ENABLED}
policyFeature={CONST.POLICY.POLICY_FEATURE.COMPANY_CARDS}
featureName={featureName}
policyFeature={policyFeature}
policyFeatureAccess={CONST.POLICY.POLICY_FEATURE_ACCESS.WRITE}
>
<SelectionScreen
Expand All @@ -119,7 +123,7 @@ function DynamicWorkspaceCompanyCardAccountSelectCardPage({route}: DynamicWorksp
)}
</View>
}
featureName={CONST.POLICY.MORE_FEATURES.ARE_COMPANY_CARDS_ENABLED}
featureName={featureName}
displayName="DynamicWorkspaceCompanyCardAccountSelectCardPage"
data={searchedListOptions ?? []}
textInputOptions={{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavig
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import {temporaryGetDisplayNameOrDefault} from '@libs/PersonalDetailsUtils';
import {getConnectedIntegration} from '@libs/PolicyUtils';
import {getIntegrationIcon} from '@libs/ReportUtils';

import Navigation from '@navigation/Navigation';

Expand Down Expand Up @@ -71,16 +72,29 @@ import {getExportMenuItem} from './utils';
type DynamicWorkspaceCompanyCardDetailsPageProps = PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.WORKSPACE.DYNAMIC_COMPANY_CARD_DETAILS>;

function DynamicWorkspaceCompanyCardDetailsPage({route}: DynamicWorkspaceCompanyCardDetailsPageProps) {
const {policyID, cardID} = route.params;
const {policyID, feed, cardID} = route.params;
const backPath = useDynamicBackPath(DYNAMIC_ROUTES.WORKSPACE_COMPANY_CARD_DETAILS.path);
const feedName = decodeURIComponent(route.params.feed) as CompanyCardFeedWithDomainID;
const feedName = decodeURIComponent(feed) as CompanyCardFeedWithDomainID;
const bank = getCompanyCardFeed(feedName);

const {translate, getLocalDateFromDatetime} = useLocalize();
const styles = useThemeStyles();
const illustrations = useThemeIllustrations();
const companyCardFeedIcons = useCompanyCardFeedIcons();
const expensifyIcons = useMemoizedLazyExpensifyIcons(['MoneySearch', 'RemoveMembers', 'Sync', 'Trashcan']);
const expensifyIcons = useMemoizedLazyExpensifyIcons([
'MoneySearch',
'RemoveMembers',
'Sync',
'Trashcan',
'XeroSquare',
'QBOSquare',
'NetSuiteSquare',
'IntacctSquare',
'QBDSquare',
'CertiniaSquare',
'RilletSquare',
'GustoSquare',
]);
const {isOffline} = useNetwork();
const {showConfirmModal} = useConfirmModal();

Expand Down Expand Up @@ -241,29 +255,6 @@ function DynamicWorkspaceCompanyCardDetailsPage({route}: DynamicWorkspaceCompany
interactive={false}
titleStyle={styles.walletCardNumber}
/>
{exportMenuItem?.shouldShowMenuItem ? (
<OfflineWithFeedback
pendingAction={exportMenuItem?.exportType ? card?.nameValuePairs?.pendingFields?.[exportMenuItem.exportType] : undefined}
errorRowStyles={errorRowStyles}
errors={exportMenuItem.exportType ? getLatestErrorField(card?.nameValuePairs ?? {}, exportMenuItem.exportType) : undefined}
onClose={() => {
if (!exportMenuItem.exportType) {
return;
}
clearCompanyCardErrorField(domainOrWorkspaceAccountID, cardID, bank, exportMenuItem.exportType);
}}
>
<MenuItemWithTopDescription
description={exportMenuItem.description}
title={exportMenuItem.title}
numberOfLinesTitle={2}
shouldShowRightIcon={canWriteCompanyCards}
onPress={() => Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.WORKSPACE_COMPANY_CARD_EXPORT.getRoute()))}
interactive={canWriteCompanyCards}
sentryLabel={CONST.SENTRY_LABEL.WORKSPACE.COMPANY_CARDS.CARD_EXPORT}
/>
</OfflineWithFeedback>
) : null}
<OfflineWithFeedback
pendingAction={card?.pendingFields?.scrapeMinDate}
errorRowStyles={errorRowStyles}
Expand Down Expand Up @@ -312,6 +303,37 @@ function DynamicWorkspaceCompanyCardDetailsPage({route}: DynamicWorkspaceCompany
sentryLabel={CONST.SENTRY_LABEL.WORKSPACE.COMPANY_CARDS.UNASSIGN_CARD}
/>
)}
{exportMenuItem?.shouldShowMenuItem ? (
<>
<View style={[styles.mh5, styles.pt3, styles.borderTop]}>
<Text style={[styles.textNormal, styles.textStrong, styles.mv3]}>{translate('workspace.common.accounting')}</Text>
</View>
<OfflineWithFeedback
pendingAction={exportMenuItem?.exportType ? card?.nameValuePairs?.pendingFields?.[exportMenuItem.exportType] : undefined}
errorRowStyles={errorRowStyles}
errors={exportMenuItem.exportType ? getLatestErrorField(card?.nameValuePairs ?? {}, exportMenuItem.exportType) : undefined}
onClose={() => {
if (!exportMenuItem.exportType) {
return;
}
clearCompanyCardErrorField(domainOrWorkspaceAccountID, cardID, bank, exportMenuItem.exportType);
}}
>
<MenuItemWithTopDescription
description={exportMenuItem.shouldHideMenuItemDescription ? undefined : exportMenuItem.description}
title={exportMenuItem.title}
numberOfLinesTitle={2}
icon={exportMenuItem.shouldShowMenuItemIcon ? getIntegrationIcon(connectedIntegration, expensifyIcons) : undefined}
iconType={CONST.ICON_TYPE_AVATAR}
avatarSize={CONST.AVATAR_SIZE.SMALLER}
shouldShowRightIcon={canWriteCompanyCards}
onPress={() => Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.WORKSPACE_COMPANY_CARD_EXPORT.getRoute(feedName, cardID)))}
interactive={canWriteCompanyCards}
sentryLabel={CONST.SENTRY_LABEL.WORKSPACE.COMPANY_CARDS.CARD_EXPORT}
/>
</OfflineWithFeedback>
</>
) : null}
</ScrollView>
</ScreenWrapper>
</AccessOrNotFoundWrapper>
Expand Down
6 changes: 5 additions & 1 deletion src/pages/workspace/companyCards/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ type ExportIntegration = {
exportPageLink: string;
data: SelectorType[];
exportType?: ValueOf<typeof CONST.COMPANY_CARDS.EXPORT_CARD_TYPES>;
shouldHideMenuItemDescription?: boolean;
shouldShowMenuItemIcon?: boolean;
shouldShowMenuItem?: boolean;
};

Expand Down Expand Up @@ -393,7 +395,7 @@ function getExportMenuItem(
: undefined) ?? cardProgramAccount?.id;
const cardAccount = rilletData?.accounts?.find((account) => account.id === cardAccountID);
const cardAccountDisplayName = cardAccount ? `${cardAccount.code} ${cardAccount.name}${isUsingCustomAccount ? '' : ` (${translate('common.default').toLocaleLowerCase()})`}` : '';
const title = cardAccountDisplayName;
const title = `${translate('common.exportsTo')} ${cardAccountDisplayName}`;
const description = currentConnectionName
? translate('workspace.moreFeatures.companyCards.integrationExport', currentConnectionName, translate('workspace.rillet.cardAccount.label'))
: undefined;
Expand All @@ -417,6 +419,8 @@ function getExportMenuItem(
title,
description,
exportType,
shouldHideMenuItemDescription: true,
shouldShowMenuItemIcon: true,
shouldShowMenuItem,
exportPageLink: ROUTES.POLICY_ACCOUNTING_RILLET_EXPORT.getRoute(policyID),
data: filteredData,
Expand Down
Loading
Loading