Merge branch 'master' into tipping_button
This commit is contained in:
commit
5b49915ff6
134 changed files with 4719 additions and 1555 deletions
|
@ -1,5 +1,5 @@
|
|||
[bumpversion]
|
||||
current_version = 0.14.3
|
||||
current_version = 0.15.0
|
||||
commit = True
|
||||
tag = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)((?P<release>[a-z]+)(?P<candidate>\d+))?
|
||||
|
|
80
CHANGELOG.md
80
CHANGELOG.md
|
@ -9,40 +9,72 @@ Web UI version numbers should always match the corresponding version of LBRY App
|
|||
## [Unreleased]
|
||||
### Added
|
||||
* Added a tipping button to send LBRY Credits to the publisher
|
||||
* Added a forward button and improved history behavior. Back/forward disable when unusable.
|
||||
* Added a new component, `FormFieldPrice` which is now used in Publish and Settings.
|
||||
* Added wallet backup guide reference.
|
||||
|
||||
*
|
||||
|
||||
### Changed
|
||||
* Updated to daemon [0.15](https://github.com/lbryio/lbry/releases). Most relevant changes for app are improved announcing of content and a fix for the daemon getting stuck running.
|
||||
* Continued to refine first-run process, process for new users, and introducing people to LBRY and LBRY credits.
|
||||
* Changed the default price settings.
|
||||
* When an "Open" button is clicked on a show page, if the file fails to open, the app will try to open the file's folder.
|
||||
* Some form field refactoring as we take baby steps towards form sanity.
|
||||
* Replaced confusing placeholder text from email input.
|
||||
* Refactored modal and settings logic.
|
||||
* Updated several packages and fixed warnings in build process (all but the [fsevents warning](https://github.com/yarnpkg/yarn/issues/3738), which is a rather dramatic debate)
|
||||
*
|
||||
*
|
||||
|
||||
### Fixed
|
||||
* Tiles will no longer be blurry on hover (Windows only bug)
|
||||
* Removed placeholder values from price selection form fields, which was causing confusion that these were real values (#426)
|
||||
* Fixed showing "other currency" help tip in publish form, which was caused due to not "setting" state for price
|
||||
* Public page now properly checks for all required fields are filled
|
||||
* Fixed pagination styling for pages > 5 (#416)
|
||||
* Fixed sizing on squat videos (#419)
|
||||
* Support claims no longer show up on Published page (#384)
|
||||
* Fixed rendering of small prices (#461)
|
||||
* Fixed incorrect URI in Downloads/Published page (#460)
|
||||
* Fixed menu bug (#503)
|
||||
*
|
||||
*
|
||||
|
||||
### Deprecated
|
||||
*
|
||||
*
|
||||
|
||||
### Removed
|
||||
* Removed the label "Max Purchase Price" from settings page. It was redundant.
|
||||
* Unused old files from previous commit(9c3d633)
|
||||
*
|
||||
*
|
||||
|
||||
## [0.15.0] - 2017-08-31
|
||||
|
||||
### Added
|
||||
* Added an Invites area inside of the Wallet. This allows users to invite others and shows the status of all past invites (including all invite data from the past year). Up to one referral reward can now be claimed, but only if both users have passed the humanity test.
|
||||
* Added new summary components for rewards and invites to the Wallet landing page.
|
||||
* Added a forward button and improved history behavior. Back/forward disable when unusable.
|
||||
* Added past history of rewards to the rewards page.
|
||||
* Added wallet backup guide reference.
|
||||
* Added a new widget for setting prices (`FormFieldPrice`), used in Publish and Settings.
|
||||
|
||||
|
||||
### Changed
|
||||
* Updated to daemon [0.15](https://github.com/lbryio/lbry/releases). Most relevant changes for app are improved announcing of content and a fix for the daemon getting stuck running.
|
||||
* Significant refinements to first-run process, process for new users, and introducing people to LBRY and LBRY credits.
|
||||
* Changed Wallet landing page to summarize status of other areas. Refactored wallet and transaction logic.
|
||||
* Added icons to missing page, improved icon and title logic.
|
||||
* Changed the default price settings for priced publishes.
|
||||
* When an "Open" button is clicked on a show page, if the file fails to open, the app will try to open the file's folder.
|
||||
* Updated several packages and fixed warnings in build process (all but the [fsevents warning](https://github.com/yarnpkg/yarn/issues/3738), which is a rather dramatic debate)
|
||||
* Some form field refactoring as we take baby steps towards form sanity.
|
||||
* Replaced confusing placeholder text from email input.
|
||||
* Refactored modal and settings logic.
|
||||
* Refactored history and navigation logic.
|
||||
|
||||
|
||||
### Removed
|
||||
* Removed the label "Max Purchase Price" from settings page. It was redundant.
|
||||
* Unused old files from previous commit(9c3d633)
|
||||
|
||||
|
||||
### Fixed
|
||||
* Tiles will no longer be blurry on hover (Windows only bug)
|
||||
* Removed placeholder values from price selection form fields, which was causing confusion that these were real values (#426)
|
||||
* Fixed showing "other currency" help tip in publish form, which was caused due to not "setting" state for price
|
||||
* Publish page now properly checks for all required fields are filled
|
||||
* Fixed pagination styling for pages > 5 (#416)
|
||||
* Fixed sizing on squat videos (#419)
|
||||
* Support claims no longer show up on Published page (#384)
|
||||
* Fixed rendering of small prices (#461)
|
||||
* Fixed incorrect URI in Downloads/Published page (#460)
|
||||
* Fixed menu bug (#503)
|
||||
* Fixed incorrect URLs on some channel content (#505)
|
||||
* Fixed video sizing for squat videos (#492)
|
||||
* Fixed issues with small prices (#461)
|
||||
* Fixed issues with negative values not being stopped by app on entry (#441)
|
||||
* Fixed source file error when editing existing claim (#467)
|
||||
|
||||
|
||||
|
||||
## [0.14.3] - 2017-08-03
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ let daemonStopRequested = false;
|
|||
let readyToQuit = false;
|
||||
|
||||
// If we receive a URI to open from an external app but there's no window to
|
||||
// send it to, it's cached in this variable.
|
||||
// sendCredits it to, it's cached in this variable.
|
||||
let openUri = null;
|
||||
|
||||
function processRequestedUri(uri) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "LBRY",
|
||||
"version": "0.14.3",
|
||||
"version": "0.15.0",
|
||||
"main": "main.js",
|
||||
"description": "A browser for the LBRY network, a digital marketplace controlled by its users.",
|
||||
"author": {
|
||||
|
|
BIN
ui/dist/font/FontAwesome.otf
vendored
BIN
ui/dist/font/FontAwesome.otf
vendored
Binary file not shown.
BIN
ui/dist/font/fontawesome-webfont.eot
vendored
BIN
ui/dist/font/fontawesome-webfont.eot
vendored
Binary file not shown.
3230
ui/dist/font/fontawesome-webfont.svg
vendored
3230
ui/dist/font/fontawesome-webfont.svg
vendored
File diff suppressed because it is too large
Load diff
Before Width: | Height: | Size: 306 KiB After Width: | Height: | Size: 434 KiB |
BIN
ui/dist/font/fontawesome-webfont.ttf
vendored
BIN
ui/dist/font/fontawesome-webfont.ttf
vendored
Binary file not shown.
BIN
ui/dist/font/fontawesome-webfont.woff
vendored
BIN
ui/dist/font/fontawesome-webfont.woff
vendored
Binary file not shown.
BIN
ui/dist/font/fontawesome-webfont.woff2
vendored
BIN
ui/dist/font/fontawesome-webfont.woff2
vendored
Binary file not shown.
|
@ -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,126 +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) {
|
||||
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,
|
||||
|
@ -301,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());
|
||||
};
|
||||
|
|
|
@ -20,6 +20,8 @@ import * as modals from "constants/modal_types";
|
|||
|
||||
const { ipcRenderer } = require("electron");
|
||||
|
||||
const DOWNLOAD_POLL_INTERVAL = 250;
|
||||
|
||||
export function doResolveUri(uri) {
|
||||
return function(dispatch, getState) {
|
||||
uri = lbryuri.normalize(uri);
|
||||
|
@ -175,7 +177,7 @@ export function doUpdateLoadStatus(uri, outpoint) {
|
|||
// download hasn't started yet
|
||||
setTimeout(() => {
|
||||
dispatch(doUpdateLoadStatus(uri, outpoint));
|
||||
}, 250);
|
||||
}, DOWNLOAD_POLL_INTERVAL);
|
||||
} else if (fileInfo.completed) {
|
||||
// TODO this isn't going to get called if they reload the client before
|
||||
// the download finished
|
||||
|
@ -221,7 +223,7 @@ export function doUpdateLoadStatus(uri, outpoint) {
|
|||
|
||||
setTimeout(() => {
|
||||
dispatch(doUpdateLoadStatus(uri, outpoint));
|
||||
}, 250);
|
||||
}, DOWNLOAD_POLL_INTERVAL);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -303,6 +305,7 @@ export function doLoadVideo(uri) {
|
|||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
dispatch({
|
||||
type: types.LOADING_VIDEO_FAILED,
|
||||
data: { uri },
|
||||
|
|
|
@ -35,7 +35,11 @@ export function doFetchCostInfoForUri(uri) {
|
|||
|
||||
if (isGenerous && claim) {
|
||||
let cost;
|
||||
const fee = claim.value.stream.metadata.fee;
|
||||
const fee = claim.value &&
|
||||
claim.value.stream &&
|
||||
claim.value.stream.metadata
|
||||
? claim.value.stream.metadata.fee
|
||||
: undefined;
|
||||
if (fee === undefined) {
|
||||
resolve({ cost: 0, includesData: true });
|
||||
} else if (fee.currency == "LBC") {
|
||||
|
|
|
@ -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,7 +2,8 @@ import * as types from "constants/action_types";
|
|||
import * as modals from "constants/modal_types";
|
||||
import lbryio from "lbryio";
|
||||
import rewards from "rewards";
|
||||
import { selectRewardsByType } from "selectors/rewards";
|
||||
import { selectUnclaimedRewardsByType } from "selectors/rewards";
|
||||
import { selectUserIsRewardApproved } from "selectors/user";
|
||||
|
||||
export function doRewardList() {
|
||||
return function(dispatch, getState) {
|
||||
|
@ -13,7 +14,7 @@ export function doRewardList() {
|
|||
});
|
||||
|
||||
lbryio
|
||||
.call("reward", "list", {})
|
||||
.call("reward", "list", { multiple_rewards_per_type: true })
|
||||
.then(userRewards => {
|
||||
dispatch({
|
||||
type: types.FETCH_REWARDS_COMPLETED,
|
||||
|
@ -31,22 +32,23 @@ export function doRewardList() {
|
|||
|
||||
export function doClaimRewardType(rewardType) {
|
||||
return function(dispatch, getState) {
|
||||
const rewardsByType = selectRewardsByType(getState()),
|
||||
reward = rewardsByType[rewardType];
|
||||
const state = getState(),
|
||||
rewardsByType = selectUnclaimedRewardsByType(state),
|
||||
reward = rewardsByType[rewardType],
|
||||
userIsRewardApproved = selectUserIsRewardApproved(state);
|
||||
|
||||
if (reward) {
|
||||
dispatch(doClaimReward(reward));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function doClaimReward(reward, saveError = false) {
|
||||
return function(dispatch, getState) {
|
||||
if (reward.transaction_id) {
|
||||
//already claimed, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
if (!userIsRewardApproved) {
|
||||
return dispatch({
|
||||
type: types.OPEN_MODAL,
|
||||
data: { modal: modals.REWARD_APPROVAL_REQUIRED },
|
||||
});
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: types.CLAIM_REWARD_STARTED,
|
||||
data: { reward },
|
||||
|
@ -70,43 +72,34 @@ export function doClaimReward(reward, saveError = false) {
|
|||
const failure = error => {
|
||||
dispatch({
|
||||
type: types.CLAIM_REWARD_FAILURE,
|
||||
data: {
|
||||
reward,
|
||||
error: saveError ? error : null,
|
||||
},
|
||||
data: { reward, error },
|
||||
});
|
||||
};
|
||||
|
||||
rewards.claimReward(reward.reward_type).then(success, failure);
|
||||
rewards.claimReward(rewardType).then(success, failure);
|
||||
};
|
||||
}
|
||||
|
||||
export function doClaimEligiblePurchaseRewards() {
|
||||
return function(dispatch, getState) {
|
||||
if (!lbryio.enabled) {
|
||||
const state = getState(),
|
||||
rewardsByType = selectUnclaimedRewardsByType(state),
|
||||
userIsRewardApproved = selectUserIsRewardApproved(state);
|
||||
|
||||
if (!userIsRewardApproved || !lbryio.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rewardsByType = selectRewardsByType(getState());
|
||||
|
||||
let types = {};
|
||||
|
||||
types[rewards.TYPE_FIRST_STREAM] = false;
|
||||
types[rewards.TYPE_FEATURED_DOWNLOAD] = false;
|
||||
types[rewards.TYPE_MANY_DOWNLOADS] = false;
|
||||
Object.values(rewardsByType).forEach(reward => {
|
||||
if (types[reward.reward_type] === false && reward.transaction_id) {
|
||||
types[reward.reward_type] = true;
|
||||
}
|
||||
});
|
||||
|
||||
let unclaimedType = Object.keys(types).find(type => {
|
||||
return types[type] === false && type !== rewards.TYPE_FEATURED_DOWNLOAD; //handled below
|
||||
});
|
||||
if (unclaimedType) {
|
||||
dispatch(doClaimRewardType(unclaimedType));
|
||||
if (rewardsByType[rewards.TYPE_FIRST_STREAM]) {
|
||||
dispatch(doClaimRewardType(rewards.TYPE_FIRST_STREAM));
|
||||
} else {
|
||||
[
|
||||
rewards.TYPE_MANY_DOWNLOADS,
|
||||
rewards.TYPE_FEATURED_DOWNLOAD,
|
||||
].forEach(type => {
|
||||
dispatch(doClaimRewardType(type));
|
||||
});
|
||||
}
|
||||
dispatch(doClaimRewardType(rewards.TYPE_FEATURED_DOWNLOAD));
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -101,6 +101,9 @@ export function doDownloadLanguage(langFile) {
|
|||
|
||||
export function doDownloadLanguages() {
|
||||
return function(dispatch, getState) {
|
||||
//temporarily disable i18n so I can get a working build out -- Jeremy
|
||||
return;
|
||||
|
||||
if (!fs.existsSync(app.i18n.directory)) {
|
||||
fs.mkdirSync(app.i18n.directory);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as types from "constants/action_types";
|
||||
import * as modals from "constants/modal_types";
|
||||
import lbryio from "lbryio";
|
||||
import { doOpenModal } from "actions/app";
|
||||
import { doOpenModal, doShowSnackBar } from "actions/app";
|
||||
import { doRewardList, doClaimRewardType } from "actions/rewards";
|
||||
import { selectEmailToVerify, selectUser } from "selectors/user";
|
||||
import rewards from "rewards";
|
||||
|
@ -19,6 +19,7 @@ export function doAuthenticate() {
|
|||
data: { user },
|
||||
});
|
||||
dispatch(doRewardList());
|
||||
dispatch(doFetchInviteStatus());
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch(doOpenModal(modals.AUTHENTICATION_FAILURE));
|
||||
|
@ -172,3 +173,62 @@ export function doFetchAccessToken() {
|
|||
lbryio.getAuthToken().then(success);
|
||||
};
|
||||
}
|
||||
|
||||
export function doFetchInviteStatus() {
|
||||
return function(dispatch, getState) {
|
||||
dispatch({
|
||||
type: types.USER_INVITE_STATUS_FETCH_STARTED,
|
||||
});
|
||||
|
||||
lbryio
|
||||
.call("user", "invite_status")
|
||||
.then(status => {
|
||||
dispatch({
|
||||
type: types.USER_INVITE_STATUS_FETCH_SUCCESS,
|
||||
data: {
|
||||
invitesRemaining: status.invites_remaining
|
||||
? status.invites_remaining
|
||||
: 0,
|
||||
invitees: status.invitees,
|
||||
},
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch({
|
||||
type: types.USER_INVITE_STATUS_FETCH_FAILURE,
|
||||
data: { error },
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function doUserInviteNew(email) {
|
||||
return function(dispatch, getState) {
|
||||
dispatch({
|
||||
type: types.USER_INVITE_NEW_STARTED,
|
||||
});
|
||||
|
||||
lbryio
|
||||
.call("user", "invite", { email: email }, "post")
|
||||
.then(invite => {
|
||||
dispatch({
|
||||
type: types.USER_INVITE_NEW_SUCCESS,
|
||||
data: { email },
|
||||
});
|
||||
|
||||
dispatch(
|
||||
doShowSnackBar({
|
||||
message: __("Invite sent to %s", email),
|
||||
})
|
||||
);
|
||||
|
||||
dispatch(doFetchInviteStatus());
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch({
|
||||
type: types.USER_INVITE_NEW_FAILURE,
|
||||
data: { error },
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ const app = {
|
|||
i18n: i18n,
|
||||
logs: logs,
|
||||
log: function(message) {
|
||||
console.log(message);
|
||||
logs.push(message);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,30 +1,21 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectCurrentModal } from "selectors/app";
|
||||
import {
|
||||
doCheckUpgradeAvailable,
|
||||
doOpenModal,
|
||||
doAlertError,
|
||||
doRecordScroll,
|
||||
} from "actions/app";
|
||||
import { doFetchRewardedContent } from "actions/content";
|
||||
|
||||
import { doUpdateBalance } from "actions/wallet";
|
||||
import { selectWelcomeModalAcknowledged } from "selectors/app";
|
||||
import { selectPageTitle } from "selectors/navigation";
|
||||
import { selectUser } from "selectors/user";
|
||||
import { doCheckUpgradeAvailable, doAlertError } from "actions/app";
|
||||
import { doRecordScroll } from "actions/navigation";
|
||||
import { doFetchRewardedContent } from "actions/content";
|
||||
import { doUpdateBalance } from "actions/wallet";
|
||||
import App from "./view";
|
||||
import * as modals from "constants/modal_types";
|
||||
|
||||
const select = (state, props) => ({
|
||||
modal: selectCurrentModal(state),
|
||||
isWelcomeAcknowledged: selectWelcomeModalAcknowledged(state),
|
||||
pageTitle: selectPageTitle(state),
|
||||
user: selectUser(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
alertError: errorList => dispatch(doAlertError(errorList)),
|
||||
checkUpgradeAvailable: () => dispatch(doCheckUpgradeAvailable()),
|
||||
openWelcomeModal: () => dispatch(doOpenModal(modals.WELCOME)),
|
||||
updateBalance: balance => dispatch(doUpdateBalance(balance)),
|
||||
fetchRewardedContent: () => dispatch(doFetchRewardedContent()),
|
||||
recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)),
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -165,7 +165,7 @@ class CardVerify extends React.Component {
|
|||
render() {
|
||||
return (
|
||||
<Link
|
||||
button="primary"
|
||||
button="alt"
|
||||
label={this.props.label}
|
||||
icon="icon-lock"
|
||||
disabled={
|
||||
|
|
|
@ -69,15 +69,18 @@ export class CreditAmount extends React.PureComponent {
|
|||
label: React.PropTypes.bool,
|
||||
showFree: React.PropTypes.bool,
|
||||
showFullPrice: React.PropTypes.bool,
|
||||
showPlus: React.PropTypes.bool,
|
||||
look: React.PropTypes.oneOf(["indicator", "plain"]),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
precision: 2,
|
||||
label: true,
|
||||
showFree: false,
|
||||
look: "indicator",
|
||||
showFree: false,
|
||||
showFullPrice: false,
|
||||
showPlus: false,
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -98,13 +101,18 @@ export class CreditAmount extends React.PureComponent {
|
|||
let amountText;
|
||||
if (this.props.showFree && parseFloat(this.props.amount) === 0) {
|
||||
amountText = __("free");
|
||||
} else if (this.props.label) {
|
||||
amountText =
|
||||
formattedAmount +
|
||||
" " +
|
||||
(parseFloat(amount) == 1 ? __("credit") : __("credits"));
|
||||
} else {
|
||||
amountText = formattedAmount;
|
||||
if (this.props.label) {
|
||||
amountText =
|
||||
formattedAmount +
|
||||
" " +
|
||||
(parseFloat(amount) == 1 ? __("credit") : __("credits"));
|
||||
} else {
|
||||
amountText = formattedAmount;
|
||||
}
|
||||
if (this.props.showPlus && amount > 0) {
|
||||
amountText = "+" + amountText;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -178,18 +178,20 @@ class FileActions extends React.PureComponent {
|
|||
onClick={this.handleSupportButtonClicked.bind(this)}
|
||||
/>
|
||||
{showMenu
|
||||
? <DropDownMenu>
|
||||
<DropDownMenuItem
|
||||
key={0}
|
||||
onClick={() => openInFolder(fileInfo)}
|
||||
label={openInFolderMessage}
|
||||
/>
|
||||
<DropDownMenuItem
|
||||
key={1}
|
||||
onClick={() => openModal(modals.CONFIRM_FILE_REMOVE)}
|
||||
label={__("Remove...")}
|
||||
/>
|
||||
</DropDownMenu>
|
||||
? <div className="button-set-item">
|
||||
<DropDownMenu>
|
||||
<DropDownMenuItem
|
||||
key={0}
|
||||
onClick={() => openInFolder(fileInfo)}
|
||||
label={openInFolderMessage}
|
||||
/>
|
||||
<DropDownMenuItem
|
||||
key={1}
|
||||
onClick={() => openModal(modals.CONFIRM_FILE_REMOVE)}
|
||||
label={__("Remove...")}
|
||||
/>
|
||||
</DropDownMenu>
|
||||
</div>
|
||||
: ""}
|
||||
<Modal
|
||||
type="confirm"
|
||||
|
|
|
@ -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 => ({
|
||||
|
|
16
ui/js/component/inviteList/index.js
Normal file
16
ui/js/component/inviteList/index.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
selectUserInvitees,
|
||||
selectUserInviteStatusIsPending,
|
||||
} from "selectors/user";
|
||||
import InviteList from "./view";
|
||||
|
||||
const select = state => ({
|
||||
invitees: selectUserInvitees(state),
|
||||
isPending: selectUserInviteStatusIsPending(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({});
|
||||
|
||||
export default connect(select, perform)(InviteList);
|
77
ui/js/component/inviteList/view.jsx
Normal file
77
ui/js/component/inviteList/view.jsx
Normal file
|
@ -0,0 +1,77 @@
|
|||
import React from "react";
|
||||
import { Icon } from "component/common";
|
||||
import RewardLink from "component/rewardLink";
|
||||
import rewards from "rewards.js";
|
||||
|
||||
class InviteList extends React.PureComponent {
|
||||
render() {
|
||||
const { invitees } = this.props;
|
||||
|
||||
if (!invitees) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("Invite History")}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
{invitees.length === 0 &&
|
||||
<span className="empty">{__("You haven't invited anyone.")} </span>}
|
||||
{invitees.length > 0 &&
|
||||
<table className="table-standard table-stretch">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
{__("Invitee Email")}
|
||||
</th>
|
||||
<th className="text-center">
|
||||
{__("Invite Status")}
|
||||
</th>
|
||||
<th className="text-center">
|
||||
{__("Reward")}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{invitees.map((invitee, index) => {
|
||||
return (
|
||||
<tr key={index}>
|
||||
<td>{invitee.email}</td>
|
||||
<td className="text-center">
|
||||
{invitee.invite_accepted
|
||||
? <Icon icon="icon-check" />
|
||||
: <span className="empty">{__("unused")}</span>}
|
||||
</td>
|
||||
<td className="text-center">
|
||||
{invitee.invite_reward_claimed
|
||||
? <Icon icon="icon-check" />
|
||||
: invitee.invite_accepted
|
||||
? <RewardLink
|
||||
label={__("Claim")}
|
||||
reward_type={rewards.TYPE_REFERRAL}
|
||||
/>
|
||||
: <span className="empty">
|
||||
{__("unclaimable")}
|
||||
</span>}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>}
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<div className="help">
|
||||
{__(
|
||||
"The maximum number of invite rewards is currently limited. Invite reward can only be claimed if the invitee passes the humanness test."
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default InviteList;
|
29
ui/js/component/inviteNew/index.js
Normal file
29
ui/js/component/inviteNew/index.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import InviteNew from "./view";
|
||||
import {
|
||||
selectUserInvitesRemaining,
|
||||
selectUserInviteNewIsPending,
|
||||
selectUserInviteNewErrorMessage,
|
||||
} from "selectors/user";
|
||||
import rewards from "rewards";
|
||||
import { makeSelectRewardAmountByType } from "selectors/rewards";
|
||||
|
||||
import { doUserInviteNew } from "actions/user";
|
||||
|
||||
const select = state => {
|
||||
const selectReward = makeSelectRewardAmountByType();
|
||||
|
||||
return {
|
||||
errorMessage: selectUserInviteNewErrorMessage(state),
|
||||
invitesRemaining: selectUserInvitesRemaining(state),
|
||||
isPending: selectUserInviteNewIsPending(state),
|
||||
rewardAmount: selectReward(state, { reward_type: rewards.TYPE_REFERRAL }),
|
||||
};
|
||||
};
|
||||
|
||||
const perform = dispatch => ({
|
||||
inviteNew: email => dispatch(doUserInviteNew(email)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(InviteNew);
|
100
ui/js/component/inviteNew/view.jsx
Normal file
100
ui/js/component/inviteNew/view.jsx
Normal file
|
@ -0,0 +1,100 @@
|
|||
import React from "react";
|
||||
import { BusyMessage, CreditAmount } from "component/common";
|
||||
import Link from "component/link";
|
||||
import { FormRow } from "component/form.js";
|
||||
|
||||
class FormInviteNew extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
email: "",
|
||||
};
|
||||
}
|
||||
|
||||
handleEmailChanged(event) {
|
||||
this.setState({
|
||||
email: event.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
this.props.inviteNew(this.state.email);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { errorMessage, isPending } = this.props;
|
||||
|
||||
return (
|
||||
<form>
|
||||
<FormRow
|
||||
type="text"
|
||||
label="Email"
|
||||
placeholder="youremail@example.org"
|
||||
name="email"
|
||||
value={this.state.email}
|
||||
errorMessage={errorMessage}
|
||||
onChange={event => {
|
||||
this.handleEmailChanged(event);
|
||||
}}
|
||||
/>
|
||||
<div className="form-row-submit">
|
||||
<Link
|
||||
button="primary"
|
||||
label={__("Send Invite")}
|
||||
disabled={isPending}
|
||||
onClick={event => {
|
||||
this.handleSubmit(event);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class InviteNew extends React.PureComponent {
|
||||
render() {
|
||||
const {
|
||||
errorMessage,
|
||||
invitesRemaining,
|
||||
inviteNew,
|
||||
inviteStatusIsPending,
|
||||
isPending,
|
||||
rewardAmount,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<CreditAmount amount={rewardAmount} />
|
||||
<h3>
|
||||
{__("Invite a Friend")}
|
||||
</h3>
|
||||
</div>
|
||||
{/*
|
||||
<div className="card__content">
|
||||
{invitesRemaining > 0 &&
|
||||
<p>{__("You have %s invites remaining.", invitesRemaining)}</p>}
|
||||
{invitesRemaining <= 0 &&
|
||||
<p className="empty">{__("You have no invites.")}</p>}
|
||||
</div> */}
|
||||
<div className="card__content">
|
||||
<p>
|
||||
{__(
|
||||
"Or an enemy. Or your cousin Jerry, who you're kind of unsure about."
|
||||
)}
|
||||
</p>
|
||||
<FormInviteNew
|
||||
errorMessage={errorMessage}
|
||||
inviteNew={inviteNew}
|
||||
isPending={isPending}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default InviteNew;
|
|
@ -1,5 +1,10 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import Link from "./view";
|
||||
|
||||
export default connect(null, null)(Link);
|
||||
const perform = dispatch => ({
|
||||
doNavigate: path => dispatch(doNavigate(path)),
|
||||
});
|
||||
|
||||
export default connect(null, perform)(Link);
|
||||
|
|
|
@ -5,7 +5,6 @@ const Link = props => {
|
|||
const {
|
||||
href,
|
||||
title,
|
||||
onClick,
|
||||
style,
|
||||
label,
|
||||
icon,
|
||||
|
@ -13,6 +12,8 @@ const Link = props => {
|
|||
button,
|
||||
disabled,
|
||||
children,
|
||||
navigate,
|
||||
doNavigate,
|
||||
} = props;
|
||||
|
||||
const className =
|
||||
|
@ -21,6 +22,12 @@ const Link = props => {
|
|||
(button ? " button-block button-" + button + " button-set-item" : "") +
|
||||
(disabled ? " disabled" : "");
|
||||
|
||||
const onClick = !props.onClick && navigate
|
||||
? () => {
|
||||
doNavigate(navigate);
|
||||
}
|
||||
: props.onClick;
|
||||
|
||||
let content;
|
||||
if (children) {
|
||||
content = children;
|
||||
|
|
5
ui/js/component/linkTransaction/index.js
Normal file
5
ui/js/component/linkTransaction/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import Link from "./view";
|
||||
|
||||
export default connect(null, null)(Link);
|
14
ui/js/component/linkTransaction/view.jsx
Normal file
14
ui/js/component/linkTransaction/view.jsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
|
||||
const LinkTransaction = props => {
|
||||
const { id } = props;
|
||||
const linkProps = Object.assign({}, props);
|
||||
|
||||
linkProps.href = "https://explorer.lbry.io/#!/transaction/" + id;
|
||||
linkProps.label = id.substr(0, 7);
|
||||
|
||||
return <Link {...linkProps} />;
|
||||
};
|
||||
|
||||
export default LinkTransaction;
|
|
@ -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 => ({
|
||||
|
|
|
@ -16,6 +16,7 @@ class PublishForm extends React.PureComponent {
|
|||
this._requiredFields = ["name", "bid", "meta_title", "tosAgree"];
|
||||
|
||||
this._defaultCopyrightNotice = "All rights reserved.";
|
||||
this._defaultPaidPrice = 0.01;
|
||||
|
||||
this.state = {
|
||||
rawName: "",
|
||||
|
@ -46,6 +47,7 @@ class PublishForm extends React.PureComponent {
|
|||
modal: null,
|
||||
isFee: false,
|
||||
customUrl: false,
|
||||
source: null,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -115,8 +117,12 @@ class PublishForm extends React.PureComponent {
|
|||
: {}),
|
||||
};
|
||||
|
||||
const { source } = this.state;
|
||||
|
||||
if (this.refs.file.getValue() !== "") {
|
||||
publishArgs.file_path = this.refs.file.getValue();
|
||||
} else if (source) {
|
||||
publishArgs.sources = source;
|
||||
}
|
||||
|
||||
const success = claim => {};
|
||||
|
@ -257,6 +263,7 @@ class PublishForm extends React.PureComponent {
|
|||
|
||||
handlePrefillClicked() {
|
||||
const claimInfo = this.myClaimInfo();
|
||||
const { source } = claimInfo.value.stream;
|
||||
const {
|
||||
license,
|
||||
licenseUrl,
|
||||
|
@ -275,6 +282,7 @@ class PublishForm extends React.PureComponent {
|
|||
meta_nsfw: nsfw,
|
||||
prefillDone: true,
|
||||
bid: claimInfo.amount,
|
||||
source,
|
||||
};
|
||||
|
||||
if (license == this._defaultCopyrightNotice) {
|
||||
|
@ -318,7 +326,9 @@ class PublishForm extends React.PureComponent {
|
|||
handleFeePrefChange(feeEnabled) {
|
||||
this.setState({
|
||||
isFee: feeEnabled,
|
||||
feeAmount: this.state.feeAmount == "" ? "5.00" : this.state.feeAmount,
|
||||
feeAmount: this.state.feeAmount == ""
|
||||
? this._defaultPaidPrice
|
||||
: this.state.feeAmount,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -786,7 +796,6 @@ class PublishForm extends React.PureComponent {
|
|||
ref="bid"
|
||||
type="number"
|
||||
step="0.01"
|
||||
min="0"
|
||||
label={__("Deposit")}
|
||||
postfix="LBC"
|
||||
onChange={event => {
|
||||
|
|
|
@ -5,8 +5,8 @@ import {
|
|||
makeSelectRewardByType,
|
||||
makeSelectIsRewardClaimPending,
|
||||
} from "selectors/rewards";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doClaimReward, doClaimRewardClearError } from "actions/rewards";
|
||||
import { doNavigate } from "actions/navigation";
|
||||
import { doClaimRewardType, doClaimRewardClearError } from "actions/rewards";
|
||||
import RewardLink from "./view";
|
||||
|
||||
const makeSelect = () => {
|
||||
|
@ -24,7 +24,7 @@ const makeSelect = () => {
|
|||
};
|
||||
|
||||
const perform = dispatch => ({
|
||||
claimReward: reward => dispatch(doClaimReward(reward, true)),
|
||||
claimReward: reward => dispatch(doClaimRewardType(reward.reward_type, true)),
|
||||
clearError: reward => dispatch(doClaimRewardClearError(reward)),
|
||||
navigate: path => dispatch(doNavigate(path)),
|
||||
});
|
||||
|
|
|
@ -9,15 +9,18 @@ const RewardLink = props => {
|
|||
claimReward,
|
||||
clearError,
|
||||
errorMessage,
|
||||
label,
|
||||
isPending,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div className="reward-link">
|
||||
<Link
|
||||
button={button ? button : "alt"}
|
||||
button={button}
|
||||
disabled={isPending}
|
||||
label={isPending ? __("Claiming...") : __("Claim Reward")}
|
||||
label={
|
||||
isPending ? __("Claiming...") : label ? label : __("Claim Reward")
|
||||
}
|
||||
onClick={() => {
|
||||
claimReward(reward);
|
||||
}}
|
||||
|
|
10
ui/js/component/rewardListClaimed/index.js
Normal file
10
ui/js/component/rewardListClaimed/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectClaimedRewards } from "selectors/rewards";
|
||||
import RewardListClaimed from "./view";
|
||||
|
||||
const select = state => ({
|
||||
rewards: selectClaimedRewards(state),
|
||||
});
|
||||
|
||||
export default connect(select, null)(RewardListClaimed);
|
44
ui/js/component/rewardListClaimed/view.jsx
Normal file
44
ui/js/component/rewardListClaimed/view.jsx
Normal file
|
@ -0,0 +1,44 @@
|
|||
import React from "react";
|
||||
import LinkTransaction from "component/linkTransaction";
|
||||
|
||||
const RewardListClaimed = props => {
|
||||
const { rewards } = props;
|
||||
|
||||
if (!rewards || !rewards.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-identity"><h3>Claimed Rewards</h3></div>
|
||||
<div className="card__content">
|
||||
<table className="table-standard table-stretch">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{__("Title")}</th>
|
||||
<th>{__("Amount")}</th>
|
||||
<th>{__("Transaction")}</th>
|
||||
<th>{__("Date")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rewards.map(reward => {
|
||||
return (
|
||||
<tr key={reward.id}>
|
||||
<td>{reward.reward_title}</td>
|
||||
<td>{reward.reward_amount}</td>
|
||||
<td><LinkTransaction id={reward.transaction_id} /></td>
|
||||
<td>
|
||||
{reward.created_at.replace("Z", " ").replace("T", " ")}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default RewardListClaimed;
|
10
ui/js/component/rewardSummary/index.js
Normal file
10
ui/js/component/rewardSummary/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectUnclaimedRewardValue } from "selectors/rewards";
|
||||
import RewardSummary from "./view";
|
||||
|
||||
const select = state => ({
|
||||
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
|
||||
});
|
||||
|
||||
export default connect(select, null)(RewardSummary);
|
29
ui/js/component/rewardSummary/view.jsx
Normal file
29
ui/js/component/rewardSummary/view.jsx
Normal file
|
@ -0,0 +1,29 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
import { CreditAmount } from "component/common";
|
||||
|
||||
const RewardSummary = props => {
|
||||
const { balance, unclaimedRewardAmount } = props;
|
||||
|
||||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("Rewards")}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
{unclaimedRewardAmount > 0 &&
|
||||
<p>
|
||||
You have{" "}
|
||||
<CreditAmount amount={unclaimedRewardAmount} precision={8} /> in
|
||||
unclaimed rewards.
|
||||
</p>}
|
||||
</div>
|
||||
<div className="card__actions card__actions--bottom">
|
||||
<Link button="text" navigate="/rewards" label={__("Rewards")} />
|
||||
<Link button="text" navigate="/invite" label={__("Invites")} />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default RewardSummary;
|
5
ui/js/component/rewardTile/index.js
Normal file
5
ui/js/component/rewardTile/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import RewardTile from "./view";
|
||||
|
||||
export default connect(null, null)(RewardTile);
|
37
ui/js/component/rewardTile/view.jsx
Normal file
37
ui/js/component/rewardTile/view.jsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
import React from "react";
|
||||
import { CreditAmount, Icon } from "component/common";
|
||||
import RewardLink from "component/rewardLink";
|
||||
import Link from "component/link";
|
||||
import rewards from "rewards";
|
||||
|
||||
const RewardTile = props => {
|
||||
const { reward } = props;
|
||||
|
||||
const claimed = !!reward.transaction_id;
|
||||
|
||||
return (
|
||||
<section className="card">
|
||||
<div className="card__inner">
|
||||
<div className="card__title-primary">
|
||||
<CreditAmount amount={reward.reward_amount} />
|
||||
<h3>{reward.reward_title}</h3>
|
||||
</div>
|
||||
<div className="card__content">{reward.reward_description}</div>
|
||||
<div className="card__actions card__actions--bottom ">
|
||||
{reward.reward_type == rewards.TYPE_REFERRAL &&
|
||||
<Link
|
||||
button="alt"
|
||||
navigate="/invite"
|
||||
label={__("Go To Invites")}
|
||||
/>}
|
||||
{reward.reward_type !== rewards.TYPE_REFERRAL &&
|
||||
(claimed
|
||||
? <span><Icon icon="icon-check" /> {__("Reward claimed.")}</span>
|
||||
: <RewardLink button="alt" reward_type={reward.reward_type} />)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default RewardTile;
|
|
@ -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),
|
||||
|
|
|
@ -2,18 +2,21 @@ import React from "react";
|
|||
import SettingsPage from "page/settings";
|
||||
import HelpPage from "page/help";
|
||||
import ReportPage from "page/report.js";
|
||||
import StartPage from "page/start.js";
|
||||
import WalletPage from "page/wallet";
|
||||
import ShowPage from "page/showPage";
|
||||
import ReceiveCreditsPage from "page/receiveCredits";
|
||||
import SendCreditsPage from "page/sendCredits";
|
||||
import ShowPage from "page/show";
|
||||
import PublishPage from "page/publish";
|
||||
import DiscoverPage from "page/discover";
|
||||
import DeveloperPage from "page/developer.js";
|
||||
import RewardsPage from "page/rewards";
|
||||
import FileListDownloaded from "page/fileListDownloaded";
|
||||
import FileListPublished from "page/fileListPublished";
|
||||
import TransactionHistoryPage from "page/transactionHistory";
|
||||
import ChannelPage from "page/channel";
|
||||
import SearchPage from "page/search";
|
||||
import AuthPage from "page/auth";
|
||||
import InvitePage from "page/invite";
|
||||
import BackupPage from "page/backup";
|
||||
|
||||
const route = (page, routesMap) => {
|
||||
|
@ -33,16 +36,17 @@ const Router = props => {
|
|||
discover: <DiscoverPage params={params} />,
|
||||
downloaded: <FileListDownloaded params={params} />,
|
||||
help: <HelpPage params={params} />,
|
||||
history: <TransactionHistoryPage params={params} />,
|
||||
invite: <InvitePage params={params} />,
|
||||
publish: <PublishPage params={params} />,
|
||||
published: <FileListPublished params={params} />,
|
||||
receive: <WalletPage params={params} />,
|
||||
receive: <ReceiveCreditsPage params={params} />,
|
||||
report: <ReportPage params={params} />,
|
||||
rewards: <RewardsPage params={params} />,
|
||||
search: <SearchPage params={params} />,
|
||||
send: <WalletPage params={params} />,
|
||||
send: <SendCreditsPage params={params} />,
|
||||
settings: <SettingsPage params={params} />,
|
||||
show: <ShowPage params={params} />,
|
||||
start: <StartPage params={params} />,
|
||||
wallet: <WalletPage params={params} />,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -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,23 +1,5 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "actions/app";
|
||||
import { doFetchTransactions } from "actions/wallet";
|
||||
import {
|
||||
selectBalance,
|
||||
selectTransactionItems,
|
||||
selectIsFetchingTransactions,
|
||||
} from "selectors/wallet";
|
||||
|
||||
import TransactionList from "./view";
|
||||
|
||||
const select = state => ({
|
||||
fetchingTransactions: selectIsFetchingTransactions(state),
|
||||
transactionItems: selectTransactionItems(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
fetchTransactions: () => dispatch(doFetchTransactions()),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(TransactionList);
|
||||
export default connect(null, null)(TransactionList);
|
||||
|
|
|
@ -1,103 +1,57 @@
|
|||
import React from "react";
|
||||
import { Address, BusyMessage, CreditAmount } from "component/common";
|
||||
import LinkTransaction from "component/linkTransaction";
|
||||
import { CreditAmount } from "component/common";
|
||||
|
||||
class TransactionList extends React.PureComponent {
|
||||
componentWillMount() {
|
||||
this.props.fetchTransactions();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { fetchingTransactions, transactionItems, navigate } = this.props;
|
||||
|
||||
function findTypeOfTx(type, is_tip) {
|
||||
if (is_tip && type === "Support") return "Tip";
|
||||
else return type;
|
||||
}
|
||||
|
||||
function getClaimLink(claim_name, claim_id) {
|
||||
if (claim_id !== "" && claim_name !== "") {
|
||||
let uri = `lbry://${claim_name}#${claim_id}`;
|
||||
|
||||
return (
|
||||
<td>
|
||||
<a
|
||||
className="button-text"
|
||||
onClick={() => navigate("/show", { uri })}
|
||||
>
|
||||
{claim_name}
|
||||
</a>
|
||||
</td>
|
||||
);
|
||||
}
|
||||
|
||||
return <td>{__("N/A")}</td>;
|
||||
}
|
||||
|
||||
const rows = [];
|
||||
if (transactionItems.length > 0) {
|
||||
transactionItems.forEach(function(item) {
|
||||
rows.push(
|
||||
<tr key={item.id}>
|
||||
<td>{findTypeOfTx(item.type, item.is_tip)}</td>
|
||||
<td>{(item.amount > 0 ? "+" : "") + item.amount}</td>
|
||||
<td>{item.fee}</td>
|
||||
<td>
|
||||
{item.date
|
||||
? item.date.toLocaleDateString()
|
||||
: <span className="empty">{__("(Transaction pending)")}</span>}
|
||||
</td>
|
||||
<td>
|
||||
{item.date
|
||||
? item.date.toLocaleTimeString()
|
||||
: <span className="empty">{__("(Transaction pending)")}</span>}
|
||||
</td>
|
||||
{getClaimLink(item.claim_name, item.claim_id)}
|
||||
<td>
|
||||
<a
|
||||
className="button-text"
|
||||
href={"https://explorer.lbry.io/#!/transaction/" + item.id}
|
||||
>
|
||||
{item.id.substr(0, 7)}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
}
|
||||
const TransactionList = props => {
|
||||
const { emptyMessage, transactions } = props;
|
||||
|
||||
if (!transactions || !transactions.length) {
|
||||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("Transaction History")}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
{fetchingTransactions &&
|
||||
<BusyMessage message={__("Loading transactions")} />}
|
||||
{!fetchingTransactions && rows.length === 0
|
||||
? <div className="empty">{__("You have no transactions.")}</div>
|
||||
: ""}
|
||||
{rows.length > 0
|
||||
? <table className="table-standard table-stretch">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{__("Type")}</th>
|
||||
<th>{__("Amount")}</th>
|
||||
<th>{__("Fee")}</th>
|
||||
<th>{__("Date")}</th>
|
||||
<th>{__("Time")}</th>
|
||||
<th>{__("Claim")}</th>
|
||||
<th>{__("Transaction")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows}
|
||||
</tbody>
|
||||
</table>
|
||||
: ""}
|
||||
</div>
|
||||
</section>
|
||||
<div className="empty">
|
||||
{emptyMessage || __("No transactions to list.")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<table className="table-standard table-stretch">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{__("Date")}</th>
|
||||
<th>{__("Amount")}</th>
|
||||
<th>{__("Transaction")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{transactions.map(item => {
|
||||
return (
|
||||
<tr key={item.id}>
|
||||
<td>
|
||||
{item.date
|
||||
? item.date.toLocaleDateString() +
|
||||
" " +
|
||||
item.date.toLocaleTimeString()
|
||||
: <span className="empty">
|
||||
{__("(Transaction pending)")}
|
||||
</span>}
|
||||
</td>
|
||||
<td>
|
||||
<CreditAmount
|
||||
amount={item.amount}
|
||||
look="plain"
|
||||
showPlus={true}
|
||||
precision={8}
|
||||
/>{" "}
|
||||
</td>
|
||||
<td>
|
||||
<LinkTransaction id={item.id} />
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
||||
|
||||
export default TransactionList;
|
||||
|
|
23
ui/js/component/transactionListRecent/index.js
Normal file
23
ui/js/component/transactionListRecent/index.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doFetchTransactions } from "actions/wallet";
|
||||
import {
|
||||
selectBalance,
|
||||
selectRecentTransactions,
|
||||
selectHasTransactions,
|
||||
selectIsFetchingTransactions,
|
||||
} from "selectors/wallet";
|
||||
|
||||
import TransactionListRecent from "./view";
|
||||
|
||||
const select = state => ({
|
||||
fetchingTransactions: selectIsFetchingTransactions(state),
|
||||
transactions: selectRecentTransactions(state),
|
||||
hasTransactions: selectHasTransactions(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
fetchTransactions: () => dispatch(doFetchTransactions()),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(TransactionListRecent);
|
41
ui/js/component/transactionListRecent/view.jsx
Normal file
41
ui/js/component/transactionListRecent/view.jsx
Normal file
|
@ -0,0 +1,41 @@
|
|||
import React from "react";
|
||||
import { BusyMessage } from "component/common";
|
||||
import Link from "component/link";
|
||||
import TransactionList from "component/transactionList";
|
||||
|
||||
class TransactionListRecent extends React.PureComponent {
|
||||
componentWillMount() {
|
||||
this.props.fetchTransactions();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { fetchingTransactions, hasTransactions, transactions } = this.props;
|
||||
|
||||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("Recent Transactions")}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
{fetchingTransactions &&
|
||||
<BusyMessage message={__("Loading transactions")} />}
|
||||
{!fetchingTransactions &&
|
||||
<TransactionList
|
||||
transactions={transactions}
|
||||
emptyMessage={__("You have no recent transactions.")}
|
||||
/>}
|
||||
</div>
|
||||
{hasTransactions &&
|
||||
<div className="card__actions card__actions--bottom">
|
||||
<Link
|
||||
navigate="/history"
|
||||
label={__("See Full History")}
|
||||
button="text"
|
||||
/>
|
||||
</div>}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TransactionListRecent;
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doUserEmailNew } from "actions/user";
|
||||
import { doUserEmailNew, doUserInviteNew } from "actions/user";
|
||||
import {
|
||||
selectEmailNewIsPending,
|
||||
selectEmailNewErrorMessage,
|
||||
|
|
|
@ -31,6 +31,16 @@ class UserEmailNew extends React.PureComponent {
|
|||
this.handleSubmit(event);
|
||||
}}
|
||||
>
|
||||
<p>
|
||||
{__(
|
||||
"This process is required to prevent abuse of the rewards program."
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{__(
|
||||
"We will also contact you about updates and new content, but you can unsubscribe at any time."
|
||||
)}
|
||||
</p>
|
||||
<FormRow
|
||||
type="text"
|
||||
label="Email"
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -26,37 +26,125 @@ class UserVerify extends React.PureComponent {
|
|||
const { errorMessage, isPending, navigate } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
{__(
|
||||
"To ensure you are a real person, we require a valid credit or debit card."
|
||||
) +
|
||||
" " +
|
||||
__("There is no charge at all, now or in the future.") +
|
||||
" "}
|
||||
<Link
|
||||
href="https://lbry.io/faq/identity-requirements"
|
||||
label={__("Read More")}
|
||||
/>
|
||||
</p>
|
||||
{errorMessage && <p className="form-field__error">{errorMessage}</p>}
|
||||
<p>
|
||||
<CardVerify
|
||||
label={__("Link Card and Finish")}
|
||||
disabled={isPending}
|
||||
token={this.onToken.bind(this)}
|
||||
stripeKey={lbryio.getStripeToken()}
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
{__(
|
||||
"You can continue without this step, but you will not be eligible to earn rewards."
|
||||
)}
|
||||
</p>
|
||||
<Link
|
||||
onClick={() => navigate("/discover")}
|
||||
button="alt"
|
||||
label={__("Skip Rewards")}
|
||||
/>
|
||||
<section className="card card--form">
|
||||
<div className="card__title-primary">
|
||||
<h1>{__("Final Human Proof")}</h1>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<p>
|
||||
Finally, please complete <strong>one and only one</strong> of the
|
||||
options below.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<section className="card card--form">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("1) Proof via Credit")}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
{__(
|
||||
"If you have a valid credit or debit card, you can use it to instantly prove your humanity."
|
||||
) +
|
||||
" " +
|
||||
__("There is no charge at all for this, now or in the future.") +
|
||||
" "}
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
{errorMessage &&
|
||||
<p className="form-field__error">{errorMessage}</p>}
|
||||
<CardVerify
|
||||
label={__("Perform Card Verification")}
|
||||
disabled={isPending}
|
||||
token={this.onToken.bind(this)}
|
||||
stripeKey={lbryio.getStripeToken()}
|
||||
/>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<div className="meta">
|
||||
{__(
|
||||
"A $1 authorization may temporarily appear with your provider."
|
||||
)}{" "}
|
||||
{" "}
|
||||
<Link
|
||||
href="https://lbry.io/faq/identity-requirements"
|
||||
label={__("Read more about why we do this.")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="card card--form">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("2) Proof via YouTube")}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<p>
|
||||
{__(
|
||||
"If you have a YouTube account with subscribers and views, you can sync your account to be granted instant verification."
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
<Link
|
||||
href="https://api.lbry.io/yt/connect"
|
||||
button="alt"
|
||||
icon="icon-youtube"
|
||||
label={__("YouTube Account Sync")}
|
||||
/>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<div className="meta">
|
||||
This will not automatically refresh after approval. Once you have
|
||||
synced your account, just navigate away or click
|
||||
{" "} <Link navigate="/rewards" label="here" />.
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="card card--form">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("3) Proof via Chat")}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<p>
|
||||
{__(
|
||||
"A moderator capable of approving you is typically available in the #verification channel of our chat room."
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{__(
|
||||
"This process will likely involve providing proof of a stable and established online or real-life identity."
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
<Link
|
||||
href="https://slack.lbry.io"
|
||||
button="alt"
|
||||
icon="icon-slack"
|
||||
label={__("Join LBRY Chat")}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section className="card card--form">
|
||||
<div className="card__title-primary">
|
||||
<h5>{__("Or, Skip It Entirely")}</h5>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
|
||||
<p className="meta">
|
||||
{__(
|
||||
"You can continue without this step, but you will not be eligible to earn rewards."
|
||||
)}
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
<Link
|
||||
onClick={() => navigate("/discover")}
|
||||
button="alt"
|
||||
label={__("Skip Rewards")}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -5,7 +5,7 @@ import {
|
|||
selectReceiveAddress,
|
||||
selectGettingNewAddress,
|
||||
} from "selectors/wallet";
|
||||
import WalletPage from "./view";
|
||||
import WalletAddress from "./view";
|
||||
|
||||
const select = state => ({
|
||||
receiveAddress: selectReceiveAddress(state),
|
||||
|
@ -17,4 +17,4 @@ const perform = dispatch => ({
|
|||
getNewAddress: () => dispatch(doGetNewAddress()),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(WalletPage);
|
||||
export default connect(select, perform)(WalletAddress);
|
||||
|
|
|
@ -16,6 +16,11 @@ class WalletAddress extends React.PureComponent {
|
|||
<h3>{__("Wallet Address")}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<p>
|
||||
{__(
|
||||
"Use this address to receive credits sent by another user (or yourself)."
|
||||
)}
|
||||
</p>
|
||||
<Address address={receiveAddress} />
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
|
@ -29,11 +34,6 @@ class WalletAddress extends React.PureComponent {
|
|||
</div>
|
||||
<div className="card__content">
|
||||
<div className="help">
|
||||
<p>
|
||||
{__(
|
||||
'Other LBRY users may send credits to you by entering this address on the "Send" page.'
|
||||
)}
|
||||
</p>
|
||||
<p>
|
||||
{__(
|
||||
"You can generate a new address at any time, and any previous addresses will continue to work. Using multiple addresses can be helpful for keeping track of incoming payments from multiple sources."
|
||||
|
|
10
ui/js/component/walletBalance/index.js
Normal file
10
ui/js/component/walletBalance/index.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectBalance } from "selectors/wallet";
|
||||
import WalletBalance from "./view";
|
||||
|
||||
const select = state => ({
|
||||
balance: selectBalance(state),
|
||||
});
|
||||
|
||||
export default connect(select, null)(WalletBalance);
|
43
ui/js/component/walletBalance/view.jsx
Normal file
43
ui/js/component/walletBalance/view.jsx
Normal file
|
@ -0,0 +1,43 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
import { CreditAmount } from "component/common";
|
||||
|
||||
const WalletBalance = props => {
|
||||
const { balance, navigate } = props;
|
||||
/*
|
||||
<div className="help">
|
||||
<Link
|
||||
onClick={() => navigate("/backup")}
|
||||
label={__("Backup Your Wallet")}
|
||||
/>
|
||||
</div>
|
||||
*/
|
||||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("Balance")}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
{(balance || balance === 0) &&
|
||||
<CreditAmount amount={balance} precision={8} />}
|
||||
</div>
|
||||
<div className="card__actions card__actions--bottom">
|
||||
<Link
|
||||
button="text"
|
||||
navigate="/send"
|
||||
disabled={balance === 0}
|
||||
label={__("Send")}
|
||||
/>
|
||||
<Link button="text" navigate="/receive" label={__("Receive")} />
|
||||
<Link
|
||||
button="text"
|
||||
disabled={balance === 0}
|
||||
navigate="/backup"
|
||||
label={__("Backup")}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default WalletBalance;
|
|
@ -34,15 +34,15 @@ const WalletSend = props => {
|
|||
onChange={setAddress}
|
||||
value={address}
|
||||
/>
|
||||
</div>
|
||||
<div className="card__actions card__actions--form-submit">
|
||||
<Link
|
||||
button="primary"
|
||||
label={__("Send")}
|
||||
onClick={sendToAddress}
|
||||
disabled={!(parseFloat(amount) > 0.0) || !address}
|
||||
/>
|
||||
<input type="submit" className="hidden" />
|
||||
<div className="form-row-submit">
|
||||
<Link
|
||||
button="primary"
|
||||
label={__("Send")}
|
||||
onClick={sendToAddress}
|
||||
disabled={!(parseFloat(amount) > 0.0) || !address}
|
||||
/>
|
||||
<input type="submit" className="hidden" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
|
|
@ -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";
|
||||
|
@ -108,6 +111,15 @@ export const USER_IDENTITY_VERIFY_FAILURE = "USER_IDENTITY_VERIFY_FAILURE";
|
|||
export const USER_FETCH_STARTED = "USER_FETCH_STARTED";
|
||||
export const USER_FETCH_SUCCESS = "USER_FETCH_SUCCESS";
|
||||
export const USER_FETCH_FAILURE = "USER_FETCH_FAILURE";
|
||||
export const USER_INVITE_STATUS_FETCH_STARTED =
|
||||
"USER_INVITE_STATUS_FETCH_STARTED";
|
||||
export const USER_INVITE_STATUS_FETCH_SUCCESS =
|
||||
"USER_INVITE_STATUS_FETCH_SUCCESS";
|
||||
export const USER_INVITE_STATUS_FETCH_FAILURE =
|
||||
"USER_INVITE_STATUS_FETCH_FAILURE";
|
||||
export const USER_INVITE_NEW_STARTED = "USER_INVITE_NEW_STARTED";
|
||||
export const USER_INVITE_NEW_SUCCESS = "USER_INVITE_NEW_SUCCESS";
|
||||
export const USER_INVITE_NEW_FAILURE = "USER_INVITE_NEW_FAILURE";
|
||||
export const FETCH_ACCESS_TOKEN_SUCCESS = "FETCH_ACCESS_TOKEN_SUCCESS";
|
||||
|
||||
// Rewards
|
||||
|
|
|
@ -9,4 +9,5 @@ export const FIRST_REWARD = "first_reward";
|
|||
export const AUTHENTICATION_FAILURE = "auth_failure";
|
||||
export const TRANSACTION_FAILED = "transaction_failed";
|
||||
export const INSUFFICIENT_BALANCE = "insufficient_balance";
|
||||
export const REWARD_APPROVAL_REQUIRED = "reward_approval_required";
|
||||
export const CREDIT_INTRO = "credit_intro";
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
/*hardcoded names still exist for these in reducers/settings.js - only discovered when debugging*/
|
||||
/*Many settings are stored in the localStorage by their name -
|
||||
be careful about changing the value of a settings constant, as doing so can invalidate existing settings*/
|
||||
export const CREDIT_INTRO_ACKNOWLEDGED = "credit_intro_acknowledged";
|
||||
export const FIRST_RUN_ACKNOWLEDGED = "welcome_acknowledged";
|
||||
export const NEW_USER_ACKNOWLEDGED = "welcome_acknowledged";
|
||||
export const LANGUAGE = "language";
|
||||
export const SHOW_NSFW = "showNsfw";
|
||||
export const SHOW_UNAVAILABLE = "showUnavailable";
|
||||
|
|
|
@ -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 }));
|
||||
|
@ -87,13 +70,6 @@ win.on("focus", () => {
|
|||
dock.setBadge("");
|
||||
});
|
||||
|
||||
const updateProgress = () => {
|
||||
const state = app.store.getState();
|
||||
const progress = selectTotalDownloadProgress(state);
|
||||
|
||||
win.setProgressBar(progress || -1);
|
||||
};
|
||||
|
||||
const initialState = app.store.getState();
|
||||
|
||||
var init = function() {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import React from "react";
|
||||
import rewards from "rewards";
|
||||
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";
|
||||
import {
|
||||
makeSelectHasClaimedReward,
|
||||
makeSelectRewardByType,
|
||||
selectTotalRewardValue,
|
||||
selectUnclaimedRewardValue,
|
||||
} from "selectors/rewards";
|
||||
import * as settings from "constants/settings";
|
||||
import ModalCreditIntro from "./view";
|
||||
|
@ -17,9 +18,9 @@ const select = (state, props) => {
|
|||
selectReward = makeSelectRewardByType();
|
||||
|
||||
return {
|
||||
currentBalance: selectBalance(state),
|
||||
isRewardApproved: selectUserIsRewardApproved(state),
|
||||
reward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
||||
totalRewardValue: selectTotalRewardValue(state),
|
||||
totalRewardValue: selectUnclaimedRewardValue(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,40 +1,64 @@
|
|||
import React from "react";
|
||||
import { Modal } from "modal/modal";
|
||||
import { CreditAmount } from "component/common";
|
||||
import { CreditAmount, CurrencySymbol } from "component/common";
|
||||
import Link from "component/link/index";
|
||||
import { formatCredits } from "util/formatCredits";
|
||||
|
||||
const ModalCreditIntro = props => {
|
||||
const { closeModal, totalRewardValue, verifyAccount } = props;
|
||||
const { closeModal, currentBalance, totalRewardValue, verifyAccount } = props;
|
||||
|
||||
const totalRewardRounded = Math.round(totalRewardValue / 10) * 10;
|
||||
|
||||
return (
|
||||
<Modal type="custom" isOpen={true} contentLabel="Welcome to LBRY">
|
||||
<section>
|
||||
<h3 className="modal__header">{__("Claim Your Credits")}</h3>
|
||||
<p>
|
||||
The LBRY network is controlled and powered by credits called{" "}
|
||||
<em>LBC</em>, a blockchain asset.
|
||||
</p>
|
||||
<p>
|
||||
{__("New patrons receive ")} {" "}
|
||||
{totalRewardValue
|
||||
? <CreditAmount amount={totalRewardRounded} />
|
||||
: <span className="credit-amount">{__("credits")}</span>}
|
||||
{" "} {__("in rewards for usage and influence of the network.")}
|
||||
</p>
|
||||
<h3 className="modal__header">{__("Blockchain 101")}</h3>
|
||||
<p>
|
||||
LBRY is controlled and powered by a blockchain asset called {" "}
|
||||
<em><CurrencySymbol /></em>.{" "}
|
||||
<CurrencySymbol />{" "}
|
||||
{__(
|
||||
"You'll also earn weekly bonuses for checking out the greatest new stuff."
|
||||
"is used to publish content, to have a say in the network rules, and to access paid content."
|
||||
)}
|
||||
</p>
|
||||
{currentBalance <= 0
|
||||
? <div>
|
||||
<p>
|
||||
You currently have <CreditAmount amount={currentBalance} />, so
|
||||
the actions you can take are limited.
|
||||
</p>
|
||||
<p>
|
||||
However, there are a variety of ways to get credits, including
|
||||
more than {" "}
|
||||
{totalRewardValue
|
||||
? <CreditAmount amount={totalRewardRounded} />
|
||||
: <span className="credit-amount">{__("?? credits")}</span>}
|
||||
{" "}{" "}
|
||||
{__(
|
||||
" in rewards available for being a proven human during the LBRY beta."
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
: <div>
|
||||
<p>
|
||||
But you probably knew this, since you've already got{" "}
|
||||
<CreditAmount amount={currentBalance} />.
|
||||
</p>
|
||||
</div>}
|
||||
|
||||
<div className="modal__buttons">
|
||||
<Link
|
||||
button="primary"
|
||||
onClick={verifyAccount}
|
||||
label={__("You Had Me At Free LBC")}
|
||||
label={__("I'm Totally A Human")}
|
||||
/>
|
||||
<Link
|
||||
button="alt"
|
||||
onClick={closeModal}
|
||||
label={
|
||||
currentBalance <= 0 ? __("Use Without LBC") : __("Meh, Not Now")
|
||||
}
|
||||
/>
|
||||
<Link button="alt" onClick={closeModal} label={__("I Burn Money")} />
|
||||
</div>
|
||||
</section>
|
||||
</Modal>
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
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 => ({});
|
||||
|
||||
const perform = dispatch => ({
|
||||
addFunds: () => {
|
||||
dispatch(doNavigate("/rewards"));
|
||||
dispatch(doNavigate("/wallet"));
|
||||
dispatch(doCloseModal());
|
||||
},
|
||||
closeModal: () => dispatch(doCloseModal()),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from "react";
|
||||
import { Modal } from "modal/modal";
|
||||
import { CurrencySymbol } from "component/common";
|
||||
|
||||
class ModalInsufficientCredits extends React.PureComponent {
|
||||
render() {
|
||||
|
@ -11,11 +12,12 @@ class ModalInsufficientCredits extends React.PureComponent {
|
|||
type="confirm"
|
||||
contentLabel={__("Not enough credits")}
|
||||
confirmButtonLabel={__("Get Credits")}
|
||||
abortButtonLabel={__("Cancel")}
|
||||
abortButtonLabel={__("Not Now")}
|
||||
onAborted={closeModal}
|
||||
onConfirmed={addFunds}
|
||||
>
|
||||
{__("More LBRY credits are required to purchase this.")}
|
||||
<h3 className="modal__header">{__("More Credits Required")}</h3>
|
||||
<p>You'll need more <CurrencySymbol /> to do this.</p>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
15
ui/js/modal/modalRewardApprovalRequired/index.js
Normal file
15
ui/js/modal/modalRewardApprovalRequired/index.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doCloseModal } from "actions/app";
|
||||
import { doAuthNavigate } from "actions/navigation";
|
||||
import ModalRewardApprovalRequired from "./view";
|
||||
|
||||
const perform = dispatch => ({
|
||||
doAuth: () => {
|
||||
dispatch(doCloseModal());
|
||||
dispatch(doAuthNavigate());
|
||||
},
|
||||
closeModal: () => dispatch(doCloseModal()),
|
||||
});
|
||||
|
||||
export default connect(null, perform)(ModalRewardApprovalRequired);
|
33
ui/js/modal/modalRewardApprovalRequired/view.jsx
Normal file
33
ui/js/modal/modalRewardApprovalRequired/view.jsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
import React from "react";
|
||||
import { Modal } from "modal/modal";
|
||||
|
||||
class ModalRewardApprovalRequired extends React.PureComponent {
|
||||
render() {
|
||||
const { closeModal, doAuth } = this.props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={true}
|
||||
contentLabel={__("Human Verification Required")}
|
||||
onConfirmed={doAuth}
|
||||
onAborted={closeModal}
|
||||
type="confirm"
|
||||
confirmButtonLabel={__("I'm Totally Real")}
|
||||
abortButtonLabel={__("Never Mind")}
|
||||
>
|
||||
<section>
|
||||
<h3 className="modal__header">
|
||||
{__("This is awkward. Are you real?")}
|
||||
</h3>
|
||||
<p>
|
||||
{__(
|
||||
"Before we can give you any credits, we need to perform a brief check to make sure you're a new and unique person."
|
||||
)}
|
||||
</p>
|
||||
</section>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ModalRewardApprovalRequired;
|
|
@ -1,20 +1,31 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectCurrentModal } from "selectors/app";
|
||||
import { doOpenModal } from "actions/app";
|
||||
import { selectWelcomeModalAcknowledged } from "selectors/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 { selectBalance } from "selectors/wallet";
|
||||
import ModalRouter from "./view";
|
||||
import * as modals from "constants/modal_types";
|
||||
|
||||
const select = (state, props) => ({
|
||||
balance: selectBalance(state),
|
||||
showPageCost: selectCostForCurrentPageUri(state),
|
||||
modal: selectCurrentModal(state),
|
||||
isWelcomeAcknowledged: selectWelcomeModalAcknowledged(state),
|
||||
page: selectCurrentPage(state),
|
||||
isWelcomeAcknowledged: makeSelectClientSetting(
|
||||
settings.NEW_USER_ACKNOWLEDGED
|
||||
)(state),
|
||||
isCreditIntroAcknowledged: makeSelectClientSetting(
|
||||
settings.CREDIT_INTRO_ACKNOWLEDGED
|
||||
)(state),
|
||||
user: selectUser(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
openWelcomeModal: () => dispatch(doOpenModal(modals.WELCOME)),
|
||||
openModal: modal => dispatch(doOpenModal(modal)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(ModalRouter);
|
||||
|
|
|
@ -6,33 +6,97 @@ import ModalInsufficientCredits from "modal/modalInsufficientCredits";
|
|||
import ModalUpgrade from "modal/modalUpgrade";
|
||||
import ModalWelcome from "modal/modalWelcome";
|
||||
import ModalFirstReward from "modal/modalFirstReward";
|
||||
import ModalRewardApprovalRequired from "modal/modalRewardApprovalRequired";
|
||||
import ModalCreditIntro from "modal/modalCreditIntro";
|
||||
import ModalTransactionFailed from "modal/modalTransactionFailed";
|
||||
import ModalInsufficientBalance from "modal/modalInsufficientBalance";
|
||||
import * as modals from "constants/modal_types";
|
||||
|
||||
class ModalRouter extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
lastTransitionModal: null,
|
||||
lastTransitionPage: null,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.showWelcome(this.props);
|
||||
this.showTransitionModals(this.props);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.showWelcome(nextProps);
|
||||
this.showTransitionModals(nextProps);
|
||||
}
|
||||
|
||||
showWelcome(props) {
|
||||
const { isWelcomeAcknowledged, openWelcomeModal, user } = props;
|
||||
showTransitionModals(props) {
|
||||
const { modal, openModal, page } = props;
|
||||
|
||||
if (modal) {
|
||||
return;
|
||||
}
|
||||
|
||||
const transitionModal = [
|
||||
this.checkShowWelcome,
|
||||
this.checkShowCreditIntro,
|
||||
this.checkShowInsufficientCredits,
|
||||
].reduce((acc, func) => {
|
||||
return !acc ? func.bind(this)(props) : acc;
|
||||
}, false);
|
||||
|
||||
if (
|
||||
transitionModal &&
|
||||
(transitionModal != this.state.lastTransitionModal ||
|
||||
page != this.state.lastTransitionPage)
|
||||
) {
|
||||
openModal(transitionModal);
|
||||
this.setState({
|
||||
lastTransitionModal: transitionModal,
|
||||
lastTransitionPage: page,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
checkShowWelcome(props) {
|
||||
const { isWelcomeAcknowledged, user } = props;
|
||||
if (
|
||||
!isWelcomeAcknowledged &&
|
||||
user &&
|
||||
!user.is_reward_approved &&
|
||||
!user.is_identity_verified
|
||||
) {
|
||||
openWelcomeModal();
|
||||
return modals.WELCOME;
|
||||
}
|
||||
}
|
||||
|
||||
checkShowCreditIntro(props) {
|
||||
const { page, isCreditIntroAcknowledged, user } = props;
|
||||
|
||||
if (
|
||||
!isCreditIntroAcknowledged &&
|
||||
user &&
|
||||
!user.is_reward_approved &&
|
||||
(["rewards", "send", "receive", "publish", "wallet"].includes(page) ||
|
||||
this.isPaidShowPage(props))
|
||||
) {
|
||||
return modals.CREDIT_INTRO;
|
||||
}
|
||||
}
|
||||
|
||||
checkShowInsufficientCredits(props) {
|
||||
const { balance, page } = props;
|
||||
|
||||
if (balance <= 0 && ["send", "publish"].includes(page)) {
|
||||
return modals.INSUFFICIENT_CREDITS;
|
||||
}
|
||||
}
|
||||
|
||||
isPaidShowPage(props) {
|
||||
const { page, showPageCost } = props;
|
||||
return page === "show" && showPageCost > 0;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { modal } = this.props;
|
||||
|
||||
|
@ -57,6 +121,8 @@ class ModalRouter extends React.PureComponent {
|
|||
return <ModalTransactionFailed />;
|
||||
case modals.INSUFFICIENT_BALANCE:
|
||||
return <ModalInsufficientBalance />;
|
||||
case modals.REWARD_APPROVAL_REQUIRED:
|
||||
return <ModalRewardApprovalRequired />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,8 @@ import ModalWelcome from "./view";
|
|||
|
||||
const perform = dispatch => () => ({
|
||||
closeModal: () => {
|
||||
dispatch(doSetClientSetting(settings.FIRST_RUN_ACKNOWLEDGED, true));
|
||||
dispatch(doSetClientSetting(settings.NEW_USER_ACKNOWLEDGED, true));
|
||||
dispatch(doCloseModal());
|
||||
dispatch(doOpenModal(modals.CREDIT_INTRO));
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -22,7 +22,11 @@ const ModalWelcome = props => {
|
|||
)}
|
||||
</p>
|
||||
<div className="modal__buttons">
|
||||
<Link button="primary" onClick={closeModal} label={__("Continue")} />
|
||||
<Link
|
||||
button="primary"
|
||||
onClick={closeModal}
|
||||
label={__("Blockchain Centaurs? I'm In")}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</Modal>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -30,11 +30,11 @@ export class AuthPage extends React.PureComponent {
|
|||
const { email, isPending, isVerificationCandidate, user } = this.props;
|
||||
|
||||
if (isPending || (user && !user.has_verified_email && !email)) {
|
||||
return __("Welcome to LBRY");
|
||||
return __("Human Proofing");
|
||||
} else if (user && !user.has_verified_email) {
|
||||
return __("Confirm Email");
|
||||
} else if (user && !user.is_identity_verified && !user.is_reward_approved) {
|
||||
return __("Confirm Identity");
|
||||
return __("Final Verification");
|
||||
} else {
|
||||
return __("Welcome to LBRY");
|
||||
}
|
||||
|
@ -44,51 +44,45 @@ export class AuthPage extends React.PureComponent {
|
|||
const { email, isPending, isVerificationCandidate, user } = this.props;
|
||||
|
||||
if (isPending) {
|
||||
return <BusyMessage message={__("Authenticating")} />;
|
||||
return [<BusyMessage message={__("Authenticating")} />, true];
|
||||
} else if (user && !user.has_verified_email && !email) {
|
||||
return <UserEmailNew />;
|
||||
return [<UserEmailNew />, true];
|
||||
} else if (user && !user.has_verified_email) {
|
||||
return <UserEmailVerify />;
|
||||
return [<UserEmailVerify />, true];
|
||||
} else if (user && !user.is_identity_verified) {
|
||||
return <UserVerify />;
|
||||
return [<UserVerify />, false];
|
||||
} else {
|
||||
return <span className="empty">{__("No further steps.")}</span>;
|
||||
return [<span className="empty">{__("No further steps.")}</span>, true];
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { email, user, isPending, navigate } = this.props;
|
||||
const [innerContent, useTemplate] = this.renderMain();
|
||||
|
||||
return (
|
||||
<main className="">
|
||||
<section className="card card--form">
|
||||
<div className="card__title-primary">
|
||||
<h1>{this.getTitle()}</h1>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
{!isPending &&
|
||||
!email &&
|
||||
user &&
|
||||
!user.has_verified_email &&
|
||||
<p>
|
||||
{__("Create a verified identity and receive LBC rewards.")}
|
||||
</p>}
|
||||
{this.renderMain()}
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<div className="help">
|
||||
{__(
|
||||
"This information is disclosed only to LBRY, Inc. and not to the LBRY network. It is only required to earn LBRY rewards."
|
||||
) + " "}
|
||||
<Link
|
||||
onClick={() => navigate("/discover")}
|
||||
label={__("Return home")}
|
||||
/>.
|
||||
return useTemplate
|
||||
? <main>
|
||||
<section className="card card--form">
|
||||
<div className="card__title-primary">
|
||||
<h1>{this.getTitle()}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
<div className="card__content">
|
||||
{innerContent}
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<div className="help">
|
||||
{__(
|
||||
"This information is disclosed only to LBRY, Inc. and not to the LBRY network. It is only required to earn LBRY rewards."
|
||||
) + " "}
|
||||
<Link
|
||||
onClick={() => navigate("/discover")}
|
||||
label={__("Return home")}
|
||||
/>.
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
: innerContent;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 { doNavigate } from "actions/app";
|
||||
import { doAuthNavigate } from "actions/navigation";
|
||||
import { connect } from "react-redux";
|
||||
import { doFetchAccessToken } from "actions/user";
|
||||
import { selectAccessToken, selectUser } from "selectors/user";
|
||||
|
@ -11,7 +11,7 @@ const select = state => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
doAuth: () => dispatch(doAuthNavigate("/help")),
|
||||
fetchAccessToken: () => dispatch(doFetchAccessToken()),
|
||||
});
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from "react";
|
|||
import lbry from "lbry.js";
|
||||
import Link from "component/link";
|
||||
import SubHeader from "component/subHeader";
|
||||
import { BusyMessage } from "component/common";
|
||||
import { BusyMessage, Icon } from "component/common";
|
||||
|
||||
class HelpPage extends React.PureComponent {
|
||||
constructor(props) {
|
||||
|
@ -50,7 +50,7 @@ class HelpPage extends React.PureComponent {
|
|||
render() {
|
||||
let ver, osName, platform, newVerLink;
|
||||
|
||||
const { navigate, user } = this.props;
|
||||
const { doAuth, user } = this.props;
|
||||
|
||||
if (this.state.versionInfo) {
|
||||
ver = this.state.versionInfo;
|
||||
|
@ -119,7 +119,7 @@ class HelpPage extends React.PureComponent {
|
|||
<p>{__("Did you find something wrong?")}</p>
|
||||
<p>
|
||||
<Link
|
||||
onClick={() => navigate("report")}
|
||||
navigate="/report"
|
||||
label={__("Submit a Bug Report")}
|
||||
icon="icon-bug"
|
||||
button="alt"
|
||||
|
@ -143,7 +143,7 @@ class HelpPage extends React.PureComponent {
|
|||
</p>
|
||||
: <p>{__("Your copy of LBRY is up to date.")}</p>}
|
||||
{this.state.uiVersion && ver
|
||||
? <table className="table-standard">
|
||||
? <table className="table-standard table-stretch table-standard--definition-list">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{__("App")}</th>
|
||||
|
@ -162,7 +162,21 @@ class HelpPage extends React.PureComponent {
|
|||
<td>
|
||||
{user && user.primary_email
|
||||
? user.primary_email
|
||||
: <span className="empty">{__("none")}</span>}
|
||||
: <span>
|
||||
<span className="empty">{__("none")} </span>
|
||||
(<Link
|
||||
onClick={() => doAuth()}
|
||||
label={__("set email")}
|
||||
/>)
|
||||
</span>}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{__("Reward Eligible")}</th>
|
||||
<td>
|
||||
{user && user.is_reward_approved
|
||||
? <Icon icon="icon-check" />
|
||||
: <Icon icon="icon-ban" />}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
19
ui/js/page/invite/index.js
Normal file
19
ui/js/page/invite/index.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import InvitePage from "./view";
|
||||
import { doFetchInviteStatus } from "actions/user";
|
||||
import {
|
||||
selectUserInviteStatusFailed,
|
||||
selectUserInviteStatusIsPending,
|
||||
} from "selectors/user";
|
||||
|
||||
const select = state => ({
|
||||
isFailed: selectUserInviteStatusFailed(state),
|
||||
isPending: selectUserInviteStatusIsPending(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
fetchInviteStatus: () => dispatch(doFetchInviteStatus()),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(InvitePage);
|
32
ui/js/page/invite/view.jsx
Normal file
32
ui/js/page/invite/view.jsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import React from "react";
|
||||
import { BusyMessage } from "component/common";
|
||||
import SubHeader from "component/subHeader";
|
||||
import InviteNew from "component/inviteNew";
|
||||
import InviteList from "component/inviteList";
|
||||
|
||||
class InvitePage extends React.PureComponent {
|
||||
componentWillMount() {
|
||||
this.props.fetchInviteStatus();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isPending, isFailed } = this.props;
|
||||
|
||||
return (
|
||||
<main className="main--single-column">
|
||||
<SubHeader />
|
||||
{isPending &&
|
||||
<BusyMessage message={__("Checking your invite status")} />}
|
||||
{!isPending &&
|
||||
isFailed &&
|
||||
<span className="empty">
|
||||
{__("Failed to retrieve invite status.")}
|
||||
</span>}
|
||||
{!isPending && !isFailed && <InviteNew />}
|
||||
{!isPending && !isFailed && <InviteList />}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default InvitePage;
|
|
@ -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,
|
||||
|
@ -16,10 +16,12 @@ import {
|
|||
doCreateChannel,
|
||||
doPublish,
|
||||
} from "actions/content";
|
||||
import { selectBalance } from "selectors/wallet";
|
||||
import rewards from "rewards";
|
||||
import PublishPage from "./view";
|
||||
|
||||
const select = state => ({
|
||||
balance: selectBalance(state),
|
||||
myClaims: selectMyClaims(state),
|
||||
fetchingChannels: selectFetchingMyChannels(state),
|
||||
channels: selectMyChannelClaims(state),
|
||||
|
|
5
ui/js/page/receiveCredits/index.js
Normal file
5
ui/js/page/receiveCredits/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import ReceiveCreditsPage from "./view";
|
||||
|
||||
export default connect(null, null)(ReceiveCreditsPage);
|
34
ui/js/page/receiveCredits/view.jsx
Normal file
34
ui/js/page/receiveCredits/view.jsx
Normal file
|
@ -0,0 +1,34 @@
|
|||
import React from "react";
|
||||
import SubHeader from "component/subHeader";
|
||||
import Link from "component/link";
|
||||
import WalletAddress from "component/walletAddress";
|
||||
|
||||
const ReceiveCreditsPage = props => {
|
||||
return (
|
||||
<main className="main--single-column">
|
||||
<SubHeader />
|
||||
<WalletAddress />
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("Where To Find Credits")}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<p>
|
||||
{
|
||||
"LBRY credits can be purchased on exchanges, earned for contributions, for mining, and more."
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
<Link
|
||||
button="alt"
|
||||
href="https://lbry.io/faq/earn-credits"
|
||||
label={__("Read More")}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReceiveCreditsPage;
|
|
@ -1,23 +1,18 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
makeSelectRewardByType,
|
||||
selectFetchingRewards,
|
||||
selectRewards,
|
||||
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 rewards from "rewards";
|
||||
import RewardsPage from "./view";
|
||||
|
||||
const select = (state, props) => {
|
||||
const selectReward = makeSelectRewardByType();
|
||||
|
||||
return {
|
||||
fetching: selectFetchingRewards(state),
|
||||
rewards: selectRewards(state),
|
||||
newUserReward: selectReward(state, { reward_type: rewards.TYPE_NEW_USER }),
|
||||
rewards: selectUnclaimedRewards(state),
|
||||
user: selectUser(state),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,31 +1,9 @@
|
|||
import React from "react";
|
||||
import { BusyMessage, CreditAmount, Icon } from "component/common";
|
||||
import { BusyMessage } from "component/common";
|
||||
import RewardListClaimed from "component/rewardListClaimed";
|
||||
import RewardTile from "component/rewardTile";
|
||||
import SubHeader from "component/subHeader";
|
||||
import Link from "component/link";
|
||||
import RewardLink from "component/rewardLink";
|
||||
|
||||
const RewardTile = props => {
|
||||
const { reward } = props;
|
||||
|
||||
const claimed = !!reward.transaction_id;
|
||||
|
||||
return (
|
||||
<section className="card">
|
||||
<div className="card__inner">
|
||||
<div className="card__title-primary">
|
||||
<CreditAmount amount={reward.reward_amount} />
|
||||
<h3>{reward.reward_title}</h3>
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
{claimed
|
||||
? <span><Icon icon="icon-check" /> {__("Reward claimed.")}</span>
|
||||
: <RewardLink reward_type={reward.reward_type} />}
|
||||
</div>
|
||||
<div className="card__content">{reward.reward_description}</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
class RewardsPage extends React.PureComponent {
|
||||
componentDidMount() {
|
||||
|
@ -44,32 +22,8 @@ class RewardsPage extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { doAuth, fetching, navigate, rewards, user } = this.props;
|
||||
|
||||
let content, cardHeader;
|
||||
|
||||
if (fetching) {
|
||||
content = (
|
||||
<div className="card__content">
|
||||
<BusyMessage message={__("Fetching rewards")} />
|
||||
</div>
|
||||
);
|
||||
} else if (rewards.length > 0) {
|
||||
content = (
|
||||
<div>
|
||||
{rewards.map(reward =>
|
||||
<RewardTile key={reward.reward_type} reward={reward} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<div className="card__content empty">
|
||||
{__("Failed to load rewards.")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
renderPageHeader() {
|
||||
const { doAuth, navigate, user } = this.props;
|
||||
|
||||
if (user && !user.is_reward_approved) {
|
||||
if (
|
||||
|
@ -77,20 +31,27 @@ class RewardsPage extends React.PureComponent {
|
|||
!user.has_verified_email ||
|
||||
!user.is_identity_verified
|
||||
) {
|
||||
cardHeader = (
|
||||
<div>
|
||||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("Humans Only")}</h3>
|
||||
</div>
|
||||
<div className="card__content empty">
|
||||
<p>
|
||||
{__("Only verified accounts are eligible to earn rewards.")}
|
||||
{__("Rewards are for human beings only.")}
|
||||
{" "}
|
||||
{__(
|
||||
"You'll have to prove you're one of us before you can claim any rewards."
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<Link onClick={doAuth} button="primary" label="Become Verified" />
|
||||
<Link onClick={doAuth} button="primary" label="Prove Humanity" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
} else {
|
||||
cardHeader = (
|
||||
return (
|
||||
<div className="card__content">
|
||||
<p>
|
||||
{__(
|
||||
|
@ -122,25 +83,52 @@ class RewardsPage extends React.PureComponent {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderUnclaimedRewards() {
|
||||
const { fetching, rewards, user } = this.props;
|
||||
|
||||
if (fetching) {
|
||||
return (
|
||||
<div className="card__content">
|
||||
<BusyMessage message={__("Fetching rewards")} />
|
||||
</div>
|
||||
);
|
||||
} else if (user === null) {
|
||||
cardHeader = (
|
||||
<div>
|
||||
<div className="card__content empty">
|
||||
<p>
|
||||
{__(
|
||||
"This application is unable to earn rewards due to an authentication failure."
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
return (
|
||||
<div className="card__content empty">
|
||||
<p>
|
||||
{__(
|
||||
"This application is unable to earn rewards due to an authentication failure."
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
} else if (!rewards || rewards.length <= 0) {
|
||||
return (
|
||||
<div className="card__content empty">
|
||||
{__("Failed to load rewards.")}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className="card-grid">
|
||||
{rewards.map(reward =>
|
||||
<RewardTile key={reward.reward_type} reward={reward} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<main className="main--single-column">
|
||||
<SubHeader />
|
||||
{cardHeader && <section className="card">{cardHeader}</section>}
|
||||
{content}
|
||||
{this.renderPageHeader()}
|
||||
{this.renderUnclaimedRewards()}
|
||||
{<RewardListClaimed />}
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 => ({
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue