Vitron-Front/app/routes/search.$query.tsx
Arda Samadi 9650073b04 Desktop responsive: search page, cart list, masonry grid
- MondrianProductList: add desktop 4-column masonry (mobile 2-col unchanged);
  improves home "for you", search results and seller feed at lg+
- search: hide mobile SearchTopBar at lg, add results heading + centered
  1320px container
- cart list: responsive 2-column grid of cart cards + desktop heading
- MyLayout: desktop chrome gate now covers / , /search/* and /cart

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 21:06:34 +03:30

121 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from "react";
import { MetaFunction } from "@remix-run/node";
import { Link, useNavigate, useParams } from "@remix-run/react";
import { onSearch } from "../utils/helpers";
import { PackageSearch } from "lucide-react";
import { useSearchInfinite } from "../requestHandler/use-search-hooks";
import MondrianProductList from "~/components/MondrianProductList";
import SearchTopBar from "~/components/SearchTopBar";
export default function Search() {
const { query } = useParams();
const navigate = useNavigate();
const [searchValue, setSearchValue] = useState(query || "");
// Update search value when route parameter changes
useEffect(() => {
if (query) {
setSearchValue(query);
}
}, [query]);
// Use infinite search hook to fetch data, passing the route query parameter
const {
data,
isLoading,
isError,
refetch,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
} = useSearchInfinite(query);
return (
<div className="flex flex-col gap-6 bg-WHITE lg:max-w-[1320px] lg:mx-auto lg:w-full lg:px-8 lg:py-6">
<div className="lg:hidden">
<SearchTopBar
searchValue={searchValue}
setSearchValue={setSearchValue}
placeholder="جستجو..."
minimumPrice={320000}
maximumPrice={1000000}
onSearch={() => onSearch(searchValue, navigate)}
/>
</div>
{/* Desktop results heading */}
<div className="hidden lg:block">
<nav className="flex items-center gap-2 text-[13px] text-GRAY">
<Link to="/" className="hover:text-BLACK">
خانه
</Link>
<span>/</span>
<span>جستجو</span>
</nav>
<h1 className="text-[26px] font-extrabold mt-2">
نتایج برای «<span className="text-VITROWN_BLUE">{query}</span>»
</h1>
</div>
<MondrianProductList
products={
data?.pages
.flatMap((page) => page.products)
.map((product) => {
return {
id: product.id,
title: product.title,
images: product.imageUrls || [],
};
}) || []
}
fetchNextPage={fetchNextPage}
hasNextPage={hasNextPage}
isFetchingNextPage={isFetchingNextPage}
isLoading={isLoading}
isError={isError}
refetch={refetch}
emptyState={{
image: <PackageSearch size={80} />,
title: "محصولی در این جستجو یافت نشد",
description: "جستجوی دیگری انجام دهید یا فیلترها را تغییر دهید",
}}
/>
</div>
);
}
export const meta: MetaFunction = ({ params }) => {
const query = params.query;
const title = query ? `جستجو: ${query} | ویترون` : "جستجو | ویترون";
const description = query
? `نتایج جستجو برای "${query}" در ویترون - یافتن بهترین محصولات با قیمت مناسب`
: "جستجو در ویترون - یافتن محصولات مورد نظر با امکانات پیشرفته فیلتر و مرتب‌سازی";
const imageUrl =
"https://vitrownstatics.s3.ir-thr-at1.arvanstorage.ir/SVG-06.svg?versionId=";
return [
{ title },
{ name: "description", content: description },
{
name: "keywords",
content: `جستجو، ${query || ""}, محصولات، ویترون، فیلتر`,
},
{ name: "robots", content: "index, follow" },
// Open Graph
{ property: "og:type", content: "website" },
{ property: "og:title", content: title },
{ property: "og:description", content: description },
{ property: "og:image", content: imageUrl },
{ property: "og:site_name", content: "ویترون" },
{ property: "og:locale", content: "fa_IR" },
// Twitter Card
{ name: "twitter:card", content: "summary_large_image" },
{ name: "twitter:title", content: title },
{ name: "twitter:description", content: description },
{ name: "twitter:image", content: imageUrl },
];
};