'use client'; import { useState, useEffect, useRef } from 'react'; import { Item } from '@/lib/db'; import { X } from 'lucide-react'; interface DebugRotationPanelProps { item: Item; imageUrl: string; originalPhotoPath?: string; originalCropBounds?: { x: number; y: number; width: number; height: number }; originalRotation?: number; imageProcessing?: any; onClose: () => void; } export function DebugRotationPanel({ item, imageUrl, originalPhotoPath, originalCropBounds, originalRotation = 0, imageProcessing, onClose, }: DebugRotationPanelProps) { const [rotation, setRotation] = useState(originalRotation); const canvasRef = useRef(null); const [log, setLog] = useState(''); const imageRef = useRef(null); const [imageLoaded, setImageLoaded] = useState(false); const [scaledDimensions, setScaledDimensions] = useState({ width: 0, height: 0, scale: 1 }); const containerRef = useRef(null); // Use original photo path if available, otherwise fall back to processed image URL const displayImageUrl = originalPhotoPath ? originalPhotoPath : imageUrl; const commonAngles = [ { label: '0°', value: 0 }, { label: '+22°', value: 22 }, { label: '-22°', value: -22 }, { label: '+45°', value: 45 }, { label: '-45°', value: -45 }, { label: '+90°', value: 90 }, { label: '-90°', value: -90 }, { label: '±180°', value: 180 }, ]; const updateLog = (message: string) => { setLog(message); }; useEffect(() => { const img = new Image(); img.crossOrigin = 'anonymous'; img.onload = () => { imageRef.current = img; setImageLoaded(true); // Calculate scaled dimensions to fit available space (much larger) const maxWidth = 900; const maxHeight = 600; const scale = Math.min(maxWidth / img.width, maxHeight / img.height); const scaledW = img.width * scale; const scaledH = img.height * scale; setScaledDimensions({ width: scaledW, height: scaledH, scale }); updateLog(`📸 ${img.width}×${img.height}px → scaled ${scaledW.toFixed(0)}×${scaledH.toFixed(0)}px (${scale.toFixed(2)}x)`); }; img.onerror = () => updateLog('❌ Failed to load image'); img.src = displayImageUrl; }, [displayImageUrl]); useEffect(() => { if (!imageLoaded || !imageRef.current || !canvasRef.current || !originalCropBounds) return; const canvas = canvasRef.current; const ctx = canvas.getContext('2d'); if (!ctx) return; const img = imageRef.current; const { scale } = scaledDimensions; // Set canvas size to match scaled image canvas.width = scaledDimensions.width; canvas.height = scaledDimensions.height; // Draw scaled image ctx.drawImage(img, 0, 0, canvas.width, canvas.height); // Calculate crop box in scaled coordinates const cropX = originalCropBounds.x * scale; const cropY = originalCropBounds.y * scale; const cropW = originalCropBounds.width * scale; const cropH = originalCropBounds.height * scale; // Save state ctx.save(); // Draw crop bounds rectangle (bright green) ctx.strokeStyle = '#00FF00'; ctx.lineWidth = 4; ctx.shadowColor = 'rgba(0, 0, 0, 0.8)'; ctx.shadowBlur = 3; ctx.strokeRect(cropX, cropY, cropW, cropH); // Draw rotation indicator (rotated rectangle inside crop area) if (Math.abs(rotation) > 0.5) { ctx.strokeStyle = '#FFB800'; ctx.lineWidth = 3; ctx.setLineDash([5, 5]); ctx.shadowColor = 'rgba(0, 0, 0, 0.8)'; ctx.shadowBlur = 2; // Draw a rotated rectangle showing where text will be after rotation ctx.save(); ctx.translate(cropX + cropW / 2, cropY + cropH / 2); ctx.rotate((rotation * Math.PI) / 180); ctx.strokeRect(-cropW / 2, -cropH / 2, cropW, cropH); ctx.restore(); } ctx.restore(); // Update log with current state const logText = `Rotation: ${rotation}° | Crop: (${cropX.toFixed(0)}, ${cropY.toFixed(0)}) ${cropW.toFixed(0)}×${cropH.toFixed(0)}px`; updateLog(logText); }, [imageLoaded, rotation, originalCropBounds, scaledDimensions]); return (
{/* Header */}

Debug Rotation & Crop

{/* Left: Controls */}
{/* Rotation Slider */}
setRotation(Number(e.target.value))} className="w-full" />
{/* Quick Presets */}
{commonAngles.map((angle) => ( ))}
{/* Original Values */} {originalRotation !== undefined && (

Original AI Values

Rotation: {originalRotation}°
{originalCropBounds && ( <>
Crop ({originalCropBounds.x}, {originalCropBounds.y})
Size {originalCropBounds.width}×{originalCropBounds.height}
)} {imageProcessing?.confidence && (
Confidence: {(imageProcessing.confidence * 100).toFixed(0)}%
)}
)}
{/* Right: Canvas + Log */}
{/* Canvas - takes most space */}

Preview (Green = Crop, Orange = Rotation)

{/* Log - single line */}
{log}
); }