feat(guide): proper order sorting & hidden

This commit is contained in:
2026-03-19 01:28:55 +07:00 Unverified
parent db21e3cea4
commit 3c04403076
6 changed files with 53 additions and 18 deletions
@@ -23,6 +23,7 @@ import { guides } from "@/lib/db/schema";
export default async function GuideEditPage({
params,
}: PageProps<"/admin/guide/[id]">) {
if (!(await adminCheck())) redirect("/login");
const { id } = await params;
const [guide] = await db.select().from(guides).where(eq(guides.id, id));
if (!guide) notFound();
@@ -21,6 +21,7 @@ import { db } from "@/lib/db";
import { guides } from "@/lib/db/schema";
export default async function GuideCreatePage() {
if (!(await adminCheck())) redirect("/login");
const [{ maxOrder }] = await db
.select({
maxOrder: sql<number>`
+19
View File
@@ -0,0 +1,19 @@
"use server";
import { eq, not } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { adminCheck } from "@/lib/auth";
import { db } from "@/lib/db";
import { guides } from "@/lib/db/schema";
export async function hideGuide(id: string) {
if (!(await adminCheck())) redirect("/login");
await db
.update(guides)
.set({
hidden: not(guides.hidden),
})
.where(eq(guides.id, id));
revalidatePath("/admin/guide");
}
+22 -13
View File
@@ -1,12 +1,14 @@
import { Pencil, PlusIcon } from "lucide-react";
import { EyeIcon, EyeOffIcon, Pencil, PlusIcon } from "lucide-react";
import Link from "next/link";
import Image from "@/components/image";
import { Button } from "@/components/ui/button";
import { Card, CardHeader, CardTitle } from "@/components/ui/card";
import { cn } from "@/lib/utils";
import { searchGuide } from "../../guide/api";
import { hideGuide } from "./api";
export default async function AdminGuidePage() {
const list = await searchGuide();
const list = await searchGuide("", true);
return (
<div className="grow-0 flex flex-col pt-5 gap-2 mx-4">
@@ -20,18 +22,25 @@ export default async function AdminGuidePage() {
{list.map((card) => (
<Card
key={card.id}
className="bg-card/50 hover:bg-border backdrop-blur-sm transition-colors py-3 sm:py-6 rounded-sm sm:rounded-xl group relative"
className={cn(
"bg-card/50 hover:bg-border backdrop-blur-sm transition-colors py-3 sm:py-6 rounded-sm sm:rounded-xl group relative",
card.hidden && "opacity-70",
)}
>
<Button
size="icon"
variant="outline"
className="absolute opacity-0 group-hover:opacity-100 transition-opacity top-0 right-0 m-2"
asChild
>
<Link href={`/admin/guide/${card.id}`}>
<Pencil />
</Link>
</Button>
<div className="flex gap-1 absolute opacity-0 group-hover:opacity-100 transition-opacity top-0 right-0 m-2">
<Button
size="icon"
variant="outline"
onClick={hideGuide.bind(null, card.id)}
>
{card.hidden ? <EyeOffIcon /> : <EyeIcon />}
</Button>
<Button size="icon" variant="outline" asChild>
<Link href={`/admin/guide/${card.id}`}>
<Pencil />
</Link>
</Button>
</div>
<CardHeader className="px-3 sm:px-6">
<CardTitle>{card.name}</CardTitle>
<div className="relative w-full aspect-square mt-2 rounded-sm sm:rounded-lg border overflow-hidden">
+9 -4
View File
@@ -1,13 +1,18 @@
"use server";
import { ilike } from "drizzle-orm";
import { and, desc, ilike, not } from "drizzle-orm";
import { db } from "@/lib/db";
import { guides } from "@/lib/db/schema";
export async function searchGuide(search: string = "") {
export async function searchGuide(search: string = "", admin = false) {
return await db
.select()
.from(guides)
.where(ilike(guides.name, `%${search}%`))
.orderBy(guides.id);
.where(
and(
ilike(guides.name, `%${search}%`),
admin ? undefined : not(guides.hidden),
),
)
.orderBy(desc(guides.order));
}
+1 -1
View File
@@ -2,6 +2,6 @@ import { searchGuide } from "./api";
import { GuideList } from "./client";
export default async function GuidePage() {
const initialData = await searchGuide();
const initialData = await searchGuide("");
return <GuideList initialList={initialData} />;
}