183 lines
6.5 KiB
TypeScript
183 lines
6.5 KiB
TypeScript
import Link from "next/link";
|
|
import { desc, sql } from "drizzle-orm";
|
|
import { ArrowUpRight, Plus } from "lucide-react";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "@/components/ui/table";
|
|
import { db } from "@/db";
|
|
import { shareTexts } from "@/db/schema";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
function formatBangkok(date: Date) {
|
|
return new Intl.DateTimeFormat("en-GB", {
|
|
dateStyle: "medium",
|
|
timeStyle: "short",
|
|
timeZone: "Asia/Bangkok",
|
|
}).format(date);
|
|
}
|
|
|
|
export default async function AllSharesPage() {
|
|
const shares = await db
|
|
.select({
|
|
id: shareTexts.id,
|
|
authorName: shareTexts.authorName,
|
|
source: shareTexts.source,
|
|
description: shareTexts.description,
|
|
contentPreview: sql<string>`left(${shareTexts.content}, 160)`,
|
|
createdAt: shareTexts.createdAt,
|
|
})
|
|
.from(shareTexts)
|
|
.orderBy(desc(shareTexts.createdAt));
|
|
|
|
return (
|
|
<div className="flex w-full flex-col gap-6">
|
|
<header className="flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between">
|
|
<div>
|
|
<h1 className="text-3xl font-bold tracking-tight">Share</h1>
|
|
<p className="mt-1 text-muted-foreground">
|
|
{shares.length.toLocaleString("th-TH")} ลิงก์สาธารณะ
|
|
</p>
|
|
</div>
|
|
<Button asChild>
|
|
<Link href="/share">
|
|
<Plus data-icon="inline-start" />
|
|
สร้างลิงก์ใหม่
|
|
</Link>
|
|
</Button>
|
|
</header>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>ข้อความที่แชร์ทั้งหมด</CardTitle>
|
|
<CardDescription>
|
|
เลือกข้อความเพื่อเปิดหน้าสาธารณะ
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="hidden border md:block">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Share</TableHead>
|
|
<TableHead>Preview</TableHead>
|
|
<TableHead>Author</TableHead>
|
|
<TableHead>Source</TableHead>
|
|
<TableHead>Created</TableHead>
|
|
<TableHead className="text-right">Open</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{shares.length === 0 ? (
|
|
<TableRow>
|
|
<TableCell
|
|
colSpan={6}
|
|
className="h-24 text-center text-muted-foreground"
|
|
>
|
|
ยังไม่มีข้อความที่แชร์
|
|
</TableCell>
|
|
</TableRow>
|
|
) : (
|
|
shares.map((share) => (
|
|
<TableRow key={share.id}>
|
|
<TableCell className="font-mono font-medium">
|
|
<Link
|
|
href={`/share/${share.id}`}
|
|
className="hover:underline"
|
|
>
|
|
{share.id}
|
|
</Link>
|
|
</TableCell>
|
|
<TableCell>
|
|
<p className="max-w-md truncate text-muted-foreground">
|
|
{share.description || share.contentPreview}
|
|
</p>
|
|
</TableCell>
|
|
<TableCell>{share.authorName}</TableCell>
|
|
<TableCell>
|
|
<Badge
|
|
variant={
|
|
share.source === "bot" ? "secondary" : "outline"
|
|
}
|
|
>
|
|
{share.source === "bot" ? "Bot" : "Web"}
|
|
</Badge>
|
|
</TableCell>
|
|
<TableCell>{formatBangkok(share.createdAt)}</TableCell>
|
|
<TableCell className="text-right">
|
|
<Button variant="ghost" size="icon-sm" asChild>
|
|
<Link
|
|
href={`/share/${share.id}`}
|
|
aria-label={`Open share ${share.id}`}
|
|
>
|
|
<ArrowUpRight />
|
|
</Link>
|
|
</Button>
|
|
</TableCell>
|
|
</TableRow>
|
|
))
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
|
|
<div className="flex flex-col gap-3 md:hidden">
|
|
{shares.length === 0 ? (
|
|
<p className="py-8 text-center text-sm text-muted-foreground">
|
|
ยังไม่มีข้อความที่แชร์
|
|
</p>
|
|
) : (
|
|
shares.map((share) => (
|
|
<Card key={share.id} size="sm">
|
|
<CardHeader>
|
|
<CardTitle className="font-mono">
|
|
<Link href={`/share/${share.id}`}>{share.id}</Link>
|
|
</CardTitle>
|
|
<CardDescription>
|
|
{share.authorName} · {formatBangkok(share.createdAt)}
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<p className="line-clamp-2 text-sm text-muted-foreground">
|
|
{share.description || share.contentPreview}
|
|
</p>
|
|
<div className="flex items-center justify-between gap-3">
|
|
<Badge
|
|
variant={
|
|
share.source === "bot" ? "secondary" : "outline"
|
|
}
|
|
>
|
|
{share.source === "bot" ? "Bot" : "Web"}
|
|
</Badge>
|
|
<Button variant="outline" size="sm" asChild>
|
|
<Link href={`/share/${share.id}`}>
|
|
เปิด
|
|
<ArrowUpRight data-icon="inline-end" />
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
))
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|