diff --git a/packages/app/src/components/PostCard/index.jsx b/packages/app/src/components/PostCard/index.jsx index f2ed249c..6d294dc0 100644 --- a/packages/app/src/components/PostCard/index.jsx +++ b/packages/app/src/components/PostCard/index.jsx @@ -1,17 +1,23 @@ import React from "react" import * as antd from "antd" +import { Swiper } from "antd-mobile" import { Icons } from "components/Icons" import { LikeButton } from "components" import moment from "moment" import classnames from "classnames" - -import { User } from "models" +import loadable from "@loadable/component" import CSSMotion from "rc-animate/lib/CSSMotion" import useLayoutEffect from "rc-util/lib/hooks/useLayoutEffect" import "./index.less" +const ContentFailed = () => { + return
+ +
+} + const getCurrentHeight = (node) => ({ height: node.offsetHeight }) const getMaxHeight = (node) => { @@ -78,13 +84,104 @@ function PostHeader(props) { } -function PostContent({ message }) { +const PostContent = React.memo((props) => { + let { message, additions } = props.data + + // first filter if is an string + additions = additions.filter(file => typeof file === "string") + + // then filter if is an uri + additions = additions.filter(file => /^(http|https):\/\//.test(file)) + + additions = additions.map((uri, index) => { + const MediaRender = loadable(async () => { + // create a basic http request for fetching the file media type + const request = new Request(uri, { + method: "HEAD", + }) + + // fetch the file media type + const mediaType = await fetch(request) + .then(response => response.headers.get("content-type")) + .catch((error) => { + console.error(error) + return null + }) + + if (!mediaType) { + return () => + } + + switch (mediaType.split("/")[0]) { + case "image": { + return () => + } + case "video": { + return () => + } + case "audio": { + return () => + } + + default: { + return () =>

+ Unsupported media type [{mediaType}] +

+ } + } + }) + + return +
+ Loading
} > + + + +
+ }) + + return
{message} -
-} -function PostActions(props) { + {additions && +
+ + {additions} + +
+ } + +}) + +const PostActions = (props) => { + const handleSelfMenuAction = async (event) => { + const fn = props.actions[event.key] + + if (typeof fn === "function") { + await fn() + } + } + return
@@ -101,10 +198,25 @@ function PostActions(props) {
- {props.isSelf &&
-
- -
+ {props.self &&
+ + } key="edit"> + Edit + + + } key="delete"> + Delete + + } + trigger={['click']} + > +
+ +
+
}
} @@ -112,36 +224,59 @@ function PostActions(props) { export class PostCard extends React.Component { state = { loading: true, - selfId: null, - data: this.props.data, + likes: this.props.data.likes, + comments: this.props.data.comments, } api = window.app.request componentDidMount = async () => { - const selfId = await User.selfUserId() - - window.app.ws.listen(`like.post.${this.props.data._id}`, async (data) => { - await this.setState({ data }) + window.app.ws.listen(`post.like.${this.props.data._id}`, async (data) => { + await this.setState({ likes: data }) }) - window.app.ws.listen(`unlike.post.${this.props.data._id}`, async (data) => { - await this.setState({ data }) + window.app.ws.listen(`post.unlike.${this.props.data._id}`, async (data) => { + await this.setState({ likes: data }) + }) + + window.app.ws.listen(`post.comment.${this.props.data._id}`, async (data) => { + await this.setState({ comments: data }) + }) + window.app.ws.listen(`post.uncomment.${this.props.data._id}`, async (data) => { + await this.setState({ comments: data }) }) await this.setState({ - selfId, loading: false }) } + onClickDelete = async () => { + const result = await this.api.delete.post({ + post_id: this.props.data._id, + }).catch(error => { + console.error(error) + antd.message.error(error.message) + + return { + success: false, + } + }) + + if (result.success) { + if (typeof this.props.close === "function") { + this.props.close() + } + } + } + onClickLike = async (to) => { let result = false if (to) { - const apiResult = await await this.api.put.like({ post_id: this.props.data._id }) + const apiResult = await this.api.put.like({ post_id: this.props.data._id }) result = apiResult.success } else { - const apiResult = await await this.api.put.unlike({ post_id: this.props.data._id }) + const apiResult = await this.api.put.unlike({ post_id: this.props.data._id }) result = apiResult.success } @@ -149,15 +284,15 @@ export class PostCard extends React.Component { } onClickSave = async () => { - // TODO: save post + // TODO + } + + onClickEdit = async () => { + // TODO } hasLiked = () => { - return this.state.data.likes.some(user_id => user_id === this.state.selfId) - } - - isSelf = () => { - return this.state.selfId === this.state.data.user._id + return this.state.likes.some((user_id) => user_id === this.props.selfId) } render() { @@ -176,13 +311,11 @@ export class PostCard extends React.Component { this.onClickLike(false)} - onClickSave={this.onClickSave} - likes={this.state.data.likes.length} - comments={this.state.data.comments.length} + likes={this.state.likes.length} + comments={this.state.comments.length} />
@@ -192,26 +325,26 @@ export class PostCard extends React.Component {
} } -export const PostCardAnimated = ({ - data, - onAppear, - motionAppear, -}, ref,) => { +export const PostCardAnimated = (props, ref,) => { const motionRef = React.useRef(false) useLayoutEffect(() => { return () => { if (motionRef.current) { - onAppear() + props.onAppear() } } }, []) @@ -219,23 +352,23 @@ export const PostCardAnimated = ({ return { motionRef.current = true return getMaxHeight(node) }} - onAppearEnd={onAppear} + onAppearEnd={props.onAppear} onLeaveStart={getCurrentHeight} onLeaveActive={getCollapsedHeight} onLeaveEnd={() => { - onLeave(id) + props.onLeave(id) }} > - {(props, passedMotionRef) => { + {(_args, passedMotionRef) => { return }} diff --git a/packages/app/src/components/PostCard/index.less b/packages/app/src/components/PostCard/index.less index 78fe680f..55a2c508 100644 --- a/packages/app/src/components/PostCard/index.less +++ b/packages/app/src/components/PostCard/index.less @@ -128,6 +128,29 @@ overflow : hidden; word-break : break-all; user-select: text; + + .additions { + width: 100%; + + .addition { + width: 100%; + + // fixtures for media content + img { + width : 100%; + border-radius: 12px; + } + + video { + border-radius: 12px; + width : 100%; + } + + audio { + width: 100%; + } + } + } } >div {