Files
jiang13-bbs/frontend/components/DeleteCommentModal.tsx

143 lines
4.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useEffect, useState } from "react";
import Modal from "@/components/Modal";
import StaffDeleteFields from "@/components/StaffDeleteFields";
export type DeleteCommentPayload = {
delete_type: string;
delete_reason: string;
};
/**
* 评论软删弹窗:
* - 评论者自删:必填理由(仅管理可见)
* - 管理删:与删帖共用类型表单;仅「其他」须填理由
*/
export default function DeleteCommentModal({
open,
mode,
busy,
onClose,
onConfirm,
}: {
open: boolean;
/** self=评论者自删;staff=版主/后台删除 */
mode: "self" | "staff";
busy?: boolean;
onClose: () => void;
onConfirm: (opts: DeleteCommentPayload) => void;
}) {
const [deleteType, setDeleteType] = useState("spam");
const [reason, setReason] = useState("");
const [err, setErr] = useState("");
useEffect(() => {
if (open) {
setDeleteType("spam");
setReason("");
setErr("");
}
}, [open]);
if (!open) return null;
const isStaff = mode === "staff";
const reasonRequired = !isStaff || deleteType === "other";
const submit = () => {
const r = reason.trim();
if (reasonRequired) {
if (!r) {
setErr("请填写删除理由");
return;
}
if ([...r].length > 200) {
setErr("删除理由不能超过 200 字");
return;
}
}
onConfirm({
delete_type: isStaff ? deleteType : "",
delete_reason: reasonRequired ? r : "",
});
};
return (
<Modal
open
title={isStaff ? "删除评论" : "删除我的评论"}
description={
isStaff
? "评论区保留匿名马赛克占位,读者看不到评论者头像与名称;可见删除类型,「其他」时还会展示补充理由。子回复不受影响。"
: "评论区保留马赛克占位,读者仅见「评论者已删除此评论」。你填写的理由仅管理员可见。"
}
onClose={onClose}
busy={busy}
maxWidthClass="max-w-[440px]"
panelClassName="p-5"
ariaLabel={isStaff ? "删除评论" : "删除我的评论"}
footer={
<>
<button type="button" className="btn btn-line" onClick={onClose} disabled={busy}>
取消
</button>
<button type="button" className="btn btn-danger" onClick={submit} disabled={busy}>
{busy ? "删除中…" : "确认删除"}
</button>
</>
}
>
{isStaff ? (
<StaffDeleteFields
deleteType={deleteType}
onTypeChange={(value) => {
setDeleteType(value);
setErr("");
if (value !== "other") setReason("");
}}
reason={reason}
onReasonChange={(value) => {
setReason(value);
setErr("");
}}
reasonId="cmt-delete-reason"
reasonPlaceholder="向读者说明删除原因(将展示在占位中)"
typeHint="选「其他」时需补充理由;其余类型直接按标签展示给读者。"
reasonHint="将公开显示在评论占位旁。"
/>
) : (
<>
<label
className="block mb-1.5 text-[12.5px] font-medium"
style={{ color: "var(--ink)" }}
htmlFor="cmt-delete-reason"
>
删除理由 <span style={{ color: "var(--danger)" }}>*</span>
</label>
<textarea
id="cmt-delete-reason"
className="field"
rows={3}
value={reason}
onChange={(e) => {
setReason(e.target.value);
setErr("");
}}
placeholder="例如:发错了 / 不想保留(仅管理员可见)"
maxLength={200}
autoFocus
/>
<p className="meta text-[11.5px] mt-1.5">普通读者看不到这条理由。</p>
</>
)}
{err ? (
<p className="mt-2 text-[12px]" style={{ color: "var(--danger)" }}>
{err}
</p>
) : null}
</Modal>
);
}