diff --git a/src/components/mii/list/index.tsx b/src/components/mii/list/index.tsx
index 33042eb..081712e 100644
--- a/src/components/mii/list/index.tsx
+++ b/src/components/mii/list/index.tsx
@@ -5,6 +5,7 @@ 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";
@@ -20,7 +21,7 @@ export default async function MiiList({ searchParams, userId, parentPage }: Prop
const parsed = searchSchema.safeParse(searchParams);
if (!parsed.success) return
{parsed.error.issues[0].message} ;
- 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;
@@ -66,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 = {
@@ -143,6 +152,7 @@ export default async function MiiList({ searchParams, userId, parentPage }: Prop
+
diff --git a/src/components/mii/list/time-range-select.tsx b/src/components/mii/list/time-range-select.tsx
new file mode 100644
index 0000000..48880ec
--- /dev/null
+++ b/src/components/mii/list/time-range-select.tsx
@@ -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 (
+
+
+
+ {selectedItem?.label || "all time"}
+
+
+
+
+ {isOpen &&
+ items.map((item, index) => (
+
+ {item.label}
+
+ ))}
+
+
+ );
+}
diff --git a/src/lib/schemas.ts b/src/lib/schemas.ts
index 490cc5f..94318e7 100644
--- a/src/lib/schemas.ts
+++ b/src/lib/schemas.ts
@@ -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