From 9e76b694cca95a09e4d195a78ab688a64896c712 Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Fri, 6 Sep 2024 10:13:01 +0200 Subject: [PATCH 1/4] Categories export done --- src/languages/en.ts | 1 + src/languages/es.ts | 1 + .../parameters/ExportCategoriesSpreadsheet.ts | 6 ++++++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 6 ++++-- src/libs/actions/Policy/Category.ts | 19 ++++++++++++++++++- .../categories/WorkspaceCategoriesPage.tsx | 11 +++++++++++ 7 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 src/libs/API/parameters/ExportCategoriesSpreadsheet.ts diff --git a/src/languages/en.ts b/src/languages/en.ts index c2902dc3d8a5..90892de735a9 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -386,6 +386,7 @@ export default { enabled: 'Enabled', import: 'Import', importSpreadsheet: 'Import spreadsheet', + downloadCSV: 'Download CSV', offlinePrompt: "You can't take this action right now.", outstanding: 'Outstanding', days: 'days', diff --git a/src/languages/es.ts b/src/languages/es.ts index 9ce98e12b135..1efd1dea4d65 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -370,6 +370,7 @@ export default { network: 'La red', reportID: 'ID del informe', importSpreadsheet: 'Importar hoja de cálculo', + downloadCSV: 'Descargar CSV', chooseFile: 'Elegir archivo', dropTitle: 'Suéltalo', dropMessage: 'Suelta tu archivo aquí', diff --git a/src/libs/API/parameters/ExportCategoriesSpreadsheet.ts b/src/libs/API/parameters/ExportCategoriesSpreadsheet.ts new file mode 100644 index 000000000000..e62cbe684cf6 --- /dev/null +++ b/src/libs/API/parameters/ExportCategoriesSpreadsheet.ts @@ -0,0 +1,6 @@ +type ExportCategoriesSpreadsheetParams = { + /** ID of the policy */ + policyID: string; +}; + +export default ExportCategoriesSpreadsheetParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index b58b35e752a1..085e1653f512 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -292,6 +292,7 @@ export type {default as CardDeactivateParams} from './CardDeactivateParams'; export type {default as UpdateExpensifyCardLimitTypeParams} from './UpdateExpensifyCardLimitTypeParams'; export type {default as UpdateQuickbooksOnlineAutoCreateVendorParams} from './UpdateQuickbooksOnlineAutoCreateVendorParams'; export type {default as ImportCategoriesSpreadsheetParams} from './ImportCategoriesSpreadsheet'; +export type {default as ExportCategoriesSpreadsheetParams} from './ExportCategoriesSpreadsheet'; export type {default as UpdateXeroGenericTypeParams} from './UpdateXeroGenericTypeParams'; export type {default as UpdateCardSettlementFrequencyParams} from './UpdateCardSettlementFrequencyParams'; export type {default as UpdateCardSettlementAccountParams} from './UpdateCardSettlementAccountParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index bc2bc5f342af..0850ac74ab72 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -133,7 +133,8 @@ const WRITE_COMMANDS = { SET_WORKSPACE_CATEGORIES_ENABLED: 'SetWorkspaceCategoriesEnabled', SET_POLICY_TAGS_ENABLED: 'SetPolicyTagsEnabled', CREATE_WORKSPACE_CATEGORIES: 'CreateWorkspaceCategories', - IMPORT_CATEGORIES_SREADSHEET: 'ImportCategoriesSpreadsheet', + IMPORT_CATEGORIES_SPREADSHEET: 'ImportCategoriesSpreadsheet', + EXPORT_CATEGORIES_CSV: 'ExportCategoriesCSV', RENAME_WORKSPACE_CATEGORY: 'RenameWorkspaceCategory', CREATE_POLICY_TAG: 'CreatePolicyTag', RENAME_POLICY_TAG: 'RenamePolicyTag', @@ -485,7 +486,8 @@ type WriteCommandParameters = { [WRITE_COMMANDS.CREATE_WORKSPACE_FROM_IOU_PAYMENT]: Parameters.CreateWorkspaceFromIOUPaymentParams; [WRITE_COMMANDS.SET_WORKSPACE_CATEGORIES_ENABLED]: Parameters.SetWorkspaceCategoriesEnabledParams; [WRITE_COMMANDS.CREATE_WORKSPACE_CATEGORIES]: Parameters.CreateWorkspaceCategoriesParams; - [WRITE_COMMANDS.IMPORT_CATEGORIES_SREADSHEET]: Parameters.ImportCategoriesSpreadsheetParams; + [WRITE_COMMANDS.IMPORT_CATEGORIES_SPREADSHEET]: Parameters.ImportCategoriesSpreadsheetParams; + [WRITE_COMMANDS.EXPORT_CATEGORIES_CSV]: Parameters.ExportCategoriesSpreadsheetParams; [WRITE_COMMANDS.RENAME_WORKSPACE_CATEGORY]: Parameters.RenameWorkspaceCategoriesParams; [WRITE_COMMANDS.SET_WORKSPACE_REQUIRES_CATEGORY]: Parameters.SetWorkspaceRequiresCategoryParams; [WRITE_COMMANDS.DELETE_WORKSPACE_CATEGORIES]: Parameters.DeleteWorkspaceCategoriesParams; diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index 4be9c8d37d63..5e868481a61b 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -4,10 +4,13 @@ import Onyx from 'react-native-onyx'; import * as API from '@libs/API'; import type {EnablePolicyCategoriesParams, OpenPolicyCategoriesPageParams, SetPolicyDistanceRatesDefaultCategoryParams, UpdatePolicyCategoryGLCodeParams} from '@libs/API/parameters'; import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; +import * as ApiUtils from '@libs/ApiUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; +import fileDownload from '@libs/fileDownload'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import {translateLocal} from '@libs/Localize'; import Log from '@libs/Log'; +import enhanceParameters from '@libs/Network/enhanceParameters'; import * as OptionsListUtils from '@libs/OptionsListUtils'; import {navigateWhenEnableFeature, removePendingFieldsFromCustomUnit} from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -307,7 +310,7 @@ function importPolicyCategories(policyID: string, categories: PolicyCategory[]) categories: JSON.stringify([...categories.map((category) => ({name: category.name, enabled: category.enabled, 'GL Code': String(category['GL Code'])}))]), }; - API.write(WRITE_COMMANDS.IMPORT_CATEGORIES_SREADSHEET, parameters, onyxData); + API.write(WRITE_COMMANDS.IMPORT_CATEGORIES_SPREADSHEET, parameters, onyxData); } function renamePolicyCategory(policyID: string, policyCategory: {oldName: string; newName: string}) { @@ -793,6 +796,19 @@ function setPolicyDistanceRatesDefaultCategory(policyID: string, currentCustomUn API.write(WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_DEFAULT_CATEGORY, params, {optimisticData, successData, failureData}); } +function downloadCategoriesCSV(policyID: string) { + const finalParameters = enhanceParameters(WRITE_COMMANDS.EXPORT_CATEGORIES_CSV, { + policyID, + }); + + const formData = new FormData(); + Object.entries(finalParameters).forEach(([key, value]) => { + formData.append(key, String(value)); + }); + + fileDownload(ApiUtils.getCommandURL({command: WRITE_COMMANDS.EXPORT_CATEGORIES_CSV}), 'Categories.csv', '', false, formData, CONST.NETWORK.METHOD.POST); +} + export { openPolicyCategoriesPage, buildOptimisticPolicyRecentlyUsedCategories, @@ -808,4 +824,5 @@ export { deleteWorkspaceCategories, buildOptimisticPolicyCategories, importPolicyCategories, + downloadCategoriesCSV, }; diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index a720b3f0e568..b98c487b6051 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -309,6 +309,17 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { Navigation.navigate(ROUTES.WORKSPACE_CATEGORIES_IMPORT.getRoute(policyId)); }, }, + { + icon: Expensicons.Download, + text: translate('common.downloadCSV'), + onSelected: () => { + if (isOffline) { + setIsOfflineModalVisible(true); + return; + } + Category.downloadCategoriesCSV(policyId); + }, + }, ]; return menuItems; From b35465e2af527f56ee26185c367fe27de8e7fc9b Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Fri, 6 Sep 2024 11:51:25 +0200 Subject: [PATCH 2/4] swm review fixes --- src/languages/en.ts | 4 ++-- src/languages/es.ts | 4 ++-- src/pages/workspace/categories/WorkspaceCategoriesPage.tsx | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 90892de735a9..ea28f9e6dabb 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -385,8 +385,6 @@ export default { ignore: 'Ignore', enabled: 'Enabled', import: 'Import', - importSpreadsheet: 'Import spreadsheet', - downloadCSV: 'Download CSV', offlinePrompt: "You can't take this action right now.", outstanding: 'Outstanding', days: 'days', @@ -690,6 +688,8 @@ export default { importFailedDescription: 'Please ensure all fields are filled out correctly and try again. If the problem persists, please reach out to Concierge.', invalidFileMessage: 'The file you uploaded is either empty or contains invalid data. Please ensure that the file is correctly formatted and contains the necessary information before uploading it again.', + importSpreadsheet: 'Import spreadsheet', + downloadCSV: 'Download CSV', }, receipt: { upload: 'Upload receipt', diff --git a/src/languages/es.ts b/src/languages/es.ts index 1efd1dea4d65..0b00013f72df 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -369,8 +369,6 @@ export default { filterLogs: 'Registros de filtrado', network: 'La red', reportID: 'ID del informe', - importSpreadsheet: 'Importar hoja de cálculo', - downloadCSV: 'Descargar CSV', chooseFile: 'Elegir archivo', dropTitle: 'Suéltalo', dropMessage: 'Suelta tu archivo aquí', @@ -683,6 +681,8 @@ export default { importSuccessfullTitle: 'Importar categorías', invalidFileMessage: 'El archivo que ha cargado está vacío o contiene datos no válidos. Asegúrese de que el archivo tiene el formato correcto y contiene la información necesaria antes de volver a cargarlo.', + importSpreadsheet: 'Importar hoja de cálculo', + downloadCSV: 'Descargar CSV', }, receipt: { upload: 'Subir recibo', diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index b98c487b6051..06652db01dbf 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -36,6 +36,7 @@ import Navigation from '@libs/Navigation/Navigation'; import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; import * as PolicyUtils from '@libs/PolicyUtils'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import * as Modal from '@userActions/Modal'; import {deleteWorkspaceCategories, setWorkspaceCategoryEnabled} from '@userActions/Policy/Category'; import * as Category from '@userActions/Policy/Category'; import CONST from '@src/CONST'; @@ -300,7 +301,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { const menuItems = [ { icon: Expensicons.Table, - text: translate('common.importSpreadsheet'), + text: translate('spreadsheet.importSpreadsheet'), onSelected: () => { if (isOffline) { setIsOfflineModalVisible(true); @@ -311,10 +312,10 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { }, { icon: Expensicons.Download, - text: translate('common.downloadCSV'), + text: translate('spreadsheet.downloadCSV'), onSelected: () => { if (isOffline) { - setIsOfflineModalVisible(true); + Modal.close(() => setIsOfflineModalVisible(true)); return; } Category.downloadCategoriesCSV(policyId); From 4f695c627e8d0125a3e9698255f5961039a318e0 Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Fri, 6 Sep 2024 12:43:23 +0200 Subject: [PATCH 3/4] add solve for imports from #48623 --- src/pages/workspace/categories/WorkspaceCategoriesPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 06652db01dbf..2de1d33e2765 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -304,7 +304,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { text: translate('spreadsheet.importSpreadsheet'), onSelected: () => { if (isOffline) { - setIsOfflineModalVisible(true); + Modal.close(() => setIsOfflineModalVisible(true)); return; } Navigation.navigate(ROUTES.WORKSPACE_CATEGORIES_IMPORT.getRoute(policyId)); From 0b87e4fd8f51f5ed72ff678b4c17ac4c1f515d77 Mon Sep 17 00:00:00 2001 From: Wiktor Gut Date: Mon, 9 Sep 2024 10:41:56 +0200 Subject: [PATCH 4/4] downloading on Android solved --- src/components/ImportSpreadsheet.tsx | 2 +- src/libs/fileDownload/index.android.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ImportSpreadsheet.tsx b/src/components/ImportSpreadsheet.tsx index fd75bfc2d3b5..8aed242987fd 100644 --- a/src/components/ImportSpreadsheet.tsx +++ b/src/components/ImportSpreadsheet.tsx @@ -167,7 +167,7 @@ function ImportSpreedsheet({backTo, goTo}: ImportSpreedsheetProps) { Navigation.navigate(backTo)} /> diff --git a/src/libs/fileDownload/index.android.ts b/src/libs/fileDownload/index.android.ts index 83255231d26b..a1e81e47994d 100644 --- a/src/libs/fileDownload/index.android.ts +++ b/src/libs/fileDownload/index.android.ts @@ -111,8 +111,7 @@ const postDownloadFile = (url: string, fileName?: string, formData?: FormData, o }) .then((fileData) => { const finalFileName = FileUtils.appendTimeToFileName(fileName ?? 'Expensify'); - const downloadPath = `${RNFS.DownloadDirectoryPath}/Expensify/${finalFileName}`; - + const downloadPath = `${RNFS.DownloadDirectoryPath}/${finalFileName}`; return RNFS.writeFile(downloadPath, fileData, 'utf8').then(() => downloadPath); }) .then((downloadPath) =>