227 lines
9.8 KiB
TypeScript
227 lines
9.8 KiB
TypeScript
import Link from "next/link";
|
|
import { notFound } from "next/navigation";
|
|
|
|
import { ManageDeviceForm, SendMessageForm } from "@/components/dashboard-actions";
|
|
import { PanelShell } from "@/components/panel-shell";
|
|
import { getCaregiverDeviceDetail } from "@/lib/caregiver-panel";
|
|
import {
|
|
formatDateTime,
|
|
getConversationRoleLabel,
|
|
getDeviceName,
|
|
getImportanceLabel,
|
|
getMessageHref,
|
|
getUsageLabel,
|
|
truncateText,
|
|
} from "@/lib/panel-format";
|
|
import { requireCaregiverSession } from "@/lib/page-auth";
|
|
import { getCaregiverDisplayName } from "@/lib/session";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
type DeviceDetailPageProps = {
|
|
params: Promise<{ deviceUuid: string }>;
|
|
};
|
|
|
|
export default async function DeviceDetailPage({ params }: DeviceDetailPageProps) {
|
|
const { deviceUuid } = await params;
|
|
const caregiver = await requireCaregiverSession(`/devices/${deviceUuid}`);
|
|
const binding = await getCaregiverDeviceDetail(caregiver.id, deviceUuid);
|
|
|
|
if (!binding) {
|
|
notFound();
|
|
}
|
|
|
|
const elderMessages = binding.elderDevice.messages.filter(
|
|
(message) => message.direction === "ELDER_TO_FAMILY",
|
|
);
|
|
const familyMessages = binding.elderDevice.messages.filter(
|
|
(message) => message.direction === "FAMILY_TO_ELDER",
|
|
);
|
|
|
|
return (
|
|
<PanelShell
|
|
currentPath="/devices"
|
|
title={getDeviceName(binding.elderDevice.displayName)}
|
|
description="给长辈写问候、查看留言和最近的使用动态。"
|
|
caregiverLabel={getCaregiverDisplayName(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">
|
|
<p className="text-sm text-[var(--muted)]">新留言</p>
|
|
<p className="mt-3 font-[family-name:var(--font-display)] text-4xl text-[var(--ink)]">
|
|
{binding.elderUnreadCount}
|
|
</p>
|
|
</div>
|
|
<div className="rounded-[28px] border border-white/80 bg-white/88 p-5">
|
|
<p className="text-sm text-[var(--muted)]">待查看</p>
|
|
<p className="mt-3 font-[family-name:var(--font-display)] text-4xl text-[var(--ink)]">
|
|
{binding.familyUnreadCount}
|
|
</p>
|
|
</div>
|
|
<div className="rounded-[28px] border border-white/80 bg-white/88 p-5">
|
|
<p className="text-sm text-[var(--muted)]">最近在线</p>
|
|
<p className="mt-3 text-lg font-semibold text-[var(--ink)]">
|
|
{formatDateTime(binding.elderDevice.lastSeenAt)}
|
|
</p>
|
|
</div>
|
|
<div className="rounded-[28px] border border-white/80 bg-white/88 p-5">
|
|
<p className="text-sm text-[var(--muted)]">设备链接</p>
|
|
<p className="mt-3 text-sm leading-7 text-[var(--ink)]">
|
|
{truncateText(binding.bindUrl, 52)}
|
|
</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section className="grid gap-6 xl:grid-cols-[0.95fr_1.05fr]">
|
|
<div className="space-y-6">
|
|
<ManageDeviceForm
|
|
deviceUuid={binding.elderDevice.deviceUuid}
|
|
initialAlias={binding.alias}
|
|
deviceLabel={getDeviceName(binding.elderDevice.displayName)}
|
|
/>
|
|
|
|
<SendMessageForm deviceUuid={binding.elderDevice.deviceUuid} />
|
|
|
|
<section className="rounded-[32px] border border-white/75 bg-white/82 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">
|
|
{elderMessages.length === 0 ? (
|
|
<p className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4 text-sm leading-7 text-[var(--muted)]">
|
|
还没有收到长辈的留言。
|
|
</p>
|
|
) : (
|
|
elderMessages.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>{getImportanceLabel(message.importance)}</span>
|
|
<span>{formatDateTime(message.createdAt)}</span>
|
|
</div>
|
|
<p className="mt-3 text-sm leading-7 text-[var(--ink)]">
|
|
{truncateText(message.content, 112)}
|
|
</p>
|
|
</Link>
|
|
))
|
|
)}
|
|
</div>
|
|
</section>
|
|
|
|
<section className="rounded-[32px] border border-white/75 bg-white/82 p-6 shadow-[0_26px_60px_rgba(115,76,42,0.12)]">
|
|
<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 className="mt-5 space-y-3">
|
|
{binding.elderDevice.usageEvents.length === 0 ? (
|
|
<p className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4 text-sm leading-7 text-[var(--muted)]">
|
|
暂时还没有使用记录。
|
|
</p>
|
|
) : (
|
|
binding.elderDevice.usageEvents.map((event) => (
|
|
<div key={event.id} className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4">
|
|
<div className="flex items-center justify-between gap-3 text-xs text-[var(--muted)]">
|
|
<span>{getUsageLabel(event.eventType)}</span>
|
|
<span>{formatDateTime(event.createdAt)}</span>
|
|
</div>
|
|
</div>
|
|
))
|
|
)}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div className="space-y-6">
|
|
<section className="rounded-[32px] border border-white/75 bg-white/82 p-6 shadow-[0_26px_60px_rgba(115,76,42,0.12)]">
|
|
<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 className="mt-5 space-y-3">
|
|
{familyMessages.length === 0 ? (
|
|
<p className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4 text-sm leading-7 text-[var(--muted)]">
|
|
还没有给这位长辈写过留言。
|
|
</p>
|
|
) : (
|
|
familyMessages.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>{getImportanceLabel(message.importance)}</span>
|
|
<span>{formatDateTime(message.createdAt)}</span>
|
|
</div>
|
|
<p className="mt-3 text-sm leading-7 text-[var(--ink)]">
|
|
{truncateText(message.content, 112)}
|
|
</p>
|
|
</Link>
|
|
))
|
|
)}
|
|
</div>
|
|
</section>
|
|
|
|
<section className="rounded-[32px] border border-white/75 bg-white/82 p-6 shadow-[0_26px_60px_rgba(115,76,42,0.12)]">
|
|
<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 className="mt-5 space-y-3">
|
|
{binding.elderDevice.conversationTurns.length === 0 ? (
|
|
<p className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4 text-sm leading-7 text-[var(--muted)]">
|
|
还没有聊天记录。
|
|
</p>
|
|
) : (
|
|
binding.elderDevice.conversationTurns.map((turn) => (
|
|
<div key={turn.id} className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4">
|
|
<div className="flex items-center justify-between gap-3 text-xs text-[var(--muted)]">
|
|
<span>{getConversationRoleLabel(turn.role)}</span>
|
|
<span>{formatDateTime(turn.createdAt)}</span>
|
|
</div>
|
|
<p className="mt-3 text-sm leading-7 text-[var(--ink)]">
|
|
{truncateText(turn.content, 124)}
|
|
</p>
|
|
</div>
|
|
))
|
|
)}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</section>
|
|
</PanelShell>
|
|
);
|
|
} |