前端主要通过与后端 API 交互来实现用户发帖。在前端组件中,可能有一个创建帖子的表单组件,用户输入文本和图片后,调用 fetch
方法向后端发送请求。从现有的代码中,虽然没有看到完整的创建帖子组件,但可以推测可能存在类似 CreatePost.jsx
的组件。
后端在 <mcfile name="postController.js" path="/Applications/Work/CodingProject/threads-clone/backend/controllers/postController.js"></mcfile>
文件中实现了 createPost
函数:
// ... existing code ...
const createPost = async (req, res) => {
try {
const { postedBy, text } = req.body;
let { img } = req.body;
if (!postedBy || !text) {
return res.status(400).json({ error: "Postedby and text fields are required" });
}
const user = await User.findById(postedBy);
if (!user) {
return res.status(404).json({ error: "User not found" });
}
if (user._id.toString() !== req.user._id.toString()) {
return res.status(401).json({ error: "Unauthorized to create post" });
}
const maxLength = 500;
if (text.length > maxLength) {
return res.status(400).json({ error: `Text must be less than ${maxLength} characters` });
}
if (img) {
const uploadedResponse = await cloudinary.uploader.upload(img);
img = uploadedResponse.secure_url;
}
const newPost = new Post({ postedBy, text, img });
await newPost.save();
res.status(201).json(newPost);
} catch (err) {
res.status(500).json({ error: err.message });
console.log(err);
}
};
// ... existing code ...
此函数首先验证用户输入,然后检查用户权限,接着处理图片上传,最后将帖子保存到数据库。
前端在 <mcfile name="Comment.jsx" path="/Applications/Work/CodingProject/threads-clone/frontend/src/components/Comment.jsx"></mcfile>
组件中展示评论,同时可能有一个输入框组件让用户输入评论内容,并调用后端 API 提交评论。
// ... existing code ...
const Comment = ({ reply, lastReply }) => {
return (
<>
<Flex gap={4} py={2} my={2} w={"full"}>
<Avatar src={reply.userProfilePic} size={"sm"} />
<Flex gap={1} w={"full"} flexDirection={"column"}>
<Flex w={"full"} justifyContent={"space-between"} alignItems={"center"}>
<Text fontSize='sm' fontWeight='bold'>
{reply.username}
</Text>
</Flex>
<Text>{reply.text}</Text>
</Flex>
</Flex>
{!lastReply ? <Divider /> : null}
</>
);
};
// ... existing code ...
后端在 <mcfile name="postController.js" path="/Applications/Work/CodingProject/threads-clone/backend/controllers/postController.js"></mcfile>
文件中实现了 replyToPost
函数:
// ... existing code ...
const replyToPost = async (req, res) => {
try {
const { text } = req.body;
const postId = req.params.id;
const userId = req.user._id;
const userProfilePic = req.user.profilePic;
const username = req.user.username;
if (!text) {
return res.status(400).json({ error: "Text field is required" });
}
const post = await Post.findById(postId);
if (!post) {
return res.status(404).json({ error: "Post not found" });
}
const reply = { userId, text, userProfilePic, username };
post.replies.push(reply);
await post.save();
res.status(200).json(reply);
} catch (err) {
res.status(500).json({ error: err.message });
}
};
// ... existing code ...
该函数接收用户输入的评论内容,找到对应的帖子,将评论添加到帖子的 replies
数组中。
前端在 <mcfile name="Conversation.jsx" path="/Applications/Work/CodingProject/threads-clone/frontend/src/components/Conversation.jsx"></mcfile>
组件中展示聊天会话,同时可能使用 socket.io-client
库与后端建立实时连接。
// ... existing code ...
const Conversation = ({ conversation, isOnline }) => {
const user = conversation.participants[0];
const currentUser = useRecoilValue(userAtom);
const lastMessage = conversation.lastMessage;
const [selectedConversation, setSelectedConversation] = useRecoilState(selectedConversationAtom);
const colorMode = useColorMode();
return (
<Flex
gap={4}
alignItems={"center"}
p={"1"}
_hover={{
cursor: "pointer",
bg: useColorModeValue("gray.600", "gray.dark"),
color: "white",
}}
onClick={() =>
setSelectedConversation({
_id: conversation._id,
userId: user._id,
userProfilePic: user.profilePic,
username: user.username,
mock: conversation.mock,
})
}
bg={
selectedConversation?._id === conversation._id ? (colorMode === "light" ? "gray.400" : "gray.dark") : ""
}
borderRadius={"md"}
>
<WrapItem>
<Avatar
size={{
base: "xs",
sm: "sm",
md: "md",
}}
src={user.profilePic}
>
{isOnline ? <AvatarBadge boxSize='1em' bg='green.500' /> : ""}
</Avatar>
</WrapItem>
<Stack direction={"column"} fontSize={"sm"}>
<Text fontWeight='700' display={"flex"} alignItems={"center"}>
{user.username} <Image src='/verified.png' w={4} h={4} ml={1} />
</Text>
<Text fontSize={"xs"} display={"flex"} alignItems={"center"} gap={1}>
{currentUser._id === lastMessage.sender ? (
<Box color={lastMessage.seen ? "blue.400" : ""}>
<BsCheck2All size={16} />
</Box>
) : (
""
)}
{lastMessage.text.length > 18
? lastMessage.text.substring(0, 18) + "..."
: lastMessage.text || <BsFillImageFill size={16} />}
</Text>
</Stack>
</Flex>
);
};
// ... existing code ...