From 6c542dfb460ffdab656d6c71af30a24e50da05ef Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Tue, 20 Jan 2026 22:21:58 +0700 Subject: [PATCH 01/39] feat: add crop receipt --- contributingGuides/PROPOSAL_TEMPLATE.md | 54 ++ src/components/ReceiptCropView/index.tsx | 460 ++++++++++++++++++ src/languages/en.ts | 1 + .../AttachmentModalBaseContent/index.tsx | 14 +- .../AttachmentModalBaseContent/types.ts | 6 + .../routes/TransactionReceiptModalContent.tsx | 223 ++++++++- 6 files changed, 751 insertions(+), 7 deletions(-) create mode 100644 src/components/ReceiptCropView/index.tsx diff --git a/contributingGuides/PROPOSAL_TEMPLATE.md b/contributingGuides/PROPOSAL_TEMPLATE.md index 8c9fa7968fe2..2e110587b3fd 100644 --- a/contributingGuides/PROPOSAL_TEMPLATE.md +++ b/contributingGuides/PROPOSAL_TEMPLATE.md @@ -2,13 +2,67 @@ ### Please re-state the problem that we are trying to solve in this issue. +Users viewing receipts in the Transaction Receipt Modal can currently rotate receipts but cannot crop them. When receipts contain unwanted areas (like table surfaces, other items, or excessive whitespace), users have no way to remove these areas before saving. This results in lower quality receipt images that may affect OCR accuracy and visual clarity. + ### What is the root cause of that problem? +The root cause is that the receipt modal UI only exposes rotation functionality through the header's rotate button. There is no crop interface that allows users to: +1. Visually select the area they want to keep +2. Interactively adjust crop boundaries +3. Preview the cropped result before saving + +The underlying `cropOrRotateImage` utility already supports cropping operations (it accepts crop actions with originX, originY, width, and height), but this functionality is not exposed in the UI. + ### What changes do you think we should make in order to solve the problem? +1. **Add action buttons footer**: Create a footer section below the receipt image with three buttons: "Rotate", "Crop", and "Replace". These buttons should be visible when viewing receipts (similar to how the rotate button currently appears in the header, but moved to a footer for better UX). + +2. **Implement crop mode state**: When the "Crop" button is clicked, enter a crop mode that: + - Hides the three action buttons (Rotate, Crop, Replace) + - Shows two buttons instead: "Cancel" (to exit crop mode) and "Save" (to apply the crop) + - Displays a draggable border overlay around the receipt image + +3. **Create draggable crop border component**: Build a `ReceiptCropView` component that: + - Renders a rectangular border with four corner handles (small circular indicators) + - Allows dragging each corner independently to adjust the crop area + - Maintains the crop rectangle bounds within the image boundaries + - Provides visual feedback (e.g., green border color) to indicate the active crop area + - Calculates the crop coordinates (originX, originY, width, height) relative to the original image dimensions + +4. **Integrate crop functionality**: + - When "Save" is clicked in crop mode, calculate the crop parameters based on the current border position + - Use the existing `cropOrRotateImage` function with the crop action + - Update the receipt using the same pattern as the rotate functionality (either `setMoneyRequestReceipt` for draft transactions or `replaceReceipt` for saved transactions) + - Exit crop mode and return to normal view after successful crop + +5. **Update header behavior**: + - Remove the rotate button from the header (it will be in the footer) + - Keep Download and Delete in the three-dots menu in the header as specified + - Ensure the header remains clean with only essential actions + +6. **Handle edge cases**: + - Disable crop mode for e-receipts (similar to how rotate is disabled) + - Ensure crop mode is only available for image files (not PDFs or other formats) + - Prevent crop when receipt is being scanned or has missing smartscan fields + - Handle image loading states appropriately + +The implementation will follow the existing patterns in the codebase: +- Use React Native Gesture Handler for drag interactions (similar to `AvatarCropModal`) +- Leverage the existing `cropOrRotateImage` utility +- Follow the same transaction update patterns used by the rotate feature +- Maintain consistency with the current modal structure and styling + ### What alternative solutions did you explore? (Optional) +1. **Separate crop modal**: Considered opening a dedicated crop modal (like `AvatarCropModal`), but this would require an extra navigation step and break the flow. Inline cropping provides a smoother UX. + +2. **Fixed aspect ratio cropping**: Considered enforcing a fixed aspect ratio, but receipts vary significantly in dimensions, so free-form cropping is more flexible. + +3. **Crop in header menu**: Considered adding crop to the three-dots menu, but having it as a primary action button in the footer makes it more discoverable and accessible. + +4. **Using existing AvatarCropModal**: The `AvatarCropModal` component uses a circular mask and zoom slider, which is optimized for avatars. For receipts, we need a rectangular crop with corner handles, so a new component is more appropriate. + **Reminder:** Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job. -1. **Add action buttons footer**: Create a footer section below the receipt image with three buttons: "Rotate", "Crop", and "Replace". These buttons should be visible when viewing receipts (similar to how the rotate button currently appears in the header, but moved to a footer for better UX). - -2. **Implement crop mode state**: When the "Crop" button is clicked, enter a crop mode that: - - Hides the three action buttons (Rotate, Crop, Replace) - - Shows two buttons instead: "Cancel" (to exit crop mode) and "Save" (to apply the crop) - - Displays a draggable border overlay around the receipt image - -3. **Create draggable crop border component**: Build a `ReceiptCropView` component that: - - Renders a rectangular border with four corner handles (small circular indicators) - - Allows dragging each corner independently to adjust the crop area - - Maintains the crop rectangle bounds within the image boundaries - - Provides visual feedback (e.g., green border color) to indicate the active crop area - - Calculates the crop coordinates (originX, originY, width, height) relative to the original image dimensions - -4. **Integrate crop functionality**: - - When "Save" is clicked in crop mode, calculate the crop parameters based on the current border position - - Use the existing `cropOrRotateImage` function with the crop action - - Update the receipt using the same pattern as the rotate functionality (either `setMoneyRequestReceipt` for draft transactions or `replaceReceipt` for saved transactions) - - Exit crop mode and return to normal view after successful crop - -5. **Update header behavior**: - - Remove the rotate button from the header (it will be in the footer) - - Keep Download and Delete in the three-dots menu in the header as specified - - Ensure the header remains clean with only essential actions - -6. **Handle edge cases**: - - Disable crop mode for e-receipts (similar to how rotate is disabled) - - Ensure crop mode is only available for image files (not PDFs or other formats) - - Prevent crop when receipt is being scanned or has missing smartscan fields - - Handle image loading states appropriately - -The implementation will follow the existing patterns in the codebase: -- Use React Native Gesture Handler for drag interactions (similar to `AvatarCropModal`) -- Leverage the existing `cropOrRotateImage` utility -- Follow the same transaction update patterns used by the rotate feature -- Maintain consistency with the current modal structure and styling - ### What alternative solutions did you explore? (Optional) -1. **Separate crop modal**: Considered opening a dedicated crop modal (like `AvatarCropModal`), but this would require an extra navigation step and break the flow. Inline cropping provides a smoother UX. - -2. **Fixed aspect ratio cropping**: Considered enforcing a fixed aspect ratio, but receipts vary significantly in dimensions, so free-form cropping is more flexible. - -3. **Crop in header menu**: Considered adding crop to the three-dots menu, but having it as a primary action button in the footer makes it more discoverable and accessible. - -4. **Using existing AvatarCropModal**: The `AvatarCropModal` component uses a circular mask and zoom slider, which is optimized for avatars. For receipts, we need a rectangular crop with corner handles, so a new component is more appropriate. - **Reminder:** Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job. + + + + + + + + + + + + \ No newline at end of file From f99444807df65e7978696a829f118a9a7f4ace2e Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Wed, 28 Jan 2026 18:29:49 +0700 Subject: [PATCH 21/39] new crop svg --- assets/images/crop.svg | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/assets/images/crop.svg b/assets/images/crop.svg index a8a79950eec0..43dd4a822ff4 100644 --- a/assets/images/crop.svg +++ b/assets/images/crop.svg @@ -1,15 +1 @@ - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file From e65fd158a4f1d3b074cafb83a91420ad4acb17b3 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 29 Jan 2026 00:05:51 +0700 Subject: [PATCH 22/39] update svg again --- assets/images/crop.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/images/crop.svg b/assets/images/crop.svg index 43dd4a822ff4..efc6018074c9 100644 --- a/assets/images/crop.svg +++ b/assets/images/crop.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From 790b8abfed9244adb9a62c018bac5a6e4bd0416b Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 29 Jan 2026 11:43:28 +0700 Subject: [PATCH 23/39] new crop icon --- assets/images/crop.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/images/crop.svg b/assets/images/crop.svg index efc6018074c9..ad1e0707465b 100644 --- a/assets/images/crop.svg +++ b/assets/images/crop.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From d7de05c50c0b8147dadfe383e1173924b973e615 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 29 Jan 2026 11:45:30 +0700 Subject: [PATCH 24/39] run compress --- assets/images/crop.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/images/crop.svg b/assets/images/crop.svg index ad1e0707465b..2f24c6258fa4 100644 --- a/assets/images/crop.svg +++ b/assets/images/crop.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From 22129cd29f821ae37d3420576c7de72fd71a082a Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 29 Jan 2026 13:46:58 +0700 Subject: [PATCH 25/39] hardcode to rotate icon --- .../routes/TransactionReceiptModalContent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx b/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx index 45a4689a5e11..90d841aee5af 100644 --- a/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx +++ b/src/pages/media/AttachmentModalScreen/routes/TransactionReceiptModalContent.tsx @@ -452,7 +452,7 @@ function TransactionReceiptModalContent({navigation, route}: AttachmentModalScre )} {!!shouldShowRotateAndCropReceiptButton && (