product detail fixed
This commit is contained in:
@@ -112,7 +112,7 @@ const CartPage = () => {
|
||||
|
||||
const isGram = item.product.meansurement?.name?.toLowerCase() === 'gr';
|
||||
const STEP = isGram ? 100 : 1;
|
||||
const MIN_QTY = isGram ? 100 : 0.5;
|
||||
const MIN_QTY = isGram ? 100 : 1;
|
||||
|
||||
let updatedQty: number;
|
||||
if (newValue !== undefined) {
|
||||
@@ -329,23 +329,6 @@ const CartPage = () => {
|
||||
}
|
||||
}, 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"
|
||||
inputMode="decimal"
|
||||
className="w-16 text-center border-none p-0"
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
ZoomControl,
|
||||
} from '@pbe/react-yandex-maps';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { AxiosError } from 'axios';
|
||||
import { format } from 'date-fns';
|
||||
import { uz } from 'date-fns/locale';
|
||||
import {
|
||||
@@ -106,7 +107,7 @@ const OrderPage = () => {
|
||||
queryClinet.refetchQueries({ queryKey: ['cart_items'] });
|
||||
} else if (message.errors && message.errors.length > 0) {
|
||||
// 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,
|
||||
position: 'top-center',
|
||||
});
|
||||
@@ -118,8 +119,14 @@ const OrderPage = () => {
|
||||
});
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(t('Xatolik yuz berdi: Mahsulot omborxoda yetarli emas'), {
|
||||
onError: (error: AxiosError) => {
|
||||
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,
|
||||
position: 'top-center',
|
||||
});
|
||||
@@ -247,6 +254,7 @@ const OrderPage = () => {
|
||||
}, [cityValue]);
|
||||
|
||||
function onSubmit(value: z.infer<typeof orderForm>) {
|
||||
console.log(value);
|
||||
if (!cartItems || cartItems.length === 0) {
|
||||
toast.error(t("Savatcha bo'sh"), {
|
||||
richColors: true,
|
||||
@@ -255,6 +263,14 @@ const OrderPage = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.comment.length > 300) {
|
||||
toast.error(t('Izoh 300ta belgidan oshib ketdi'), {
|
||||
richColors: true,
|
||||
position: 'top-center',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Yetkazib berish vaqtini tekshirish
|
||||
if (!deliveryDate) {
|
||||
toast.error(t('Yetkazib berish sanasini tanlang'), {
|
||||
@@ -291,7 +307,6 @@ const OrderPage = () => {
|
||||
}));
|
||||
if (user) {
|
||||
const dealTime = formatDate.format(deliveryDate, 'DD.MM.YYYY');
|
||||
|
||||
mutate({
|
||||
order: [
|
||||
{
|
||||
@@ -311,7 +326,7 @@ const OrderPage = () => {
|
||||
],
|
||||
});
|
||||
} else {
|
||||
toast.error(t('Xatolik yuz berdi'), {
|
||||
toast.error(t('Xatolik yuz berdi: Foydalanuvchi topilmadi'), {
|
||||
richColors: true,
|
||||
position: 'top-center',
|
||||
});
|
||||
@@ -361,7 +376,7 @@ const OrderPage = () => {
|
||||
<p className="text-gray-600">{t("Ma'lumotlaringizni to'ldiring")}</p>
|
||||
</div>
|
||||
<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="lg:col-span-2 space-y-6">
|
||||
{/* Contact Information */}
|
||||
@@ -672,7 +687,6 @@ const OrderPage = () => {
|
||||
<button
|
||||
type="submit"
|
||||
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"
|
||||
>
|
||||
{isPending ? (
|
||||
@@ -686,7 +700,7 @@ const OrderPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { product_api } from '@/shared/config/api/product/api';
|
||||
import { BASE_URL } from '@/shared/config/api/URLs';
|
||||
import { useRouter } from '@/shared/config/i18n/navigation';
|
||||
import { useCartId } from '@/shared/hooks/cartId';
|
||||
import formatDate from '@/shared/lib/formatDate';
|
||||
import formatPrice from '@/shared/lib/formatPrice';
|
||||
import { cn } from '@/shared/lib/utils';
|
||||
import { Input } from '@/shared/ui/input';
|
||||
@@ -26,6 +27,9 @@ const ProductDetail = () => {
|
||||
const { cart_id } = useCartId();
|
||||
const { user } = userStore();
|
||||
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);
|
||||
|
||||
@@ -50,6 +54,12 @@ const ProductDetail = () => {
|
||||
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({
|
||||
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 isGram = measurement === 'gr';
|
||||
|
||||
@@ -338,7 +369,7 @@ const ProductDetail = () => {
|
||||
{t('Jami')}: {formatPrice(Number(subtotal) * numericQty, true)}
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3">
|
||||
<div className="flex gap-3 mb-6">
|
||||
<button
|
||||
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"
|
||||
@@ -368,6 +399,15 @@ const ProductDetail = () => {
|
||||
</button>
|
||||
</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="text-center">
|
||||
<Truck className="mx-auto mb-1" />
|
||||
@@ -380,6 +420,55 @@ const ProductDetail = () => {
|
||||
</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>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -61,7 +61,7 @@ export interface ProductDetail {
|
||||
litr: null | string;
|
||||
box_type_code: null | string;
|
||||
box_quant: null | string;
|
||||
groups: { id: number; name: string }[];
|
||||
group: { id: number; name: string };
|
||||
state: 'A' | 'P';
|
||||
barcodes: string;
|
||||
article_code: null | string;
|
||||
|
||||
@@ -205,5 +205,7 @@
|
||||
"Yangilangan": "Обновлено",
|
||||
"Narxi o'zgargan bo'lishi mumkin": "Цена может быть изменена",
|
||||
"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";
|
||||
'ga yangilandi': 'ga yangilandi';
|
||||
'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;
|
||||
|
||||
@@ -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": "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