Files

179 lines
5.2 KiB
TypeScript

import { useState, type ChangeEvent, type SubmitEvent } from "react";
import { RiLoader5Fill } from "@remixicon/react";
import { add } from "~/components/ui/notice/utils";
import { useIsLogin } from "~/composables/use-is-login";
import { clsn } from "~/utils";
import { getAuthorInfo, setAuthorInfo } from "~/utils/comment";
export interface CommentFormSubmitValues {
name: string;
email: string;
site: string;
content: string;
root?: string;
parent?: string;
}
interface CommentFormProps {
className?: string;
parent?: string;
root?: string;
onSubmit: (values: CommentFormSubmitValues) => Promise<unknown>;
}
export default function CommentForm({ className, parent, root, onSubmit }: CommentFormProps) {
const isLogin = useIsLogin();
const [loading, setLoading] = useState(false);
const [input, setInput] = useState(() => ({
...getAuthorInfo(),
content: "",
}));
const onChange = (ev: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = ev.target;
setInput((prev) => ({ ...prev, [name]: value }));
};
const onFormSubmit = (ev: SubmitEvent) => {
ev.preventDefault();
if (!isLogin && (!input.name || !input.email || !input.content)) {
add({
title: "评论失败",
type: "error",
content: "缺少必填项",
});
return;
}
if (!input.content) {
add({
title: "评论失败",
type: "error",
content: "缺少必填项",
});
return;
}
setAuthorInfo({
name: input.name,
email: input.email,
site: input.site,
});
setLoading(true);
onSubmit({
...input,
root,
parent,
}).then(() => {
setInput((prev) => ({ ...prev, content: "" }));
setLoading(false);
}).catch(() => {
setLoading(false);
});
};
const inputClass = "w-full px-3 py-2.5 rounded-xl bg-white border-4 border-gray-200 focus:border-pink-400 outline-none transition-colors placeholder:text-neutral-400";
const labelClass = "block text-sm font-medium mb-2 text-neutral-500";
if (isLogin) {
return (
<form className={clsn("mb-8", className)} onSubmit={onFormSubmit}>
<div className="mb-4">
<h3 className="text-pink-400 font-bold text-lg mb-1">欢迎回来!</h3>
</div>
<div className="mb-4">
<textarea
name="content"
className={clsn(inputClass, "min-h-[7em] resize-y")}
placeholder="评论"
rows={3}
required
value={input.content}
onChange={onChange}
/>
</div>
<button
type="submit"
className="inline-flex items-center justify-center px-6 py-3 rounded-xl bg-pink-400 text-white font-medium hover:bg-pink-500 transition-colors cursor-pointer disabled:opacity-60 disabled:cursor-not-allowed"
disabled={loading}
>
{loading && <RiLoader5Fill className="animate-spin mr-2" />}
提交
</button>
</form>
);
}
return (
<form className={clsn("mb-8", className)} onSubmit={onFormSubmit}>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div className="flex flex-col gap-4">
<div>
<label className={labelClass}>昵称</label>
<input
type="text"
name="name"
className={inputClass}
placeholder="园友"
required
value={input.name}
onChange={onChange}
/>
</div>
<div>
<label className={labelClass}>邮箱</label>
<input
type="email"
name="email"
className={inputClass}
placeholder="user@example.com"
required
value={input.email}
onChange={onChange}
/>
</div>
<div>
<label className={labelClass}>站点</label>
<input
type="url"
name="site"
className={inputClass}
placeholder="https://example.com"
value={input.site}
onChange={onChange}
/>
</div>
</div>
<div className="flex flex-col gap-4 md:h-full">
<div className="flex flex-col flex-1 min-h-0">
<label className={labelClass}>评论</label>
<textarea
name="content"
className={clsn(inputClass, "md:flex-1 resize-y")}
placeholder="注意言行举止,来做评论排行榜的前十名吧~"
rows={3}
required
value={input.content}
onChange={onChange}
/>
</div>
<button
type="submit"
className="w-full inline-flex items-center justify-center px-6 py-2.5 rounded-xl border-4 border-transparent bg-pink-400 text-white font-medium hover:bg-pink-500 transition-colors cursor-pointer disabled:opacity-60 disabled:cursor-not-allowed"
disabled={loading}
>
{loading && <RiLoader5Fill className="animate-spin mr-2" />}
提交
</button>
</div>
</div>
</form>
);
}