123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- import React from "react"
- import Participants from "misago/components/participants"
- import { Poll, PollForm } from "misago/components/poll"
- import PostsList from "misago/components/posts-list"
- import * as participants from "misago/reducers/participants"
- import * as poll from "misago/reducers/poll"
- import * as posts from "misago/reducers/posts"
- import * as thread from "misago/reducers/thread"
- import ajax from "misago/services/ajax"
- import polls from "misago/services/polls"
- import snackbar from "misago/services/snackbar"
- import posting from "misago/services/posting"
- import store from "misago/services/store"
- import title from "misago/services/page-title"
- import { PostingQuoteSelection } from "../posting"
- import PageContainer from "../PageContainer"
- import ThreadHeader from "./ThreadHeader"
- import ThreadToolbarBottom from "./ThreadToolbarBottom"
- import ThreadToolbarTop from "./ThreadToolbarTop"
- export default class extends React.Component {
- constructor(props) {
- super(props)
- this.state = {
- editPoll: false,
- }
- }
- componentDidMount() {
- if (this.shouldFetchData()) {
- this.fetchData()
- this.setPageTitle()
- }
- this.startPollingApi()
- }
- componentDidUpdate() {
- if (this.shouldFetchData()) {
- this.fetchData()
- this.startPollingApi()
- this.setPageTitle()
- }
- }
- componentWillUnmount() {
- this.stopPollingApi()
- }
- shouldFetchData() {
- if (this.props.posts.isLoaded) {
- const page = (this.props.params.page || 1) * 1
- return page != this.props.posts.page
- } else {
- return false
- }
- }
- fetchData() {
- store.dispatch(posts.unload())
- ajax
- .get(
- this.props.thread.api.posts.index,
- {
- page: this.props.params.page || 1,
- },
- "posts"
- )
- .then(
- (data) => {
- this.update(data)
- },
- (rejection) => {
- snackbar.apiError(rejection)
- }
- )
- }
- startPollingApi() {
- polls.start({
- poll: "thread-posts",
- url: this.props.thread.api.posts.index,
- data: {
- page: this.props.params.page || 1,
- },
- update: this.update,
- frequency: 120 * 1000,
- delayed: true,
- })
- }
- stopPollingApi() {
- polls.stop("thread-posts")
- }
- setPageTitle() {
- title.set({
- title: this.props.thread.title,
- parent: this.props.thread.category.name,
- page: (this.props.params.page || 1) * 1,
- })
- }
- update = (data) => {
- store.dispatch(thread.replace(data))
- store.dispatch(posts.load(data.post_set))
- if (data.participants) {
- store.dispatch(participants.replace(data.participants))
- }
- if (data.poll) {
- store.dispatch(poll.replace(data.poll))
- }
- this.setPageTitle()
- }
- openPollForm = () => {
- this.setState({ editPoll: true })
- }
- closePollForm = () => {
- this.setState({ editPoll: false })
- }
- openReplyForm = () => {
- posting.open({
- mode: "REPLY",
- thread: this.props.thread,
- config: this.props.thread.api.editor,
- submit: this.props.thread.api.posts.index,
- })
- }
- render() {
- const category = this.props.thread.category
- let className = "page page-thread"
- if (category.css_class) {
- className += " page-thread-" + category.css_class
- }
- const styleName =
- category.special_role === "private_threads"
- ? "private-threads"
- : category.css_class || "category-threads"
- const threadModeration = getThreadModeration(
- this.props.thread,
- this.props.user
- )
- const postsModeration = getPostsModeration(
- this.props.posts.results,
- this.props.user
- )
- const selection = this.props.posts.results.filter((post) => post.isSelected)
- return (
- <div className={className}>
- <ThreadHeader
- styleName={styleName}
- thread={this.props.thread}
- posts={this.props.posts}
- user={this.props.user}
- moderation={threadModeration}
- />
- <PageContainer>
- <Participants
- participants={this.props.participants}
- thread={this.props.thread}
- user={this.props.user}
- />
- <ThreadToolbarTop
- thread={this.props.thread}
- posts={this.props.posts}
- user={this.props.user}
- selection={selection}
- moderation={postsModeration}
- pollDisabled={this.state.editPoll}
- onPoll={this.openPollForm}
- onReply={this.openReplyForm}
- />
- {this.state.editPoll ? (
- <PollForm
- poll={this.props.poll}
- thread={this.props.thread}
- close={this.closePollForm}
- />
- ) : (
- <Poll
- poll={this.props.poll}
- thread={this.props.thread}
- user={this.props.user}
- edit={this.openPollForm}
- />
- )}
- {this.props.thread.acl.can_reply ? (
- <PostingQuoteSelection
- posting={{
- mode: "REPLY",
- thread: this.props.thread,
- config: this.props.thread.api.editor,
- submit: this.props.thread.api.posts.index,
- }}
- >
- <PostsList {...this.props} />
- </PostingQuoteSelection>
- ) : (
- <PostsList {...this.props} />
- )}
- <ThreadToolbarBottom
- thread={this.props.thread}
- posts={this.props.posts}
- user={this.props.user}
- selection={selection}
- moderation={postsModeration}
- onReply={this.openReplyForm}
- />
- </PageContainer>
- </div>
- )
- }
- }
- const getThreadModeration = (thread, user) => {
- const moderation = {
- enabled: false,
- edit: false,
- approve: false,
- close: false,
- open: false,
- hide: false,
- unhide: false,
- move: false,
- merge: false,
- pinGlobally: false,
- pinLocally: false,
- unpin: false,
- delete: false,
- }
- if (!user.is_authenticated) return moderation
- moderation.edit = thread.acl.can_edit
- moderation.approve = thread.acl.can_approve && thread.is_unapproved
- moderation.close = thread.acl.can_close && !thread.is_closed
- moderation.open = thread.acl.can_close && thread.is_closed
- moderation.hide = thread.acl.can_hide && !thread.is_hidden
- moderation.unhide = thread.acl.can_unhide && thread.is_hidden
- moderation.move = thread.acl.can_move
- moderation.merge = thread.acl.can_merge
- moderation.pinGlobally = thread.acl.can_pin_globally && thread.weight < 2
- moderation.pinLocally = thread.acl.can_pin && thread.weight !== 1
- moderation.unpin =
- (thread.acl.can_pin && thread.weight === 1) ||
- (thread.acl.can_pin_globally && thread.weight === 2)
- moderation.delete = thread.acl.can_delete
- moderation.enabled =
- moderation.edit ||
- moderation.approve ||
- moderation.close ||
- moderation.open ||
- moderation.hide ||
- moderation.unhide ||
- moderation.move ||
- moderation.merge ||
- moderation.pinGlobally ||
- moderation.pinLocally ||
- moderation.unpin ||
- moderation.delete
- return moderation
- }
- const getPostsModeration = (posts, user) => {
- const moderation = {
- enabled: false,
- approve: false,
- move: false,
- merge: false,
- protect: false,
- hide: false,
- delete: false,
- }
- if (!user.is_authenticated) return moderation
- posts.forEach((post) => {
- if (!post.is_event) {
- if (post.acl.can_approve && post.is_unapproved) {
- moderation.approve = true
- }
- if (post.acl.can_move) moderation.move = true
- if (post.acl.can_merge) moderation.merge = true
- if (post.acl.can_protect || post.acl.can_unprotect) {
- moderation.protect = true
- }
- if (post.acl.can_hide || post.acl.can_unhide) {
- moderation.hide = true
- }
- if (post.acl.can_delete) moderation.delete = true
- if (
- moderation.approve ||
- moderation.move ||
- moderation.merge ||
- moderation.protect ||
- moderation.hide ||
- moderation.delete
- ) {
- moderation.enabled = true
- }
- }
- })
- return moderation
- }
|