This commit is contained in:
Samandar Turgunboyev
2026-02-20 15:47:02 +05:00
parent bb84da82a8
commit ef55c1ecd8
6 changed files with 105 additions and 104 deletions

View File

@@ -36,7 +36,7 @@ export async function generateMetadata({
openGraph: {
title,
description,
url: `/search${query ? `?q=${encodeURIComponent(query)}` : ''}`,
url: `/search${query ? `?search=${encodeURIComponent(query)}` : ''}`,
type: 'website',
},
twitter: {
@@ -64,7 +64,7 @@ export async function generateMetadata({
openGraph: {
title,
description,
url: `/search${query ? `?q=${encodeURIComponent(query)}` : ''}`,
url: `/search${query ? `?search=${encodeURIComponent(query)}` : ''}`,
type: 'website',
},
twitter: {

View File

@@ -40,17 +40,20 @@ const HistoryTabs = () => {
return (
<div className="flex flex-col items-center justify-center py-16 text-center px-4">
<div className="bg-gray-100 p-6 rounded-full mb-4">
<Package className="w-16 h-16 text-gray-400" />
<Package className="w-12 h-12 text-gray-400" />
</div>
<p className="text-xl font-bold text-gray-800 mb-2">
<p className="text-lg font-bold text-gray-800 mb-2">
{t('Buyurtmalar topilmadi')}
</p>
<p className="text-sm text-gray-500 max-w-md">
<p className="text-sm text-gray-500 max-w-xs">
{t(
"Hali buyurtma qilmagansiz. Mahsulotlarni ko'rib chiqing va birinchi buyurtmangizni bering!",
)}
</p>
<Button onClick={() => router.push('/')} className="mt-6">
<Button
onClick={() => router.push('/')}
className="mt-6 w-full max-w-xs"
>
<ShoppingBag className="w-4 h-4 mr-2" />
{t('Xarid qilish')}
</Button>
@@ -59,21 +62,21 @@ const HistoryTabs = () => {
}
return (
<div className="max-w-5xl mx-auto px-3 md:px-0">
<div className="w-full px-3 md:px-0">
{/* Header */}
<div className="flex flex-col md:flex-row md:items-center justify-between mb-6 pb-4 border-b gap-2">
<div className="flex items-center justify-between mb-4 pb-3 border-b">
<div>
<h2 className="text-2xl md:text-3xl font-bold text-gray-900">
<h2 className="text-xl md:text-3xl font-bold text-gray-900">
{t('Buyurtmalar tarixi')}
</h2>
<p className="text-sm text-gray-500 mt-1">
<p className="text-xs md:text-sm text-gray-500 mt-0.5">
{data.length} {t('ta buyurtma')}
</p>
</div>
</div>
{/* Orders List */}
<div className="space-y-4 md:space-y-6">
<div className="space-y-3 md:space-y-6">
{data.map((order: OrderList) => {
const totalPrice = order.items.reduce(
(sum, item) => sum + Number(item.price) * item.quantity,
@@ -83,31 +86,31 @@ const HistoryTabs = () => {
return (
<Card
key={order.id}
className="border-2 border-gray-200 hover:border-blue-400 transition-all duration-200 shadow-sm hover:shadow-lg"
className="border border-gray-200 hover:border-blue-400 transition-all duration-200 shadow-sm hover:shadow-md rounded-xl overflow-hidden"
>
<CardContent className="p-0">
{/* Order Header */}
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 p-3 md:p-4 border-b-2 border-gray-200">
<div className="flex flex-col md:flex-row md:items-center justify-between gap-3">
<div className="flex items-center gap-3">
<div className="bg-blue-600 text-white px-3 py-1 rounded-full text-sm font-bold">
<div className="bg-gradient-to-r from-blue-50 to-indigo-50 px-3 py-2.5 md:p-4 border-b border-gray-200">
<div className="flex items-center justify-between gap-2">
{/* Order ID */}
<div className="flex items-center gap-2">
<div className="bg-blue-600 text-white px-2.5 py-1 rounded-full text-xs font-bold">
#{order.id}
</div>
<div>
<p className="text-xs text-gray-500">
{t('Buyurtma raqami')}
</p>
</div>
<p className="text-xs text-gray-500">
{t('Buyurtma raqami')}
</p>
</div>
{/* Delivery date - compact on mobile */}
{order.delivery_date && (
<div className="flex items-center gap-2 bg-white px-3 py-2 rounded-lg shadow-sm">
<Calendar className="w-4 h-4 text-blue-600" />
<div className="flex items-center gap-1.5 bg-white px-2 py-1 rounded-lg shadow-sm">
<Calendar className="w-3.5 h-3.5 text-blue-600 flex-shrink-0" />
<div>
<p className="text-xs text-gray-500">
<p className="text-[10px] text-gray-500 leading-none">
{t('Yetkazib berish')}
</p>
<p className="text-sm font-semibold text-gray-800">
<p className="text-xs font-semibold text-gray-800 mt-0.5">
{order.delivery_date}
</p>
</div>
@@ -117,14 +120,14 @@ const HistoryTabs = () => {
{/* Comment */}
{order.comment && (
<div className="mt-3 bg-white p-3 rounded-lg shadow-sm border border-gray-200">
<div className="mt-2 bg-white p-2.5 rounded-lg shadow-sm border border-gray-100">
<div className="flex items-start gap-2">
<MessageSquare className="w-4 h-4 text-blue-600 mt-0.5 flex-shrink-0" />
<div className="flex-1">
<p className="text-xs font-medium text-gray-500 mb-1">
<MessageSquare className="w-3.5 h-3.5 text-blue-600 mt-0.5 flex-shrink-0" />
<div className="flex-1 min-w-0">
<p className="text-[10px] font-medium text-gray-500 mb-0.5">
{t('Izoh')}:
</p>
<p className="text-sm text-gray-700 leading-relaxed">
<p className="text-xs text-gray-700 leading-relaxed line-clamp-3">
{order.comment}
</p>
</div>
@@ -134,7 +137,7 @@ const HistoryTabs = () => {
</div>
{/* Products */}
<div className="p-3 md:p-4 space-y-3">
<div className="p-2.5 md:p-4 space-y-2 md:space-y-3">
{order.items.map((item, index) => {
const product = item.product;
@@ -147,12 +150,12 @@ const HistoryTabs = () => {
return (
<div
key={item.id}
className="border-2 border-gray-100 rounded-xl p-3 md:p-4 bg-gradient-to-br from-white to-gray-50 hover:shadow-md transition-shadow"
className="border border-gray-100 rounded-lg p-2.5 md:p-4 bg-white hover:shadow-sm transition-shadow"
>
<div className="flex gap-3 md:gap-4">
{/* Image */}
<div className="flex gap-2.5 md:gap-4">
{/* Image — smaller on mobile */}
<div className="flex-shrink-0">
<div className="w-16 h-16 md:w-24 md:h-24 bg-gray-100 rounded-lg overflow-hidden border-2 border-gray-200">
<div className="w-14 h-14 md:w-24 md:h-24 bg-gray-50 rounded-lg overflow-hidden border border-gray-200">
<Image
src={productImage}
alt={product.name}
@@ -166,55 +169,47 @@ const HistoryTabs = () => {
{/* Info */}
<div className="flex-1 min-w-0">
<div className="flex flex-col md:flex-row md:items-start md:justify-between gap-2 mb-2">
<div className="min-w-0">
<div className="flex items-center gap-2 mb-1">
<span className="bg-blue-100 text-blue-800 text-xs font-semibold px-2 py-1 rounded">
{index + 1}
</span>
<h3 className="font-bold text-sm md:text-lg text-gray-900 truncate">
{product.name}
</h3>
</div>
{product.short_name && (
<p className="text-xs md:text-sm text-gray-600 line-clamp-2">
{product.short_name}
</p>
)}
</div>
<div className="text-left md:text-right">
<p className="text-xs text-gray-500">
{t('Mahsulotlar narxi')}
</p>
<p className="text-base md:text-lg font-bold text-blue-600">
{formatPrice(Number(item.price), true)}
</p>
{/* Name row */}
<div className="flex items-start justify-between gap-1 mb-1.5">
<div className="flex items-center gap-1.5 min-w-0">
<span className="bg-blue-100 text-blue-800 text-[10px] font-semibold px-1.5 py-0.5 rounded flex-shrink-0">
{index + 1}
</span>
<h3 className="font-bold text-sm text-gray-900 truncate">
{product.name}
</h3>
</div>
<p className="text-sm font-bold text-blue-600 flex-shrink-0">
{formatPrice(Number(item.price), true)}
</p>
</div>
{/* Details */}
<div className="grid grid-cols-2 gap-2 md:gap-3 p-2 md:p-3 bg-white rounded-lg border border-gray-200">
{product.short_name && (
<p className="text-xs text-gray-500 line-clamp-1 mb-1.5">
{product.short_name}
</p>
)}
{/* Qty + Total — single row on mobile */}
<div className="flex items-center justify-between bg-gray-50 rounded-lg px-2.5 py-1.5 border border-gray-100">
<div>
<span className="text-xs text-gray-500">
<span className="text-[10px] text-gray-400 block">
{t('Miqdor')}
</span>
<p className="text-sm md:text-base font-bold">
<span className="text-xs font-bold">
{item.quantity}
</p>
</span>
</div>
<div className="text-right">
<span className="text-xs text-gray-500">
<span className="text-[10px] text-gray-400 block">
{t('Jami')}
</span>
<p className="text-sm md:text-base font-bold text-green-600">
<span className="text-xs font-bold text-green-600">
{formatPrice(
Number(item.price) * item.quantity,
true,
)}
</p>
</span>
</div>
</div>
</div>
@@ -225,18 +220,18 @@ const HistoryTabs = () => {
</div>
{/* Footer */}
<div className="bg-gradient-to-r from-gray-50 to-blue-50 p-3 md:p-4 border-t-2 border-gray-200">
<div className="space-y-1 md:space-y-2 text-sm">
<div className="flex justify-between text-gray-600">
<div className="bg-gradient-to-r from-gray-50 to-blue-50 px-3 py-3 md:p-4 border-t border-gray-200">
<div className="space-y-1 text-xs md:text-sm">
<div className="flex justify-between text-gray-500">
<span>{t('Mahsulotlar narxi')}:</span>
<span className="font-semibold">
<span className="font-semibold text-gray-700">
{formatPrice(totalPrice, true)}
</span>
</div>
<div className="flex justify-between text-gray-600">
<div className="flex justify-between text-gray-500">
<span>{t('Mahsulotlar soni')}:</span>
<span className="font-semibold">
<span className="font-semibold text-gray-700">
{order.items.reduce(
(sum, item) => sum + item.quantity,
0,
@@ -246,8 +241,10 @@ const HistoryTabs = () => {
</div>
<div className="border-t border-dashed pt-2 flex justify-between items-center">
<span className="font-bold">{t('Umumiy summa')}:</span>
<span className="text-lg md:text-2xl font-bold text-green-600">
<span className="font-bold text-sm md:text-base">
{t('Umumiy summa')}:
</span>
<span className="text-base md:text-2xl font-bold text-green-600">
{formatPrice(totalPrice, true)}
</span>
</div>
@@ -258,7 +255,7 @@ const HistoryTabs = () => {
onClick={() =>
router.push(`/profile/refresh-order?id=${order.id}`)
}
className="w-full md:w-auto mt-3 gap-2"
className="w-full mt-3 gap-2 text-sm h-9"
>
<RefreshCw className="w-4 h-4" />
{t('Qayta buyurtma')}

View File

@@ -129,7 +129,7 @@ const Profile = () => {
</div>
{/* Main Content */}
<main className="flex-1 md:p-4 lg:p-8 lg:pb-8">
<main className="flex-1 p-2 overflow-hidden">
<div className="lg:hidden flex items-center justify-between mb-4 md:mb-6">
<div className="flex items-center gap-2 md:gap-3">
<Avatar className="w-10 h-10 md:w-12 md:h-12 ring-2 ring-emerald-500 ring-offset-2">

View File

@@ -16,55 +16,57 @@ const SearchResult = () => {
const t = useTranslations();
const searchParams = useSearchParams();
const query = searchParams.get('q') || '';
const query = searchParams.get('search') || '';
const [inputValue, setInputValue] = useState(query);
/* 🔹 Input va URL sync */
/* 🔹 URL → Input sync */
useEffect(() => {
setInputValue(query);
}, [query]);
/* 🔹 Debounce → Input → URL sync */
useEffect(() => {
const delay = setTimeout(() => {
if (!inputValue.trim()) {
router.replace('/search');
} else {
router.replace(`/search?search=${encodeURIComponent(inputValue)}`);
}
}, 400);
return () => clearTimeout(delay);
}, [inputValue, router]);
/* 🔹 Default product list */
const { data: productList, isLoading: listLoading } = useQuery({
queryKey: ['product_list'],
queryFn: () => product_api.list({ page: 1, page_size: 12 }),
select: (res) => res.data.results,
enabled: !query,
staleTime: 0,
});
/* 🔹 Search query */
const { data: searchList, isLoading: searchLoading } = useQuery({
queryKey: ['search', query],
queryKey: ['search', query, inputValue],
queryFn: () =>
product_api.search({
search: query,
search: inputValue, // agar backend `q` kutsa → q: query
page: 1,
page_size: 12,
}),
select: (res) => {
return res.data.products;
},
select: (res) => res.data.products,
enabled: !!query,
staleTime: 0,
});
const data = query ? (searchList ?? []) : (productList ?? []);
const isLoading = query ? searchLoading : listLoading;
/* 🔹 Handlers */
const handleSearch = (value: string) => {
setInputValue(value);
if (!value.trim()) {
router.push('/search');
return;
}
router.push(`/search?q=${encodeURIComponent(value)}`);
};
const clearSearch = () => {
setInputValue('');
router.push('/search');
router.replace('/search');
};
return (
@@ -77,7 +79,7 @@ const SearchResult = () => {
<Input
value={inputValue}
placeholder={t('Mahsulot nomi')}
onChange={(e) => handleSearch(e.target.value)}
onChange={(e) => setInputValue(e.target.value)}
className="w-full pl-10 pr-10 h-12"
/>
@@ -86,7 +88,7 @@ const SearchResult = () => {
onClick={clearSearch}
className="absolute right-3 top-1/2 -translate-y-1/2"
>
<X />
<X className="w-5 h-5" />
</button>
)}
</div>
@@ -97,10 +99,10 @@ const SearchResult = () => {
<div className="text-center py-20">{t('Yuklanmoqda')}...</div>
) : data.length > 0 ? (
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
{data.map((products) => (
{data.map((product) => (
<ProductCard
product={products as ProductListResult}
key={(products as ProductListResult).id}
key={(product as ProductListResult).id}
product={product as ProductListResult}
/>
))}
</div>

View File

@@ -196,6 +196,8 @@ export function ProductCard({
onSuccess: () => {
queryClient.refetchQueries({ queryKey: ['product_list'] });
queryClient.refetchQueries({ queryKey: ['list'] });
queryClient.refetchQueries({ queryKey: ['all_products'] });
queryClient.refetchQueries({ queryKey: ['favourite_product'] });
},

View File

@@ -429,7 +429,7 @@ const Navbar = () => {
onBlur={() => setTimeout(() => setSearchOpen(false), 200)}
onKeyDown={(e) => {
if (e.key === 'Enter' && query.trim()) {
router.push(`/search?q=${encodeURIComponent(query)}`);
router.push(`/search?search=${encodeURIComponent(query)}`);
setSearchOpen(false);
}
}}