Merge pull request #64 from ragestudio/posts-comments

Posts comments
This commit is contained in:
srgooglo 2022-09-16 15:06:47 +02:00 committed by GitHub
commit c6953bdc6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 380 additions and 23 deletions

View File

@ -12,6 +12,7 @@
"variants": {
"light": {
"appColor": "#ff6064",
"text-color": "#000000",
"layoutBackgroundColor": "255, 255, 255",
"background-color-primary": "#ffffff",
"background-color-primary2": "#f0f0f0",

View File

@ -0,0 +1,13 @@
import React from "react"
import * as antd from "antd"
import "./index.less"
export default (props) => {
return <div className="commentCreator">
<antd.Input.TextArea
placeholder="Write a comment..."
autoSize={{ minRows: 2, maxRows: 5 }}
/>
</div>
}

View File

@ -0,0 +1,22 @@
.commentCreator {
display: flex;
flex-direction: column;
align-items: right;
width: 100%;
height: 100%;
.ant-input {
background-color: var(--background-color-accent) !important;
border: none !important;
outline: none !important;
}
.ant-btn {
width: fit-content;
margin-top: 20px;
}
}

View File

@ -0,0 +1,86 @@
import React from "react"
import * as antd from "antd"
import moment from "moment"
import { CommentCreator } from "components"
import "./index.less"
export default (props) => {
const [postData, setPostData] = React.useState(null)
const [comments, setComments] = React.useState(null)
const fetchData = async () => {
setPostData(null)
setComments(null)
// fetch post data
const postDataResult = await window.app.api.request("main", "get", `post`, undefined, {
post_id: props.post_id
}).catch((err) => {
console.log(err)
antd.message.error("Failed to fetch post data")
return null
})
if (!postDataResult) return
setPostData(postDataResult)
// fetch comments
const commentsResult = await window.app.api.customRequest("main", {
method: "get",
url: `/post/${props.post_id}/comments`,
}).catch((err) => {
console.log(err)
antd.message.error("Failed to fetch comments")
return null
})
console.log(commentsResult)
if (!commentsResult) return
setComments(commentsResult.data)
}
React.useEffect(() => {
fetchData()
}, [])
const renderComments = () => {
return comments.map((comment) => {
return <div className="comment" id={comment._id}>
<div className="header">
<div className="avatar">
<antd.Avatar src={comment.user.avatar} />
</div>
<div className="username">
{comment.user.username}
</div>
<div className="timeAgo">
{moment(comment.createdAt).fromNow()}
</div>
</div>
<div className="content">
{comment.message}
</div>
</div>
})
}
if (!comments) {
return <antd.Skeleton active />
}
return <div className="comments">
{renderComments()}
<div className="commentCreatorWrapper">
<CommentCreator />
</div>
</div>
}

View File

@ -0,0 +1,71 @@
.comments {
display: flex;
flex-direction: column;
padding: 10px;
.comment {
display: flex;
flex-direction: column;
margin-bottom: 10px;
background-color: var(--background-color-accent);
padding: 10px;
border-radius: 8px;
.header {
display: flex;
flex-direction: row;
align-items: center;
margin-bottom: 15px;
.avatar {
width: 30px;
height: 30px;
border-radius: 50%;
margin-right: 10px;
}
.username {
font-size: 14px;
font-weight: 600;
color: #000;
}
.timeAgo {
font-size: 12px;
color: #999;
margin-left: 10px;
}
}
.content {
font-size: 14px;
color: var(--text-color);
margin-left: 20px;
}
}
.commentCreatorWrapper {
position: sticky;
display: flex;
flex-direction: column;
align-items: center;
bottom: 0;
right: 0;
width: 100%;
padding: 30px 5px;
backdrop-filter: blur(10px);
border-radius: 10px;
background-color: rgba(var(--background-color-accent), 0.6);
}
}

View File

@ -349,6 +349,16 @@ export const PostCard = React.memo(({
return events.onDoubleClick(data)
}
React.useEffect(() => {
if (fullmode) {
app.eventBus.emit("style.compactMode", true)
}
return () => {
app.eventBus.emit("style.compactMode", false)
}
}, [])
React.useEffect(() => {
// first listen to post changes
window.app.api.namespaces["main"].listenEvent(`post.dataUpdate.${data._id}`, onDataUpdate)
@ -397,29 +407,36 @@ export const PostCard = React.memo(({
isLiked={hasLiked}
likes={likes.length}
comments={comments.length}
fullmode={fullmode}
/>
<PostContent
data={data}
autoCarrousel={autoCarrousel}
fullmode={fullmode}
/>
</div>
<div className="actionsIndicatorWrapper">
<div className="actionsIndicator">
<Icons.MoreHorizontal />
{!fullmode &&
<div className="actionsIndicatorWrapper">
<div className="actionsIndicator">
<Icons.MoreHorizontal />
</div>
</div>
</div>
<div className="actionsWrapper">
<PostActions
isSelf={selfId === data.user_id}
defaultLiked={hasLiked}
defaultSaved={hasSaved}
onClickLike={onClickLike}
onClickSave={onClickSave}
actions={{
delete: onClickDelete,
}}
/>
</div>
}
{!fullmode &&
<div className="actionsWrapper">
<PostActions
isSelf={selfId === data.user_id}
defaultLiked={hasLiked}
defaultSaved={hasSaved}
onClickLike={onClickLike}
onClickSave={onClickSave}
actions={{
delete: onClickDelete,
}}
fullmode={fullmode}
/>
</div>
}
</div>
})

View File

@ -33,6 +33,51 @@
&.fullmode {
max-width: none;
height: 100%;
background-color: transparent;
filter: none;
.actionsIndicatorWrapper {
opacity: 0;
}
.actionsWrapper {
opacity: 1;
}
.wrapper {
height: 100%;
.content {
height: 100%;
.additions {
height: fit-content;
max-height: 80vh;
.addition {
display: flex !important;
flex-direction: column;
align-items: center;
justify-content: center;
img,
video {
width: fit-content;
height: 100%;
align-self: center;
object-fit: contain;
border-radius: 8px;
}
}
}
}
}
}
.wrapper {

View File

@ -40,6 +40,10 @@ export { default as PostsFeed } from "./PostsFeed"
export { default as PostCard } from "./PostCard"
export { default as PostCreator } from "./PostCreator"
// COMMENTS
export { default as CommentsCard } from "./CommentsCard"
export { default as CommentCreator } from "./CommentCreator"
// USERS
export { default as FollowersList } from "./FollowersList"

View File

@ -1,7 +1,7 @@
import React from "react"
import * as antd from "antd"
import { PostCard } from "components"
import { PostCard, CommentsCard } from "components"
import "./index.less"
@ -28,6 +28,11 @@ export default (props) => {
}
return <div className="fullPost">
<PostCard data={data} fullmode />
<div className="postWrapper">
<PostCard data={data} fullmode />
</div>
<div className="commentsWrapper">
<CommentsCard post_id={data._id} />
</div>
</div>
}

View File

@ -1,3 +1,28 @@
.fullPost {
display: flex;
flex-direction: row;
width: 100%;
height: 100vh;
overflow: hidden;
.postWrapper {
height: 100vh;
width: 100%;
margin: 0 10px;
}
.commentsWrapper {
max-width: 600px;
min-width: 400px;
width: 40%;
height: 100vh;
overflow: scroll;
margin: 0 10px;
}
}

View File

@ -32,6 +32,7 @@ export default class Server {
controllers.PostsController,
controllers.StreamingController,
controllers.BadgesController,
controllers.CommentsController,
]
middlewares = middlewares

View File

@ -2,15 +2,70 @@ import { Controller } from "linebridge/dist/server"
import { User, Post, Comment } from "../../models"
import { Schematized } from "../../lib"
import getComments from "./methods/getComments"
export default class CommentsController extends Controller {
static refName = "CommentsController"
get = {
"/comments": {
fn: Schematized({
required: ["targetId"],
select: ["targetId"],
}, async (req, res) => {
})
},
"/post/:post_id/comments": {
fn: async (req, res) => {
const { post_id } = req.params
let comments = await Comment.find({ parent_id: post_id }).catch(err => {
res.status(500).json({ message: err.message })
return false
})
if (comments) {
// fullfill comments with user data
comments = await Promise.all(comments.map(async comment => {
const user = await User.findById(comment.user_id)
return {
...comment.toObject(),
user: user.toObject(),
}
}))
return res.json(comments)
}
}
}
}
post = {
"/post/:post_id/comment": {
middlewares: ["withAuthentication"],
fn: Schematized({
required: ["message"],
select: ["message"],
}, async (req, res) => {
const { post_id } = req.params
const { message } = req.selection
const comment = new Comment({
user_id: req.user._id.toString(),
parent_id: post_id,
message: message,
})
await comment.save()
if (comment) {
return res.json(comment)
}
})
}
}
put = {

View File

@ -0,0 +1,11 @@
import { User, Post, Comment } from "../../../models"
export default (payload) => {
const { parent_id, _id } = payload
if (typeof _id !== "undefined") {
return Comment.findById(_id)
}
return Comment.find({ parent_id })
}

View File

@ -6,4 +6,5 @@ export { default as FilesController } from "./FilesController"
export { default as PublicController } from "./PublicController"
export { default as PostsController } from "./PostsController"
export { default as StreamingController } from "./StreamingController"
export { default as BadgesController } from "./BadgesController"
export { default as BadgesController } from "./BadgesController"
export { default as CommentsController } from "./CommentsController"

View File

@ -1,7 +1,7 @@
export default {
user_id: { type: String, required: true },
parent_id: { type: String, required: true },
content: { type: String, required: true },
message: { type: String, required: true },
created_at: { type: Date, default: Date.now },
liked: { type: Array, default: [] },
//liked: { type: Array, default: [] },
}