//sanity/queries/page.ts
import { groq } from "next-sanity";
import { client } from "../lib/client";
import { Category, Component, License, Tag } from "@/types/types";
import qs from "query-string";
interface Query {
category?: string;
tag?: string;
}
export const getComponents = async (query: Query): Promise<Component[]> => {
const url = qs.stringify({
query: {
category: query.category,
tag: query.tag,
},
});
const getComponentQuery = groq`*[_type =="component"] | order(name asc) {
name,
"slug": slug.current,
"imageUrl": mainImage.asset->url,
desc,
"category": categories[]->slug.current,
"tag": tags[]->slug.current,
"plan": license->title,
publishedAt
}`;
return await client.fetch(getComponentQuery, {
revalidate: new Date().getSeconds(),
});
};
export const getComponentTag = async (): Promise<Tag[]> => {
const getTagQuery = groq`*[_type =="componentTag"] | order(title asc) {
title,
"slug": slug.current,
}`;
return await client.fetch(getTagQuery, {
revalidate: new Date().getSeconds(),
});
};
export const getTemplateTag = async (): Promise<Tag[]> => {
const getTagQuery = groq`*[_type =="templateTag"] | order(title asc) {
title,
"slug": slug.current,
}`;
return await client.fetch(getTagQuery, {
revalidate: new Date().getSeconds(),
});
};
//types/types.ts
export interface Component {
slug: string;
category: Category;
tag: Tag;
name: string;
desc: string;
imageUrl: string;
}
export interface Category {
slug: string;
title: string;
}
export interface Tag {
slug: string;
title: string;
}
//Filter/filter.tsx
"use client";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { Category, Tag } from "@/types/types";
import { useSearchParams, useRouter } from "next/navigation";
import qs from "query-string";
import React from "react";
interface Props {
data: (Category | Tag)[];
name: string;
valueKey: string;
}
const Filter = ({ data, name, valueKey }: Props) => {
const searchParams = useSearchParams();
const router = useRouter();
const selectedValue = searchParams.get(valueKey);
const onClick = (slug: string) => {
const current = qs.parse(searchParams.toString());
const query = {
...current,
[valueKey]: slug,
};
if (current[valueKey] === slug) {
query[valueKey] = null;
}
const url = qs.stringifyUrl(
{
url: window.location.href,
query,
},
{ skipNull: true }
);
router.push(url);
};
return (
<div className="mb-8">
<h3 className="text-lg font-semibold">{name}</h3>
<hr className="my-4" />
<div className="flex flex-wrap gap-2">
{data.map((filter: any) => (
<div key={filter.slug} className="flex items-center">
<Button
size="sm"
className={cn(
"rounded-md text-sm text-gray-800 bg-white border border-gray-300 shadow-
none",
selectedValue === filter.slug && "bg-black text-white"
)}
onClick={() => onClick(filter.slug)}
>
{filter.title}
</Button>
</div>
))}
</div>
</div>
);
};
//app/components/page.tsx
export const revalidate = 0;
import Filter from "@/components/elements/Filter/filter";
import { ElementCard, NoResult } from "@/components/elements";
import Sidebar from "@/components/elements/props/props";
import Sorting from "@/components/elements/sorting/sorting";
import MobileNav from "@/components/layouts/mobile-menu/mobile-menu";
import { Showcase } from "@/components/sections";
import {
getComponentCategory,
getComponents,
getComponentTag,
} from "@/sanity/queries/page";
import React from "react";
type Props = {
searchParams: {
category: string;
tag: string;
};
};
const ComponentPage = async ({ searchParams }: Props) => {
const components = await getComponents({
category: searchParams.category,
tag: searchParams.tag,
});
const categories = await getComponentCategory();
const tags = await getComponentTag();
return (
<div>
<div className="relative flex items-start justify-between w-full px-4 lg:px-8
py- 2 border-b">
<MobileNav>
<Filter valueKey="category" name="Categories" data={categories} />
<Filter valueKey="tag" name="Tags" data={tags} />
</MobileNav>
<div>
<Sidebar />
</div>
<div className="flex items-center gap-2">
<h2 className="text-gray-500">Sort by:</h2>
<Sorting />
</div>
</div>
<div className="mt-6">
{components.length === 0 && <NoResult />}
<Showcase>
{components.map((item) => (
<ElementCard key={item.slug} data={item} />
))}
</Showcase>
</div>
</div>
);
};
export default ComponentPage;
I am building a Nextjs app using Sanity.io as my backend, and I am trying to filter through my data from Sanity, but unfortunately, it doesn’t seem to be working. The filter parameters are the category
and tag
, and with query-string
the filters seem to be working just fine. The filters change the URL when clicked by category and by tag, but those filters are not applied on the components
fetched from Sanity. I think the problem has to do with my query-string
inside getComponents
, but either way I am not able to solve the problem.
Your help would be appreciated. Thanks in advance.