Skip to content

Commit

Permalink
Enable filter by tags (#212)
Browse files Browse the repository at this point in the history
Tags can be clicked and will show posts that are related to that tag.
  • Loading branch information
NiallJoeMaher authored Mar 30, 2023
1 parent d41b9d4 commit 53052f2
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 8 deletions.
11 changes: 8 additions & 3 deletions pages/articles/[slug].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
GetServerSidePropsContext,
} from "next";
import { Menu, Transition } from "@headlessui/react";
import Link from "next/link";
import Head from "next/head";
import {
HeartIcon,
Expand Down Expand Up @@ -102,7 +103,10 @@ const ArticlePage: NextPage = ({
<meta name="msapplication-config" content="browserconfig.xml" />
<meta name="theme-color" content="#000" />
<meta property="og:type" content="article" />
<meta property="og:url" content={`https://${host}/articles/${post.slug}`} />
<meta
property="og:url"
content={`https://${host}/articles/${post.slug}`}
/>
<meta
name="image"
property="og:image"
Expand Down Expand Up @@ -209,12 +213,13 @@ const ArticlePage: NextPage = ({
{post.tags.length > 0 && (
<section className="flex flex-wrap gap-3">
{post.tags.map(({ tag }) => (
<div
<Link
href={`/articles?tag=${tag.title.toLowerCase()}`}
key={tag.title}
className="bg-gradient-to-r from-orange-400 to-pink-600 hover:bg-pink-700 text-white py-1 px-3 rounded-full text-xs font-bold"
>
{tag.title}
</div>
</Link>
))}
</section>
)}
Expand Down
28 changes: 24 additions & 4 deletions pages/articles/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Children, Fragment, useEffect } from "react";
import Head from "next/head";
import { TagIcon } from "@heroicons/react/outline";
import ArticlePreview from "../../components/ArticlePreview/ArticlePreview";
import ArticleLoading from "../../components/ArticlePreview/ArticleLoading";
import Layout from "../../components/Layout/Layout";
Expand All @@ -10,7 +11,8 @@ import { useRouter } from "next/router";
const ArticlesPage = () => {
const router = useRouter();

const { filter } = router.query;
const { filter, tag: dirtyTag } = router.query;
const tag = typeof dirtyTag === "string" ? dirtyTag.toLowerCase() : null;

type Filter = "newest" | "oldest" | "top";
const filters: Filter[] = ["newest", "oldest", "top"];
Expand All @@ -27,7 +29,7 @@ const ArticlesPage = () => {

const { status, data, isFetchingNextPage, fetchNextPage, hasNextPage } =
trpc.post.all.useInfiniteQuery(
{ limit: 15, sort: selectedSortFilter },
{ limit: 15, sort: selectedSortFilter, tag },
{
getNextPageParam: (lastPage) => lastPage.nextCursor,
}
Expand All @@ -41,6 +43,10 @@ const ArticlesPage = () => {
}
}, [inView]);

// @TODO make a list of words like "JavaScript" that we can map the words to if they exist
const capitalize = (str: string) =>
str.replace(/(?:^|\s|["'([{])+\S/g, (match) => match.toUpperCase());

return (
<>
<Head>
Expand All @@ -67,7 +73,14 @@ const ArticlesPage = () => {
<div className="relative sm:mx-auto max-w-2xl mx-4">
<div className="my-8 border-b-2 pb-4 flex justify-between items-center">
<h1 className="text-3xl tracking-tight font-extrabold text-gray-50 sm:text-4xl ">
Articles
{typeof tag === "string" ? (
<div className="flex justify-center items-center">
<TagIcon className="text-neutral-200 h-6 w-6 mr-3" />
{capitalize(tag)}
</div>
) : (
"Articles"
)}
</h1>
<div>
<label htmlFor="filter" className="sr-only">
Expand All @@ -78,7 +91,11 @@ const ArticlesPage = () => {
name="filter"
className="capitalize mt-2 block w-full rounded-md border-0 py-1.5 pl-3 pr-10 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-pink-600 sm:text-sm sm:leading-6 "
onChange={(e) => {
router.push(`/articles?filter=${e.target.value}`);
router.push(
`/articles?filter=${e.target.value}${
tag ? `&tag=${tag}` : ""
}`
);
}}
value={selectedSortFilter}
>
Expand Down Expand Up @@ -131,6 +148,9 @@ const ArticlesPage = () => {
</Fragment>
);
})}
{status === "success" && !data.pages[0].posts.length && (
<h2 className="text-lg">No results founds</h2>
)}
{isFetchingNextPage ? <ArticleLoading /> : null}
<span className="invisible" ref={ref}>
intersection observer marker
Expand Down
1 change: 1 addition & 0 deletions schema/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const GetPostsSchema = z.object({
limit: z.number().min(1).max(100).nullish(),
cursor: z.string().nullish(),
sort: z.enum(["newest", "oldest", "top"]),
tag: z.string().nullish(),
});

export type SavePostInput = z.TypeOf<typeof SavePostSchema>;
Expand Down
16 changes: 15 additions & 1 deletion server/trpc/router/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ export const postRouter = router({
all: publicProcedure.input(GetPostsSchema).query(async ({ ctx, input }) => {
const userId = ctx.session?.user?.id;
const limit = input?.limit ?? 50;
const { cursor, sort } = input;
const { cursor, sort, tag } = input;

const orderMapping = {
newest: {
published: "desc" as Prisma.SortOrder,
Expand All @@ -262,6 +263,19 @@ export const postRouter = router({
NOT: {
published: null,
},
...(tag
? {
tags: {
some: {
tag: {
title: {
contains: tag?.toUpperCase() || "",
},
},
},
},
}
: {}),
},
select: {
id: true,
Expand Down

0 comments on commit 53052f2

Please sign in to comment.