import { memo, useRef, useState } from "react"; import AddImageModal from "../modals/AddImageModal"; import ConfirmBuyModal from "../modals/ConfirmBuyModal"; import ImageModal from "../modals/ImageModal"; function GroceryListItem({ item, onClick, onImageAdded, onLongPress }) { const [showModal, setShowModal] = useState(false); const [showAddImageModal, setShowAddImageModal] = useState(false); const [showConfirmBuyModal, setShowConfirmBuyModal] = useState(false); const longPressTimer = useRef(null); const pressStartPos = useRef({ x: 0, y: 0 }); const handleTouchStart = (e) => { const touch = e.touches[0]; pressStartPos.current = { x: touch.clientX, y: touch.clientY }; longPressTimer.current = setTimeout(() => { if (onLongPress) { onLongPress(item); } }, 500); // 500ms for long press }; const handleTouchMove = (e) => { // Cancel long press if finger moves too much const touch = e.touches[0]; const moveDistance = Math.sqrt( Math.pow(touch.clientX - pressStartPos.current.x, 2) + Math.pow(touch.clientY - pressStartPos.current.y, 2) ); if (moveDistance > 10) { clearTimeout(longPressTimer.current); } }; const handleTouchEnd = () => { clearTimeout(longPressTimer.current); }; const handleMouseDown = () => { longPressTimer.current = setTimeout(() => { if (onLongPress) { onLongPress(item); } }, 500); }; const handleMouseUp = () => { clearTimeout(longPressTimer.current); }; const handleMouseLeave = () => { clearTimeout(longPressTimer.current); }; const handleItemClick = () => { if (onClick) { setShowConfirmBuyModal(true); } }; const handleConfirmBuy = (quantity) => { if (onClick) { onClick(quantity); } setShowConfirmBuyModal(false); }; const handleCancelBuy = () => { setShowConfirmBuyModal(false); }; const handleImageClick = (e) => { e.stopPropagation(); // Prevent triggering the bought action if (item.item_image) { setShowModal(true); } else { setShowAddImageModal(true); } }; const handleAddImage = async (imageFile) => { if (onImageAdded) { await onImageAdded(item.id, item.item_name, item.quantity, imageFile); } setShowAddImageModal(false); }; const imageUrl = item.item_image && item.image_mime_type ? `data:${item.image_mime_type};base64,${item.item_image}` : null; const getTimeAgo = (dateString) => { if (!dateString) return null; const addedDate = new Date(dateString); const now = new Date(); const diffMs = now - addedDate; const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); if (diffDays < 7) { return `${diffDays}d ago`; } else if (diffDays < 30) { const weeks = Math.floor(diffDays / 7); return `${weeks}w ago`; } else { const months = Math.floor(diffDays / 30); return `${months}m ago`; } }; return ( <>
  • {item.item_image ? ( {item.item_name} ) : ( 📦 )} x{item.quantity}
    {item.item_name}
    {item.added_by_users && item.added_by_users.length > 0 && (
    {item.last_added_on && `${getTimeAgo(item.last_added_on)} -- `} {item.added_by_users.join(" • ")}
    )}
  • {showModal && ( setShowModal(false)} /> )} {showAddImageModal && ( setShowAddImageModal(false)} onAddImage={handleAddImage} /> )} {showConfirmBuyModal && ( )} ); } // Memoize component to prevent re-renders when props haven't changed export default memo(GroceryListItem, (prevProps, nextProps) => { // Only re-render if the item data or handlers have changed return ( prevProps.item.id === nextProps.item.id && prevProps.item.item_name === nextProps.item.item_name && prevProps.item.quantity === nextProps.item.quantity && prevProps.item.item_image === nextProps.item.item_image && prevProps.item.bought === nextProps.item.bought && prevProps.item.last_added_on === nextProps.item.last_added_on && prevProps.item.added_by_users?.join(',') === nextProps.item.added_by_users?.join(',') && prevProps.onClick === nextProps.onClick && prevProps.onImageAdded === nextProps.onImageAdded && prevProps.onLongPress === nextProps.onLongPress ); });