diff --git a/src/libs/fileDownload/FileUtils.ts b/src/libs/fileDownload/FileUtils.ts index e0db610c6215..39c096ebb3ac 100644 --- a/src/libs/fileDownload/FileUtils.ts +++ b/src/libs/fileDownload/FileUtils.ts @@ -254,6 +254,25 @@ function base64ToFile(base64: string, filename: string): File { return file; } +/** + * Converts a File instance in to base64 encoded image. + * + * @param file - The File instance with image. + * @returns string with base64 encoding of image. + */ +function fileToBase64(file?: File) { + return new Promise((resolve, reject) => { + if (!file) { + resolve(''); + return; + } + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve(reader.result as string); + reader.onerror = (error) => reject(error); + }); +} + function validateImageForCorruption(file: FileObject): Promise<{width: number; height: number} | void> { if (!Str.isImage(file.name ?? '') || !file.uri) { return Promise.resolve(); @@ -669,6 +688,7 @@ export { appendTimeToFileName, readFileAsync, base64ToFile, + fileToBase64, isLocalFile, validateImageForCorruption, isImage, diff --git a/src/pages/workspace/duplicate/WorkspaceDuplicateForm.tsx b/src/pages/workspace/duplicate/WorkspaceDuplicateForm.tsx index 3b19e8101c1d..4105aa64fab0 100644 --- a/src/pages/workspace/duplicate/WorkspaceDuplicateForm.tsx +++ b/src/pages/workspace/duplicate/WorkspaceDuplicateForm.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useState} from 'react'; +import React, {useCallback, useMemo, useState} from 'react'; import {View} from 'react-native'; import AvatarWithImagePicker from '@components/AvatarWithImagePicker'; import FormProvider from '@components/Form/FormProvider'; @@ -17,6 +17,7 @@ import useWorkspaceConfirmationAvatar from '@hooks/useWorkspaceConfirmationAvata import {generatePolicyID, setDuplicateWorkspaceData} from '@libs/actions/Policy/Policy'; import type {CustomRNImageManipulatorResult} from '@libs/cropOrRotateImage/types'; import {addErrorMessage} from '@libs/ErrorUtils'; +import {fileToBase64} from '@libs/fileDownload/FileUtils'; import getFirstAlphaNumericCharacter from '@libs/getFirstAlphaNumericCharacter'; import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils'; import {isRequiredFulfilled} from '@libs/ValidationUtils'; @@ -36,6 +37,7 @@ function WorkspaceDuplicateForm({policyID}: WorkspaceDuplicateFormProps) { const {inputCallbackRef} = useAutoFocusInput(); const policy = usePolicy(policyID); const defaultWorkspaceName = `${policy?.name} (${translate('workspace.common.duplicateWorkspacePrefix')})`; + const newPolicyID = useMemo(generatePolicyID, []); const validate = useCallback( (values: FormOnyxValues) => { @@ -60,11 +62,12 @@ function WorkspaceDuplicateForm({policyID}: WorkspaceDuplicateFormProps) { if (!policyID) { return; } - const newPolicyID = generatePolicyID(); - setDuplicateWorkspaceData({policyID: newPolicyID, name, file: avatarFile}); + fileToBase64(avatarFile as File | undefined).then((base64) => { + setDuplicateWorkspaceData({policyID: newPolicyID, name, file: base64}); + }); Navigation.navigate(ROUTES.WORKSPACE_DUPLICATE_SELECT_FEATURES.getRoute(policyID, ROUTES.WORKSPACES_LIST.route)); }, - [policyID], + [policyID, newPolicyID], ); const [workspaceNameFirstCharacter, setWorkspaceNameFirstCharacter] = useState(defaultWorkspaceName ?? ''); @@ -79,7 +82,7 @@ function WorkspaceDuplicateForm({policyID}: WorkspaceDuplicateFormProps) { const stashedLocalAvatarImage = workspaceAvatar?.avatarUri ?? undefined; const DefaultAvatar = useWorkspaceConfirmationAvatar({ - policyID, + policyID: newPolicyID, // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- nullish coalescing cannot be used if left side can be empty string source: stashedLocalAvatarImage || getDefaultWorkspaceAvatar(workspaceNameFirstCharacter), name: workspaceNameFirstCharacter, diff --git a/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx b/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx index 8c5e34df83aa..c5f2f7d6d051 100644 --- a/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx +++ b/src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx @@ -10,6 +10,7 @@ import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; +import {base64ToFile} from '@libs/fileDownload/FileUtils'; import {getDistanceRateCustomUnit, getMemberAccountIDsForWorkspace, getPerDiemCustomUnit, isCollectPolicy} from '@libs/PolicyUtils'; import {getReportFieldsByPolicyID} from '@libs/ReportUtils'; import Navigation from '@navigation/Navigation'; @@ -239,7 +240,7 @@ function WorkspaceDuplicateSelectFeaturesForm({policyID}: WorkspaceDuplicateForm invoices: selectedItems.includes('invoices'), exportLayouts: selectedItems.includes('workflows'), }, - file: duplicateWorkspace?.file, + file: duplicateWorkspace?.file ? base64ToFile(duplicateWorkspace?.file, 'tmpfile') : undefined, }); Navigation.closeRHPFlow(); }, [duplicateWorkspace?.file, duplicateWorkspace?.name, duplicateWorkspace?.policyID, policy, policyCategories, selectedItems, translate]); diff --git a/src/types/onyx/DuplicateWorkspace.ts b/src/types/onyx/DuplicateWorkspace.ts index 453cdfb441a5..14854ea5868a 100644 --- a/src/types/onyx/DuplicateWorkspace.ts +++ b/src/types/onyx/DuplicateWorkspace.ts @@ -1,4 +1,3 @@ -import type {CustomRNImageManipulatorResult} from '@libs/cropOrRotateImage/types'; import type * as OnyxCommon from './OnyxCommon'; /** Model of plaid data */ @@ -10,7 +9,7 @@ type DuplicateWorkspace = { name?: string; /** Workspace avatar */ - file?: File | CustomRNImageManipulatorResult; + file?: string; /** Whether the data is being fetched from server */ isLoading?: boolean;