Files
Novault-Frontend-web/src/components/transaction/ImagePreview

ImagePreview Component

Full-screen image preview component with navigation support for viewing transaction images.

Requirements

  • 4.6: Display full-screen image preview when user clicks on uploaded image
  • 4.14: Support left/right swipe navigation for switching between images

Features

  • Full-screen modal overlay with dark background
  • Image counter showing current position (e.g., "2 / 5")
  • Previous/Next navigation buttons
  • Keyboard navigation (Arrow keys, Escape)
  • Touch swipe navigation for mobile devices
  • Mouse drag navigation for desktop
  • Circular navigation (wraps around at edges)
  • Image information display (filename, file size)
  • Close button and click-outside-to-close
  • Body scroll lock when modal is open
  • Smooth animations and transitions
  • Responsive design for all screen sizes
  • Accessibility support (ARIA labels, keyboard navigation)

Usage

import { ImagePreview } from './components/transaction/ImagePreview/ImagePreview';
import type { TransactionImage } from './types';

function MyComponent() {
  const [previewOpen, setPreviewOpen] = useState(false);
  const [previewIndex, setPreviewIndex] = useState(0);
  
  const images: TransactionImage[] = [
    {
      id: 1,
      transactionId: 100,
      filePath: '/uploads/image1.jpg',
      fileName: 'receipt1.jpg',
      fileSize: 102400,
      mimeType: 'image/jpeg',
      createdAt: '2024-01-01T10:00:00Z',
    },
    // ... more images
  ];

  const handleImageClick = (index: number) => {
    setPreviewIndex(index);
    setPreviewOpen(true);
  };

  return (
    <>
      {/* Thumbnail grid */}
      <div className="thumbnails">
        {images.map((image, index) => (
          <img
            key={image.id}
            src={`/api/images/${image.id}`}
            onClick={() => handleImageClick(index)}
          />
        ))}
      </div>

      {/* Image preview modal */}
      <ImagePreview
        images={images}
        initialIndex={previewIndex}
        open={previewOpen}
        onClose={() => setPreviewOpen(false)}
      />
    </>
  );
}

Props

Prop Type Required Description
images TransactionImage[] Yes Array of images to preview
initialIndex number Yes Index of the image to display initially (0-based)
open boolean Yes Whether the preview modal is open
onClose () => void Yes Callback when the modal should close

Navigation Methods

Keyboard

  • Arrow Left: Previous image
  • Arrow Right: Next image
  • Escape: Close preview

Mouse

  • Click navigation buttons: Navigate between images
  • Click close button: Close preview
  • Click overlay: Close preview
  • Drag left/right: Navigate between images (desktop)

Touch

  • Swipe left: Next image
  • Swipe right: Previous image
  • Tap close button: Close preview
  • Tap overlay: Close preview

Behavior

Circular Navigation

  • When on the first image, clicking "Previous" wraps to the last image
  • When on the last image, clicking "Next" wraps to the first image

Body Scroll Lock

  • When the preview is open, body scrolling is disabled
  • Scroll is restored when the preview is closed

Index Reset

  • When initialIndex prop changes, the preview resets to that index
  • Useful when opening the preview from different entry points

Single Image

  • Navigation buttons are hidden when there's only one image
  • Swipe/drag navigation is disabled for single images

Styling

The component uses CSS custom properties for theming:

  • Dark overlay: rgba(0, 0, 0, 0.95)
  • Button backgrounds: rgba(255, 255, 255, 0.1) with backdrop blur
  • Animations: Fade in (200ms), Zoom in (300ms)

Responsive Breakpoints

  • Desktop: Full size controls
  • Tablet (≤768px): Slightly smaller controls
  • Mobile (≤480px): Compact controls and layout

Accessibility

  • Proper ARIA roles and labels
  • Keyboard navigation support
  • Focus management
  • Screen reader friendly
  • Reduced motion support

Testing

The component includes comprehensive unit tests covering:

  • Rendering in different states
  • Navigation functionality (buttons, keyboard, touch)
  • Close functionality
  • Body scroll lock
  • Index reset
  • Accessibility features

Run tests:

npm test ImagePreview.test.tsx

Integration with ImageAttachment

The ImagePreview component is designed to work seamlessly with the ImageAttachment component:

import { ImageAttachment } from './components/transaction/ImageAttachment/ImageAttachment';
import { ImagePreview } from './components/transaction/ImagePreview/ImagePreview';

function TransactionForm() {
  const [images, setImages] = useState<TransactionImage[]>([]);
  const [previewOpen, setPreviewOpen] = useState(false);
  const [previewIndex, setPreviewIndex] = useState(0);

  const handlePreview = (index: number) => {
    setPreviewIndex(index);
    setPreviewOpen(true);
  };

  return (
    <>
      <ImageAttachment
        images={images}
        onAdd={handleAddImage}
        onRemove={handleRemoveImage}
        onPreview={handlePreview}
      />
      
      <ImagePreview
        images={images}
        initialIndex={previewIndex}
        open={previewOpen}
        onClose={() => setPreviewOpen(false)}
      />
    </>
  );
}

Browser Support

  • Modern browsers with ES6+ support
  • Touch events for mobile devices
  • Backdrop filter support (with fallback)
  • CSS animations and transitions

Performance Considerations

  • Images are loaded on-demand
  • Smooth animations using CSS transforms
  • Efficient event listeners (cleanup on unmount)
  • Minimal re-renders with proper state management