Skip to content

Conversation

@DecodeX15
Copy link
Contributor

@DecodeX15 DecodeX15 commented Sep 24, 2025

Adding feature regarding this issue #528 - Add Zoom-on-Scroll Support in Media View

This PR adds zoom in and out on scroll down and up
Wherever mouse is, the zoom or scale factor will be large for that area (as shown in the video)

after adding this feature
https://github.com/user-attachments/assets/6c3b437e-59b2-427b-ad5e-66db844a378c

sir requested to correct the logic so after logic correctiion

Recording.2025-10-07.120644.1.mp4

Summary by CodeRabbit

  • New Features

    • Interactive zoom, pan and pinch controls with dedicated zoom in/out/reset actions.
    • UI buttons can now programmatically control viewer zoom and reset; zoom integrates with slideshow actions.
  • Style

    • Improved media viewer layout and image styling for smoother dragging, rotation, and transitions.
  • Bug Fixes

    • Robust fallback for missing or errored images retained.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

ImageViewer was refactored to use react-zoom-pan-pinch (TransformWrapper/TransformComponent) and now exposes an imperative ImageViewerRef (zoomIn/zoomOut/reset) via forwardRef and a resetSignal prop; MediaView now holds a ref and uses new zoom/reset handlers; OpenAPI schemas added additionalProperties; dependency added.

Changes

Cohort / File(s) Summary
Image viewer refactor & zoom/pan integration
frontend/src/components/Media/ImageViewer.tsx
Replaced inline transform/scale/position logic with TransformWrapper/TransformComponent from react-zoom-pan-pinch; removed scale and position props; added resetSignal?: number prop; exported ImageViewer as forwardRef<ImageViewerRef, ImageViewerProps>; added ImageViewerRef interface exposing zoomIn, zoomOut, reset; uses transformRef and useImperativeHandle; image wrapped in TransformComponent with wrapperStyle/contentStyle; retains fallback image handling.
Parent integration: ref + reset/zoom handlers
frontend/src/components/Media/MediaView.tsx
Added useRef and ImageViewerRef-typed imageViewerRef; introduced resetSignal state and handlers handleZoomIn, handleZoomOut, handleResetZoom that call imageViewerRef.current methods and update resetSignal; passes ref and resetSignal to ImageViewer; adjusted container overflow and removed direct reliance on viewState.scale/viewState.position.
OpenAPI schema loosened
docs/backend/backend_python/openapi.json
Added "additionalProperties": true to two object schemas within anyOf selectors for metadata-like fields, allowing extra arbitrary properties.
Dependency added
frontend/package.json
Added runtime dependency react-zoom-pan-pinch (^3.7.0).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant MediaView
    participant ImageViewer as ImageViewer (forwardRef)
    participant Transform as TransformWrapper/TransformComponent
    participant IMG as <img>

    User->>MediaView: open image / interact
    MediaView->>ImageViewer: render with `ref` and `resetSignal`
    ImageViewer->>Transform: mount wrapper/component
    Transform->>IMG: render image with transform styles

    alt User zooms/pans
        User->>IMG: scroll/pinch/drag
        IMG->>Transform: input events
        Transform->>IMG: update scale/translate
    end

    alt Parent calls methods
        MediaView->>ImageViewer: call zoomIn/zoomOut/reset
        ImageViewer->>Transform: invoke control methods via transformRef
        Transform->>IMG: update transform
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰
I nudged the pic with a gentle paw,
Wrapped it round so you can saw,
Zoom and reset at my command,
Pixels hop at my light hand,
A tiny rabbit's joyous law.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Zoom-on-Scroll Support in Image Preiew" is directly related to and clearly summarizes the main change in the changeset. The PR's primary objective, as stated in the PR description, is to "add zoom-in and zoom-out on mouse scroll for image/media preview," which the title accurately captures. The core implementation changes involve refactoring the ImageViewer component to support zoom controls via react-zoom-pan-pinch and updating MediaView to expose zoom/pan functionality through imperative methods. The title is concise and specific enough that a reviewer scanning the commit history would immediately understand the feature being added. However, there is a minor typo: "Preiew" should be "Preview," which slightly detracts from clarity.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 24f30c9 and 5c53ba9.

📒 Files selected for processing (1)
  • frontend/src/components/Media/MediaView.tsx (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/components/Media/MediaView.tsx (2)
frontend/src/components/Media/ImageViewer.tsx (2)
  • ImageViewerRef (18-22)
  • ImageViewer (24-106)
frontend/src/hooks/useKeyboardNavigation.ts (1)
  • useKeyboardNavigation (13-50)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Tauri Build Check (macos-latest, --target aarch64-apple-darwin)
  • GitHub Check: Tauri Build Check (windows-latest)
  • GitHub Check: Tauri Build Check (ubuntu-22.04)
  • GitHub Check: Backend Tests
🔇 Additional comments (1)
frontend/src/components/Media/MediaView.tsx (1)

147-165: Unable to verify the stated requirements for cursor-relative zoom.

The original review makes specific claims about "PR objectives describing zoom-on-scroll support with cursor-relative zoom" and references a "previous review" that I cannot access or find in the codebase. While I can confirm that:

  • Current code has no onWheel handler in MediaView.tsx
  • react-zoom-pan-pinch handles wheel events by default (though not necessarily with cursor-relative anchoring)
  • No TODO/FIXME comments about cursor-relative zoom exist in the codebase

I cannot verify the actual PR requirements because the GitHub PR description is not accessible. Additionally, the suggested diff in the original review has issues: it wraps ImageViewer with a wheel handler but calls zoomIn/zoomOut without actually passing cursor coordinates, which wouldn't implement true cursor-relative zoom anyway.

Action needed: Confirm whether cursor-relative zoom is an actual requirement. If it is, the current implementation may be incomplete. If wheel zoom is working as intended, then no changes are needed.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
frontend/src/components/Media/ImageCard.tsx (1)

35-37: Drop debug console.log in click handler.

Avoids noisy logs and accidental PII leakage.

Apply this diff:

-    console.log(imageIndex);
     dispatch(setCurrentViewIndex(imageIndex));
frontend/src/components/Media/MediaView.tsx (1)

107-107: Remove commented-out dead code.

Keeps the file clean.

-  // const [mouselocation, setMouselocation] = useState({x:0,y:0});
frontend/src/components/Media/ImageViewer.tsx (1)

52-59: Transform-origin and containment updates look good.

This aligns with wheel-zoom math. Consider adding willChange: 'transform' for smoother animations on capable devices.

Optional:

           transition: isDragging ? 'none' : 'transform 0.2s ease-in-out',
           cursor: isDragging ? 'grabbing' : 'grab',
+          willChange: 'transform',
           maxWidth: '100%',
           maxHeight: '100%',
           userSelect: 'none',
           objectFit: 'contain',
frontend/src/pages/Home/Home.tsx (1)

32-32: Remove stray console.log (frontend/src/pages/Home/Home.tsx:32)

This log is noisy and can trigger react-hooks/exhaustive-deps warnings; remove it or move it into a useEffect keyed on displayImages.

Apply this diff:

-    console.log(displayImages);

Or keep for debugging:

useEffect(() => {
  if (process.env.NODE_ENV !== 'production') {
    // eslint-disable-next-line no-console
    console.log(displayImages);
  }
}, [displayImages]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73fa275 and 4e03380.

📒 Files selected for processing (5)
  • frontend/src/components/Media/ImageCard.tsx (1 hunks)
  • frontend/src/components/Media/ImageViewer.tsx (1 hunks)
  • frontend/src/components/Media/MediaView.tsx (2 hunks)
  • frontend/src/hooks/useImageViewControls.ts (2 hunks)
  • frontend/src/pages/Home/Home.tsx (1 hunks)

Comment on lines 128 to 131
onWheel={(e) => {
const rect = e.currentTarget.getBoundingClientRect();
handlers.handleWheelZoom(e, rect);
}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Pass the image element’s rect to wheel-zoom to keep the cursor anchored.

Using the container’s rect causes anchor drift with centered layout. Query the child img’s rect.

Apply this diff:

-        onWheel={(e) => {
-          const rect = e.currentTarget.getBoundingClientRect();
-          handlers.handleWheelZoom(e, rect);
-        }}
+        onWheel={(e) => {
+          const img =
+            (e.currentTarget as HTMLElement).querySelector('img') ?? undefined;
+          const rect =
+            img?.getBoundingClientRect() ?? e.currentTarget.getBoundingClientRect();
+          handlers.handleWheelZoom(e, rect);
+        }}

Note: This avoids ref pluming. If you prefer a stricter approach, forward a ref from ImageViewer to the img and use that rect directly.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onWheel={(e) => {
const rect = e.currentTarget.getBoundingClientRect();
handlers.handleWheelZoom(e, rect);
}}
onWheel={(e) => {
const img =
(e.currentTarget as HTMLElement).querySelector('img') ?? undefined;
const rect =
img?.getBoundingClientRect() ?? e.currentTarget.getBoundingClientRect();
handlers.handleWheelZoom(e, rect);
}}
🤖 Prompt for AI Agents
In frontend/src/components/Media/MediaView.tsx around lines 128-131, the onWheel
handler currently grabs the container's bounding rect which causes anchor drift;
change it to get the child img element's bounding rect (e.g., find the img via
e.currentTarget.querySelector('img') and call getBoundingClientRect() on that
node) and pass that rect to handlers.handleWheelZoom; if the img is not found,
fall back to the container rect. Alternatively, if you prefer stricter typing
and no DOM queries, forward a ref from ImageViewer to the img and use that
ref.current.getBoundingClientRect() instead.

@github-actions github-actions bot added UI good first issue Good for newcomers labels Oct 2, 2025
@rahulharpal1603 rahulharpal1603 added the enhancement New feature or request label Oct 2, 2025
@rahulharpal1603
Copy link
Contributor

@Vaibhaviitian

Please fix the linting errors

@DecodeX15
Copy link
Contributor Author

@rahulharpal1603 done sir

Copy link
Contributor

@rahulharpal1603 rahulharpal1603 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current approach doesn't seem very intuitive. When I have my mouse pointer on the door handle, it should zoom near that thing, not anywhere else (See the attached video)

2025-10-07.00-44-31.mov

@DecodeX15
Copy link
Contributor Author

DecodeX15 commented Oct 6, 2025

The current approach doesn't seem very intuitive. When I have my mouse pointer on the door handle, it should zoom near that thing, not anywhere else (See the attached video)

2025-10-07.00-44-31.mov

sir i had tried to make as ideal zoom work but what happens when user scrolled for first time then the x,y coordinate for the user cursor get changed and then scaling happening with respect to that new x,y so this was the issue i had faced ,
so sir let me know if i haave to work more on it

@rahulharpal1603
Copy link
Contributor

The current approach doesn't seem very intuitive. When I have my mouse pointer on the door handle, it should zoom near that thing, not anywhere else (See the attached video)

2025-10-07.00-44-31.mov

sir i had tried to make as ideal zoom work but what happens when user scrolled for first time then the x,y coordinate for the user cursor get changed and then scaling happening with respect to that new x,y so this was the issue i had faced ,
so sir let me know if i haave to work more on it

Yes, you have to improve it.

@DecodeX15
Copy link
Contributor Author

The current approach doesn't seem very intuitive. When I have my mouse pointer on the door handle, it should zoom near that thing, not anywhere else (See the attached video)
2025-10-07.00-44-31.mov

sir i had tried to make as ideal zoom work but what happens when user scrolled for first time then the x,y coordinate for the user cursor get changed and then scaling happening with respect to that new x,y so this was the issue i had faced ,
so sir let me know if i haave to work more on it

Yes, you have to improve it.

ok sir

@DecodeX15
Copy link
Contributor Author

The current approach doesn't seem very intuitive. When I have my mouse pointer on the door handle, it should zoom near that thing, not anywhere else (See the attached video)
2025-10-07.00-44-31.mov

sir i had tried to make as ideal zoom work but what happens when user scrolled for first time then the x,y coordinate for the user cursor get changed and then scaling happening with respect to that new x,y so this was the issue i had faced ,
so sir let me know if i haave to work more on it

Yes, you have to improve it.

Sir i had updated the logic and i have added new video in pr please revview

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
frontend/src/components/Media/MediaView.tsx (1)

143-143: Anchor drift issue already flagged in previous review.

A previous review comment already identified that using the container's rect causes anchor drift during wheel zoom. The suggested fix is to query the child img element's rect instead. This aligns with the zoom positioning issues you mentioned in the PR comments.

Please refer to the previous review comment for the suggested solution.

🧹 Nitpick comments (1)
frontend/src/components/Media/MediaView.tsx (1)

106-106: Remove commented-out code.

Commented-out code should be removed to keep the codebase clean. If this state is needed in the future, it can be retrieved from version control.

Apply this diff to remove the commented-out code:

-  // const [mouselocation, setMouselocation] = useState({x:0,y:0});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08f56f6 and 1142f6b.

📒 Files selected for processing (3)
  • frontend/src/components/Media/ImageViewer.tsx (2 hunks)
  • frontend/src/components/Media/MediaView.tsx (3 hunks)
  • frontend/src/hooks/useImageViewControls.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/src/components/Media/ImageViewer.tsx
  • frontend/src/hooks/useImageViewControls.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Tauri Build Check (windows-latest)
  • GitHub Check: Tauri Build Check (ubuntu-22.04)
  • GitHub Check: Tauri Build Check (macos-latest, --target aarch64-apple-darwin)
  • GitHub Check: Backend Tests
🔇 Additional comments (2)
frontend/src/components/Media/MediaView.tsx (2)

140-142: LGTM!

The simplified onClick handler is cleaner and maintains the same functionality.


149-149: NavigationButtons signature includes onNext prop Verified that NavigationButtonsProps defines onNext and the component destructures it.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
frontend/src/hooks/useImageViewControls.ts (1)

20-45: Zoom anchor still drifts; container rect ≠ image rect when image is centered.

The previous review flagged that using the container's bounding rect causes zoom drift when the image is centered (flex layout). The current implementation still retrieves the parent element's rect (line 26) and computes mouse coordinates relative to it (lines 27-28), which doesn't account for the image's actual position within that container.

Why this causes drift:

  • The image is centered in its container (likely via flex layout)
  • transformOrigin: 'top left' means transforms are anchored to the image's top-left corner
  • When you compute mouseX/Y relative to the container's top-left, you're not accounting for the gap between the container edge and the image edge
  • Each zoom adjusts position.x/y, but the baseline is wrong, so the cursor "slips" after the first scroll

The fix: Pass the image element's getBoundingClientRect() (not the parent's) to the handler, either as a parameter or by directly accessing the image ref. The previous review provides a comprehensive solution with the correct math.

🧹 Nitpick comments (1)
frontend/src/hooks/useImageViewControls.ts (1)

24-26: Consider passing the rect explicitly for robustness.

Traversing the DOM via e.currentTarget.parentElement assumes a specific DOM structure. If the component layout changes (e.g., wrapper div added), this breaks.

Instead, consider passing the image element's rect as a parameter to handleWheelZoom, or use a ref to the image directly. This makes the code more resilient and easier to test.

Example signature:

const handleWheelZoom = useCallback((e: React.WheelEvent, imageRect: DOMRect) => {
  e.preventDefault();
  e.stopPropagation();
  // Use imageRect directly...
}, []);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1142f6b and f7ea813.

📒 Files selected for processing (2)
  • frontend/src/components/Media/ImageViewer.tsx (2 hunks)
  • frontend/src/hooks/useImageViewControls.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/Media/ImageViewer.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Backend Tests
  • GitHub Check: Tauri Build Check (macos-latest, --target aarch64-apple-darwin)
  • GitHub Check: Tauri Build Check (windows-latest)
  • GitHub Check: Tauri Build Check (ubuntu-22.04)

@DecodeX15
Copy link
Contributor Author

@rahulharpal1603 sir please review this

Copy link
Contributor

@rahulharpal1603 rahulharpal1603 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vertical images are being displayed as zoomed in by default:

Current behaviour:
image

Expected behaviour:
image

Image link: https://unsplash.com/photos/brown-gondola-on-body-of-water-XG391m6rH_8

{/* Main viewer area */}
<div
className="relative flex h-full w-full items-center justify-center"
className="relativ flex h-full w-full"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be relative

@DecodeX15
Copy link
Contributor Author

@rahulharpal1603 sir i opened some vertical images but seems no issue see the video i had attached

@DecodeX15
Copy link
Contributor Author

Recording.2025-10-19.131926.mp4

see it sir @rahulharpal1603 , and i corrected relative

@rahulharpal1603
Copy link
Contributor

Recording.2025-10-19.131926.mp4
see it sir @rahulharpal1603 , and i corrected relative

Don't take a screenshot of the boat image. Download its full resolution version and then show how it's being displayed.
link: https://images.unsplash.com/photo-1544376798-89aa6b82c6cd?ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&q=80&w=774

@DecodeX15
Copy link
Contributor Author

so sir i think it is not a problem that boat image have large dimension that is the issue if you makes it dimension shorter then it would be correct

@DecodeX15
Copy link
Contributor Author

let me know sir for further moves

@rahulharpal1603
Copy link
Contributor

so sir i think it is not a problem that boat image have large dimension that is the issue if you makes it dimension shorter then it would be correct

If you open a branch without all your 9 commits and then test with the boat image, then the correct behaviour is there. After your commits, this issue is occuring.

@DecodeX15
Copy link
Contributor Author

so sir i think it is not a problem that boat image have large dimension that is the issue if you makes it dimension shorter then it would be correct

If you open a branch without all your 9 commits and then test with the boat image, then the correct behaviour is there. After your commits, this issue is occuring.

okay sir let me check

@DecodeX15
Copy link
Contributor Author

so sir i think it is not a problem that boat image have large dimension that is the issue if you makes it dimension shorter then it would be correct

If you open a branch without all your 9 commits and then test with the boat image, then the correct behaviour is there. After your commits, this issue is occuring.

sir i had tried to fix it but not able to figure out it. 😞😞😞😞😞😞😞😞😞😞
actually sir when you told me to update the functionality then i had implemented the zoom by shifting the coordinate control to the image using CSS transforms. now the conflict is: if I center the image, the transformation's starting point is interrupted, which instantly breaks the math needed for scroll-to-zoom functionality.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
frontend/src/components/Media/ImageViewer.tsx (1)

53-63: Consider extracting static styles to CSS classes.

The inline style object has grown significantly with many static properties (maxWidth, maxHeight, userSelect, objectFit, display). For better maintainability, consider moving the static styles to a CSS class and keeping only the dynamic transform-related properties inline.

For example, create a CSS class:

.image-viewer-img {
  max-width: 100%;
  max-height: 100%;
  user-select: none;
  object-fit: contain;
  display: block;
}

Then simplify the inline styles to only dynamic properties:

         <img
+          className="image-viewer-img"
           src={convertFileSrc(imagePath) || '/placeholder.svg'}
           alt={alt}
           draggable={false}
           onError={(e) => {
             const img = e.target as HTMLImageElement;
             img.onerror = null;
             img.src = '/placeholder.svg';
           }}
           onWheel={onWheel}
           style={{
             transform: `translate(${position.x}px, ${position.y}px) scale(${scale}) rotate(${rotation}deg)`,
             transformOrigin: '0 0',
             transition: isDragging ? 'none' : 'transform 0.2s ease-in-out',
             cursor: isDragging ? 'grabbing' : 'grab',
-            maxWidth: '100%',
-            maxHeight: '100%',
-            userSelect: 'none',
-            objectFit: 'contain',
-            display: 'block',
           }}
         />
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 21a52e2 and a8041eb.

📒 Files selected for processing (2)
  • frontend/src/components/Media/ImageViewer.tsx (2 hunks)
  • frontend/src/components/Media/MediaView.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/Media/MediaView.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Tauri Build Check (windows-latest)
  • GitHub Check: Tauri Build Check (macos-latest, --target aarch64-apple-darwin)
  • GitHub Check: Tauri Build Check (ubuntu-22.04)
  • GitHub Check: Frontend Tests
  • GitHub Check: Linting
🔇 Additional comments (1)
frontend/src/components/Media/ImageViewer.tsx (1)

16-16: LGTM: Event handler prop addition is correct.

The onWheel prop follows the same pattern as other event handlers in the interface and is appropriately typed.

Comment on lines 34 to 52
<div
id="zoomable-image"
className="relative"
onClick={onClick}
onMouseDown={onMouseDown}
onMouseMove={onMouseMove}
onMouseUp={onMouseUp}
onMouseLeave={onMouseLeave}
>
<img
src={convertFileSrc(imagePath) || '/placeholder.svg'}
alt={alt}
draggable={false}
onError={(e) => {
const img = e.target as HTMLImageElement;
img.onerror = null;
img.src = '/placeholder.svg';
}}
onWheel={onWheel}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Move onWheel to the parent div for consistent cursor position handling.

The onWheel handler is attached to the img element (line 52), while all other interaction handlers (onClick, onMouseDown, onMouseMove, onMouseUp, onMouseLeave) are attached to the parent div (lines 37-41). This inconsistency creates coordination problems because cursor position calculations will be relative to different elements. For zoom-to-cursor functionality to work correctly, the wheel event must capture the cursor position relative to the same element as the other handlers.

Apply this diff to move onWheel to the parent div:

       <div
         id="zoomable-image"
         className="relative"
         onClick={onClick}
         onMouseDown={onMouseDown}
         onMouseMove={onMouseMove}
         onMouseUp={onMouseUp}
         onMouseLeave={onMouseLeave}
+        onWheel={onWheel}
       >
         <img
           src={convertFileSrc(imagePath) || '/placeholder.svg'}
           alt={alt}
           draggable={false}
           onError={(e) => {
             const img = e.target as HTMLImageElement;
             img.onerror = null;
             img.src = '/placeholder.svg';
           }}
-          onWheel={onWheel}
           style={{
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div
id="zoomable-image"
className="relative"
onClick={onClick}
onMouseDown={onMouseDown}
onMouseMove={onMouseMove}
onMouseUp={onMouseUp}
onMouseLeave={onMouseLeave}
>
<img
src={convertFileSrc(imagePath) || '/placeholder.svg'}
alt={alt}
draggable={false}
onError={(e) => {
const img = e.target as HTMLImageElement;
img.onerror = null;
img.src = '/placeholder.svg';
}}
onWheel={onWheel}
<div
id="zoomable-image"
className="relative"
onClick={onClick}
onMouseDown={onMouseDown}
onMouseMove={onMouseMove}
onMouseUp={onMouseUp}
onMouseLeave={onMouseLeave}
onWheel={onWheel}
>
<img
src={convertFileSrc(imagePath) || '/placeholder.svg'}
alt={alt}
draggable={false}
onError={(e) => {
const img = e.target as HTMLImageElement;
img.onerror = null;
img.src = '/placeholder.svg';
}}
🤖 Prompt for AI Agents
In frontend/src/components/Media/ImageViewer.tsx around lines 34 to 52, the
onWheel handler is attached to the <img> while all other mouse handlers are on
the parent <div>, causing inconsistent cursor position references for
zoom-to-cursor; move the onWheel prop from the <img> to the parent <div> so it
sits alongside onClick/onMouseDown/onMouseMove/onMouseUp/onMouseLeave, remove
onWheel from the <img>, and ensure event types/handler signature remain
unchanged (pass the same handler reference and update any refs/logic if it
relied on event.target being the image).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
frontend/src/components/Media/ImageViewer.tsx (1)

69-78: Remove inline transform that overrides library behavior.

The inline transform style at line 75 directly conflicts with react-zoom-pan-pinch's internal transform management. When the user zooms or pans, the library calculates the correct transform, but this inline style immediately overrides it with stale values from props, breaking the zoom-to-cursor and pan functionality you're trying to implement.

The library already handles:

  • ✓ Scale (zoom) via mouse wheel
  • ✓ Translation (pan) via mouse drag
  • ✓ Smooth transitions
  • ✓ Cursor states (grab/grabbing)

Remove the custom transform and let the library handle it. If you need rotation, apply it separately and carefully to avoid interfering with zoom/pan math (see previous comment for approach).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8041eb and 057561b.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • frontend/package.json (1 hunks)
  • frontend/src/components/Media/ImageViewer.tsx (2 hunks)
  • frontend/src/components/Media/MediaView.tsx (2 hunks)
  • frontend/src/hooks/useImageViewControls.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • frontend/src/hooks/useImageViewControls.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/Media/MediaView.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Tauri Build Check (ubuntu-22.04)
  • GitHub Check: Tauri Build Check (windows-latest)
  • GitHub Check: Tauri Build Check (macos-latest, --target aarch64-apple-darwin)
  • GitHub Check: Backend Tests
🔇 Additional comments (1)
frontend/package.json (1)

64-64: Good library choice for zoom/pan functionality.

The react-zoom-pan-pinch library (v3.7.0) is well-suited for implementing zoom-on-scroll with proper zoom-to-cursor behavior. This version includes fixes for mobile pinch and Safari rendering, which aligns well with the PR's goals. However, the current implementation in ImageViewer.tsx doesn't fully leverage this library and creates conflicts with existing custom transform code (see comments in that file).

Based on learnings.

Comment on lines 33 to 82
<TransformWrapper
initialScale={1}
minScale={0.1}
maxScale={8}
centerOnInit={true}
limitToBounds={false}
>
<img
src={convertFileSrc(imagePath) || '/placeholder.svg'}
alt={alt}
draggable={false}
className="h-full w-full object-contain select-none"
onError={(e) => {
const img = e.target as HTMLImageElement;
img.onerror = null;
img.src = '/placeholder.svg';
<TransformComponent
wrapperStyle={{
width: '100%',
height: '100%',
overflow: 'visible',
}}
style={{
transform: `translate(${position.x}px, ${position.y}px) scale(${scale}) rotate(${rotation}deg)`,
transition: isDragging ? 'none' : 'transform 0.2s ease-in-out',
cursor: isDragging ? 'grabbing' : 'grab',
contentStyle={{
width: '100%',
height: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
/>
</div>
>
<img
onClick={onClick}
onMouseDown={onMouseDown}
onMouseMove={onMouseMove}
onMouseUp={onMouseUp}
onMouseLeave={onMouseLeave}
src={convertFileSrc(imagePath) || '/placeholder.svg'}
alt={alt}
draggable={false}
className="select-none"
onError={(e) => {
const img = e.target as HTMLImageElement;
img.onerror = null;
img.src = '/placeholder.svg';
}}
style={{
maxWidth: '100%',
maxHeight: '100%',
objectFit: 'contain',
// transform: `rotate(${rotation}deg)`,
zIndex: 50,
transform: `translate(${position.x}px, ${position.y}px) scale(${scale}) rotate(${rotation}deg)`,
transition: isDragging ? 'none' : 'transform 0.2s ease-in-out',
cursor: isDragging ? 'grabbing' : 'grab',
}}
/>
</TransformComponent>
</TransformWrapper>
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Conflicting transform systems break zoom/pan functionality.

The component uses react-zoom-pan-pinch (TransformWrapper/TransformComponent) but also applies custom transforms via props (scale, position) as inline styles (line 75). These two transform systems conflict with each other:

  1. react-zoom-pan-pinch manages zoom/pan transforms internally and applies them to the content
  2. Inline style transform at line 75 uses prop values to override those transforms

When a user scrolls to zoom, the library calculates and applies a transform, but then the inline style immediately overrides it with the prop values. This explains the erratic behavior described in the PR comments (zoom not centering on cursor, issues with large images, etc.).

Additionally, the component receives custom mouse handlers (onMouseDown, onMouseMove, etc.) and isDragging state for manual pan/drag, which duplicates the library's built-in pan functionality and creates further conflicts.

Recommended refactoring approach:

Remove the custom transform logic and let react-zoom-pan-pinch handle all zoom and pan:

 interface ImageViewerProps {
   imagePath: string;
   alt: string;
-  scale: number;
-  position: { x: number; y: number };
   rotation: number;
-  isDragging: boolean;
-  onMouseDown: (e: React.MouseEvent) => void;
-  onMouseMove: (e: React.MouseEvent) => void;
-  onMouseUp: () => void;
-  onMouseLeave: () => void;
   onClick?: (e: React.MouseEvent) => void;
 }

 export const ImageViewer: React.FC<ImageViewerProps> = ({
   imagePath,
   alt,
-  scale,
-  position,
   rotation,
-  isDragging,
-  onMouseDown,
-  onMouseMove,
-  onMouseUp,
-  onMouseLeave,
   onClick,
 }) => {
   return (
     <TransformWrapper
       initialScale={1}
       minScale={0.1}
       maxScale={8}
       centerOnInit={true}
       limitToBounds={false}
+      wheel={{ smoothStep: 0.01 }}
     >
       <TransformComponent
         wrapperStyle={{
           width: '100%',
           height: '100%',
-          overflow: 'visible',
         }}
         contentStyle={{
           width: '100%',
           height: '100%',
           display: 'flex',
           alignItems: 'center',
           justifyContent: 'center',
         }}
       >
         <img
           onClick={onClick}
-          onMouseDown={onMouseDown}
-          onMouseMove={onMouseMove}
-          onMouseUp={onMouseUp}
-          onMouseLeave={onMouseLeave}
           src={convertFileSrc(imagePath) || '/placeholder.svg'}
           alt={alt}
           draggable={false}
           className="select-none"
           onError={(e) => {
             const img = e.target as HTMLImageElement;
             img.onerror = null;
             img.src = '/placeholder.svg';
           }}
           style={{
             maxWidth: '100%',
             maxHeight: '100%',
             objectFit: 'contain',
-            // transform: `rotate(${rotation}deg)`,
-            zIndex: 50,
-            transform: `translate(${position.x}px, ${position.y}px) scale(${scale}) rotate(${rotation}deg)`,
-            transition: isDragging ? 'none' : 'transform 0.2s ease-in-out',
-            cursor: isDragging ? 'grabbing' : 'grab',
+            transform: `rotate(${rotation}deg)`,
+            cursor: 'grab',
           }}
         />
       </TransformComponent>
     </TransformWrapper>
   );
 };

For rotation: If you need dynamic rotation control, use the library's programmatic API via render props or useControls hook to apply rotation in coordination with zoom/pan transforms.

For the parent hook: Update useImageViewControls.ts to remove custom zoom/pan state and handlers since the library manages them internally. If you need to respond to transform changes, use the library's onTransformed callback or useTransformEffect hook.

Would you like me to generate a complete refactored implementation showing how to properly integrate rotation with react-zoom-pan-pinch?

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
frontend/src/components/Media/ImageViewer.tsx lines 33-82: the component is
conflicting with react-zoom-pan-pinch because it applies an inline CSS transform
(translate/scale/rotate) from props (position, scale, rotation) while
TransformWrapper/TransformComponent already applies transforms; similarly,
custom mouse handlers and isDragging duplicate library pan logic. Remove the
inline transform and any custom zoom/pan state/handlers so the image element
only receives rotation (if needed) via the library API or combined with the
library transform, and wire rotation through react-zoom-pan-pinch programmatic
API (render props or useControls/useTransformEffect) and onTransformed
callbacks; update useImageViewControls.ts to stop managing scale/position/mouse
events and instead expose hooks/callbacks that call the library controls for
rotation and to observe transform changes.

@DecodeX15
Copy link
Contributor Author

@rahulharpal1603 sir review

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
frontend/src/components/Media/MediaView.tsx (1)

142-158: Remove custom drag handler props passed to ImageViewer.

The isDragging prop (line 147) and mouse handler props (lines 148-151) should be removed from the ImageViewer call, as they conflict with the library's built-in pan functionality (see the critical issue in ImageViewer.tsx review).

Apply this diff:

         <ImageViewer
           ref={imageViewerRef}
           imagePath={currentImagePath}
           alt={currentImageAlt}
           rotation={viewState.rotation}
-          isDragging={viewState.isDragging}
-          onMouseDown={handlers.handleMouseDown}
-          onMouseMove={handlers.handleMouseMove}
-          onMouseUp={handlers.handleMouseUp}
-          onMouseLeave={handlers.handleMouseUp}
           onClick={(e) => {
             if (e.target === e.currentTarget) {
               handleClose();
             }
           }}
           resetSignal={resetSignal}
         />

After this change, verify that useImageViewControls hook no longer needs to manage isDragging, handleMouseDown, handleMouseMove, and handleMouseUp state/handlers.

frontend/src/components/Media/ImageViewer.tsx (1)

5-16: Critical: Custom drag handlers conflict with react-zoom-pan-pinch's built-in pan functionality.

The library provides built-in pan/drag support that works seamlessly with zoom and wheel events. The custom drag handlers (isDragging, onMouseDown, onMouseMove, onMouseUp, onMouseLeave) attached to the <img> element (lines 79-82) will interfere with the library's pan gestures, causing unpredictable behavior. This likely explains the erratic zoom/pan issues described in the PR comments.

Remove the custom drag handlers from the interface and let the library handle all pan interactions:

 interface ImageViewerProps {
   imagePath: string;
   alt: string;
   rotation: number;
-  isDragging: boolean;
-  onMouseDown: (e: React.MouseEvent) => void;
-  onMouseMove: (e: React.MouseEvent) => void;
-  onMouseUp: () => void;
-  onMouseLeave: () => void;
   onClick?: (e: React.MouseEvent) => void;
   resetSignal?: number;
 }

Then remove the handler props from the component signature (lines 30-34) and from the <img> element (lines 79-82, 99).

🧹 Nitpick comments (1)
frontend/src/components/Media/MediaView.tsx (1)

77-77: Optional: Consider memoizing derived values.

currentImagePath and currentImageAlt are derived from currentImage, which is already memoized. While not critical (since they'll only recompute when currentImage changes), wrapping them in useMemo would make the optimization explicit and prevent potential issues if the component structure changes.

-  const currentImagePath = currentImage.path;
-  const currentImageAlt = `image-${currentViewIndex}`;
+  const currentImagePath = useMemo(() => currentImage.path, [currentImage]);
+  const currentImageAlt = useMemo(() => `image-${currentViewIndex}`, [currentViewIndex]);

Also applies to: 100-101

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 140a580 and 24f30c9.

📒 Files selected for processing (2)
  • frontend/src/components/Media/ImageViewer.tsx (1 hunks)
  • frontend/src/components/Media/MediaView.tsx (8 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/components/Media/MediaView.tsx (1)
frontend/src/components/Media/ImageViewer.tsx (2)
  • ImageViewerRef (18-22)
  • ImageViewer (24-106)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Backend Tests
🔇 Additional comments (7)
frontend/src/components/Media/ImageViewer.tsx (4)

18-22: LGTM: Clean imperative API for zoom controls.

The ref interface properly exposes zoom controls to the parent component, enabling programmatic zoom management.


49-52: LGTM: Valid pattern for prop-driven reset.

The useEffect correctly triggers a transform reset when the resetSignal prop changes, providing a declarative way for the parent to reset the view.


54-62: LGTM: Appropriate TransformWrapper configuration.

The wrapper configuration provides a reasonable zoom range (0.1× to 8×) and centerOnInit ensures proper initial positioning. The limitToBounds={false} setting allows free panning, which is appropriate for image viewing.


63-76: Verify that overflow: 'visible' is necessary.

Setting overflow: 'visible' on the wrapper (line 67) can interfere with the library's bounds calculations and clipping behavior. This may contribute to the zoom positioning issues described in the PR comments. The library typically expects contained overflow for proper transform calculations.

Unless there's a specific requirement for content to overflow the container, consider removing this override and using the library's default overflow handling:

         wrapperStyle={{
           width: '100%',
           height: '100%',
-          overflow: 'visible',
         }}

If overflow is intentional, please test thoroughly with images of varying sizes, especially the large boat image (~3000×4500) mentioned in the PR discussion.

frontend/src/components/Media/MediaView.tsx (3)

1-1: LGTM: Proper ref setup with correct typing.

The ImageViewerRef is correctly imported and the ref is properly typed.

Also applies to: 18-18, 39-39


169-177: LGTM: ZoomControls properly wired to new handlers.

The zoom controls now correctly invoke the new handleZoomIn, handleZoomOut, and handleResetZoom handlers that operate through the library's imperative API.

Note: The onRotate handler (line 173) still uses handlers.handleRotate. Verify that rotation works correctly with the library's transform system. As noted in the ImageViewer.tsx review, rotation should ideally be applied to a wrapper element rather than directly on the <img> to avoid transform conflicts.


136-136: LGTM: ClassName typo fixed.

The className is now correct with proper spacing and includes the centering classes (items-center justify-center), addressing the past review comment.

Note: The overflow-visible class here, combined with overflow: 'visible' in ImageViewer's wrapperStyle, may contribute to the zoom positioning issues. See the related concern in the ImageViewer.tsx review.

Comment on lines +40 to +47
const transformRef = useRef<any>(null);

// Expose zoom functions to parent
useImperativeHandle(ref, () => ({
zoomIn: () => transformRef.current?.zoomIn(),
zoomOut: () => transformRef.current?.zoomOut(),
reset: () => transformRef.current?.resetTransform(),
}));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Replace any type with the library's proper ref type.

Using any defeats TypeScript's type safety. The react-zoom-pan-pinch library exports a ReactZoomPanPinchRef type for the TransformWrapper ref.

Apply this diff to use proper typing:

-import React, { useRef, useImperativeHandle, forwardRef } from 'react';
-import { TransformWrapper, TransformComponent } from 'react-zoom-pan-pinch';
+import React, { useRef, useImperativeHandle, forwardRef } from 'react';
+import { 
+  TransformWrapper, 
+  TransformComponent,
+  ReactZoomPanPinchRef 
+} from 'react-zoom-pan-pinch';
-    const transformRef = useRef<any>(null);
+    const transformRef = useRef<ReactZoomPanPinchRef>(null);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In frontend/src/components/Media/ImageViewer.tsx around lines 40 to 47, the
transformRef is typed as any which disables TypeScript safety; import the
ReactZoomPanPinchRef type from 'react-zoom-pan-pinch' and use it as the generic
for useRef (e.g. useRef<ReactZoomPanPinchRef | null>(null)), and ensure any
forwardRef/imperative handle types align with that ref type so
zoomIn/zoomOut/reset calls are properly typed.

Comment on lines 77 to 101
<img
onClick={onClick}
onMouseDown={onMouseDown}
onMouseMove={onMouseMove}
onMouseUp={onMouseUp}
onMouseLeave={onMouseLeave}
src={convertFileSrc(imagePath) || '/placeholder.svg'}
alt={alt}
draggable={false}
className="select-none"
onError={(e) => {
const img = e.target as HTMLImageElement;
img.onerror = null;
img.src = '/placeholder.svg';
}}
style={{
maxWidth: '100%',
maxHeight: '100%',
objectFit: 'contain',
zIndex: 50,
transform: `rotate(${rotation}deg)`,
transition: isDragging ? 'none' : 'transform 0.2s ease-in-out',
cursor: isDragging ? 'grabbing' : 'grab',
}}
/>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Rotation transform conflicts with library transforms.

Applying transform: rotate(${rotation}deg) directly on the image (line 97) conflicts with the library's own transform. The library applies zoom/pan transforms to the content, and adding an additional CSS transform creates a composition where transforms combine in unpredictable ways, potentially breaking zoom-to-cursor positioning.

Additionally, the transition and cursor styles (lines 98-99) depend on isDragging, which should be removed along with the custom drag handlers.

Solution: Use the library's programmatic API to compose rotation with zoom/pan transforms. Here's the recommended approach:

           <img
             onClick={onClick}
-            onMouseDown={onMouseDown}
-            onMouseMove={onMouseMove}
-            onMouseUp={onMouseUp}
-            onMouseLeave={onMouseLeave}
             src={convertFileSrc(imagePath) || '/placeholder.svg'}
             alt={alt}
             draggable={false}
             className="select-none"
             onError={(e) => {
               const img = e.target as HTMLImageElement;
               img.onerror = null;
               img.src = '/placeholder.svg';
             }}
             style={{
               maxWidth: '100%',
               maxHeight: '100%',
               objectFit: 'contain',
-              zIndex: 50,
               transform: `rotate(${rotation}deg)`,
-              transition: isDragging ? 'none' : 'transform 0.2s ease-in-out',
-              cursor: isDragging ? 'grabbing' : 'grab',
             }}
           />

For rotation, wrap the <img> in a container <div> that applies rotation, and let the library transform the container:

<TransformComponent ...>
  <div style={{ transform: `rotate(${rotation}deg)` }}>
    <img ... style={{ maxWidth: '100%', maxHeight: '100%', objectFit: 'contain' }} />
  </div>
</TransformComponent>

This separates rotation (on the wrapper) from zoom/pan (managed by the library), preventing transform conflicts.

🤖 Prompt for AI Agents
In frontend/src/components/Media/ImageViewer.tsx around lines 77 to 101, the
image is being rotated via inline CSS transform and using transition/cursor tied
to isDragging while the library also applies its own zoom/pan transforms, which
causes transform composition bugs; remove the inline transform, transition and
cursor from the <img> element and stop using custom drag handlers/isDragging for
styling, and instead wrap the <img> in a container <div> that you rotate using
style={{ transform: `rotate(${rotation}deg)` }} (keep the image styles like
maxWidth/maxHeight/objectFit on the img) and let the library’s
TransformComponent manage zoom/pan on the rotated wrapper so rotation and
library transforms are composed correctly via the library API.

Comment on lines +102 to +114
const handleZoomIn = useCallback(() => {
imageViewerRef.current?.zoomIn();
}, []);

const handleZoomOut = useCallback(() => {
imageViewerRef.current?.zoomOut();
}, []);

const handleResetZoom = useCallback(() => {
imageViewerRef.current?.reset();
handlers.resetZoom();
setResetSignal((s) => s + 1);
}, [handlers]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Redundant reset logic and unclear responsibilities.

handleResetZoom has three reset calls:

  1. Line 111: imageViewerRef.current?.reset() - resets the library transform
  2. Line 112: handlers.resetZoom() - unclear what this resets in useImageViewControls
  3. Line 113: setResetSignal((s) => s + 1) - triggers the useEffect in ImageViewer (lines 50-52) which calls resetTransform() again

This results in calling reset twice on the library (lines 111 and via the effect), which is redundant.

Since the library now manages all zoom/pan state, handlers.resetZoom() likely manages obsolete state. Consider removing it:

 const handleResetZoom = useCallback(() => {
   imageViewerRef.current?.reset();
-  handlers.resetZoom();
   setResetSignal((s) => s + 1);
 }, [handlers]);

Or, if you prefer using only the prop-driven reset pattern:

 const handleResetZoom = useCallback(() => {
-  imageViewerRef.current?.reset();
-  handlers.resetZoom();
   setResetSignal((s) => s + 1);
-}, [handlers]);
+}, []);

Similarly, review whether handlers.resetZoom() calls in handleNextImage (line 51), handlePreviousImage (line 56), and handleThumbnailClick (line 67) should be replaced with setResetSignal.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleZoomIn = useCallback(() => {
imageViewerRef.current?.zoomIn();
}, []);
const handleZoomOut = useCallback(() => {
imageViewerRef.current?.zoomOut();
}, []);
const handleResetZoom = useCallback(() => {
imageViewerRef.current?.reset();
handlers.resetZoom();
setResetSignal((s) => s + 1);
}, [handlers]);
const handleResetZoom = useCallback(() => {
imageViewerRef.current?.reset();
setResetSignal((s) => s + 1);
}, [handlers]);

Copy link
Contributor

@rahulharpal1603 rahulharpal1603 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Vaibhaviitian

@rahulharpal1603 rahulharpal1603 merged commit c28830e into AOSSIE-Org:main Oct 23, 2025
7 checks passed
@DecodeX15
Copy link
Contributor Author

Thanks @Vaibhaviitian

It's my pleasure sir

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants