import React from "react" import * as antd from "antd" import { User } from "models" import { Icons } from "components/Icons" import { PostCard, LoadMore } from "components" import "./index.less" const LoadingComponent = () => { // FIXME: Im not sure why but, using will cause a memory leak of DOM Nodes when using IntersectionObserver //return return

Loading more ...

} const NoResultComponent = () => { return } export default class PostsFeed extends React.Component { state = { selfId: null, initialLoading: true, fetchingData: true, hasMorePosts: true, renderList: [], } api = window.app.api.withEndpoints() listRef = React.createRef() wsEvents = { "post.new": async (data) => { this.insert(data) }, "post.delete": async (data) => { this.remove(data) } } componentDidMount = async () => { await this.loadSelfId() // load ws events Object.keys(this.wsEvents).forEach((event) => { window.app.api.namespaces["main"].listenEvent(event, this.wsEvents[event]) }) // TODO: register keybindings to handle directions key scrolling to posts (use app.shortcuts) // window.app.shortcuts.register("ArrowUp", () => { // // {...} // }) // window.app.shortcuts.register("ArrowDown", () => { // // {...} // }) await this.loadPosts() await this.setState({ initialLoading: false }) } componentWillUnmount = async () => { // unload ws events Object.keys(this.wsEvents).forEach((event) => { window.app.api.namespaces["main"].unlistenEvent(event, this.wsEvents[event]) }) } loadSelfId = async () => { const selfId = await User.selfUserId() this.setState({ selfId: selfId, }) } loadPosts = async ({ trim, replace = false } = {}) => { // toogle fetching flag await this.setState({ fetchingData: true, }) // get posts from api const result = await this.api.get.feed(undefined, { trim: trim ?? this.state.renderList.length, limit: this.props.feedLength ?? window.app.settings.get("feed_max_fetch"), user_id: this.props.fromUserId, }) console.log(result) if (result) { // if result is empty, its mean there is no more posts, so set hasMorePosts to false if (result.length === 0) { await this.setState({ hasMorePosts: false, }) return false } if (replace) { // replace all posts render list await this.setState({ renderList: result.map((item) => this.getPostRender(item, item.key)) }) } else { // else append posts to render list await this.setState({ renderList: [ ...this.state.renderList, ...result.map((item) => this.getPostRender(item, item.key)) ] }) } } // toogle fetching flag await this.setState({ fetchingData: false, }) } onLikePost = async (data) => { let result = await this.api.put.toogleLike({ post_id: data._id }).catch(() => { antd.message.error("Failed to like post") return false }) return result } onDeletePost = async (data) => { let result = await this.api.delete.post({ post_id: data._id }).catch(() => { antd.message.error("Failed to delete post") return false }) return result } onDoubleClickPost = (data) => { // open post app.setLocation(`/post/${data._id}`) } insert = async (data) => { await this.setState({ renderList: [this.getPostRender(data), ...this.state.renderList], }) } remove = async (post_id) => { const updatedList = this.state.renderList const postIndex = updatedList.findIndex((item) => item.props.data._id === post_id) updatedList.splice(postIndex, 1) await this.setState({ renderList: updatedList, }) } getPostRender = (item, index = this.state.renderList.length) => { return } render() { if (this.state.initialLoading) { return } if (this.state.renderList.length === 0) { return

Whoa, nothing on here...

} return
{ this.loadPosts() }} loadingComponent={LoadingComponent} noResultComponent={NoResultComponent} fetching={this.state.fetchingData} hasMore={this.state.hasMorePosts} className="posts" ref={this.listRef} > {this.state.renderList}
} }