mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-13 12:34:16 +00:00
232 lines
6.9 KiB
JavaScript
Executable File
232 lines
6.9 KiB
JavaScript
Executable File
import React from "react"
|
|
import * as antd from "antd"
|
|
import classnames from "classnames"
|
|
import Plyr from "plyr-react"
|
|
|
|
import { CommentsCard } from "components"
|
|
import { Icons } from "components/Icons"
|
|
|
|
import { processString } from "utils"
|
|
|
|
import PostHeader from "./components/header"
|
|
import PostActions from "./components/actions"
|
|
import PostAttachments from "./components/attachments"
|
|
|
|
import "./index.less"
|
|
|
|
const messageRegexs = [
|
|
{
|
|
regex: /https?:\/\/(?:www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_-]{11})(&[a-zA-Z0-9_-]+=[a-zA-Z0-9_-]+)*/g,
|
|
fn: (key, result) => {
|
|
return <Plyr source={{
|
|
type: "video",
|
|
sources: [{
|
|
src: result[1],
|
|
provider: "youtube",
|
|
}],
|
|
}} />
|
|
}
|
|
},
|
|
{
|
|
regex: /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/gi,
|
|
fn: (key, result) => {
|
|
return <a key={key} href={result[1]} target="_blank" rel="noopener noreferrer">{result[1]}</a>
|
|
}
|
|
},
|
|
{
|
|
regex: /(@[a-zA-Z0-9_]+)/gi,
|
|
fn: (key, result) => {
|
|
return <a key={key} onClick={() => window.app.setLocation(`/@${result[1].substr(1)}`)}>{result[1]}</a>
|
|
}
|
|
},
|
|
]
|
|
|
|
export default class PostCard extends React.PureComponent {
|
|
state = {
|
|
countLikes: this.props.data.countLikes ?? 0,
|
|
countComments: this.props.data.countComments ?? 0,
|
|
|
|
hasLiked: this.props.data.isLiked ?? false,
|
|
hasSaved: this.props.data.isSaved ?? false,
|
|
|
|
open: this.props.defaultOpened ?? false,
|
|
|
|
isNsfw: this.props.data.flags?.includes("nsfw") ?? false,
|
|
nsfwAccepted: false,
|
|
}
|
|
|
|
onClickDelete = async () => {
|
|
if (typeof this.props.events.onClickDelete !== "function") {
|
|
console.warn("onClickDelete event is not a function")
|
|
return
|
|
}
|
|
|
|
return await this.props.events.onClickDelete(this.props.data)
|
|
}
|
|
|
|
onClickLike = async () => {
|
|
if (typeof this.props.events.onClickLike !== "function") {
|
|
console.warn("onClickLike event is not a function")
|
|
return
|
|
}
|
|
|
|
return await this.props.events.onClickLike(this.props.data)
|
|
}
|
|
|
|
onClickSave = async () => {
|
|
if (typeof this.props.events.onClickSave !== "function") {
|
|
console.warn("onClickSave event is not a function")
|
|
return
|
|
}
|
|
|
|
return await this.props.events.onClickSave(this.props.data)
|
|
}
|
|
|
|
onClickEdit = async () => {
|
|
if (typeof this.props.events.onClickEdit !== "function") {
|
|
console.warn("onClickEdit event is not a function")
|
|
return
|
|
}
|
|
|
|
return await this.props.events.onClickEdit(this.props.data)
|
|
}
|
|
|
|
onDoubleClick = async () => {
|
|
this.handleOpen()
|
|
}
|
|
|
|
onClickComments = async () => {
|
|
this.handleOpen()
|
|
}
|
|
|
|
handleOpen = (to) => {
|
|
if (typeof to === "undefined") {
|
|
to = !this.state.open
|
|
}
|
|
|
|
if (typeof this.props.events?.onToogleOpen === "function") {
|
|
this.props.events?.onToogleOpen(to, this.props.data)
|
|
}
|
|
|
|
this.setState({
|
|
open: to,
|
|
})
|
|
|
|
//app.controls.openPostViewer(this.props.data)
|
|
}
|
|
|
|
onLikesUpdate = (data) => {
|
|
console.log("onLikesUpdate", data)
|
|
|
|
if (data.to) {
|
|
this.setState({
|
|
countLikes: this.state.countLikes + 1,
|
|
})
|
|
} else {
|
|
this.setState({
|
|
countLikes: this.state.countLikes - 1,
|
|
})
|
|
}
|
|
}
|
|
|
|
componentDidMount = async () => {
|
|
// first listen to post changes
|
|
app.cores.api.listenEvent(`post.${this.props.data._id}.likes.update`, this.onLikesUpdate)
|
|
}
|
|
|
|
componentWillUnmount = () => {
|
|
// remove the listener
|
|
app.cores.api.unlistenEvent(`post.${this.props.data._id}.likes.update`, this.onLikesUpdate)
|
|
}
|
|
|
|
componentDidCatch = (error, info) => {
|
|
console.error(error)
|
|
|
|
return <div className="postCard error">
|
|
<h1>
|
|
<Icons.AlertTriangle />
|
|
<span>Cannot render this post</span>
|
|
<span>
|
|
Maybe this version of the app is outdated or is not supported yet
|
|
</span>
|
|
</h1>
|
|
</div>
|
|
}
|
|
|
|
render() {
|
|
return <div
|
|
key={this.props.index}
|
|
id={this.props.data._id}
|
|
className={classnames(
|
|
"postCard",
|
|
{
|
|
["open"]: this.state.open,
|
|
}
|
|
)}
|
|
style={this.props.style}
|
|
context-menu={"postCard-context"}
|
|
user-id={this.props.data.user_id}
|
|
>
|
|
<PostHeader
|
|
postData={this.props.data}
|
|
onDoubleClick={this.onDoubleClick}
|
|
/>
|
|
|
|
<div
|
|
id="post_content"
|
|
className={classnames(
|
|
"post_content",
|
|
{
|
|
["nsfw"]: this.state.isNsfw && !this.state.nsfwAccepted,
|
|
}
|
|
)}
|
|
>
|
|
{
|
|
this.state.isNsfw && !this.state.nsfwAccepted &&
|
|
<div className="nsfw_alert">
|
|
<h2>
|
|
This post may contain sensitive content.
|
|
</h2>
|
|
|
|
<antd.Button onClick={() => this.setState({ nsfwAccepted: true })}>
|
|
Show anyways
|
|
</antd.Button>
|
|
</div>
|
|
}
|
|
|
|
<div className="message">
|
|
{
|
|
processString(messageRegexs)(this.props.data.message ?? "")
|
|
}
|
|
</div>
|
|
|
|
{
|
|
this.props.data.attachments && this.props.data.attachments.length > 0 && <PostAttachments
|
|
attachments={this.props.data.attachments}
|
|
/>
|
|
}
|
|
|
|
</div>
|
|
|
|
<PostActions
|
|
user_id={this.props.data.user_id}
|
|
likesCount={this.state.countLikes}
|
|
commentsCount={this.state.countComments}
|
|
defaultLiked={this.state.hasLiked}
|
|
defaultSaved={this.state.hasSaved}
|
|
actions={{
|
|
onClickLike: this.onClickLike,
|
|
onClickEdit: this.onClickEdit,
|
|
onClickDelete: this.onClickDelete,
|
|
onClickSave: this.onClickSave,
|
|
onClickComments: this.onClickComments,
|
|
}}
|
|
/>
|
|
|
|
<CommentsCard
|
|
post_id={this.props.data._id}
|
|
visible={this.state.open}
|
|
/>
|
|
</div>
|
|
}
|
|
} |