112 lines
3.8 KiB
TypeScript
112 lines
3.8 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { ExternalLink, Send } from "lucide-react";
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { EmptyState } from "@/components/layout/empty-state";
|
|
import { PageHeader } from "@/components/layout/page-header";
|
|
import { notify } from "@/lib/notifications/store";
|
|
|
|
interface PublishedItem {
|
|
id: string;
|
|
text: string;
|
|
angle?: string | null;
|
|
hook?: string | null;
|
|
permalink?: string | null;
|
|
publishedAt: string;
|
|
views?: number | null;
|
|
likes?: number | null;
|
|
replies?: number | null;
|
|
}
|
|
|
|
export default function PublishedPage() {
|
|
const [items, setItems] = useState<PublishedItem[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
fetch("/api/published")
|
|
.then(async (r) => {
|
|
const data = await r.json();
|
|
if (!r.ok) {
|
|
throw new Error(data.error ?? "無法載入已發布貼文");
|
|
}
|
|
setItems(data.published ?? []);
|
|
})
|
|
.catch((error) => {
|
|
notify({
|
|
type: "error",
|
|
title: "載入失敗",
|
|
message: error instanceof Error ? error.message : "請稍後再試",
|
|
});
|
|
})
|
|
.finally(() => setLoading(false));
|
|
}, []);
|
|
|
|
return (
|
|
<div>
|
|
<PageHeader
|
|
eyebrow="SYSTEM"
|
|
title="成效紀錄"
|
|
description="查看已發布到 Threads 的貼文,追蹤瀏覽與互動數據。"
|
|
/>
|
|
|
|
{loading ? (
|
|
<div className="space-y-4">
|
|
{[0, 1].map((i) => (
|
|
<div key={i} className="skeleton h-32 animate-pulse" />
|
|
))}
|
|
</div>
|
|
) : items.length === 0 ? (
|
|
<EmptyState
|
|
icon={Send}
|
|
title="尚無已發布貼文"
|
|
description="完成海巡與草稿審核後,發布的貼文會出現在這裡。"
|
|
/>
|
|
) : (
|
|
<div className="space-y-4">
|
|
{items.map((item, i) => (
|
|
<Card
|
|
key={item.id}
|
|
className="animate-fade-in-up"
|
|
style={{ animationDelay: `${i * 50}ms` }}
|
|
>
|
|
<CardHeader>
|
|
<CardTitle>{item.angle ?? "已發布貼文"}</CardTitle>
|
|
<CardDescription className="flex flex-wrap items-center gap-3">
|
|
<span>{new Date(item.publishedAt).toLocaleString("zh-TW")}</span>
|
|
{item.permalink && (
|
|
<a
|
|
href={item.permalink}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="inline-flex items-center gap-1 text-muted-foreground transition-colors hover:text-foreground"
|
|
>
|
|
<ExternalLink className="h-3 w-3" />
|
|
查看貼文
|
|
</a>
|
|
)}
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
{item.hook && (
|
|
<p className="mb-2 text-[14px] font-medium leading-snug">{item.hook}</p>
|
|
)}
|
|
<p className="whitespace-pre-wrap text-[15px] leading-[1.7] text-foreground/90">
|
|
{item.text}
|
|
</p>
|
|
{(item.views != null || item.likes != null || item.replies != null) && (
|
|
<div className="mt-4 flex flex-wrap gap-4 border-t border-border pt-3 text-sm text-muted-foreground">
|
|
{item.views != null && <span>瀏覽 {item.views}</span>}
|
|
{item.likes != null && <span>讚 {item.likes}</span>}
|
|
{item.replies != null && <span>留言 {item.replies}</span>}
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|