From 9ba0a7b23cec73a5cf9ad8f178c1c2734d1ddf7a Mon Sep 17 00:00:00 2001 From: Mohit Date: Wed, 29 Jul 2026 18:08:25 +0530 Subject: [PATCH 1/2] fix: prevent search viewport jump to top --- src/components/custom/search-bar.tsx | 6 +++--- src/components/custom/tags-filter.tsx | 2 +- src/components/discussions/categories-carousel.tsx | 4 ++-- src/components/discussions/sort-by-dropdown.tsx | 2 +- src/components/projects/sort-by-dropdown.tsx | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/custom/search-bar.tsx b/src/components/custom/search-bar.tsx index 29292e1..cfa9a57 100644 --- a/src/components/custom/search-bar.tsx +++ b/src/components/custom/search-bar.tsx @@ -18,11 +18,11 @@ export default function Search({ placeholder }: { placeholder: string }) { } else { params.delete('query'); } - replace(`${pathname}?${params.toString()}`); + replace(`${pathname}?${params.toString()}`, { scroll: false }); }, 300); return ( -
+
e.preventDefault()} className="relative min-w-60 flex flex-1 flex-shrink-0"> @@ -35,6 +35,6 @@ export default function Search({ placeholder }: { placeholder: string }) { defaultValue={searchParams.get('query')?.toString()} /> -
+ ); } \ No newline at end of file diff --git a/src/components/custom/tags-filter.tsx b/src/components/custom/tags-filter.tsx index 52edf4d..682775f 100644 --- a/src/components/custom/tags-filter.tsx +++ b/src/components/custom/tags-filter.tsx @@ -44,7 +44,7 @@ export function TagsFilter({ for: filterType }: { for: 'discussions' | 'projects } else { params.delete('tags'); } - replace(`${pathname}?${params.toString()}`); + replace(`${pathname}?${params.toString()}`, { scroll: false }); }; const onSelectTag = (tag: string) => { diff --git a/src/components/discussions/categories-carousel.tsx b/src/components/discussions/categories-carousel.tsx index 86a0d2b..600906d 100644 --- a/src/components/discussions/categories-carousel.tsx +++ b/src/components/discussions/categories-carousel.tsx @@ -19,14 +19,14 @@ export function CategoriesCarousel() { const params = new URLSearchParams(searchParams); const currentcategory = params.get('category') as DiscussionCategory | null; - const handleFilter = (category : DiscussionCategory | null) => { + const handleFilter = (category: DiscussionCategory | null) => { params.set('page', '1'); if (category) { params.set('category', category); } else { params.delete('category'); } - replace(`${pathname}?${params.toString()}`); + replace(`${pathname}?${params.toString()}`, { scroll: false }); }; return ( diff --git a/src/components/discussions/sort-by-dropdown.tsx b/src/components/discussions/sort-by-dropdown.tsx index dd4ab7a..598b536 100644 --- a/src/components/discussions/sort-by-dropdown.tsx +++ b/src/components/discussions/sort-by-dropdown.tsx @@ -22,7 +22,7 @@ export function SortByDropdown() { params.delete('orderBy'); params.delete('sort'); } - replace(`${pathname}?${params.toString()}`); + replace(`${pathname}?${params.toString()}`, { scroll: false }); }; return ( diff --git a/src/components/projects/sort-by-dropdown.tsx b/src/components/projects/sort-by-dropdown.tsx index d345bf3..aad078b 100644 --- a/src/components/projects/sort-by-dropdown.tsx +++ b/src/components/projects/sort-by-dropdown.tsx @@ -22,7 +22,7 @@ export function SortByDropdown() { params.delete('orderBy'); params.delete('sort'); } - replace(`${pathname}?${params.toString()}`); + replace(`${pathname}?${params.toString()}`, { scroll: false }); }; return ( @@ -35,7 +35,7 @@ export function SortByDropdown() { ? "oldest" : "most recent" } - + From 9ab600785e246fceefc200d9f6ad7fef7c1478a5 Mon Sep 17 00:00:00 2001 From: Mohit Date: Mon, 10 Aug 2026 18:55:14 +0530 Subject: [PATCH 2/2] feat: implement search, filter, and sorting components for discussions and projects pages --- app/discussions/page.tsx | 2 +- app/profile/discussions/page.tsx | 2 +- app/profile/projects/page.tsx | 2 +- app/projects/page.tsx | 2 +- src/components/custom/pagination.tsx | 7 +- src/components/custom/search-bar.tsx | 85 ++++++++++--------- src/components/custom/tags-filter.tsx | 7 +- .../discussions/categories-carousel.tsx | 9 +- .../discussions/sort-by-dropdown.tsx | 6 +- .../projects/activity-status-selection.tsx | 6 +- src/components/projects/domains-carousel.tsx | 9 +- src/components/projects/project-forum.tsx | 2 +- src/components/projects/sort-by-dropdown.tsx | 6 +- 13 files changed, 88 insertions(+), 57 deletions(-) diff --git a/app/discussions/page.tsx b/app/discussions/page.tsx index 560f7cf..e567cfb 100644 --- a/app/discussions/page.tsx +++ b/app/discussions/page.tsx @@ -46,7 +46,7 @@ export default async function Page(props: { - }> + }> diff --git a/app/profile/discussions/page.tsx b/app/profile/discussions/page.tsx index 4b75af2..491d77b 100644 --- a/app/profile/discussions/page.tsx +++ b/app/profile/discussions/page.tsx @@ -30,7 +30,7 @@ export default async function MyProjects(props: { - }> + }> diff --git a/app/profile/projects/page.tsx b/app/profile/projects/page.tsx index fcd45ca..3538f77 100644 --- a/app/profile/projects/page.tsx +++ b/app/profile/projects/page.tsx @@ -35,7 +35,7 @@ export default async function MyProjects(props: { Start A New Project - }> + }> diff --git a/app/projects/page.tsx b/app/projects/page.tsx index 7d3fdc7..d7a515c 100644 --- a/app/projects/page.tsx +++ b/app/projects/page.tsx @@ -48,7 +48,7 @@ export default async function Page(props: { - }> + }> diff --git a/src/components/custom/pagination.tsx b/src/components/custom/pagination.tsx index 5eeaaa4..28eab31 100644 --- a/src/components/custom/pagination.tsx +++ b/src/components/custom/pagination.tsx @@ -12,7 +12,7 @@ export default function CustomPagination({ totalPages }: { totalPages: number }) const createPageURL = (pageNumber: number | string) => { const params = new URLSearchParams(searchParams); params.set('page', pageNumber.toString()); - router.push(`${pathname}?${params.toString()}`); + router.push(`${pathname}?${params.toString()}`, { scroll: false }); }; return ( @@ -23,7 +23,7 @@ export default function CustomPagination({ totalPages }: { totalPages: number }) createPageURL(currentPage - 1)} + onClick={(e) => { e.preventDefault(); if (currentPage > 1) createPageURL(currentPage - 1); }} /> @@ -31,6 +31,7 @@ export default function CustomPagination({ totalPages }: { totalPages: number }) e.preventDefault()} > {currentPage} @@ -41,7 +42,7 @@ export default function CustomPagination({ totalPages }: { totalPages: number }) createPageURL(currentPage + 1)} + onClick={(e) => { e.preventDefault(); if (currentPage < totalPages) createPageURL(currentPage + 1); }} /> diff --git a/src/components/custom/search-bar.tsx b/src/components/custom/search-bar.tsx index cfa9a57..cdc016a 100644 --- a/src/components/custom/search-bar.tsx +++ b/src/components/custom/search-bar.tsx @@ -1,40 +1,45 @@ -'use client'; - -import { Input } from '@/src/components/ui/input'; -import { Label } from '@/src/components/ui/label'; -import { debounce } from '@/src/utils/utils'; -import { SearchIcon } from 'lucide-react'; -import { usePathname, useRouter, useSearchParams } from 'next/navigation'; - -export default function Search({ placeholder }: { placeholder: string }) { - const searchParams = useSearchParams(); - const pathname = usePathname(); - const { replace } = useRouter(); - const handleSearch = debounce((term) => { - const params = new URLSearchParams(searchParams); - params.set('page', '1'); - if (term) { - params.set('query', term); - } else { - params.delete('query'); - } - replace(`${pathname}?${params.toString()}`, { scroll: false }); - }, 300); - - return ( -
e.preventDefault()} className="relative min-w-60 flex flex-1 flex-shrink-0"> - - { - handleSearch(e.target.value); - }} - defaultValue={searchParams.get('query')?.toString()} - /> - - - ); -} \ No newline at end of file +'use client'; + +import { Input } from '@/src/components/ui/input'; +import { Label } from '@/src/components/ui/label'; +import { debounce } from '@/src/utils/utils'; +import { SearchIcon } from 'lucide-react'; +import { usePathname, useRouter, useSearchParams } from 'next/navigation'; +import { useTransition } from 'react'; + +export default function Search({ placeholder }: { placeholder: string }) { + const searchParams = useSearchParams(); + const pathname = usePathname(); + const { replace } = useRouter(); + const [, startTransition] = useTransition(); + + const handleSearch = debounce((term: string) => { + const params = new URLSearchParams(searchParams); + params.set('page', '1'); + if (term) { + params.set('query', term); + } else { + params.delete('query'); + } + startTransition(() => { + replace(`${pathname}?${params.toString()}`, { scroll: false }); + }); + }, 300); + + return ( +
e.preventDefault()} className="relative min-w-60 flex flex-1 flex-shrink-0"> + + { + handleSearch(e.target.value); + }} + defaultValue={searchParams.get('query')?.toString()} + /> + + + ); +} \ No newline at end of file diff --git a/src/components/custom/tags-filter.tsx b/src/components/custom/tags-filter.tsx index 682775f..d32fa78 100644 --- a/src/components/custom/tags-filter.tsx +++ b/src/components/custom/tags-filter.tsx @@ -1,7 +1,7 @@ 'use client' import { usePathname, useRouter, useSearchParams } from "next/navigation"; -import { useEffect, useState } from "react"; +import { useEffect, useState, useTransition } from "react"; import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; import { Button } from "../ui/button"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "../ui/command"; @@ -13,6 +13,7 @@ export function TagsFilter({ for: filterType }: { for: 'discussions' | 'projects const searchParams = useSearchParams(); const pathname = usePathname(); const { replace } = useRouter(); + const [, startTransition] = useTransition(); const params = new URLSearchParams(searchParams); const currentTags = params.get('tags')?.split(',') || []; const [allTags, setAllTags] = useState([]); @@ -44,7 +45,9 @@ export function TagsFilter({ for: filterType }: { for: 'discussions' | 'projects } else { params.delete('tags'); } - replace(`${pathname}?${params.toString()}`, { scroll: false }); + startTransition(() => { + replace(`${pathname}?${params.toString()}`, { scroll: false }); + }); }; const onSelectTag = (tag: string) => { diff --git a/src/components/discussions/categories-carousel.tsx b/src/components/discussions/categories-carousel.tsx index 600906d..94784bf 100644 --- a/src/components/discussions/categories-carousel.tsx +++ b/src/components/discussions/categories-carousel.tsx @@ -9,6 +9,7 @@ import { } from "@/src/components/ui/carousel" import { DiscussionCategoriesDescriptions, DiscussionCategory } from "@/src/types/enums" import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { useTransition } from "react"; import { Button } from "../ui/button"; import { cn } from "@/src/lib/utils"; @@ -16,6 +17,7 @@ export function CategoriesCarousel() { const searchParams = useSearchParams(); const pathname = usePathname(); const { replace } = useRouter(); + const [, startTransition] = useTransition(); const params = new URLSearchParams(searchParams); const currentcategory = params.get('category') as DiscussionCategory | null; @@ -26,7 +28,9 @@ export function CategoriesCarousel() { } else { params.delete('category'); } - replace(`${pathname}?${params.toString()}`, { scroll: false }); + startTransition(() => { + replace(`${pathname}?${params.toString()}`, { scroll: false }); + }); }; return ( @@ -42,11 +46,12 @@ export function CategoriesCarousel() {