diff --git a/package-lock.json b/package-lock.json index deb47c70ee6ee..a1796563ec465 100644 --- a/package-lock.json +++ b/package-lock.json @@ -93,7 +93,7 @@ "react-content-loader": "^7.0.0", "react-dom": "19.2.0", "react-error-boundary": "^4.0.11", - "react-fast-pdf": "^1.0.32", + "react-fast-pdf": "^1.0.33", "react-is": "^18.3.1", "react-map-gl": "^7.1.3", "react-native": "0.83.1", diff --git a/package.json b/package.json index a60aa49e5cfae..b2c7bd555eff7 100644 --- a/package.json +++ b/package.json @@ -156,7 +156,7 @@ "react-content-loader": "^7.0.0", "react-dom": "19.2.0", "react-error-boundary": "^4.0.11", - "react-fast-pdf": "^1.0.32", + "react-fast-pdf": "^1.0.33", "react-is": "^18.3.1", "react-map-gl": "^7.1.3", "react-native": "0.83.1", diff --git a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.tsx b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.tsx index e8f6568f98c0b..5196a3a99c660 100644 --- a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.tsx +++ b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.tsx @@ -2,7 +2,7 @@ import React, {memo} from 'react'; import PDFView from '@components/PDFView'; import type AttachmentViewPdfProps from './types'; -function AttachmentViewPdf({file, encryptedSourceUrl, isFocused, onPress, onToggleKeyboard, onLoadComplete, style, isUsedAsChatAttachment, onLoadError}: AttachmentViewPdfProps) { +function AttachmentViewPdf({file, encryptedSourceUrl, isFocused, onPress, onToggleKeyboard, onLoadComplete, style, isUsedAsChatAttachment, onLoadError, rotation}: AttachmentViewPdfProps) { return ( ); } diff --git a/src/components/Attachments/AttachmentView/AttachmentViewPdf/types.ts b/src/components/Attachments/AttachmentView/AttachmentViewPdf/types.ts index dd5bae6e9e7b7..d10e9561735f2 100644 --- a/src/components/Attachments/AttachmentView/AttachmentViewPdf/types.ts +++ b/src/components/Attachments/AttachmentView/AttachmentViewPdf/types.ts @@ -1,3 +1,4 @@ +import type {RotationDegrees} from 'react-fast-pdf'; import type {StyleProp, ViewStyle} from 'react-native'; import type {AttachmentViewProps} from '..'; @@ -16,6 +17,9 @@ type AttachmentViewPdfProps = Pick; + + /** Controlled rotation angle for the PDF */ + rotation?: RotationDegrees; }; function checkIsFileImage(source: string | number | ImageURISource | ImageURISource[], fileName: string | undefined) { @@ -131,6 +135,7 @@ function AttachmentView({ isUploading = false, reportID, transaction: transactionProp, + rotation, }: AttachmentViewProps) { const icons = useMemoizedLazyExpensifyIcons(['ArrowCircleClockwise', 'Gallery']); const [transactionFromOnyx] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${getNonEmptyStringOnyxID(transactionID)}`); @@ -255,6 +260,7 @@ function AttachmentView({ style={isUsedInAttachmentModal ? styles.imageModalPDF : styles.flex1} isUsedAsChatAttachment={isUsedAsChatAttachment} onLoadError={onPDFLoadError} + rotation={rotation} /> ); diff --git a/src/components/PDFView/index.tsx b/src/components/PDFView/index.tsx index 9242f2a1bcadf..195ee25e514ef 100644 --- a/src/components/PDFView/index.tsx +++ b/src/components/PDFView/index.tsx @@ -22,7 +22,7 @@ import type {PDFViewProps} from './types'; const LOADING_THUMBNAIL_HEIGHT = 250; const LOADING_THUMBNAIL_WIDTH = 250; -function PDFView({onToggleKeyboard, fileName, onPress, isFocused, sourceURL, style, isUsedAsChatAttachment, onLoadError}: PDFViewProps) { +function PDFView({onToggleKeyboard, fileName, onPress, isFocused, sourceURL, style, isUsedAsChatAttachment, onLoadError, rotation}: PDFViewProps) { const [isKeyboardOpen, setIsKeyboardOpen] = useState(false); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -117,6 +117,7 @@ function PDFView({onToggleKeyboard, fileName, onPress, isFocused, sourceURL, sty } shouldShowErrorComponent={false} onLoadError={onLoadError} + rotation={rotation} renderPasswordForm={({isPasswordInvalid, onSubmit, onPasswordChange}) => ( @@ -291,6 +293,7 @@ function AttachmentModalBaseContent({ isWorkspaceAvatar, maybeIcon, onNavigate, + pdfRotation, report, reportID, setAttachmentError, diff --git a/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/types.ts b/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/types.ts index 94d737d12ce92..d15d17f528093 100644 --- a/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/types.ts +++ b/src/pages/media/AttachmentModalScreen/AttachmentModalBaseContent/types.ts @@ -1,4 +1,5 @@ import type {RefObject} from 'react'; +import type {RotationDegrees} from 'react-fast-pdf'; import type {StyleProp, View, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; @@ -142,6 +143,9 @@ type AttachmentModalBaseContentProps = { /** Extra styles to pass for the attachment view container */ attachmentViewContainerStyles?: StyleProp; + + /** Controlled rotation angle for the PDF */ + pdfRotation?: RotationDegrees; }; export type { diff --git a/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx b/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx index 37ba7f306c5a6..d49f2e54fdc00 100644 --- a/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx +++ b/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx @@ -1,5 +1,6 @@ import {Str} from 'expensify-common'; import React, {useCallback, useEffect, useMemo, useState} from 'react'; +import type {RotationDegrees} from 'react-fast-pdf'; import {View} from 'react-native'; import Button from '@components/Button'; import ConfirmModal from '@components/ConfirmModal'; @@ -161,11 +162,13 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre const isEReceipt = transaction && !hasReceiptSource(transaction) && hasEReceipt(transaction); const fileName = (isOdometerImage ? odometerFilename : receiptFilename) ?? ''; const isImage = !!fileName && Str.isImage(fileName); + const isPDF = !!fileName && Str.isPDF(fileName); const fileType = isOdometerImage ? odometerFileType : (transaction?.receipt?.type ?? CONST.IMAGE_FILE_FORMAT.JPEG); const isTrackExpenseActionValue = isTrackExpenseAction(parentReportAction); const iouType = useMemo(() => iouTypeParam ?? (isTrackExpenseActionValue ? CONST.IOU.TYPE.TRACK : CONST.IOU.TYPE.SUBMIT), [isTrackExpenseActionValue, iouTypeParam]); const [isDeleteReceiptConfirmModalVisible, setIsDeleteReceiptConfirmModalVisible] = useState(false); + const [pdfRotation, setPdfRotation] = useState(0); const [isRotating, setIsRotating] = useState(false); const [isCropping, setIsCropping] = useState(false); const [isCropSaving, setIsCropSaving] = useState(false); @@ -537,6 +540,14 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre style={styles.transactionReceiptButton} /> )} + {isPDF && !isNative && ( +