From 2643e894957c7cb21d7ed1e8f64f916cd6d9400a Mon Sep 17 00:00:00 2001 From: cretadn22 Date: Tue, 17 Sep 2024 22:04:30 +0700 Subject: [PATCH 1/4] display downlaod failure modal --- src/libs/Permissions.ts | 2 +- src/libs/actions/Policy/Category.ts | 4 +-- src/libs/fileDownload/DownloadUtils.ts | 8 +++++- src/libs/fileDownload/index.desktop.ts | 4 +-- .../categories/WorkspaceCategoriesPage.tsx | 25 +++++++++++++++---- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index 8c47100e465b..8b7d92701a55 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -4,7 +4,7 @@ import type {IOUType} from '@src/CONST'; import type Beta from '@src/types/onyx/Beta'; function canUseAllBetas(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.ALL); + return true; } function canUseDefaultRooms(betas: OnyxEntry): boolean { diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index 5716eed8947d..f7685b444e69 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -1001,7 +1001,7 @@ function setPolicyDistanceRatesDefaultCategory(policyID: string, currentCustomUn API.write(WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_DEFAULT_CATEGORY, params, {optimisticData, successData, failureData}); } -function downloadCategoriesCSV(policyID: string) { +function downloadCategoriesCSV(policyID: string, onDownloadFailed?: () => void) { const finalParameters = enhanceParameters(WRITE_COMMANDS.EXPORT_CATEGORIES_CSV, { policyID, }); @@ -1011,7 +1011,7 @@ function downloadCategoriesCSV(policyID: string) { formData.append(key, String(value)); }); - fileDownload(ApiUtils.getCommandURL({command: WRITE_COMMANDS.EXPORT_CATEGORIES_CSV}), 'Categories.csv', '', false, formData, CONST.NETWORK.METHOD.POST); + fileDownload(ApiUtils.getCommandURL({command: WRITE_COMMANDS.EXPORT_CATEGORIES_CSV}), 'Categories.csv', '', false, formData, CONST.NETWORK.METHOD.POST, onDownloadFailed); } function setWorkspaceCategoryDescriptionHint(policyID: string, categoryName: string, commentHint: string) { diff --git a/src/libs/fileDownload/DownloadUtils.ts b/src/libs/fileDownload/DownloadUtils.ts index a09b0aa38c75..4f0ce6ab0c92 100644 --- a/src/libs/fileDownload/DownloadUtils.ts +++ b/src/libs/fileDownload/DownloadUtils.ts @@ -53,7 +53,13 @@ const fetchFileDownload: FileDownload = (url, fileName, successMessage = '', sho }; return fetch(url, fetchOptions) - .then((response) => response.blob()) + .then((response) => { + const contentType = response.headers.get('content-type'); + if (contentType === 'application/json' && fileName?.includes('.csv')) { + throw new Error(); + } + return response.blob(); + }) .then((blob) => { // Create blob link to download const href = URL.createObjectURL(new Blob([blob])); diff --git a/src/libs/fileDownload/index.desktop.ts b/src/libs/fileDownload/index.desktop.ts index de000f61b41b..6a601a4af249 100644 --- a/src/libs/fileDownload/index.desktop.ts +++ b/src/libs/fileDownload/index.desktop.ts @@ -7,10 +7,10 @@ import type {FileDownload} from './types'; /** * The function downloads an attachment on desktop platforms. */ -const fileDownload: FileDownload = (url, fileName, successMessage, shouldOpenExternalLink, formData, requestType) => { +const fileDownload: FileDownload = (url, fileName, successMessage, shouldOpenExternalLink, formData, requestType, onDownloadFailed?: () => void) => { if (requestType === CONST.NETWORK.METHOD.POST) { window.electron.send(ELECTRON_EVENTS.DOWNLOAD); - return fetchFileDownload(url, fileName, successMessage, shouldOpenExternalLink, formData, requestType); + return fetchFileDownload(url, fileName, successMessage, shouldOpenExternalLink, formData, requestType, onDownloadFailed); } const options: Options = { diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 267b8ec52019..11dd49d0befb 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -8,6 +8,7 @@ import Button from '@components/Button'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; import type {DropdownOption} from '@components/ButtonWithDropdownMenu/types'; import ConfirmModal from '@components/ConfirmModal'; +import DecisionModal from '@components/DecisionModal'; import EmptyStateComponent from '@components/EmptyStateComponent'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -54,13 +55,14 @@ type PolicyOption = ListItem & { type WorkspaceCategoriesPageProps = StackScreenProps; function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { - const {shouldUseNarrowLayout} = useResponsiveLayout(); + const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout(); const {windowWidth} = useWindowDimensions(); const styles = useThemeStyles(); const theme = useTheme(); const {translate} = useLocalize(); const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false); const [selectedCategories, setSelectedCategories] = useState>({}); + const [downloadFailureModalVisible, setDownloadFailureModalVisible] = useState(false); const [deleteCategoriesConfirmModalVisible, setDeleteCategoriesConfirmModalVisible] = useState(false); const isFocused = useIsFocused(); const {environmentURL} = useEnvironment(); @@ -308,7 +310,9 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { Navigation.navigate(ROUTES.WORKSPACE_CATEGORIES_IMPORT.getRoute(policyId)); }, }, - { + ]; + if (hasVisibleCategories) { + menuItems.push({ icon: Expensicons.Download, text: translate('spreadsheet.downloadCSV'), onSelected: () => { @@ -316,10 +320,12 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { Modal.close(() => setIsOfflineModalVisible(true)); return; } - Category.downloadCategoriesCSV(policyId); + Category.downloadCategoriesCSV(policyId, () => { + setDownloadFailureModalVisible(true); + }); }, - }, - ]; + }); + } return menuItems; }, [policyId, translate, isOffline]); @@ -415,6 +421,15 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { confirmText={translate('common.buttonConfirm')} shouldShowCancelButton={false} /> + setDownloadFailureModalVisible(false)} + secondOptionText={translate('common.buttonConfirm')} + isVisible={downloadFailureModalVisible} + onClose={() => setDownloadFailureModalVisible(false)} + /> ); From 175fa24a789559942cbcf6a6facf9ae1babeaa2e Mon Sep 17 00:00:00 2001 From: cretadn22 Date: Tue, 17 Sep 2024 22:10:05 +0700 Subject: [PATCH 2/4] update the lint error --- src/libs/Permissions.ts | 2 +- src/pages/workspace/categories/WorkspaceCategoriesPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index 8b7d92701a55..8c47100e465b 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -4,7 +4,7 @@ import type {IOUType} from '@src/CONST'; import type Beta from '@src/types/onyx/Beta'; function canUseAllBetas(betas: OnyxEntry): boolean { - return true; + return !!betas?.includes(CONST.BETAS.ALL); } function canUseDefaultRooms(betas: OnyxEntry): boolean { diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index 11dd49d0befb..b6870702d487 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -328,7 +328,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { } return menuItems; - }, [policyId, translate, isOffline]); + }, [policyId, translate, isOffline, hasVisibleCategories]); const selectionModeHeader = selectionMode?.isEnabled && shouldUseNarrowLayout; From 6bb28d6c9b1caebd86a22e675c7dfaa9b4676ccd Mon Sep 17 00:00:00 2001 From: cretadn22 Date: Wed, 18 Sep 2024 21:57:13 +0700 Subject: [PATCH 3/4] fix bug on IOS --- src/libs/actions/Policy/Category.ts | 2 +- src/libs/fileDownload/index.android.ts | 4 ++++ src/libs/fileDownload/index.ios.ts | 4 ++++ .../categories/WorkspaceCategoriesPage.tsx | 16 +++++++++------- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/libs/actions/Policy/Category.ts b/src/libs/actions/Policy/Category.ts index de277edb6b44..0fe7030dd2e1 100644 --- a/src/libs/actions/Policy/Category.ts +++ b/src/libs/actions/Policy/Category.ts @@ -1001,7 +1001,7 @@ function setPolicyDistanceRatesDefaultCategory(policyID: string, currentCustomUn API.write(WRITE_COMMANDS.SET_POLICY_DISTANCE_RATES_DEFAULT_CATEGORY, params, {optimisticData, successData, failureData}); } -function downloadCategoriesCSV(policyID: string, onDownloadFailed?: () => void) { +function downloadCategoriesCSV(policyID: string, onDownloadFailed: () => void) { const finalParameters = enhanceParameters(WRITE_COMMANDS.EXPORT_CATEGORIES_CSV, { policyID, }); diff --git a/src/libs/fileDownload/index.android.ts b/src/libs/fileDownload/index.android.ts index a1e81e47994d..8426e20a33f7 100644 --- a/src/libs/fileDownload/index.android.ts +++ b/src/libs/fileDownload/index.android.ts @@ -107,6 +107,10 @@ const postDownloadFile = (url: string, fileName?: string, formData?: FormData, o if (!response.ok) { throw new Error('Failed to download file'); } + const contentType = response.headers.get('content-type'); + if (contentType === 'application/json' && fileName?.includes('.csv')) { + throw new Error(); + } return response.text(); }) .then((fileData) => { diff --git a/src/libs/fileDownload/index.ios.ts b/src/libs/fileDownload/index.ios.ts index 1fff9fb998e6..fb2e1c2c146a 100644 --- a/src/libs/fileDownload/index.ios.ts +++ b/src/libs/fileDownload/index.ios.ts @@ -38,6 +38,10 @@ const postDownloadFile = (url: string, fileName?: string, formData?: FormData, o if (!response.ok) { throw new Error('Failed to download file'); } + const contentType = response.headers.get('content-type'); + if (contentType === 'application/json' && fileName?.includes('.csv')) { + throw new Error(); + } return response.text(); }) .then((fileData) => { diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index e4571e0a3d78..478510eae0a1 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -63,7 +63,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { const {translate} = useLocalize(); const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false); const [selectedCategories, setSelectedCategories] = useState>({}); - const [downloadFailureModalVisible, setDownloadFailureModalVisible] = useState(false); + const [isDownloadFailureModalVisible, setIsDownloadFailureModalVisible] = useState(false); const [deleteCategoriesConfirmModalVisible, setDeleteCategoriesConfirmModalVisible] = useState(false); const isFocused = useIsFocused(); const {environmentURL} = useEnvironment(); @@ -323,9 +323,11 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { Modal.close(() => setIsOfflineModalVisible(true)); return; } - Category.downloadCategoriesCSV(policyId, () => { - setDownloadFailureModalVisible(true); - }); + Modal.close(() => { + Category.downloadCategoriesCSV(policyId, () => { + setIsDownloadFailureModalVisible(true); + }); + }) }, }); } @@ -428,10 +430,10 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { title={translate('common.downloadFailedTitle')} prompt={translate('common.downloadFailedDescription')} isSmallScreenWidth={isSmallScreenWidth} - onSecondOptionSubmit={() => setDownloadFailureModalVisible(false)} + onSecondOptionSubmit={() => setIsDownloadFailureModalVisible(false)} secondOptionText={translate('common.buttonConfirm')} - isVisible={downloadFailureModalVisible} - onClose={() => setDownloadFailureModalVisible(false)} + isVisible={isDownloadFailureModalVisible} + onClose={() => setIsDownloadFailureModalVisible(false)} /> From 289faed1fe02641928ab97b27a959c8c092a1a3f Mon Sep 17 00:00:00 2001 From: cretadn22 Date: Wed, 18 Sep 2024 22:06:14 +0700 Subject: [PATCH 4/4] add comma --- 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 478510eae0a1..340bd991c609 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -327,7 +327,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { Category.downloadCategoriesCSV(policyId, () => { setIsDownloadFailureModalVisible(true); }); - }) + }); }, }); }