248 lines
11 KiB
TypeScript
248 lines
11 KiB
TypeScript
import Link from "next/link";
|
||
import { MessageCircle, Smartphone, Activity, ScanLine } from "lucide-react";
|
||
|
||
import { PanelShell } from "@/components/panel-shell";
|
||
import { getCaregiverOverview } from "@/lib/caregiver-panel";
|
||
import {
|
||
formatDateTime,
|
||
getDeviceName,
|
||
getImportanceLabel,
|
||
getMessageHref,
|
||
truncateText,
|
||
} from "@/lib/panel-format";
|
||
import { requireCaregiverSession } from "@/lib/page-auth";
|
||
import { getCaregiverDisplayName } from "@/lib/session";
|
||
|
||
export const dynamic = "force-dynamic";
|
||
|
||
export default async function Home() {
|
||
const caregiver = await requireCaregiverSession("/");
|
||
const { dashboard, recentIncomingMessages, recentOutgoingMessages } =
|
||
await getCaregiverOverview(caregiver.id);
|
||
|
||
const totalUnreadForElder = dashboard.devices.reduce(
|
||
(total, device) => total + device.familyUnreadCount,
|
||
0,
|
||
);
|
||
const totalUnreadForCaregiver = dashboard.devices.reduce(
|
||
(total, device) => total + device.elderUnreadCount,
|
||
0,
|
||
);
|
||
const totalConversations = dashboard.devices.reduce(
|
||
(total, device) => total + device.elderDevice._count.conversationTurns,
|
||
0,
|
||
);
|
||
|
||
return (
|
||
<PanelShell
|
||
currentPath="/"
|
||
title="今日概览"
|
||
description="随时了解长辈的近况,留言和动态一目了然。"
|
||
caregiverLabel={getCaregiverDisplayName(dashboard.caregiver)}
|
||
>
|
||
<section className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
||
<div className="rounded-[28px] border border-white/80 bg-white/88 p-5 shadow-[0_20px_50px_rgba(115,76,42,0.10)]">
|
||
<p className="text-sm text-[var(--muted)]">已连接设备</p>
|
||
<p className="mt-3 font-[family-name:var(--font-display)] text-4xl text-[var(--ink)]">
|
||
{dashboard.devices.length}
|
||
</p>
|
||
</div>
|
||
<div className="rounded-[28px] border border-white/80 bg-white/88 p-5 shadow-[0_20px_50px_rgba(115,76,42,0.10)]">
|
||
<p className="text-sm text-[var(--muted)]">长辈的新留言</p>
|
||
<p className="mt-3 font-[family-name:var(--font-display)] text-4xl text-[var(--ink)]">
|
||
{totalUnreadForCaregiver}
|
||
</p>
|
||
</div>
|
||
<div className="rounded-[28px] border border-white/80 bg-white/88 p-5 shadow-[0_20px_50px_rgba(115,76,42,0.10)]">
|
||
<p className="text-sm text-[var(--muted)]">待长辈查看</p>
|
||
<p className="mt-3 font-[family-name:var(--font-display)] text-4xl text-[var(--ink)]">
|
||
{totalUnreadForElder}
|
||
</p>
|
||
</div>
|
||
<div className="rounded-[28px] border border-white/80 bg-white/88 p-5 shadow-[0_20px_50px_rgba(115,76,42,0.10)]">
|
||
<p className="text-sm text-[var(--muted)]">陪伴对话</p>
|
||
<p className="mt-3 font-[family-name:var(--font-display)] text-4xl text-[var(--ink)]">
|
||
{totalConversations}
|
||
</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section className="grid gap-4 lg:grid-cols-4">
|
||
{[
|
||
{
|
||
href: "/messages",
|
||
title: "留言板",
|
||
text: "查看长辈捎来的话,也能回看您发出的每一条问候。",
|
||
tone: "bg-[rgba(53,84,141,0.12)]",
|
||
icon: MessageCircle,
|
||
},
|
||
{
|
||
href: "/devices",
|
||
title: "我的设备",
|
||
text: "管理已绑定的长辈设备,进入设备详情给长辈写留言。",
|
||
tone: "bg-[rgba(118,132,94,0.14)]",
|
||
icon: Smartphone,
|
||
},
|
||
{
|
||
href: "/activity",
|
||
title: "陪伴动态",
|
||
text: "了解长辈最近的使用情况和聊天记录,安心守护。",
|
||
tone: "bg-[rgba(199,103,51,0.12)]",
|
||
icon: Activity,
|
||
},
|
||
{
|
||
href: "/scan",
|
||
title: "扫码绑定",
|
||
text: "扫描长辈手机上的二维码,一步完成设备连接。",
|
||
tone: "bg-[rgba(36,27,20,0.08)]",
|
||
icon: ScanLine,
|
||
},
|
||
].map((item) => {
|
||
const Icon = item.icon;
|
||
return (
|
||
<Link
|
||
key={item.href}
|
||
href={item.href}
|
||
className="rounded-[28px] border border-white/80 bg-white/84 p-5 shadow-[0_20px_50px_rgba(115,76,42,0.10)] transition hover:-translate-y-0.5"
|
||
>
|
||
<div className={`inline-flex items-center gap-2 rounded-full px-3 py-1 text-xs font-semibold text-[var(--ink)] ${item.tone}`}>
|
||
<Icon size={14} />
|
||
{item.title}
|
||
</div>
|
||
<h2 className="mt-4 font-[family-name:var(--font-display)] text-2xl text-[var(--ink)]">
|
||
{item.title}
|
||
</h2>
|
||
<p className="mt-3 text-sm leading-7 text-[var(--muted)]">{item.text}</p>
|
||
<p className="mt-4 text-sm font-semibold text-[var(--copper)]">查看详情 →</p>
|
||
</Link>
|
||
);
|
||
})}
|
||
</section>
|
||
|
||
{dashboard.devices.length === 0 ? (
|
||
<section className="rounded-[32px] border border-dashed border-[var(--line)] bg-white/70 px-6 py-10 text-center shadow-[0_20px_50px_rgba(115,76,42,0.10)]">
|
||
<p className="text-sm font-medium tracking-[0.18em] text-[var(--copper)] uppercase">
|
||
开始使用
|
||
</p>
|
||
<h2 className="mt-3 font-[family-name:var(--font-display)] text-3xl text-[var(--ink)]">
|
||
先连接长辈的设备
|
||
</h2>
|
||
<p className="mx-auto mt-4 max-w-2xl text-base leading-8 text-[var(--muted)]">
|
||
让长辈打开手机里的「家人连接」页面,用您的手机扫描二维码,即可建立连接。连接成功后,您就能收到长辈的留言和使用动态。
|
||
</p>
|
||
<div className="mt-6 flex justify-center gap-3">
|
||
<Link
|
||
href="/scan"
|
||
className="inline-flex h-12 items-center justify-center rounded-full bg-[var(--copper)] px-5 text-sm font-semibold text-white transition hover:bg-[var(--copper-deep)]"
|
||
>
|
||
扫码连接
|
||
</Link>
|
||
<Link
|
||
href="/devices"
|
||
className="inline-flex h-12 items-center justify-center rounded-full border border-[var(--line)] bg-white px-5 text-sm font-semibold text-[var(--ink)] transition hover:bg-[var(--paper-soft)]"
|
||
>
|
||
手动添加
|
||
</Link>
|
||
</div>
|
||
</section>
|
||
) : (
|
||
<section className="grid gap-6 xl:grid-cols-2">
|
||
<div className="rounded-[32px] border border-white/75 bg-white/80 p-6 shadow-[0_26px_60px_rgba(115,76,42,0.12)]">
|
||
<div className="flex items-center justify-between gap-3">
|
||
<div>
|
||
<p className="text-sm font-medium tracking-[0.18em] text-[var(--copper)] uppercase">
|
||
长辈的留言
|
||
</p>
|
||
<h2 className="mt-2 font-[family-name:var(--font-display)] text-3xl text-[var(--ink)]">
|
||
最近收到的话
|
||
</h2>
|
||
</div>
|
||
<Link
|
||
href="/messages"
|
||
className="inline-flex h-11 items-center justify-center rounded-full border border-[var(--line)] bg-white px-4 text-sm font-semibold text-[var(--ink)] transition hover:bg-[var(--paper-soft)]"
|
||
>
|
||
查看全部
|
||
</Link>
|
||
</div>
|
||
|
||
<div className="mt-5 space-y-3">
|
||
{recentIncomingMessages.length === 0 ? (
|
||
<p className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4 text-sm leading-7 text-[var(--muted)]">
|
||
暂时还没有收到新留言。
|
||
</p>
|
||
) : (
|
||
recentIncomingMessages.map((message) => (
|
||
<Link
|
||
key={message.id}
|
||
href={getMessageHref(message.publicId)}
|
||
className="block rounded-[24px] bg-[var(--paper-soft)] px-5 py-4 transition hover:bg-white"
|
||
>
|
||
<div className="flex flex-wrap items-center gap-2 text-xs text-[var(--muted)]">
|
||
<span className="rounded-full bg-white px-3 py-1 font-semibold text-[var(--ink)]">
|
||
#{message.publicId}
|
||
</span>
|
||
<span>{getDeviceName(message.elderDevice.displayName)}</span>
|
||
<span>{getImportanceLabel(message.importance)}</span>
|
||
<span>{formatDateTime(message.createdAt)}</span>
|
||
</div>
|
||
<p className="mt-3 text-sm leading-7 text-[var(--ink)]">
|
||
{truncateText(message.content)}
|
||
</p>
|
||
</Link>
|
||
))
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="rounded-[32px] border border-white/75 bg-white/80 p-6 shadow-[0_26px_60px_rgba(115,76,42,0.12)]">
|
||
<div className="flex items-center justify-between gap-3">
|
||
<div>
|
||
<p className="text-sm font-medium tracking-[0.18em] text-[var(--copper)] uppercase">
|
||
我发出的问候
|
||
</p>
|
||
<h2 className="mt-2 font-[family-name:var(--font-display)] text-3xl text-[var(--ink)]">
|
||
最近写给长辈的话
|
||
</h2>
|
||
</div>
|
||
<Link
|
||
href="/devices"
|
||
className="inline-flex h-11 items-center justify-center rounded-full border border-[var(--line)] bg-white px-4 text-sm font-semibold text-[var(--ink)] transition hover:bg-[var(--paper-soft)]"
|
||
>
|
||
写新留言
|
||
</Link>
|
||
</div>
|
||
|
||
<div className="mt-5 space-y-3">
|
||
{recentOutgoingMessages.length === 0 ? (
|
||
<p className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4 text-sm leading-7 text-[var(--muted)]">
|
||
还没有给长辈留过言,去设备页写一句问候吧。
|
||
</p>
|
||
) : (
|
||
recentOutgoingMessages.map((message) => (
|
||
<Link
|
||
key={message.id}
|
||
href={getMessageHref(message.publicId)}
|
||
className="block rounded-[24px] bg-[var(--paper-soft)] px-5 py-4 transition hover:bg-white"
|
||
>
|
||
<div className="flex flex-wrap items-center gap-2 text-xs text-[var(--muted)]">
|
||
<span className="rounded-full bg-white px-3 py-1 font-semibold text-[var(--ink)]">
|
||
#{message.publicId}
|
||
</span>
|
||
<span>{getDeviceName(message.elderDevice.displayName)}</span>
|
||
<span>{getImportanceLabel(message.importance)}</span>
|
||
<span>{formatDateTime(message.createdAt)}</span>
|
||
</div>
|
||
<p className="mt-3 text-sm leading-7 text-[var(--ink)]">
|
||
{truncateText(message.content)}
|
||
</p>
|
||
</Link>
|
||
))
|
||
)}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)}
|
||
</PanelShell>
|
||
);
|
||
}
|