Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/discussions/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default async function Page(props: {
<Search placeholder="Search discussions..." />
<SortByDropdown />
</div>
<Suspense key={query || '' + currentPage} fallback={<DiscussionsSkeleton />}>
<Suspense fallback={<DiscussionsSkeleton />}>
<Discussions creator={creator} query={query} status={status} category={category} tags={tags} currentPage={currentPage} orderBy={orderBy} sort={sort} />
</Suspense>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/profile/discussions/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default async function MyProjects(props: {
<Search placeholder="Search my discussions..." />
<DiscussionFormDialog />
</div>
<Suspense key={query + currentPage} fallback={<DiscussionsSkeleton />}>
<Suspense fallback={<DiscussionsSkeleton />}>
<Discussions editable={true} creator={user.id} query={query} status={status} currentPage={currentPage} />
</Suspense>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/profile/projects/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default async function MyProjects(props: {
Start A New Project
</Link>
</div>
<Suspense key={query + currentPage} fallback={<ProjectsSkeleton />}>
<Suspense fallback={<ProjectsSkeleton />}>
<Projects editable={true} creator={user.id} query={query} status={status} currentPage={currentPage} />
</Suspense>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/projects/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default async function Page(props: {
<ActivityStatusSelection/>
<SortByDropdown />
</div>
<Suspense key={query || '' + currentPage} fallback={<ProjectsSkeleton />}>
<Suspense fallback={<ProjectsSkeleton />}>
<Projects creator={creator} query={query} domain={domain} status={status} currentPage={currentPage} orderBy={orderBy} sort={sort} activityStatus={activityStatus} tags={tags} />
</Suspense>
</div>
Expand Down
7 changes: 4 additions & 3 deletions src/components/custom/pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -23,14 +23,15 @@ export default function CustomPagination({ totalPages }: { totalPages: number })
<PaginationPrevious
aria-disabled={currentPage === 1}
className='text-xs text-foreground aria-disabled:text-muted-foreground aria-disabled:cursor-not-allowed cursor-pointer'
onClick={() => createPageURL(currentPage - 1)}
onClick={(e) => { e.preventDefault(); if (currentPage > 1) createPageURL(currentPage - 1); }}
/>
</PaginationItem>

{/* Current Button */}
<PaginationItem>
<PaginationLink
isActive
onClick={(e) => e.preventDefault()}
>
{currentPage}
</PaginationLink>
Expand All @@ -41,7 +42,7 @@ export default function CustomPagination({ totalPages }: { totalPages: number })
<PaginationNext
aria-disabled={currentPage === totalPages}
className='text-xs text-foreground aria-disabled:text-muted-foreground aria-disabled:cursor-not-allowed cursor-pointer'
onClick={() => createPageURL(currentPage + 1)}
onClick={(e) => { e.preventDefault(); if (currentPage < totalPages) createPageURL(currentPage + 1); }}
/>
</PaginationItem>
</PaginationContent>
Expand Down
85 changes: 45 additions & 40 deletions src/components/custom/search-bar.tsx
Original file line number Diff line number Diff line change
@@ -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()}`);
}, 300);

return (
<div className="relative min-w-60 flex flex-1 flex-shrink-0">
<Label htmlFor="search" className="sr-only">
Search
</Label>
<Input
className="peer block w-full rounded-md border py-[9px] pl-10 text-sm outline-2 text-muted-foreground"
placeholder={placeholder}
onChange={(e) => {
handleSearch(e.target.value);
}}
defaultValue={searchParams.get('query')?.toString()}
/>
<SearchIcon className="absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-muted-foreground" />
</div>
);
}
'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 (
<form onSubmit={(e) => e.preventDefault()} className="relative min-w-60 flex flex-1 flex-shrink-0">
<Label htmlFor="search" className="sr-only">
Search
</Label>
<Input
className="peer block w-full rounded-md border py-[9px] pl-10 text-sm outline-2 text-muted-foreground"
placeholder={placeholder}
onChange={(e) => {
handleSearch(e.target.value);
}}
defaultValue={searchParams.get('query')?.toString()}
/>
<SearchIcon className="absolute left-3 top-1/2 h-[18px] w-[18px] -translate-y-1/2 text-muted-foreground" />
</form>
);
}
7 changes: 5 additions & 2 deletions src/components/custom/tags-filter.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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<string[]>([]);
Expand Down Expand Up @@ -44,7 +45,9 @@ export function TagsFilter({ for: filterType }: { for: 'discussions' | 'projects
} else {
params.delete('tags');
}
replace(`${pathname}?${params.toString()}`);
startTransition(() => {
replace(`${pathname}?${params.toString()}`, { scroll: false });
});
};

const onSelectTag = (tag: string) => {
Expand Down
11 changes: 8 additions & 3 deletions src/components/discussions/categories-carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,28 @@ 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";

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;

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()}`);
startTransition(() => {
replace(`${pathname}?${params.toString()}`, { scroll: false });
});
};

return (
Expand All @@ -42,11 +46,12 @@ export function CategoriesCarousel() {
<CarouselItem key={index} className="basis-1/2 md:basis-1/3 lg:basis-1/4 max-w-48" title={category ? DiscussionCategoriesDescriptions[category] : "All categories"}>
<div className="p-1">
<Button
type="button"
variant="ghost"
className={cn("w-full h-full flex aspect-square whitespace-normal text-muted-foreground hover:text-green border font-semibold capitalize",
currentcategory === category && "border-green text-green font-bold",
)}
onClick={() => handleFilter(category)}
onClick={(e) => { e.preventDefault(); handleFilter(category); }}
disabled={currentcategory === category}
>
{category ?? "all categories"}
Expand Down
6 changes: 5 additions & 1 deletion src/components/discussions/sort-by-dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client'

import { useTransition } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { Button } from "../ui/button";
Expand All @@ -9,6 +10,7 @@ export function SortByDropdown() {
const searchParams = useSearchParams();
const pathname = usePathname();
const { replace } = useRouter();
const [, startTransition] = useTransition();
const params = new URLSearchParams(searchParams);
const currentSort = params.get('sort');
const currentOrderBy = params.get('orderBy');
Expand All @@ -22,7 +24,9 @@ export function SortByDropdown() {
params.delete('orderBy');
params.delete('sort');
}
replace(`${pathname}?${params.toString()}`);
startTransition(() => {
replace(`${pathname}?${params.toString()}`, { scroll: false });
});
};

return (
Expand Down
6 changes: 5 additions & 1 deletion src/components/projects/activity-status-selection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import { ActivityStatus } from "@/src/types/enums"
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useTransition } from "react";
import { RadioGroup, RadioGroupItem } from "../ui/radio-group";
import { Label } from "../ui/label";

export function ActivityStatusSelection() {
const searchParams = useSearchParams();
const pathname = usePathname();
const { replace } = useRouter();
const [, startTransition] = useTransition();
const params = new URLSearchParams(searchParams);
const currentStatus = params.get('activityStatus') as ActivityStatus ?? "all";

Expand All @@ -19,7 +21,9 @@ export function ActivityStatusSelection() {
} else {
params.delete('activityStatus');
}
replace(`${pathname}?${params.toString()}`);
startTransition(() => {
replace(`${pathname}?${params.toString()}`, { scroll: false });
});
};

return (
Expand Down
9 changes: 7 additions & 2 deletions src/components/projects/domains-carousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import {
} from "@/src/components/ui/carousel"
import { ProjectDomain } 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";

export function DomainsCarousel() {
const searchParams = useSearchParams();
const pathname = usePathname();
const { replace } = useRouter();
const [, startTransition] = useTransition();
const params = new URLSearchParams(searchParams);
const currentDomain = params.get('domain') as ProjectDomain | null;

Expand All @@ -26,7 +28,9 @@ export function DomainsCarousel() {
} else {
params.delete('domain');
}
replace(`${pathname}?${params.toString()}`);
startTransition(() => {
replace(`${pathname}?${params.toString()}`, { scroll: false });
});
};

return (
Expand All @@ -42,11 +46,12 @@ export function DomainsCarousel() {
<CarouselItem key={index} className="basis-1/2 md:basis-1/3 lg:basis-1/4 max-w-48">
<div className="p-1">
<Button
type="button"
variant="ghost"
className={cn("w-full h-full flex aspect-square whitespace-normal text-muted-foreground hover:text-green border font-semibold",
currentDomain === domain && "border-green text-green font-bold",
)}
onClick={() => handleFilter(domain)}
onClick={(e) => { e.preventDefault(); handleFilter(domain); }}
disabled={currentDomain === domain}
>
{domain ?? "All Domains"}
Expand Down
2 changes: 1 addition & 1 deletion src/components/projects/project-forum.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default async function ProjectForum({ ...props }: {
<div className="w-full p-8 ">
<Search placeholder="Search topics..." />
</div>
<Suspense key={props.query || '' + currentPage} fallback={null}>
<Suspense fallback={null}>
<Topics project={props.projectId} query={props.query} tag={props.tag} currentPage={currentPage} orderBy={props.orderBy} sort={props.sort} />
</Suspense>
<div className="mt-5 flex w-full justify-center">
Expand Down
8 changes: 6 additions & 2 deletions src/components/projects/sort-by-dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client'

import { useTransition } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { Button } from "../ui/button";
Expand All @@ -9,6 +10,7 @@ export function SortByDropdown() {
const searchParams = useSearchParams();
const pathname = usePathname();
const { replace } = useRouter();
const [, startTransition] = useTransition();
const params = new URLSearchParams(searchParams);
const currentSort = params.get('sort');
const currentOrderBy = params.get('orderBy');
Expand All @@ -22,7 +24,9 @@ export function SortByDropdown() {
params.delete('orderBy');
params.delete('sort');
}
replace(`${pathname}?${params.toString()}`);
startTransition(() => {
replace(`${pathname}?${params.toString()}`, { scroll: false });
});
};

return (
Expand All @@ -35,7 +39,7 @@ export function SortByDropdown() {
? "oldest"
: "most recent"
}
<ChevronDown size={16}/>
<ChevronDown size={16} />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-48">
Expand Down