doctor-mail/apps/web/src/components/models/post/detail/PostCommentCard.tsx

115 lines
3.1 KiB
TypeScript
Raw Normal View History

2025-01-24 00:19:02 +08:00
import { PostDto, VisitType } from "@nice/common";
import { motion } from "framer-motion";
import dayjs from "dayjs";
2025-01-24 17:39:41 +08:00
2025-01-24 11:39:51 +08:00
import { Avatar } from "antd";
2025-01-24 00:19:02 +08:00
import { useVisitor } from "@nice/client";
2025-01-24 17:39:41 +08:00
import { useContext, useState } from "react";
2025-01-24 00:19:02 +08:00
import { PostDetailContext } from "./context/PostDetailContext";
2025-01-24 17:39:41 +08:00
import { LikeFilled, LikeOutlined } from "@ant-design/icons";
2025-01-24 00:19:02 +08:00
export default function PostCommentCard({
post,
index,
2025-01-24 17:39:41 +08:00
isReceiverComment,
2025-01-24 00:19:02 +08:00
}: {
post: PostDto;
index: number;
2025-01-24 15:06:57 +08:00
isReceiverComment: boolean;
2025-01-24 00:19:02 +08:00
}) {
const { user } = useContext(PostDetailContext);
2025-01-24 17:39:41 +08:00
const { like, unLike } = useVisitor();
const [liked, setLiked] = useState(post?.liked || false);
const [likeCount, setLikeCount] = useState(post?.likes || 0);
2025-01-24 00:19:02 +08:00
async function likeThisPost() {
2025-01-24 17:39:41 +08:00
if (!liked) {
2025-01-24 00:19:02 +08:00
try {
2025-01-24 17:39:41 +08:00
setLikeCount((prev) => prev + 1);
setLiked(true);
like.mutateAsync({
2025-01-24 00:19:02 +08:00
data: {
visitorId: user?.id || null,
postId: post.id,
type: VisitType.LIKE,
},
});
} catch (error) {
2025-01-24 11:39:51 +08:00
console.error("Failed to like post:", error);
2025-01-24 17:39:41 +08:00
setLikeCount((prev) => prev - 1);
setLiked(false);
2025-01-24 00:19:02 +08:00
}
2025-01-24 17:39:41 +08:00
} else {
setLikeCount((prev) => prev - 1);
setLiked(false);
unLike.mutateAsync({
where: {
visitorId: user?.id || null,
postId: post.id,
type: VisitType.LIKE,
},
});
2025-01-24 00:19:02 +08:00
}
}
return (
<motion.div
className="bg-white rounded-lg shadow-sm border border-slate-200 p-4"
layout>
<div className="flex items-start space-x-3">
<div className="flex-shrink-0">
<Avatar
2025-01-24 17:39:41 +08:00
className="ring-2 ring-white hover:ring-[#00538E]/90
transition-all duration-200 ease-in-out shadow-md
hover:shadow-lg"
2025-01-24 00:19:02 +08:00
src={post.author?.avatar}
2025-01-24 17:39:41 +08:00
size={40}>
{!post.author?.avatar &&
(post.author?.showname || "匿名用户")}
2025-01-24 11:39:51 +08:00
</Avatar>
2025-01-24 00:19:02 +08:00
</div>
<div className="flex-1 min-w-0">
<div
className="flex items-center space-x-2"
style={{ height: 40 }}>
<span className="font-medium text-slate-900">
{post.author?.showname || "匿名用户"}
</span>
<span className="text-sm text-slate-500">
{dayjs(post?.createdAt).format("YYYY-MM-DD HH:mm")}
</span>
2025-01-24 17:39:41 +08:00
{isReceiverComment && (
<span className="inline-flex items-center px-2 py-1 text-xs font-medium rounded-full bg-blue-100 text-blue-800">
</span>
)}
2025-01-24 00:19:02 +08:00
</div>
<div
className="ql-editor text-slate-800"
style={{
padding: 0,
}}
dangerouslySetInnerHTML={{ __html: post.content || "" }}
/>
{/* 添加有帮助按钮 */}
<div className="mt-3 flex items-center">
<motion.button
onClick={likeThisPost}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
className={`inline-flex items-center space-x-1.5 px-3 py-1.5 rounded-full text-sm
2025-01-24 17:39:41 +08:00
${
liked
? "bg-blue-50 text-blue-600"
: "hover:bg-slate-50 text-slate-600"
} transition-colors duration-200`}>
{liked ? <LikeFilled /> : <LikeOutlined />}
<span>{likeCount} </span>
2025-01-24 00:19:02 +08:00
</motion.button>
</div>
</div>
</div>
</motion.div>
);
}