fixed
This commit is contained in:
@@ -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: {
|
||||
|
||||
@@ -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')}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'] });
|
||||
},
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user