import { useState, useCallback, useRef, useEffect } from "react"; import { QuantityControl } from "./QuantityControl"; import { Loader2 } from "lucide-react"; interface ThrottledQuantityControlProps { initialQuantity: number; maxQuantity: number; onQuantityUpdate: (quantity: number) => void; isPending?: boolean; allowManualEdit?: boolean; onRemove?: () => void; throttleDelay?: number; } export const ThrottledQuantityControl = ({ initialQuantity, maxQuantity, onQuantityUpdate, isPending: externalIsPending = false, allowManualEdit = false, onRemove, throttleDelay = 1000, }: ThrottledQuantityControlProps) => { const [quantity, setQuantity] = useState(initialQuantity); const [isUpdating, setIsUpdating] = useState(false); const throttleTimerRef = useRef(null); const isMountedRef = useRef(true); useEffect(() => { return () => { isMountedRef.current = false; if (throttleTimerRef.current) { clearTimeout(throttleTimerRef.current); } }; }, []); useEffect(() => { setQuantity(initialQuantity); }, [initialQuantity]); const performUpdate = useCallback( async (newQuantity: number) => { try { setIsUpdating(true); await onQuantityUpdate(newQuantity); } catch (error) { // Revert quantity on error if (isMountedRef.current) { setQuantity(initialQuantity); } } finally { if (isMountedRef.current) { setIsUpdating(false); } } }, [onQuantityUpdate, initialQuantity] ); const scheduleUpdate = useCallback( (newQuantity: number) => { // Update local state immediately for responsive UI setQuantity(newQuantity); // Clear existing timer if (throttleTimerRef.current) { clearTimeout(throttleTimerRef.current); } // Schedule the API call after throttle delay throttleTimerRef.current = setTimeout(() => { performUpdate(newQuantity); }, throttleDelay); }, [performUpdate, throttleDelay] ); const handleIncrease = useCallback(() => { if (quantity < maxQuantity && !isUpdating && !externalIsPending) { const newQuantity = quantity + 1; scheduleUpdate(newQuantity); } }, [quantity, maxQuantity, isUpdating, externalIsPending, scheduleUpdate]); const handleDecrease = useCallback(() => { if (quantity > 0 && !isUpdating && !externalIsPending) { const newQuantity = quantity - 1; scheduleUpdate(newQuantity); } }, [quantity, isUpdating, externalIsPending, scheduleUpdate]); const handleQuantityChange = useCallback( (newQuantity: number) => { if ( newQuantity >= 0 && newQuantity <= maxQuantity && !isUpdating && !externalIsPending ) { scheduleUpdate(newQuantity); } }, [maxQuantity, isUpdating, externalIsPending, scheduleUpdate] ); const isLoading = isUpdating || externalIsPending; // Custom wrapper to show loading on entire component return (
{/* Loading overlay for entire component */} {isLoading && (
)}
); };