mirror of
https://github.com/trafficlunar/tomodachi-share.git
synced 2026-05-13 13:17:45 +00:00
Merge 8df69bcd79 into c72dab1962
This commit is contained in:
commit
f4bfb59430
3 changed files with 84 additions and 3 deletions
|
|
@ -1,12 +1,11 @@
|
|||
import { Prisma } from "@prisma/client";
|
||||
|
||||
import crypto from "crypto";
|
||||
|
||||
import { searchSchema } from "@/lib/schemas";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
import SortSelect from "./sort-select";
|
||||
import TimeRangeSelect from "./time-range-select";
|
||||
import Pagination from "./pagination";
|
||||
import FilterMenu from "./filter-menu";
|
||||
import MiiGrid from "./mii-grid";
|
||||
|
|
@ -22,7 +21,7 @@ export default async function MiiList({ searchParams, userId, parentPage }: Prop
|
|||
const parsed = searchSchema.safeParse(searchParams);
|
||||
if (!parsed.success) return <h1>{parsed.error.issues[0].message}</h1>;
|
||||
|
||||
const { q: query, sort, tags, exclude, platform, gender, makeup, allowCopying, quarantined, page = 1, limit = 24 } = parsed.data;
|
||||
const { q: query, sort, tags, exclude, platform, gender, makeup, allowCopying, quarantined, page = 1, limit = 24, timeRange } = parsed.data;
|
||||
|
||||
// My Likes page
|
||||
let miiIdsLiked: number[] | undefined = undefined;
|
||||
|
|
@ -68,6 +67,14 @@ export default async function MiiList({ searchParams, userId, parentPage }: Prop
|
|||
...(makeup && { makeup: { equals: makeup } }),
|
||||
// Quarantined
|
||||
...(!quarantined && !userId && { quarantined: false }),
|
||||
// Time range
|
||||
...(timeRange && {
|
||||
createdAt: {
|
||||
gte: new Date(
|
||||
Date.now() - { day: 86400000, week: 604800000, month: 2592000000, year: 31536000000 }[timeRange],
|
||||
),
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
const select: Prisma.MiiSelect = {
|
||||
|
|
@ -145,6 +152,7 @@ export default async function MiiList({ searchParams, userId, parentPage }: Prop
|
|||
<div className="relative flex items-center justify-end gap-2 w-full md:max-w-2/3 max-md:justify-center">
|
||||
<FilterMenu />
|
||||
<SortSelect />
|
||||
<TimeRangeSelect />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
71
src/components/mii/list/time-range-select.tsx
Normal file
71
src/components/mii/list/time-range-select.tsx
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
"use client";
|
||||
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { useTransition } from "react";
|
||||
import { useSelect } from "downshift";
|
||||
import { Icon } from "@iconify/react";
|
||||
|
||||
type TimeRange = "day" | "week" | "month" | "year";
|
||||
|
||||
const items: { value: TimeRange | "all"; label: string }[] = [
|
||||
{ value: "all", label: "all time" },
|
||||
{ value: "day", label: "today" },
|
||||
{ value: "week", label: "this week" },
|
||||
{ value: "month", label: "this month" },
|
||||
{ value: "year", label: "this year" },
|
||||
];
|
||||
|
||||
export default function TimeRangeSelect() {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const [, startTransition] = useTransition();
|
||||
|
||||
const currentRange = (searchParams.get("timeRange") as TimeRange) || "all";
|
||||
const currentItem = items.find((i) => i.value === currentRange) || items[0];
|
||||
|
||||
const { isOpen, getToggleButtonProps, getMenuProps, getItemProps, highlightedIndex, selectedItem } = useSelect({
|
||||
items,
|
||||
selectedItem: currentItem,
|
||||
itemToString: (item) => item?.label || "",
|
||||
onSelectedItemChange: ({ selectedItem }) => {
|
||||
if (!selectedItem) return;
|
||||
|
||||
const params = new URLSearchParams(searchParams);
|
||||
params.set("page", "1");
|
||||
|
||||
if (selectedItem.value === "all") {
|
||||
params.delete("timeRange");
|
||||
} else {
|
||||
params.set("timeRange", selectedItem.value);
|
||||
}
|
||||
|
||||
startTransition(() => {
|
||||
router.push(`?${params.toString()}`, { scroll: false });
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative w-fit">
|
||||
<button type="button" {...getToggleButtonProps()} aria-label="Time range dropdown" className="pill input w-full gap-1 justify-between! text-nowrap">
|
||||
<Icon icon="mdi:clock-outline" className="size-5" />
|
||||
{selectedItem?.label || "all time"}
|
||||
<Icon icon="tabler:chevron-down" className="ml-1 size-5" />
|
||||
</button>
|
||||
|
||||
<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.value} {...getItemProps({ item, index })} className={`px-4 py-1 cursor-pointer text-sm ${highlightedIndex === index ? "bg-black/15" : ""}`}>
|
||||
{item.label}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -72,6 +72,8 @@ export const searchSchema = z.object({
|
|||
.max(100, { error: "Limit cannot be more than 100" })
|
||||
.optional(),
|
||||
page: z.coerce.number({ error: "Page must be a number" }).int({ error: "Page must be an integer" }).min(1, { error: "Page must be at least 1" }).optional(),
|
||||
// Time range filter
|
||||
timeRange: z.enum(["day", "week", "month", "year"], { error: "Time range must be either 'day', 'week', 'month', or 'year'" }).optional(),
|
||||
});
|
||||
|
||||
export const userNameSchema = z
|
||||
|
|
|
|||
Loading…
Reference in a new issue