mirror of
https://github.com/vercel/commerce.git
synced 2025-07-23 04:36:49 +00:00
feat: filter by product meta field
Signed-off-by: Chloe <pinkcloudvnn@gmail.com>
This commit is contained in:
58
components/layout/search/filters/filters-list.tsx
Normal file
58
components/layout/search/filters/filters-list.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
'use client';
|
||||
import clsx from 'clsx';
|
||||
import { Filter } from 'lib/shopify/types';
|
||||
import { createUrl } from 'lib/utils';
|
||||
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
||||
|
||||
const Filters = ({ filters }: { filters: Filter[] }) => {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const handleChange = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
const formData = new FormData(e.currentTarget);
|
||||
const newSearchParams = new URLSearchParams(searchParams);
|
||||
|
||||
Array.from(formData.keys()).forEach((key) => {
|
||||
const values = formData.getAll(key);
|
||||
newSearchParams.delete(key);
|
||||
values.forEach((value) => newSearchParams.append(key, String(value)));
|
||||
});
|
||||
|
||||
router.replace(createUrl(pathname, newSearchParams), { scroll: false });
|
||||
};
|
||||
|
||||
return (
|
||||
<form onChange={handleChange} className="space-y-5 divide-y divide-gray-200">
|
||||
{filters.map(({ label, id, values }) => (
|
||||
<div key={id} className="flex h-auto max-h-[550px] flex-col gap-y-3 overflow-hidden pt-5">
|
||||
<div className="block text-sm font-medium text-gray-900">{label}</div>
|
||||
<div className="flex-grow space-y-3 overflow-auto pb-1 pl-1 pt-2">
|
||||
{values.map(({ id: valueId, label, count, value }) => (
|
||||
<label
|
||||
key={valueId}
|
||||
htmlFor={valueId}
|
||||
className={clsx('flex items-center gap-2 text-sm text-gray-600', {
|
||||
'cursor-not-allowed opacity-50': count === 0
|
||||
})}
|
||||
>
|
||||
<input
|
||||
id={valueId}
|
||||
name={id}
|
||||
defaultChecked={searchParams.getAll(id).includes(String(value))}
|
||||
type="checkbox"
|
||||
value={String(value)}
|
||||
className="h-4 w-4 rounded border-gray-300 text-secondary focus:ring-secondary disabled:cursor-not-allowed disabled:opacity-50"
|
||||
disabled={count === 0}
|
||||
/>
|
||||
<span>{`${label} (${count})`}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default Filters;
|
@@ -1,7 +1,9 @@
|
||||
import { getMenu } from 'lib/shopify';
|
||||
import { Filter } from 'lib/shopify/types';
|
||||
import Link from 'next/link';
|
||||
import FiltersList from './filters-list';
|
||||
|
||||
const Filters = async ({ collection }: { collection: string }) => {
|
||||
const Filters = async ({ collection, filters }: { collection: string; filters: Filter[] }) => {
|
||||
const menu = await getMenu('main-menu');
|
||||
const subMenu = menu.find((item) => item.path === `/search/${collection}`)?.items || [];
|
||||
return (
|
||||
@@ -23,6 +25,8 @@ const Filters = async ({ collection }: { collection: string }) => {
|
||||
</ul>
|
||||
</>
|
||||
) : null}
|
||||
<h3 className="sr-only">Filters</h3>
|
||||
<FiltersList filters={filters} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@@ -8,15 +8,17 @@ const SortingItem = ({ item, hover }: { item: SortFilterItem; hover: boolean })
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const active = searchParams.get('sort') === item.slug;
|
||||
const q = searchParams.get('q');
|
||||
const href = createUrl(
|
||||
pathname,
|
||||
new URLSearchParams({
|
||||
...(q && { q }),
|
||||
...(item.slug && item.slug.length && { sort: item.slug })
|
||||
})
|
||||
);
|
||||
|
||||
const newSearchParams = new URLSearchParams(searchParams);
|
||||
if (item.slug && item.slug.length) {
|
||||
newSearchParams.set('sort', item.slug);
|
||||
} else {
|
||||
newSearchParams.delete('sort');
|
||||
}
|
||||
|
||||
const href = createUrl(pathname, newSearchParams);
|
||||
const DynamicTag = active ? 'p' : Link;
|
||||
|
||||
return (
|
||||
<DynamicTag
|
||||
prefetch={!active ? false : undefined}
|
||||
|
Reference in New Issue
Block a user