diff --git a/modules/foundups/gotjunk/frontend/App.tsx b/modules/foundups/gotjunk/frontend/App.tsx index 01c3bf0b..80b40680 100644 --- a/modules/foundups/gotjunk/frontend/App.tsx +++ b/modules/foundups/gotjunk/frontend/App.tsx @@ -99,6 +99,36 @@ const App: React.FC = () => { const [pendingClassificationItem, setPendingClassificationItem] = useState<{blob: Blob, url: string, location?: {latitude: number, longitude: number}} | null>(null); const [isProcessingClassification, setIsProcessingClassification] = useState(false); + // Safety backup: Store last captured item that needs classification + const pendingClassificationBackupRef = useRef<{blob: Blob, url: string, location?: {latitude: number, longitude: number}} | null>(null); + const classificationCompletedRef = useRef(false); + + // === AUTO-CLASSIFY STATE === + const [autoClassifyEnabled, setAutoClassifyEnabled] = useState(false); + const [lastClassification, setLastClassification] = useState<{ + type: ItemClassification, + discountPercent?: number, + bidDurationHours?: number + } | null>(null); + + // Safety verification: Ensure classification modal appears and waits for user selection + useEffect(() => { + if (!pendingClassificationItem && pendingClassificationBackupRef.current && !classificationCompletedRef.current) { + // Classification modal disappeared without user completing it! + const backup = pendingClassificationBackupRef.current; + + console.warn('[GotJunk] SAFETY CHECK: Classification modal closed without selection! Restoring...'); + + // Restore the pending item after a short delay to ensure clean state + setTimeout(() => { + if (!classificationCompletedRef.current) { + console.log('[GotJunk] SAFETY RESTORE: Re-opening classification modal'); + setPendingClassificationItem(backup); + } + }, 100); + } + }, [pendingClassificationItem]); + // === FULLSCREEN REVIEW STATE (My Items tab) === const [reviewingItem, setReviewingItem] = useState(null); const [reviewQueue, setReviewQueue] = useState([]); @@ -254,12 +284,36 @@ const App: React.FC = () => { console.error("Could not get location for capture:", error); } - // Show classification modal instead of immediately saving - setPendingClassificationItem({ + const capturedItem = { blob, url: URL.createObjectURL(blob), location - }); + }; + + // Check if auto-classify is enabled + if (autoClassifyEnabled && lastClassification) { + console.log('[GotJunk] Auto-classify enabled - using last classification:', lastClassification); + + // Mark as completed immediately to skip safety verification + classificationCompletedRef.current = true; + pendingClassificationBackupRef.current = null; + + // Directly process with last classification (skip modal) + setPendingClassificationItem(capturedItem); + await handleClassify(lastClassification.type, lastClassification.discountPercent, lastClassification.bidDurationHours); + return; + } + + // Manual mode: Show classification modal + // Reset classification completion flag for new capture + classificationCompletedRef.current = false; + + // Store backup for safety verification + pendingClassificationBackupRef.current = capturedItem; + + // Show classification modal + console.log('[GotJunk] Photo captured - opening classification modal'); + setPendingClassificationItem(capturedItem); }; const handleClassify = async (classification: ItemClassification, discountPercent?: number, bidDurationHours?: number) => { @@ -273,6 +327,19 @@ const App: React.FC = () => { // Immediately capture the item data and clear pending state to prevent race conditions const { blob, url, location } = pendingClassificationItem; + + // Mark classification as completed to prevent safety restore + classificationCompletedRef.current = true; + pendingClassificationBackupRef.current = null; + + // Store this classification for future auto-classify + setLastClassification({ + type: classification, + discountPercent, + bidDurationHours + }); + console.log('[GotJunk] Stored classification for auto-classify:', { classification, discountPercent, bidDurationHours }); + setPendingClassificationItem(null); setIsProcessingClassification(true); @@ -739,6 +806,9 @@ const App: React.FC = () => { // TODO: Open search modal }} showCameraOrb={showCameraOrb} + autoClassifyEnabled={autoClassifyEnabled} + onToggleAutoClassify={() => setAutoClassifyEnabled(!autoClassifyEnabled)} + lastClassification={lastClassification} /> {/* Re-classification Modal (tap badge) */} diff --git a/modules/foundups/gotjunk/frontend/components/BottomNavBar.tsx b/modules/foundups/gotjunk/frontend/components/BottomNavBar.tsx index 7dca6c72..fe485a83 100644 --- a/modules/foundups/gotjunk/frontend/components/BottomNavBar.tsx +++ b/modules/foundups/gotjunk/frontend/components/BottomNavBar.tsx @@ -19,6 +19,9 @@ interface BottomNavBarProps { hasReviewItems: boolean; onSearchClick?: () => void; // Search functionality showCameraOrb?: boolean; + autoClassifyEnabled?: boolean; + onToggleAutoClassify?: () => void; + lastClassification?: { type: string, discountPercent?: number, bidDurationHours?: number } | null; } const buttonVariants = { @@ -37,6 +40,9 @@ export const BottomNavBar: React.FC = ({ hasReviewItems, onSearchClick = () => console.log('🔍 Search clicked'), showCameraOrb = true, + autoClassifyEnabled = false, + onToggleAutoClassify = () => console.log('🔄 Auto-classify toggled'), + lastClassification = null, }) => { const cameraRef = useRef(null); const pressTimerRef = useRef(null); @@ -136,7 +142,7 @@ export const BottomNavBar: React.FC = ({ {/* Camera Orb - Floating above nav bar */} {showCameraOrb && (
{/* Main capture button with live preview - Intelligent scaling: iPhone 11=143px, iPhone 16=149px */} @@ -153,6 +159,34 @@ export const BottomNavBar: React.FC = ({ >
+ + {/* Auto-Classify Toggle Button */} + +
+
+ + Auto: {autoClassifyEnabled ? 'ON' : 'OFF'} + +
+ {autoClassifyEnabled && lastClassification && ( +
+ {lastClassification.type === 'discount' && `${lastClassification.discountPercent || 75}% OFF`} + {lastClassification.type === 'bid' && `${lastClassification.bidDurationHours || 48}h`} + {lastClassification.type === 'free' && 'FREE'} +
+ )} +
)}