Skip to content

Commit 3921a4e

Browse files
authored
Merge pull request Expensify#65149 from Expensify/nikki-add-custom-is-templates
[Export Templates] Add custom IS Templates to export dropdown
2 parents 3f8f569 + ebce92b commit 3921a4e

7 files changed

Lines changed: 80 additions & 13 deletions

File tree

src/ONYXKEYS.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ const ONYXKEYS = {
250250
/** Details on whether an account is locked or not */
251251
NVP_PRIVATE_LOCK_ACCOUNT_DETAILS: 'nvp_private_lockAccountDetails',
252252

253+
/** The NVP containing the user's custom IS templates */
254+
NVP_INTEGRATION_SERVER_EXPORT_TEMPLATES: 'nvp_expensify_integrationServerExportTemplates',
255+
253256
/** Plaid data (access tokens, bank accounts ...) */
254257
PLAID_DATA: 'plaidData',
255258

@@ -1213,6 +1216,7 @@ type OnyxValuesMapping = {
12131216
[ONYXKEYS.NVP_LAST_IPHONE_LOGIN]: string;
12141217
[ONYXKEYS.NVP_LAST_ANDROID_LOGIN]: string;
12151218
[ONYXKEYS.TRANSACTION_THREAD_NAVIGATION_REPORT_IDS]: string[];
1219+
[ONYXKEYS.NVP_INTEGRATION_SERVER_EXPORT_TEMPLATES]: OnyxTypes.IntegrationServerExportTemplate[];
12161220
[ONYXKEYS.ONBOARDING_USER_REPORTED_INTEGRATION]: OnboardingAccounting;
12171221
[ONYXKEYS.HYBRID_APP]: OnyxTypes.HybridApp;
12181222
};

src/components/MoneyReportHeader.tsx

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ function MoneyReportHeader({
172172
const [download] = useOnyx(`${ONYXKEYS.COLLECTION.DOWNLOAD}${reportPDFFilename}`, {canBeMissing: true});
173173
const isDownloadingPDF = download?.isDownloading ?? false;
174174
const [session] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false});
175+
const [integrationsExportTemplates] = useOnyx(ONYXKEYS.NVP_INTEGRATION_SERVER_EXPORT_TEMPLATES, {canBeMissing: true});
175176
const requestParentReportAction = useMemo(() => {
176177
if (!reportActions || !transactionThreadReport?.parentReportActionID) {
177178
return null;
@@ -549,8 +550,8 @@ function MoneyReportHeader({
549550

550551
const [offlineModalVisible, setOfflineModalVisible] = useState(false);
551552

552-
const exportSubMenuOptions: Record<ValueOf<typeof CONST.REPORT.EXPORT_OPTIONS>, DropdownOption<ValueOf<typeof CONST.REPORT.EXPORT_OPTIONS>>> = useMemo(
553-
() => ({
553+
const exportSubmenuOptions: Record<string, DropdownOption<string>> = useMemo(() => {
554+
const options: Record<string, DropdownOption<string>> = {
554555
[CONST.REPORT.EXPORT_OPTIONS.DOWNLOAD_CSV]: {
555556
text: translate('export.basicExport'),
556557
icon: Expensicons.Table,
@@ -611,9 +612,22 @@ function MoneyReportHeader({
611612
markAsManuallyExported(moneyRequestReport?.reportID, connectedIntegration);
612613
},
613614
},
614-
}),
615-
[translate, connectedIntegrationFallback, connectedIntegration, moneyRequestReport, isOffline, transactionIDs, isExported, beginExportWithTemplate],
616-
);
615+
};
616+
617+
// If the user has any custom integration export templates, add them as export options
618+
if (integrationsExportTemplates && integrationsExportTemplates.length > 0) {
619+
for (const template of integrationsExportTemplates) {
620+
options[template.name] = {
621+
text: template.name,
622+
icon: Expensicons.Table,
623+
value: template.name,
624+
onSelected: () => beginExportWithTemplate(template.name, CONST.EXPORT_TEMPLATE_TYPES.INTEGRATIONS, transactionIDs),
625+
};
626+
}
627+
}
628+
629+
return options;
630+
}, [translate, connectedIntegrationFallback, connectedIntegration, moneyRequestReport, isOffline, transactionIDs, isExported, beginExportWithTemplate, integrationsExportTemplates]);
617631

618632
const primaryActionsImplementation = {
619633
[CONST.REPORT.PRIMARY_ACTIONS.SUBMIT]: (
@@ -759,8 +773,8 @@ function MoneyReportHeader({
759773
if (!moneyRequestReport) {
760774
return [];
761775
}
762-
return getSecondaryExportReportActions(moneyRequestReport, policy, reportActions);
763-
}, [moneyRequestReport, policy, reportActions]);
776+
return getSecondaryExportReportActions(moneyRequestReport, policy, reportActions, integrationsExportTemplates ?? []);
777+
}, [moneyRequestReport, policy, reportActions, integrationsExportTemplates]);
764778

765779
const secondaryActionsImplementation: Record<
766780
ValueOf<typeof CONST.REPORT.SECONDARY_ACTIONS>,
@@ -779,7 +793,7 @@ function MoneyReportHeader({
779793
text: translate('common.export'),
780794
backButtonText: translate('common.export'),
781795
icon: Expensicons.Export,
782-
subMenuItems: secondaryExportActions.map((action) => exportSubMenuOptions[action]),
796+
subMenuItems: secondaryExportActions.map((action) => exportSubmenuOptions[action as string]),
783797
},
784798
[CONST.REPORT.SECONDARY_ACTIONS.DOWNLOAD_PDF]: {
785799
value: CONST.REPORT.SECONDARY_ACTIONS.DOWNLOAD_PDF,

src/hooks/useSelectedTransactionsActions.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ function useSelectedTransactionsActions({
4949
}) {
5050
const {selectedTransactionIDs, clearSelectedTransactions} = useSearchContext();
5151
const [allTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {canBeMissing: false});
52+
const [integrationsExportTemplates] = useOnyx(ONYXKEYS.NVP_INTEGRATION_SERVER_EXPORT_TEMPLATES, {canBeMissing: true});
5253
const {duplicateTransactions, duplicateTransactionViolations} = useDuplicateTransactionsAndViolations(selectedTransactionIDs);
5354
const isReportArchived = useReportIsArchived(report?.reportID);
5455
const selectedTransactions = useMemo(
@@ -210,6 +211,17 @@ function useSelectedTransactionsActions({
210211
});
211212
}
212213

214+
// If the user has any custom integration export templates, add them as export options
215+
if (integrationsExportTemplates && integrationsExportTemplates.length > 0) {
216+
for (const template of integrationsExportTemplates) {
217+
exportOptions.push({
218+
text: template.name,
219+
icon: Expensicons.Table,
220+
onSelected: () => beginExportWithTemplate(template.name, CONST.EXPORT_TEMPLATE_TYPES.INTEGRATIONS, selectedTransactionIDs),
221+
});
222+
}
223+
}
224+
213225
return exportOptions;
214226
};
215227

@@ -279,6 +291,7 @@ function useSelectedTransactionsActions({
279291
session?.accountID,
280292
showDeleteModal,
281293
beginExportWithTemplate,
294+
integrationsExportTemplates,
282295
]);
283296

284297
return {

src/libs/ReportSecondaryActionUtils.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
22
import type {ValueOf} from 'type-fest';
33
import CONST from '@src/CONST';
44
import ONYXKEYS from '@src/ONYXKEYS';
5-
import type {Policy, Report, ReportAction, ReportNameValuePairs, Transaction, TransactionViolation} from '@src/types/onyx';
5+
import type {IntegrationServerExportTemplate, Policy, Report, ReportAction, ReportNameValuePairs, Transaction, TransactionViolation} from '@src/types/onyx';
66
import {isApprover as isApproverUtils} from './actions/Policy/Member';
77
import {getCurrentUserAccountID, getCurrentUserEmail} from './actions/Report';
88
import {
@@ -646,9 +646,13 @@ function getSecondaryReportActions({
646646
return options;
647647
}
648648

649-
function getSecondaryExportReportActions(report: Report, policy?: Policy, reportActions?: ReportAction[]): Array<ValueOf<typeof CONST.REPORT.EXPORT_OPTIONS>> {
650-
const options: Array<ValueOf<typeof CONST.REPORT.EXPORT_OPTIONS>> = [];
651-
649+
function getSecondaryExportReportActions(
650+
report: Report,
651+
policy?: Policy,
652+
reportActions?: ReportAction[],
653+
integrationsExportTemplates?: IntegrationServerExportTemplate[],
654+
): Array<ValueOf<string>> {
655+
const options: Array<ValueOf<string>> = [];
652656
if (isExportAction(report, policy, reportActions)) {
653657
options.push(CONST.REPORT.EXPORT_OPTIONS.EXPORT_TO_INTEGRATION);
654658
}
@@ -659,6 +663,12 @@ function getSecondaryExportReportActions(report: Report, policy?: Policy, report
659663

660664
options.push(CONST.REPORT.EXPORT_OPTIONS.DOWNLOAD_CSV, CONST.REPORT.EXPORT_OPTIONS.EXPENSE_LEVEL_EXPORT, CONST.REPORT.EXPORT_OPTIONS.REPORT_LEVEL_EXPORT);
661665

666+
if (integrationsExportTemplates && integrationsExportTemplates.length > 0) {
667+
for (const template of integrationsExportTemplates) {
668+
options.push(template.name);
669+
}
670+
}
671+
662672
return options;
663673
}
664674

src/pages/Search/SearchPage.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ function SearchPage({route}: SearchPageProps) {
7979
const [newParentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${newReport?.parentReportID}`, {canBeMissing: true});
8080
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID, {canBeMissing: false});
8181
const [activePolicy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`, {canBeMissing: true});
82-
82+
const [integrationsExportTemplates] = useOnyx(ONYXKEYS.NVP_INTEGRATION_SERVER_EXPORT_TEMPLATES, {canBeMissing: true});
8383
const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false);
8484
const [isDownloadErrorModalVisible, setIsDownloadErrorModalVisible] = useState(false);
8585
const [isDeleteExpensesConfirmModalVisible, setIsDeleteExpensesConfirmModalVisible] = useState(false);
@@ -198,6 +198,20 @@ function SearchPage({route}: SearchPageProps) {
198198
});
199199
}
200200

201+
// If the user has any custom integration export templates, add them as export options
202+
if (integrationsExportTemplates && integrationsExportTemplates.length > 0) {
203+
for (const template of integrationsExportTemplates) {
204+
exportOptions.push({
205+
text: template.name,
206+
icon: Expensicons.Table,
207+
onSelected: () => {
208+
// Custom IS templates are not policy specific, so we don't need to pass a policyID
209+
beginExportWithTemplate(template.name, CONST.EXPORT_TEMPLATE_TYPES.INTEGRATIONS, undefined);
210+
},
211+
});
212+
}
213+
}
214+
201215
return exportOptions;
202216
};
203217

@@ -433,6 +447,7 @@ function SearchPage({route}: SearchPageProps) {
433447
styles.fontWeightNormal,
434448
styles.textWrap,
435449
beginExportWithTemplate,
450+
integrationsExportTemplates,
436451
]);
437452

438453
const handleDeleteExpenses = () => {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import type * as OnyxCommon from './OnyxCommon';
2+
3+
/** Information about integration server export templates */
4+
type IntegrationServerExportTemplate = OnyxCommon.OnyxValueWithOfflineFeedback<{
5+
/** Name of the template */
6+
name: string;
7+
}>;
8+
9+
export default IntegrationServerExportTemplate;

src/types/onyx/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import type {FundList} from './Fund';
3434
import type Fund from './Fund';
3535
import type HybridApp from './HybridApp';
3636
import type ImportedSpreadsheet from './ImportedSpreadsheet';
37+
import type IntegrationServerExportTemplate from './IntegrationServerExportTemplate';
3738
import type IntroSelected from './IntroSelected';
3839
import type InvitedEmailsToAccountIDs from './InvitedEmailsToAccountIDs';
3940
import type JoinablePolicies from './JoinablePolicies';
@@ -265,5 +266,6 @@ export type {
265266
ValidateUserAndGetAccessiblePolicies,
266267
VacationDelegate,
267268
BillingReceiptDetails,
269+
IntegrationServerExportTemplate,
268270
HybridApp,
269271
};

0 commit comments

Comments
 (0)