Skip to content

Commit 2de2b6e

Browse files
authored
Merge pull request Expensify#86806 from Krishna2323/krishna2323/issue/85052
feat: Add Edit Company Card feed feature for CSV Card Import
2 parents d64cf97 + 258b781 commit 2de2b6e

5 files changed

Lines changed: 52 additions & 5 deletions

File tree

src/libs/actions/CompanyCards.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ type ImportCSVCompanyCardsData = {
6464
existingCardsList?: WorkspaceCardsList;
6565
lastSelectedFeed?: CompanyCardFeedWithDomainID;
6666
workspaceCardFeeds?: OnyxEntry<CardFeeds>;
67+
existingInstanceID?: string;
6768
};
6869

6970
type OptimisticCompanyCardCSVTransaction = Pick<Transaction, 'transactionID' | 'amount' | 'created' | 'currency' | 'merchant' | 'category' | 'tag' | 'comment' | 'cardName' | 'bank'> & {
@@ -1124,10 +1125,11 @@ function importCSVCompanyCards({
11241125
existingCardsList,
11251126
lastSelectedFeed,
11261127
workspaceCardFeeds,
1128+
existingInstanceID,
11271129
}: ImportCSVCompanyCardsData) {
11281130
const feedName = layoutType as CompanyCardFeed;
11291131
const {csvDataWithGeneratedIDs, normalizedColumnMappings, transactions: optimisticTransactions} = buildOptimisticCompanyCardCSVTransactions(csvData, columnMappings, feedName);
1130-
const instanceID = Date.now().toString();
1132+
const instanceID = existingInstanceID ?? Date.now().toString();
11311133

11321134
const parameters: ImportCSVCompanyCardsParams = {
11331135
policyID,

src/pages/workspace/companyCards/WorkspaceCompanyCardsSettingsPage.tsx

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import useLocalize from '@hooks/useLocalize';
1818
import useOnyx from '@hooks/useOnyx';
1919
import usePolicy from '@hooks/usePolicy';
2020
import useThemeStyles from '@hooks/useThemeStyles';
21-
import {deleteWorkspaceCompanyCardFeed, setWorkspaceCompanyCardTransactionLiability} from '@libs/actions/CompanyCards';
22-
import {getCompanyCardFeed, getCompanyFeeds, getCustomOrFormattedFeedName, getDomainOrWorkspaceAccountID, getSelectedFeed, isDirectFeed} from '@libs/CardUtils';
21+
import {deleteWorkspaceCompanyCardFeed, setAddNewCompanyCardStepAndData, setWorkspaceCompanyCardTransactionLiability} from '@libs/actions/CompanyCards';
22+
import {getCompanyCardFeed, getCompanyFeeds, getCustomOrFormattedFeedName, getDomainOrWorkspaceAccountID, getSelectedFeed, isCSVUploadFeed, isDirectFeed} from '@libs/CardUtils';
2323
import Navigation from '@libs/Navigation/Navigation';
2424
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
2525
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
@@ -32,6 +32,15 @@ import ROUTES from '@src/ROUTES';
3232
import type SCREENS from '@src/SCREENS';
3333
import type {CompanyCardFeedWithDomainID} from '@src/types/onyx';
3434

35+
const ADVANCED_CSV_COLUMNS = new Set<string>([
36+
CONST.CSV_IMPORT_COLUMNS.ORIGINAL_TRANSACTION_DATE,
37+
CONST.CSV_IMPORT_COLUMNS.ORIGINAL_AMOUNT,
38+
CONST.CSV_IMPORT_COLUMNS.ORIGINAL_CURRENCY,
39+
CONST.CSV_IMPORT_COLUMNS.COMMENT,
40+
CONST.CSV_IMPORT_COLUMNS.CATEGORY,
41+
CONST.CSV_IMPORT_COLUMNS.TAG,
42+
]);
43+
3544
type WorkspaceCompanyCardsSettingsPageProps = PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.WORKSPACE.COMPANY_CARDS_SETTINGS>;
3645

3746
function WorkspaceCompanyCardsSettingsPage({
@@ -55,7 +64,7 @@ function WorkspaceCompanyCardsSettingsPage({
5564
const {showConfirmModal} = useConfirmModal();
5665

5766
const [cardsList] = useCardsList(selectedFeed);
58-
const icons = useMemoizedLazyExpensifyIcons(['Sync', 'Trashcan']);
67+
const icons = useMemoizedLazyExpensifyIcons(['Sync', 'Trashcan', 'Table']);
5968
const feedName = selectedFeed ? getCustomOrFormattedFeedName(translate, feed, cardFeeds?.[selectedFeed]?.customFeedName) : undefined;
6069
const companyFeeds = getCompanyFeeds(cardFeeds);
6170
const selectedFeedData = selectedFeed ? companyFeeds[selectedFeed] : undefined;
@@ -64,6 +73,10 @@ function WorkspaceCompanyCardsSettingsPage({
6473
const domainOrWorkspaceAccountID = getDomainOrWorkspaceAccountID(workspaceAccountID, selectedFeedData);
6574
const isPending = !!selectedFeedData?.pending;
6675
const isDirectFeedType = isDirectFeed(feed);
76+
const isCsvFeed = isCSVUploadFeed(feed);
77+
const storedMappings = selectedFeedData?.uploadLayoutSettings?.columnMappings;
78+
const hadAdvancedFields = !!storedMappings && Object.keys(storedMappings).some((col) => ADVANCED_CSV_COLUMNS.has(col));
79+
6780
const statementCloseDate = useMemo(() => {
6881
if (!selectedFeedData?.statementPeriodEndDay) {
6982
return undefined;
@@ -173,6 +186,23 @@ function WorkspaceCompanyCardsSettingsPage({
173186
}}
174187
/>
175188
)}
189+
{isCsvFeed && (
190+
<MenuItem
191+
icon={icons.Table}
192+
title={translate('spreadsheet.importSpreadsheet')}
193+
onPress={() => {
194+
setAddNewCompanyCardStepAndData({
195+
data: {
196+
layoutType: feed,
197+
companyCardLayoutName: selectedFeedData?.customFeedName ?? feedName ?? '',
198+
useAdvancedFields: hadAdvancedFields,
199+
existingInstanceID: selectedFeedData?.uploadLayoutSettings?.instanceID ?? null,
200+
},
201+
});
202+
Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_IMPORT_SPREADSHEET.getRoute(policyID));
203+
}}
204+
/>
205+
)}
176206
<MenuItem
177207
icon={icons.Trashcan}
178208
title={translate('workspace.moreFeatures.companyCards.removeCardFeed')}

src/pages/workspace/companyCards/addNew/CompanyCardsImportSpreadsheetPage.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import React from 'react';
22
import ImportSpreadsheet from '@components/ImportSpreadsheet';
3+
import useOnyx from '@hooks/useOnyx';
34
import usePolicy from '@hooks/usePolicy';
45
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
56
import {goBackFromInvalidPolicy} from '@libs/PolicyUtils';
67
import type {WorkspaceSplitNavigatorParamList} from '@navigation/types';
78
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
89
import CONST from '@src/CONST';
10+
import ONYXKEYS from '@src/ONYXKEYS';
911
import ROUTES from '@src/ROUTES';
1012
import type SCREENS from '@src/SCREENS';
1113
import {isEmptyObject} from '@src/types/utils/EmptyObject';
@@ -15,7 +17,9 @@ type CompanyCardsImportSpreadsheetPageProps = PlatformStackScreenProps<Workspace
1517
function CompanyCardsImportSpreadsheetPage({route}: CompanyCardsImportSpreadsheetPageProps) {
1618
const {policyID} = route.params;
1719
const policy = usePolicy(policyID);
18-
const backTo = ROUTES.WORKSPACE_COMPANY_CARDS_ADD_NEW.getRoute(policyID);
20+
const [addNewCard] = useOnyx(ONYXKEYS.ADD_NEW_COMPANY_CARD);
21+
const isEditing = !!addNewCard?.data?.layoutType;
22+
const backTo = isEditing ? ROUTES.WORKSPACE_COMPANY_CARDS_SETTINGS.getRoute(policyID) : ROUTES.WORKSPACE_COMPANY_CARDS_ADD_NEW.getRoute(policyID);
1923
const goTo = ROUTES.WORKSPACE_COMPANY_CARDS_IMPORTED.getRoute(policyID);
2024

2125
return (

src/pages/workspace/companyCards/addNew/CompanyCardsImportedPage.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ function CompanyCardsImportedPage({route}: CompanyCardsImportedPageProps) {
138138
existingCardsList,
139139
lastSelectedFeed: lastSelectedFeed ?? undefined,
140140
workspaceCardFeeds,
141+
existingInstanceID: addNewCard?.data?.existingInstanceID,
141142
});
142143
};
143144

src/types/onyx/CardFeeds.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,13 @@ type CustomCardFeedData = OnyxCommon.OnyxValueWithOfflineFeedback<{
123123
uploadLayoutSettings?: {
124124
/** User-defined name for the CSV upload layout */
125125
layoutName?: string;
126+
127+
/** Unique identifier for this CSV layout instance */
128+
instanceID?: string;
129+
130+
/** Stored column mappings from the most recent CSV import (column name → column index) */
131+
columnMappings?: Record<string, string>;
132+
126133
[key: string]: unknown;
127134
};
128135

@@ -305,6 +312,9 @@ type AddNewCardFeedData = {
305312
/** Whether to use advanced fields in the CSV layout */
306313
useAdvancedFields?: boolean;
307314

315+
/** Existing instance ID when editing a CSV feed */
316+
existingInstanceID?: string;
317+
308318
/** Plaid accounts */
309319
plaidAccounts?: LinkAccount[] | PlaidAccount[];
310320
};

0 commit comments

Comments
 (0)