diff --git a/modules/foundups/gotjunk/frontend/components/ItemReviewer.tsx b/modules/foundups/gotjunk/frontend/components/ItemReviewer.tsx index 04c8c87c..3d734dd8 100644 --- a/modules/foundups/gotjunk/frontend/components/ItemReviewer.tsx +++ b/modules/foundups/gotjunk/frontend/components/ItemReviewer.tsx @@ -33,6 +33,14 @@ export const ItemReviewer: React.FC = ({ item, onDecision, on const swipeThreshold = 50; const velocityThreshold = 200; + // Check for vertical swipe UP to close (collapse back to thumbnails) + if (onClose && (info.offset.y < -swipeThreshold || info.velocity.y < -velocityThreshold)) { + console.log('[ItemReviewer] Swipe up detected - closing fullscreen'); + onClose(); + return; + } + + // Horizontal swipe for keep/delete let decision: 'keep' | 'delete' | null = null; if (info.offset.x > swipeThreshold || info.velocity.x > velocityThreshold) { @@ -68,8 +76,8 @@ export const ItemReviewer: React.FC = ({ item, onDecision, on style={{ zIndex: Z_LAYERS.fullscreen }} role="dialog" aria-modal="true" - drag="x" - dragConstraints={{ left: -150, right: 150 }} + drag + dragConstraints={{ left: -150, right: 150, top: -200, bottom: 50 }} dragElastic={0.2} onDragEnd={handleDragEnd} onClick={handleTap} @@ -100,6 +108,32 @@ export const ItemReviewer: React.FC = ({ item, onDecision, on /> )} + + {/* Collapse button (-) - Bottom right corner */} + {onClose && ( + + )} ); }; diff --git a/modules/foundups/gotjunk/frontend/hooks/useLongPress.ts b/modules/foundups/gotjunk/frontend/hooks/useLongPress.ts index d4a9f235..8f69b53c 100644 --- a/modules/foundups/gotjunk/frontend/hooks/useLongPress.ts +++ b/modules/foundups/gotjunk/frontend/hooks/useLongPress.ts @@ -43,6 +43,7 @@ export function useLongPress({ const longPressTriggeredRef = useRef(false); const startPosRef = useRef<{ x: number; y: number } | null>(null); const lastLongPressTimeRef = useRef(0); + const lastTapTimeRef = useRef(0); // Prevent double-tap from touch+mouse events const clear = useCallback(() => { if (timerRef.current) { @@ -101,6 +102,17 @@ export function useLongPress({ // Fire tap only if long-press wasn't triggered if (!longPressTriggeredRef.current && onTap) { + const now = Date.now(); + + // Prevent double-tap from touch+mouse events (mobile browsers fire both) + // Skip if onTap was called within 300ms (debounce) + if (now - lastTapTimeRef.current < 300) { + console.log('[useLongPress] Skipping duplicate tap event (touch+mouse collision)'); + startPosRef.current = null; + return; + } + + lastTapTimeRef.current = now; onTap(event); }