Files
nekonest-cloud/app/dashboard/feedback/page.tsx
T

88 lines
3.3 KiB
TypeScript

import { requireCloudViewer } from "../../cloud-auth";
import {
DashboardShell,
PageHeading,
StatusPill,
formatDate,
} from "../../components/Shells";
import {
getOrCreateAccount,
listAccountFeedback,
type FeedbackCategory,
} from "@/db/repository";
import { FeedbackForm } from "./FeedbackForm";
export const dynamic = "force-dynamic";
const categoryLabels: Record<FeedbackCategory, string> = {
connection_issue: "连接或接入",
bug: "功能异常",
suggestion: "使用建议",
other: "其他",
};
export default async function FeedbackPage() {
const viewer = await requireCloudViewer("/dashboard/feedback");
const account = await getOrCreateAccount(viewer);
const feedback = await listAccountFeedback(account.id);
return (
<DashboardShell viewer={viewer} active="/dashboard/feedback">
<div className="cloud-page narrow-cloud-page">
<PageHeading
eyebrow="BETA FEEDBACK / 公测反馈"
title="遇到问题,直接告诉我们。"
description="这是免费公测期的站内反馈通道。后台回复会保存在这里;当前不承诺即时客服,但接入故障会优先处理。"
/>
<div className="feedback-layout">
<section className="panel form-panel">
<div className="panel-heading">
<div><span>新反馈</span><h2>描述你卡住的地方</h2></div>
</div>
<FeedbackForm />
</section>
<aside className="form-aside feedback-aside">
<span className="eyebrow">提交前</span>
<h2>尽量让问题可以复现。</h2>
<ol>
<li><strong>先写目标</strong><p>你原本想完成什么操作。</p></li>
<li><strong>再写现象</strong><p>页面或 daemon 显示了什么。</p></li>
<li><strong>保护秘密</strong><p>不要粘贴令牌、密码、私钥或完整会话正文。</p></li>
</ol>
</aside>
</div>
<section className="panel full-panel">
<div className="panel-heading">
<div><span>处理记录</span><h2>我的反馈</h2></div>
<StatusPill tone="info">{feedback.length} </StatusPill>
</div>
{feedback.length ? (
<div className="feedback-list">
{feedback.map((item) => (
<article key={item.id}>
<div className="feedback-meta">
<StatusPill tone={item.status === "resolved" ? "good" : "warn"}>
{item.status === "resolved" ? "已回复" : "待处理"}
</StatusPill>
<span>{categoryLabels[item.category]}</span>
<time>{formatDate(item.created_at, true)}</time>
</div>
<p>{item.message}</p>
{item.admin_response && (
<div className="feedback-response">
<strong>后台回复</strong>
<p>{item.admin_response}</p>
</div>
)}
</article>
))}
</div>
) : (
<div className="empty-inline">还没有反馈记录。</div>
)}
</section>
</div>
</DashboardShell>
);
}