mirror of
https://github.com/trafficlunar/tomodachi-share.git
synced 2026-05-13 13:17:45 +00:00
Merge 8df69bcd79 into 79b19f4807
This commit is contained in:
commit
5f45f205f4
3 changed files with 84 additions and 1 deletions
|
|
@ -5,6 +5,7 @@ import { auth } from "@/lib/auth";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
|
|
||||||
import SortSelect from "./sort-select";
|
import SortSelect from "./sort-select";
|
||||||
|
import TimeRangeSelect from "./time-range-select";
|
||||||
import Pagination from "./pagination";
|
import Pagination from "./pagination";
|
||||||
import FilterMenu from "./filter-menu";
|
import FilterMenu from "./filter-menu";
|
||||||
import MiiGrid from "./mii-grid";
|
import MiiGrid from "./mii-grid";
|
||||||
|
|
@ -20,7 +21,7 @@ export default async function MiiList({ searchParams, userId, parentPage }: Prop
|
||||||
const parsed = searchSchema.safeParse(searchParams);
|
const parsed = searchSchema.safeParse(searchParams);
|
||||||
if (!parsed.success) return <h1>{parsed.error.issues[0].message}</h1>;
|
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
|
// My Likes page
|
||||||
let miiIdsLiked: number[] | undefined = undefined;
|
let miiIdsLiked: number[] | undefined = undefined;
|
||||||
|
|
@ -66,6 +67,14 @@ export default async function MiiList({ searchParams, userId, parentPage }: Prop
|
||||||
...(makeup && { makeup: { equals: makeup } }),
|
...(makeup && { makeup: { equals: makeup } }),
|
||||||
// Quarantined
|
// Quarantined
|
||||||
...(!quarantined && !userId && { quarantined: false }),
|
...(!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 = {
|
const select: Prisma.MiiSelect = {
|
||||||
|
|
@ -143,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">
|
<div className="relative flex items-center justify-end gap-2 w-full md:max-w-2/3 max-md:justify-center">
|
||||||
<FilterMenu />
|
<FilterMenu />
|
||||||
<SortSelect />
|
<SortSelect />
|
||||||
|
<TimeRangeSelect />
|
||||||
</div>
|
</div>
|
||||||
</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" })
|
.max(100, { error: "Limit cannot be more than 100" })
|
||||||
.optional(),
|
.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(),
|
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
|
export const userNameSchema = z
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue