();
+ const router = useRouter();
+ const searchParams = useSearchParams();
+ const SearchQueryUpdate = debounce((searchQuery) => {
+ const params = new URLSearchParams(searchParams);
+ if (searchQuery) {
+ params.set("search", searchQuery);
+ } else {
+ params.delete("search");
+ }
+ router.push(`?${params}`, { scroll: false });
+ }, 300);
+
+ // retrieving state from url, could be useful to share the filtered posts
+ useEffect(() => {
+ setSearchQuery(searchParams.get("search") || "");
+ }, []);
+
+ // calling filter upon change in search keyword
+ useEffect(() => {
+ SearchQueryUpdate(searchQuery);
+ }, [searchQuery]);
+ return (
+
+ setSearchQuery(e.target.value as string)}
+ value={searchQuery}
+ />
+
+ );
+};
+
+export default Search;
diff --git a/components/posts/create.tsx b/components/posts/create.tsx
index 5d3b618..eb34038 100644
--- a/components/posts/create.tsx
+++ b/components/posts/create.tsx
@@ -81,6 +81,7 @@ export const CreatePostSheet = ({
onSuccess: () => {
toast.success("Feature Request Added");
queryClient.invalidateQueries({ queryKey: ["posts", boardId] });
+ form.reset();
setOpen(false);
},
onError: (error) => {
diff --git a/components/posts/list.tsx b/components/posts/list.tsx
index de80a64..dda38b4 100644
--- a/components/posts/list.tsx
+++ b/components/posts/list.tsx
@@ -1,11 +1,12 @@
"use client";
-import React from "react";
+import React, { useEffect, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import Link from "next/link";
import { BoardPostType, PostStatus } from "@prisma/client";
import { JsonValue } from "@prisma/client/runtime/library";
import { motion } from "framer-motion";
+import Fuse from "fuse.js";
import Spinner from "@/components/common/spinner";
@@ -17,6 +18,7 @@ interface PostsListProps {
currentUserId: string;
cols?: number;
hasAccess: boolean;
+ searchKeyword: string;
}
interface Post {
@@ -53,7 +55,9 @@ export function PostsList({
currentUserId,
cols = 2,
hasAccess,
+ searchKeyword,
}: PostsListProps) {
+ const [isSearching, setIsSearching] = useState(false);
const { data, isLoading } = useQuery<{ posts: Post[] }>({
queryKey: ["posts", boardId],
queryFn: async () => {
@@ -67,7 +71,24 @@ export function PostsList({
},
});
- if (isLoading) {
+ const posts = data?.posts || [];
+ const [filteredPosts, setFilteredPosts] = useState(posts);
+ useEffect(() => {
+ if (searchKeyword) {
+ setIsSearching(true);
+ const fuseOptions = {
+ keys: ["title", "description"],
+ };
+
+ const fuse = new Fuse(posts, fuseOptions);
+ const results = fuse.search(searchKeyword);
+ setIsSearching(false);
+ setFilteredPosts(results.map((result) => result.item));
+ } else {
+ setFilteredPosts(posts);
+ }
+ }, [searchKeyword, data]);
+ if (isLoading || isSearching) {
return (
@@ -75,10 +96,8 @@ export function PostsList({
);
}
- const posts = data?.posts || [];
-
// Sort posts by createdAt in descending order
- const sortedPosts = [...posts].sort(
+ const sortedPosts = [...filteredPosts].sort(
(a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
);
@@ -111,10 +130,10 @@ export function PostsList({
currentUserId={currentUserId}
hasAccess={hasAccess}
layout={view}
- // @ts-ignore
+ // @ts-expect-error: will improve ts later
post={post}
postType={post.postType}
- // @ts-ignore
+ // @ts-expect-error: will improve ts later
user={post.user!}
/>
diff --git a/package.json b/package.json
index 72735ce..12c2e91 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
"cmdk": "1.0.0",
"date-fns": "4.0.0-beta.1",
"framer-motion": "~11.1.1",
+ "fuse.js": "^7.0.0",
"geist": "^1.3.1",
"intl-messageformat": "^10.5.0",
"jsonwebtoken": "^9.0.2",