From f04ae13c39879a1ff4eb066d57a2ca70667e3529 Mon Sep 17 00:00:00 2001 From: Samandar Turgunboyev Date: Wed, 4 Mar 2026 15:54:00 +0500 Subject: [PATCH] bug fix --- src/features/cart/ui/CartPage.tsx | 26 +++++-- src/features/product/ui/Product.tsx | 109 +++++++++++++++------------- 2 files changed, 78 insertions(+), 57 deletions(-) diff --git a/src/features/cart/ui/CartPage.tsx b/src/features/cart/ui/CartPage.tsx index 2bb4d3d..f5698cc 100644 --- a/src/features/cart/ui/CartPage.tsx +++ b/src/features/cart/ui/CartPage.tsx @@ -146,12 +146,6 @@ const CartPage = () => { }); }; - const price = cartItems?.map((item) => - item.product.prices.find((p) => p.price_type.code === '1') - ? item.product.prices.find((p) => p.price_type.code === '1')?.price - : Math.min(...item.product.prices.map((p) => Number(p.price))), - ); - if (isLoading) return (
@@ -254,7 +248,25 @@ const CartPage = () => {
- {formatPrice(Number(price), true)} + {item.product.prices.find( + (p) => p.price_type.code === '1', + ) + ? formatPrice( + Number( + item.product.prices.find( + (p) => p.price_type.code === '1', + )?.price, + ), + true, + ) + : formatPrice( + Math.min( + ...item.product.prices.map((p) => + Number(p.price), + ), + ), + true, + )} /{measurementDisplay} diff --git a/src/features/product/ui/Product.tsx b/src/features/product/ui/Product.tsx index 057b8dc..50c81fd 100644 --- a/src/features/product/ui/Product.tsx +++ b/src/features/product/ui/Product.tsx @@ -23,10 +23,14 @@ const ProductDetail = () => { const queryClient = useQueryClient(); const { cart_id } = useCartId(); - /** ✅ number | string */ const [quantity, setQuantity] = useState(1); + + // ✅ debounce ref const debounceRef = useRef(null); + // ✅ Flag: faqat manual input (klaviatura) da debounce ishlaydi + const isManualInputRef = useRef(false); + /* ---------------- PRODUCT DETAIL ---------------- */ const { data, isLoading } = useQuery({ queryKey: ['product_detail', product], @@ -42,8 +46,6 @@ const ProductDetail = () => { enabled: !!cart_id, }); - const maxBalance = data?.balance ?? 0; - const measurement = data?.meansurement?.name?.toLowerCase() || ''; const isGram = measurement === 'gr'; @@ -52,7 +54,7 @@ const ProductDetail = () => { const measurementDisplay = data?.meansurement?.name || 'шт.'; - /** ✅ Safe numeric */ + /** Safe numeric value */ const numericQty = quantity === '' || quantity === '.' || quantity === ',' ? 0 @@ -60,8 +62,12 @@ const ProductDetail = () => { /* ---------------- HELPERS ---------------- */ const clampQuantity = (value: number) => { - if (!maxBalance) return value; - return Math.min(value, maxBalance); + if (isNaN(value)) return MIN_QTY; + + let safe = Math.max(value, MIN_QTY); + safe = Math.min(safe); + + return safe; }; const getQuantityMessage = (qty: number, measurement: string | null) => { @@ -69,7 +75,7 @@ const ProductDetail = () => { return `${qty} ${measurement}`; }; - /* ---------------- SYNC CART ---------------- */ + /* ---------------- SYNC CART (boshlang'ich holat) ---------------- */ useEffect(() => { if (!data || !cartItems) return; @@ -82,35 +88,11 @@ const ProductDetail = () => { } else { setQuantity(MIN_QTY); } + // isManualInputRef ni reset qilish shart - bu sync, manual input emas + isManualInputRef.current = false; }, [data, cartItems, MIN_QTY]); - /* ---------------- DEBOUNCE UPDATE ---------------- */ - useEffect(() => { - if (!cart_id || !data || !cartItems) return; - - const cartItem = cartItems.data.cart_item.find( - (i) => Number(i.product.id) === data.id, - ); - - if (!cartItem || cartItem.quantity === numericQty) return; - - if (debounceRef.current) clearTimeout(debounceRef.current); - - debounceRef.current = setTimeout(() => { - if (numericQty > 0) { - updateCartItem({ - cart_item_id: cartItem.id.toString(), - body: { quantity: numericQty }, - }); - } - }, 500); - - return () => { - if (debounceRef.current) clearTimeout(debounceRef.current); - }; - }, [numericQty]); - - /* ---------------- ADD ---------------- */ + /* ---------------- MUTATIONS ---------------- */ const { mutate: addToCart } = useMutation({ mutationFn: (body: { product: string; quantity: number; cart: string }) => cart_api.cart_item(body), @@ -121,10 +103,7 @@ const ProductDetail = () => { const measurementName = data?.meansurement?.name || null; toast.success( - `${getQuantityMessage( - variables.quantity, - measurementName, - )} ${t("savatga qo'shildi")}`, + `${getQuantityMessage(variables.quantity, measurementName)} ${t("savatga qo'shildi")}`, { richColors: true, position: 'top-center' }, ); }, @@ -132,7 +111,6 @@ const ProductDetail = () => { onError: (err: AxiosError) => { const msg = (err.response?.data as { detail: string })?.detail || err.message; - toast.error(msg, { richColors: true }); }, }); @@ -149,17 +127,47 @@ const ProductDetail = () => { const measurementName = data?.meansurement?.name || null; toast.success( - `${t('Miqdor')} ${getQuantityMessage( - variables.body.quantity, - measurementName, - )} ${t('ga yangilandi')}`, + `${t('Miqdor')} ${getQuantityMessage(variables.body.quantity, measurementName)} ${t('ga yangilandi')}`, { richColors: true, position: 'top-center' }, ); }, }); + /* ---------------- DEBOUNCE UPDATE (faqat manual input uchun) ---------------- */ + useEffect(() => { + // ✅ Faqat klaviatura orqali yozilganda ishlaydi + if (!isManualInputRef.current) return; + if (!cart_id || !data || !cartItems) return; + + const cartItem = cartItems.data.cart_item.find( + (i) => Number(i.product.id) === data.id, + ); + + if (!cartItem || cartItem.quantity === numericQty) return; + + if (debounceRef.current) clearTimeout(debounceRef.current); + + debounceRef.current = setTimeout(() => { + if (numericQty >= MIN_QTY) { + updateCartItem({ + cart_item_id: cartItem.id.toString(), + body: { quantity: numericQty }, + }); + } + isManualInputRef.current = false; + }, 500); + + return () => { + if (debounceRef.current) clearTimeout(debounceRef.current); + }; + }, [numericQty]); + /* ---------------- HANDLERS ---------------- */ const handleAddToCart = () => { + // ✅ Debounce-ni bekor qil - double request oldini olish + if (debounceRef.current) clearTimeout(debounceRef.current); + isManualInputRef.current = false; + if (!data || !cart_id) { toast.error(t('Tizimga kirilmagan'), { richColors: true, @@ -186,28 +194,29 @@ const ProductDetail = () => { quantity: normalizedQty, }); } - setQuantity(normalizedQty); }; const handleIncrease = () => { + // ✅ Bu manual input emas - flag ni false qoldirish + isManualInputRef.current = false; + setQuantity((q) => { const base = q === '' || q === '.' || q === ',' ? 0 : Number(q); let next = base + STEP; - if (isGram) next = Math.ceil(next / STEP) * STEP; - return next; }); }; const handleDecrease = () => { + // ✅ Bu manual input emas - flag ni false qoldirish + isManualInputRef.current = false; + setQuantity((q) => { const base = q === '' || q === '.' || q === ',' ? MIN_QTY : Number(q); let next = base - STEP; - if (isGram) next = Math.floor(next / STEP) * STEP; - return Math.max(next, MIN_QTY); }); }; @@ -257,7 +266,6 @@ const ProductDetail = () => { /{measurementDisplay}
- {/* ✅ INPUT FIXED */}