From adbe3c68570bed527ca81f41d3b364a87a8fd8b1 Mon Sep 17 00:00:00 2001 From: Mitchell Gerber Date: Mon, 22 Jan 2018 21:29:49 -0600 Subject: [PATCH] client - thread page pagination done --- client/app/assets/arrow-left.gif | Bin 0 -> 456 bytes client/app/assets/arrow-right.gif | Bin 0 -> 455 bytes .../pagination-links/pagination-links.scss | 4 + .../pagination-links/pagination-links.tsx | 25 +++++- client/app/model/reply.ts | 1 + client/app/pages/forum/forum.tsx | 6 +- client/app/pages/thread/thread.scss | 4 + client/app/pages/thread/thread.tsx | 85 ++++++++++++++---- 8 files changed, 105 insertions(+), 20 deletions(-) create mode 100644 client/app/assets/arrow-left.gif create mode 100644 client/app/assets/arrow-right.gif create mode 100644 client/app/components/pagination-links/pagination-links.scss diff --git a/client/app/assets/arrow-left.gif b/client/app/assets/arrow-left.gif new file mode 100644 index 0000000000000000000000000000000000000000..c30dfbb31cbabb69694ca36d0bf771506b065a77 GIT binary patch literal 456 zcmV;(0XP0fNk%w1VHp4!0M$PL0006&F8~Jx0|5gF*O~x0Ck6lPyCfO~8x;c*4gzFI z0RP804Gj!FEdjfR0Hk&Rje}_f3>Sf2098Ez%aQ>8-;wy{w*2Y278Mlt<+cCTZI)~R z{_DE+a^j|rvKxc(4#T+z&AiP5h5WTNJ2L0*sI^KGqfV( zDF6TeA^8LW002J#EC2ui02u%o000K%z@KnPEE85tKnAc0|oMOzpU9U&nX z7ZntNYmh@)IuJY@1_m506%K)Ro>>4hhaDEBr7r}lgGLcDJ}@>pF$==NAa#MQKM?~1 zI|mKVtAP^|8xIr6KU)9-&e4GqCk`G3*sj|L-T@B;1Qd5mTinqTCoC!tSf2098Ez%aQ>8-;wy{w*2Y278Mlt<+cCTZI)~R z{_DE+a^j|rvKxc(4#T+z&AiP5h5WTNJ2L0*sI^KGqfV( zDF6TeA^8LW002J#EC2ui02u%o000K$z@KnPEEPk^le>0}=tn+2Rs0*zQ9hU`kmsHFj7`SRZ>JJr@}nBM^50OJfCl6cra2 zAt45@4wkMhJoc8p(AWNwQ=R06SHpsgeKy literal 0 HcmV?d00001 diff --git a/client/app/components/pagination-links/pagination-links.scss b/client/app/components/pagination-links/pagination-links.scss new file mode 100644 index 0000000..c7d676d --- /dev/null +++ b/client/app/components/pagination-links/pagination-links.scss @@ -0,0 +1,4 @@ +.pagination-links { + display: flex; + align-items: center; +} diff --git a/client/app/components/pagination-links/pagination-links.tsx b/client/app/components/pagination-links/pagination-links.tsx index 067d637..df92cee 100644 --- a/client/app/components/pagination-links/pagination-links.tsx +++ b/client/app/components/pagination-links/pagination-links.tsx @@ -1,9 +1,16 @@ import React from 'react'; +import './pagination-links.scss'; + +const arrows = { + right: require('../../assets/arrow-right.gif'), + left: require('../../assets/arrow-left.gif'), +}; interface Props { pageLinks: (number | string)[]; activePage: number; onPageSelect: (page: number) => void; + showArrows?: boolean; } interface State { @@ -26,11 +33,26 @@ export class PaginationLinks extends React.Component { this.onPageSelect(page)}>{page}; } + onArrowClick(arrow: 'right' | 'left') { + const nextPage = this.props.activePage + (arrow === 'right' ? 1 : -1); + if (this.props.pageLinks.includes(nextPage)) { + this.onPageSelect(nextPage); + } + } + + renderArrow(arrow: 'right' | 'left') { + if (this.props.showArrows) { + return this.onArrowClick(arrow)} className="clickable"/>; + } + return null; + } + render() { const { activePage, pageLinks } = this.props; return ( - + + {this.renderArrow('left')} {pageLinks.map((link, index) => { const active = link === activePage; return ( @@ -43,6 +65,7 @@ export class PaginationLinks extends React.Component { ); })} + {this.renderArrow('right')} ); } diff --git a/client/app/model/reply.ts b/client/app/model/reply.ts index d6fefd7..cc3cd85 100644 --- a/client/app/model/reply.ts +++ b/client/app/model/reply.ts @@ -4,6 +4,7 @@ export interface ReplyModel { content: string; edited: boolean; id: number; + index?: number; inserted_at: string; quote_id: number; thread_id: number; diff --git a/client/app/pages/forum/forum.tsx b/client/app/pages/forum/forum.tsx index e035d7c..7e2a499 100644 --- a/client/app/pages/forum/forum.tsx +++ b/client/app/pages/forum/forum.tsx @@ -99,8 +99,8 @@ export class Forum extends React.Component { this.setState({ threads, pageThreads: [...threads].splice(threadIndex, threadsPerPage), - pageLinks: pagination(page, numPages) }, - ); + pageLinks: pagination(page, numPages), + }); } private orderBy(threads: ThreadModel[], props: Props) { @@ -235,7 +235,7 @@ export class Forum extends React.Component { return (
-
+
Page: { userStore: UserStore; + page: number; } interface State { @@ -20,6 +21,8 @@ interface State { quotedReply?: ReplyModel; showEditor: boolean; thread?: ThreadModel; + replies: ReplyModel[]; + pageLinks: (number | string)[]; } @inject('userStore') @@ -30,6 +33,8 @@ export class Thread extends React.Component { super(props); this.state = { showEditor: false, + replies: [], + pageLinks: [], }; } @@ -37,10 +42,45 @@ export class Thread extends React.Component { 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']); - thread.replies = orderBy(thread.replies, ['inserted_at']); - this.setState({ thread }); + 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() { @@ -122,7 +162,7 @@ export class Thread extends React.Component { } renderReplies(): any { - return this.state.thread!.replies.map((reply, index) => { + return this.state.replies.map((reply, index) => { const replyDark = index % 2 === 0 ? 'reply--dark' : ''; const bluePost = reply.user.permissions === 'admin' ? 'blue-post' : ''; return ( @@ -133,7 +173,7 @@ export class Thread extends React.Component {
- {`${index + 1}. `}{index > 0 && 'Re: '}{this.state.thread!.title} + {`${reply.index! + 1}. `}{index > 0 && 'Re: '}{this.state.thread!.title} | {this.getTimeFormat(reply.inserted_at)}
@@ -160,21 +200,33 @@ export class Thread extends React.Component { }); } + renderPagingBg() { + return ( +
+ this.navigateHere(page)} + showArrows={true} + /> +
+ ); + } + render() { - if (!this.state.thread) { + const { editingReply, thread, replies, showEditor, quotedReply } = this.state; + + if (!thread) { return
; } - const replies = get(this.state, 'thread.replies'); - return ( - {this.state.showEditor && + {showEditor && this.onEditorClose(cancel)} - quotedReply={this.state.quotedReply} - editingReply={this.state.editingReply} + quotedReply={quotedReply} + editingReply={editingReply} /> }
@@ -182,7 +234,7 @@ export class Thread extends React.Component {
Topic: - | {this.getTimeFormat(this.state.thread!.inserted_at)} + | {this.getTimeFormat(thread!.inserted_at)}
{ />
-
+ {this.renderPagingBg()}
{replies && this.renderReplies()}
-
+ {this.renderPagingBg()} +
this.navigateForumIndex()}