feat: sort select in mii list
This commit is contained in:
parent
cc506f2619
commit
b5b431028a
2 changed files with 65 additions and 18 deletions
|
|
@ -6,6 +6,7 @@ import { prisma } from "@/lib/prisma";
|
||||||
|
|
||||||
import Carousel from "./carousel";
|
import Carousel from "./carousel";
|
||||||
import LikeButton from "./like-button";
|
import LikeButton from "./like-button";
|
||||||
|
import SortSelect from "./sort-select";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||||
|
|
@ -18,18 +19,16 @@ export default async function MiiList({ searchParams, userId, where }: Props) {
|
||||||
const session = await auth();
|
const session = await auth();
|
||||||
const resolvedSearchParams = await searchParams;
|
const resolvedSearchParams = await searchParams;
|
||||||
|
|
||||||
// sort search param
|
// Sort search param
|
||||||
const orderBy: { createdAt?: Prisma.SortOrder; likes?: Prisma.SortOrder } = {};
|
// Defaults to newest
|
||||||
|
const orderBy: Prisma.MiiOrderByWithRelationInput =
|
||||||
|
resolvedSearchParams.sort === "newest"
|
||||||
|
? { createdAt: "desc" }
|
||||||
|
: resolvedSearchParams.sort === "likes"
|
||||||
|
? { likedBy: { _count: "desc" } }
|
||||||
|
: { createdAt: "desc" };
|
||||||
|
|
||||||
if (resolvedSearchParams.sort === "newest") {
|
// Tag search param
|
||||||
orderBy.createdAt = "desc";
|
|
||||||
} else if (resolvedSearchParams.sort === "likes") {
|
|
||||||
orderBy.likes = "desc";
|
|
||||||
} else {
|
|
||||||
orderBy.createdAt = "desc"; // Default to newest if no valid sort is provided
|
|
||||||
}
|
|
||||||
|
|
||||||
// tag search param
|
|
||||||
const rawTags = resolvedSearchParams.tags;
|
const rawTags = resolvedSearchParams.tags;
|
||||||
const tagFilter =
|
const tagFilter =
|
||||||
typeof rawTags === "string"
|
typeof rawTags === "string"
|
||||||
|
|
@ -115,13 +114,7 @@ export default async function MiiList({ searchParams, userId, where }: Props) {
|
||||||
<span>todo</span>
|
<span>todo</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="pill gap-2">
|
<SortSelect />
|
||||||
<label htmlFor="sort">Sort:</label>
|
|
||||||
<select name="sort">
|
|
||||||
<option value="likes">Likes</option>
|
|
||||||
<option value="newest">Newest</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
54
src/app/components/sort-select.tsx
Normal file
54
src/app/components/sort-select.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Icon } from "@iconify/react";
|
||||||
|
import { useSelect } from "downshift";
|
||||||
|
import { redirect, useSearchParams } from "next/navigation";
|
||||||
|
|
||||||
|
type Sort = "likes" | "newest";
|
||||||
|
|
||||||
|
const items = ["likes", "newest"];
|
||||||
|
|
||||||
|
export default function SortSelect() {
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
|
const currentSort = (searchParams.get("sort") as Sort) || "newest";
|
||||||
|
|
||||||
|
const { isOpen, getToggleButtonProps, getMenuProps, getItemProps, highlightedIndex, selectedItem } = useSelect({
|
||||||
|
items,
|
||||||
|
selectedItem: currentSort,
|
||||||
|
onSelectedItemChange: ({ selectedItem }) => {
|
||||||
|
if (!selectedItem) return;
|
||||||
|
redirect(`?sort=${selectedItem}`);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative w-full">
|
||||||
|
{/* Toggle button to open the dropdown */}
|
||||||
|
<button type="button" {...getToggleButtonProps()} className="pill input w-full gap-1 !justify-between">
|
||||||
|
<span>Sort by </span>
|
||||||
|
{selectedItem || "Select a way to sort"}
|
||||||
|
<Icon icon="tabler:chevron-down" className="ml-2 size-5" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Dropdown menu */}
|
||||||
|
<ul
|
||||||
|
{...getMenuProps()}
|
||||||
|
className={`absolute z-50 w-full bg-orange-200 border-2 border-orange-400 rounded-lg mt-1 shadow-lg max-h-60 overflow-y-auto ${
|
||||||
|
isOpen ? "block" : "hidden"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{isOpen &&
|
||||||
|
items.map((item, index) => (
|
||||||
|
<li
|
||||||
|
key={item}
|
||||||
|
{...getItemProps({ item, index })}
|
||||||
|
className={`px-4 py-1 cursor-pointer text-sm ${highlightedIndex === index ? "bg-black/15" : ""}`}
|
||||||
|
>
|
||||||
|
{item}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue