{uri}
@@ -51,7 +71,18 @@ class ChannelPage extends React.PureComponent {
{__("Published Content")}
{contentList}
-
+
+ {(!fetching || (claimsInChannel && claimsInChannel.length)) &&
+ totalPages > 1 &&
+
this.changePage(e.selected + 1)}
+ initialPage={parseInt(page - 1)}
+ containerClassName="pagination"
+ />}
+
);
}
}
diff --git a/ui/js/page/showPage/index.js b/ui/js/page/showPage/index.js
index cd9677169..6306e5e33 100644
--- a/ui/js/page/showPage/index.js
+++ b/ui/js/page/showPage/index.js
@@ -10,8 +10,8 @@ const makeSelect = () => {
selectIsResolving = makeSelectIsResolvingForUri();
const select = (state, props) => ({
- claim: selectClaim(state, props),
- isResolvingUri: selectIsResolving(state, props),
+ claim: selectClaim(state, props.params),
+ isResolvingUri: selectIsResolving(state, props.params),
});
return select;
diff --git a/ui/js/page/showPage/view.jsx b/ui/js/page/showPage/view.jsx
index 687cb5498..67bbf6178 100644
--- a/ui/js/page/showPage/view.jsx
+++ b/ui/js/page/showPage/view.jsx
@@ -6,13 +6,15 @@ import FilePage from "page/filePage";
class ShowPage extends React.PureComponent {
componentWillMount() {
- const { isResolvingUri, resolveUri, uri } = this.props;
+ const { isResolvingUri, resolveUri, params } = this.props;
+ const { uri } = params;
if (!isResolvingUri) resolveUri(uri);
}
componentWillReceiveProps(nextProps) {
- const { isResolvingUri, resolveUri, claim, uri } = nextProps;
+ const { isResolvingUri, resolveUri, claim, params } = nextProps;
+ const { uri } = params;
if (!isResolvingUri && claim === undefined && uri) {
resolveUri(uri);
@@ -20,7 +22,8 @@ class ShowPage extends React.PureComponent {
}
render() {
- const { claim, uri, isResolvingUri } = this.props;
+ const { claim, params, isResolvingUri } = this.props;
+ const { uri } = params;
let innerContent = "";
diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js
index 9e072f1ce..c70fd45e0 100644
--- a/ui/js/reducers/claims.js
+++ b/ui/js/reducers/claims.js
@@ -101,17 +101,44 @@ reducers[types.FETCH_CHANNEL_LIST_MINE_COMPLETED] = function(state, action) {
});
};
-reducers[types.FETCH_CHANNEL_CLAIMS_COMPLETED] = function(state, action) {
- const { uri, claims } = action.data;
+reducers[types.FETCH_CHANNEL_CLAIMS_STARTED] = function(state, action) {
+ const { uri, page } = action.data;
+ const fetchingChannelClaims = Object.assign({}, state.fetchingChannelClaims);
- const newClaims = Object.assign({}, state.claimsByChannel);
-
- if (claims !== undefined) {
- newClaims[uri] = claims;
- }
+ fetchingChannelClaims[uri] = page;
return Object.assign({}, state, {
- claimsByChannel: newClaims,
+ fetchingChannelClaims,
+ });
+};
+
+reducers[types.FETCH_CHANNEL_CLAIMS_COMPLETED] = function(state, action) {
+ const { uri, claims, page } = action.data;
+
+ const claimsByChannel = Object.assign({}, state.claimsByChannel);
+ const byChannel = Object.assign({}, claimsByChannel[uri]);
+ const allClaimIds = new Set(byChannel["all"]);
+ const currentPageClaimIds = [];
+ const byId = Object.assign({}, state.byId);
+ const fetchingChannelClaims = Object.assign({}, state.fetchingChannelClaims);
+
+ if (claims !== undefined) {
+ claims.forEach(claim => {
+ allClaimIds.add(claim.claim_id);
+ currentPageClaimIds.push(claim.claim_id);
+ byId[claim.claim_id] = claim;
+ });
+ }
+
+ byChannel["all"] = allClaimIds;
+ byChannel[page] = currentPageClaimIds;
+ claimsByChannel[uri] = byChannel;
+ delete fetchingChannelClaims[uri];
+
+ return Object.assign({}, state, {
+ claimsByChannel,
+ byId,
+ fetchingChannelClaims,
});
};
diff --git a/ui/js/reducers/content.js b/ui/js/reducers/content.js
index f346e2d27..0e1d71fed 100644
--- a/ui/js/reducers/content.js
+++ b/ui/js/reducers/content.js
@@ -47,6 +47,17 @@ reducers[types.RESOLVE_URI_CANCELED] = reducers[
});
};
+reducers[types.FETCH_CHANNEL_CLAIMS_COMPLETED] = function(state, action) {
+ const channelPages = Object.assign({}, state.channelPages);
+ const { uri, totalPages } = action.data;
+
+ channelPages[uri] = totalPages;
+
+ return Object.assign({}, state, {
+ channelPages,
+ });
+};
+
export default function reducer(state = defaultState, action) {
const handler = reducers[action.type];
if (handler) return handler(state, action);
diff --git a/ui/js/selectors/app.js b/ui/js/selectors/app.js
index 3951a8216..a67dc9f37 100644
--- a/ui/js/selectors/app.js
+++ b/ui/js/selectors/app.js
@@ -1,5 +1,5 @@
import { createSelector } from "reselect";
-import { parseQueryParams } from "util/query_params";
+import { parseQueryParams, toQueryString } from "util/query_params";
import lbry from "lbry";
import lbryuri from "lbryuri";
@@ -55,8 +55,14 @@ export const selectPageTitle = createSelector(
return params.query
? __("Search results for %s", params.query)
: __("Search");
- case "show":
- return lbryuri.normalize(params.uri);
+ case "show": {
+ const parts = [lbryuri.normalize(params.uri)];
+ // If the params has any keys other than "uri"
+ if (Object.keys(params).length > 1) {
+ parts.push(toQueryString(Object.assign({}, params, { uri: null })));
+ }
+ return parts.join("?");
+ }
case "downloaded":
return __("Downloads & Purchases");
case "published":
diff --git a/ui/js/selectors/claims.js b/ui/js/selectors/claims.js
index 3c10ec931..2c4b4b511 100644
--- a/ui/js/selectors/claims.js
+++ b/ui/js/selectors/claims.js
@@ -1,4 +1,5 @@
import { createSelector } from "reselect";
+import { selectCurrentParams } from "selectors/app";
import lbryuri from "lbryuri";
const _selectState = state => state.claims || {};
@@ -60,14 +61,59 @@ export const makeSelectClaimForUriIsMine = () => {
return createSelector(selectClaimForUriIsMine, isMine => isMine);
};
+export const selectAllFetchingChannelClaims = createSelector(
+ _selectState,
+ state => state.fetchingChannelClaims || {}
+);
+
+const selectFetchingChannelClaims = (state, props) => {
+ const allFetchingChannelClaims = selectAllFetchingChannelClaims(state);
+
+ return allFetchingChannelClaims[props.uri];
+};
+
+export const makeSelectFetchingChannelClaims = (state, props) => {
+ return createSelector(selectFetchingChannelClaims, fetching => fetching);
+};
+
export const selectClaimsInChannelForUri = (state, props) => {
- return selectAllClaimsByChannel(state)[props.uri];
+ const byId = selectClaimsById(state);
+ const byChannel = selectAllClaimsByChannel(state)[props.uri] || {};
+ const claimIds = byChannel["all"];
+
+ if (!claimIds) return claimIds;
+
+ const claims = [];
+
+ claimIds.forEach(claimId => claims.push(byId[claimId]));
+
+ return claims;
};
export const makeSelectClaimsInChannelForUri = () => {
return createSelector(selectClaimsInChannelForUri, claims => claims);
};
+export const selectClaimsInChannelForCurrentPage = (state, props) => {
+ const byId = selectClaimsById(state);
+ const byChannel = selectAllClaimsByChannel(state)[props.uri] || {};
+ const params = selectCurrentParams(state);
+ const page = params && params.page ? params.page : 1;
+ const claimIds = byChannel[page];
+
+ if (!claimIds) return claimIds;
+
+ const claims = [];
+
+ claimIds.forEach(claimId => claims.push(byId[claimId]));
+
+ return claims;
+};
+
+export const makeSelectClaimsInChannelForCurrentPage = () => {
+ return createSelector(selectClaimsInChannelForCurrentPage, claims => claims);
+};
+
const selectMetadataForUri = (state, props) => {
const claim = selectClaimForUri(state, props);
const metadata =
diff --git a/ui/js/selectors/content.js b/ui/js/selectors/content.js
index 75162a454..663aab145 100644
--- a/ui/js/selectors/content.js
+++ b/ui/js/selectors/content.js
@@ -24,3 +24,16 @@ const selectResolvingUri = (state, props) => {
export const makeSelectIsResolvingForUri = () => {
return createSelector(selectResolvingUri, resolving => resolving);
};
+
+export const selectChannelPages = createSelector(
+ _selectState,
+ state => state.channelPages || {}
+);
+
+const selectTotalPagesForChannel = (state, props) => {
+ return selectChannelPages(state)[props.uri];
+};
+
+export const makeSelectTotalPagesForChannel = () => {
+ return createSelector(selectTotalPagesForChannel, totalPages => totalPages);
+};
diff --git a/ui/package.json b/ui/package.json
index fd9137ba5..5d447d6a4 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -31,6 +31,7 @@
"react-dom": "^15.4.0",
"react-markdown": "^2.5.0",
"react-modal": "^1.5.2",
+ "react-paginate": "^4.4.3",
"react-redux": "^5.0.3",
"react-simplemde-editor": "^3.6.11",
"redux": "^3.6.0",
@@ -54,8 +55,8 @@
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.18.0",
- "electron-rebuild": "^1.5.11",
"css-loader": "^0.28.4",
+ "electron-rebuild": "^1.5.11",
"eslint": "^3.10.2",
"eslint-config-airbnb": "^13.0.0",
"eslint-loader": "^1.6.1",
diff --git a/ui/scss/all.scss b/ui/scss/all.scss
index 61612d7df..d899566ab 100644
--- a/ui/scss/all.scss
+++ b/ui/scss/all.scss
@@ -17,6 +17,7 @@
@import "component/_modal.scss";
@import "component/_snack-bar.scss";
@import "component/_video.scss";
+@import "component/_pagination.scss";
@import "page/_developer.scss";
@import "page/_reward.scss";
@import "page/_show.scss";
diff --git a/ui/scss/component/_pagination.scss b/ui/scss/component/_pagination.scss
new file mode 100644
index 000000000..b16076f76
--- /dev/null
+++ b/ui/scss/component/_pagination.scss
@@ -0,0 +1,18 @@
+ul.pagination {
+ display: inline-block;
+ padding: 0;
+ margin: 0;
+}
+
+ul.pagination li {
+ display: inline;
+ float: left;
+ padding: 8px 16px;
+}
+
+ul.pagination li:not(.selected) {
+ background: white;
+ a {
+ cursor: hand;
+ }
+}
diff --git a/ui/yarn.lock b/ui/yarn.lock
index cb2ca85fb..5d5848976 100644
--- a/ui/yarn.lock
+++ b/ui/yarn.lock
@@ -1204,6 +1204,10 @@ clap@^1.0.9:
dependencies:
chalk "^1.1.3"
+classnames@^2.2.5:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
+
cli-cursor@^1.0.1, cli-cursor@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
@@ -2329,6 +2333,14 @@ faye-websocket@~0.11.0:
dependencies:
websocket-driver ">=0.5.1"
+fbjs@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.2.1.tgz#622061630a43e11f845017b9044aaa648ed3f731"
+ dependencies:
+ core-js "^1.0.0"
+ promise "^7.0.3"
+ whatwg-fetch "^0.9.0"
+
fbjs@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.6.1.tgz#9636b7705f5ba9684d44b72f78321254afc860f7"
@@ -2339,7 +2351,7 @@ fbjs@^0.6.1:
ua-parser-js "^0.7.9"
whatwg-fetch "^0.9.0"
-fbjs@^0.8.9:
+fbjs@^0.8.4, fbjs@^0.8.9:
version "0.8.12"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
dependencies:
@@ -4771,10 +4783,26 @@ rc@^1.1.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
+react-addons-create-fragment@^0.14.7:
+ version "0.14.8"
+ resolved "https://registry.yarnpkg.com/react-addons-create-fragment/-/react-addons-create-fragment-0.14.8.tgz#e83240d1cba49249690fcc6f148710baa11d2b7a"
+
+react-addons-create-fragment@^15.0.0:
+ version "15.6.0"
+ resolved "https://registry.yarnpkg.com/react-addons-create-fragment/-/react-addons-create-fragment-15.6.0.tgz#af91a22b1fb095dd01f1afba43bfd0ef589d8b20"
+ dependencies:
+ fbjs "^0.8.4"
+ loose-envify "^1.3.1"
+ object-assign "^4.1.0"
+
react-dom-factories@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/react-dom-factories/-/react-dom-factories-1.0.0.tgz#f43c05e5051b304f33251618d5bc859b29e46b6d"
+react-dom@^0.14.7:
+ version "0.14.9"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-0.14.9.tgz#05064a3dcf0fb1880a3b2bfc9d58c55d8d9f6293"
+
react-dom@^15.4.0:
version "15.6.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.6.1.tgz#2cb0ed4191038e53c209eb3a79a23e2a4cf99470"
@@ -4804,6 +4832,15 @@ react-modal@^1.5.2:
prop-types "^15.5.7"
react-dom-factories "^1.0.0"
+react-paginate@^4.4.3:
+ version "4.4.3"
+ resolved "https://registry.yarnpkg.com/react-paginate/-/react-paginate-4.4.3.tgz#11817ece628fa59c54a2df7968c854ed64b99077"
+ dependencies:
+ classnames "^2.2.5"
+ prop-types "^15.5.7"
+ react "^15.0.0"
+ react-addons-create-fragment "^15.0.0"
+
react-redux@^5.0.3:
version "5.0.5"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.5.tgz#f8e8c7b239422576e52d6b7db06439469be9846a"
@@ -4823,14 +4860,20 @@ react-simplemde-editor@^3.6.11:
react "^0.14.2"
simplemde "^1.11.2"
-react@^0.14.2:
+react-tap-event-plugin@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/react-tap-event-plugin/-/react-tap-event-plugin-0.2.2.tgz#4f6f257851654f6c2b1c213a1d3ff21b353ae4e1"
+ dependencies:
+ fbjs "^0.2.1"
+
+react@^0.14.2, react@^0.14.7:
version "0.14.9"
resolved "https://registry.yarnpkg.com/react/-/react-0.14.9.tgz#9110a6497c49d44ba1c0edd317aec29c2e0d91d1"
dependencies:
envify "^3.0.0"
fbjs "^0.6.1"
-react@^15.4.0:
+react@^15.0.0, react@^15.4.0:
version "15.6.1"
resolved "https://registry.yarnpkg.com/react/-/react-15.6.1.tgz#baa8434ec6780bde997cdc380b79cd33b96393df"
dependencies:
--
2.45.2
From 16c2eb94791043e406fa1863d79eff74c1d2fd5c Mon Sep 17 00:00:00 2001
From: Jeremy Kauffman