Fix bugs in history navigation in stack ordering and loss of scrolling
and refactor history
This commit is contained in:
parent
7e23b62c7b
commit
339945018d
44 changed files with 399 additions and 450 deletions
|
@ -5,18 +5,10 @@ import {
|
|||
selectUpgradeDownloadPath,
|
||||
selectUpgradeDownloadItem,
|
||||
selectUpgradeFilename,
|
||||
selectPageTitle,
|
||||
selectCurrentPage,
|
||||
selectCurrentParams,
|
||||
selectHistoryBack,
|
||||
selectHistoryForward,
|
||||
} from "selectors/app";
|
||||
import { doSearch } from "actions/search";
|
||||
import { doFetchDaemonSettings } from "actions/settings";
|
||||
import { doAuthenticate } from "actions/user";
|
||||
import { doFileList } from "actions/file_info";
|
||||
import { toQueryString } from "util/query_params";
|
||||
import { parseQueryParams } from "util/query_params";
|
||||
|
||||
const { remote, ipcRenderer, shell } = require("electron");
|
||||
const path = require("path");
|
||||
|
@ -24,130 +16,6 @@ const { download } = remote.require("electron-dl");
|
|||
const fs = remote.require("fs");
|
||||
const { lbrySettings: config } = require("../../../app/package.json");
|
||||
|
||||
export function doNavigate(path, params = {}, options = {}) {
|
||||
return function(dispatch, getState) {
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
|
||||
let url = path;
|
||||
if (params) url = `${url}?${toQueryString(params)}`;
|
||||
|
||||
dispatch(doChangePath(url));
|
||||
|
||||
const state = getState();
|
||||
const pageTitle = selectPageTitle(state);
|
||||
const historyState = history.state;
|
||||
|
||||
dispatch(
|
||||
doHistoryPush({ params, page: historyState.page + 1 }, pageTitle, url)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export function doAuthNavigate(pathAfterAuth = null, params = {}) {
|
||||
return function(dispatch, getState) {
|
||||
if (pathAfterAuth) {
|
||||
dispatch({
|
||||
type: types.CHANGE_AFTER_AUTH_PATH,
|
||||
data: {
|
||||
path: `${pathAfterAuth}?${toQueryString(params)}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
dispatch(doNavigate("/auth"));
|
||||
};
|
||||
}
|
||||
|
||||
export function doChangePath(path, options = {}) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch({
|
||||
type: types.CHANGE_PATH,
|
||||
data: {
|
||||
path,
|
||||
},
|
||||
});
|
||||
|
||||
const state = getState();
|
||||
const pageTitle = selectPageTitle(state);
|
||||
const scrollY = options.scrollY;
|
||||
|
||||
window.document.title = pageTitle;
|
||||
|
||||
if (scrollY) window.scrollTo(0, scrollY);
|
||||
else window.scrollTo(0, 0);
|
||||
|
||||
const currentPage = selectCurrentPage(state);
|
||||
if (currentPage === "search") {
|
||||
const params = selectCurrentParams(state);
|
||||
dispatch(doSearch(params.query));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function doHistoryBack() {
|
||||
return function(dispatch, getState) {
|
||||
// Get back history from stack
|
||||
const back = selectHistoryBack(getState());
|
||||
|
||||
if (back) {
|
||||
// Set location
|
||||
dispatch(doChangePath(back.location));
|
||||
|
||||
dispatch({
|
||||
type: types.HISTORY_NAVIGATE,
|
||||
data: { page: back },
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function doHistoryForward() {
|
||||
return function(dispatch, getState) {
|
||||
// Get forward history from stack
|
||||
const forward = selectHistoryForward(getState());
|
||||
|
||||
if (forward) {
|
||||
// Set location
|
||||
dispatch(doChangePath(forward.location));
|
||||
|
||||
dispatch({
|
||||
type: types.HISTORY_NAVIGATE,
|
||||
data: { page: forward },
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function doHistoryPush(currentState, title, relativeUrl) {
|
||||
return function(dispatch, getState) {
|
||||
title += " - LBRY";
|
||||
history.pushState(currentState, title, `#${relativeUrl}`);
|
||||
dispatch({
|
||||
type: types.HISTORY_NAVIGATE,
|
||||
data: {
|
||||
location: relativeUrl,
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doRecordScroll(scroll) {
|
||||
return function(dispatch, getState) {
|
||||
const state = getState();
|
||||
const historyState = history.state;
|
||||
|
||||
if (!historyState) return;
|
||||
|
||||
historyState.scrollY = scroll;
|
||||
history.replaceState(
|
||||
historyState,
|
||||
document.title,
|
||||
`#${state.app.currentPath}`
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export function doOpenModal(modal) {
|
||||
return {
|
||||
type: types.OPEN_MODAL,
|
||||
|
@ -305,25 +173,8 @@ export function doAlertError(errorList) {
|
|||
|
||||
export function doDaemonReady() {
|
||||
return function(dispatch, getState) {
|
||||
const path = window.location.hash || "#/discover";
|
||||
const params = parseQueryParams(path.split("?")[1] || "");
|
||||
|
||||
// Get first page
|
||||
const page = {
|
||||
index: 0,
|
||||
location: path.replace(/^#/, ""),
|
||||
};
|
||||
|
||||
history.replaceState(
|
||||
{ params, is_first_page: true, page: 1 },
|
||||
document.title,
|
||||
`${path}`
|
||||
);
|
||||
dispatch(doAuthenticate());
|
||||
dispatch({
|
||||
type: types.DAEMON_READY,
|
||||
data: { page },
|
||||
});
|
||||
dispatch({ type: types.DAEMON_READY });
|
||||
dispatch(doFetchDaemonSettings());
|
||||
dispatch(doFileList());
|
||||
};
|
||||
|
|
|
@ -12,7 +12,8 @@ import {
|
|||
selectUrisLoading,
|
||||
selectTotalDownloadProgress,
|
||||
} from "selectors/file_info";
|
||||
import { doCloseModal, doHistoryBack } from "actions/app";
|
||||
import { doCloseModal } from "actions/app";
|
||||
import { doHistoryBack } from "actions/navigation";
|
||||
import setProgressBar from "util/setProgressBar";
|
||||
import batchActions from "util/batchActions";
|
||||
|
||||
|
|
104
ui/js/actions/navigation.js
Normal file
104
ui/js/actions/navigation.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
import * as types from "constants/action_types";
|
||||
import {
|
||||
selectPageTitle,
|
||||
selectCurrentPage,
|
||||
selectCurrentParams,
|
||||
selectHistoryStack,
|
||||
selectHistoryIndex,
|
||||
} from "selectors/navigation";
|
||||
import { doSearch } from "actions/search";
|
||||
import { toQueryString } from "util/query_params";
|
||||
|
||||
export function doNavigate(path, params = {}, options = {}) {
|
||||
return function(dispatch, getState) {
|
||||
if (!path) {
|
||||
return;
|
||||
}
|
||||
|
||||
let url = path;
|
||||
if (params && Object.values(params).length) {
|
||||
url += "?" + toQueryString(params);
|
||||
}
|
||||
|
||||
dispatch(doChangePath(url, options));
|
||||
|
||||
const pageTitle = selectPageTitle(getState()) + " - LBRY";
|
||||
|
||||
dispatch({
|
||||
type: types.HISTORY_NAVIGATE,
|
||||
data: { url, index: options.index },
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doAuthNavigate(pathAfterAuth = null, params = {}) {
|
||||
return function(dispatch, getState) {
|
||||
if (pathAfterAuth) {
|
||||
dispatch({
|
||||
type: types.CHANGE_AFTER_AUTH_PATH,
|
||||
data: {
|
||||
path: `${pathAfterAuth}?${toQueryString(params)}`,
|
||||
},
|
||||
});
|
||||
}
|
||||
dispatch(doNavigate("/auth"));
|
||||
};
|
||||
}
|
||||
|
||||
export function doChangePath(path, options = {}) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch({
|
||||
type: types.CHANGE_PATH,
|
||||
data: {
|
||||
path,
|
||||
},
|
||||
});
|
||||
|
||||
const state = getState();
|
||||
const scrollY = options.scrollY;
|
||||
|
||||
//I wasn't seeing it scroll to the proper position without this -- possibly because the page isn't fully rendered? Not sure - Jeremy
|
||||
setTimeout(() => {
|
||||
window.scrollTo(0, scrollY ? scrollY : 0);
|
||||
}, 100);
|
||||
|
||||
const currentPage = selectCurrentPage(state);
|
||||
if (currentPage === "search") {
|
||||
const params = selectCurrentParams(state);
|
||||
dispatch(doSearch(params.query));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function doHistoryTraverse(dispatch, state, modifier) {
|
||||
const stack = selectHistoryStack(state),
|
||||
index = selectHistoryIndex(state) + modifier;
|
||||
|
||||
if (index >= 0 && index < stack.length) {
|
||||
const historyItem = stack[index];
|
||||
return dispatch(
|
||||
doNavigate(historyItem.path, {}, { scrollY: historyItem.scrollY, index })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function doHistoryBack() {
|
||||
return function(dispatch, getState) {
|
||||
return doHistoryTraverse(dispatch, getState(), -1);
|
||||
};
|
||||
}
|
||||
|
||||
export function doHistoryForward() {
|
||||
return function(dispatch, getState) {
|
||||
return doHistoryTraverse(dispatch, getState(), 1);
|
||||
};
|
||||
}
|
||||
|
||||
export function doRecordScroll(scroll) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch({
|
||||
type: types.WINDOW_SCROLLED,
|
||||
data: { scrollY: scroll },
|
||||
});
|
||||
};
|
||||
}
|
|
@ -2,8 +2,8 @@ import * as types from "constants/action_types";
|
|||
import lbryuri from "lbryuri";
|
||||
import lighthouse from "lighthouse";
|
||||
import { doResolveUri } from "actions/content";
|
||||
import { doNavigate, doHistoryPush } from "actions/app";
|
||||
import { selectCurrentPage } from "selectors/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { selectCurrentPage } from "selectors/navigation";
|
||||
import batchActions from "util/batchActions";
|
||||
|
||||
export function doSearch(query) {
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectPageTitle } from "selectors/navigation";
|
||||
import { selectUser } from "selectors/user";
|
||||
import {
|
||||
doCheckUpgradeAvailable,
|
||||
doAlertError,
|
||||
doRecordScroll,
|
||||
} from "actions/app";
|
||||
import { doRecordScroll } from "actions/navigation";
|
||||
import { doFetchRewardedContent } from "actions/content";
|
||||
import { doUpdateBalance } from "actions/wallet";
|
||||
import { selectUser } from "selectors/user";
|
||||
import App from "./view";
|
||||
|
||||
const select = (state, props) => ({
|
||||
pageTitle: selectPageTitle(state),
|
||||
user: selectUser(state),
|
||||
});
|
||||
|
||||
|
|
|
@ -30,12 +30,22 @@ class App extends React.PureComponent {
|
|||
this.scrollListener = () => this.props.recordScroll(window.scrollY);
|
||||
|
||||
window.addEventListener("scroll", this.scrollListener);
|
||||
|
||||
this.setTitleFromProps(this.props);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener("scroll", this.scrollListener);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props) {
|
||||
this.setTitleFromProps(props);
|
||||
}
|
||||
|
||||
setTitleFromProps(props) {
|
||||
window.document.title = props.pageTitle;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div id="window">
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectPlatform } from "selectors/app";
|
||||
import { selectPlatform, selectCurrentModal } from "selectors/app";
|
||||
import {
|
||||
makeSelectFileInfoForUri,
|
||||
makeSelectDownloadingForUri,
|
||||
makeSelectLoadingForUri,
|
||||
} from "selectors/file_info";
|
||||
import { makeSelectIsAvailableForUri } from "selectors/availability";
|
||||
import { selectCurrentModal } from "selectors/app";
|
||||
import { makeSelectCostInfoForUri } from "selectors/cost_info";
|
||||
import { doCloseModal, doOpenModal } from "actions/app";
|
||||
import { doFetchAvailability } from "actions/availability";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { doResolveUri } from "actions/content";
|
||||
import { selectShowNsfw } from "selectors/settings";
|
||||
import {
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
selectCurrentSearchResults,
|
||||
selectSearchQuery,
|
||||
} from "selectors/search";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import FileListSearch from "./view";
|
||||
|
||||
const select = state => ({
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { doResolveUri } from "actions/content";
|
||||
import {
|
||||
makeSelectClaimForUri,
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
import React from "react";
|
||||
import { formatCredits } from "util/formatCredits";
|
||||
import { connect } from "react-redux";
|
||||
import { selectIsBackDisabled, selectIsForwardDisabled } from "selectors/app";
|
||||
import {
|
||||
selectIsBackDisabled,
|
||||
selectIsForwardDisabled,
|
||||
} from "selectors/navigation";
|
||||
import { selectBalance } from "selectors/wallet";
|
||||
import { doNavigate, doHistoryBack, doHistoryForward } from "actions/app";
|
||||
import {
|
||||
doNavigate,
|
||||
doHistoryBack,
|
||||
doHistoryForward,
|
||||
} from "actions/navigation";
|
||||
import Header from "./view";
|
||||
|
||||
const select = state => ({
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import NsfwOverlay from "./view";
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
makeSelectRewardByType,
|
||||
makeSelectIsRewardClaimPending,
|
||||
} from "selectors/rewards";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { doClaimRewardType, doClaimRewardClearError } from "actions/rewards";
|
||||
import RewardLink from "./view";
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import Router from "./view.jsx";
|
||||
import { selectCurrentPage, selectCurrentParams } from "selectors/app.js";
|
||||
import {
|
||||
selectCurrentPage,
|
||||
selectCurrentParams,
|
||||
} from "selectors/navigation.js";
|
||||
|
||||
const select = state => ({
|
||||
params: selectCurrentParams(state),
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate, doRemoveSnackBarSnack } from "actions/app";
|
||||
import { doRemoveSnackBarSnack } from "actions/app";
|
||||
import { selectSnackBarSnacks } from "selectors/app";
|
||||
import SnackBar from "./view";
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
removeSnack: () => dispatch(doRemoveSnackBarSnack()),
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ class SnackBar extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { navigate, snacks, removeSnack } = this.props;
|
||||
const { snacks, removeSnack } = this.props;
|
||||
|
||||
if (!snacks.length) {
|
||||
this._hideTimeout = null; //should be unmounting anyway, but be safe?
|
||||
|
@ -33,7 +33,7 @@ class SnackBar extends React.PureComponent {
|
|||
{linkText &&
|
||||
linkTarget &&
|
||||
<Link
|
||||
onClick={() => navigate(linkTarget)}
|
||||
navigate={linkTarget}
|
||||
className="snack-bar__action"
|
||||
label={linkText}
|
||||
/>}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectCurrentPage, selectHeaderLinks } from "selectors/app";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { selectCurrentPage, selectHeaderLinks } from "selectors/navigation";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import SubHeader from "./view";
|
||||
|
||||
const select = (state, props) => ({
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { doUserIdentityVerify } from "actions/user";
|
||||
import rewards from "rewards";
|
||||
import { makeSelectRewardByType } from "selectors/rewards";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doCloseModal } from "actions/app";
|
||||
import { doNavigate, doChangeVolume } from "actions/app";
|
||||
import { doChangeVolume } from "actions/app";
|
||||
import { selectCurrentModal, selectVolume } from "selectors/app";
|
||||
import { doPurchaseUri, doLoadVideo } from "actions/content";
|
||||
import {
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from "react";
|
|||
import { connect } from "react-redux";
|
||||
import lbryuri from "lbryuri.js";
|
||||
import { selectWunderBarAddress, selectWunderBarIcon } from "selectors/search";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import Wunderbar from "./view";
|
||||
|
||||
const select = state => ({
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
export const CHANGE_PATH = "CHANGE_PATH";
|
||||
export const OPEN_MODAL = "OPEN_MODAL";
|
||||
export const CLOSE_MODAL = "CLOSE_MODAL";
|
||||
export const HISTORY_NAVIGATE = "HISTORY_NAVIGATE";
|
||||
export const SHOW_SNACKBAR = "SHOW_SNACKBAR";
|
||||
export const REMOVE_SNACKBAR_SNACK = "REMOVE_SNACKBAR_SNACK";
|
||||
export const WINDOW_FOCUSED = "WINDOW_FOCUSED";
|
||||
export const CHANGE_AFTER_AUTH_PATH = "CHANGE_AFTER_AUTH_PATH";
|
||||
export const DAEMON_READY = "DAEMON_READY";
|
||||
export const DAEMON_VERSION_MATCH = "DAEMON_VERSION_MATCH";
|
||||
export const DAEMON_VERSION_MISMATCH = "DAEMON_VERSION_MISMATCH";
|
||||
export const VOLUME_CHANGED = "VOLUME_CHANGED";
|
||||
|
||||
// Navigation
|
||||
export const CHANGE_PATH = "CHANGE_PATH";
|
||||
export const CHANGE_AFTER_AUTH_PATH = "CHANGE_AFTER_AUTH_PATH";
|
||||
export const WINDOW_SCROLLED = "WINDOW_SCROLLED";
|
||||
export const HISTORY_NAVIGATE = "HISTORY_NAVIGATE";
|
||||
|
||||
// Upgrades
|
||||
export const UPGRADE_CANCELLED = "UPGRADE_CANCELLED";
|
||||
export const DOWNLOAD_UPGRADE = "DOWNLOAD_UPGRADE";
|
||||
|
|
|
@ -6,9 +6,9 @@ import SnackBar from "component/snackBar";
|
|||
import { Provider } from "react-redux";
|
||||
import store from "store.js";
|
||||
import SplashScreen from "component/splash";
|
||||
import { doChangePath, doNavigate, doDaemonReady } from "actions/app";
|
||||
import { doDaemonReady } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { doDownloadLanguages } from "actions/settings";
|
||||
import { toQueryString } from "util/query_params";
|
||||
import * as types from "constants/action_types";
|
||||
|
||||
const env = ENV;
|
||||
|
@ -28,23 +28,6 @@ window.addEventListener("contextmenu", event => {
|
|||
event.preventDefault();
|
||||
});
|
||||
|
||||
window.addEventListener("popstate", (event, param) => {
|
||||
event.preventDefault();
|
||||
|
||||
const hash = document.location.hash;
|
||||
let action;
|
||||
|
||||
if (hash !== "") {
|
||||
const url = hash.replace(/^#/, "");
|
||||
const { params, scrollY } = event.state || {};
|
||||
const queryString = toQueryString(params);
|
||||
|
||||
app.store.dispatch(doChangePath(`${url}?${queryString}`, { scrollY }));
|
||||
} else {
|
||||
app.store.dispatch(doChangePath("/discover"));
|
||||
}
|
||||
});
|
||||
|
||||
ipcRenderer.on("open-uri-requested", (event, uri) => {
|
||||
if (uri && uri.startsWith("lbry://")) {
|
||||
app.store.dispatch(doNavigate("/show", { uri }));
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doCloseModal, doAuthNavigate } from "actions/app";
|
||||
import { doCloseModal } from "actions/app";
|
||||
import { doAuthNavigate } from "actions/navigation";
|
||||
import { doSetClientSetting } from "actions/settings";
|
||||
import { selectUserIsRewardApproved } from "selectors/user";
|
||||
import { selectBalance } from "selectors/wallet";
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doCloseModal, doNavigate } from "actions/app";
|
||||
import { doCloseModal } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import ModalInsufficientCredits from "./view";
|
||||
|
||||
const select = state => ({});
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doCloseModal, doHistoryBack } from "actions/app";
|
||||
import { doCloseModal } from "actions/app";
|
||||
import { doDeleteFileAndGoBack } from "actions/file_info";
|
||||
import { makeSelectClaimForUriIsMine } from "selectors/claims";
|
||||
import batchActions from "util/batchActions";
|
||||
|
||||
import ModalRemoveFile from "./view";
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectCurrentModal, selectCurrentPage } from "selectors/app";
|
||||
import { doOpenModal } from "actions/app";
|
||||
import * as settings from "constants/settings";
|
||||
import { selectCurrentModal } from "selectors/app";
|
||||
import { selectCurrentPage } from "selectors/navigation";
|
||||
import { selectCostForCurrentPageUri } from "selectors/cost_info";
|
||||
import { makeSelectClientSetting } from "selectors/settings";
|
||||
import { selectUser } from "selectors/user";
|
||||
import { selectCostForCurrentPageUri } from "selectors/cost_info";
|
||||
import * as settings from "constants/settings";
|
||||
import { selectBalance } from "selectors/wallet";
|
||||
import ModalRouter from "./view";
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { connect } from "react-redux";
|
||||
import { selectPathAfterAuth } from "selectors/app";
|
||||
import { selectPathAfterAuth } from "selectors/navigation";
|
||||
import {
|
||||
selectAuthenticationIsPending,
|
||||
selectEmailToVerify,
|
||||
|
|
|
@ -9,8 +9,8 @@ import {
|
|||
makeSelectClaimsInChannelForCurrentPage,
|
||||
makeSelectFetchingChannelClaims,
|
||||
} from "selectors/claims";
|
||||
import { selectCurrentParams } from "selectors/app";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { selectCurrentParams } from "selectors/navigation";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { makeSelectTotalPagesForChannel } from "selectors/content";
|
||||
import ChannelPage from "./view";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { doFetchFileInfo } from "actions/file_info";
|
||||
import { makeSelectFileInfoForUri } from "selectors/file_info";
|
||||
import { selectRewardContentClaimIds } from "selectors/content";
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
selectIsFetchingClaimListMine,
|
||||
} from "selectors/claims";
|
||||
import { doFetchClaimListMine } from "actions/content";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { doCancelAllResolvingUris } from "actions/content";
|
||||
import FileListDownloaded from "./view";
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
selectIsFetchingClaimListMine,
|
||||
} from "selectors/claims";
|
||||
import { doClaimRewardType } from "actions/rewards";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { doCancelAllResolvingUris } from "actions/content";
|
||||
import FileListPublished from "./view";
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { doAuthNavigate } from "actions/app";
|
||||
import { doAuthNavigate } from "actions/navigation";
|
||||
import { connect } from "react-redux";
|
||||
import { doFetchAccessToken } from "actions/user";
|
||||
import { selectAccessToken, selectUser } from "selectors/user";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate, doHistoryBack } from "actions/app";
|
||||
import { doNavigate, doHistoryBack } from "actions/navigation";
|
||||
import { doClaimRewardType } from "actions/rewards";
|
||||
import {
|
||||
selectMyClaims,
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
selectUnclaimedRewards,
|
||||
} from "selectors/rewards";
|
||||
import { selectUser } from "selectors/user";
|
||||
import { doAuthNavigate, doNavigate } from "actions/app";
|
||||
import { doAuthNavigate, doNavigate } from "actions/navigation";
|
||||
import { doRewardList } from "actions/rewards";
|
||||
import RewardsPage from "./view";
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
selectSearchQuery,
|
||||
selectCurrentSearchResults,
|
||||
} from "selectors/search";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import SearchPage from "./view";
|
||||
|
||||
const select = state => ({
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
import * as types from "constants/action_types";
|
||||
import * as modalTypes from "constants/modal_types";
|
||||
|
||||
const currentPath = () => {
|
||||
const hash = document.location.hash;
|
||||
if (hash !== "") return hash.replace(/^#/, "");
|
||||
else return "/discover";
|
||||
};
|
||||
|
||||
const { remote } = require("electron");
|
||||
const application = remote.app;
|
||||
const win = remote.BrowserWindow.getFocusedWindow();
|
||||
|
@ -14,28 +8,18 @@ const win = remote.BrowserWindow.getFocusedWindow();
|
|||
const reducers = {};
|
||||
const defaultState = {
|
||||
isLoaded: false,
|
||||
isBackDisabled: true,
|
||||
isForwardDisabled: true,
|
||||
currentPath: currentPath(),
|
||||
pathAfterAuth: "/discover",
|
||||
platform: process.platform,
|
||||
upgradeSkipped: sessionStorage.getItem("upgradeSkipped"),
|
||||
daemonVersionMatched: null,
|
||||
daemonReady: false,
|
||||
hasSignature: false,
|
||||
badgeNumber: 0,
|
||||
history: { index: 0, stack: [] },
|
||||
volume: sessionStorage.getItem("volume") || 1,
|
||||
};
|
||||
|
||||
reducers[types.DAEMON_READY] = function(state, action) {
|
||||
const { history } = state;
|
||||
const { page } = action.data;
|
||||
history.stack.push(page);
|
||||
|
||||
return Object.assign({}, state, {
|
||||
daemonReady: true,
|
||||
history,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -52,18 +36,6 @@ reducers[types.DAEMON_VERSION_MISMATCH] = function(state, action) {
|
|||
});
|
||||
};
|
||||
|
||||
reducers[types.CHANGE_PATH] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
currentPath: action.data.path,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.CHANGE_AFTER_AUTH_PATH] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
pathAfterAuth: action.data.path,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.UPGRADE_CANCELLED] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
downloadProgress: null,
|
||||
|
@ -171,55 +143,6 @@ reducers[types.WINDOW_FOCUSED] = function(state, action) {
|
|||
});
|
||||
};
|
||||
|
||||
reducers[types.HISTORY_NAVIGATE] = (state, action) => {
|
||||
let page = false;
|
||||
let location = false;
|
||||
|
||||
// Get history from state
|
||||
const { history } = state;
|
||||
|
||||
if (action.data.page) {
|
||||
// Get page
|
||||
page = action.data.page;
|
||||
} else if (action.data.location) {
|
||||
// Get new location
|
||||
location = action.data.location;
|
||||
}
|
||||
|
||||
// Add new location to stack
|
||||
if (location) {
|
||||
const lastItem = history.stack.length - 1;
|
||||
|
||||
// Check for duplicated
|
||||
let is_duplicate = lastItem > -1
|
||||
? history.stack[lastItem].location === location
|
||||
: false;
|
||||
|
||||
if (!is_duplicate) {
|
||||
// Create new page
|
||||
page = {
|
||||
index: history.stack.length,
|
||||
location,
|
||||
};
|
||||
|
||||
// Update index
|
||||
history.index = history.stack.length;
|
||||
|
||||
// Add to stack
|
||||
history.stack.push(page);
|
||||
}
|
||||
} else if (page) {
|
||||
// Update index
|
||||
history.index = page.index;
|
||||
}
|
||||
|
||||
return Object.assign({}, state, {
|
||||
history,
|
||||
isBackDisabled: history.index === 0, // First page
|
||||
isForwardDisabled: history.index === history.stack.length - 1, // Last page
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.VOLUME_CHANGED] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
volume: action.data.volume,
|
||||
|
|
85
ui/js/reducers/navigation.js
Normal file
85
ui/js/reducers/navigation.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
import * as types from "constants/action_types";
|
||||
import { parseQueryParams } from "util/query_params";
|
||||
|
||||
const currentPath = () => {
|
||||
const hash = document.location.hash;
|
||||
if (hash !== "") return hash.replace(/^#/, "");
|
||||
else return "/discover";
|
||||
};
|
||||
|
||||
const reducers = {};
|
||||
const defaultState = {
|
||||
currentPath: currentPath(),
|
||||
pathAfterAuth: "/discover",
|
||||
index: 0,
|
||||
stack: [],
|
||||
};
|
||||
|
||||
reducers[types.DAEMON_READY] = function(state, action) {
|
||||
const { currentPath } = state;
|
||||
const params = parseQueryParams(currentPath.split("?")[1] || "");
|
||||
|
||||
return Object.assign({}, state, {
|
||||
stack: [{ path: currentPath, scrollY: 0 }],
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.CHANGE_PATH] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
currentPath: action.data.path,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.CHANGE_AFTER_AUTH_PATH] = function(state, action) {
|
||||
return Object.assign({}, state, {
|
||||
pathAfterAuth: action.data.path,
|
||||
});
|
||||
};
|
||||
|
||||
reducers[types.HISTORY_NAVIGATE] = (state, action) => {
|
||||
const { stack, index } = state;
|
||||
|
||||
let newState = {};
|
||||
|
||||
const path = action.data.url,
|
||||
previousIndex = index - 1;
|
||||
|
||||
// Check for duplicated
|
||||
if (action.data.index >= 0) {
|
||||
newState.index = action.data.index;
|
||||
} else if (
|
||||
previousIndex === -1 ||
|
||||
!stack[previousIndex] ||
|
||||
stack[previousIndex].path !== path
|
||||
) {
|
||||
newState.stack = [...stack.slice(0, index + 1), { path, scrollY: 0 }];
|
||||
newState.index = newState.stack.length - 1;
|
||||
}
|
||||
|
||||
history.replaceState(null, null, "#" + path); //this allows currentPath() to retain the URL on reload
|
||||
|
||||
return Object.assign({}, state, newState);
|
||||
};
|
||||
|
||||
reducers[types.WINDOW_SCROLLED] = (state, action) => {
|
||||
const { stack, index } = state;
|
||||
const { scrollY } = action.data;
|
||||
|
||||
return Object.assign({}, state, {
|
||||
stack: state.stack.map((stackItem, itemIndex) => {
|
||||
if (itemIndex !== index) {
|
||||
return stackItem;
|
||||
}
|
||||
return {
|
||||
...stackItem,
|
||||
scrollY: scrollY,
|
||||
};
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
export default function reducer(state = defaultState, action) {
|
||||
const handler = reducers[action.type];
|
||||
if (handler) return handler(state, action);
|
||||
return state;
|
||||
}
|
|
@ -1,88 +1,7 @@
|
|||
import { createSelector } from "reselect";
|
||||
import { parseQueryParams, toQueryString } from "util/query_params";
|
||||
import * as settings from "constants/settings.js";
|
||||
import lbryuri from "lbryuri";
|
||||
|
||||
export const _selectState = state => state.app || {};
|
||||
|
||||
export const selectIsLoaded = createSelector(
|
||||
_selectState,
|
||||
state => state.isLoaded
|
||||
);
|
||||
|
||||
export const selectCurrentPath = createSelector(
|
||||
_selectState,
|
||||
state => state.currentPath
|
||||
);
|
||||
|
||||
export const selectCurrentPage = createSelector(selectCurrentPath, path => {
|
||||
return path.replace(/^\//, "").split("?")[0];
|
||||
});
|
||||
|
||||
export const selectCurrentParams = createSelector(selectCurrentPath, path => {
|
||||
if (path === undefined) return {};
|
||||
if (!path.match(/\?/)) return {};
|
||||
|
||||
return parseQueryParams(path.split("?")[1]);
|
||||
});
|
||||
|
||||
export const selectPageTitle = createSelector(
|
||||
selectCurrentPage,
|
||||
selectCurrentParams,
|
||||
(page, params) => {
|
||||
switch (page) {
|
||||
case "settings":
|
||||
return __("Settings");
|
||||
case "report":
|
||||
return __("Report");
|
||||
case "wallet":
|
||||
return __("Wallet");
|
||||
case "send":
|
||||
return __("Send Credits");
|
||||
case "receive":
|
||||
return __("Wallet Address");
|
||||
case "backup":
|
||||
return __("Backup Your Wallet");
|
||||
case "rewards":
|
||||
return __("Rewards");
|
||||
case "invite":
|
||||
return __("Invites");
|
||||
case "start":
|
||||
return __("Start");
|
||||
case "publish":
|
||||
return __("Publish");
|
||||
case "help":
|
||||
return __("Help");
|
||||
case "developer":
|
||||
return __("Developer");
|
||||
case "search":
|
||||
return params.query
|
||||
? __("Search results for %s", params.query)
|
||||
: __("Search");
|
||||
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":
|
||||
return __("Publishes");
|
||||
case "discover":
|
||||
return __("Home");
|
||||
case false:
|
||||
case null:
|
||||
case "":
|
||||
return "";
|
||||
default:
|
||||
return page[0].toUpperCase() + (page.length > 0 ? page.substr(1) : "");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const selectPlatform = createSelector(
|
||||
_selectState,
|
||||
state => state.platform
|
||||
|
@ -137,41 +56,6 @@ export const selectDownloadComplete = createSelector(
|
|||
state => state.upgradeDownloadCompleted
|
||||
);
|
||||
|
||||
export const selectHeaderLinks = createSelector(selectCurrentPage, page => {
|
||||
// This contains intentional fall throughs
|
||||
switch (page) {
|
||||
case "wallet":
|
||||
case "history":
|
||||
case "send":
|
||||
case "receive":
|
||||
case "invite":
|
||||
case "rewards":
|
||||
case "backup":
|
||||
return {
|
||||
wallet: __("Overview"),
|
||||
history: __("History"),
|
||||
send: __("Send"),
|
||||
receive: __("Receive"),
|
||||
rewards: __("Rewards"),
|
||||
invite: __("Invites"),
|
||||
};
|
||||
case "downloaded":
|
||||
case "published":
|
||||
return {
|
||||
downloaded: __("Downloaded"),
|
||||
published: __("Published"),
|
||||
};
|
||||
case "settings":
|
||||
case "help":
|
||||
return {
|
||||
settings: __("Settings"),
|
||||
help: __("Help"),
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
export const selectUpgradeSkipped = createSelector(
|
||||
_selectState,
|
||||
state => state.upgradeSkipped
|
||||
|
@ -222,41 +106,4 @@ export const selectCurrentLanguage = createSelector(
|
|||
() => app.i18n.getLocale() || "en"
|
||||
);
|
||||
|
||||
export const selectPathAfterAuth = createSelector(
|
||||
_selectState,
|
||||
state => state.pathAfterAuth
|
||||
);
|
||||
|
||||
export const selectIsBackDisabled = createSelector(
|
||||
_selectState,
|
||||
state => state.isBackDisabled
|
||||
);
|
||||
|
||||
export const selectIsForwardDisabled = createSelector(
|
||||
_selectState,
|
||||
state => state.isForwardDisabled
|
||||
);
|
||||
|
||||
export const selectHistoryBack = createSelector(_selectState, state => {
|
||||
const { history } = state;
|
||||
const index = history.index - 1;
|
||||
|
||||
// Check if page exists
|
||||
if (index > -1) {
|
||||
// Get back history
|
||||
return history.stack[index];
|
||||
}
|
||||
});
|
||||
|
||||
export const selectHistoryForward = createSelector(_selectState, state => {
|
||||
const { history } = state;
|
||||
const index = history.index + 1;
|
||||
|
||||
// Check if page exists
|
||||
if (index <= history.stack.length) {
|
||||
// Get forward history
|
||||
return history.stack[index];
|
||||
}
|
||||
});
|
||||
|
||||
export const selectVolume = createSelector(_selectState, state => state.volume);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { createSelector } from "reselect";
|
||||
import { selectCurrentParams } from "selectors/app";
|
||||
import { selectCurrentParams } from "selectors/navigation";
|
||||
import lbryuri from "lbryuri";
|
||||
|
||||
const _selectState = state => state.claims || {};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { createSelector } from "reselect";
|
||||
import { selectCurrentParams } from "./app";
|
||||
import { selectCurrentParams } from "selectors/navigation";
|
||||
|
||||
export const _selectState = state => state.costInfo || {};
|
||||
|
||||
|
|
129
ui/js/selectors/navigation.js
Normal file
129
ui/js/selectors/navigation.js
Normal file
|
@ -0,0 +1,129 @@
|
|||
import { createSelector } from "reselect";
|
||||
import { parseQueryParams, toQueryString } from "util/query_params";
|
||||
import * as settings from "constants/settings.js";
|
||||
import lbryuri from "lbryuri";
|
||||
|
||||
export const _selectState = state => state.navigation || {};
|
||||
|
||||
export const selectCurrentPath = createSelector(
|
||||
_selectState,
|
||||
state => state.currentPath
|
||||
);
|
||||
|
||||
export const selectCurrentPage = createSelector(selectCurrentPath, path => {
|
||||
return path.replace(/^\//, "").split("?")[0];
|
||||
});
|
||||
|
||||
export const selectCurrentParams = createSelector(selectCurrentPath, path => {
|
||||
if (path === undefined) return {};
|
||||
if (!path.match(/\?/)) return {};
|
||||
|
||||
return parseQueryParams(path.split("?")[1]);
|
||||
});
|
||||
|
||||
export const selectHeaderLinks = createSelector(selectCurrentPage, page => {
|
||||
// This contains intentional fall throughs
|
||||
switch (page) {
|
||||
case "wallet":
|
||||
case "send":
|
||||
case "receive":
|
||||
case "rewards":
|
||||
case "backup":
|
||||
return {
|
||||
wallet: __("Overview"),
|
||||
send: __("Send"),
|
||||
receive: __("Receive"),
|
||||
rewards: __("Rewards"),
|
||||
};
|
||||
case "downloaded":
|
||||
case "published":
|
||||
return {
|
||||
downloaded: __("Downloaded"),
|
||||
published: __("Published"),
|
||||
};
|
||||
case "settings":
|
||||
case "help":
|
||||
return {
|
||||
settings: __("Settings"),
|
||||
help: __("Help"),
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
export const selectPageTitle = createSelector(
|
||||
selectCurrentPage,
|
||||
selectCurrentParams,
|
||||
(page, params) => {
|
||||
switch (page) {
|
||||
case "settings":
|
||||
return __("Settings");
|
||||
case "report":
|
||||
return __("Report");
|
||||
case "wallet":
|
||||
return __("Wallet");
|
||||
case "send":
|
||||
return __("Send");
|
||||
case "receive":
|
||||
return __("Receive");
|
||||
case "backup":
|
||||
return __("Backup");
|
||||
case "rewards":
|
||||
return __("Rewards");
|
||||
case "start":
|
||||
return __("Start");
|
||||
case "publish":
|
||||
return __("Publish");
|
||||
case "help":
|
||||
return __("Help");
|
||||
case "developer":
|
||||
return __("Developer");
|
||||
case "search":
|
||||
return params.query
|
||||
? __("Search results for %s", params.query)
|
||||
: __("Search");
|
||||
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":
|
||||
return __("Publishes");
|
||||
case "discover":
|
||||
return __("Home");
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export const selectPathAfterAuth = createSelector(
|
||||
_selectState,
|
||||
state => state.pathAfterAuth
|
||||
);
|
||||
|
||||
export const selectIsBackDisabled = createSelector(
|
||||
_selectState,
|
||||
state => state.index === 0
|
||||
);
|
||||
|
||||
export const selectIsForwardDisabled = createSelector(
|
||||
_selectState,
|
||||
state => state.index === state.stack.length - 1
|
||||
);
|
||||
|
||||
export const selectHistoryIndex = createSelector(
|
||||
_selectState,
|
||||
state => state.index
|
||||
);
|
||||
|
||||
export const selectHistoryStack = createSelector(
|
||||
_selectState,
|
||||
state => state.stack
|
||||
);
|
|
@ -1,5 +1,5 @@
|
|||
import { createSelector } from "reselect";
|
||||
import { selectPageTitle, selectCurrentPage } from "selectors/app";
|
||||
import { selectPageTitle, selectCurrentPage } from "selectors/navigation";
|
||||
|
||||
export const _selectState = state => state.search || {};
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { createSelector } from "reselect";
|
||||
import { selectCurrentPage, selectDaemonReady } from "selectors/app";
|
||||
|
||||
export const _selectState = state => state.wallet || {};
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import claimsReducer from "reducers/claims";
|
|||
import contentReducer from "reducers/content";
|
||||
import costInfoReducer from "reducers/cost_info";
|
||||
import fileInfoReducer from "reducers/file_info";
|
||||
import navigationReducer from "reducers/navigation";
|
||||
import rewardsReducer from "reducers/rewards";
|
||||
import searchReducer from "reducers/search";
|
||||
import settingsReducer from "reducers/settings";
|
||||
|
@ -13,8 +14,8 @@ import walletReducer from "reducers/wallet";
|
|||
import { persistStore, autoRehydrate } from "redux-persist";
|
||||
import createCompressor from "redux-persist-transform-compress";
|
||||
import createFilter from "redux-persist-transform-filter";
|
||||
import { REHYDRATE } from "redux-persist/constants";
|
||||
import createActionBuffer from "redux-action-buffer";
|
||||
//import { REHYDRATE } from "redux-persist/constants";
|
||||
//import createActionBuffer from "redux-action-buffer";
|
||||
|
||||
const localForage = require("localforage");
|
||||
const redux = require("redux");
|
||||
|
@ -55,6 +56,7 @@ function enableBatching(reducer) {
|
|||
|
||||
const reducers = redux.combineReducers({
|
||||
app: appReducer,
|
||||
navigation: navigationReducer,
|
||||
availability: availabilityReducer,
|
||||
claims: claimsReducer,
|
||||
fileInfo: fileInfoReducer,
|
||||
|
|
Loading…
Reference in a new issue