Skip to content

Commit

Permalink
Add sort and filter to products page (#143)
Browse files Browse the repository at this point in the history
* burst hack

* more stuff

* fix dev logs

* Add to collections query

* Update SortFilter.tsx

* minor fixup

* daniel lint
  • Loading branch information
cartogram authored Nov 15, 2022
1 parent 4666184 commit 8619e5a
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 5 deletions.
119 changes: 119 additions & 0 deletions templates/demo-store/app/components/SortFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import {useState} from 'react';
import {Heading, Button, Drawer as DrawerComponent} from '~/components';
import {Link, useLocation} from '@remix-run/react';
import type {
FilterType,
Filter,
} from '@shopify/hydrogen-react/storefront-api-types';

type Props = {
filters: Filter[];
};

export function SortFilter({filters}: {filters: Filter[]}) {
const [isOpen, setIsOpen] = useState(false);

return (
<>
<div className="flex items-center justify-end">
<Button variant="secondary" onClick={() => setIsOpen(true)}>
Filter and sort
</Button>
</div>
<Drawer
filters={filters}
isOpen={isOpen}
onClose={() => setIsOpen(false)}
/>
</>
);
}

export function Drawer({
isOpen,
onClose,
filters = [],
}: {
isOpen: boolean;
onClose: () => void;
filters: Filter[];
}) {
const location = useLocation();

return (
<DrawerComponent
open={isOpen}
onClose={onClose}
heading="Filter and sort"
openFrom="right"
>
<>
<nav className="py-8 px-8 md:px-12 ">
{filters.map((filter: Filter) => (
<>
<Heading as="h4" size="lead" className="pb-2">
{filter.label}
</Heading>
<ul key={filter.id} className="pb-8">
{filter.values?.map((option) => {
const params = new URLSearchParams(location.search);

const newParams = filterInputToParams(
filter.type,
option.input as string,
params,
);

const to = `${location.pathname}?${newParams.toString()}`;
return (
<li key={option.id}>
<Link
className="focus:underline hover:underline whitespace-nowrap"
prefetch="intent"
onClick={onClose}
reloadDocument
to={to}
>
{option.label}
</Link>
</li>
);
})}
</ul>
</>
))}
</nav>
</>
</DrawerComponent>
);
}

function filterInputToParams(
type: FilterType,
rawInput: string | Record<string, any>,
params: URLSearchParams,
) {
const input = typeof rawInput === 'string' ? JSON.parse(rawInput) : rawInput;
switch (type) {
case 'PRICE_RANGE':
params.set('minPrice', input.min);
params.set('maxPrice', input.max);
break;
case 'LIST':
Object.entries(input).forEach(([key, value]) => {
if (typeof value === 'string') {
params.set(key, value);
} else if (typeof value === 'boolean') {
params.set(key, value.toString());
} else {
const {name, value: val} = value as {name: string; value: string};
const newInput = {[name]: val};

filterInputToParams(type, newInput, params);
}
});
break;
}

return params;
}
1 change: 1 addition & 0 deletions templates/demo-store/app/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ export {Modal} from './Modal';
export {Link} from './Link';
export {FeaturedCollections} from './FeaturedCollections';
export {Hero} from './Hero';
export {SortFilter} from './SortFilter';
// Sue me
export * from './Icon';
56 changes: 51 additions & 5 deletions templates/demo-store/app/routes/collections/$collectionHandle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import {
type LoaderArgs,
} from '@shopify/hydrogen-remix';
import {useLoaderData} from '@remix-run/react';
import type {Collection as CollectionType} from '@shopify/hydrogen-react/storefront-api-types';
import type {
Collection as CollectionType,
Filter,
} from '@shopify/hydrogen-react/storefront-api-types';
import invariant from 'tiny-invariant';
import {PageHeader, Section, Text} from '~/components';
import {PageHeader, Section, Text, SortFilter} from '~/components';
import {ProductGrid} from '~/components/ProductGrid';
import {getLocalizationFromLang} from '~/lib/utils';

import {PRODUCT_CARD_FRAGMENT} from '~/data';

const PAGINATION_SIZE = 48;
Expand All @@ -23,19 +27,36 @@ export async function loader({

invariant(collectionHandle, 'Missing collectionHandle param');

const cursor = new URL(request.url).searchParams.get('cursor') ?? undefined;
const searchParams = new URL(request.url).searchParams;
const knownFilters = ['cursor', 'productVendor', 'productType', 'available'];

const variantOption: Record<string, string>[] = [];
const variables: Record<string, string> = {};

for (const [key, value] of searchParams.entries()) {
// TODO: Add price min/max to query
if (knownFilters.includes(key)) {
variables[key] = value;
} else {
variantOption.push({name: key, value});
}
}

const {language, country} = getLocalizationFromLang(params.lang);

const {collection} = await storefront.query<{
collection: CollectionType;
}>({
query: COLLECTION_QUERY,
variables: {
...variables,
handle: collectionHandle,
pageBy: PAGINATION_SIZE,
cursor,
language,
country,
available: variables.available === 'false' ? false : true,
// TODO: Can we pass in multiple variantOptions?
variantOption: variantOption.length > 0 ? variantOption[0] : undefined,
},
});

Expand Down Expand Up @@ -74,6 +95,7 @@ export default function Collection() {
)}
</PageHeader>
<Section>
<SortFilter filters={collection.products.filters as Filter[]} />
<ProductGrid
key={collection.id}
collection={collection as CollectionType}
Expand All @@ -92,6 +114,10 @@ const COLLECTION_QUERY = `#graphql
$language: LanguageCode
$pageBy: Int!
$cursor: String
$productVendor: String
$productType: String
$available: Boolean
$variantOption: VariantOptionFilter
) @inContext(country: $country, language: $language) {
collection(handle: $handle) {
id
Expand All @@ -109,7 +135,27 @@ const COLLECTION_QUERY = `#graphql
height
altText
}
products(first: $pageBy, after: $cursor) {
products(
first: $pageBy,
after: $cursor,
filters: {
productVendor: $productVendor,
productType: $productType,
available: $available
variantOption: $variantOption
}
) {
filters {
id
label
type
values {
id
label
count
input
}
}
nodes {
...ProductCard
}
Expand Down

0 comments on commit 8619e5a

Please sign in to comment.