import React from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { chain, get, find } from 'lodash'; import marked from 'marked'; import { DateTime } from 'luxon'; import { inject, observer } from 'mobx-react'; import { CharacterService, ThreadService } from '../../services'; import { Editor, PaginationLinks, Portrait, ScrollToTop } from '../../components'; import { ReplyModel, ThreadModel } from '../../model'; import { UserStore } from '../../stores/user-store'; import { Oauth, pagination } from '../../util'; import './thread.scss'; interface Props extends RouteComponentProps { userStore: UserStore; page: number; } interface State { editingReply?: ReplyModel; quotedReply?: ReplyModel; showEditor: boolean; thread?: ThreadModel; replies: ReplyModel[]; pageLinks: (number | string)[]; } @inject('userStore') @observer export class Thread extends React.Component { constructor(props: Props) { super(props); this.state = { showEditor: false, replies: [], pageLinks: [], }; } componentDidMount() { this.getReplies(); } componentWillReceiveProps(nextProps: Props) { if (this.props.match.params['page'] !== nextProps.match.params['page']) { this.processReplies(this.state.thread!, nextProps); } } private routeParams(props: Props = this.props) { return { categoryId: parseInt(props.match.params['categoryId'], 10), threadId: parseInt(props.match.params['threadId'], 10), page: parseInt(props.match.params['page'], 10) || 1, }; } private navigateHere(page: number) { const { categoryId, threadId } = this.routeParams(); const url = `/t/${categoryId}/${threadId}/${page}`; this.props.history.push(url); } private async getReplies() { const thread = await ThreadService.getThread(this.props.match.params['threadId']); this.processReplies(thread); } private processReplies(thread: ThreadModel, props: Props = this.props) { thread.replies = chain(thread.replies) .orderBy(['inserted_at'], ['asc']) .map((t, i) => { t.index = i; return t; }) .value(); const { page } = this.routeParams(props); const numPages = Math.ceil(thread.replies.length / 20); const replyIndex = (page - 1) * 20; this.setState({ thread, replies: [...thread.replies].splice(replyIndex, 20), pageLinks: pagination(page, numPages), }); } private onReplyClick() { this.props.userStore.user ? this.setState({ showEditor: true }) : Oauth.openOuathWindow(); } private onQuoteClick(reply: ReplyModel) { this.props.userStore.user ? this.setState({ showEditor: true, quotedReply: reply, }) : Oauth.openOuathWindow(); } private onEditClick(reply: ReplyModel) { this.setState({ editingReply: reply, showEditor: true, }); } private onEditorClose(cancel: boolean) { this.setState({ showEditor: false, quotedReply: undefined, editingReply: undefined, }); if (!cancel) { this.getReplies(); } } private navigateForumIndex() { this.props.history.push(`/f/${this.state.thread!.category_id}`); } private getTimeFormat(dateTime: string) { return DateTime.fromISO(dateTime).toLocaleString({ year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: '2-digit', timeZoneName: 'short', }); } private renderQuotedReply(reply: ReplyModel) { const quotedReply = find(this.state.thread!.replies, { id: reply.quote_id }); return (quotedReply &&
Q u o t e:
); } renderUserInfo(reply: ReplyModel) { const { battletag, character_avatar, character_class, character_guild, character_name, character_realm, permissions } = reply.user; return (
{character_name || battletag}
{character_class &&
{character_class}
} {character_guild &&
Guild: {character_guild}
} {character_realm &&
Realm: {character_realm}
} {permissions === 'admin' &&
Admin Poster
}
); } renderEditbutton(reply: ReplyModel): any { if (get(this.props, 'userStore.user.id') === reply.user_id) { return this.onEditClick(reply)}>Edit; } } renderReplies(): any { return this.state.replies.map((reply, index) => { const replyDark = index % 2 === 0 ? 'reply--dark' : ''; const bluePost = reply.user.permissions === 'admin' ? 'blue-post' : ''; return (
{this.renderUserInfo(reply)}
{`${reply.index! + 1}. `}{index > 0 && 'Re: '}{this.state.thread!.title} | {this.getTimeFormat(reply.inserted_at)}
{this.renderEditbutton(reply)} this.onQuoteClick(reply)}/> this.onReplyClick()}/>
{this.renderQuotedReply(reply)}
{reply.edited && [ post edited by {reply.user.character_name || reply.user.battletag} ]}
); }); } renderPagingBg() { return (
this.navigateHere(page)} showArrows={true} />
); } render() { const { editingReply, thread, replies, showEditor, quotedReply } = this.state; if (!thread) { return
; } return ( {showEditor && this.onEditorClose(cancel)} quotedReply={quotedReply} editingReply={editingReply} /> }
Topic: | {this.getTimeFormat(thread!.inserted_at)}
this.navigateForumIndex()} style={{ cursor: 'pointer' }} />
{this.renderPagingBg()}
{replies && this.renderReplies()}
{this.renderPagingBg()}
this.navigateForumIndex()} style={{ cursor: 'pointer', float: 'right' }} />
); } }