This commit is contained in:
Samandar Turgunboyev
2026-01-24 16:46:02 +05:00
parent 1f77cc360d
commit ecc0029322
24 changed files with 632 additions and 563 deletions

View File

@@ -1,3 +1,6 @@
'use client';
import LogosProduct from '@/assets/product.png';
import { product_api } from '@/shared/config/api/product/api';
import {
ProductListResult,
@@ -11,7 +14,6 @@ import { useQuery } from '@tanstack/react-query';
import { PackageOpen } from 'lucide-react';
import { useTranslations } from 'next-intl';
import Image from 'next/image';
import { Fragment, useEffect, useState } from 'react';
type SearchResultProps = {
query: string;
@@ -20,55 +22,54 @@ type SearchResultProps = {
export const SearchResult = ({ query }: SearchResultProps) => {
const router = useRouter();
const t = useTranslations();
const [searchRes, setSearchRes] = useState<
ProductListResult[] | SearchDataPro[] | []
>([]);
const { data: product } = useQuery({
/* 🔹 Default products - query bo'lmaganda */
const { data: products, isLoading: isLoadingDefault } = useQuery<
ProductListResult[]
>({
queryKey: ['product_list'],
queryFn: () => product_api.list({ page: 1, page_size: 99 }),
select(data) {
return data.data.results;
queryFn: async () => {
const res = await product_api.list({ page: 1, page_size: 10 });
return res.data.results;
},
enabled: !query,
});
const { data, isLoading } = useQuery({
/* 🔹 Search - query bo'lganda */
const { data: searchData, isLoading: isLoadingSearch } = useQuery<
ProductListResult[]
>({
queryKey: ['search', query],
queryFn: () => product_api.search({ search: query, page: 1, page_szie: 5 }),
select(data) {
return data.data.products;
queryFn: async () => {
const res = await product_api.search({
search: query,
page: 1,
page_size: 10,
});
// API response strukturasiga qarab to'g'rilash kerak
// Agar res.data.products array bo'lsa:
return Array.isArray(res.data.products)
? res.data.products
: (res.data.products as SearchDataPro[]).map(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(item: any) => item.products || item,
);
},
enabled: !!query,
enabled: !!query && query.trim().length > 0,
});
useEffect(() => {
if (data) {
setSearchRes(data);
} else if (product && product.length > 0) {
setSearchRes(product);
} else {
setSearchRes([]);
}
}, [product, data]);
if (searchRes && searchRes.length === 0) {
return (
<div className="flex flex-col justify-center items-center min-h-[300px] max-h-[600px] gap-2">
<PackageOpen className="size-22 text-muted-foreground" />
<p className="text-lg text-muted-foreground text-center">
{t('Hech narsa topilmadi')}
</p>
</div>
);
}
const isLoading = query ? isLoadingSearch : isLoadingDefault;
const list: ProductListResult[] = query
? (searchData ?? [])
: (products ?? []);
if (isLoading) {
return (
<div className="space-y-3">
{Array.from({ length: 5 }).map((_, i) => (
<div key={i} className="flex items-center gap-3 p-2 rounded-lg">
<div key={i} className="flex items-center gap-3 p-2">
<Skeleton className="w-16 h-16 rounded-md" />
<div className="flex-1 space-y-2">
<Skeleton className="h-4 w-[70%]" />
<Skeleton className="h-3 w-[40%]" />
@@ -79,45 +80,62 @@ export const SearchResult = ({ query }: SearchResultProps) => {
);
}
if (!list.length) {
return (
<div className="flex flex-col justify-center items-center min-h-[300px] gap-2">
<PackageOpen className="size-20 text-muted-foreground" />
<p className="text-lg text-muted-foreground">
{query ? t('Hech narsa topilmadi') : t('Mahsulotlar mavjud emas')}
</p>
</div>
);
}
return (
<div className="space-y-3">
<p className="text-sm font-semibold text-foreground">
{query.length > 0 ? t('Qidiruv natijalari') : t('Tavsiya etiladi')}
<p className="text-sm font-semibold text-slate-700">
{query ? t('Qidiruv natijalari') : t('Tavsiya etiladi')}
</p>
{searchRes &&
searchRes
.filter((product) => product.is_active)
.slice(0, 5)
.map((product, index) => (
<Fragment key={index}>
<div
className="flex items-center gap-3 p-2 rounded-lg hover:bg-slate-100 cursor-pointer transition"
onClick={() => router.push(`/product/${product.id}`)}
>
<Image
width={500}
height={500}
src={
product.image.includes(BASE_URL)
? product.image
: BASE_URL + product.image
}
alt={product.name}
className="w-16 h-16 rounded-md object-contain"
/>
{list
.filter((item) => item.state === 'A')
.slice(0, 5)
.map((product) => {
const image =
product.images.length > 0
? product?.images[0].image?.includes(BASE_URL)
? product.images[0].image
: BASE_URL + product.images[0].image
: LogosProduct;
const price = product.prices?.[0]?.price;
<div className="flex-1">
<p className="text-sm font-medium text-slate-800">
{product.name}
return (
<div
key={product.id}
className="flex items-center gap-3 p-2 rounded-lg hover:bg-slate-100 cursor-pointer transition-colors"
onClick={() => router.push(`/product/${product.id}`)}
>
<Image
src={image}
alt={product.name}
width={64}
height={64}
className="w-16 h-16 rounded-md object-contain bg-white border border-slate-100"
/>
<div className="flex-1">
<p className="text-sm font-medium text-slate-900 line-clamp-2">
{product.name}
</p>
{price && (
<p className="text-sm font-semibold text-[#57A595] mt-1">
{formatPrice(price)}
</p>
<p className="text-xs text-slate-600">
{formatPrice(product.price)}
</p>
</div>
)}
</div>
</Fragment>
))}
</div>
);
})}
</div>
);
};