From 09d7b3b6bebc23eedd23102344bd3f6e4353da9f Mon Sep 17 00:00:00 2001 From: joshslee Date: Thu, 3 Sep 2020 16:08:51 -0700 Subject: [PATCH 1/5] userContributions load more (pending backend pagination) --- components/Author/Tabs/UserContributions.js | 111 ++++++++++++++++++-- redux/author/index.js | 39 +++++-- 2 files changed, 129 insertions(+), 21 deletions(-) diff --git a/components/Author/Tabs/UserContributions.js b/components/Author/Tabs/UserContributions.js index c8d112b15c..40beaa8852 100644 --- a/components/Author/Tabs/UserContributions.js +++ b/components/Author/Tabs/UserContributions.js @@ -1,11 +1,15 @@ import { StyleSheet, css } from "aphrodite"; import { connect } from "react-redux"; import ReactPlaceholder from "react-placeholder"; +import Ripples from "react-ripples"; // Components import ComponentWrapper from "~/components/ComponentWrapper"; import PaperEntryCard from "~/components/Hubs/PaperEntryCard"; -import { Reply, Comment } from "~/components/DiscussionComment"; +import { Reply } from "~/components/DiscussionComment"; + +// Redux +import { AuthorActions } from "~/redux/author"; // Config import colors from "~/config/themes/colors"; @@ -15,14 +19,19 @@ class UserContributionsTab extends React.Component { constructor(props) { super(props); this.state = { - contributions: [], + contributions: + this.props.author.userContributions && + this.props.author.userContributions.contributions + ? this.props.author.userContributions.contributions + : [], + fetching: false, }; } componentDidMount() { let { author } = this.props; this.setState({ - contributions: author.userContributions.contributions, + // contributions: author.userContributions.contributions, }); } @@ -40,9 +49,43 @@ class UserContributionsTab extends React.Component { let contributions = [...this.state.contributions]; contributions[index] = paper; - this.setState({ - contributions, - }); + this.setState({ contributions }); + }; + + loadMore = () => { + const next = this.props.author.userContributions.next; + this.props.getUserContributions({ next }); + }; + + renderLoadMoreButton = () => { + let { author } = this.props; + let { fetching } = this.state; + + if (author && author.userContributions) { + let { next } = author.userContributions; + + if (next !== null) { + return ( +
+ {!fetching ? ( + + Load More + + ) : ( + + )} +
+ ); + } + } }; render() { @@ -51,17 +94,25 @@ class UserContributionsTab extends React.Component {
{contribution.type === "paper" ? ( ) : contribution.type === "comment" ? (
- +
) : (
- +
)}
@@ -75,7 +126,10 @@ class UserContributionsTab extends React.Component { customPlaceholder={} > {contributions.length > 0 ? ( -
{contributions}
+
+ {contributions} + {this.renderLoadMoreButton()} +
) : (
@@ -125,10 +179,47 @@ var styles = StyleSheet.create({ height: 50, marginBottom: 10, }, + buttonContainer: { + width: "100%", + display: "flex", + justifyContent: "center", + alignItems: "center", + marginTop: 25, + height: 45, + "@media only screen and (max-width: 768px)": { + marginTop: 15, + marginBottom: 15, + }, + }, + loadMoreButton: { + fontSize: 14, + border: `1px solid ${colors.BLUE()}`, + boxSizing: "border-box", + borderRadius: 4, + height: 45, + width: 155, + display: "flex", + justifyContent: "center", + alignItems: "center", + color: colors.BLUE(), + cursor: "pointer", + userSelect: "none", + ":hover": { + color: "#FFF", + backgroundColor: colors.BLUE(), + }, + }, }); const mapStateToProps = (state) => ({ author: state.author, }); -export default connect(mapStateToProps)(UserContributionsTab); +const mapDispatchToProps = { + getUserContributions: AuthorActions.getUserContributions, +}; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(UserContributionsTab); diff --git a/redux/author/index.js b/redux/author/index.js index d08e3650bf..36e74fb5b7 100644 --- a/redux/author/index.js +++ b/redux/author/index.js @@ -84,26 +84,34 @@ export const AuthorActions = { commentOffset = 0, replyOffset = 0, paperUploadOffset = 0, + next = null, }) => { - return async (dispatch) => { + return async (dispatch, getState) => { dispatch({ contributionsDoneFetching: false, type: types.GET_USER_CONTRIBUTIONS_PENDING, }); - const response = await fetch( - API.USER_CONTRIBUTION({ - authorId, - commentOffset, - replyOffset, - paperUploadOffset, - }), - API.GET_CONFIG() - ).catch(utils.handleCatch); + + let ENDPOINT = next + ? next + : API.USER_CONTRIBUTION({ + authorId, + commentOffset, + replyOffset, + paperUploadOffset, + }); + + const response = await fetch(ENDPOINT, API.GET_CONFIG()).catch( + utils.handleCatch + ); let action = actions.getUserContributionsFailure(); if (response.ok) { const body = await response.json(); - let contributions = []; + + let contributions = next + ? [...getState().author.userContributions.contributions] + : []; for (let i = 0; i < body.results.length; i++) { let contribution = body.results[i]; if (contribution.type === "reply") { @@ -135,6 +143,15 @@ export const AuthorActions = { }; }, + getNextUserContributions: ({ authorId }) => { + return async (dispatch) => { + dispatch({ + contributionsDoneFetching: false, + type: types.GET_USER_CONTRIBUTIONS_PENDING, + }); + }; + }, + saveAuthorChanges: ({ changes, authorId, file }) => { return (dispatch) => { let config = API.PATCH_CONFIG(changes); From 681a57bde2d288934da8c7c0dbeefbb2d9011abb Mon Sep 17 00:00:00 2001 From: joshslee Date: Thu, 3 Sep 2020 17:18:22 -0700 Subject: [PATCH 2/5] tabbed content should exist in DOM before switching to it --- components/Author/Tabs/UserDiscussions.js | 9 ++-- components/Hubs/PaperEntryCard.js | 1 - components/TabBar.js | 40 +++++++++++--- pages/user/[authorId]/[tabName]/index.js | 65 +++++++++++++++++------ 4 files changed, 86 insertions(+), 29 deletions(-) diff --git a/components/Author/Tabs/UserDiscussions.js b/components/Author/Tabs/UserDiscussions.js index 9b235d677b..0a51177f49 100644 --- a/components/Author/Tabs/UserDiscussions.js +++ b/components/Author/Tabs/UserDiscussions.js @@ -31,7 +31,7 @@ class UserDiscussionsTab extends React.Component { this.setState({ fetching: true }, () => { fetch(userDiscussions.next, API.GET_CONFIG()) - .then((res) => Helpers.checkStatus(res, this.props.dispatch)) + .then(Helpers.checkStatus) .then(Helpers.parseJSON) .then((res) => { let newState = { ...userDiscussions }; @@ -194,10 +194,9 @@ const mapStateToProps = (state) => ({ author: state.author, }); -const mapDispatchToProps = (dispatch) => ({ - updateAuthorByKey: () => dispatch(AuthorActions.updateAuthorByKey), - dispatch, -}); +const mapDispatchToProps = { + updateAuthorByKey: AuthorActions.updateAuthorByKey, +}; export default connect( mapStateToProps, diff --git a/components/Hubs/PaperEntryCard.js b/components/Hubs/PaperEntryCard.js index 0ff61759c2..069492cdbb 100644 --- a/components/Hubs/PaperEntryCard.js +++ b/components/Hubs/PaperEntryCard.js @@ -11,7 +11,6 @@ import "~/components/Paper/CitationCard.css"; // Components import VoteWidget from "../VoteWidget"; -import AuthorAvatar from "~/components/AuthorAvatar"; import HubTag from "./HubTag"; import HubDropDown from "./HubDropDown"; diff --git a/components/TabBar.js b/components/TabBar.js index 9907f4f703..d5c0b40054 100644 --- a/components/TabBar.js +++ b/components/TabBar.js @@ -2,13 +2,14 @@ import Link from "next/link"; import { StyleSheet, css } from "aphrodite"; import colors, { paperTabColors } from "~/config/themes/colors"; import { paperTabFont } from "~/config/themes/fonts"; +import Loader from "~/components/Loader/Loader"; // Components import ComponentWrapper from "./ComponentWrapper"; const TabBar = (props) => { const selectedTab = props.selectedTab; - const { dynamic_href } = props; + const { dynamic_href, fetching } = props; const tabs = props.tabs.map(formatTabs); return ( @@ -22,7 +23,7 @@ const TabBar = (props) => { return null; } } - return renderTab(tab, selectedTab, dynamic_href); + return renderTab(tab, selectedTab, dynamic_href, props.fetching); })}
@@ -38,7 +39,8 @@ function formatTabs(tab) { function renderTab( { key, href, label, showCount, count }, selected, - dynamic_href + dynamic_href, + fetching ) { let isSelected = false; let classNames = [styles.tab]; @@ -52,7 +54,9 @@ function renderTab(
{label}{" "} - {showCount && } + {showCount && ( + + )}
@@ -60,14 +64,29 @@ function renderTab( } const Count = (props) => { - const { amount, isSelected } = props; + const { amount, isSelected, fetching } = props; // if (amount < 1) { // return ; // } + return ( - - {amount > 0 ? amount : 0} + + {fetching ? ( + + ) : amount > 0 ? ( + amount + ) : ( + 0 + )} ); @@ -134,6 +153,13 @@ const styles = StyleSheet.create({ borderBottom: "solid 3px", borderColor: colors.PURPLE(1), }, + loaderContainer: { + padding: 0, + width: "unset", + }, + loaderStyle: { + display: "unset", + }, }); export default TabBar; diff --git a/pages/user/[authorId]/[tabName]/index.js b/pages/user/[authorId]/[tabName]/index.js index c58fb36064..93ab2d9973 100644 --- a/pages/user/[authorId]/[tabName]/index.js +++ b/pages/user/[authorId]/[tabName]/index.js @@ -35,6 +35,7 @@ const AuthorPage = (props) => { let { tabName } = router.query; const dispatch = useDispatch(); const store = useStore(); + const [fetching, setFetching] = useState(true); const [openShareModal, setOpenShareModal] = useState(false); const [hoverName, setHoverName] = useState(false); const [hoverDescription, setHoverDescription] = useState(false); @@ -119,6 +120,7 @@ const AuthorPage = (props) => { paperUploadOffset, }) ); + setFetching(false); } function fetchUserTransactions() { @@ -246,20 +248,44 @@ const AuthorPage = (props) => { ]; let renderTabContent = () => { - switch (tabName) { - case "contributions": - return ; - case "authored-papers": - return ; - case "discussions": - return ; - case "citations": - return null; - case "transactions": - return ; - case "boosts": - return ; - } + return ( + // render all tab content on the dom, but only show if selected +
+ + + + + + + + + + + + + + + +
+ ); }; let renderEditButton = (action) => { @@ -703,6 +729,7 @@ const AuthorPage = (props) => { dynamic_href={"/user/[authorId]/[tabName]"} author={author} user={user} + fetching={fetching} />
{renderTabContent()}
({ From f23da7e557f0a1082958db4d236c330807d66bc5 Mon Sep 17 00:00:00 2001 From: joshslee Date: Fri, 4 Sep 2020 16:39:07 -0700 Subject: [PATCH 3/5] connect loading & pagination to backend feature --- components/Author/Tabs/UserContributions.js | 45 ++++++++------------- components/Author/Tabs/UserDiscussions.js | 4 +- components/Author/Tabs/UserTransactions.js | 2 +- components/DiscussionComment.js | 6 ++- config/api.js | 11 +---- pages/user/[authorId]/[tabName]/index.js | 17 +++----- redux/author/index.js | 21 ++++------ 7 files changed, 40 insertions(+), 66 deletions(-) diff --git a/components/Author/Tabs/UserContributions.js b/components/Author/Tabs/UserContributions.js index 40beaa8852..b6274ebf32 100644 --- a/components/Author/Tabs/UserContributions.js +++ b/components/Author/Tabs/UserContributions.js @@ -6,7 +6,7 @@ import Ripples from "react-ripples"; // Components import ComponentWrapper from "~/components/ComponentWrapper"; import PaperEntryCard from "~/components/Hubs/PaperEntryCard"; -import { Reply } from "~/components/DiscussionComment"; +import Loader from "~/components/Loader/Loader"; // Redux import { AuthorActions } from "~/redux/author"; @@ -53,13 +53,15 @@ class UserContributionsTab extends React.Component { }; loadMore = () => { - const next = this.props.author.userContributions.next; - this.props.getUserContributions({ next }); + this.setState({ fetching: true }, async () => { + const next = this.props.author.userContributions.next; + await this.props.getUserContributions({ next }); + setTimeout(() => this.setState({ fetching: false }), 400); + }); }; renderLoadMoreButton = () => { let { author } = this.props; - let { fetching } = this.state; if (author && author.userContributions) { let { next } = author.userContributions; @@ -67,7 +69,7 @@ class UserContributionsTab extends React.Component { if (next !== null) { return (
- {!fetching ? ( + {!this.state.fetching ? ( { return (
- {contribution.type === "paper" ? ( - - ) : contribution.type === "comment" ? ( -
- -
- ) : ( -
- -
- )} +
); }); return ( } > diff --git a/components/Author/Tabs/UserDiscussions.js b/components/Author/Tabs/UserDiscussions.js index 0a51177f49..7465c9e36d 100644 --- a/components/Author/Tabs/UserDiscussions.js +++ b/components/Author/Tabs/UserDiscussions.js @@ -100,7 +100,9 @@ class UserDiscussionsTab extends React.Component { return ( } > diff --git a/components/Author/Tabs/UserTransactions.js b/components/Author/Tabs/UserTransactions.js index 8226046396..71ddf74bea 100644 --- a/components/Author/Tabs/UserTransactions.js +++ b/components/Author/Tabs/UserTransactions.js @@ -76,7 +76,7 @@ class UserTransaction extends React.Component { return ( } > diff --git a/components/DiscussionComment.js b/components/DiscussionComment.js index f769f1d26d..538d163eeb 100644 --- a/components/DiscussionComment.js +++ b/components/DiscussionComment.js @@ -58,7 +58,11 @@ class DiscussionComment extends React.Component { } createdByCurrentUser = () => { - return this.state.createdBy.id === this.props.currentUser.id; + if (this.state.createdBy) { + if (this.props.currentUser) { + return this.state.createdBy.id === this.props.currentUser.id; + } + } }; setReadOnly = (readOnly) => { diff --git a/config/api.js b/config/api.js index 0c764a2ae0..1d64c87449 100644 --- a/config/api.js +++ b/config/api.js @@ -183,15 +183,8 @@ const routes = (BASE_URL) => { return url; }, - USER_CONTRIBUTION: ({ - authorId, - commentOffset, - replyOffset, - paperUploadOffset, - }) => { - let url = - BASE_URL + - `author/${authorId}/get_user_contributions/?commentOffset=${commentOffset}&replyOffset=${replyOffset}&paperUploadOffset=${paperUploadOffset}`; + USER_CONTRIBUTION: ({ authorId }) => { + let url = BASE_URL + `author/${authorId}/get_user_contributions/`; return url; }, diff --git a/pages/user/[authorId]/[tabName]/index.js b/pages/user/[authorId]/[tabName]/index.js index 93ab2d9973..6e590299f1 100644 --- a/pages/user/[authorId]/[tabName]/index.js +++ b/pages/user/[authorId]/[tabName]/index.js @@ -107,17 +107,9 @@ const AuthorPage = (props) => { if (!author.user) { return; } - let { - commentOffset, - replyOffset, - paperUploadOffset, - } = props.author.userContributions; await dispatch( AuthorActions.getUserContributions({ authorId: router.query.authorId, - commentOffset, - replyOffset, - paperUploadOffset, }) ); setFetching(false); @@ -152,6 +144,7 @@ const AuthorPage = (props) => { } useEffect(() => { + setFetching(true); async function refetchAuthor() { await dispatch( AuthorActions.getAuthor({ authorId: router.query.authorId }) @@ -256,28 +249,28 @@ const AuthorPage = (props) => { tabName === "contributions" ? styles.reveal : styles.hidden )} > - + - + - + - + { + getUserContributions: ({ authorId, next = null }) => { return async (dispatch, getState) => { dispatch({ contributionsDoneFetching: false, @@ -96,9 +90,6 @@ export const AuthorActions = { ? next : API.USER_CONTRIBUTION({ authorId, - commentOffset, - replyOffset, - paperUploadOffset, }); const response = await fetch(ENDPOINT, API.GET_CONFIG()).catch( @@ -116,15 +107,19 @@ export const AuthorActions = { let contribution = body.results[i]; if (contribution.type === "reply") { let formatted = discussionShim.transformReply(body.results[i]); - formatted.type = contribution.type; + // formatted.type = contribution.type; contributions.push(formatted); } else if (contribution.type === "comment") { let formatted = discussionShim.transformComment(body.results[i]); - formatted.type = contribution.type; + // formatted.type = contribution.type; contributions.push(formatted); } else if (contribution.type === "paper") { let formatted = paperShim.paper(body.results[i]); - formatted.type = contribution.type; + // formatted.type = contribution.type; + contributions.push(formatted); + } else { + let formatted = paperShim.paper(body.results[i]); + // formatted.type = contribution.type; contributions.push(formatted); } } From 8b006adb966350dd5e5b493e6a15a72970332be2 Mon Sep 17 00:00:00 2001 From: joshslee Date: Fri, 4 Sep 2020 16:58:45 -0700 Subject: [PATCH 4/5] convert divs to appropriating heading tags --- components/Hubs/HubPage.js | 4 ++-- components/Paper/Tabs/DiscussionTab.js | 4 ++-- components/Paper/Tabs/LimitationTab.js | 2 +- components/Paper/Tabs/PaperTab.js | 2 +- components/Paper/Tabs/SummaryTab.js | 4 ++-- components/PaperPageCard.js | 12 ++++++++---- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/components/Hubs/HubPage.js b/components/Hubs/HubPage.js index 24e79db9f5..28fa449cb4 100644 --- a/components/Hubs/HubPage.js +++ b/components/Hubs/HubPage.js @@ -644,14 +644,14 @@ class HubPage extends React.Component { )} id={"topbar"} > -
+

{this.getTitle()} {this.props.home ? "ResearchHub" : this.props.hub.name} -

+
{ ref={discussionRef} >
-
+

Comments {fetching ? ( @@ -452,7 +452,7 @@ const DiscussionTab = (props) => { Tweets

-
+ {!showEditor && !showTwitterComments && renderAddDiscussion()}
diff --git a/components/Paper/Tabs/LimitationTab.js b/components/Paper/Tabs/LimitationTab.js index cd2e377e96..c10a9b3c53 100644 --- a/components/Paper/Tabs/LimitationTab.js +++ b/components/Paper/Tabs/LimitationTab.js @@ -255,7 +255,7 @@ class LimitationTab extends React.Component { return (
-
Limitations
+

Limitations

{this.renderDropdown()}
diff --git a/components/Paper/Tabs/PaperTab.js b/components/Paper/Tabs/PaperTab.js index a283c1dd03..ab902e5610 100644 --- a/components/Paper/Tabs/PaperTab.js +++ b/components/Paper/Tabs/PaperTab.js @@ -267,7 +267,7 @@ function PaperTab(props) {
-
Paper PDF
+

Paper PDF

{file && renderDownloadPdf()}
{file && isModerator && ( diff --git a/components/Paper/Tabs/SummaryTab.js b/components/Paper/Tabs/SummaryTab.js index b6299f6a20..8953607967 100644 --- a/components/Paper/Tabs/SummaryTab.js +++ b/components/Paper/Tabs/SummaryTab.js @@ -465,10 +465,10 @@ class SummaryTab extends React.Component { {this.state.readOnly ? (
-
+

Description {this.renderTabs()} -

+
{/*
-
+

{paper && paper.title} -

+ {paper.paper_title && paper.paper_title !== paper.title ? ( -
+

{`From Paper: ${paper.paper_title}`} -

+ ) : null}
@@ -933,6 +933,9 @@ const styles = StyleSheet.create({ fontSize: 30, position: "relative", wordBreak: "break-word", + fontWeight: "unset", + padding: 0, + margin: 0, "@media only screen and (max-width: 760px)": { fontSize: 28, }, @@ -951,6 +954,7 @@ const styles = StyleSheet.create({ opacity: 0.5, fontSize: 16, marginTop: 10, + fontWeight: "unset", "@media only screen and (max-width: 415px)": { fontSize: 14, }, From 299077f228db9e7fa6c9d5e435faff1b09d50894 Mon Sep 17 00:00:00 2001 From: joshslee Date: Fri, 4 Sep 2020 17:28:25 -0700 Subject: [PATCH 5/5] revert padding/margin from heading styles --- components/Hubs/HubPage.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/Hubs/HubPage.js b/components/Hubs/HubPage.js index 28fa449cb4..a897f247e0 100644 --- a/components/Hubs/HubPage.js +++ b/components/Hubs/HubPage.js @@ -968,6 +968,8 @@ var styles = StyleSheet.create({ whiteSpace: "pre-wrap", width: "100%", textAlign: "center", + padding: 0, + margin: 0, "@media only screen and (min-width: 800px)": { textAlign: "left", paddingRight: 16,