diff --git a/src/ROUTES.ts b/src/ROUTES.ts index d686f31266b3..0444b1d8ece8 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -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', + entryScreens: [SCREENS.WORKSPACE.DYNAMIC_COMPANY_CARD_DETAILS, SCREENS.WORKSPACE.DYNAMIC_EXPENSIFY_CARD_DETAILS, SCREENS.WORKSPACE.ACCOUNTING.RILLET_CARD_ACCOUNT_CARD_LIST], + 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', diff --git a/src/languages/de.ts b/src/languages/de.ts index 1e5a4131ca3a..0b54036378b1 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -529,6 +529,7 @@ const translations: TranslationDeepObject = { 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', diff --git a/src/languages/en.ts b/src/languages/en.ts index 75bfadee2ca7..b041d4f678d8 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -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', diff --git a/src/languages/es.ts b/src/languages/es.ts index 5e173ef30b78..cf2e328bbbb5 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -482,6 +482,7 @@ const translations: TranslationDeepObject = { 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', diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 664cee6663fb..ac007d09c5b2 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -529,6 +529,7 @@ const translations: TranslationDeepObject = { 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', diff --git a/src/languages/it.ts b/src/languages/it.ts index 6dc456a27c0c..c9ea8dc64e27 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -529,6 +529,7 @@ const translations: TranslationDeepObject = { 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', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 11db3c3def10..137fbc5a060b 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -528,6 +528,7 @@ const translations: TranslationDeepObject = { unableToDisplayChart: 'グラフを表示できません', webGLNotSupported: 'お使いのブラウザは WebGL に対応していません。有効にするか、別のブラウザに切り替えてください。', apiKey: 'API キー', + exportsTo: 'エクスポート先', }, socials: { podcast: 'ポッドキャストでフォロー', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index c774982e5ffe..62698ba1b017 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -528,6 +528,7 @@ const translations: TranslationDeepObject = { 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', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index ac30cc2c6efc..46f1c581c2f8 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -528,6 +528,7 @@ const translations: TranslationDeepObject = { 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', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index fe6a996bfccf..e664680a4161 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -527,6 +527,7 @@ const translations: TranslationDeepObject = { 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', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 487d47fe7611..1a6cfd712ba7 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -524,6 +524,7 @@ const translations: TranslationDeepObject = { unableToDisplayChart: '无法显示图表', webGLNotSupported: '您的浏览器不支持 WebGL。请启用该功能或更换浏览器。', apiKey: 'API 密钥', + exportsTo: '导出到', }, socials: { podcast: '在播客上关注我们', diff --git a/src/libs/actions/CompanyCards.ts b/src/libs/actions/CompanyCards.ts index 8ba9884979eb..51bc536a4024 100644 --- a/src/libs/actions/CompanyCards.ts +++ b/src/libs/actions/CompanyCards.ts @@ -36,6 +36,7 @@ import type { AddNewCardFeedStep, CardFeedData, CardFeedDetails, + CardFeedWithNumber, CompanyCardFeed, CompanyCardFeedWithDomainID, CompanyCardFeedWithNumber, @@ -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]: { diff --git a/src/pages/workspace/accounting/rillet/export/RilletCardAccountCardList.tsx b/src/pages/workspace/accounting/rillet/export/RilletCardAccountCardList.tsx index 3355d52e2065..60775dc3b1e0 100644 --- a/src/pages/workspace/accounting/rillet/export/RilletCardAccountCardList.tsx +++ b/src/pages/workspace/accounting/rillet/export/RilletCardAccountCardList.tsx @@ -93,7 +93,7 @@ function RilletCardAccountCardList({ 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( diff --git a/src/pages/workspace/companyCards/DynamicWorkspaceCompanyCardAccountSelectCardPage.tsx b/src/pages/workspace/companyCards/DynamicWorkspaceCompanyCardAccountSelectCardPage.tsx index 337d38b1cd6d..6bdc2394b4bc 100644 --- a/src/pages/workspace/companyCards/DynamicWorkspaceCompanyCardAccountSelectCardPage.tsx +++ b/src/pages/workspace/companyCards/DynamicWorkspaceCompanyCardAccountSelectCardPage.tsx @@ -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'; @@ -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]); @@ -94,8 +98,8 @@ function DynamicWorkspaceCompanyCardAccountSelectCardPage({route}: DynamicWorksp return ( } - featureName={CONST.POLICY.MORE_FEATURES.ARE_COMPANY_CARDS_ENABLED} + featureName={featureName} displayName="DynamicWorkspaceCompanyCardAccountSelectCardPage" data={searchedListOptions ?? []} textInputOptions={{ diff --git a/src/pages/workspace/companyCards/DynamicWorkspaceCompanyCardDetailsPage.tsx b/src/pages/workspace/companyCards/DynamicWorkspaceCompanyCardDetailsPage.tsx index a0920da17692..3d1a51264419 100644 --- a/src/pages/workspace/companyCards/DynamicWorkspaceCompanyCardDetailsPage.tsx +++ b/src/pages/workspace/companyCards/DynamicWorkspaceCompanyCardDetailsPage.tsx @@ -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'; @@ -71,16 +72,29 @@ import {getExportMenuItem} from './utils'; type DynamicWorkspaceCompanyCardDetailsPageProps = PlatformStackScreenProps; 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(); @@ -241,29 +255,6 @@ function DynamicWorkspaceCompanyCardDetailsPage({route}: DynamicWorkspaceCompany interactive={false} titleStyle={styles.walletCardNumber} /> - {exportMenuItem?.shouldShowMenuItem ? ( - { - if (!exportMenuItem.exportType) { - return; - } - clearCompanyCardErrorField(domainOrWorkspaceAccountID, cardID, bank, exportMenuItem.exportType); - }} - > - Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.WORKSPACE_COMPANY_CARD_EXPORT.getRoute()))} - interactive={canWriteCompanyCards} - sentryLabel={CONST.SENTRY_LABEL.WORKSPACE.COMPANY_CARDS.CARD_EXPORT} - /> - - ) : null} )} + {exportMenuItem?.shouldShowMenuItem ? ( + <> + + {translate('workspace.common.accounting')} + + { + if (!exportMenuItem.exportType) { + return; + } + clearCompanyCardErrorField(domainOrWorkspaceAccountID, cardID, bank, exportMenuItem.exportType); + }} + > + Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.WORKSPACE_COMPANY_CARD_EXPORT.getRoute(feedName, cardID)))} + interactive={canWriteCompanyCards} + sentryLabel={CONST.SENTRY_LABEL.WORKSPACE.COMPANY_CARDS.CARD_EXPORT} + /> + + + ) : null} diff --git a/src/pages/workspace/companyCards/utils.tsx b/src/pages/workspace/companyCards/utils.tsx index 1d421fb3c1c7..76890c42352c 100644 --- a/src/pages/workspace/companyCards/utils.tsx +++ b/src/pages/workspace/companyCards/utils.tsx @@ -20,6 +20,8 @@ type ExportIntegration = { exportPageLink: string; data: SelectorType[]; exportType?: ValueOf; + shouldHideMenuItemDescription?: boolean; + shouldShowMenuItemIcon?: boolean; shouldShowMenuItem?: boolean; }; @@ -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; @@ -417,6 +419,8 @@ function getExportMenuItem( title, description, exportType, + shouldHideMenuItemDescription: true, + shouldShowMenuItemIcon: true, shouldShowMenuItem, exportPageLink: ROUTES.POLICY_ACCOUNTING_RILLET_EXPORT.getRoute(policyID), data: filteredData, diff --git a/src/pages/workspace/expensifyCard/DynamicWorkspaceExpensifyCardDetailsPage.tsx b/src/pages/workspace/expensifyCard/DynamicWorkspaceExpensifyCardDetailsPage.tsx index 79cbd3fe8a35..3375b061d3ac 100644 --- a/src/pages/workspace/expensifyCard/DynamicWorkspaceExpensifyCardDetailsPage.tsx +++ b/src/pages/workspace/expensifyCard/DynamicWorkspaceExpensifyCardDetailsPage.tsx @@ -29,14 +29,17 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; +import {clearCompanyCardErrorField} from '@libs/actions/CompanyCards'; import {openPolicyExpensifyCardsPage} from '@libs/actions/Policy/Policy'; import navigateToCardTransactions from '@libs/CardNavigationUtils'; -import {getAllCardsForWorkspace, getCardFeedTextColor, getCardHintText, getTranslationKeyForLimitType, isCardFrozen, maskCard} from '@libs/CardUtils'; +import {getAllCardsForWorkspace, getCardFeedTextColor, getCardHintText, getCardFeedWithDomainID, getTranslationKeyForLimitType, isCardFrozen, maskCard} from '@libs/CardUtils'; +import {getLatestErrorField} from '@libs/ErrorUtils'; import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import {temporaryGetDisplayNameOrDefault} from '@libs/PersonalDetailsUtils'; -import {arePolicyRulesEnabled, canMemberWrite} from '@libs/PolicyUtils'; +import {arePolicyRulesEnabled, canMemberWrite, getConnectedIntegration} from '@libs/PolicyUtils'; +import {getIntegrationIcon} from '@libs/ReportUtils'; import {getSpendRuleByCardID, getSpendRuleSummaryText} from '@libs/SpendRulesUtils'; import Navigation from '@navigation/Navigation'; @@ -44,6 +47,7 @@ import Navigation from '@navigation/Navigation'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import CardDetailsActionButtons, {CardDetailsActionButton} from '@pages/settings/Wallet/CardDetailsActionButtons'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import {getExportMenuItem} from '@pages/workspace/companyCards/utils'; import variables from '@styles/variables'; @@ -95,7 +99,20 @@ function DynamicWorkspaceExpensifyCardDetailsPage({route}: DynamicWorkspaceExpen const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false); const {translate} = useLocalize(); const {login: currentUserLogin = ''} = useCurrentUserPersonalDetails(); - const expensifyIcons = useMemoizedLazyExpensifyIcons(['FreezeCard', 'MoneySearch', 'Trashcan', 'CreditCardLock']); + const expensifyIcons = useMemoizedLazyExpensifyIcons([ + 'FreezeCard', + 'MoneySearch', + 'Trashcan', + 'CreditCardLock', + 'XeroSquare', + 'QBOSquare', + 'NetSuiteSquare', + 'IntacctSquare', + 'QBDSquare', + 'CertiniaSquare', + 'RilletSquare', + 'GustoSquare', + ]); const illustrations = useMemoizedLazyIllustrations(['ExpensifyCardImage']); // We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to use the correct modal type for the decision modal // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth @@ -117,6 +134,10 @@ function DynamicWorkspaceExpensifyCardDetailsPage({route}: DynamicWorkspaceExpen const [allFeedsCards, allFeedsCardsResult] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST); const workspaceCards = getAllCardsForWorkspace(defaultFundID, allFeedsCards, cardFeeds, expensifyCardSettings, /* includeDeactivated */ true); + const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policyID}`); + const syncingAccountingIntegration = CONST.POLICY.CONNECTIONS.ACCOUNTING_CONNECTION_NAMES.find((integration) => integration === connectionSyncProgress?.connectionName); + const connectedIntegration = getConnectedIntegration(policy, CONST.POLICY.CONNECTIONS.ACCOUNTING_CONNECTION_NAMES) ?? syncingAccountingIntegration; + const workspaceCard = workspaceCards?.[cardID]; const card = workspaceCard ?? cardFromCardList; const currency = useCurrencyForExpensifyCard({ @@ -131,6 +152,7 @@ function DynamicWorkspaceExpensifyCardDetailsPage({route}: DynamicWorkspaceExpen passedPersonalDetails: cardholder, translate, }); + const exportMenuItem = getExportMenuItem(connectedIntegration, policyID, translate, styles, policy, card); const translationForLimitType = getTranslationKeyForLimitType(card?.nameValuePairs?.limitType); const remainingLimitHintTranslationKey = getLimitHintTranslationKey(card?.nameValuePairs?.limitType); const remainingLimitHint = remainingLimitHintTranslationKey ? translate(remainingLimitHintTranslationKey, formattedAvailableSpendAmount) : undefined; @@ -415,7 +437,6 @@ function DynamicWorkspaceExpensifyCardDetailsPage({route}: DynamicWorkspaceExpen interactive={canWriteExpensifyCard} /> - {canEditSpendRules && ( )} + {exportMenuItem?.shouldShowMenuItem ? ( + <> + + {translate('workspace.common.accounting')} + + { + if (!exportMenuItem.exportType) { + return; + } + clearCompanyCardErrorField(Number(card?.fundID ?? defaultFundID), cardID, CONST.EXPENSIFY_CARD.BANK, exportMenuItem.exportType); + }} + > + + Navigation.navigate( + createDynamicRoute( + DYNAMIC_ROUTES.WORKSPACE_COMPANY_CARD_EXPORT.getRoute(getCardFeedWithDomainID(card.bank, card?.fundID ?? defaultFundID), String(card.cardID)), + ), + ) + } + interactive={canWriteExpensifyCard} + sentryLabel={CONST.SENTRY_LABEL.WORKSPACE.COMPANY_CARDS.CARD_EXPORT} + /> + + + ) : null}