product detail fixed
This commit is contained in:
@@ -112,7 +112,7 @@ const CartPage = () => {
|
|||||||
|
|
||||||
const isGram = item.product.meansurement?.name?.toLowerCase() === 'gr';
|
const isGram = item.product.meansurement?.name?.toLowerCase() === 'gr';
|
||||||
const STEP = isGram ? 100 : 1;
|
const STEP = isGram ? 100 : 1;
|
||||||
const MIN_QTY = isGram ? 100 : 0.5;
|
const MIN_QTY = isGram ? 100 : 1;
|
||||||
|
|
||||||
let updatedQty: number;
|
let updatedQty: number;
|
||||||
if (newValue !== undefined) {
|
if (newValue !== undefined) {
|
||||||
@@ -329,23 +329,6 @@ const CartPage = () => {
|
|||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
}}
|
}}
|
||||||
onBlur={() => {
|
|
||||||
// Blur bo'lganda noto'g'ri qiymatlarni tuzatish
|
|
||||||
const isGram =
|
|
||||||
item.product.meansurement?.name?.toLowerCase() ===
|
|
||||||
'gr';
|
|
||||||
const MIN_QTY = isGram ? 100 : 0.5;
|
|
||||||
let value = quantities[item.id] ?? item.quantity;
|
|
||||||
|
|
||||||
if (!value || isNaN(value) || value < MIN_QTY)
|
|
||||||
value = MIN_QTY;
|
|
||||||
|
|
||||||
setInputValues((prev) => ({
|
|
||||||
...prev,
|
|
||||||
[item.id]: String(value),
|
|
||||||
}));
|
|
||||||
handleQuantityChange(item.id, 0, value);
|
|
||||||
}}
|
|
||||||
type="text"
|
type="text"
|
||||||
inputMode="decimal"
|
inputMode="decimal"
|
||||||
className="w-16 text-center border-none p-0"
|
className="w-16 text-center border-none p-0"
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import {
|
|||||||
ZoomControl,
|
ZoomControl,
|
||||||
} from '@pbe/react-yandex-maps';
|
} from '@pbe/react-yandex-maps';
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { AxiosError } from 'axios';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { uz } from 'date-fns/locale';
|
import { uz } from 'date-fns/locale';
|
||||||
import {
|
import {
|
||||||
@@ -106,7 +107,7 @@ const OrderPage = () => {
|
|||||||
queryClinet.refetchQueries({ queryKey: ['cart_items'] });
|
queryClinet.refetchQueries({ queryKey: ['cart_items'] });
|
||||||
} else if (message.errors && message.errors.length > 0) {
|
} else if (message.errors && message.errors.length > 0) {
|
||||||
// Xatolik bo'lsa chiqarish
|
// Xatolik bo'lsa chiqarish
|
||||||
toast.error(t('Xatolik yuz berdi: ') + message.errors[0].message, {
|
toast.error(t('Xatolik yuz berdi') + message.errors[0].message, {
|
||||||
richColors: true,
|
richColors: true,
|
||||||
position: 'top-center',
|
position: 'top-center',
|
||||||
});
|
});
|
||||||
@@ -118,8 +119,14 @@ const OrderPage = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: (error: AxiosError) => {
|
||||||
toast.error(t('Xatolik yuz berdi: Mahsulot omborxoda yetarli emas'), {
|
const errors = (error.response?.data as { data: { message: string } })
|
||||||
|
.data.message;
|
||||||
|
const errorsDetail = (
|
||||||
|
error.response?.data as { data: { detail: string } }
|
||||||
|
).data.detail;
|
||||||
|
|
||||||
|
toast.error(errors || errorsDetail || t('Xatolik yuz berdi'), {
|
||||||
richColors: true,
|
richColors: true,
|
||||||
position: 'top-center',
|
position: 'top-center',
|
||||||
});
|
});
|
||||||
@@ -247,6 +254,7 @@ const OrderPage = () => {
|
|||||||
}, [cityValue]);
|
}, [cityValue]);
|
||||||
|
|
||||||
function onSubmit(value: z.infer<typeof orderForm>) {
|
function onSubmit(value: z.infer<typeof orderForm>) {
|
||||||
|
console.log(value);
|
||||||
if (!cartItems || cartItems.length === 0) {
|
if (!cartItems || cartItems.length === 0) {
|
||||||
toast.error(t("Savatcha bo'sh"), {
|
toast.error(t("Savatcha bo'sh"), {
|
||||||
richColors: true,
|
richColors: true,
|
||||||
@@ -255,6 +263,14 @@ const OrderPage = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value.comment.length > 300) {
|
||||||
|
toast.error(t('Izoh 300ta belgidan oshib ketdi'), {
|
||||||
|
richColors: true,
|
||||||
|
position: 'top-center',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Yetkazib berish vaqtini tekshirish
|
// Yetkazib berish vaqtini tekshirish
|
||||||
if (!deliveryDate) {
|
if (!deliveryDate) {
|
||||||
toast.error(t('Yetkazib berish sanasini tanlang'), {
|
toast.error(t('Yetkazib berish sanasini tanlang'), {
|
||||||
@@ -291,7 +307,6 @@ const OrderPage = () => {
|
|||||||
}));
|
}));
|
||||||
if (user) {
|
if (user) {
|
||||||
const dealTime = formatDate.format(deliveryDate, 'DD.MM.YYYY');
|
const dealTime = formatDate.format(deliveryDate, 'DD.MM.YYYY');
|
||||||
|
|
||||||
mutate({
|
mutate({
|
||||||
order: [
|
order: [
|
||||||
{
|
{
|
||||||
@@ -311,7 +326,7 @@ const OrderPage = () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toast.error(t('Xatolik yuz berdi'), {
|
toast.error(t('Xatolik yuz berdi: Foydalanuvchi topilmadi'), {
|
||||||
richColors: true,
|
richColors: true,
|
||||||
position: 'top-center',
|
position: 'top-center',
|
||||||
});
|
});
|
||||||
@@ -361,7 +376,7 @@ const OrderPage = () => {
|
|||||||
<p className="text-gray-600">{t("Ma'lumotlaringizni to'ldiring")}</p>
|
<p className="text-gray-600">{t("Ma'lumotlaringizni to'ldiring")}</p>
|
||||||
</div>
|
</div>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<div onSubmit={form.handleSubmit(onSubmit)} className="contents">
|
<form onSubmit={form.handleSubmit(onSubmit)} className="contents">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||||
<div className="lg:col-span-2 space-y-6">
|
<div className="lg:col-span-2 space-y-6">
|
||||||
{/* Contact Information */}
|
{/* Contact Information */}
|
||||||
@@ -672,7 +687,6 @@ const OrderPage = () => {
|
|||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
onClick={form.handleSubmit(onSubmit)}
|
|
||||||
className="w-full bg-blue-600 text-white py-4 rounded-lg font-semibold hover:bg-blue-700 transition disabled:bg-gray-400 disabled:cursor-not-allowed"
|
className="w-full bg-blue-600 text-white py-4 rounded-lg font-semibold hover:bg-blue-700 transition disabled:bg-gray-400 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
{isPending ? (
|
{isPending ? (
|
||||||
@@ -686,7 +700,7 @@ const OrderPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { product_api } from '@/shared/config/api/product/api';
|
|||||||
import { BASE_URL } from '@/shared/config/api/URLs';
|
import { BASE_URL } from '@/shared/config/api/URLs';
|
||||||
import { useRouter } from '@/shared/config/i18n/navigation';
|
import { useRouter } from '@/shared/config/i18n/navigation';
|
||||||
import { useCartId } from '@/shared/hooks/cartId';
|
import { useCartId } from '@/shared/hooks/cartId';
|
||||||
|
import formatDate from '@/shared/lib/formatDate';
|
||||||
import formatPrice from '@/shared/lib/formatPrice';
|
import formatPrice from '@/shared/lib/formatPrice';
|
||||||
import { cn } from '@/shared/lib/utils';
|
import { cn } from '@/shared/lib/utils';
|
||||||
import { Input } from '@/shared/ui/input';
|
import { Input } from '@/shared/ui/input';
|
||||||
@@ -26,6 +27,9 @@ const ProductDetail = () => {
|
|||||||
const { cart_id } = useCartId();
|
const { cart_id } = useCartId();
|
||||||
const { user } = userStore();
|
const { user } = userStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
// const [api, setApi] = useState<CarouselApi>();
|
||||||
|
// const [canScrollPrev, setCanScrollPrev] = useState(false);
|
||||||
|
// const [canScrollNext, setCanScrollNext] = useState(false);
|
||||||
|
|
||||||
const [quantity, setQuantity] = useState<number | string>(1);
|
const [quantity, setQuantity] = useState<number | string>(1);
|
||||||
|
|
||||||
@@ -50,6 +54,12 @@ const ProductDetail = () => {
|
|||||||
enabled: !!cart_id,
|
enabled: !!cart_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// const { data: recomendation, isLoading: recLoad } = useQuery({
|
||||||
|
// queryKey: ['product_list', data?.group.id],
|
||||||
|
// queryFn: () => product_api.list({ page: 1, page_size: 12 }),
|
||||||
|
// select: (res) => res.data.results,
|
||||||
|
// });
|
||||||
|
|
||||||
const favouriteMutation = useMutation({
|
const favouriteMutation = useMutation({
|
||||||
mutationFn: (productId: string) => product_api.favourite(productId),
|
mutationFn: (productId: string) => product_api.favourite(productId),
|
||||||
|
|
||||||
@@ -67,6 +77,27 @@ const ProductDetail = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// if (!api) return;
|
||||||
|
|
||||||
|
// const updateButtons = () => {
|
||||||
|
// setCanScrollPrev(api.canScrollPrev());
|
||||||
|
// setCanScrollNext(api.canScrollNext());
|
||||||
|
// };
|
||||||
|
|
||||||
|
// updateButtons();
|
||||||
|
// api.on('select', updateButtons);
|
||||||
|
// api.on('reInit', updateButtons);
|
||||||
|
|
||||||
|
// return () => {
|
||||||
|
// api.off('select', updateButtons);
|
||||||
|
// api.off('reInit', updateButtons);
|
||||||
|
// };
|
||||||
|
// }, [api]);
|
||||||
|
|
||||||
|
// const scrollPrev = () => api?.scrollPrev();
|
||||||
|
// const scrollNext = () => api?.scrollNext();
|
||||||
|
|
||||||
const measurement = data?.meansurement?.name?.toLowerCase() || '';
|
const measurement = data?.meansurement?.name?.toLowerCase() || '';
|
||||||
const isGram = measurement === 'gr';
|
const isGram = measurement === 'gr';
|
||||||
|
|
||||||
@@ -338,7 +369,7 @@ const ProductDetail = () => {
|
|||||||
{t('Jami')}: {formatPrice(Number(subtotal) * numericQty, true)}
|
{t('Jami')}: {formatPrice(Number(subtotal) * numericQty, true)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3 mb-6">
|
||||||
<button
|
<button
|
||||||
onClick={handleAddToCart}
|
onClick={handleAddToCart}
|
||||||
className="flex-1 bg-green-600 hover:bg-green-700 text-white py-3 rounded-lg flex justify-center items-center gap-2"
|
className="flex-1 bg-green-600 hover:bg-green-700 text-white py-3 rounded-lg flex justify-center items-center gap-2"
|
||||||
@@ -368,6 +399,15 @@ const ProductDetail = () => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{data?.updated_at && data.payment_type === 'cash' && (
|
||||||
|
<div className="bg-yellow-50 border border-yellow-400 text-yellow-800 p-3 mb-4 rounded-md">
|
||||||
|
<p className="text-xs font-medium">
|
||||||
|
{t("Narxi o'zgargan bo'lishi mumkin")} • {t('Yangilangan')}:{' '}
|
||||||
|
{formatDate.format(data.updated_at, 'DD-MM-YYYY')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4 mt-6 border-t pt-4">
|
<div className="grid grid-cols-2 gap-4 mt-6 border-t pt-4">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<Truck className="mx-auto mb-1" />
|
<Truck className="mx-auto mb-1" />
|
||||||
@@ -380,6 +420,55 @@ const ProductDetail = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* <div className="mt-10 bg-white p-6 rounded-lg shadow relative">
|
||||||
|
<Button
|
||||||
|
onClick={scrollPrev}
|
||||||
|
disabled={!canScrollPrev}
|
||||||
|
className="absolute top-1/2 left-0 -translate-x-1/2 z-20 rounded-full"
|
||||||
|
size={'icon'}
|
||||||
|
variant={'outline'}
|
||||||
|
>
|
||||||
|
<ChevronLeft size={32} />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<h2 className="text-2xl font-bold mb-4">{t("O'xshash mahsulotlar")}</h2>
|
||||||
|
|
||||||
|
<Carousel setApi={setApi}>
|
||||||
|
<CarouselContent>
|
||||||
|
{recLoad &&
|
||||||
|
Array.from({ length: 6 }).map((_, i) => (
|
||||||
|
<CarouselItem
|
||||||
|
key={i}
|
||||||
|
className="basis-1/1 sm:basis-1/3 md:basis-1/4 lg:basis-1/5 xl:basis-1/6 pb-2"
|
||||||
|
>
|
||||||
|
<Skeleton className="h-60 w-full" />
|
||||||
|
</CarouselItem>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{recomendation
|
||||||
|
?.filter((p) => p.state === 'A')
|
||||||
|
.map((p) => (
|
||||||
|
<CarouselItem
|
||||||
|
key={p.id}
|
||||||
|
className="basis-1/2 sm:basis-1/3 md:basis-1/4 lg:basis-1/5 xl:basis-1/6 pb-2"
|
||||||
|
>
|
||||||
|
<ProductCard product={p} />
|
||||||
|
</CarouselItem>
|
||||||
|
))}
|
||||||
|
</CarouselContent>
|
||||||
|
</Carousel>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={scrollNext}
|
||||||
|
disabled={!canScrollNext}
|
||||||
|
className="absolute top-1/2 -translate-x-1/2 z-20 -right-10 rounded-full"
|
||||||
|
size={'icon'}
|
||||||
|
variant={'outline'}
|
||||||
|
>
|
||||||
|
<ChevronRight size={32} />
|
||||||
|
</Button>
|
||||||
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export interface ProductDetail {
|
|||||||
litr: null | string;
|
litr: null | string;
|
||||||
box_type_code: null | string;
|
box_type_code: null | string;
|
||||||
box_quant: null | string;
|
box_quant: null | string;
|
||||||
groups: { id: number; name: string }[];
|
group: { id: number; name: string };
|
||||||
state: 'A' | 'P';
|
state: 'A' | 'P';
|
||||||
barcodes: string;
|
barcodes: string;
|
||||||
article_code: null | string;
|
article_code: null | string;
|
||||||
|
|||||||
@@ -205,5 +205,7 @@
|
|||||||
"Yangilangan": "Обновлено",
|
"Yangilangan": "Обновлено",
|
||||||
"Narxi o'zgargan bo'lishi mumkin": "Цена может быть изменена",
|
"Narxi o'zgargan bo'lishi mumkin": "Цена может быть изменена",
|
||||||
"ga yangilandi": "обновлено",
|
"ga yangilandi": "обновлено",
|
||||||
"Izoh 300 ta belgidan oshmasligi kerak": "Комментарий не должен превышать 300 символов"
|
"Izoh 300 ta belgidan oshmasligi kerak": "Комментарий не должен превышать 300 символов",
|
||||||
|
"Xatolik yuz berdi: Foydalanuvchi topilmadi": "Ошибка: Пользователь не найден",
|
||||||
|
"Izoh 300ta belgidan oshib ketdi": "Комментарий превышает 300 символов"
|
||||||
}
|
}
|
||||||
@@ -209,5 +209,7 @@ declare const messages: {
|
|||||||
"Narxi o'zgargan bo'lishi mumkin": "Narxi o'zgargan bo'lishi mumkin";
|
"Narxi o'zgargan bo'lishi mumkin": "Narxi o'zgargan bo'lishi mumkin";
|
||||||
'ga yangilandi': 'ga yangilandi';
|
'ga yangilandi': 'ga yangilandi';
|
||||||
'Izoh 300 ta belgidan oshmasligi kerak': 'Izoh 300 ta belgidan oshmasligi kerak';
|
'Izoh 300 ta belgidan oshmasligi kerak': 'Izoh 300 ta belgidan oshmasligi kerak';
|
||||||
|
'Xatolik yuz berdi: Foydalanuvchi topilmadi': 'Xatolik yuz berdi: Foydalanuvchi topilmadi';
|
||||||
|
'Izoh 300ta belgidan oshib ketdi': 'Izoh 300ta belgidan oshib ketdi';
|
||||||
};
|
};
|
||||||
export default messages;
|
export default messages;
|
||||||
|
|||||||
@@ -205,5 +205,7 @@
|
|||||||
"Yangilangan": "Yangilangan",
|
"Yangilangan": "Yangilangan",
|
||||||
"Narxi o'zgargan bo'lishi mumkin": "Narxi o'zgargan bo'lishi mumkin",
|
"Narxi o'zgargan bo'lishi mumkin": "Narxi o'zgargan bo'lishi mumkin",
|
||||||
"ga yangilandi": "ga yangilandi",
|
"ga yangilandi": "ga yangilandi",
|
||||||
"Izoh 300 ta belgidan oshmasligi kerak": "Izoh 300 ta belgidan oshmasligi kerak"
|
"Izoh 300 ta belgidan oshmasligi kerak": "Izoh 300 ta belgidan oshmasligi kerak",
|
||||||
|
"Xatolik yuz berdi: Foydalanuvchi topilmadi": "Xatolik yuz berdi: Foydalanuvchi topilmadi",
|
||||||
|
"Izoh 300ta belgidan oshib ketdi": "Izoh 300ta belgidan oshib ketdi"
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user