simplify: remove image rotation modal, save original image as-is
Removed the rotation/zoom adjustment modal feature. Approach was too complex and time-consuming without delivering stable results. New simplified flow: 1. User extracts item with AI 2. Item saved with original image (resized/compressed by backend) 3. No rotation adjustments in frontend 4. Image editing can be implemented as a future feature This unblocks the workflow and gets users to a working state. Backend still applies compression/resizing, just no rotation processing. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -99,7 +99,8 @@
|
|||||||
"Bash(sqlite3 *)",
|
"Bash(sqlite3 *)",
|
||||||
"Skill(gsd-resume-work)",
|
"Skill(gsd-resume-work)",
|
||||||
"Bash(git revert *)",
|
"Bash(git revert *)",
|
||||||
"Skill(gsd-next)"
|
"Skill(gsd-next)",
|
||||||
|
"Bash(grep -E \"\\\\.\\(tsx|ts\\)$\")"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import React, { useState } from 'react';
|
|||||||
import { toast } from 'react-hot-toast';
|
import { toast } from 'react-hot-toast';
|
||||||
import { Camera, Check, RefreshCw, X, Image as ImageIcon, Sparkles, Hash, Layout, Layers, Package, ChevronDown } from 'lucide-react';
|
import { Camera, Check, RefreshCw, X, Image as ImageIcon, Sparkles, Hash, Layout, Layers, Package, ChevronDown } from 'lucide-react';
|
||||||
import { useAIExtraction } from '@/hooks/useAIExtraction';
|
import { useAIExtraction } from '@/hooks/useAIExtraction';
|
||||||
import { ImageAdjustmentModal } from './ImageAdjustmentModal';
|
// Image adjustment modal disabled - image editing to be implemented as future feature
|
||||||
|
|
||||||
interface AIOnboardingProps {
|
interface AIOnboardingProps {
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
@@ -14,9 +14,6 @@ interface AIOnboardingProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function AIOnboarding({ onCancel, onComplete, categories, inventory }: AIOnboardingProps) {
|
export default function AIOnboarding({ onCancel, onComplete, categories, inventory }: AIOnboardingProps) {
|
||||||
const [showImageAdjustment, setShowImageAdjustment] = useState(false);
|
|
||||||
const [adjustingItemIndex, setAdjustingItemIndex] = useState<number | null>(null);
|
|
||||||
const [pendingItemData, setPendingItemData] = useState<any>(null);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
image,
|
image,
|
||||||
@@ -49,115 +46,11 @@ export default function AIOnboarding({ onCancel, onComplete, categories, invento
|
|||||||
const confirmSingleItem = (index: number) => {
|
const confirmSingleItem = (index: number) => {
|
||||||
if (!extractedItems[index]) return;
|
if (!extractedItems[index]) return;
|
||||||
|
|
||||||
const data = extractedItems[index];
|
// Skip image adjustment modal - just save original image
|
||||||
const skipPhoto = data._skipPhoto === true;
|
// Image editing will be implemented as a future feature
|
||||||
|
hookConfirmSingleItem(index);
|
||||||
if (skipPhoto || !image) {
|
|
||||||
hookConfirmSingleItem(index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setPendingItemData({ index, data, skipPhoto });
|
|
||||||
setAdjustingItemIndex(index);
|
|
||||||
setShowImageAdjustment(true);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImageAdjustmentConfirm = async (adjustments: any) => {
|
|
||||||
if (!pendingItemData) return;
|
|
||||||
|
|
||||||
const { index } = pendingItemData;
|
|
||||||
|
|
||||||
console.log('=== AIONBOARDING ADJUSTMENT CONFIRM ===');
|
|
||||||
console.log('[Input] Adjustments from modal:', adjustments);
|
|
||||||
console.log('[Input] Current item index:', index);
|
|
||||||
console.log('[Input] Current extractedItems[index]:', extractedItems[index]);
|
|
||||||
console.log('[Current] extractedImageBlob before:', extractedImageBlob?.size || 'null', 'bytes');
|
|
||||||
|
|
||||||
if (adjustments && extractedItems[index]) {
|
|
||||||
// UPDATE IMMEDIATELY - don't use setState, update the array directly
|
|
||||||
// because hookConfirmSingleItem needs to see the updated values synchronously
|
|
||||||
const updatedItems = [...extractedItems];
|
|
||||||
updatedItems[index] = {
|
|
||||||
...updatedItems[index],
|
|
||||||
image_processing: {
|
|
||||||
...updatedItems[index].image_processing,
|
|
||||||
rotation_degrees: adjustments.rotation,
|
|
||||||
crop_bounds: {
|
|
||||||
x: Math.round(adjustments.cropBounds.x),
|
|
||||||
y: Math.round(adjustments.cropBounds.y),
|
|
||||||
width: Math.round(adjustments.cropBounds.width),
|
|
||||||
height: Math.round(adjustments.cropBounds.height)
|
|
||||||
},
|
|
||||||
user_adjusted: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
console.log('[Update] Updated item_processing:', updatedItems[index].image_processing);
|
|
||||||
|
|
||||||
// CRITICAL: Update state AND processed blob BEFORE calling hook
|
|
||||||
setExtractedItems(updatedItems);
|
|
||||||
|
|
||||||
// DON'T replace image blob - modal no longer processes image
|
|
||||||
// Backend will apply rotation to original image
|
|
||||||
if (adjustments.imageBlob) {
|
|
||||||
console.log('[Update] Processed blob received but NOT using (backend will process)');
|
|
||||||
} else {
|
|
||||||
console.log('[Update] No imageBlob - using original, backend will apply rotation');
|
|
||||||
}
|
|
||||||
|
|
||||||
// CRITICAL: Call hook with UPDATED item, not old one
|
|
||||||
console.log('[Action] Calling hookConfirmSingleItem with UPDATED item');
|
|
||||||
console.log('[Action] Updated item:', updatedItems[index]);
|
|
||||||
|
|
||||||
// We need to manually call the hook logic here since we can't wait for state
|
|
||||||
// Build the item exactly as the hook does, but with updated values
|
|
||||||
const data = updatedItems[index];
|
|
||||||
const skipPhoto = data._skipPhoto === true;
|
|
||||||
|
|
||||||
const newItem = {
|
|
||||||
name: String(data.Item || data.name || "New AI Item"),
|
|
||||||
category: String(data.Category || data.category || "Uncategorized"),
|
|
||||||
type: data.Type || data.type ? String(data.Type || data.type) : null,
|
|
||||||
part_number: data.PartNr || data.part_number ? String(data.PartNr || data.part_number) : null,
|
|
||||||
color: data.Color || data.color ? String(data.Color || data.color) : null,
|
|
||||||
description: String(data.Description || data.description || ""),
|
|
||||||
connector: data.Connector || data.connector ? String(data.Connector || data.connector) : null,
|
|
||||||
size: data.Size || data.size ? String(data.Size || data.size) : null,
|
|
||||||
ocr_text: data.OCR || data.ocr_text ? String(data.OCR || data.ocr_text) : null,
|
|
||||||
specs: String(data.specs || ""),
|
|
||||||
barcode: String(data.barcode || data.PartNr || data.part_number || `AI-${Date.now()}-${index}`),
|
|
||||||
quantity: parseFloat(String(data.quantity || 1)),
|
|
||||||
min_quantity: 1.0,
|
|
||||||
box_label: data.box_label ? String(data.box_label) : null,
|
|
||||||
labels_data: JSON.stringify(data),
|
|
||||||
...(skipPhoto ? {} : {
|
|
||||||
extractedImageBlob: adjustments.imageBlob || extractedImageBlob,
|
|
||||||
imageProcessing: data.image_processing
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('[Final] newItem with ADJUSTED values:', newItem);
|
|
||||||
console.log('[Final] imageProcessing in final item:', newItem.imageProcessing);
|
|
||||||
onComplete(newItem);
|
|
||||||
|
|
||||||
// Clean up extracted items
|
|
||||||
const remaining = [...updatedItems];
|
|
||||||
remaining.splice(index, 1);
|
|
||||||
setExtractedItems(remaining.length > 0 ? remaining : []);
|
|
||||||
} else {
|
|
||||||
hookConfirmSingleItem(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('=== END CONFIRM DEBUG ===');
|
|
||||||
setShowImageAdjustment(false);
|
|
||||||
setAdjustingItemIndex(null);
|
|
||||||
setPendingItemData(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleImageAdjustmentCancel = () => {
|
|
||||||
setShowImageAdjustment(false);
|
|
||||||
setAdjustingItemIndex(null);
|
|
||||||
setPendingItemData(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
const confirmAllItems = async () => {
|
const confirmAllItems = async () => {
|
||||||
await hookConfirmAllItems();
|
await hookConfirmAllItems();
|
||||||
@@ -607,13 +500,6 @@ export default function AIOnboarding({ onCancel, onComplete, categories, invento
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showImageAdjustment && image && (
|
|
||||||
<ImageAdjustmentModal
|
|
||||||
imageUrl={image}
|
|
||||||
onConfirm={handleImageAdjustmentConfirm}
|
|
||||||
onCancel={handleImageAdjustmentCancel}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user