Setup ESLint and Prettier and apply changes to sources #891
298 changed files with 6769 additions and 7403 deletions
34
.eslintrc.json
Normal file
34
.eslintrc.json
Normal file
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"plugins": [
|
||||
"flowtype"
|
||||
],
|
||||
"extends": [
|
||||
"airbnb",
|
||||
"plugin:import/electron",
|
||||
"plugin:flowtype/recommended",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"webpack": {
|
||||
"config": "webpack.renderer.additions.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"globals": {
|
||||
"__static": true,
|
||||
"staticResourcesPath": true,
|
||||
"__": true,
|
||||
"__n": true,
|
||||
"app": true
|
||||
},
|
||||
"rules": {
|
||||
"import/no-commonjs": 1,
|
||||
"import/no-amd": 1
|
||||
}
|
||||
}
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -12,6 +12,7 @@
|
|||
/lbry-app
|
||||
/lbry-venv
|
||||
/static/daemon/lbrynet*
|
||||
/static/locales
|
||||
/daemon/build
|
||||
/daemon/venv
|
||||
/daemon/requirements.txt
|
||||
|
|
12
.lintstagedrc
Normal file
12
.lintstagedrc
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"linters": {
|
||||
"src/**/*.{js,jsx,scss,json}": [
|
||||
"prettier --write",
|
||||
"git add"
|
||||
],
|
||||
"src/**/*.{js,jsx}": [
|
||||
"eslint --fix",
|
||||
"git add"
|
||||
]
|
||||
}
|
||||
}
|
5
.prettierrc.json
Normal file
5
.prettierrc.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"trailingComma": "es5",
|
||||
"printWidth": 100,
|
||||
"singleQuote": true
|
||||
}
|
14
README.md
14
README.md
|
@ -32,9 +32,9 @@ Run `yarn dev`
|
|||
|
||||
This will set up a server that will automatically compile any changes made inside `src\` folder and automatically reload the app without losing the state.
|
||||
|
||||
### Packaging
|
||||
### Build
|
||||
|
||||
Run `yarn dist`
|
||||
Run `yarn build`
|
||||
|
||||
We use [electron-builder](https://github.com/electron-userland/electron-builder)
|
||||
to create distributable packages.
|
||||
|
@ -60,16 +60,16 @@ exit
|
|||
python -m pip install -r build\requirements.txt
|
||||
npm install -g yarn
|
||||
yarn install
|
||||
yarn dist
|
||||
yarn build
|
||||
```
|
||||
3. Download the lbry daemon and cli [binaries](https://github.com/lbryio/lbry/releases) and place them in `dist\`
|
||||
|
||||
### Building lbry-app
|
||||
Run `yarn dist`
|
||||
3. Download the lbry daemon and cli [binaries](https://github.com/lbryio/lbry/releases) and place them in `static\daemon`
|
||||
|
||||
### Ongoing Development
|
||||
Run `yarn dev`
|
||||
|
||||
### Build
|
||||
Run `yarn build`
|
||||
|
||||
This will set up a server that will automatically compile any changes made inside `src\` folder and automatically reload the app without losing the state.
|
||||
|
||||
## Internationalization
|
||||
|
|
|
@ -26,7 +26,7 @@ dir static\daemon\ # verify that daemon binary is there
|
|||
rm daemon.zip
|
||||
|
||||
# build electron app
|
||||
yarn dist
|
||||
yarn build
|
||||
dir dist # verify that binary was built/named correctly
|
||||
|
||||
python build\upload_assets.py
|
||||
|
|
|
@ -77,7 +77,7 @@ if [ "$FULL_BUILD" == "true" ]; then
|
|||
security unlock-keychain -p ${KEYCHAIN_PASSWORD} osx-build.keychain
|
||||
fi
|
||||
|
||||
yarn dist
|
||||
yarn build
|
||||
|
||||
# electron-build has a publish feature, but I had a hard time getting
|
||||
# it to reliably work and it also seemed difficult to configure. Not proud of
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
var extract = require("i18n-extract");
|
||||
const extract = require("i18n-extract");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
var dir = __dirname + "/../../dist/locales";
|
||||
var path = dir + "/en.json";
|
||||
const outputDir = `${__dirname}/../static/locales`;
|
||||
const outputPath = `${outputDir}/en.json`;
|
||||
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir);
|
||||
if (!fs.existsSync(outputDir)) {
|
||||
fs.mkdirSync(outputDir);
|
||||
}
|
||||
|
||||
fs.writeFile(path, "{}", "utf8", function(err) {
|
||||
fs.writeFile(outputPath, "{}", "utf8", err => {
|
||||
if (err) {
|
||||
return console.log(err);
|
||||
}
|
||||
var enLocale = require(path);
|
||||
const enLocale = require(outputPath);
|
||||
|
||||
const keys = extract.extractFromFiles(["js/**/*.{js,jsx}"], {
|
||||
const keys = extract.extractFromFiles("src/**/*.{js,jsx}", {
|
||||
marker: "__",
|
||||
});
|
||||
|
||||
|
@ -22,21 +23,21 @@ fs.writeFile(path, "{}", "utf8", function(err) {
|
|||
reports = reports.concat(extract.findMissing(enLocale, keys));
|
||||
|
||||
if (reports.length > 0) {
|
||||
fs.readFile(path, "utf8", function readFileCallback(err, data) {
|
||||
fs.readFile(outputPath, "utf8", (err, data) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
} else {
|
||||
localeObj = JSON.parse(data);
|
||||
|
||||
for (var i = 0; i < reports.length; i++) {
|
||||
for (let i = 0; i < reports.length; i++) {
|
||||
// no need to care for other types than MISSING because starting file will always be empty
|
||||
if (reports[i].type === "MISSING") {
|
||||
localeObj[reports[i].key] = reports[i].key;
|
||||
}
|
||||
}
|
||||
|
||||
var json = JSON.stringify(localeObj, null, "\t"); //convert it back to json-string
|
||||
fs.writeFile(path, json, "utf8", function callback(err) {
|
||||
const json = JSON.stringify(localeObj, null, "\t"); // convert it back to json-string
|
||||
fs.writeFile(outputPath, json, "utf8", err => {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
31
package.json
31
package.json
|
@ -14,21 +14,23 @@
|
|||
"name": "LBRY Inc.",
|
||||
"email": "hello@lbry.io"
|
||||
},
|
||||
"main": "src/main/index.js",
|
||||
"scripts": {
|
||||
"extract-langs": "node src/renderer/extractLocals.js",
|
||||
"extract-langs": "node build/extractLocals.js",
|
||||
"dev": "electron-webpack dev",
|
||||
"compile": "electron-webpack && yarn extract-langs",
|
||||
"dist": "yarn compile && electron-builder",
|
||||
"dist:dir": "yarn dist -- --dir -c.compression=store -c.mac.identity=null",
|
||||
"build": "yarn compile && electron-builder build",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"precommit": "lint-staged"
|
||||
"precommit": "lint-staged",
|
||||
"lint": "eslint 'src/**/*.{js,jsx}' --fix",
|
||||
"pretty-print": "prettier 'src/**/*.{js,jsx,scss,json}' --write"
|
||||
},
|
||||
"main": "src/main/index.js",
|
||||
"keywords": [
|
||||
"lbry"
|
||||
],
|
||||
"dependencies": {
|
||||
"amplitude-js": "^4.0.0",
|
||||
"bluebird": "^3.5.1",
|
||||
"classnames": "^2.2.5",
|
||||
"electron-dl": "^1.6.0",
|
||||
"formik": "^0.10.4",
|
||||
|
@ -64,18 +66,27 @@
|
|||
"y18n": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^8.0.3",
|
||||
"babel-plugin-module-resolver": "^3.0.0",
|
||||
"babel-plugin-react-require": "^3.0.0",
|
||||
"babel-polyfill": "^6.20.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-preset-stage-2": "^6.18.0",
|
||||
"bluebird": "^3.5.1",
|
||||
"devtron": "^1.4.0",
|
||||
"electron": "^1.7.9",
|
||||
"electron-builder": "^19.48.2",
|
||||
"electron-builder": "^19.49.0",
|
||||
"electron-devtools-installer": "^2.2.1",
|
||||
"electron-webpack": "^1.11.0",
|
||||
"eslint": "^4.13.1",
|
||||
"eslint-config-airbnb": "^16.1.0",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-import-resolver-webpack": "^0.8.3",
|
||||
"eslint-plugin-flowtype": "^2.40.1",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.3",
|
||||
"eslint-plugin-prettier": "^2.4.0",
|
||||
"eslint-plugin-react": "^7.5.1",
|
||||
"flow-babel-webpack-plugin": "^1.1.0",
|
||||
"flow-bin": "^0.61.0",
|
||||
"flow-typed": "^2.2.3",
|
||||
|
@ -98,12 +109,6 @@
|
|||
"yarn": "^1.3"
|
||||
},
|
||||
"license": "MIT",
|
||||
"lint-staged": {
|
||||
"src/**/*.{js,jsx}": [
|
||||
"prettier --trailing-comma es5 --write",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"lbrySettings": {
|
||||
"lbrynetDaemonVersion": "0.18.0",
|
||||
"lbrynetDaemonUrlTemplate": "https://github.com/lbryio/lbry/releases/download/vDAEMONVER/lbrynet-daemon-vDAEMONVER-OSNAME.zip"
|
||||
|
|
|
@ -1,67 +1,39 @@
|
|||
/* eslint-disable no-console */
|
||||
// Module imports
|
||||
const {
|
||||
app,
|
||||
BrowserWindow,
|
||||
ipcMain,
|
||||
Menu,
|
||||
Tray,
|
||||
globalShortcut,
|
||||
} = require("electron");
|
||||
const path = require("path");
|
||||
const url = require("url");
|
||||
const jayson = require("jayson");
|
||||
const semver = require("semver");
|
||||
const https = require("https");
|
||||
const keytar = require("keytar");
|
||||
// tree-kill has better cross-platform handling of
|
||||
// killing a process. child-process.kill was unreliable
|
||||
const kill = require("tree-kill");
|
||||
const child_process = require("child_process");
|
||||
const assert = require("assert");
|
||||
import Path from 'path';
|
||||
import Url from 'url';
|
||||
import Jayson from 'jayson';
|
||||
import Semver from 'semver';
|
||||
import Https from 'https';
|
||||
import Keytar from 'keytar';
|
||||
import ChildProcess from 'child_process';
|
||||
import Assert from 'assert';
|
||||
import { app, BrowserWindow, globalShortcut, ipcMain, Menu, Tray } from 'electron';
|
||||
import mainMenu from './menu/mainMenu';
|
||||
|
||||
const localVersion = app.getVersion();
|
||||
const setMenu = require("./menu/main-menu.js");
|
||||
export const contextMenu = require("./menu/context-menu");
|
||||
export { contextMenu as Default } from './menu/contextMenu';
|
||||
|
||||
// Debug configs
|
||||
const isDevelopment = process.env.NODE_ENV === "development";
|
||||
if (isDevelopment) {
|
||||
try {
|
||||
const {
|
||||
default: installExtension,
|
||||
REACT_DEVELOPER_TOOLS,
|
||||
REDUX_DEVTOOLS,
|
||||
} = require("electron-devtools-installer");
|
||||
app.on("ready", () => {
|
||||
[REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS].forEach(extension => {
|
||||
installExtension(extension)
|
||||
.then(name => console.log(`Added Extension: ${name}`))
|
||||
.catch(err => console.log("An error occurred: ", err));
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
const isDevelopment = process.env.NODE_ENV === 'development';
|
||||
|
||||
// Misc constants
|
||||
const LATEST_RELEASE_API_URL =
|
||||
"https://api.github.com/repos/lbryio/lbry-app/releases/latest";
|
||||
const DAEMON_PATH =
|
||||
process.env.LBRY_DAEMON || path.join(__static, "daemon/lbrynet-daemon");
|
||||
const LATEST_RELEASE_API_URL = 'https://api.github.com/repos/lbryio/lbry-app/releases/latest';
|
||||
const DAEMON_PATH = process.env.LBRY_DAEMON || Path.join(__static, 'daemon/lbrynet-daemon');
|
||||
const rendererUrl = isDevelopment
|
||||
? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`
|
||||
: `file://${__dirname}/index.html`;
|
||||
|
||||
let client = jayson.client.http({
|
||||
host: "localhost",
|
||||
const client = Jayson.client.http({
|
||||
host: 'localhost',
|
||||
port: 5279,
|
||||
path: "/",
|
||||
path: '/',
|
||||
timeout: 1000,
|
||||
});
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let win;
|
||||
let rendererWindow;
|
||||
// Also keep the daemon subprocess alive
|
||||
let daemonSubprocess;
|
||||
|
||||
|
@ -94,11 +66,10 @@ function processRequestedUri(uri) {
|
|||
// lbry://channel/#claimid. We remove the slash here as well.
|
||||
// On Linux and Mac, we just return the URI as given.
|
||||
|
||||
if (process.platform === "win32") {
|
||||
return uri.replace(/\/$/, "").replace("/#", "#");
|
||||
} else {
|
||||
return uri;
|
||||
if (process.platform === 'win32') {
|
||||
return uri.replace(/\/$/, '').replace('/#', '#');
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -109,226 +80,21 @@ function processRequestedUri(uri) {
|
|||
function openItem(fullPath) {
|
||||
const subprocOptions = {
|
||||
detached: true,
|
||||
stdio: "ignore",
|
||||
stdio: 'ignore',
|
||||
};
|
||||
|
||||
let child;
|
||||
if (process.platform === "darwin") {
|
||||
child = child_process.spawn("open", [fullPath], subprocOptions);
|
||||
} else if (process.platform === "linux") {
|
||||
child = child_process.spawn("xdg-open", [fullPath], subprocOptions);
|
||||
} else if (process.platform === "win32") {
|
||||
child = child_process.spawn(
|
||||
fullPath,
|
||||
Object.assign({}, subprocOptions, { shell: true })
|
||||
);
|
||||
if (process.platform === 'darwin') {
|
||||
child = ChildProcess.spawn('open', [fullPath], subprocOptions);
|
||||
} else if (process.platform === 'linux') {
|
||||
child = ChildProcess.spawn('xdg-open', [fullPath], subprocOptions);
|
||||
} else if (process.platform === 'win32') {
|
||||
child = ChildProcess.spawn(fullPath, Object.assign({}, subprocOptions, { shell: true }));
|
||||
}
|
||||
|
||||
// Causes child process reference to be garbage collected, allowing main process to exit
|
||||
child.unref();
|
||||
}
|
||||
|
||||
function getPidsForProcessName(name) {
|
||||
if (process.platform === "win32") {
|
||||
const tasklistOut = child_process.execSync(
|
||||
`tasklist /fi "Imagename eq ${name}.exe" /nh`,
|
||||
{ encoding: "utf8" }
|
||||
);
|
||||
if (tasklistOut.startsWith("INFO")) {
|
||||
return [];
|
||||
} else {
|
||||
return tasklistOut.match(/[^\r\n]+/g).map(line => line.split(/\s+/)[1]); // Second column of every non-empty line
|
||||
}
|
||||
} else {
|
||||
const pgrepOut = child_process.spawnSync("pgrep", ["-x", name], {
|
||||
encoding: "utf8",
|
||||
}).stdout;
|
||||
return pgrepOut.match(/\d+/g);
|
||||
}
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
// Disable renderer process's webSecurity on development to enable CORS.
|
||||
win = isDevelopment
|
||||
? new BrowserWindow({
|
||||
backgroundColor: "#155B4A",
|
||||
minWidth: 800,
|
||||
minHeight: 600,
|
||||
webPreferences: { webSecurity: false },
|
||||
})
|
||||
: new BrowserWindow({
|
||||
backgroundColor: "#155B4A",
|
||||
minWidth: 800,
|
||||
minHeight: 600,
|
||||
});
|
||||
|
||||
win.webContents.session.setUserAgent(`LBRY/${localVersion}`);
|
||||
|
||||
win.maximize();
|
||||
if (isDevelopment) {
|
||||
win.webContents.openDevTools();
|
||||
}
|
||||
win.loadURL(rendererUrl);
|
||||
if (openUri) {
|
||||
// We stored and received a URI that an external app requested before we had a window object
|
||||
win.webContents.on("did-finish-load", () => {
|
||||
win.webContents.send("open-uri-requested", openUri, true);
|
||||
});
|
||||
}
|
||||
|
||||
win.removeAllListeners();
|
||||
|
||||
win.on("close", function(event) {
|
||||
if (minimize) {
|
||||
event.preventDefault();
|
||||
win.hide();
|
||||
}
|
||||
});
|
||||
|
||||
win.on("closed", () => {
|
||||
win = null;
|
||||
});
|
||||
|
||||
win.on("hide", () => {
|
||||
// Checks what to show in the tray icon menu
|
||||
if (minimize) updateTray();
|
||||
});
|
||||
|
||||
win.on("show", () => {
|
||||
// Checks what to show in the tray icon menu
|
||||
if (minimize) updateTray();
|
||||
});
|
||||
|
||||
win.on("blur", () => {
|
||||
// Checks what to show in the tray icon menu
|
||||
if (minimize) updateTray();
|
||||
|
||||
// Unregisters Alt+F4 shortcut
|
||||
globalShortcut.unregister("Alt+F4");
|
||||
});
|
||||
|
||||
win.on("focus", () => {
|
||||
// Checks what to show in the tray icon menu
|
||||
if (minimize) updateTray();
|
||||
|
||||
// Registers shortcut for closing(quitting) the app
|
||||
globalShortcut.register("Alt+F4", () => safeQuit());
|
||||
|
||||
win.webContents.send("window-is-focused", null);
|
||||
});
|
||||
|
||||
// Menu bar
|
||||
win.setAutoHideMenuBar(true);
|
||||
win.setMenuBarVisibility(isDevelopment);
|
||||
setMenu();
|
||||
}
|
||||
|
||||
function createTray() {
|
||||
// Minimize to tray logic follows:
|
||||
// Set the tray icon
|
||||
let iconPath;
|
||||
if (process.platform === "darwin") {
|
||||
// Using @2x for mac retina screens so the icon isn't blurry
|
||||
// file name needs to include "Template" at the end for dark menu bar
|
||||
iconPath = path.join(__static, "/img/fav/macTemplate@2x.png");
|
||||
} else {
|
||||
iconPath = path.join(__static, "/img/fav/32x32.png");
|
||||
}
|
||||
|
||||
tray = new Tray(iconPath);
|
||||
tray.setToolTip("LBRY App");
|
||||
tray.setTitle("LBRY");
|
||||
tray.on("double-click", () => {
|
||||
win.show();
|
||||
});
|
||||
}
|
||||
|
||||
// This needs to be done as for linux the context menu doesn't update automatically(docs)
|
||||
function updateTray() {
|
||||
let contextMenu = Menu.buildFromTemplate(getMenuTemplate());
|
||||
if (tray) {
|
||||
tray.setContextMenu(contextMenu);
|
||||
} else {
|
||||
console.log("How did update tray get called without a tray?");
|
||||
}
|
||||
}
|
||||
|
||||
function getMenuTemplate() {
|
||||
return [
|
||||
getToggleItem(),
|
||||
{
|
||||
label: "Quit",
|
||||
click: () => safeQuit(),
|
||||
},
|
||||
];
|
||||
|
||||
function getToggleItem() {
|
||||
if (win.isVisible() && win.isFocused()) {
|
||||
return {
|
||||
label: "Hide LBRY App",
|
||||
click: () => win.hide(),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
label: "Show LBRY App",
|
||||
click: () => win.show(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleOpenUriRequested(uri) {
|
||||
if (!win) {
|
||||
// Window not created yet, so store up requested URI for when it is
|
||||
openUri = processRequestedUri(uri);
|
||||
} else {
|
||||
if (win.isMinimized()) {
|
||||
win.restore();
|
||||
} else if (!win.isVisible()) {
|
||||
win.show();
|
||||
}
|
||||
|
||||
win.focus();
|
||||
win.webContents.send("open-uri-requested", processRequestedUri(uri));
|
||||
}
|
||||
}
|
||||
|
||||
function handleDaemonSubprocessExited() {
|
||||
console.log("The daemon has exited.");
|
||||
daemonSubprocess = null;
|
||||
if (!daemonStopRequested) {
|
||||
// We didn't request to stop the daemon, so display a
|
||||
// warning and schedule a quit.
|
||||
//
|
||||
// TODO: maybe it would be better to restart the daemon?
|
||||
if (win) {
|
||||
console.log("Did not request daemon stop, so quitting in 5 seconds.");
|
||||
win.loadURL(`file://${__static}/warning.html`);
|
||||
setTimeout(quitNow, 5000);
|
||||
} else {
|
||||
console.log("Did not request daemon stop, so quitting.");
|
||||
quitNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function launchDaemon() {
|
||||
assert(!daemonSubprocess, "Tried to launch daemon twice");
|
||||
|
||||
console.log("Launching daemon:", DAEMON_PATH);
|
||||
daemonSubprocess = child_process.spawn(DAEMON_PATH);
|
||||
// Need to handle the data event instead of attaching to
|
||||
// process.stdout because the latter doesn't work. I believe on
|
||||
// windows it buffers stdout and we don't get any meaningful output
|
||||
daemonSubprocess.stdout.on("data", buf => {
|
||||
console.log(String(buf).trim());
|
||||
});
|
||||
daemonSubprocess.stderr.on("data", buf => {
|
||||
console.log(String(buf).trim());
|
||||
});
|
||||
daemonSubprocess.on("exit", handleDaemonSubprocessExited);
|
||||
}
|
||||
|
||||
/*
|
||||
* Quits by first killing the daemon, the calling quitting for real.
|
||||
*/
|
||||
|
@ -337,6 +103,155 @@ export function safeQuit() {
|
|||
app.quit();
|
||||
}
|
||||
|
||||
function getMenuTemplate() {
|
||||
function getToggleItem() {
|
||||
if (rendererWindow.isVisible() && rendererWindow.isFocused()) {
|
||||
return {
|
||||
label: 'Hide LBRY App',
|
||||
click: () => rendererWindow.hide(),
|
||||
};
|
||||
}
|
||||
return {
|
||||
label: 'Show LBRY App',
|
||||
click: () => rendererWindow.show(),
|
||||
};
|
||||
}
|
||||
|
||||
return [
|
||||
getToggleItem(),
|
||||
{
|
||||
label: 'Quit',
|
||||
click: () => safeQuit(),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// This needs to be done as for linux the context menu doesn't update automatically(docs)
|
||||
function updateTray() {
|
||||
const trayContextMenu = Menu.buildFromTemplate(getMenuTemplate());
|
||||
if (tray) {
|
||||
tray.setContextMenu(trayContextMenu);
|
||||
} else {
|
||||
console.log('How did update tray get called without a tray?');
|
||||
}
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
// Disable renderer process's webSecurity on development to enable CORS.
|
||||
let windowConfiguration = {
|
||||
backgroundColor: '#155B4A',
|
||||
minWidth: 800,
|
||||
minHeight: 600,
|
||||
autoHideMenuBar: true,
|
||||
};
|
||||
|
||||
windowConfiguration = isDevelopment
|
||||
? {
|
||||
...windowConfiguration,
|
||||
webPreferences: {
|
||||
webSecurity: false,
|
||||
},
|
||||
}
|
||||
: windowConfiguration;
|
||||
|
||||
let window = new BrowserWindow(windowConfiguration);
|
||||
|
||||
window.webContents.session.setUserAgent(`LBRY/${localVersion}`);
|
||||
|
||||
window.maximize();
|
||||
if (isDevelopment) {
|
||||
window.webContents.openDevTools();
|
||||
}
|
||||
window.loadURL(rendererUrl);
|
||||
if (openUri) {
|
||||
// We stored and received a URI that an external app requested before we had a window object
|
||||
window.webContents.on('did-finish-load', () => {
|
||||
window.webContents.send('open-uri-requested', openUri, true);
|
||||
});
|
||||
}
|
||||
|
||||
window.removeAllListeners();
|
||||
|
||||
window.on('close', event => {
|
||||
if (minimize) {
|
||||
event.preventDefault();
|
||||
window.hide();
|
||||
}
|
||||
});
|
||||
|
||||
window.on('closed', () => {
|
||||
window = null;
|
||||
});
|
||||
|
||||
window.on('hide', () => {
|
||||
// Checks what to show in the tray icon menu
|
||||
if (minimize) updateTray();
|
||||
});
|
||||
|
||||
window.on('show', () => {
|
||||
// Checks what to show in the tray icon menu
|
||||
if (minimize) updateTray();
|
||||
});
|
||||
|
||||
window.on('blur', () => {
|
||||
// Checks what to show in the tray icon menu
|
||||
if (minimize) updateTray();
|
||||
|
||||
// Unregisters Alt+F4 shortcut
|
||||
globalShortcut.unregister('Alt+F4');
|
||||
});
|
||||
|
||||
window.on('focus', () => {
|
||||
// Checks what to show in the tray icon menu
|
||||
if (minimize) updateTray();
|
||||
|
||||
// Registers shortcut for closing(quitting) the app
|
||||
globalShortcut.register('Alt+F4', () => safeQuit());
|
||||
|
||||
window.webContents.send('window-is-focused', null);
|
||||
});
|
||||
|
||||
mainMenu();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
function createTray() {
|
||||
// Minimize to tray logic follows:
|
||||
// Set the tray icon
|
||||
let iconPath;
|
||||
if (process.platform === 'darwin') {
|
||||
// Using @2x for mac retina screens so the icon isn't blurry
|
||||
// file name needs to include "Template" at the end for dark menu bar
|
||||
iconPath = Path.join(__static, '/img/fav/macTemplate@2x.png');
|
||||
} else {
|
||||
iconPath = Path.join(__static, '/img/fav/32x32.png');
|
||||
}
|
||||
|
||||
tray = new Tray(iconPath);
|
||||
tray.setToolTip('LBRY App');
|
||||
tray.setTitle('LBRY');
|
||||
tray.on('double-click', () => {
|
||||
rendererWindow.show();
|
||||
});
|
||||
}
|
||||
|
||||
function handleOpenUriRequested(uri) {
|
||||
if (!rendererWindow) {
|
||||
// Window not created yet, so store up requested URI for when it is
|
||||
openUri = processRequestedUri(uri);
|
||||
} else {
|
||||
if (rendererWindow.isMinimized()) {
|
||||
rendererWindow.restore();
|
||||
} else if (!rendererWindow.isVisible()) {
|
||||
rendererWindow.show();
|
||||
}
|
||||
|
||||
rendererWindow.focus();
|
||||
rendererWindow.webContents.send('open-uri-requested', processRequestedUri(uri));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Quits without any preparation. When a quit is requested (either through the
|
||||
* interface or through app.quit()), we abort the quit, try to shut down the daemon,
|
||||
|
@ -347,16 +262,52 @@ function quitNow() {
|
|||
safeQuit();
|
||||
}
|
||||
|
||||
function handleDaemonSubprocessExited() {
|
||||
console.log('The daemon has exited.');
|
||||
daemonSubprocess = null;
|
||||
if (!daemonStopRequested) {
|
||||
// We didn't request to stop the daemon, so display a
|
||||
// warning and schedule a quit.
|
||||
//
|
||||
// TODO: maybe it would be better to restart the daemon?
|
||||
if (rendererWindow) {
|
||||
console.log('Did not request daemon stop, so quitting in 5 seconds.');
|
||||
rendererWindow.loadURL(`file://${__static}/warning.html`);
|
||||
setTimeout(quitNow, 5000);
|
||||
} else {
|
||||
console.log('Did not request daemon stop, so quitting.');
|
||||
quitNow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function launchDaemon() {
|
||||
Assert(!daemonSubprocess, 'Tried to launch daemon twice');
|
||||
|
||||
console.log('Launching daemon:', DAEMON_PATH);
|
||||
daemonSubprocess = ChildProcess.spawn(DAEMON_PATH);
|
||||
// Need to handle the data event instead of attaching to
|
||||
// process.stdout because the latter doesn't work. I believe on
|
||||
// windows it buffers stdout and we don't get any meaningful output
|
||||
daemonSubprocess.stdout.on('data', buf => {
|
||||
console.log(String(buf).trim());
|
||||
});
|
||||
daemonSubprocess.stderr.on('data', buf => {
|
||||
console.log(String(buf).trim());
|
||||
});
|
||||
daemonSubprocess.on('exit', handleDaemonSubprocessExited);
|
||||
}
|
||||
|
||||
const isSecondaryInstance = app.makeSingleInstance(argv => {
|
||||
if (argv.length >= 2) {
|
||||
handleOpenUriRequested(argv[1]); // This will handle restoring and focusing the window
|
||||
} else if (win) {
|
||||
if (win.isMinimized()) {
|
||||
win.restore();
|
||||
} else if (!win.isVisible()) {
|
||||
win.show();
|
||||
} else if (rendererWindow) {
|
||||
if (rendererWindow.isMinimized()) {
|
||||
rendererWindow.restore();
|
||||
} else if (!rendererWindow.isVisible()) {
|
||||
rendererWindow.show();
|
||||
}
|
||||
win.focus();
|
||||
rendererWindow.focus();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -368,126 +319,44 @@ if (isSecondaryInstance) {
|
|||
function launchDaemonIfNotRunning() {
|
||||
// Check if the daemon is already running. If we get
|
||||
// an error its because its not running
|
||||
console.log("Checking for lbrynet daemon");
|
||||
client.request("status", [], function(err, res) {
|
||||
console.log('Checking for lbrynet daemon');
|
||||
client.request('status', [], err => {
|
||||
if (err) {
|
||||
console.log("lbrynet daemon needs to be launched");
|
||||
console.log('lbrynet daemon needs to be launched');
|
||||
launchDaemon();
|
||||
} else {
|
||||
console.log("lbrynet daemon is already running");
|
||||
console.log('lbrynet daemon is already running');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Last resort for killing unresponsive daemon instances.
|
||||
* Looks for any processes called "lbrynet-daemon" and
|
||||
* tries to force kill them.
|
||||
*/
|
||||
function forceKillAllDaemonsAndQuit() {
|
||||
console.log(
|
||||
"Attempting to force kill any running lbrynet-daemon instances..."
|
||||
);
|
||||
|
||||
const daemonPids = getPidsForProcessName("lbrynet-daemon");
|
||||
if (!daemonPids) {
|
||||
console.log("No lbrynet-daemon found running.");
|
||||
quitNow();
|
||||
} else {
|
||||
console.log(
|
||||
`Found ${
|
||||
daemonPids.length
|
||||
} running daemon instances. Attempting to force kill...`
|
||||
);
|
||||
|
||||
for (const pid of daemonPids) {
|
||||
let daemonKillAttemptsComplete = 0;
|
||||
kill(pid, "SIGKILL", err => {
|
||||
daemonKillAttemptsComplete++;
|
||||
if (err) {
|
||||
console.log(
|
||||
`Failed to force kill daemon task with pid ${pid}. Error message: ${
|
||||
err.message
|
||||
}`
|
||||
);
|
||||
} else {
|
||||
console.log(`Force killed daemon task with pid ${pid}.`);
|
||||
}
|
||||
if (daemonKillAttemptsComplete >= daemonPids.length - 1) {
|
||||
quitNow();
|
||||
}
|
||||
});
|
||||
// Taken from webtorrent-desktop
|
||||
function checkLinuxTraySupport(cb) {
|
||||
// Check that we're on Ubuntu (or another debian system) and that we have
|
||||
// libappindicator1.
|
||||
ChildProcess.exec('dpkg --get-selections libappindicator1', (err, stdout) => {
|
||||
if (err) return cb(err);
|
||||
// Unfortunately there's no cleaner way, as far as I can tell, to check
|
||||
// whether a debian package is installed:
|
||||
if (stdout.endsWith('\tinstall\n')) {
|
||||
return cb(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app.setAsDefaultProtocolClient("lbry");
|
||||
|
||||
app.on("ready", function() {
|
||||
launchDaemonIfNotRunning();
|
||||
if (process.platform === "linux") {
|
||||
checkLinuxTraySupport(err => {
|
||||
if (!err) createTray();
|
||||
else minimize = false;
|
||||
});
|
||||
} else {
|
||||
createTray();
|
||||
}
|
||||
createWindow();
|
||||
});
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on("window-all-closed", () => {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== "darwin") {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
app.on("before-quit", event => {
|
||||
if (!readyToQuit) {
|
||||
// We need to shutdown the daemon before we're ready to actually quit. This
|
||||
// event will be triggered re-entrantly once preparation is done.
|
||||
event.preventDefault();
|
||||
shutdownDaemonAndQuit();
|
||||
} else {
|
||||
console.log("Quitting.");
|
||||
}
|
||||
});
|
||||
|
||||
app.on("activate", () => {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (win === null) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
|
||||
if (process.platform === "darwin") {
|
||||
app.on("open-url", (event, uri) => {
|
||||
handleOpenUriRequested(uri);
|
||||
return cb(new Error('debian package not installed'));
|
||||
});
|
||||
} else if (process.argv.length >= 2) {
|
||||
handleOpenUriRequested(process.argv[1]);
|
||||
}
|
||||
|
||||
// When a quit is attempted, this is called. It attempts to shutdown the daemon,
|
||||
// then calls quitNow() to quit for real.
|
||||
function shutdownDaemonAndQuit(evenIfNotStartedByApp = false) {
|
||||
function doShutdown() {
|
||||
console.log("Shutting down daemon");
|
||||
console.log('Shutting down daemon');
|
||||
daemonStopRequested = true;
|
||||
client.request("daemon_stop", [], (err, res) => {
|
||||
client.request('daemon_stop', [], err => {
|
||||
if (err) {
|
||||
console.log(
|
||||
`received error when stopping lbrynet-daemon. Error message: ${
|
||||
err.message
|
||||
}\n`
|
||||
);
|
||||
console.log("You will need to manually kill the daemon.");
|
||||
console.log(`received error when stopping lbrynet-daemon. Error message: ${err.message}\n`);
|
||||
console.log('You will need to manually kill the daemon.');
|
||||
} else {
|
||||
console.log("Successfully stopped daemon via RPC call.");
|
||||
console.log('Successfully stopped daemon via RPC call.');
|
||||
quitNow();
|
||||
}
|
||||
});
|
||||
|
@ -496,7 +365,7 @@ function shutdownDaemonAndQuit(evenIfNotStartedByApp = false) {
|
|||
if (daemonSubprocess) {
|
||||
doShutdown();
|
||||
} else if (!evenIfNotStartedByApp) {
|
||||
console.log("Not killing lbrynet-daemon because app did not start it");
|
||||
console.log('Not killing lbrynet-daemon because app did not start it');
|
||||
quitNow();
|
||||
} else {
|
||||
doShutdown();
|
||||
|
@ -506,111 +375,154 @@ function shutdownDaemonAndQuit(evenIfNotStartedByApp = false) {
|
|||
// If not, we should wait until the daemon is closed before we start the install.
|
||||
}
|
||||
|
||||
// Taken from webtorrent-desktop
|
||||
function checkLinuxTraySupport(cb) {
|
||||
// Check that we're on Ubuntu (or another debian system) and that we have
|
||||
// libappindicator1.
|
||||
child_process.exec("dpkg --get-selections libappindicator1", function(
|
||||
err,
|
||||
stdout
|
||||
) {
|
||||
if (err) return cb(err);
|
||||
// Unfortunately there's no cleaner way, as far as I can tell, to check
|
||||
// whether a debian package is installed:
|
||||
if (stdout.endsWith("\tinstall\n")) {
|
||||
cb(null);
|
||||
} else {
|
||||
cb(new Error("debian package not installed"));
|
||||
}
|
||||
});
|
||||
if (isDevelopment) {
|
||||
import('devtron')
|
||||
.then(({ install }) => {
|
||||
install();
|
||||
console.log('Added Extension: Devtron');
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
import('electron-devtools-installer')
|
||||
.then(({ default: installExtension, REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS }) => {
|
||||
app.on('ready', () => {
|
||||
[REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS].forEach(extension => {
|
||||
installExtension(extension)
|
||||
.then(name => console.log(`Added Extension: ${name}`))
|
||||
.catch(err => console.log('An error occurred: ', err));
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
ipcMain.on("upgrade", (event, installerPath) => {
|
||||
app.on("quit", () => {
|
||||
console.log("Launching upgrade installer at", installerPath);
|
||||
app.setAsDefaultProtocolClient('lbry');
|
||||
|
||||
app.on('ready', () => {
|
||||
launchDaemonIfNotRunning();
|
||||
if (process.platform === 'linux') {
|
||||
checkLinuxTraySupport(err => {
|
||||
if (!err) createTray();
|
||||
else minimize = false;
|
||||
});
|
||||
} else {
|
||||
createTray();
|
||||
}
|
||||
rendererWindow = createWindow();
|
||||
});
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', () => {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
app.on('before-quit', event => {
|
||||
if (!readyToQuit) {
|
||||
// We need to shutdown the daemon before we're ready to actually quit. This
|
||||
// event will be triggered re-entrantly once preparation is done.
|
||||
event.preventDefault();
|
||||
shutdownDaemonAndQuit();
|
||||
} else {
|
||||
console.log('Quitting.');
|
||||
}
|
||||
});
|
||||
|
||||
app.on('activate', () => {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (rendererWindow === null) {
|
||||
createWindow();
|
||||
}
|
||||
});
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
app.on('open-url', (event, uri) => {
|
||||
handleOpenUriRequested(uri);
|
||||
});
|
||||
} else if (process.argv.length >= 2) {
|
||||
handleOpenUriRequested(process.argv[1]);
|
||||
}
|
||||
|
||||
ipcMain.on('upgrade', (event, installerPath) => {
|
||||
app.on('quit', () => {
|
||||
console.log('Launching upgrade installer at', installerPath);
|
||||
// This gets triggered called after *all* other quit-related events, so
|
||||
// we'll only get here if we're fully prepared and quitting for real.
|
||||
openItem(installerPath);
|
||||
});
|
||||
|
||||
if (win) {
|
||||
win.loadURL(`file://${__static}/upgrade.html`);
|
||||
if (rendererWindow) {
|
||||
rendererWindow.loadURL(`file://${__static}/upgrade.html`);
|
||||
}
|
||||
|
||||
shutdownDaemonAndQuit(true);
|
||||
// wait for daemon to shut down before upgrading
|
||||
// what to do if no shutdown in a long time?
|
||||
console.log("Update downloaded to", installerPath);
|
||||
console.log('Update downloaded to', installerPath);
|
||||
console.log(
|
||||
"The app will close, and you will be prompted to install the latest version of LBRY."
|
||||
'The app will close, and you will be prompted to install the latest version of LBRY.'
|
||||
);
|
||||
console.log("After the install is complete, please reopen the app.");
|
||||
console.log('After the install is complete, please reopen the app.');
|
||||
});
|
||||
|
||||
ipcMain.on("version-info-requested", () => {
|
||||
ipcMain.on('version-info-requested', () => {
|
||||
function formatRc(ver) {
|
||||
// Adds dash if needed to make RC suffix semver friendly
|
||||
return ver.replace(/([^-])rc/, "$1-rc");
|
||||
return ver.replace(/([^-])rc/, '$1-rc');
|
||||
}
|
||||
|
||||
let result = "";
|
||||
let result = '';
|
||||
const opts = {
|
||||
headers: {
|
||||
"User-Agent": `LBRY/${localVersion}`,
|
||||
'User-Agent': `LBRY/${localVersion}`,
|
||||
},
|
||||
};
|
||||
|
||||
const req = https.get(
|
||||
Object.assign(opts, url.parse(LATEST_RELEASE_API_URL)),
|
||||
res => {
|
||||
res.on("data", data => {
|
||||
result += data;
|
||||
});
|
||||
res.on("end", () => {
|
||||
const tagName = JSON.parse(result).tag_name;
|
||||
const [_, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
|
||||
if (!remoteVersion) {
|
||||
if (win) {
|
||||
win.webContents.send("version-info-received", null);
|
||||
}
|
||||
} else {
|
||||
const upgradeAvailable = semver.gt(
|
||||
formatRc(remoteVersion),
|
||||
formatRc(localVersion)
|
||||
);
|
||||
if (win) {
|
||||
win.webContents.send("version-info-received", {
|
||||
remoteVersion,
|
||||
localVersion,
|
||||
upgradeAvailable,
|
||||
});
|
||||
}
|
||||
const req = Https.get(Object.assign(opts, Url.parse(LATEST_RELEASE_API_URL)), res => {
|
||||
res.on('data', data => {
|
||||
result += data;
|
||||
});
|
||||
res.on('end', () => {
|
||||
const tagName = JSON.parse(result).tag_name;
|
||||
const [, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
|
||||
if (!remoteVersion) {
|
||||
if (rendererWindow) {
|
||||
rendererWindow.webContents.send('version-info-received', null);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
} else {
|
||||
const upgradeAvailable = Semver.gt(formatRc(remoteVersion), formatRc(localVersion));
|
||||
if (rendererWindow) {
|
||||
rendererWindow.webContents.send('version-info-received', {
|
||||
remoteVersion,
|
||||
localVersion,
|
||||
upgradeAvailable,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on("error", err => {
|
||||
console.log("Failed to get current version from GitHub. Error:", err);
|
||||
if (win) {
|
||||
win.webContents.send("version-info-received", null);
|
||||
req.on('error', err => {
|
||||
console.log('Failed to get current version from GitHub. Error:', err);
|
||||
if (rendererWindow) {
|
||||
rendererWindow.webContents.send('version-info-received', null);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("get-auth-token", event => {
|
||||
keytar.getPassword("LBRY", "auth_token").then(token => {
|
||||
event.sender.send(
|
||||
"auth-token-response",
|
||||
token ? token.toString().trim() : null
|
||||
);
|
||||
ipcMain.on('get-auth-token', event => {
|
||||
Keytar.getPassword('LBRY', 'auth_token').then(token => {
|
||||
event.sender.send('auth-token-response', token ? token.toString().trim() : null);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("set-auth-token", (event, token) => {
|
||||
keytar.setPassword(
|
||||
"LBRY",
|
||||
"auth_token",
|
||||
token ? token.toString().trim() : null
|
||||
);
|
||||
ipcMain.on('set-auth-token', (event, token) => {
|
||||
Keytar.setPassword('LBRY', 'auth_token', token ? token.toString().trim() : null);
|
||||
});
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
const {Menu} = require('electron');
|
||||
const electron = require('electron');
|
||||
const app = electron.app;
|
||||
|
||||
const contextMenuTemplate = [
|
||||
{
|
||||
role: 'cut',
|
||||
},
|
||||
{
|
||||
role: 'copy',
|
||||
},
|
||||
{
|
||||
role: 'paste',
|
||||
},
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
showContextMenu(win, posX, posY, showDevItems) {
|
||||
let template = contextMenuTemplate.slice();
|
||||
if (showDevItems) {
|
||||
template.push({
|
||||
type: 'separator',
|
||||
});
|
||||
template.push(
|
||||
{
|
||||
label: 'Inspect Element',
|
||||
click() {
|
||||
win.inspectElement(posX, posY);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Menu.buildFromTemplate(template).popup(win);
|
||||
},
|
||||
};
|
30
src/main/menu/contextMenu.js
Normal file
30
src/main/menu/contextMenu.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { Menu } from 'electron';
|
||||
|
||||
const contextMenuTemplate = [
|
||||
{
|
||||
role: 'cut',
|
||||
},
|
||||
{
|
||||
role: 'copy',
|
||||
},
|
||||
{
|
||||
role: 'paste',
|
||||
},
|
||||
];
|
||||
|
||||
export default function contextMenu(win, posX, posY, showDevItems) {
|
||||
const template = contextMenuTemplate.slice();
|
||||
if (showDevItems) {
|
||||
template.push({
|
||||
type: 'separator',
|
||||
});
|
||||
template.push({
|
||||
label: 'Inspect Element',
|
||||
click() {
|
||||
win.inspectElement(posX, posY);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Menu.buildFromTemplate(template).popup(win);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
const { app, shell, Menu } = require('electron');
|
||||
const { safeQuit } = require('../index.js');
|
||||
import { app, Menu, shell } from 'electron';
|
||||
import { safeQuit } from '../index';
|
||||
|
||||
const baseTemplate = [
|
||||
{
|
||||
|
@ -7,10 +7,10 @@ const baseTemplate = [
|
|||
submenu: [
|
||||
{
|
||||
label: 'Quit',
|
||||
accelerator: "CommandOrControl+Q",
|
||||
accelerator: 'CommandOrControl+Q',
|
||||
click: () => safeQuit(),
|
||||
},
|
||||
]
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
|
@ -36,32 +36,32 @@ const baseTemplate = [
|
|||
{
|
||||
role: 'selectall',
|
||||
},
|
||||
]
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
submenu: [
|
||||
{
|
||||
role: 'reload'
|
||||
role: 'reload',
|
||||
},
|
||||
{
|
||||
label: 'Developer',
|
||||
submenu: [
|
||||
{
|
||||
role: 'forcereload'
|
||||
role: 'forcereload',
|
||||
},
|
||||
{
|
||||
role: 'toggledevtools'
|
||||
role: 'toggledevtools',
|
||||
},
|
||||
]
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
type: 'separator',
|
||||
},
|
||||
{
|
||||
role: 'togglefullscreen'
|
||||
}
|
||||
]
|
||||
role: 'togglefullscreen',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
role: 'help',
|
||||
|
@ -72,34 +72,34 @@ const baseTemplate = [
|
|||
if (focusedWindow) {
|
||||
focusedWindow.webContents.send('open-menu', '/help');
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Frequently Asked Questions',
|
||||
click(item, focusedWindow){
|
||||
shell.openExternal('https://lbry.io/faq')
|
||||
}
|
||||
click() {
|
||||
shell.openExternal('https://lbry.io/faq');
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
type: 'separator',
|
||||
},
|
||||
{
|
||||
label: 'Report Issue',
|
||||
click(item, focusedWindow){
|
||||
click() {
|
||||
shell.openExternal('https://lbry.io/faq/contributing#report-a-bug');
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
type: 'separator',
|
||||
},
|
||||
{
|
||||
label: 'Developer API Guide',
|
||||
click(item, focusedWindow){
|
||||
shell.openExternal('https://lbry.io/quickstart')
|
||||
}
|
||||
click() {
|
||||
shell.openExternal('https://lbry.io/quickstart');
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const macOSAppMenuTemplate = {
|
||||
|
@ -126,11 +126,13 @@ const macOSAppMenuTemplate = {
|
|||
{
|
||||
role: 'quit',
|
||||
},
|
||||
]
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = () => {
|
||||
let template = baseTemplate.slice();
|
||||
(process.platform === 'darwin') && template.unshift(macOSAppMenuTemplate);
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
|
||||
export default () => {
|
||||
const template = baseTemplate.slice();
|
||||
if (process.platform === 'darwin') {
|
||||
template.unshift(macOSAppMenuTemplate);
|
||||
}
|
||||
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
|
||||
};
|
|
@ -1,29 +1,40 @@
|
|||
import store from "store.js";
|
||||
import { remote } from "electron";
|
||||
import store from 'store';
|
||||
import { remote } from 'electron';
|
||||
import Path from 'path';
|
||||
import y18n from 'y18n';
|
||||
|
||||
const env = process.env.NODE_ENV || "production";
|
||||
const config = {
|
||||
...require(`./config/${env}`),
|
||||
};
|
||||
const i18n = require("y18n")({
|
||||
directory: remote.app.getAppPath() + "/locales",
|
||||
const env = process.env.NODE_ENV || 'production';
|
||||
const i18n = y18n({
|
||||
directory: Path.join(remote.app.getAppPath(), '/../static/locales').replace(/\\/g, '\\\\'),
|
||||
updateFiles: false,
|
||||
locale: "en",
|
||||
locale: 'en',
|
||||
});
|
||||
|
||||
const logs = [];
|
||||
const app = {
|
||||
env: env,
|
||||
config: config,
|
||||
store: store,
|
||||
i18n: i18n,
|
||||
logs: logs,
|
||||
log: function(message) {
|
||||
env,
|
||||
store,
|
||||
i18n,
|
||||
logs,
|
||||
log(message) {
|
||||
logs.push(message);
|
||||
},
|
||||
};
|
||||
|
||||
window.__ = i18n.__;
|
||||
window.__n = i18n.__n;
|
||||
// Workaround for https://github.com/electron-userland/electron-webpack/issues/52
|
||||
if (env !== 'development') {
|
||||
window.staticResourcesPath = Path.join(remote.app.getAppPath(), '../static').replace(
|
||||
/\\/g,
|
||||
'\\\\'
|
||||
);
|
||||
} else {
|
||||
window.staticResourcesPath = '';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
global.__ = i18n.__;
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
global.__n = i18n.__n;
|
||||
global.app = app;
|
||||
module.exports = app;
|
||||
|
||||
export default app;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { connect } from "react-redux";
|
||||
import { doShowSnackBar } from "redux/actions/app";
|
||||
import Address from "./view";
|
||||
import { connect } from 'react-redux';
|
||||
import { doShowSnackBar } from 'redux/actions/app';
|
||||
import Address from './view';
|
||||
|
||||
export default connect(null, {
|
||||
doShowSnackBar,
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { clipboard } from "electron";
|
||||
import Link from "component/link";
|
||||
import classnames from "classnames";
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { clipboard } from 'electron';
|
||||
import Link from 'component/link';
|
||||
import classnames from 'classnames';
|
||||
|
||||
export default class Address extends React.PureComponent {
|
||||
static propTypes = {
|
||||
|
@ -21,8 +21,8 @@ export default class Address extends React.PureComponent {
|
|||
return (
|
||||
<div className="form-field form-field--address">
|
||||
<input
|
||||
className={classnames("input-copyable", {
|
||||
"input-copyable--with-copy-btn": showCopyButton,
|
||||
className={classnames('input-copyable', {
|
||||
'input-copyable--with-copy-btn': showCopyButton,
|
||||
})}
|
||||
type="text"
|
||||
ref={input => {
|
||||
|
@ -32,7 +32,7 @@ export default class Address extends React.PureComponent {
|
|||
this._inputElem.select();
|
||||
}}
|
||||
readOnly="readonly"
|
||||
value={address || ""}
|
||||
value={address || ''}
|
||||
/>
|
||||
{showCopyButton && (
|
||||
<span className="header__item">
|
||||
|
@ -41,7 +41,7 @@ export default class Address extends React.PureComponent {
|
|||
icon="clipboard"
|
||||
onClick={() => {
|
||||
clipboard.writeText(address);
|
||||
doShowSnackBar({ message: __("Address copied") });
|
||||
doShowSnackBar({ message: __('Address copied') });
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
selectPageTitle,
|
||||
selectHistoryIndex,
|
||||
selectActiveHistoryEntry,
|
||||
} from "redux/selectors/navigation";
|
||||
import { selectUser } from "redux/selectors/user";
|
||||
import { doAlertError } from "redux/actions/app";
|
||||
import { doRecordScroll } from "redux/actions/navigation";
|
||||
import App from "./view";
|
||||
} from 'redux/selectors/navigation';
|
||||
import { selectUser } from 'redux/selectors/user';
|
||||
import { doAlertError } from 'redux/actions/app';
|
||||
import { doRecordScroll } from 'redux/actions/navigation';
|
||||
import App from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
pageTitle: selectPageTitle(state),
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import React from "react";
|
||||
import Router from "component/router/index";
|
||||
import Header from "component/header";
|
||||
import Theme from "component/theme";
|
||||
import ModalRouter from "modal/modalRouter";
|
||||
import ReactModal from "react-modal";
|
||||
import throttle from "util/throttle";
|
||||
import React from 'react';
|
||||
import Router from 'component/router/index';
|
||||
import Header from 'component/header';
|
||||
import Theme from 'component/theme';
|
||||
import ModalRouter from 'modal/modalRouter';
|
||||
import ReactModal from 'react-modal';
|
||||
import throttle from 'util/throttle';
|
||||
|
||||
class App extends React.PureComponent {
|
||||
constructor() {
|
||||
|
@ -15,25 +15,25 @@ class App extends React.PureComponent {
|
|||
componentWillMount() {
|
||||
const { alertError } = this.props;
|
||||
|
||||
document.addEventListener("unhandledError", event => {
|
||||
document.addEventListener('unhandledError', event => {
|
||||
alertError(event.detail);
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { recordScroll } = this.props;
|
||||
const mainContent = document.getElementById("main-content");
|
||||
const mainContent = document.getElementById('main-content');
|
||||
this.mainContent = mainContent;
|
||||
|
||||
const scrollListener = () => recordScroll(this.mainContent.scrollTop);
|
||||
|
||||
this.mainContent.addEventListener("scroll", throttle(scrollListener, 750));
|
||||
this.mainContent.addEventListener('scroll', throttle(scrollListener, 750));
|
||||
|
||||
ReactModal.setAppElement("#window"); //fuck this
|
||||
ReactModal.setAppElement('#window'); // fuck this
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.mainContent.removeEventListener("scroll", this.scrollListener);
|
||||
this.mainContent.removeEventListener('scroll', this.scrollListener);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props) {
|
||||
|
@ -50,7 +50,7 @@ class App extends React.PureComponent {
|
|||
}
|
||||
|
||||
setTitleFromProps(props) {
|
||||
window.document.title = props.pageTitle || "LBRY";
|
||||
window.document.title = props.pageTitle || 'LBRY';
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import CardMedia from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import CardMedia from './view';
|
||||
|
||||
const select = state => ({});
|
||||
const perform = dispatch => ({});
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import React from "react";
|
||||
import React from 'react';
|
||||
|
||||
class CardMedia extends React.PureComponent {
|
||||
static AUTO_THUMB_CLASSES = [
|
||||
"purple",
|
||||
"red",
|
||||
"pink",
|
||||
"indigo",
|
||||
"blue",
|
||||
"light-blue",
|
||||
"cyan",
|
||||
"teal",
|
||||
"green",
|
||||
"yellow",
|
||||
"orange",
|
||||
'purple',
|
||||
'red',
|
||||
'pink',
|
||||
'indigo',
|
||||
'blue',
|
||||
'light-blue',
|
||||
'cyan',
|
||||
'teal',
|
||||
'green',
|
||||
'yellow',
|
||||
'orange',
|
||||
];
|
||||
|
||||
componentWillMount() {
|
||||
|
@ -29,12 +29,7 @@ class CardMedia extends React.PureComponent {
|
|||
const atClass = this.state.autoThumbClass;
|
||||
|
||||
if (thumbnail) {
|
||||
return (
|
||||
<div
|
||||
className="card__media"
|
||||
style={{ backgroundImage: "url('" + thumbnail + "')" }}
|
||||
/>
|
||||
);
|
||||
return <div className="card__media" style={{ backgroundImage: `url('${thumbnail}')` }} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -42,8 +37,8 @@ class CardMedia extends React.PureComponent {
|
|||
<div className="card__autothumb__text">
|
||||
{title &&
|
||||
title
|
||||
.replace(/\s+/g, "")
|
||||
.substring(0, Math.min(title.replace(" ", "").length, 5))
|
||||
.replace(/\s+/g, '')
|
||||
.substring(0, Math.min(title.replace(' ', '').length, 5))
|
||||
.toUpperCase()}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectUserEmail } from "redux/selectors/user";
|
||||
import CardVerify from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectUserEmail } from 'redux/selectors/user';
|
||||
import CardVerify from './view';
|
||||
|
||||
const select = state => ({
|
||||
email: selectUserEmail(state),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Link from "component/link";
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Link from 'component/link';
|
||||
|
||||
let scriptLoading = false;
|
||||
let scriptLoaded = false;
|
||||
|
@ -48,8 +48,8 @@ class CardVerify extends React.Component {
|
|||
|
||||
scriptLoading = true;
|
||||
|
||||
const script = document.createElement("script");
|
||||
script.src = "https://checkout.stripe.com/checkout.js";
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://checkout.stripe.com/checkout.js';
|
||||
script.async = 1;
|
||||
|
||||
this.loadPromise = (() => {
|
||||
|
@ -69,12 +69,8 @@ class CardVerify extends React.Component {
|
|||
};
|
||||
});
|
||||
const wrappedPromise = new Promise((accept, cancel) => {
|
||||
promise.then(
|
||||
() => (canceled ? cancel({ isCanceled: true }) : accept())
|
||||
);
|
||||
promise.catch(
|
||||
error => (canceled ? cancel({ isCanceled: true }) : cancel(error))
|
||||
);
|
||||
promise.then(() => (canceled ? cancel({ isCanceled: true }) : accept()));
|
||||
promise.catch(error => (canceled ? cancel({ isCanceled: true }) : cancel(error)));
|
||||
});
|
||||
|
||||
return {
|
||||
|
@ -85,9 +81,7 @@ class CardVerify extends React.Component {
|
|||
};
|
||||
})();
|
||||
|
||||
this.loadPromise.promise
|
||||
.then(this.onScriptLoaded)
|
||||
.catch(this.onScriptError);
|
||||
this.loadPromise.promise.then(this.onScriptLoaded).catch(this.onScriptError);
|
||||
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
|
@ -119,7 +113,7 @@ class CardVerify extends React.Component {
|
|||
};
|
||||
|
||||
onScriptError = (...args) => {
|
||||
throw new Error("Unable to load credit validation script.");
|
||||
throw new Error('Unable to load credit validation script.');
|
||||
};
|
||||
|
||||
onClosed = () => {
|
||||
|
@ -139,10 +133,10 @@ class CardVerify extends React.Component {
|
|||
CardVerify.stripeHandler.open({
|
||||
allowRememberMe: false,
|
||||
closed: this.onClosed,
|
||||
description: __("Confirm Identity"),
|
||||
description: __('Confirm Identity'),
|
||||
email: this.props.email,
|
||||
locale: "auto",
|
||||
panelLabel: "Verify",
|
||||
locale: 'auto',
|
||||
panelLabel: 'Verify',
|
||||
token: this.props.token,
|
||||
zipCode: true,
|
||||
});
|
||||
|
@ -151,9 +145,7 @@ class CardVerify extends React.Component {
|
|||
onClick = () => {
|
||||
if (scriptDidError) {
|
||||
try {
|
||||
throw new Error(
|
||||
"Tried to call onClick, but StripeCheckout failed to load"
|
||||
);
|
||||
throw new Error('Tried to call onClick, but StripeCheckout failed to load');
|
||||
} catch (x) {}
|
||||
} else if (CardVerify.stripeHandler) {
|
||||
this.showStripeDialog();
|
||||
|
@ -168,9 +160,7 @@ class CardVerify extends React.Component {
|
|||
button="alt"
|
||||
label={this.props.label}
|
||||
icon="icon-lock"
|
||||
disabled={
|
||||
this.props.disabled || this.state.open || this.hasPendingClick
|
||||
}
|
||||
disabled={this.props.disabled || this.state.open || this.hasPendingClick}
|
||||
onClick={this.onClick.bind(this)}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { makeSelectClaimForUri } from "redux/selectors/claims";
|
||||
import { doNavigate } from "redux/actions/navigation";
|
||||
import { doResolveUri } from "redux/actions/content";
|
||||
import { makeSelectTotalItemsForChannel } from "redux/selectors/content";
|
||||
import { makeSelectIsUriResolving } from "redux/selectors/content";
|
||||
import ChannelTile from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { makeSelectClaimForUri } from 'redux/selectors/claims';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doResolveUri } from 'redux/actions/content';
|
||||
import { makeSelectTotalItemsForChannel } from 'redux/selectors/content';
|
||||
import { makeSelectIsUriResolving } from 'redux/selectors/content';
|
||||
import ChannelTile from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
claim: makeSelectClaimForUri(props.uri)(state),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import CardMedia from "component/cardMedia";
|
||||
import { TruncatedText, BusyMessage } from "component/common.js";
|
||||
import React from 'react';
|
||||
import CardMedia from 'component/cardMedia';
|
||||
import { TruncatedText, BusyMessage } from 'component/common.js';
|
||||
|
||||
class ChannelTile extends React.PureComponent {
|
||||
componentDidMount() {
|
||||
|
@ -26,12 +26,12 @@ class ChannelTile extends React.PureComponent {
|
|||
channelId = claim.claim_id;
|
||||
}
|
||||
|
||||
let onClick = () => navigate("/show", { uri });
|
||||
const onClick = () => navigate('/show', { uri });
|
||||
|
||||
return (
|
||||
<section className="file-tile card">
|
||||
<div onClick={onClick} className="card__link">
|
||||
<div className={"card__inner file-tile__row"}>
|
||||
<div className="card__inner file-tile__row">
|
||||
{channelName && <CardMedia title={channelName} thumbnail={null} />}
|
||||
<div className="file-tile__content">
|
||||
<div className="card__title-primary">
|
||||
|
@ -40,19 +40,15 @@ class ChannelTile extends React.PureComponent {
|
|||
</h3>
|
||||
</div>
|
||||
<div className="card__content card__subtext">
|
||||
{isResolvingUri && (
|
||||
<BusyMessage message={__("Resolving channel")} />
|
||||
)}
|
||||
{isResolvingUri && <BusyMessage message={__('Resolving channel')} />}
|
||||
{totalItems > 0 && (
|
||||
<span>
|
||||
This is a channel with {totalItems}{" "}
|
||||
{totalItems === 1 ? " item" : " items"} inside of it.
|
||||
This is a channel with {totalItems} {totalItems === 1 ? ' item' : ' items'}{' '}
|
||||
inside of it.
|
||||
</span>
|
||||
)}
|
||||
{!isResolvingUri &&
|
||||
!totalItems && (
|
||||
<span className="empty">This is an empty channel.</span>
|
||||
)}
|
||||
!totalItems && <span className="empty">This is an empty channel.</span>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { formatCredits, formatFullPrice } from "util/formatCredits";
|
||||
import lbry from "../lbry.js";
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { formatCredits, formatFullPrice } from 'util/formatCredits';
|
||||
import lbry from '../lbry.js';
|
||||
|
||||
//component/icon.js
|
||||
// component/icon.js
|
||||
export class Icon extends React.PureComponent {
|
||||
static propTypes = {
|
||||
icon: PropTypes.string.isRequired,
|
||||
|
@ -13,12 +13,9 @@ export class Icon extends React.PureComponent {
|
|||
|
||||
render() {
|
||||
const { fixed, className } = this.props;
|
||||
const spanClassName =
|
||||
"icon " +
|
||||
("fixed" in this.props ? "icon-fixed-width " : "") +
|
||||
this.props.icon +
|
||||
" " +
|
||||
(this.props.className || "");
|
||||
const spanClassName = `icon ${'fixed' in this.props ? 'icon-fixed-width ' : ''}${
|
||||
this.props.icon
|
||||
} ${this.props.className || ''}`;
|
||||
return <span className={spanClassName} />;
|
||||
}
|
||||
}
|
||||
|
@ -34,10 +31,7 @@ export class TruncatedText extends React.PureComponent {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<span
|
||||
className="truncated-text"
|
||||
style={{ WebkitLineClamp: this.props.lines }}
|
||||
>
|
||||
<span className="truncated-text" style={{ WebkitLineClamp: this.props.lines }}>
|
||||
{this.props.children}
|
||||
</span>
|
||||
);
|
||||
|
@ -73,14 +67,14 @@ export class CreditAmount extends React.PureComponent {
|
|||
showFree: PropTypes.bool,
|
||||
showFullPrice: PropTypes.bool,
|
||||
showPlus: PropTypes.bool,
|
||||
look: PropTypes.oneOf(["indicator", "plain", "fee"]),
|
||||
look: PropTypes.oneOf(['indicator', 'plain', 'fee']),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
precision: 2,
|
||||
label: true,
|
||||
showFree: false,
|
||||
look: "indicator",
|
||||
look: 'indicator',
|
||||
showFullPrice: false,
|
||||
showPlus: false,
|
||||
};
|
||||
|
@ -90,46 +84,43 @@ export class CreditAmount extends React.PureComponent {
|
|||
const { amount, precision, showFullPrice } = this.props;
|
||||
|
||||
let formattedAmount;
|
||||
let fullPrice = formatFullPrice(amount, 2);
|
||||
const fullPrice = formatFullPrice(amount, 2);
|
||||
|
||||
if (showFullPrice) {
|
||||
formattedAmount = fullPrice;
|
||||
} else {
|
||||
formattedAmount =
|
||||
amount > 0 && amount < minimumRenderableAmount
|
||||
? "<" + minimumRenderableAmount
|
||||
? `<${minimumRenderableAmount}`
|
||||
: formatCredits(amount, precision);
|
||||
}
|
||||
|
||||
let amountText;
|
||||
if (this.props.showFree && parseFloat(this.props.amount) === 0) {
|
||||
amountText = __("free");
|
||||
amountText = __('free');
|
||||
} else {
|
||||
if (this.props.label) {
|
||||
const label =
|
||||
typeof this.props.label === "string"
|
||||
typeof this.props.label === 'string'
|
||||
? this.props.label
|
||||
: parseFloat(amount) == 1 ? __("credit") : __("credits");
|
||||
: parseFloat(amount) == 1 ? __('credit') : __('credits');
|
||||
|
||||
amountText = formattedAmount + " " + label;
|
||||
amountText = `${formattedAmount} ${label}`;
|
||||
} else {
|
||||
amountText = formattedAmount;
|
||||
}
|
||||
if (this.props.showPlus && amount > 0) {
|
||||
amountText = "+" + amountText;
|
||||
amountText = `+${amountText}`;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`credit-amount credit-amount--${this.props.look}`}
|
||||
title={fullPrice}
|
||||
>
|
||||
<span className={`credit-amount credit-amount--${this.props.look}`} title={fullPrice}>
|
||||
<span>{amountText}</span>
|
||||
{this.props.isEstimate ? (
|
||||
<span
|
||||
className="credit-amount__estimate"
|
||||
title={__("This is an estimate and does not include data fees")}
|
||||
title={__('This is an estimate and does not include data fees')}
|
||||
>
|
||||
*
|
||||
</span>
|
||||
|
@ -155,7 +146,7 @@ export class Thumbnail extends React.PureComponent {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this._defaultImageUri = lbry.imagePath("default-thumb.svg");
|
||||
this._defaultImageUri = lbry.imagePath('default-thumb.svg');
|
||||
this._maxLoadTime = 10000;
|
||||
this._isMounted = false;
|
||||
|
||||
|
@ -180,7 +171,7 @@ export class Thumbnail extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const className = this.props.className ? this.props.className : "",
|
||||
const className = this.props.className ? this.props.className : '',
|
||||
otherProps = Object.assign({}, this.props);
|
||||
delete otherProps.className;
|
||||
return (
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import React from "react";
|
||||
import classnames from "classnames";
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
export default ({ dark, className }) => {
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
"spinner",
|
||||
{
|
||||
"spinner--dark": dark,
|
||||
},
|
||||
className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export default ({ dark, className }) => (
|
||||
<div
|
||||
className={classnames(
|
||||
'spinner',
|
||||
{
|
||||
'spinner--dark': dark,
|
||||
},
|
||||
className
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { makeSelectBlockDate } from "redux/selectors/wallet";
|
||||
import { doFetchBlock } from "redux/actions/wallet";
|
||||
import DateTime from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { makeSelectBlockDate } from 'redux/selectors/wallet';
|
||||
import { doFetchBlock } from 'redux/actions/wallet';
|
||||
import DateTime from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
date:
|
||||
!props.date && props.block
|
||||
? makeSelectBlockDate(props.block)(state)
|
||||
: props.date,
|
||||
date: !props.date && props.block ? makeSelectBlockDate(props.block)(state) : props.date,
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import React from "react";
|
||||
import React from 'react';
|
||||
|
||||
class DateTime extends React.PureComponent {
|
||||
static SHOW_DATE = "date";
|
||||
static SHOW_TIME = "time";
|
||||
static SHOW_BOTH = "both";
|
||||
static SHOW_DATE = 'date';
|
||||
static SHOW_TIME = 'time';
|
||||
static SHOW_BOTH = 'both';
|
||||
|
||||
static defaultProps = {
|
||||
formatOptions: {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -37,12 +37,12 @@ class DateTime extends React.PureComponent {
|
|||
<span>
|
||||
{date &&
|
||||
(show == DateTime.SHOW_BOTH || show === DateTime.SHOW_DATE) &&
|
||||
date.toLocaleDateString([locale, "en-US"], formatOptions)}
|
||||
{show == DateTime.SHOW_BOTH && " "}
|
||||
date.toLocaleDateString([locale, 'en-US'], formatOptions)}
|
||||
{show == DateTime.SHOW_BOTH && ' '}
|
||||
{date &&
|
||||
(show == DateTime.SHOW_BOTH || show === DateTime.SHOW_TIME) &&
|
||||
date.toLocaleTimeString()}
|
||||
{!date && "..."}
|
||||
{!date && '...'}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const { remote } = require('electron');
|
||||
|
||||
const { remote } = require("electron");
|
||||
class FileSelector extends React.PureComponent {
|
||||
static propTypes = {
|
||||
type: PropTypes.oneOf(["file", "directory"]),
|
||||
type: PropTypes.oneOf(['file', 'directory']),
|
||||
initPath: PropTypes.string,
|
||||
onFileChosen: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
type: "file",
|
||||
type: 'file',
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
@ -27,10 +28,7 @@ class FileSelector extends React.PureComponent {
|
|||
handleButtonClick() {
|
||||
remote.dialog.showOpenDialog(
|
||||
{
|
||||
properties:
|
||||
this.props.type == "file"
|
||||
? ["openFile"]
|
||||
: ["openDirectory", "createDirectory"],
|
||||
properties: this.props.type == 'file' ? ['openFile'] : ['openDirectory', 'createDirectory'],
|
||||
},
|
||||
paths => {
|
||||
if (!paths) {
|
||||
|
@ -40,7 +38,7 @@ class FileSelector extends React.PureComponent {
|
|||
|
||||
const path = paths[0];
|
||||
this.setState({
|
||||
path: path,
|
||||
path,
|
||||
});
|
||||
if (this.props.onFileChosen) {
|
||||
this.props.onFileChosen(path);
|
||||
|
@ -59,12 +57,10 @@ class FileSelector extends React.PureComponent {
|
|||
>
|
||||
<span className="button__content">
|
||||
<span className="button-label">
|
||||
{this.props.type == "file"
|
||||
? __("Choose File")
|
||||
: __("Choose Directory")}
|
||||
{this.props.type == 'file' ? __('Choose File') : __('Choose Directory')}
|
||||
</span>
|
||||
</span>
|
||||
</button>{" "}
|
||||
</button>{' '}
|
||||
<span className="file-selector__path">
|
||||
<input
|
||||
className="input-copyable"
|
||||
|
@ -76,7 +72,7 @@ class FileSelector extends React.PureComponent {
|
|||
this._inputElem.select();
|
||||
}}
|
||||
readOnly="readonly"
|
||||
value={this.state.path || __("No File Chosen")}
|
||||
value={this.state.path || __('No File Chosen')}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { makeSelectFileInfoForUri } from "redux/selectors/file_info";
|
||||
import { makeSelectCostInfoForUri } from "redux/selectors/cost_info";
|
||||
import { doOpenModal } from "redux/actions/app";
|
||||
import { makeSelectClaimIsMine } from "redux/selectors/claims";
|
||||
import FileActions from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { makeSelectFileInfoForUri } from 'redux/selectors/file_info';
|
||||
import { makeSelectCostInfoForUri } from 'redux/selectors/cost_info';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import { makeSelectClaimIsMine } from 'redux/selectors/claims';
|
||||
import FileActions from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
|
||||
/*availability check is disabled due to poor performance, TBD if it dies forever or requires daemon fix*/
|
||||
/* availability check is disabled due to poor performance, TBD if it dies forever or requires daemon fix */
|
||||
costInfo: makeSelectCostInfoForUri(props.uri)(state),
|
||||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
import FileDownloadLink from "component/fileDownloadLink";
|
||||
import * as modals from "constants/modal_types";
|
||||
import React from 'react';
|
||||
import Link from 'component/link';
|
||||
import FileDownloadLink from 'component/fileDownloadLink';
|
||||
import * as modals from 'constants/modal_types';
|
||||
|
||||
class FileActions extends React.PureComponent {
|
||||
render() {
|
||||
|
@ -17,7 +17,7 @@ class FileActions extends React.PureComponent {
|
|||
<Link
|
||||
button="text"
|
||||
icon="icon-trash"
|
||||
label={__("Remove")}
|
||||
label={__('Remove')}
|
||||
className="no-underline"
|
||||
onClick={() => openModal(modals.CONFIRM_FILE_REMOVE, { uri })}
|
||||
/>
|
||||
|
@ -28,22 +28,22 @@ class FileActions extends React.PureComponent {
|
|||
icon="icon-flag"
|
||||
href={`https://lbry.io/dmca?claim_id=${claimId}`}
|
||||
className="no-underline"
|
||||
label={__("report")}
|
||||
label={__('report')}
|
||||
/>
|
||||
)}
|
||||
<Link
|
||||
button="primary"
|
||||
icon="icon-gift"
|
||||
label={__("Support")}
|
||||
label={__('Support')}
|
||||
navigate="/show"
|
||||
className="card__action--right"
|
||||
navigateParams={{ uri, tab: "tip" }}
|
||||
navigateParams={{ uri, tab: 'tip' }}
|
||||
/>
|
||||
{claimIsMine && (
|
||||
<Link
|
||||
button="alt"
|
||||
icon="icon-edit"
|
||||
label={__("Edit")}
|
||||
label={__('Edit')}
|
||||
navigate="/publish"
|
||||
className="card__action--right"
|
||||
navigateParams={{ id: claimId }}
|
||||
|
|
|
@ -1,18 +1,12 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "redux/actions/navigation";
|
||||
import { doResolveUri } from "redux/actions/content";
|
||||
import { selectShowNsfw } from "redux/selectors/settings";
|
||||
import {
|
||||
makeSelectClaimForUri,
|
||||
makeSelectMetadataForUri,
|
||||
} from "redux/selectors/claims";
|
||||
import { makeSelectFileInfoForUri } from "redux/selectors/file_info";
|
||||
import {
|
||||
makeSelectIsUriResolving,
|
||||
selectRewardContentClaimIds,
|
||||
} from "redux/selectors/content";
|
||||
import FileCard from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doResolveUri } from 'redux/actions/content';
|
||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||
import { makeSelectClaimForUri, makeSelectMetadataForUri } from 'redux/selectors/claims';
|
||||
import { makeSelectFileInfoForUri } from 'redux/selectors/file_info';
|
||||
import { makeSelectIsUriResolving, selectRewardContentClaimIds } from 'redux/selectors/content';
|
||||
import FileCard from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
claim: makeSelectClaimForUri(props.uri)(state),
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from "react";
|
||||
import lbryuri from "lbryuri.js";
|
||||
import CardMedia from "component/cardMedia";
|
||||
import Link from "component/link";
|
||||
import { TruncatedText } from "component/common";
|
||||
import Icon from "component/icon";
|
||||
import FilePrice from "component/filePrice";
|
||||
import UriIndicator from "component/uriIndicator";
|
||||
import NsfwOverlay from "component/nsfwOverlay";
|
||||
import TruncatedMarkdown from "component/truncatedMarkdown";
|
||||
import * as icons from "constants/icons";
|
||||
import React from 'react';
|
||||
import lbryuri from 'lbryuri.js';
|
||||
import CardMedia from 'component/cardMedia';
|
||||
import Link from 'component/link';
|
||||
import { TruncatedText } from 'component/common';
|
||||
import Icon from 'component/icon';
|
||||
import FilePrice from 'component/filePrice';
|
||||
import UriIndicator from 'component/uriIndicator';
|
||||
import NsfwOverlay from 'component/nsfwOverlay';
|
||||
import TruncatedMarkdown from 'component/truncatedMarkdown';
|
||||
import * as icons from 'constants/icons';
|
||||
|
||||
class FileCard extends React.PureComponent {
|
||||
constructor(props) {
|
||||
|
@ -59,35 +59,27 @@ class FileCard extends React.PureComponent {
|
|||
|
||||
const uri = lbryuri.normalize(this.props.uri);
|
||||
const title = metadata && metadata.title ? metadata.title : uri;
|
||||
const thumbnail =
|
||||
metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
|
||||
const isRewardContent =
|
||||
claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||
|
||||
let description = "";
|
||||
let description = '';
|
||||
if (isResolvingUri && !claim) {
|
||||
description = __("Loading...");
|
||||
description = __('Loading...');
|
||||
} else if (metadata && metadata.description) {
|
||||
description = metadata.description;
|
||||
} else if (claim === null) {
|
||||
description = __("This address contains no content.");
|
||||
description = __('This address contains no content.');
|
||||
}
|
||||
|
||||
return (
|
||||
<section
|
||||
className={
|
||||
"card card--small card--link " +
|
||||
(obscureNsfw ? "card--obscured " : "")
|
||||
}
|
||||
className={`card card--small card--link ${obscureNsfw ? 'card--obscured ' : ''}`}
|
||||
onMouseEnter={this.handleMouseOver.bind(this)}
|
||||
onMouseLeave={this.handleMouseOut.bind(this)}
|
||||
>
|
||||
<div className="card__inner">
|
||||
<Link
|
||||
onClick={() => navigate("/show", { uri })}
|
||||
className="card__link"
|
||||
>
|
||||
<Link onClick={() => navigate('/show', { uri })} className="card__link">
|
||||
<CardMedia title={title} thumbnail={thumbnail} />
|
||||
<div className="card__title-identity">
|
||||
<div className="card__title" title={title}>
|
||||
|
@ -95,12 +87,11 @@ class FileCard extends React.PureComponent {
|
|||
</div>
|
||||
<div className="card__subtitle">
|
||||
<span className="card__indicators card--file-subtitle">
|
||||
<FilePrice uri={uri} />{" "}
|
||||
{isRewardContent && <Icon icon={icons.FEATURED} />}{" "}
|
||||
<FilePrice uri={uri} /> {isRewardContent && <Icon icon={icons.FEATURED} />}{' '}
|
||||
{fileInfo && <Icon icon={icons.LOCAL} />}
|
||||
</span>
|
||||
<span className="card--file-subtitle">
|
||||
<UriIndicator uri={uri} link={true} span={true} smallCard />
|
||||
<UriIndicator uri={uri} link span smallCard />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
makeSelectClaimForUri,
|
||||
makeSelectContentTypeForUri,
|
||||
makeSelectMetadataForUri,
|
||||
} from "redux/selectors/claims";
|
||||
import FileDetails from "./view";
|
||||
import { doOpenFileInFolder } from "redux/actions/file_info";
|
||||
import { makeSelectFileInfoForUri } from "redux/selectors/file_info";
|
||||
} from 'redux/selectors/claims';
|
||||
import FileDetails from './view';
|
||||
import { doOpenFileInFolder } from 'redux/actions/file_info';
|
||||
import { makeSelectFileInfoForUri } from 'redux/selectors/file_info';
|
||||
|
||||
const select = (state, props) => ({
|
||||
claim: makeSelectClaimForUri(props.uri)(state),
|
||||
|
|
|
@ -1,27 +1,20 @@
|
|||
import React from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import lbry from "lbry.js";
|
||||
import FileActions from "component/fileActions";
|
||||
import Link from "component/link";
|
||||
import DateTime from "component/dateTime";
|
||||
import React from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import lbry from 'lbry.js';
|
||||
import FileActions from 'component/fileActions';
|
||||
import Link from 'component/link';
|
||||
import DateTime from 'component/dateTime';
|
||||
|
||||
const path = require("path");
|
||||
const path = require('path');
|
||||
|
||||
class FileDetails extends React.PureComponent {
|
||||
render() {
|
||||
const {
|
||||
claim,
|
||||
contentType,
|
||||
fileInfo,
|
||||
metadata,
|
||||
openFolder,
|
||||
uri,
|
||||
} = this.props;
|
||||
const { claim, contentType, fileInfo, metadata, openFolder, uri } = this.props;
|
||||
|
||||
if (!claim || !metadata) {
|
||||
return (
|
||||
<div className="card__content">
|
||||
<span className="empty">{__("Empty claim or metadata info.")}</span>
|
||||
<span className="empty">{__('Empty claim or metadata info.')}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -29,9 +22,7 @@ class FileDetails extends React.PureComponent {
|
|||
const { description, language, license } = metadata;
|
||||
const mediaType = lbry.getMediaType(contentType);
|
||||
|
||||
const downloadPath = fileInfo
|
||||
? path.normalize(fileInfo.download_path)
|
||||
: null;
|
||||
const downloadPath = fileInfo ? path.normalize(fileInfo.download_path) : null;
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
@ -40,33 +31,31 @@ class FileDetails extends React.PureComponent {
|
|||
<div className="divider__horizontal" />
|
||||
<div className="card__content card__subtext card__subtext--allow-newlines">
|
||||
<ReactMarkdown
|
||||
source={description || ""}
|
||||
escapeHtml={true}
|
||||
disallowedTypes={["Heading", "HtmlInline", "HtmlBlock"]}
|
||||
source={description || ''}
|
||||
escapeHtml
|
||||
disallowedTypes={['Heading', 'HtmlInline', 'HtmlBlock']}
|
||||
/>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<table className="table-standard table-stretch">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{__("Content-Type")}</td>
|
||||
<td>{__('Content-Type')}</td>
|
||||
<td>{mediaType}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{__("Language")}</td>
|
||||
<td>{__('Language')}</td>
|
||||
<td>{language}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{__("License")}</td>
|
||||
<td>{__('License')}</td>
|
||||
<td>{license}</td>
|
||||
</tr>
|
||||
{downloadPath && (
|
||||
<tr>
|
||||
<td>{__("Downloaded to")}</td>
|
||||
<td>{__('Downloaded to')}</td>
|
||||
<td>
|
||||
<Link onClick={() => openFolder(downloadPath)}>
|
||||
{downloadPath}
|
||||
</Link>
|
||||
<Link onClick={() => openFolder(downloadPath)}>{downloadPath}</Link>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
makeSelectFileInfoForUri,
|
||||
makeSelectDownloadingForUri,
|
||||
makeSelectLoadingForUri,
|
||||
} from "redux/selectors/file_info";
|
||||
import { makeSelectCostInfoForUri } from "redux/selectors/cost_info";
|
||||
import { doFetchAvailability } from "redux/actions/availability";
|
||||
import { doOpenFileInShell } from "redux/actions/file_info";
|
||||
import { doPurchaseUri, doStartDownload } from "redux/actions/content";
|
||||
import { setVideoPause } from "redux/actions/video";
|
||||
import FileDownloadLink from "./view";
|
||||
} from 'redux/selectors/file_info';
|
||||
import { makeSelectCostInfoForUri } from 'redux/selectors/cost_info';
|
||||
import { doFetchAvailability } from 'redux/actions/availability';
|
||||
import { doOpenFileInShell } from 'redux/actions/file_info';
|
||||
import { doPurchaseUri, doStartDownload } from 'redux/actions/content';
|
||||
import { setVideoPause } from 'redux/actions/video';
|
||||
import FileDownloadLink from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
|
||||
/*availability check is disabled due to poor performance, TBD if it dies forever or requires daemon fix*/
|
||||
/* availability check is disabled due to poor performance, TBD if it dies forever or requires daemon fix */
|
||||
downloading: makeSelectDownloadingForUri(props.uri)(state),
|
||||
costInfo: makeSelectCostInfoForUri(props.uri)(state),
|
||||
loading: makeSelectLoadingForUri(props.uri)(state),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { Icon, BusyMessage } from "component/common";
|
||||
import Link from "component/link";
|
||||
import React from 'react';
|
||||
import { Icon, BusyMessage } from 'component/common';
|
||||
import Link from 'component/link';
|
||||
|
||||
class FileDownloadLink extends React.PureComponent {
|
||||
componentWillMount() {
|
||||
|
@ -55,9 +55,7 @@ class FileDownloadLink extends React.PureComponent {
|
|||
fileInfo && fileInfo.written_bytes
|
||||
? fileInfo.written_bytes / fileInfo.total_bytes * 100
|
||||
: 0,
|
||||
label = fileInfo
|
||||
? progress.toFixed(0) + __("% complete")
|
||||
: __("Connecting..."),
|
||||
label = fileInfo ? progress.toFixed(0) + __('% complete') : __('Connecting...'),
|
||||
labelWithIcon = (
|
||||
<span className="button__content">
|
||||
<Icon icon="icon-download" />
|
||||
|
@ -69,7 +67,7 @@ class FileDownloadLink extends React.PureComponent {
|
|||
<div className="faux-button-block file-download button-set-item">
|
||||
<div
|
||||
className="faux-button-block file-download__overlay"
|
||||
style={{ width: progress + "%" }}
|
||||
style={{ width: `${progress}%` }}
|
||||
>
|
||||
{labelWithIcon}
|
||||
</div>
|
||||
|
@ -78,24 +76,23 @@ class FileDownloadLink extends React.PureComponent {
|
|||
);
|
||||
} else if (fileInfo === null && !downloading) {
|
||||
if (!costInfo) {
|
||||
return <BusyMessage message={__("Fetching cost info")} />;
|
||||
} else {
|
||||
return (
|
||||
<Link
|
||||
button="text"
|
||||
label={__("Download")}
|
||||
icon="icon-download"
|
||||
className="no-underline"
|
||||
onClick={() => {
|
||||
purchaseUri(uri);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
return <BusyMessage message={__('Fetching cost info')} />;
|
||||
}
|
||||
return (
|
||||
<Link
|
||||
button="text"
|
||||
label={__('Download')}
|
||||
icon="icon-download"
|
||||
className="no-underline"
|
||||
onClick={() => {
|
||||
purchaseUri(uri);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else if (fileInfo && fileInfo.download_path) {
|
||||
return (
|
||||
<Link
|
||||
label={__("Open")}
|
||||
label={__('Open')}
|
||||
button="text"
|
||||
icon="icon-external-link-square"
|
||||
className="no-underline"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import FileList from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import FileList from './view';
|
||||
|
||||
const select = state => ({});
|
||||
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
import React from "react";
|
||||
import lbryuri from "lbryuri.js";
|
||||
import FormField from "component/formField";
|
||||
import FileTile from "component/fileTile";
|
||||
import { BusyMessage } from "component/common.js";
|
||||
import React from 'react';
|
||||
import lbryuri from 'lbryuri.js';
|
||||
import FormField from 'component/formField';
|
||||
import FileTile from 'component/fileTile';
|
||||
import { BusyMessage } from 'component/common.js';
|
||||
|
||||
class FileList extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
sortBy: "date",
|
||||
sortBy: 'date',
|
||||
};
|
||||
|
||||
this._sortFunctions = {
|
||||
date: function(fileInfos) {
|
||||
date(fileInfos) {
|
||||
return fileInfos.slice().reverse();
|
||||
},
|
||||
title: function(fileInfos) {
|
||||
return fileInfos.slice().sort(function(fileInfo1, fileInfo2) {
|
||||
title(fileInfos) {
|
||||
return fileInfos.slice().sort((fileInfo1, fileInfo2) => {
|
||||
const title1 = fileInfo1.value
|
||||
? fileInfo1.value.stream.metadata.title.toLowerCase()
|
||||
: fileInfo1.name;
|
||||
|
@ -28,25 +28,21 @@ class FileList extends React.PureComponent {
|
|||
return -1;
|
||||
} else if (title1 > title2) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
},
|
||||
filename: function(fileInfos) {
|
||||
return fileInfos
|
||||
.slice()
|
||||
.sort(function({ file_name: fileName1 }, { file_name: fileName2 }) {
|
||||
const fileName1Lower = fileName1.toLowerCase();
|
||||
const fileName2Lower = fileName2.toLowerCase();
|
||||
if (fileName1Lower < fileName2Lower) {
|
||||
return -1;
|
||||
} else if (fileName2Lower > fileName1Lower) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
filename(fileInfos) {
|
||||
return fileInfos.slice().sort(({ file_name: fileName1 }, { file_name: fileName2 }) => {
|
||||
const fileName1Lower = fileName1.toLowerCase();
|
||||
const fileName2Lower = fileName2.toLowerCase();
|
||||
if (fileName1Lower < fileName2Lower) {
|
||||
return -1;
|
||||
} else if (fileName2Lower > fileName1Lower) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -54,9 +50,8 @@ class FileList extends React.PureComponent {
|
|||
getChannelSignature(fileInfo) {
|
||||
if (fileInfo.value) {
|
||||
return fileInfo.value.publisherSignature.certificateId;
|
||||
} else {
|
||||
return fileInfo.metadata.publisherSignature.certificateId;
|
||||
}
|
||||
return fileInfo.metadata.publisherSignature.certificateId;
|
||||
}
|
||||
|
||||
handleSortChanged(event) {
|
||||
|
@ -71,7 +66,7 @@ class FileList extends React.PureComponent {
|
|||
const content = [];
|
||||
|
||||
this._sortFunctions[sortBy](fileInfos).forEach(fileInfo => {
|
||||
let uriParams = {};
|
||||
const uriParams = {};
|
||||
|
||||
if (fileInfo.channel_name) {
|
||||
uriParams.channelName = fileInfo.channel_name;
|
||||
|
@ -89,7 +84,7 @@ class FileList extends React.PureComponent {
|
|||
uri={uri}
|
||||
showPrice={false}
|
||||
showLocal={false}
|
||||
showActions={true}
|
||||
showActions
|
||||
showEmpty={this.props.fileTileShowEmpty}
|
||||
/>
|
||||
);
|
||||
|
@ -98,10 +93,10 @@ class FileList extends React.PureComponent {
|
|||
<section className="file-list__header">
|
||||
{fetching && <BusyMessage />}
|
||||
<span className="sort-section">
|
||||
{__("Sort by")}{" "}
|
||||
{__('Sort by')}{' '}
|
||||
<FormField type="select" onChange={this.handleSortChanged.bind(this)}>
|
||||
<option value="date">{__("Date")}</option>
|
||||
<option value="title">{__("Title")}</option>
|
||||
<option value="date">{__('Date')}</option>
|
||||
<option value="title">{__('Title')}</option>
|
||||
</FormField>
|
||||
</span>
|
||||
{content}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doSearch } from "redux/actions/search";
|
||||
import {
|
||||
selectIsSearching,
|
||||
makeSelectSearchUris,
|
||||
} from "redux/selectors/search";
|
||||
import FileListSearch from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { doSearch } from 'redux/actions/search';
|
||||
import { selectIsSearching, makeSelectSearchUris } from 'redux/selectors/search';
|
||||
import FileListSearch from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
isSearching: selectIsSearching(state),
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from "react";
|
||||
import FileTile from "component/fileTile";
|
||||
import ChannelTile from "component/channelTile";
|
||||
import Link from "component/link";
|
||||
import { BusyMessage } from "component/common.js";
|
||||
import lbryuri from "lbryuri";
|
||||
import React from 'react';
|
||||
import FileTile from 'component/fileTile';
|
||||
import ChannelTile from 'component/channelTile';
|
||||
import Link from 'component/link';
|
||||
import { BusyMessage } from 'component/common.js';
|
||||
import lbryuri from 'lbryuri';
|
||||
|
||||
const SearchNoResults = props => {
|
||||
const { query } = props;
|
||||
|
@ -11,8 +11,8 @@ const SearchNoResults = props => {
|
|||
return (
|
||||
<section>
|
||||
<span className="empty">
|
||||
{(__("No one has checked anything in for %s yet."), query)}{" "}
|
||||
<Link label={__("Be the first")} navigate="/publish" />
|
||||
{(__('No one has checked anything in for %s yet.'), query)}{' '}
|
||||
<Link label={__('Be the first')} navigate="/publish" />
|
||||
</span>
|
||||
</section>
|
||||
);
|
||||
|
@ -38,18 +38,14 @@ class FileListSearch extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<div>
|
||||
{isSearching &&
|
||||
!uris && (
|
||||
<BusyMessage message={__("Looking up the Dewey Decimals")} />
|
||||
)}
|
||||
{isSearching && !uris && <BusyMessage message={__('Looking up the Dewey Decimals')} />}
|
||||
|
||||
{isSearching &&
|
||||
uris && <BusyMessage message={__("Refreshing the Dewey Decimals")} />}
|
||||
{isSearching && uris && <BusyMessage message={__('Refreshing the Dewey Decimals')} />}
|
||||
|
||||
{uris && uris.length
|
||||
? uris.map(
|
||||
uri =>
|
||||
lbryuri.parse(uri).name[0] === "@" ? (
|
||||
lbryuri.parse(uri).name[0] === '@' ? (
|
||||
<ChannelTile key={uri} uri={uri} />
|
||||
) : (
|
||||
<FileTile key={uri} uri={uri} />
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doFetchCostInfoForUri } from "redux/actions/cost_info";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { doFetchCostInfoForUri } from 'redux/actions/cost_info';
|
||||
import {
|
||||
makeSelectCostInfoForUri,
|
||||
makeSelectFetchingCostInfoForUri,
|
||||
} from "redux/selectors/cost_info";
|
||||
import { makeSelectClaimForUri } from "redux/selectors/claims";
|
||||
import FilePrice from "./view";
|
||||
} from 'redux/selectors/cost_info';
|
||||
import { makeSelectClaimForUri } from 'redux/selectors/claims';
|
||||
import FilePrice from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
costInfo: makeSelectCostInfoForUri(props.uri)(state),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { CreditAmount } from "component/common";
|
||||
import React from 'react';
|
||||
import { CreditAmount } from 'component/common';
|
||||
|
||||
class FilePrice extends React.PureComponent {
|
||||
componentWillMount() {
|
||||
|
@ -19,14 +19,12 @@ class FilePrice extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { costInfo, look = "indicator", showFullPrice = false } = this.props;
|
||||
const { costInfo, look = 'indicator', showFullPrice = false } = this.props;
|
||||
|
||||
const isEstimate = costInfo ? !costInfo.includesData : null;
|
||||
|
||||
if (!costInfo) {
|
||||
return (
|
||||
<span className={`credit-amount credit-amount--${look}`}>???</span>
|
||||
);
|
||||
return <span className={`credit-amount credit-amount--${look}`}>???</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -34,7 +32,7 @@ class FilePrice extends React.PureComponent {
|
|||
label={false}
|
||||
amount={costInfo.cost}
|
||||
isEstimate={isEstimate}
|
||||
showFree={true}
|
||||
showFree
|
||||
showFullPrice={showFullPrice}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -1,18 +1,12 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "redux/actions/navigation";
|
||||
import { doResolveUri } from "redux/actions/content";
|
||||
import {
|
||||
makeSelectClaimForUri,
|
||||
makeSelectMetadataForUri,
|
||||
} from "redux/selectors/claims";
|
||||
import { makeSelectFileInfoForUri } from "redux/selectors/file_info";
|
||||
import { selectShowNsfw } from "redux/selectors/settings";
|
||||
import {
|
||||
makeSelectIsUriResolving,
|
||||
selectRewardContentClaimIds,
|
||||
} from "redux/selectors/content";
|
||||
import FileTile from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doResolveUri } from 'redux/actions/content';
|
||||
import { makeSelectClaimForUri, makeSelectMetadataForUri } from 'redux/selectors/claims';
|
||||
import { makeSelectFileInfoForUri } from 'redux/selectors/file_info';
|
||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||
import { makeSelectIsUriResolving, selectRewardContentClaimIds } from 'redux/selectors/content';
|
||||
import FileTile from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
claim: makeSelectClaimForUri(props.uri)(state),
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import React from "react";
|
||||
import * as icons from "constants/icons";
|
||||
import lbryuri from "lbryuri.js";
|
||||
import CardMedia from "component/cardMedia";
|
||||
import { TruncatedText } from "component/common.js";
|
||||
import FilePrice from "component/filePrice";
|
||||
import NsfwOverlay from "component/nsfwOverlay";
|
||||
import Icon from "component/icon";
|
||||
import React from 'react';
|
||||
import * as icons from 'constants/icons';
|
||||
import lbryuri from 'lbryuri.js';
|
||||
import CardMedia from 'component/cardMedia';
|
||||
import { TruncatedText } from 'component/common.js';
|
||||
import FilePrice from 'component/filePrice';
|
||||
import NsfwOverlay from 'component/nsfwOverlay';
|
||||
import Icon from 'component/icon';
|
||||
|
||||
class FileTile extends React.PureComponent {
|
||||
static SHOW_EMPTY_PUBLISH = "publish";
|
||||
static SHOW_EMPTY_PENDING = "pending";
|
||||
static SHOW_EMPTY_PUBLISH = 'publish';
|
||||
static SHOW_EMPTY_PENDING = 'pending';
|
||||
|
||||
static defaultProps = {
|
||||
showPrice: true,
|
||||
|
@ -36,11 +36,7 @@ class FileTile extends React.PureComponent {
|
|||
}
|
||||
|
||||
handleMouseOver() {
|
||||
if (
|
||||
this.props.obscureNsfw &&
|
||||
this.props.metadata &&
|
||||
this.props.metadata.nsfw
|
||||
) {
|
||||
if (this.props.obscureNsfw && this.props.metadata && this.props.metadata.nsfw) {
|
||||
this.setState({
|
||||
showNsfwHelp: true,
|
||||
});
|
||||
|
@ -73,59 +69,49 @@ class FileTile extends React.PureComponent {
|
|||
const isClaimed = !!claim;
|
||||
const isClaimable = lbryuri.isClaimable(uri);
|
||||
const title =
|
||||
isClaimed && metadata && metadata.title
|
||||
? metadata.title
|
||||
: lbryuri.parse(uri).contentName;
|
||||
const thumbnail =
|
||||
metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||
isClaimed && metadata && metadata.title ? metadata.title : lbryuri.parse(uri).contentName;
|
||||
const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
|
||||
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
|
||||
const isRewardContent =
|
||||
claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||
|
||||
let onClick = () => navigate("/show", { uri });
|
||||
let onClick = () => navigate('/show', { uri });
|
||||
|
||||
let name = "";
|
||||
let name = '';
|
||||
if (claim) {
|
||||
name = claim.name;
|
||||
}
|
||||
|
||||
let description = "";
|
||||
let description = '';
|
||||
if (isClaimed) {
|
||||
description = metadata && metadata.description;
|
||||
} else if (isResolvingUri) {
|
||||
description = __("Loading...");
|
||||
description = __('Loading...');
|
||||
} else if (showEmpty === FileTile.SHOW_EMPTY_PUBLISH) {
|
||||
onClick = () => navigate("/publish", {});
|
||||
onClick = () => navigate('/publish', {});
|
||||
description = (
|
||||
<span className="empty">
|
||||
{__("This location is unused.")}{" "}
|
||||
{isClaimable && (
|
||||
<span className="button-text">{__("Put something here!")}</span>
|
||||
)}
|
||||
{__('This location is unused.')}{' '}
|
||||
{isClaimable && <span className="button-text">{__('Put something here!')}</span>}
|
||||
</span>
|
||||
);
|
||||
} else if (showEmpty === FileTile.SHOW_EMPTY_PENDING) {
|
||||
description = (
|
||||
<span className="empty">
|
||||
{__("This file is pending confirmation.")}
|
||||
</span>
|
||||
);
|
||||
description = <span className="empty">{__('This file is pending confirmation.')}</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<section
|
||||
className={"file-tile card " + (obscureNsfw ? "card--obscured " : "")}
|
||||
className={`file-tile card ${obscureNsfw ? 'card--obscured ' : ''}`}
|
||||
onMouseEnter={this.handleMouseOver.bind(this)}
|
||||
onMouseLeave={this.handleMouseOut.bind(this)}
|
||||
>
|
||||
<div onClick={onClick} className="card__link">
|
||||
<div className={"card__inner file-tile__row"}>
|
||||
<div className="card__inner file-tile__row">
|
||||
<CardMedia title={title || name} thumbnail={thumbnail} />
|
||||
<div className="file-tile__content">
|
||||
<div className="card__title-primary">
|
||||
<span className="card__indicators">
|
||||
{showPrice && <FilePrice uri={this.props.uri} />}{" "}
|
||||
{isRewardContent && <Icon icon={icons.FEATURED} />}{" "}
|
||||
{showPrice && <FilePrice uri={this.props.uri} />}{' '}
|
||||
{isRewardContent && <Icon icon={icons.FEATURED} />}{' '}
|
||||
{showLocal && fileInfo && <Icon icon={icons.LOCAL} />}
|
||||
</span>
|
||||
<h3>
|
||||
|
@ -134,9 +120,7 @@ class FileTile extends React.PureComponent {
|
|||
</div>
|
||||
{description && (
|
||||
<div className="card__content card__subtext">
|
||||
<TruncatedText lines={!showActions ? 3 : 2}>
|
||||
{description}
|
||||
</TruncatedText>
|
||||
<TruncatedText lines={!showActions ? 3 : 2}>{description}</TruncatedText>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import FormField from "component/formField";
|
||||
import { Icon } from "component/common.js";
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import FormField from 'component/formField';
|
||||
import { Icon } from 'component/common.js';
|
||||
|
||||
let formFieldCounter = 0;
|
||||
|
||||
export const formFieldNestedLabelTypes = ["radio", "checkbox"];
|
||||
export const formFieldNestedLabelTypes = ['radio', 'checkbox'];
|
||||
|
||||
export function formFieldId() {
|
||||
return "form-field-" + ++formFieldCounter;
|
||||
return `form-field-${++formFieldCounter}`;
|
||||
}
|
||||
|
||||
export class Form extends React.PureComponent {
|
||||
|
@ -26,11 +26,7 @@ export class Form extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<form onSubmit={event => this.handleSubmit(event)}>
|
||||
{this.props.children}
|
||||
</form>
|
||||
);
|
||||
return <form onSubmit={event => this.handleSubmit(event)}>{this.props.children}</form>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,7 +46,7 @@ export class FormRow extends React.PureComponent {
|
|||
|
||||
this._field = null;
|
||||
|
||||
this._fieldRequiredText = __("This field is required");
|
||||
this._fieldRequiredText = __('This field is required');
|
||||
|
||||
this.state = this.getStateFromProps(props);
|
||||
}
|
||||
|
@ -63,11 +59,9 @@ export class FormRow extends React.PureComponent {
|
|||
return {
|
||||
isError: !!props.errorMessage,
|
||||
errorMessage:
|
||||
typeof props.errorMessage === "string"
|
||||
typeof props.errorMessage === 'string'
|
||||
? props.errorMessage
|
||||
: props.errorMessage instanceof Error
|
||||
? props.errorMessage.toString()
|
||||
: "",
|
||||
: props.errorMessage instanceof Error ? props.errorMessage.toString() : '',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -85,7 +79,7 @@ export class FormRow extends React.PureComponent {
|
|||
clearError(text) {
|
||||
this.setState({
|
||||
isError: false,
|
||||
errorMessage: "",
|
||||
errorMessage: '',
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -116,9 +110,7 @@ export class FormRow extends React.PureComponent {
|
|||
render() {
|
||||
const fieldProps = Object.assign({}, this.props),
|
||||
elementId = formFieldId(),
|
||||
renderLabelInFormField = formFieldNestedLabelTypes.includes(
|
||||
this.props.type
|
||||
);
|
||||
renderLabelInFormField = formFieldNestedLabelTypes.includes(this.props.type);
|
||||
|
||||
if (!renderLabelInFormField) {
|
||||
delete fieldProps.label;
|
||||
|
@ -128,28 +120,24 @@ export class FormRow extends React.PureComponent {
|
|||
delete fieldProps.isFocus;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={"form-row" + (this.state.isFocus ? " form-row--focus" : "")}
|
||||
>
|
||||
<div className={`form-row${this.state.isFocus ? ' form-row--focus' : ''}`}>
|
||||
{this.props.label && !renderLabelInFormField ? (
|
||||
<div
|
||||
className={
|
||||
"form-row__label-row " +
|
||||
(this.props.labelPrefix ? "form-row__label-row--prefix" : "")
|
||||
}
|
||||
className={`form-row__label-row ${
|
||||
this.props.labelPrefix ? 'form-row__label-row--prefix' : ''
|
||||
}`}
|
||||
>
|
||||
<label
|
||||
htmlFor={elementId}
|
||||
className={
|
||||
"form-field__label " +
|
||||
(this.state.isError ? "form-field__label--error" : " ")
|
||||
}
|
||||
className={`form-field__label ${
|
||||
this.state.isError ? 'form-field__label--error' : ' '
|
||||
}`}
|
||||
>
|
||||
{this.props.label}
|
||||
</label>
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
''
|
||||
)}
|
||||
<FormField
|
||||
ref={ref => {
|
||||
|
@ -163,12 +151,12 @@ export class FormRow extends React.PureComponent {
|
|||
{!this.state.isError && this.props.helper ? (
|
||||
<div className="form-field__helper">{this.props.helper}</div>
|
||||
) : (
|
||||
""
|
||||
''
|
||||
)}
|
||||
{this.state.isError ? (
|
||||
<div className="form-field__error">{this.state.errorMessage}</div>
|
||||
) : (
|
||||
""
|
||||
''
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -178,16 +166,14 @@ export class FormRow extends React.PureComponent {
|
|||
export const Submit = props => {
|
||||
const { title, label, icon, disabled } = props;
|
||||
|
||||
const className =
|
||||
"button-block" +
|
||||
" button-primary" +
|
||||
" button-set-item" +
|
||||
" button--submit" +
|
||||
(disabled ? " disabled" : "");
|
||||
const className = `${'button-block' +
|
||||
' button-primary' +
|
||||
' button-set-item' +
|
||||
' button--submit'}${disabled ? ' disabled' : ''}`;
|
||||
|
||||
const content = (
|
||||
<span className="button__content">
|
||||
{"icon" in props ? <Icon icon={icon} fixed={true} /> : null}
|
||||
{'icon' in props ? <Icon icon={icon} fixed /> : null}
|
||||
{label ? <span className="button-label">{label}</span> : null}
|
||||
</span>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import FormField from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import FormField from './view';
|
||||
|
||||
export default connect(null, null, null, { withRef: true })(FormField);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import FileSelector from "component/file-selector.js";
|
||||
import SimpleMDE from "react-simplemde-editor";
|
||||
import { formFieldNestedLabelTypes, formFieldId } from "../form";
|
||||
import style from "react-simplemde-editor/dist/simplemde.min.css";
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import FileSelector from 'component/file-selector.js';
|
||||
import SimpleMDE from 'react-simplemde-editor';
|
||||
import { formFieldNestedLabelTypes, formFieldId } from '../form';
|
||||
import style from 'react-simplemde-editor/dist/simplemde.min.css';
|
||||
|
||||
const formFieldFileSelectorTypes = ["file", "directory"];
|
||||
const formFieldFileSelectorTypes = ['file', 'directory'];
|
||||
|
||||
class FormField extends React.PureComponent {
|
||||
static propTypes = {
|
||||
|
@ -14,10 +14,7 @@ class FormField extends React.PureComponent {
|
|||
postfix: PropTypes.string,
|
||||
hasError: PropTypes.bool,
|
||||
trim: PropTypes.bool,
|
||||
regexp: PropTypes.oneOfType([
|
||||
PropTypes.instanceOf(RegExp),
|
||||
PropTypes.string,
|
||||
]),
|
||||
regexp: PropTypes.oneOfType([PropTypes.instanceOf(RegExp), PropTypes.string]),
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -27,7 +24,7 @@ class FormField extends React.PureComponent {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this._fieldRequiredText = __("This field is required");
|
||||
this._fieldRequiredText = __('This field is required');
|
||||
this._type = null;
|
||||
this._element = null;
|
||||
this._extraElementProps = {};
|
||||
|
@ -39,22 +36,22 @@ class FormField extends React.PureComponent {
|
|||
}
|
||||
|
||||
componentWillMount() {
|
||||
if (["text", "number", "radio", "checkbox"].includes(this.props.type)) {
|
||||
this._element = "input";
|
||||
if (['text', 'number', 'radio', 'checkbox'].includes(this.props.type)) {
|
||||
this._element = 'input';
|
||||
this._type = this.props.type;
|
||||
} else if (this.props.type == "text-number") {
|
||||
this._element = "input";
|
||||
this._type = "text";
|
||||
} else if (this.props.type == "SimpleMDE") {
|
||||
} else if (this.props.type == 'text-number') {
|
||||
this._element = 'input';
|
||||
this._type = 'text';
|
||||
} else if (this.props.type == 'SimpleMDE') {
|
||||
this._element = SimpleMDE;
|
||||
this._type = "textarea";
|
||||
this._type = 'textarea';
|
||||
this._extraElementProps.options = {
|
||||
placeholder: this.props.placeholder,
|
||||
hideIcons: ["heading", "image", "fullscreen", "side-by-side"],
|
||||
hideIcons: ['heading', 'image', 'fullscreen', 'side-by-side'],
|
||||
};
|
||||
} else if (formFieldFileSelectorTypes.includes(this.props.type)) {
|
||||
this._element = "input";
|
||||
this._type = "hidden";
|
||||
this._element = 'input';
|
||||
this._type = 'hidden';
|
||||
} else {
|
||||
// Non <input> field, e.g. <select>, <textarea>
|
||||
this._element = this.props.type;
|
||||
|
@ -66,7 +63,7 @@ class FormField extends React.PureComponent {
|
|||
* We have to add the webkitdirectory attribute here because React doesn't allow it in JSX
|
||||
* https://github.com/facebook/react/issues/3468
|
||||
*/
|
||||
if (this.props.type == "directory") {
|
||||
if (this.props.type == 'directory') {
|
||||
this.refs.field.webkitdirectory = true;
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +72,7 @@ class FormField extends React.PureComponent {
|
|||
this.refs.field.value = path;
|
||||
if (this.props.onChange) {
|
||||
// Updating inputs programmatically doesn't generate an event, so we have to make our own
|
||||
const event = new Event("change", { bubbles: true });
|
||||
const event = new Event('change', { bubbles: true });
|
||||
this.refs.field.dispatchEvent(event); // This alone won't generate a React event, but we use it to attach the field as a target
|
||||
this.props.onChange(event);
|
||||
}
|
||||
|
@ -91,20 +88,17 @@ class FormField extends React.PureComponent {
|
|||
clearError() {
|
||||
this.setState({
|
||||
isError: false,
|
||||
errorMessage: "",
|
||||
errorMessage: '',
|
||||
});
|
||||
}
|
||||
|
||||
getValue() {
|
||||
if (this.props.type == "checkbox") {
|
||||
if (this.props.type == 'checkbox') {
|
||||
return this.refs.field.checked;
|
||||
} else if (this.props.type == "SimpleMDE") {
|
||||
} else if (this.props.type == 'SimpleMDE') {
|
||||
return this.refs.field.simplemde.value();
|
||||
} else {
|
||||
return this.props.trim
|
||||
? this.refs.field.value.trim()
|
||||
: this.refs.field.value;
|
||||
}
|
||||
return this.props.trim ? this.refs.field.value.trim() : this.refs.field.value;
|
||||
}
|
||||
|
||||
getSelectedElement() {
|
||||
|
@ -116,9 +110,9 @@ class FormField extends React.PureComponent {
|
|||
}
|
||||
|
||||
validate() {
|
||||
if ("regexp" in this.props) {
|
||||
if ('regexp' in this.props) {
|
||||
if (!this.getValue().match(this.props.regexp)) {
|
||||
this.showError(__("Invalid format."));
|
||||
this.showError(__('Invalid format.'));
|
||||
} else {
|
||||
this.clearError();
|
||||
}
|
||||
|
@ -133,8 +127,7 @@ class FormField extends React.PureComponent {
|
|||
render() {
|
||||
// Pass all unhandled props to the field element
|
||||
const otherProps = Object.assign({}, this.props),
|
||||
isError =
|
||||
this.state.isError !== null ? this.state.isError : this.props.hasError,
|
||||
isError = this.state.isError !== null ? this.state.isError : this.props.hasError,
|
||||
elementId = this.props.elementId ? this.props.elementId : formFieldId(),
|
||||
renderElementInsideLabel =
|
||||
this.props.label && formFieldNestedLabelTypes.includes(this.props.type);
|
||||
|
@ -158,13 +151,8 @@ class FormField extends React.PureComponent {
|
|||
placeholder={this.props.placeholder}
|
||||
onBlur={() => this.validate()}
|
||||
onFocus={() => this.props.onFocus && this.props.onFocus()}
|
||||
className={
|
||||
"form-field__input form-field__input-" +
|
||||
this.props.type +
|
||||
" " +
|
||||
(this.props.className || "") +
|
||||
(isError ? "form-field__input--error" : "")
|
||||
}
|
||||
className={`form-field__input form-field__input-${this.props.type} ${this.props.className ||
|
||||
''}${isError ? 'form-field__input--error' : ''}`}
|
||||
{...otherProps}
|
||||
{...this._extraElementProps}
|
||||
>
|
||||
|
@ -173,19 +161,13 @@ class FormField extends React.PureComponent {
|
|||
);
|
||||
|
||||
return (
|
||||
<div className={"form-field form-field--" + this.props.type}>
|
||||
{this.props.prefix ? (
|
||||
<span className="form-field__prefix">{this.props.prefix}</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<div className={`form-field form-field--${this.props.type}`}>
|
||||
{this.props.prefix ? <span className="form-field__prefix">{this.props.prefix}</span> : ''}
|
||||
{element}
|
||||
{renderElementInsideLabel && (
|
||||
<label
|
||||
htmlFor={elementId}
|
||||
className={
|
||||
"form-field__label " + (isError ? "form-field__label--error" : "")
|
||||
}
|
||||
className={`form-field__label ${isError ? 'form-field__label--error' : ''}`}
|
||||
>
|
||||
{this.props.label}
|
||||
</label>
|
||||
|
@ -194,20 +176,18 @@ class FormField extends React.PureComponent {
|
|||
<FileSelector
|
||||
type={this.props.type}
|
||||
onFileChosen={this.handleFileChosen.bind(this)}
|
||||
{...(this.props.defaultValue
|
||||
? { initPath: this.props.defaultValue }
|
||||
: {})}
|
||||
{...(this.props.defaultValue ? { initPath: this.props.defaultValue } : {})}
|
||||
/>
|
||||
) : null}
|
||||
{this.props.postfix ? (
|
||||
<span className="form-field__postfix">{this.props.postfix}</span>
|
||||
) : (
|
||||
""
|
||||
''
|
||||
)}
|
||||
{isError && this.state.errorMessage ? (
|
||||
<div className="form-field__error">{this.state.errorMessage}</div>
|
||||
) : (
|
||||
""
|
||||
''
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import FormFieldPrice from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import FormFieldPrice from './view';
|
||||
|
||||
export default connect(null, null)(FormFieldPrice);
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
import React from "react";
|
||||
import FormField from "component/formField";
|
||||
import React from 'react';
|
||||
import FormField from 'component/formField';
|
||||
|
||||
class FormFieldPrice extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
amount:
|
||||
props.defaultValue && props.defaultValue.amount
|
||||
? props.defaultValue.amount
|
||||
: "",
|
||||
amount: props.defaultValue && props.defaultValue.amount ? props.defaultValue.amount : '',
|
||||
currency:
|
||||
props.defaultValue && props.defaultValue.currency
|
||||
? props.defaultValue.currency
|
||||
: "LBC",
|
||||
props.defaultValue && props.defaultValue.currency ? props.defaultValue.currency : 'LBC',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -45,24 +40,20 @@ class FormFieldPrice extends React.PureComponent {
|
|||
name="amount"
|
||||
min={min}
|
||||
placeholder={placeholder || null}
|
||||
step="any" //Unfortunately, you cannot set a step without triggering validation that enforces a multiple of the step
|
||||
step="any" // Unfortunately, you cannot set a step without triggering validation that enforces a multiple of the step
|
||||
onChange={event => this.handleFeeAmountChange(event)}
|
||||
defaultValue={
|
||||
defaultValue && defaultValue.amount ? defaultValue.amount : ""
|
||||
}
|
||||
defaultValue={defaultValue && defaultValue.amount ? defaultValue.amount : ''}
|
||||
className="form-field__input--inline"
|
||||
/>
|
||||
<FormField
|
||||
type="select"
|
||||
name="currency"
|
||||
onChange={event => this.handleFeeCurrencyChange(event)}
|
||||
defaultValue={
|
||||
defaultValue && defaultValue.currency ? defaultValue.currency : ""
|
||||
}
|
||||
defaultValue={defaultValue && defaultValue.currency ? defaultValue.currency : ''}
|
||||
className="form-field__input--inline"
|
||||
>
|
||||
<option value="LBC">{__("LBRY Credits (LBC)")}</option>
|
||||
<option value="USD">{__("US Dollars")}</option>
|
||||
<option value="LBC">{__('LBRY Credits (LBC)')}</option>
|
||||
<option value="USD">{__('US Dollars')}</option>
|
||||
</FormField>
|
||||
</span>
|
||||
);
|
||||
|
|
|
@ -1,19 +1,12 @@
|
|||
import React from "react";
|
||||
import { formatCredits } from "util/formatCredits";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
selectIsBackDisabled,
|
||||
selectIsForwardDisabled,
|
||||
} from "redux/selectors/navigation";
|
||||
import { selectBalance } from "redux/selectors/wallet";
|
||||
import {
|
||||
doNavigate,
|
||||
doHistoryBack,
|
||||
doHistoryForward,
|
||||
} from "redux/actions/navigation";
|
||||
import Header from "./view";
|
||||
import { selectIsUpgradeAvailable } from "redux/selectors/app";
|
||||
import { doDownloadUpgrade } from "redux/actions/app";
|
||||
import React from 'react';
|
||||
import { formatCredits } from 'util/formatCredits';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectIsBackDisabled, selectIsForwardDisabled } from 'redux/selectors/navigation';
|
||||
import { selectBalance } from 'redux/selectors/wallet';
|
||||
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
|
||||
import Header from './view';
|
||||
import { selectIsUpgradeAvailable } from 'redux/selectors/app';
|
||||
import { doDownloadUpgrade } from 'redux/actions/app';
|
||||
|
||||
const select = state => ({
|
||||
isBackDisabled: selectIsBackDisabled(state),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
import WunderBar from "component/wunderbar";
|
||||
import React from 'react';
|
||||
import Link from 'component/link';
|
||||
import WunderBar from 'component/wunderbar';
|
||||
|
||||
export const Header = props => {
|
||||
const {
|
||||
|
@ -21,7 +21,7 @@ export const Header = props => {
|
|||
disabled={isBackDisabled}
|
||||
button="alt button--flat"
|
||||
icon="icon-arrow-left"
|
||||
title={__("Back")}
|
||||
title={__('Back')}
|
||||
/>
|
||||
</div>
|
||||
<div className="header__item">
|
||||
|
@ -30,23 +30,23 @@ export const Header = props => {
|
|||
disabled={isForwardDisabled}
|
||||
button="alt button--flat"
|
||||
icon="icon-arrow-right"
|
||||
title={__("Forward")}
|
||||
title={__('Forward')}
|
||||
/>
|
||||
</div>
|
||||
<div className="header__item">
|
||||
<Link
|
||||
onClick={() => navigate("/discover")}
|
||||
onClick={() => navigate('/discover')}
|
||||
button="alt button--flat"
|
||||
icon="icon-home"
|
||||
title={__("Discover Content")}
|
||||
title={__('Discover Content')}
|
||||
/>
|
||||
</div>
|
||||
<div className="header__item">
|
||||
<Link
|
||||
onClick={() => navigate("/subscriptions")}
|
||||
onClick={() => navigate('/subscriptions')}
|
||||
button="alt button--flat"
|
||||
icon="icon-at"
|
||||
title={__("My Subscriptions")}
|
||||
title={__('My Subscriptions')}
|
||||
/>
|
||||
</div>
|
||||
<div className="header__item header__item--wunderbar">
|
||||
|
@ -54,36 +54,36 @@ export const Header = props => {
|
|||
</div>
|
||||
<div className="header__item">
|
||||
<Link
|
||||
onClick={() => navigate("/wallet")}
|
||||
onClick={() => navigate('/wallet')}
|
||||
button="text"
|
||||
className="no-underline"
|
||||
icon="icon-bank"
|
||||
label={balance}
|
||||
title={__("Wallet")}
|
||||
title={__('Wallet')}
|
||||
/>
|
||||
</div>
|
||||
<div className="header__item">
|
||||
<Link
|
||||
onClick={() => navigate("/publish")}
|
||||
onClick={() => navigate('/publish')}
|
||||
button="primary button--flat"
|
||||
icon="icon-upload"
|
||||
label={__("Publish")}
|
||||
label={__('Publish')}
|
||||
/>
|
||||
</div>
|
||||
<div className="header__item">
|
||||
<Link
|
||||
onClick={() => navigate("/downloaded")}
|
||||
onClick={() => navigate('/downloaded')}
|
||||
button="alt button--flat"
|
||||
icon="icon-folder"
|
||||
title={__("Downloads and Publishes")}
|
||||
title={__('Downloads and Publishes')}
|
||||
/>
|
||||
</div>
|
||||
<div className="header__item">
|
||||
<Link
|
||||
onClick={() => navigate("/settings")}
|
||||
onClick={() => navigate('/settings')}
|
||||
button="alt button--flat"
|
||||
icon="icon-gear"
|
||||
title={__("Settings")}
|
||||
title={__('Settings')}
|
||||
/>
|
||||
</div>
|
||||
{isUpgradeAvailable && (
|
||||
|
@ -91,7 +91,7 @@ export const Header = props => {
|
|||
onClick={() => downloadUpgrade()}
|
||||
button="primary button--flat"
|
||||
icon="icon-arrow-up"
|
||||
label={__("Upgrade App")}
|
||||
label={__('Upgrade App')}
|
||||
/>
|
||||
)}
|
||||
</header>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import Icon from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import Icon from './view';
|
||||
|
||||
export default connect(null, null)(Icon);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import * as icons from "constants/icons";
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import * as icons from 'constants/icons';
|
||||
|
||||
export default class Icon extends React.PureComponent {
|
||||
static propTypes = {
|
||||
|
@ -15,17 +15,17 @@ export default class Icon extends React.PureComponent {
|
|||
getIconClass() {
|
||||
const { icon } = this.props;
|
||||
|
||||
return icon.startsWith("icon-") ? icon : "icon-" + icon;
|
||||
return icon.startsWith('icon-') ? icon : `icon-${icon}`;
|
||||
}
|
||||
|
||||
getIconTitle() {
|
||||
switch (this.props.icon) {
|
||||
case icons.FEATURED:
|
||||
return __("Watch this and earn rewards.");
|
||||
return __('Watch this and earn rewards.');
|
||||
case icons.LOCAL:
|
||||
return __("You have a copy of this file.");
|
||||
return __('You have a copy of this file.');
|
||||
default:
|
||||
return "";
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,7 @@ export default class Icon extends React.PureComponent {
|
|||
const className = this.getIconClass(),
|
||||
title = this.getIconTitle();
|
||||
|
||||
const spanClassName =
|
||||
"icon " + className + (this.props.fixed ? " icon-fixed-width " : "");
|
||||
const spanClassName = `icon ${className}${this.props.fixed ? ' icon-fixed-width ' : ''}`;
|
||||
|
||||
return <span className={spanClassName} title={title} />;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
selectUserInvitees,
|
||||
selectUserInviteStatusIsPending,
|
||||
} from "redux/selectors/user";
|
||||
import InviteList from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectUserInvitees, selectUserInviteStatusIsPending } from 'redux/selectors/user';
|
||||
import InviteList from './view';
|
||||
|
||||
const select = state => ({
|
||||
invitees: selectUserInvitees(state),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { Icon } from "component/common";
|
||||
import RewardLink from "component/rewardLink";
|
||||
import rewards from "rewards.js";
|
||||
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() {
|
||||
|
@ -14,7 +14,7 @@ class InviteList extends React.PureComponent {
|
|||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("Invite History")}</h3>
|
||||
<h3>{__('Invite History')}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
{invitees.length === 0 && (
|
||||
|
@ -24,38 +24,33 @@ class InviteList extends React.PureComponent {
|
|||
<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>
|
||||
<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_reward_claimable ? (
|
||||
<RewardLink
|
||||
label={__("claim")}
|
||||
reward_type={rewards.TYPE_REFERRAL}
|
||||
/>
|
||||
) : (
|
||||
<span className="empty">{__("unclaimable")}</span>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
{invitees.map((invitee, index) => (
|
||||
<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_reward_claimable ? (
|
||||
<RewardLink label={__('claim')} reward_type={rewards.TYPE_REFERRAL} />
|
||||
) : (
|
||||
<span className="empty">{__('unclaimable')}</span>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
|
@ -63,7 +58,7 @@ class InviteList extends React.PureComponent {
|
|||
<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."
|
||||
'The maximum number of invite rewards is currently limited. Invite reward can only be claimed if the invitee passes the humanness test.'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import InviteNew from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import InviteNew from './view';
|
||||
import {
|
||||
selectUserInvitesRemaining,
|
||||
selectUserInviteNewIsPending,
|
||||
selectUserInviteNewErrorMessage,
|
||||
} from "redux/selectors/user";
|
||||
import rewards from "rewards";
|
||||
import { makeSelectRewardAmountByType } from "redux/selectors/rewards";
|
||||
} from 'redux/selectors/user';
|
||||
import rewards from 'rewards';
|
||||
import { makeSelectRewardAmountByType } from 'redux/selectors/rewards';
|
||||
|
||||
import { doUserInviteNew } from "redux/actions/user";
|
||||
import { doUserInviteNew } from 'redux/actions/user';
|
||||
|
||||
const select = state => {
|
||||
const selectReward = makeSelectRewardAmountByType();
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import React from "react";
|
||||
import { BusyMessage, CreditAmount } from "component/common";
|
||||
import { Form, FormRow, Submit } from "component/form.js";
|
||||
import React from 'react';
|
||||
import { BusyMessage, CreditAmount } from 'component/common';
|
||||
import { Form, FormRow, Submit } from 'component/form.js';
|
||||
|
||||
class FormInviteNew extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
email: "",
|
||||
email: '',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ class FormInviteNew extends React.PureComponent {
|
|||
}}
|
||||
/>
|
||||
<div className="form-row-submit">
|
||||
<Submit label={__("Send Invite")} disabled={isPending} />
|
||||
<Submit label={__('Send Invite')} disabled={isPending} />
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
|
@ -61,7 +61,7 @@ class InviteNew extends React.PureComponent {
|
|||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<CreditAmount amount={rewardAmount} />
|
||||
<h3>{__("Invite a Friend")}</h3>
|
||||
<h3>{__('Invite a Friend')}</h3>
|
||||
</div>
|
||||
{/*
|
||||
<div className="card__content">
|
||||
|
@ -71,16 +71,8 @@ class InviteNew extends React.PureComponent {
|
|||
<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}
|
||||
/>
|
||||
<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>
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "redux/actions/navigation";
|
||||
import Link from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import Link from './view';
|
||||
|
||||
const perform = dispatch => ({
|
||||
doNavigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import Icon from "component/icon";
|
||||
import React from 'react';
|
||||
import Icon from 'component/icon';
|
||||
|
||||
const Link = props => {
|
||||
const {
|
||||
|
@ -20,15 +20,15 @@ const Link = props => {
|
|||
} = props;
|
||||
|
||||
const combinedClassName =
|
||||
(className || "") +
|
||||
(!className && !button ? "button-text" : "") + // Non-button links get the same look as text buttons
|
||||
(button ? " button-block button-" + button + " button-set-item" : "") +
|
||||
(disabled ? " disabled" : "");
|
||||
(className || '') +
|
||||
(!className && !button ? 'button-text' : '') + // Non-button links get the same look as text buttons
|
||||
(button ? ` button-block button-${button} button-set-item` : '') +
|
||||
(disabled ? ' disabled' : '');
|
||||
|
||||
const onClick =
|
||||
!props.onClick && navigate
|
||||
? e => {
|
||||
e.stopPropagation();
|
||||
? event => {
|
||||
event.stopPropagation();
|
||||
doNavigate(navigate, navigateParams || {});
|
||||
}
|
||||
: props.onClick;
|
||||
|
@ -38,27 +38,23 @@ const Link = props => {
|
|||
content = children;
|
||||
} else {
|
||||
content = (
|
||||
<span {...("button" in props ? { className: "button__content" } : {})}>
|
||||
{icon ? <Icon icon={icon} fixed={true} /> : null}
|
||||
<span {...('button' in props ? { className: 'button__content' } : {})}>
|
||||
{icon ? <Icon icon={icon} fixed /> : null}
|
||||
{label ? <span className="link-label">{label}</span> : null}
|
||||
{iconRight ? <Icon icon={iconRight} fixed={true} /> : null}
|
||||
{iconRight ? <Icon icon={iconRight} fixed /> : null}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
const linkProps = {
|
||||
className: combinedClassName,
|
||||
href: href || "javascript:;",
|
||||
href: href || 'javascript:;',
|
||||
title,
|
||||
onClick,
|
||||
style,
|
||||
};
|
||||
|
||||
return span ? (
|
||||
<span {...linkProps}>{content}</span>
|
||||
) : (
|
||||
<a {...linkProps}>{content}</a>
|
||||
);
|
||||
return span ? <span {...linkProps}>{content}</span> : <a {...linkProps}>{content}</a>;
|
||||
};
|
||||
|
||||
export default Link;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import LinkTransaction from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import LinkTransaction from './view';
|
||||
|
||||
export default connect(null, null)(LinkTransaction);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
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.href = `https://explorer.lbry.io/#!/transaction/${id}`;
|
||||
linkProps.label = id.substr(0, 7);
|
||||
|
||||
return <Link {...linkProps} />;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import lbry from "../lbry.js";
|
||||
import { BusyMessage, Icon } from "./common.js";
|
||||
import Link from "component/link";
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import lbry from '../lbry.js';
|
||||
import { BusyMessage, Icon } from './common.js';
|
||||
import Link from 'component/link';
|
||||
|
||||
class LoadScreen extends React.PureComponent {
|
||||
static propTypes = {
|
||||
|
@ -26,7 +26,7 @@ class LoadScreen extends React.PureComponent {
|
|||
};
|
||||
|
||||
render() {
|
||||
const imgSrc = lbry.imagePath("lbry-white-485x160.png");
|
||||
const imgSrc = lbry.imagePath('lbry-white-485x160.png');
|
||||
return (
|
||||
<div className="load-screen">
|
||||
<img src={imgSrc} alt="LBRY" />
|
||||
|
@ -37,15 +37,14 @@ class LoadScreen extends React.PureComponent {
|
|||
) : (
|
||||
<span>
|
||||
<Icon icon="icon-warning" />
|
||||
{" " + this.props.message}
|
||||
{` ${this.props.message}`}
|
||||
</span>
|
||||
)}
|
||||
</h3>
|
||||
<span
|
||||
className={
|
||||
"load-screen__details " +
|
||||
(this.props.isWarning ? "load-screen__details--warning" : "")
|
||||
}
|
||||
className={`load-screen__details ${
|
||||
this.props.isWarning ? 'load-screen__details--warning' : ''
|
||||
}`}
|
||||
>
|
||||
{this.props.details}
|
||||
</span>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Icon } from "./common.js";
|
||||
import Link from "component/link";
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Icon } from './common.js';
|
||||
import Link from 'component/link';
|
||||
|
||||
export class DropDownMenuItem extends React.PureComponent {
|
||||
static propTypes = {
|
||||
|
@ -12,22 +12,22 @@ export class DropDownMenuItem extends React.PureComponent {
|
|||
};
|
||||
|
||||
static defaultProps = {
|
||||
iconPosition: "left",
|
||||
iconPosition: 'left',
|
||||
};
|
||||
|
||||
render() {
|
||||
var icon = this.props.icon ? <Icon icon={this.props.icon} fixed /> : null;
|
||||
const icon = this.props.icon ? <Icon icon={this.props.icon} fixed /> : null;
|
||||
|
||||
return (
|
||||
<a
|
||||
className="menu__menu-item"
|
||||
onClick={this.props.onClick}
|
||||
href={this.props.href || "javascript:"}
|
||||
href={this.props.href || 'javascript:'}
|
||||
label={this.props.label}
|
||||
>
|
||||
{this.props.iconPosition == "left" ? icon : null}
|
||||
{this.props.iconPosition == 'left' ? icon : null}
|
||||
{this.props.label}
|
||||
{this.props.iconPosition == "left" ? null : icon}
|
||||
{this.props.iconPosition == 'left' ? null : icon}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ export class DropDownMenu extends React.PureComponent {
|
|||
|
||||
componentWillUnmount() {
|
||||
if (this._isWindowClickBound) {
|
||||
window.removeEventListener("click", this.handleWindowClick, false);
|
||||
window.removeEventListener('click', this.handleWindowClick, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ export class DropDownMenu extends React.PureComponent {
|
|||
});
|
||||
if (!this.state.menuOpen && !this._isWindowClickBound) {
|
||||
this._isWindowClickBound = true;
|
||||
window.addEventListener("click", this.handleWindowClick, false);
|
||||
window.addEventListener('click', this.handleWindowClick, false);
|
||||
e.stopPropagation();
|
||||
}
|
||||
return false;
|
||||
|
@ -70,12 +70,9 @@ export class DropDownMenu extends React.PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
/*this will force "this" to always be the class, even when passed to an event listener*/
|
||||
/* this will force "this" to always be the class, even when passed to an event listener */
|
||||
handleWindowClick = e => {
|
||||
if (
|
||||
this.state.menuOpen &&
|
||||
(!this._menuDiv || !this._menuDiv.contains(e.target))
|
||||
) {
|
||||
if (this.state.menuOpen && (!this._menuDiv || !this._menuDiv.contains(e.target))) {
|
||||
this.setState({
|
||||
menuOpen: false,
|
||||
});
|
||||
|
@ -85,7 +82,7 @@ export class DropDownMenu extends React.PureComponent {
|
|||
render() {
|
||||
if (!this.state.menuOpen && this._isWindowClickBound) {
|
||||
this._isWindowClickBound = false;
|
||||
window.removeEventListener("click", this.handleWindowClick, false);
|
||||
window.removeEventListener('click', this.handleWindowClick, false);
|
||||
}
|
||||
return (
|
||||
<div className="menu-container">
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "redux/actions/navigation";
|
||||
import NsfwOverlay from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import NsfwOverlay from './view';
|
||||
|
||||
const perform = dispatch => ({
|
||||
navigateSettings: () => dispatch(doNavigate("/settings")),
|
||||
navigateSettings: () => dispatch(doNavigate('/settings')),
|
||||
});
|
||||
|
||||
export default connect(null, perform)(NsfwOverlay);
|
||||
|
|
|
@ -1,21 +1,17 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
import React from 'react';
|
||||
import Link from 'component/link';
|
||||
|
||||
const NsfwOverlay = props => {
|
||||
return (
|
||||
<div className="card-overlay">
|
||||
<p>
|
||||
{__(
|
||||
"This content is Not Safe For Work. To view adult content, please change your"
|
||||
)}{" "}
|
||||
<Link
|
||||
className="button-text"
|
||||
onClick={() => props.navigateSettings()}
|
||||
label={__("Settings")}
|
||||
/>.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const NsfwOverlay = props => (
|
||||
<div className="card-overlay">
|
||||
<p>
|
||||
{__('This content is Not Safe For Work. To view adult content, please change your')}{' '}
|
||||
<Link
|
||||
className="button-text"
|
||||
onClick={() => props.navigateSettings()}
|
||||
label={__('Settings')}
|
||||
/>.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default NsfwOverlay;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import PublishForm from "./view";
|
||||
import { selectBalance } from "redux/selectors/wallet";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PublishForm from './view';
|
||||
import { selectBalance } from 'redux/selectors/wallet';
|
||||
|
||||
const select = state => ({
|
||||
balance: selectBalance(state),
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import React from "react";
|
||||
import lbryuri from "lbryuri";
|
||||
import { FormRow } from "component/form.js";
|
||||
import { BusyMessage } from "component/common";
|
||||
import Link from "component/link";
|
||||
import React from 'react';
|
||||
import lbryuri from 'lbryuri';
|
||||
import { FormRow } from 'component/form.js';
|
||||
import { BusyMessage } from 'component/common';
|
||||
import Link from 'component/link';
|
||||
|
||||
class ChannelSection extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
newChannelName: "@",
|
||||
newChannelName: '@',
|
||||
newChannelBid: 10,
|
||||
addingChannel: false,
|
||||
};
|
||||
|
@ -17,7 +17,7 @@ class ChannelSection extends React.PureComponent {
|
|||
|
||||
handleChannelChange(event) {
|
||||
const channel = event.target.value;
|
||||
if (channel === "new") this.setState({ addingChannel: true });
|
||||
if (channel === 'new') this.setState({ addingChannel: true });
|
||||
else {
|
||||
this.setState({ addingChannel: false });
|
||||
this.props.handleChannelChange(event.target.value);
|
||||
|
@ -25,21 +25,17 @@ class ChannelSection extends React.PureComponent {
|
|||
}
|
||||
|
||||
handleNewChannelNameChange(event) {
|
||||
const newChannelName = event.target.value.startsWith("@")
|
||||
const newChannelName = event.target.value.startsWith('@')
|
||||
? event.target.value
|
||||
: "@" + event.target.value;
|
||||
: `@${event.target.value}`;
|
||||
|
||||
if (
|
||||
newChannelName.length > 1 &&
|
||||
!lbryuri.isValidName(newChannelName.substr(1), false)
|
||||
) {
|
||||
if (newChannelName.length > 1 && !lbryuri.isValidName(newChannelName.substr(1), false)) {
|
||||
this.refs.newChannelName.showError(
|
||||
__("LBRY channel names must contain only letters, numbers and dashes.")
|
||||
__('LBRY channel names must contain only letters, numbers and dashes.')
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
this.refs.newChannelName.clearError();
|
||||
}
|
||||
this.refs.newChannelName.clearError();
|
||||
|
||||
this.setState({
|
||||
newChannelName,
|
||||
|
@ -57,9 +53,7 @@ class ChannelSection extends React.PureComponent {
|
|||
const { newChannelBid } = this.state;
|
||||
|
||||
if (newChannelBid > balance) {
|
||||
this.refs.newChannelName.showError(
|
||||
__("Unable to create channel due to insufficient funds.")
|
||||
);
|
||||
this.refs.newChannelName.showError(__('Unable to create channel due to insufficient funds.'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -85,19 +79,17 @@ class ChannelSection extends React.PureComponent {
|
|||
this.setState({
|
||||
creatingChannel: false,
|
||||
});
|
||||
this.refs.newChannelName.showError(
|
||||
__("Unable to create channel due to an internal error.")
|
||||
);
|
||||
this.refs.newChannelName.showError(__('Unable to create channel due to an internal error.'));
|
||||
};
|
||||
this.props.createChannel(newChannelName, amount).then(success, failure);
|
||||
}
|
||||
|
||||
render() {
|
||||
const lbcInputHelp = __(
|
||||
"This LBC remains yours. It is a deposit to reserve the name and can be undone at any time."
|
||||
'This LBC remains yours. It is a deposit to reserve the name and can be undone at any time.'
|
||||
);
|
||||
|
||||
const channel = this.state.addingChannel ? "new" : this.props.channel;
|
||||
const channel = this.state.addingChannel ? 'new' : this.props.channel;
|
||||
const { fetchingChannels, channels = [] } = this.props;
|
||||
|
||||
const channelSelector = (
|
||||
|
@ -109,7 +101,7 @@ class ChannelSection extends React.PureComponent {
|
|||
value={channel}
|
||||
>
|
||||
<option key="anonymous" value="anonymous">
|
||||
{__("Anonymous")}
|
||||
{__('Anonymous')}
|
||||
</option>
|
||||
{channels.map(({ name }) => (
|
||||
<option key={name} value={name}>
|
||||
|
@ -117,7 +109,7 @@ class ChannelSection extends React.PureComponent {
|
|||
</option>
|
||||
))}
|
||||
<option key="new" value="new">
|
||||
{__("New channel...")}
|
||||
{__('New channel...')}
|
||||
</option>
|
||||
</FormRow>
|
||||
);
|
||||
|
@ -125,12 +117,10 @@ class ChannelSection extends React.PureComponent {
|
|||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h4>{__("Channel Name")}</h4>
|
||||
<h4>{__('Channel Name')}</h4>
|
||||
<div className="card__subtitle">
|
||||
{__(
|
||||
"This is a username or handle that your content can be found under."
|
||||
)}{" "}
|
||||
{__("Ex. @Marvel, @TheBeatles, @BooksByJoe")}
|
||||
{__('This is a username or handle that your content can be found under.')}{' '}
|
||||
{__('Ex. @Marvel, @TheBeatles, @BooksByJoe')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
|
@ -143,13 +133,13 @@ class ChannelSection extends React.PureComponent {
|
|||
{this.state.addingChannel && (
|
||||
<div className="card__content">
|
||||
<FormRow
|
||||
label={__("Name")}
|
||||
label={__('Name')}
|
||||
type="text"
|
||||
onChange={this.handleNewChannelNameChange.bind(this)}
|
||||
value={this.state.newChannelName}
|
||||
/>
|
||||
<FormRow
|
||||
label={__("Deposit")}
|
||||
label={__('Deposit')}
|
||||
postfix="LBC"
|
||||
step="any"
|
||||
min="0"
|
||||
|
@ -163,9 +153,7 @@ class ChannelSection extends React.PureComponent {
|
|||
<Link
|
||||
button="primary"
|
||||
label={
|
||||
!this.state.creatingChannel
|
||||
? __("Create channel")
|
||||
: __("Creating channel...")
|
||||
!this.state.creatingChannel ? __('Create channel') : __('Creating channel...')
|
||||
}
|
||||
onClick={this.handleCreateChannelClick.bind(this)}
|
||||
disabled={this.state.creatingChannel}
|
||||
|
|
|
@ -1,44 +1,44 @@
|
|||
import React from "react";
|
||||
import lbry from "lbry";
|
||||
import lbryuri from "lbryuri";
|
||||
import FormField from "component/formField";
|
||||
import { Form, FormRow, Submit } from "component/form.js";
|
||||
import Link from "component/link";
|
||||
import FormFieldPrice from "component/formFieldPrice";
|
||||
import Modal from "modal/modal";
|
||||
import { BusyMessage } from "component/common";
|
||||
import ChannelSection from "./internal/channelSection";
|
||||
import React from 'react';
|
||||
import lbry from 'lbry';
|
||||
import lbryuri from 'lbryuri';
|
||||
import FormField from 'component/formField';
|
||||
import { Form, FormRow, Submit } from 'component/form.js';
|
||||
import Link from 'component/link';
|
||||
import FormFieldPrice from 'component/formFieldPrice';
|
||||
import Modal from 'modal/modal';
|
||||
import { BusyMessage } from 'component/common';
|
||||
import ChannelSection from './internal/channelSection';
|
||||
|
||||
class PublishForm extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this._requiredFields = ["name", "bid", "meta_title", "tosAgree"];
|
||||
this._requiredFields = ['name', 'bid', 'meta_title', 'tosAgree'];
|
||||
|
||||
this._defaultCopyrightNotice = "All rights reserved.";
|
||||
this._defaultCopyrightNotice = 'All rights reserved.';
|
||||
this._defaultPaidPrice = 0.01;
|
||||
|
||||
this.state = {
|
||||
id: null,
|
||||
uri: null,
|
||||
rawName: "",
|
||||
name: "",
|
||||
rawName: '',
|
||||
name: '',
|
||||
bid: 10,
|
||||
hasFile: false,
|
||||
feeAmount: "",
|
||||
feeCurrency: "LBC",
|
||||
channel: "anonymous",
|
||||
newChannelName: "@",
|
||||
feeAmount: '',
|
||||
feeCurrency: 'LBC',
|
||||
channel: 'anonymous',
|
||||
newChannelName: '@',
|
||||
newChannelBid: 10,
|
||||
meta_title: "",
|
||||
meta_thumbnail: "",
|
||||
meta_description: "",
|
||||
meta_language: "en",
|
||||
meta_nsfw: "0",
|
||||
licenseType: "",
|
||||
meta_title: '',
|
||||
meta_thumbnail: '',
|
||||
meta_description: '',
|
||||
meta_language: 'en',
|
||||
meta_nsfw: '0',
|
||||
licenseType: '',
|
||||
copyrightNotice: this._defaultCopyrightNotice,
|
||||
otherLicenseDescription: "",
|
||||
otherLicenseUrl: "",
|
||||
otherLicenseDescription: '',
|
||||
otherLicenseUrl: '',
|
||||
tosAgree: false,
|
||||
prefillDone: false,
|
||||
uploadProgress: 0.0,
|
||||
|
@ -50,7 +50,7 @@ class PublishForm extends React.PureComponent {
|
|||
isFee: false,
|
||||
customUrl: false,
|
||||
source: null,
|
||||
mode: "publish",
|
||||
mode: 'publish',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ class PublishForm extends React.PureComponent {
|
|||
const { bid } = this.state;
|
||||
|
||||
if (bid > balance) {
|
||||
this.handlePublishError({ message: "insufficient funds" });
|
||||
this.handlePublishError({ message: 'insufficient funds' });
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -74,16 +74,16 @@ class PublishForm extends React.PureComponent {
|
|||
submitting: true,
|
||||
});
|
||||
|
||||
let checkFields = this._requiredFields;
|
||||
const checkFields = this._requiredFields;
|
||||
if (!this.myClaimExists()) {
|
||||
checkFields.unshift("file");
|
||||
checkFields.unshift('file');
|
||||
}
|
||||
|
||||
let missingFieldFound = false;
|
||||
for (let fieldName of checkFields) {
|
||||
for (const fieldName of checkFields) {
|
||||
const field = this.refs[fieldName];
|
||||
if (field) {
|
||||
if (field.getValue() === "" || field.getValue() === false) {
|
||||
if (field.getValue() === '' || field.getValue() === false) {
|
||||
field.showRequiredError();
|
||||
if (!missingFieldFound) {
|
||||
field.focus();
|
||||
|
@ -102,10 +102,10 @@ class PublishForm extends React.PureComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
let metadata = {};
|
||||
const metadata = {};
|
||||
|
||||
for (let metaField of ["title", "description", "thumbnail", "language"]) {
|
||||
const value = this.state["meta_" + metaField];
|
||||
for (const metaField of ['title', 'description', 'thumbnail', 'language']) {
|
||||
const value = this.state[`meta_${metaField}`];
|
||||
if (value) {
|
||||
metadata[metaField] = value;
|
||||
}
|
||||
|
@ -115,19 +115,19 @@ class PublishForm extends React.PureComponent {
|
|||
metadata.licenseUrl = this.getLicenseUrl();
|
||||
metadata.nsfw = !!parseInt(this.state.meta_nsfw);
|
||||
|
||||
var doPublish = () => {
|
||||
var publishArgs = {
|
||||
const doPublish = () => {
|
||||
const publishArgs = {
|
||||
name: this.state.name,
|
||||
bid: parseFloat(this.state.bid),
|
||||
metadata: metadata,
|
||||
...(this.state.channel != "new" && this.state.channel != "anonymous"
|
||||
metadata,
|
||||
...(this.state.channel != 'new' && this.state.channel != 'anonymous'
|
||||
? { channel_name: this.state.channel }
|
||||
: {}),
|
||||
};
|
||||
|
||||
const { source } = this.state;
|
||||
|
||||
if (this.refs.file.getValue() !== "") {
|
||||
if (this.refs.file.getValue() !== '') {
|
||||
publishArgs.file_path = this.refs.file.getValue();
|
||||
} else if (source) {
|
||||
publishArgs.sources = source;
|
||||
|
@ -145,7 +145,7 @@ class PublishForm extends React.PureComponent {
|
|||
metadata.fee = {
|
||||
currency: this.state.feeCurrency,
|
||||
amount: parseFloat(this.state.feeAmount),
|
||||
address: address,
|
||||
address,
|
||||
};
|
||||
|
||||
doPublish();
|
||||
|
@ -157,18 +157,18 @@ class PublishForm extends React.PureComponent {
|
|||
|
||||
handlePublishStarted() {
|
||||
this.setState({
|
||||
modal: "publishStarted",
|
||||
modal: 'publishStarted',
|
||||
});
|
||||
}
|
||||
|
||||
handlePublishStartedConfirmed() {
|
||||
this.props.navigate("/published");
|
||||
this.props.navigate('/published');
|
||||
}
|
||||
|
||||
handlePublishError(error) {
|
||||
this.setState({
|
||||
submitting: false,
|
||||
modal: "error",
|
||||
modal: 'error',
|
||||
errorMessage: error.message,
|
||||
});
|
||||
}
|
||||
|
@ -220,13 +220,11 @@ class PublishForm extends React.PureComponent {
|
|||
myClaimInfo() {
|
||||
const { id } = this.state;
|
||||
|
||||
return Object.values(this.props.myClaims).find(
|
||||
claim => claim.claim_id === id
|
||||
);
|
||||
return Object.values(this.props.myClaims).find(claim => claim.claim_id === id);
|
||||
}
|
||||
|
||||
handleNameChange(event) {
|
||||
var rawName = event.target.value;
|
||||
const rawName = event.target.value;
|
||||
this.setState({
|
||||
customUrl: Boolean(rawName.length),
|
||||
});
|
||||
|
@ -237,33 +235,31 @@ class PublishForm extends React.PureComponent {
|
|||
nameChanged(rawName) {
|
||||
if (!rawName) {
|
||||
this.setState({
|
||||
rawName: "",
|
||||
name: "",
|
||||
uri: "",
|
||||
rawName: '',
|
||||
name: '',
|
||||
uri: '',
|
||||
prefillDone: false,
|
||||
mode: "publish",
|
||||
mode: 'publish',
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lbryuri.isValidName(rawName, false)) {
|
||||
this.refs.name.showError(
|
||||
__("LBRY names must contain only letters, numbers and dashes.")
|
||||
);
|
||||
this.refs.name.showError(__('LBRY names must contain only letters, numbers and dashes.'));
|
||||
return;
|
||||
}
|
||||
|
||||
let channel = "";
|
||||
if (this.state.channel !== "anonymous") channel = this.state.channel;
|
||||
let channel = '';
|
||||
if (this.state.channel !== 'anonymous') channel = this.state.channel;
|
||||
|
||||
const name = rawName.toLowerCase();
|
||||
const uri = lbryuri.build({ contentName: name, channelName: channel });
|
||||
this.setState({
|
||||
rawName: rawName,
|
||||
name: name,
|
||||
rawName,
|
||||
name,
|
||||
prefillDone: false,
|
||||
mode: "publish",
|
||||
mode: 'publish',
|
||||
uri,
|
||||
});
|
||||
|
||||
|
@ -282,26 +278,18 @@ class PublishForm extends React.PureComponent {
|
|||
const { claim_id, name, channel_name, amount } = claimInfo;
|
||||
const { source, metadata } = claimInfo.value.stream;
|
||||
|
||||
const {
|
||||
license,
|
||||
licenseUrl,
|
||||
title,
|
||||
thumbnail,
|
||||
description,
|
||||
language,
|
||||
nsfw,
|
||||
} = metadata;
|
||||
const { license, licenseUrl, title, thumbnail, description, language, nsfw } = metadata;
|
||||
|
||||
let newState = {
|
||||
const newState = {
|
||||
id: claim_id,
|
||||
channel: channel_name || "anonymous",
|
||||
channel: channel_name || 'anonymous',
|
||||
bid: amount,
|
||||
meta_title: title,
|
||||
meta_thumbnail: thumbnail,
|
||||
meta_description: description,
|
||||
meta_language: language,
|
||||
meta_nsfw: nsfw,
|
||||
mode: "edit",
|
||||
mode: 'edit',
|
||||
prefillDone: true,
|
||||
rawName: name,
|
||||
name,
|
||||
|
@ -309,21 +297,18 @@ class PublishForm extends React.PureComponent {
|
|||
};
|
||||
|
||||
if (license == this._defaultCopyrightNotice) {
|
||||
newState.licenseType = "copyright";
|
||||
newState.licenseType = 'copyright';
|
||||
newState.copyrightNotice = this._defaultCopyrightNotice;
|
||||
} else {
|
||||
// If the license URL or description matches one of the drop-down options, use that
|
||||
let licenseType = "other"; // Will be overridden if we find a match
|
||||
for (let option of this._meta_license.getOptions()) {
|
||||
if (
|
||||
option.getAttribute("data-url") === licenseUrl ||
|
||||
option.text === license
|
||||
) {
|
||||
let licenseType = 'other'; // Will be overridden if we find a match
|
||||
for (const option of this._meta_license.getOptions()) {
|
||||
if (option.getAttribute('data-url') === licenseUrl || option.text === license) {
|
||||
licenseType = option.value;
|
||||
}
|
||||
}
|
||||
|
||||
if (licenseType == "other") {
|
||||
if (licenseType == 'other') {
|
||||
newState.otherLicenseDescription = license;
|
||||
newState.otherLicenseUrl = licenseUrl;
|
||||
}
|
||||
|
@ -349,10 +334,7 @@ class PublishForm extends React.PureComponent {
|
|||
handleFeePrefChange(feeEnabled) {
|
||||
this.setState({
|
||||
isFee: feeEnabled,
|
||||
feeAmount:
|
||||
this.state.feeAmount == ""
|
||||
? this._defaultPaidPrice
|
||||
: this.state.feeAmount,
|
||||
feeAmount: this.state.feeAmount == '' ? this._defaultPaidPrice : this.state.feeAmount,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -363,7 +345,7 @@ class PublishForm extends React.PureComponent {
|
|||
* more complex logic and the final value is determined at submit time.
|
||||
*/
|
||||
this.setState({
|
||||
["meta_" + event.target.name]: event.target.value,
|
||||
[`meta_${event.target.name}`]: event.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -399,7 +381,7 @@ class PublishForm extends React.PureComponent {
|
|||
|
||||
handleChannelChange(channelName) {
|
||||
this.setState({
|
||||
mode: "publish",
|
||||
mode: 'publish',
|
||||
channel: channelName,
|
||||
});
|
||||
const nameChanged = () => this.nameChanged(this.state.rawName);
|
||||
|
@ -414,9 +396,9 @@ class PublishForm extends React.PureComponent {
|
|||
|
||||
getLicense() {
|
||||
switch (this.state.licenseType) {
|
||||
case "copyright":
|
||||
case 'copyright':
|
||||
return this.state.copyrightNotice;
|
||||
case "other":
|
||||
case 'other':
|
||||
return this.state.otherLicenseDescription;
|
||||
default:
|
||||
return this._meta_license.getSelectedElement().text;
|
||||
|
@ -425,12 +407,12 @@ class PublishForm extends React.PureComponent {
|
|||
|
||||
getLicenseUrl() {
|
||||
switch (this.state.licenseType) {
|
||||
case "copyright":
|
||||
return "";
|
||||
case "other":
|
||||
case 'copyright':
|
||||
return '';
|
||||
case 'other':
|
||||
return this.state.otherLicenseUrl;
|
||||
default:
|
||||
return this._meta_license.getSelectedElement().getAttribute("data-url");
|
||||
return this._meta_license.getSelectedElement().getAttribute('data-url');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -450,8 +432,8 @@ class PublishForm extends React.PureComponent {
|
|||
const { mode } = this.state;
|
||||
if (this.refs.file.getValue()) {
|
||||
this.setState({ hasFile: true });
|
||||
if (!this.state.customUrl && mode !== "edit") {
|
||||
let fileName = this._getFileName(this.refs.file.getValue());
|
||||
if (!this.state.customUrl && mode !== 'edit') {
|
||||
const fileName = this._getFileName(this.refs.file.getValue());
|
||||
this.nameChanged(fileName);
|
||||
}
|
||||
} else {
|
||||
|
@ -460,11 +442,11 @@ class PublishForm extends React.PureComponent {
|
|||
}
|
||||
|
||||
_getFileName(fileName) {
|
||||
const path = require("path");
|
||||
const path = require('path');
|
||||
const extension = path.extname(fileName);
|
||||
|
||||
fileName = path.basename(fileName, extension);
|
||||
fileName = fileName.replace(lbryuri.REGEXP_INVALID_URI, "");
|
||||
fileName = fileName.replace(lbryuri.REGEXP_INVALID_URI, '');
|
||||
return fileName;
|
||||
}
|
||||
|
||||
|
@ -474,23 +456,20 @@ class PublishForm extends React.PureComponent {
|
|||
const claim = this.claim();
|
||||
|
||||
if (prefillDone) {
|
||||
return __("Existing claim data was prefilled");
|
||||
return __('Existing claim data was prefilled');
|
||||
}
|
||||
|
||||
if (uri && resolvingUris.indexOf(uri) !== -1 && claim === undefined) {
|
||||
return __("Checking...");
|
||||
return __('Checking...');
|
||||
} else if (!name) {
|
||||
return __("Select a URL for this publish.");
|
||||
return __('Select a URL for this publish.');
|
||||
} else if (!claim) {
|
||||
return __("This URL is unused.");
|
||||
return __('This URL is unused.');
|
||||
} else if (this.myClaimExists() && !prefillDone) {
|
||||
return (
|
||||
<span>
|
||||
{__("You already have a claim with this name.")}{" "}
|
||||
<Link
|
||||
label={__("Edit existing claim")}
|
||||
onClick={() => this.handleEditClaim()}
|
||||
/>
|
||||
{__('You already have a claim with this name.')}{' '}
|
||||
<Link label={__('Edit existing claim')} onClick={() => this.handleEditClaim()} />
|
||||
</span>
|
||||
);
|
||||
} else if (claim) {
|
||||
|
@ -504,20 +483,18 @@ class PublishForm extends React.PureComponent {
|
|||
)}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<span>
|
||||
{__(
|
||||
'A deposit of at least "%s" credits is required to win "%s". However, you can still get a permanent URL for any amount.',
|
||||
topClaimValue,
|
||||
name
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
return (
|
||||
<span>
|
||||
{__(
|
||||
'A deposit of at least "%s" credits is required to win "%s". However, you can still get a permanent URL for any amount.',
|
||||
topClaimValue,
|
||||
name
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
closeModal() {
|
||||
|
@ -529,14 +506,12 @@ class PublishForm extends React.PureComponent {
|
|||
render() {
|
||||
const { mode, submitting } = this.state;
|
||||
|
||||
const lbcInputHelp = __(
|
||||
"This LBC remains yours and the deposit can be undone at any time."
|
||||
);
|
||||
const lbcInputHelp = __('This LBC remains yours and the deposit can be undone at any time.');
|
||||
|
||||
let submitLabel = !submitting ? __("Publish") : __("Publishing...");
|
||||
let submitLabel = !submitting ? __('Publish') : __('Publishing...');
|
||||
|
||||
if (mode === "edit") {
|
||||
submitLabel = !submitting ? __("Update") : __("Updating...");
|
||||
if (mode === 'edit') {
|
||||
submitLabel = !submitting ? __('Update') : __('Updating...');
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -544,10 +519,8 @@ class PublishForm extends React.PureComponent {
|
|||
<Form onSubmit={this.handleSubmit.bind(this)}>
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h4>{__("Content")}</h4>
|
||||
<div className="card__subtitle">
|
||||
{__("What are you publishing?")}
|
||||
</div>
|
||||
<h4>{__('Content')}</h4>
|
||||
<div className="card__subtitle">{__('What are you publishing?')}</div>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<FormRow
|
||||
|
@ -571,7 +544,7 @@ class PublishForm extends React.PureComponent {
|
|||
<div className="card__content">
|
||||
<FormRow
|
||||
ref="meta_title"
|
||||
label={__("Title")}
|
||||
label={__('Title')}
|
||||
type="text"
|
||||
name="title"
|
||||
value={this.state.meta_title}
|
||||
|
@ -584,7 +557,7 @@ class PublishForm extends React.PureComponent {
|
|||
<div className="card__content">
|
||||
<FormRow
|
||||
type="text"
|
||||
label={__("Thumbnail URL")}
|
||||
label={__('Thumbnail URL')}
|
||||
name="thumbnail"
|
||||
value={this.state.meta_thumbnail}
|
||||
placeholder="http://spee.ch/mylogo"
|
||||
|
@ -596,11 +569,11 @@ class PublishForm extends React.PureComponent {
|
|||
<div className="card__content">
|
||||
<FormRow
|
||||
type="SimpleMDE"
|
||||
label={__("Description")}
|
||||
label={__('Description')}
|
||||
ref="meta_description"
|
||||
name="description"
|
||||
value={this.state.meta_description}
|
||||
placeholder={__("Description of your content")}
|
||||
placeholder={__('Description of your content')}
|
||||
onChange={text => {
|
||||
this.handleDescriptionChanged(text);
|
||||
}}
|
||||
|
@ -608,7 +581,7 @@ class PublishForm extends React.PureComponent {
|
|||
</div>
|
||||
<div className="card__content">
|
||||
<FormRow
|
||||
label={__("Language")}
|
||||
label={__('Language')}
|
||||
type="select"
|
||||
value={this.state.meta_language}
|
||||
name="language"
|
||||
|
@ -616,19 +589,19 @@ class PublishForm extends React.PureComponent {
|
|||
this.handleMetadataChange(event);
|
||||
}}
|
||||
>
|
||||
<option value="en">{__("English")}</option>
|
||||
<option value="zh">{__("Chinese")}</option>
|
||||
<option value="fr">{__("French")}</option>
|
||||
<option value="de">{__("German")}</option>
|
||||
<option value="jp">{__("Japanese")}</option>
|
||||
<option value="ru">{__("Russian")}</option>
|
||||
<option value="es">{__("Spanish")}</option>
|
||||
<option value="en">{__('English')}</option>
|
||||
<option value="zh">{__('Chinese')}</option>
|
||||
<option value="fr">{__('French')}</option>
|
||||
<option value="de">{__('German')}</option>
|
||||
<option value="jp">{__('Japanese')}</option>
|
||||
<option value="ru">{__('Russian')}</option>
|
||||
<option value="es">{__('Spanish')}</option>
|
||||
</FormRow>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<FormRow
|
||||
type="select"
|
||||
label={__("Maturity")}
|
||||
label={__('Maturity')}
|
||||
value={this.state.meta_nsfw}
|
||||
name="nsfw"
|
||||
onChange={event => {
|
||||
|
@ -636,8 +609,8 @@ class PublishForm extends React.PureComponent {
|
|||
}}
|
||||
>
|
||||
{/* <option value=""></option> */}
|
||||
<option value="0">{__("All Ages")}</option>
|
||||
<option value="1">{__("Adults Only")}</option>
|
||||
<option value="0">{__('All Ages')}</option>
|
||||
<option value="1">{__('Adults Only')}</option>
|
||||
</FormRow>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -646,14 +619,12 @@ class PublishForm extends React.PureComponent {
|
|||
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h4>{__("Price")}</h4>
|
||||
<div className="card__subtitle">
|
||||
{__("How much does this content cost?")}
|
||||
</div>
|
||||
<h4>{__('Price')}</h4>
|
||||
<div className="card__subtitle">{__('How much does this content cost?')}</div>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<FormRow
|
||||
label={__("Free")}
|
||||
label={__('Free')}
|
||||
type="radio"
|
||||
name="isFree"
|
||||
onChange={() => this.handleFeePrefChange(false)}
|
||||
|
@ -662,27 +633,26 @@ class PublishForm extends React.PureComponent {
|
|||
<FormField
|
||||
type="radio"
|
||||
name="isFree"
|
||||
label={!this.state.isFee ? __("Choose price...") : __("Price ")}
|
||||
label={!this.state.isFee ? __('Choose price...') : __('Price ')}
|
||||
onChange={() => {
|
||||
this.handleFeePrefChange(true);
|
||||
}}
|
||||
checked={this.state.isFee}
|
||||
/>
|
||||
<span className={!this.state.isFee ? "hidden" : ""}>
|
||||
<span className={!this.state.isFee ? 'hidden' : ''}>
|
||||
<FormFieldPrice
|
||||
min="0"
|
||||
defaultValue={{
|
||||
amount: this._defaultPaidPrice,
|
||||
currency: "LBC",
|
||||
currency: 'LBC',
|
||||
}}
|
||||
onChange={val => this.handleFeeChange(val)}
|
||||
/>
|
||||
</span>
|
||||
{this.state.isFee &&
|
||||
this.state.feeCurrency.toUpperCase() != "LBC" ? (
|
||||
{this.state.isFee && this.state.feeCurrency.toUpperCase() != 'LBC' ? (
|
||||
<div className="form-field__helper">
|
||||
{__(
|
||||
"All content fees are charged in LBC. For non-LBC payment methods, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase."
|
||||
'All content fees are charged in LBC. For non-LBC payment methods, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase.'
|
||||
)}
|
||||
</div>
|
||||
) : null}
|
||||
|
@ -690,7 +660,7 @@ class PublishForm extends React.PureComponent {
|
|||
</section>
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h4>{__("License")}</h4>
|
||||
<h4>{__('License')}</h4>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<FormRow
|
||||
|
@ -703,61 +673,51 @@ class PublishForm extends React.PureComponent {
|
|||
this.handleLicenseTypeChange(event);
|
||||
}}
|
||||
>
|
||||
<option>{__("None")}</option>
|
||||
<option value="publicDomain">{__("Public Domain")}</option>
|
||||
<option>{__('None')}</option>
|
||||
<option value="publicDomain">{__('Public Domain')}</option>
|
||||
<option
|
||||
value="cc-by"
|
||||
data-url="https://creativecommons.org/licenses/by/4.0/legalcode"
|
||||
>
|
||||
{__("Creative Commons Attribution 4.0 International")}
|
||||
{__('Creative Commons Attribution 4.0 International')}
|
||||
</option>
|
||||
<option
|
||||
value="cc-by-sa"
|
||||
data-url="https://creativecommons.org/licenses/by-sa/4.0/legalcode"
|
||||
>
|
||||
{__(
|
||||
"Creative Commons Attribution-ShareAlike 4.0 International"
|
||||
)}
|
||||
{__('Creative Commons Attribution-ShareAlike 4.0 International')}
|
||||
</option>
|
||||
<option
|
||||
value="cc-by-nd"
|
||||
data-url="https://creativecommons.org/licenses/by-nd/4.0/legalcode"
|
||||
>
|
||||
{__(
|
||||
"Creative Commons Attribution-NoDerivatives 4.0 International"
|
||||
)}
|
||||
{__('Creative Commons Attribution-NoDerivatives 4.0 International')}
|
||||
</option>
|
||||
<option
|
||||
value="cc-by-nc"
|
||||
data-url="https://creativecommons.org/licenses/by-nc/4.0/legalcode"
|
||||
>
|
||||
{__(
|
||||
"Creative Commons Attribution-NonCommercial 4.0 International"
|
||||
)}
|
||||
{__('Creative Commons Attribution-NonCommercial 4.0 International')}
|
||||
</option>
|
||||
<option
|
||||
value="cc-by-nc-sa"
|
||||
data-url="https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode"
|
||||
>
|
||||
{__(
|
||||
"Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International"
|
||||
)}
|
||||
{__('Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International')}
|
||||
</option>
|
||||
<option
|
||||
value="cc-by-nc-nd"
|
||||
data-url="https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode"
|
||||
>
|
||||
{__(
|
||||
"Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International"
|
||||
)}
|
||||
{__('Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International')}
|
||||
</option>
|
||||
<option value="copyright">{__("Copyrighted...")}</option>
|
||||
<option value="other">{__("Other...")}</option>
|
||||
<option value="copyright">{__('Copyrighted...')}</option>
|
||||
<option value="other">{__('Other...')}</option>
|
||||
</FormRow>
|
||||
|
||||
{this.state.licenseType == "copyright" ? (
|
||||
{this.state.licenseType == 'copyright' ? (
|
||||
<FormRow
|
||||
label={__("Copyright notice")}
|
||||
label={__('Copyright notice')}
|
||||
type="text"
|
||||
name="copyright-notice"
|
||||
value={this.state.copyrightNotice}
|
||||
|
@ -767,9 +727,9 @@ class PublishForm extends React.PureComponent {
|
|||
/>
|
||||
) : null}
|
||||
|
||||
{this.state.licenseType == "other" ? (
|
||||
{this.state.licenseType == 'other' ? (
|
||||
<FormRow
|
||||
label={__("License description")}
|
||||
label={__('License description')}
|
||||
type="text"
|
||||
name="other-license-description"
|
||||
value={this.state.otherLicenseDescription}
|
||||
|
@ -779,9 +739,9 @@ class PublishForm extends React.PureComponent {
|
|||
/>
|
||||
) : null}
|
||||
|
||||
{this.state.licenseType == "other" ? (
|
||||
{this.state.licenseType == 'other' ? (
|
||||
<FormRow
|
||||
label={__("License URL")}
|
||||
label={__('License URL')}
|
||||
type="text"
|
||||
name="other-license-url"
|
||||
value={this.state.otherLicenseUrl}
|
||||
|
@ -801,23 +761,18 @@ class PublishForm extends React.PureComponent {
|
|||
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h4>{__("Content URL")}</h4>
|
||||
<h4>{__('Content URL')}</h4>
|
||||
<div className="card__subtitle">
|
||||
{__(
|
||||
"This is the exact address where people find your content (ex. lbry://myvideo)."
|
||||
)}{" "}
|
||||
<Link
|
||||
label={__("Learn more")}
|
||||
href="https://lbry.io/faq/naming"
|
||||
/>.
|
||||
'This is the exact address where people find your content (ex. lbry://myvideo).'
|
||||
)}{' '}
|
||||
<Link label={__('Learn more')} href="https://lbry.io/faq/naming" />.
|
||||
</div>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<FormRow
|
||||
prefix={`lbry://${
|
||||
this.state.channel === "anonymous"
|
||||
? ""
|
||||
: `${this.state.channel}/`
|
||||
this.state.channel === 'anonymous' ? '' : `${this.state.channel}/`
|
||||
}`}
|
||||
type="text"
|
||||
ref="name"
|
||||
|
@ -835,7 +790,7 @@ class PublishForm extends React.PureComponent {
|
|||
ref="bid"
|
||||
type="number"
|
||||
step="any"
|
||||
label={__("Deposit")}
|
||||
label={__('Deposit')}
|
||||
postfix="LBC"
|
||||
onChange={event => {
|
||||
this.handleBidChange(event);
|
||||
|
@ -847,23 +802,23 @@ class PublishForm extends React.PureComponent {
|
|||
/>
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
''
|
||||
)}
|
||||
</section>
|
||||
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h4>{__("Terms of Service")}</h4>
|
||||
<h4>{__('Terms of Service')}</h4>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
<FormRow
|
||||
ref="tosAgree"
|
||||
label={
|
||||
<span>
|
||||
{__("I agree to the")}{" "}
|
||||
{__('I agree to the')}{' '}
|
||||
<Link
|
||||
href="https://www.lbry.io/termsofservice"
|
||||
label={__("LBRY terms of service")}
|
||||
label={__('LBRY terms of service')}
|
||||
/>
|
||||
</span>
|
||||
}
|
||||
|
@ -878,36 +833,27 @@ class PublishForm extends React.PureComponent {
|
|||
|
||||
<div className="card-series-submit">
|
||||
<Submit
|
||||
label={
|
||||
!this.state.submitting ? __("Publish") : __("Publishing...")
|
||||
}
|
||||
label={!this.state.submitting ? __('Publish') : __('Publishing...')}
|
||||
disabled={
|
||||
this.props.balance <= 0 ||
|
||||
this.state.submitting ||
|
||||
(this.state.uri &&
|
||||
this.props.resolvingUris.indexOf(this.state.uri) !== -1) ||
|
||||
(this.claim() &&
|
||||
!this.topClaimIsMine() &&
|
||||
this.state.bid <= this.topClaimValue())
|
||||
(this.state.uri && this.props.resolvingUris.indexOf(this.state.uri) !== -1) ||
|
||||
(this.claim() && !this.topClaimIsMine() && this.state.bid <= this.topClaimValue())
|
||||
}
|
||||
/>
|
||||
<Link
|
||||
button="cancel"
|
||||
onClick={this.props.back}
|
||||
label={__("Cancel")}
|
||||
/>
|
||||
<Link button="cancel" onClick={this.props.back} label={__('Cancel')} />
|
||||
</div>
|
||||
</Form>
|
||||
|
||||
<Modal
|
||||
isOpen={this.state.modal == "publishStarted"}
|
||||
contentLabel={__("File published")}
|
||||
isOpen={this.state.modal == 'publishStarted'}
|
||||
contentLabel={__('File published')}
|
||||
onConfirmed={event => {
|
||||
this.handlePublishStartedConfirmed(event);
|
||||
}}
|
||||
>
|
||||
<p>
|
||||
{__("Your file has been published to LBRY at the address")}{" "}
|
||||
{__('Your file has been published to LBRY at the address')}{' '}
|
||||
<code>{this.state.uri}</code>!
|
||||
</p>
|
||||
<p>
|
||||
|
@ -917,15 +863,14 @@ class PublishForm extends React.PureComponent {
|
|||
</p>
|
||||
</Modal>
|
||||
<Modal
|
||||
isOpen={this.state.modal == "error"}
|
||||
contentLabel={__("Error publishing file")}
|
||||
isOpen={this.state.modal == 'error'}
|
||||
contentLabel={__('Error publishing file')}
|
||||
onConfirmed={event => {
|
||||
this.closeModal(event);
|
||||
}}
|
||||
>
|
||||
{__(
|
||||
"The following error occurred when attempting to publish your file"
|
||||
)}: {this.state.errorMessage}
|
||||
{__('The following error occurred when attempting to publish your file')}:{' '}
|
||||
{this.state.errorMessage}
|
||||
</Modal>
|
||||
</main>
|
||||
);
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
makeSelectClaimRewardError,
|
||||
makeSelectRewardByType,
|
||||
makeSelectIsRewardClaimPending,
|
||||
} from "redux/selectors/rewards";
|
||||
import { doNavigate } from "redux/actions/navigation";
|
||||
import {
|
||||
doClaimRewardType,
|
||||
doClaimRewardClearError,
|
||||
} from "redux/actions/rewards";
|
||||
import RewardLink from "./view";
|
||||
} from 'redux/selectors/rewards';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doClaimRewardType, doClaimRewardClearError } from 'redux/actions/rewards';
|
||||
import RewardLink from './view';
|
||||
|
||||
const makeSelect = () => {
|
||||
const selectIsPending = makeSelectIsRewardClaimPending();
|
||||
|
|
|
@ -1,33 +1,23 @@
|
|||
import React from "react";
|
||||
import Modal from "modal/modal";
|
||||
import Link from "component/link";
|
||||
import React from 'react';
|
||||
import Modal from 'modal/modal';
|
||||
import Link from 'component/link';
|
||||
|
||||
const RewardLink = props => {
|
||||
const {
|
||||
reward,
|
||||
button,
|
||||
claimReward,
|
||||
clearError,
|
||||
errorMessage,
|
||||
label,
|
||||
isPending,
|
||||
} = props;
|
||||
const { reward, button, claimReward, clearError, errorMessage, label, isPending } = props;
|
||||
|
||||
return (
|
||||
<div className="reward-link">
|
||||
<Link
|
||||
button={button}
|
||||
disabled={isPending}
|
||||
label={
|
||||
isPending ? __("Claiming...") : label ? label : __("Claim Reward")
|
||||
}
|
||||
label={isPending ? __('Claiming...') : label || __('Claim Reward')}
|
||||
onClick={() => {
|
||||
claimReward(reward);
|
||||
}}
|
||||
/>
|
||||
{errorMessage ? (
|
||||
<Modal
|
||||
isOpen={true}
|
||||
isOpen
|
||||
contentLabel="Reward Claim Error"
|
||||
className="error-modal"
|
||||
onConfirmed={() => {
|
||||
|
@ -37,7 +27,7 @@ const RewardLink = props => {
|
|||
{errorMessage}
|
||||
</Modal>
|
||||
) : (
|
||||
""
|
||||
''
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectClaimedRewards } from "redux/selectors/rewards";
|
||||
import RewardListClaimed from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectClaimedRewards } from 'redux/selectors/rewards';
|
||||
import RewardListClaimed from './view';
|
||||
|
||||
const select = state => ({
|
||||
rewards: selectClaimedRewards(state),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import LinkTransaction from "component/linkTransaction";
|
||||
import React from 'react';
|
||||
import LinkTransaction from 'component/linkTransaction';
|
||||
|
||||
const RewardListClaimed = props => {
|
||||
const { rewards } = props;
|
||||
|
@ -17,27 +17,23 @@ const RewardListClaimed = props => {
|
|||
<table className="table-standard table-stretch">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{__("Title")}</th>
|
||||
<th>{__("Amount")}</th>
|
||||
<th>{__("Transaction")}</th>
|
||||
<th>{__("Date")}</th>
|
||||
<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>
|
||||
);
|
||||
})}
|
||||
{rewards.map(reward => (
|
||||
<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>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectUnclaimedRewardValue } from "redux/selectors/rewards";
|
||||
import RewardSummary from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectUnclaimedRewardValue } from 'redux/selectors/rewards';
|
||||
import RewardSummary from './view';
|
||||
|
||||
const select = state => ({
|
||||
unclaimedRewardAmount: selectUnclaimedRewardValue(state),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
import React from "react";
|
||||
import Link from "component/link";
|
||||
import { CreditAmount } from "component/common";
|
||||
import React from 'react';
|
||||
import Link from 'component/link';
|
||||
import { CreditAmount } from 'component/common';
|
||||
|
||||
type Props = {
|
||||
unclaimedRewardAmount: number,
|
||||
|
@ -13,29 +13,20 @@ const RewardSummary = (props: Props) => {
|
|||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("Rewards")}</h3>
|
||||
<h3>{__('Rewards')}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
{unclaimedRewardAmount > 0 ? (
|
||||
<p>
|
||||
{__("You have")}{" "}
|
||||
<CreditAmount amount={unclaimedRewardAmount} precision={8} />{" "}
|
||||
{__("in unclaimed rewards")}.
|
||||
{__('You have')} <CreditAmount amount={unclaimedRewardAmount} precision={8} />{' '}
|
||||
{__('in unclaimed rewards')}.
|
||||
</p>
|
||||
) : (
|
||||
<p>
|
||||
{__(
|
||||
"There are no rewards available at this time, please check back later"
|
||||
)}.
|
||||
</p>
|
||||
<p>{__('There are no rewards available at this time, please check back later')}.</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="card__actions">
|
||||
<Link
|
||||
button="primary"
|
||||
navigate="/rewards"
|
||||
label={__("Claim Rewards")}
|
||||
/>
|
||||
<Link button="primary" navigate="/rewards" label={__('Claim Rewards')} />
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import RewardTile from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import RewardTile from './view';
|
||||
|
||||
export default connect(null, null)(RewardTile);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from "react";
|
||||
import { CreditAmount, Icon } from "component/common";
|
||||
import RewardLink from "component/rewardLink";
|
||||
import Link from "component/link";
|
||||
import rewards from "rewards";
|
||||
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;
|
||||
|
@ -19,12 +19,12 @@ const RewardTile = props => {
|
|||
<div className="card__content">{reward.reward_description}</div>
|
||||
<div className="card__actions ">
|
||||
{reward.reward_type == rewards.TYPE_REFERRAL && (
|
||||
<Link button="alt" navigate="/invite" label={__("Go To Invites")} />
|
||||
<Link button="alt" navigate="/invite" label={__('Go To Invites')} />
|
||||
)}
|
||||
{reward.reward_type !== rewards.TYPE_REFERRAL &&
|
||||
(claimed ? (
|
||||
<span>
|
||||
<Icon icon="icon-check" /> {__("Reward claimed.")}
|
||||
<Icon icon="icon-check" /> {__('Reward claimed.')}
|
||||
</span>
|
||||
) : (
|
||||
<RewardLink button="alt" reward_type={reward.reward_type} />
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import Router from "./view.jsx";
|
||||
import {
|
||||
selectCurrentPage,
|
||||
selectCurrentParams,
|
||||
} from "redux/selectors/navigation.js";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import Router from './view.jsx';
|
||||
import { selectCurrentPage, selectCurrentParams } from 'redux/selectors/navigation.js';
|
||||
|
||||
const select = state => ({
|
||||
params: selectCurrentParams(state),
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
import React from "react";
|
||||
import SettingsPage from "page/settings";
|
||||
import HelpPage from "page/help";
|
||||
import ReportPage from "page/report.js";
|
||||
import WalletPage from "page/wallet";
|
||||
import GetCreditsPage from "../../page/getCredits";
|
||||
import SendReceivePage from "page/sendCredits";
|
||||
import ShowPage from "page/show";
|
||||
import PublishPage from "page/publish";
|
||||
import DiscoverPage from "page/discover";
|
||||
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";
|
||||
import SubscriptionsPage from "page/subscriptions";
|
||||
import React from 'react';
|
||||
import SettingsPage from 'page/settings';
|
||||
import HelpPage from 'page/help';
|
||||
import ReportPage from 'page/report.js';
|
||||
import WalletPage from 'page/wallet';
|
||||
import GetCreditsPage from '../../page/getCredits';
|
||||
import SendReceivePage from 'page/sendCredits';
|
||||
import ShowPage from 'page/show';
|
||||
import PublishPage from 'page/publish';
|
||||
import DiscoverPage from 'page/discover';
|
||||
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';
|
||||
import SubscriptionsPage from 'page/subscriptions';
|
||||
|
||||
const route = (page, routesMap) => {
|
||||
const component = routesMap[page];
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { connect } from "react-redux";
|
||||
import { connect } from 'react-redux';
|
||||
import {
|
||||
createShapeShift,
|
||||
shapeShiftInit,
|
||||
getCoinStats,
|
||||
clearShapeShift,
|
||||
getActiveShift,
|
||||
} from "redux/actions/shape_shift";
|
||||
import { doShowSnackBar } from "redux/actions/app";
|
||||
import { selectReceiveAddress } from "redux/selectors/wallet";
|
||||
import { selectShapeShift } from "redux/selectors/shape_shift";
|
||||
import ShapeShift from "./view";
|
||||
} from 'redux/actions/shape_shift';
|
||||
import { doShowSnackBar } from 'redux/actions/app';
|
||||
import { selectReceiveAddress } from 'redux/selectors/wallet';
|
||||
import { selectShapeShift } from 'redux/selectors/shape_shift';
|
||||
import ShapeShift from './view';
|
||||
|
||||
const select = state => ({
|
||||
receiveAddress: selectReceiveAddress(state),
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
// @flow
|
||||
import * as React from "react";
|
||||
import QRCode from "qrcode.react";
|
||||
import * as statuses from "constants/shape_shift";
|
||||
import Address from "component/address";
|
||||
import Link from "component/link";
|
||||
import type { Dispatch } from "redux/actions/shape_shift";
|
||||
import ShiftMarketInfo from "./market_info";
|
||||
import * as React from 'react';
|
||||
import QRCode from 'qrcode.react';
|
||||
import * as statuses from 'constants/shape_shift';
|
||||
import Address from 'component/address';
|
||||
import Link from 'component/link';
|
||||
import type { Dispatch } from 'redux/actions/shape_shift';
|
||||
import ShiftMarketInfo from './market_info';
|
||||
|
||||
type Props = {
|
||||
shiftState: ?string,
|
||||
|
@ -78,10 +78,10 @@ class ActiveShapeShift extends React.PureComponent<Props> {
|
|||
{shiftState === statuses.NO_DEPOSITS && (
|
||||
<div>
|
||||
<p>
|
||||
Send up to{" "}
|
||||
Send up to{' '}
|
||||
<span className="credit-amount--bold">
|
||||
{originCoinDepositMax} {shiftCoinType}
|
||||
</span>{" "}
|
||||
</span>{' '}
|
||||
to the address below.
|
||||
</p>
|
||||
<ShiftMarketInfo
|
||||
|
@ -104,41 +104,32 @@ class ActiveShapeShift extends React.PureComponent<Props> {
|
|||
{shiftState === statuses.RECEIVED && (
|
||||
<div className="card__content--extra-vertical-space">
|
||||
<p>
|
||||
{__(
|
||||
"ShapeShift has received your payment! Sending the funds to your LBRY wallet."
|
||||
)}
|
||||
{__('ShapeShift has received your payment! Sending the funds to your LBRY wallet.')}
|
||||
</p>
|
||||
<span className="help">
|
||||
{__("This can take a while, especially with BTC.")}
|
||||
</span>
|
||||
<span className="help">{__('This can take a while, especially with BTC.')}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{shiftState === statuses.COMPLETE && (
|
||||
<div className="card__content--extra-vertical-space">
|
||||
<p>
|
||||
{__(
|
||||
"Transaction complete! You should see the new LBC in your wallet."
|
||||
)}
|
||||
</p>
|
||||
<p>{__('Transaction complete! You should see the new LBC in your wallet.')}</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="card__actions card__actions--only-vertical">
|
||||
<Link
|
||||
button={shiftState === statuses.COMPLETE ? "primary" : "alt"}
|
||||
button={shiftState === statuses.COMPLETE ? 'primary' : 'alt'}
|
||||
onClick={clearShapeShift}
|
||||
label={
|
||||
shiftState === statuses.COMPLETE ||
|
||||
shiftState === statuses.RECEIVED
|
||||
? __("Done")
|
||||
: __("Cancel")
|
||||
shiftState === statuses.COMPLETE || shiftState === statuses.RECEIVED
|
||||
? __('Done')
|
||||
: __('Cancel')
|
||||
}
|
||||
/>
|
||||
{shiftOrderId && (
|
||||
<span className="shapeshift__link">
|
||||
<Link
|
||||
button="text"
|
||||
label={__("View the status on Shapeshift.io")}
|
||||
label={__('View the status on Shapeshift.io')}
|
||||
href={`https://shapeshift.io/#/status/${shiftOrderId}`}
|
||||
/>
|
||||
</span>
|
||||
|
@ -147,8 +138,8 @@ class ActiveShapeShift extends React.PureComponent<Props> {
|
|||
shiftReturnAddress && (
|
||||
<div className="shapeshift__actions-help">
|
||||
<span className="help">
|
||||
If the transaction doesn't go through, ShapeShift will return
|
||||
your {shiftCoinType} back to {shiftReturnAddress}
|
||||
If the transaction doesn't go through, ShapeShift will return your {shiftCoinType}{' '}
|
||||
back to {shiftReturnAddress}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
import { getExampleAddress } from "util/shape_shift";
|
||||
import { Submit, FormRow } from "component/form";
|
||||
import type { ShapeShiftFormValues, Dispatch } from "redux/actions/shape_shift";
|
||||
import ShiftMarketInfo from "./market_info";
|
||||
import React from 'react';
|
||||
import Link from 'component/link';
|
||||
import { getExampleAddress } from 'util/shape_shift';
|
||||
import { Submit, FormRow } from 'component/form';
|
||||
import type { ShapeShiftFormValues, Dispatch } from 'redux/actions/shape_shift';
|
||||
import ShiftMarketInfo from './market_info';
|
||||
|
||||
type ShapeShiftFormErrors = {
|
||||
returnAddress?: string,
|
||||
|
@ -50,7 +50,7 @@ export default (props: Props) => {
|
|||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="form-field">
|
||||
<span>{__("Exchange")} </span>
|
||||
<span>{__('Exchange')} </span>
|
||||
<select
|
||||
className="form-field__input form-field__input-select"
|
||||
name="originCoin"
|
||||
|
@ -65,7 +65,7 @@ export default (props: Props) => {
|
|||
</option>
|
||||
))}
|
||||
</select>
|
||||
<span> {__("for LBC")}</span>
|
||||
<span> {__('for LBC')}</span>
|
||||
<div className="shapeshift__tx-info">
|
||||
{!updating &&
|
||||
originCoinDepositMax && (
|
||||
|
@ -84,7 +84,7 @@ export default (props: Props) => {
|
|||
type="text"
|
||||
name="returnAddress"
|
||||
placeholder={getExampleAddress(originCoin)}
|
||||
label={__("Return address")}
|
||||
label={__('Return address')}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
value={values.returnAddress}
|
||||
|
@ -93,14 +93,13 @@ export default (props: Props) => {
|
|||
/>
|
||||
<span className="help">
|
||||
<span>
|
||||
({__("optional but recommended")}) {__("We will return your")}{" "}
|
||||
{originCoin}{" "}
|
||||
({__('optional but recommended')}) {__('We will return your')} {originCoin}{' '}
|
||||
{__("to this address if the transaction doesn't go through.")}
|
||||
</span>
|
||||
</span>
|
||||
<div className="card__actions card__actions--only-vertical">
|
||||
<Submit
|
||||
label={__("Begin Conversion")}
|
||||
label={__('Begin Conversion')}
|
||||
disabled={isSubmitting || !!Object.keys(errors).length}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// @flow
|
||||
import React from "react";
|
||||
import React from 'react';
|
||||
|
||||
type Props = {
|
||||
shapeShiftRate: ?number,
|
||||
|
@ -21,13 +21,13 @@ export default (props: Props) => {
|
|||
return (
|
||||
<div>
|
||||
<span className="help">
|
||||
{__("Receive")} {shapeShiftRate} LBC
|
||||
{" / "}
|
||||
{"1"} {originCoin} {__("less")} {originCoinDepositFee} LBC {__("fee")}.
|
||||
{__('Receive')} {shapeShiftRate} LBC
|
||||
{' / '}
|
||||
{'1'} {originCoin} {__('less')} {originCoinDepositFee} LBC {__('fee')}.
|
||||
<br />
|
||||
{__("Exchange max")}: {originCoinDepositMax} {originCoin}
|
||||
{__('Exchange max')}: {originCoinDepositMax} {originCoin}
|
||||
<br />
|
||||
{__("Exchange min")}: {originCoinDepositMin} {originCoin}
|
||||
{__('Exchange min')}: {originCoinDepositMin} {originCoin}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
// @flow
|
||||
import * as React from "react";
|
||||
import { shell } from "electron";
|
||||
import { Formik } from "formik";
|
||||
import classnames from "classnames";
|
||||
import * as statuses from "constants/shape_shift";
|
||||
import { validateShapeShiftForm } from "util/shape_shift";
|
||||
import Link from "component/link";
|
||||
import Spinner from "component/common/spinner";
|
||||
import { BusyMessage } from "component/common";
|
||||
import ShapeShiftForm from "./internal/form";
|
||||
import ActiveShapeShift from "./internal/active-shift";
|
||||
import * as React from 'react';
|
||||
import { shell } from 'electron';
|
||||
import { Formik } from 'formik';
|
||||
import classnames from 'classnames';
|
||||
import * as statuses from 'constants/shape_shift';
|
||||
import { validateShapeShiftForm } from 'util/shape_shift';
|
||||
import Link from 'component/link';
|
||||
import Spinner from 'component/common/spinner';
|
||||
import { BusyMessage } from 'component/common';
|
||||
import ShapeShiftForm from './internal/form';
|
||||
import ActiveShapeShift from './internal/active-shift';
|
||||
|
||||
import type { ShapeShiftState } from "redux/reducers/shape_shift";
|
||||
import type { Dispatch, ShapeShiftFormValues } from "redux/actions/shape_shift";
|
||||
import type { ShapeShiftState } from 'redux/reducers/shape_shift';
|
||||
import type { Dispatch, ShapeShiftFormValues } from 'redux/actions/shape_shift';
|
||||
|
||||
type Props = {
|
||||
shapeShift: ShapeShiftState,
|
||||
|
@ -27,10 +27,7 @@ type Props = {
|
|||
|
||||
class ShapeShift extends React.PureComponent<Props> {
|
||||
componentDidMount() {
|
||||
const {
|
||||
shapeShiftInit,
|
||||
shapeShift: { hasActiveShift, shiftSupportedCoins },
|
||||
} = this.props;
|
||||
const { shapeShiftInit, shapeShift: { hasActiveShift, shiftSupportedCoins } } = this.props;
|
||||
|
||||
if (!hasActiveShift && !shiftSupportedCoins.length) {
|
||||
// calls shapeshift to see list of supported coins for shifting
|
||||
|
@ -70,8 +67,8 @@ class ShapeShift extends React.PureComponent<Props> {
|
|||
|
||||
const initialFormValues: ShapeShiftFormValues = {
|
||||
receiveAddress,
|
||||
originCoin: "BTC",
|
||||
returnAddress: "",
|
||||
originCoin: 'BTC',
|
||||
returnAddress: '',
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -80,19 +77,17 @@ class ShapeShift extends React.PureComponent<Props> {
|
|||
// if the markup below changes for the initial render (form.jsx) there will be content jumping
|
||||
// the styling in shapeshift.scss will need to be updated to the correct min-height
|
||||
<section
|
||||
className={classnames("card shapeshift__wrapper", {
|
||||
"shapeshift__initial-wrapper": loading,
|
||||
className={classnames('card shapeshift__wrapper', {
|
||||
'shapeshift__initial-wrapper': loading,
|
||||
})}
|
||||
>
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("Convert Crypto to LBC")}</h3>
|
||||
<h3>{__('Convert Crypto to LBC')}</h3>
|
||||
<p className="help">
|
||||
{__("Powered by ShapeShift. Read our FAQ")}{" "}
|
||||
<Link href="https://lbry.io/faq/shapeshift">{__("here")}</Link>.
|
||||
{__('Powered by ShapeShift. Read our FAQ')}{' '}
|
||||
<Link href="https://lbry.io/faq/shapeshift">{__('here')}</Link>.
|
||||
{hasActiveShift &&
|
||||
shiftState !== "complete" && (
|
||||
<span>{__("This will update automatically.")}</span>
|
||||
)}
|
||||
shiftState !== 'complete' && <span>{__('This will update automatically.')}</span>}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doRemoveSnackBarSnack } from "redux/actions/app";
|
||||
import { selectSnackBarSnacks } from "redux/selectors/app";
|
||||
import SnackBar from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { doRemoveSnackBarSnack } from 'redux/actions/app';
|
||||
import { selectSnackBarSnacks } from 'redux/selectors/app';
|
||||
import SnackBar from './view';
|
||||
|
||||
const perform = dispatch => ({
|
||||
removeSnack: () => dispatch(doRemoveSnackBarSnack()),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
import React from 'react';
|
||||
import Link from 'component/link';
|
||||
|
||||
class SnackBar extends React.PureComponent {
|
||||
constructor(props) {
|
||||
|
@ -13,7 +13,7 @@ class SnackBar extends React.PureComponent {
|
|||
const { snacks, removeSnack } = this.props;
|
||||
|
||||
if (!snacks.length) {
|
||||
this._hideTimeout = null; //should be unmounting anyway, but be safe?
|
||||
this._hideTimeout = null; // should be unmounting anyway, but be safe?
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -32,11 +32,7 @@ class SnackBar extends React.PureComponent {
|
|||
{message}
|
||||
{linkText &&
|
||||
linkTarget && (
|
||||
<Link
|
||||
navigate={linkTarget}
|
||||
className="snack-bar__action"
|
||||
label={linkText}
|
||||
/>
|
||||
<Link navigate={linkTarget} className="snack-bar__action" label={linkText} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import {
|
||||
selectCurrentModal,
|
||||
selectDaemonVersionMatched,
|
||||
} from "redux/selectors/app";
|
||||
import { doCheckDaemonVersion } from "redux/actions/app";
|
||||
import SplashScreen from "./view";
|
||||
import { selectCurrentModal, selectDaemonVersionMatched } from 'redux/selectors/app';
|
||||
import { doCheckDaemonVersion } from 'redux/actions/app';
|
||||
import SplashScreen from './view';
|
||||
|
||||
const select = state => {
|
||||
return {
|
||||
modal: selectCurrentModal(state),
|
||||
daemonVersionMatched: selectDaemonVersionMatched(state),
|
||||
};
|
||||
};
|
||||
const select = state => ({
|
||||
modal: selectCurrentModal(state),
|
||||
daemonVersionMatched: selectDaemonVersionMatched(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
checkDaemonVersion: () => dispatch(doCheckDaemonVersion()),
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import lbry from "lbry.js";
|
||||
import LoadScreen from "../load_screen.js";
|
||||
import ModalIncompatibleDaemon from "modal/modalIncompatibleDaemon";
|
||||
import ModalUpgrade from "modal/modalUpgrade";
|
||||
import ModalDownloading from "modal/modalDownloading";
|
||||
import * as modals from "constants/modal_types";
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import lbry from 'lbry.js';
|
||||
import LoadScreen from '../load_screen.js';
|
||||
import ModalIncompatibleDaemon from 'modal/modalIncompatibleDaemon';
|
||||
import ModalUpgrade from 'modal/modalUpgrade';
|
||||
import ModalDownloading from 'modal/modalDownloading';
|
||||
import * as modals from 'constants/modal_types';
|
||||
|
||||
export class SplashScreen extends React.PureComponent {
|
||||
static propTypes = {
|
||||
|
@ -17,8 +17,8 @@ export class SplashScreen extends React.PureComponent {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
details: __("Starting daemon"),
|
||||
message: __("Connecting"),
|
||||
details: __('Starting daemon'),
|
||||
message: __('Connecting'),
|
||||
isRunning: false,
|
||||
isLagging: false,
|
||||
};
|
||||
|
@ -32,19 +32,19 @@ export class SplashScreen extends React.PureComponent {
|
|||
|
||||
_updateStatusCallback(status) {
|
||||
const startupStatus = status.startup_status;
|
||||
if (startupStatus.code == "started") {
|
||||
if (startupStatus.code == 'started') {
|
||||
// Wait until we are able to resolve a name before declaring
|
||||
// that we are done.
|
||||
// TODO: This is a hack, and the logic should live in the daemon
|
||||
// to give us a better sense of when we are actually started
|
||||
this.setState({
|
||||
message: __("Testing Network"),
|
||||
details: __("Waiting for name resolution"),
|
||||
message: __('Testing Network'),
|
||||
details: __('Waiting for name resolution'),
|
||||
isLagging: false,
|
||||
isRunning: true,
|
||||
});
|
||||
|
||||
lbry.resolve({ uri: "lbry://one" }).then(() => {
|
||||
lbry.resolve({ uri: 'lbry://one' }).then(() => {
|
||||
// Only leave the load screen if the daemon version matched;
|
||||
// otherwise we'll notify the user at the end of the load screen.
|
||||
|
||||
|
@ -54,24 +54,18 @@ export class SplashScreen extends React.PureComponent {
|
|||
});
|
||||
return;
|
||||
}
|
||||
if (
|
||||
status.blockchain_status &&
|
||||
status.blockchain_status.blocks_behind > 0
|
||||
) {
|
||||
if (status.blockchain_status && status.blockchain_status.blocks_behind > 0) {
|
||||
const format =
|
||||
status.blockchain_status.blocks_behind == 1
|
||||
? "%s block behind"
|
||||
: "%s blocks behind";
|
||||
status.blockchain_status.blocks_behind == 1 ? '%s block behind' : '%s blocks behind';
|
||||
this.setState({
|
||||
message: __("Blockchain Sync"),
|
||||
message: __('Blockchain Sync'),
|
||||
details: __(format, status.blockchain_status.blocks_behind),
|
||||
isLagging: startupStatus.is_lagging,
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
message: __("Network Loading"),
|
||||
details:
|
||||
startupStatus.message + (startupStatus.is_lagging ? "" : "..."),
|
||||
message: __('Network Loading'),
|
||||
details: startupStatus.message + (startupStatus.is_lagging ? '' : '...'),
|
||||
isLagging: startupStatus.is_lagging,
|
||||
});
|
||||
}
|
||||
|
@ -90,9 +84,9 @@ export class SplashScreen extends React.PureComponent {
|
|||
.catch(() => {
|
||||
this.setState({
|
||||
isLagging: true,
|
||||
message: __("Connection Failure"),
|
||||
message: __('Connection Failure'),
|
||||
details: __(
|
||||
"Try closing all LBRY processes and starting again. If this still happens, your anti-virus software or firewall may be preventing LBRY from connecting. Contact hello@lbry.io if you think this is a software bug."
|
||||
'Try closing all LBRY processes and starting again. If this still happens, your anti-virus software or firewall may be preventing LBRY from connecting. Contact hello@lbry.io if you think this is a software bug.'
|
||||
),
|
||||
});
|
||||
});
|
||||
|
@ -104,19 +98,13 @@ export class SplashScreen extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<LoadScreen
|
||||
message={message}
|
||||
details={details}
|
||||
isWarning={isLagging}
|
||||
/>
|
||||
<LoadScreen message={message} details={details} isWarning={isLagging} />
|
||||
{/* Temp hack: don't show any modals on splash screen daemon is running;
|
||||
daemon doesn't let you quit during startup, so the "Quit" buttons
|
||||
in the modals won't work. */}
|
||||
{modal == "incompatibleDaemon" &&
|
||||
isRunning && <ModalIncompatibleDaemon />}
|
||||
{modal == 'incompatibleDaemon' && isRunning && <ModalIncompatibleDaemon />}
|
||||
{modal == modals.UPGRADE && isRunning && <ModalUpgrade />}
|
||||
{modal == modals.DOWNLOADING &&
|
||||
isRunning && <ModalDownloading />}
|
||||
{modal == modals.DOWNLOADING && isRunning && <ModalDownloading />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
selectCurrentPage,
|
||||
selectHeaderLinks,
|
||||
} from "redux/selectors/navigation";
|
||||
import { doNavigate } from "redux/actions/navigation";
|
||||
import SubHeader from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectCurrentPage, selectHeaderLinks } from 'redux/selectors/navigation';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import SubHeader from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
currentPage: selectCurrentPage(state),
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
import classnames from "classnames";
|
||||
import React from 'react';
|
||||
import Link from 'component/link';
|
||||
import classnames from 'classnames';
|
||||
|
||||
const SubHeader = props => {
|
||||
const { subLinks, currentPage, navigate, fullWidth, smallMargin } = props;
|
||||
|
||||
const links = [];
|
||||
|
||||
for (let link of Object.keys(subLinks)) {
|
||||
for (const link of Object.keys(subLinks)) {
|
||||
links.push(
|
||||
<Link
|
||||
onClick={event => navigate(`/${link}`, event)}
|
||||
key={link}
|
||||
className={
|
||||
link == currentPage ? "sub-header-selected" : "sub-header-unselected"
|
||||
}
|
||||
className={link == currentPage ? 'sub-header-selected' : 'sub-header-unselected'}
|
||||
>
|
||||
{subLinks[link]}
|
||||
</Link>
|
||||
|
@ -23,9 +21,9 @@ const SubHeader = props => {
|
|||
|
||||
return (
|
||||
<nav
|
||||
className={classnames("sub-header", {
|
||||
"sub-header--full-width": fullWidth,
|
||||
"sub-header--small-margin": smallMargin,
|
||||
className={classnames('sub-header', {
|
||||
'sub-header--full-width': fullWidth,
|
||||
'sub-header--small-margin': smallMargin,
|
||||
})}
|
||||
>
|
||||
{links}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import { connect } from "react-redux";
|
||||
import {
|
||||
doChannelSubscribe,
|
||||
doChannelUnsubscribe,
|
||||
} from "redux/actions/subscriptions";
|
||||
import { selectSubscriptions } from "redux/selectors/subscriptions";;
|
||||
import SubscribeButton from "./view";
|
||||
import { connect } from 'react-redux';
|
||||
import { doChannelSubscribe, doChannelUnsubscribe } from 'redux/actions/subscriptions';
|
||||
import { selectSubscriptions } from 'redux/selectors/subscriptions';
|
||||
|
||||
import SubscribeButton from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
subscriptions: selectSubscriptions(state),
|
||||
|
@ -12,5 +10,5 @@ const select = (state, props) => ({
|
|||
|
||||
export default connect(select, {
|
||||
doChannelSubscribe,
|
||||
doChannelUnsubscribe
|
||||
doChannelUnsubscribe,
|
||||
})(SubscribeButton);
|
||||
|
|
|
@ -1,36 +1,27 @@
|
|||
import React from "react";
|
||||
import Link from "component/link";
|
||||
|
||||
export default ({
|
||||
channelName,
|
||||
uri,
|
||||
subscriptions,
|
||||
doChannelSubscribe,
|
||||
doChannelUnsubscribe
|
||||
}) => {
|
||||
import React from 'react';
|
||||
import Link from 'component/link';
|
||||
|
||||
export default ({ channelName, uri, subscriptions, doChannelSubscribe, doChannelUnsubscribe }) => {
|
||||
const isSubscribed =
|
||||
subscriptions
|
||||
.map(subscription => subscription.channelName)
|
||||
.indexOf(channelName) !== -1;
|
||||
subscriptions.map(subscription => subscription.channelName).indexOf(channelName) !== -1;
|
||||
|
||||
const subscriptionHandler = isSubscribed
|
||||
? doChannelUnsubscribe
|
||||
: doChannelSubscribe;
|
||||
const subscriptionHandler = isSubscribed ? doChannelUnsubscribe : doChannelSubscribe;
|
||||
|
||||
const subscriptionLabel = isSubscribed ? __("Unsubscribe") : __("Subscribe");
|
||||
const subscriptionLabel = isSubscribed ? __('Unsubscribe') : __('Subscribe');
|
||||
|
||||
return channelName && uri ? (
|
||||
<div className="card__actions">
|
||||
<Link
|
||||
iconRight={isSubscribed ? "" : "at"}
|
||||
button={isSubscribed ? "alt" : "primary"}
|
||||
iconRight={isSubscribed ? '' : 'at'}
|
||||
button={isSubscribed ? 'alt' : 'primary'}
|
||||
label={subscriptionLabel}
|
||||
onClick={() => subscriptionHandler({
|
||||
channelName,
|
||||
uri,
|
||||
})}
|
||||
onClick={() =>
|
||||
subscriptionHandler({
|
||||
channelName,
|
||||
uri,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : null;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { selectThemePath } from "redux/selectors/settings.js";
|
||||
import Theme from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { selectThemePath } from 'redux/selectors/settings.js';
|
||||
import Theme from './view';
|
||||
|
||||
const select = state => ({
|
||||
themePath: selectThemePath(state),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import React from 'react';
|
||||
|
||||
const Theme = props => {
|
||||
const { themePath } = props;
|
||||
|
@ -7,14 +7,7 @@ const Theme = props => {
|
|||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<link
|
||||
href={themePath}
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
media="screen,print"
|
||||
/>
|
||||
);
|
||||
return <link href={themePath} rel="stylesheet" type="text/css" media="screen,print" />;
|
||||
};
|
||||
|
||||
export default Theme;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export class ToolTip extends React.PureComponent {
|
||||
static propTypes = {
|
||||
|
@ -29,7 +29,7 @@ export class ToolTip extends React.PureComponent {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<span className={"tooltip " + (this.props.className || "")}>
|
||||
<span className={`tooltip ${this.props.className || ''}`}>
|
||||
<a
|
||||
className="tooltip__link"
|
||||
onClick={() => {
|
||||
|
@ -39,9 +39,7 @@ export class ToolTip extends React.PureComponent {
|
|||
{this.props.label}
|
||||
</a>
|
||||
<div
|
||||
className={
|
||||
"tooltip__body " + (this.state.showTooltip ? "" : " hidden")
|
||||
}
|
||||
className={`tooltip__body ${this.state.showTooltip ? '' : ' hidden'}`}
|
||||
onMouseOut={() => {
|
||||
this.handleTooltipMouseOut();
|
||||
}}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doNavigate } from "redux/actions/navigation";
|
||||
import { doOpenModal } from "redux/actions/app";
|
||||
import { selectClaimedRewardsByTransactionId } from "redux/selectors/rewards";
|
||||
import { selectAllMyClaimsByOutpoint } from "redux/selectors/claims";
|
||||
import TransactionList from "./view";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { doNavigate } from 'redux/actions/navigation';
|
||||
import { doOpenModal } from 'redux/actions/app';
|
||||
import { selectClaimedRewardsByTransactionId } from 'redux/selectors/rewards';
|
||||
import { selectAllMyClaimsByOutpoint } from 'redux/selectors/claims';
|
||||
import TransactionList from './view';
|
||||
|
||||
const select = state => ({
|
||||
rewards: selectClaimedRewardsByTransactionId(state),
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import React from "react";
|
||||
import LinkTransaction from "component/linkTransaction";
|
||||
import { CreditAmount } from "component/common";
|
||||
import DateTime from "component/dateTime";
|
||||
import Link from "component/link";
|
||||
import lbryuri from "lbryuri";
|
||||
import * as txnTypes from "constants/transaction_types";
|
||||
import React from 'react';
|
||||
import LinkTransaction from 'component/linkTransaction';
|
||||
import { CreditAmount } from 'component/common';
|
||||
import DateTime from 'component/dateTime';
|
||||
import Link from 'component/link';
|
||||
import lbryuri from 'lbryuri';
|
||||
import * as txnTypes from 'constants/transaction_types';
|
||||
|
||||
class TransactionListItem extends React.PureComponent {
|
||||
abandonClaim() {
|
||||
|
@ -16,21 +16,10 @@ class TransactionListItem extends React.PureComponent {
|
|||
getLink(type) {
|
||||
if (type == txnTypes.TIP) {
|
||||
return (
|
||||
<Link
|
||||
onClick={this.abandonClaim.bind(this)}
|
||||
icon="icon-unlock-alt"
|
||||
title={__("Unlock")}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Link
|
||||
onClick={this.abandonClaim.bind(this)}
|
||||
icon="icon-trash"
|
||||
title={__("Revoke")}
|
||||
/>
|
||||
<Link onClick={this.abandonClaim.bind(this)} icon="icon-unlock-alt" title={__('Unlock')} />
|
||||
);
|
||||
}
|
||||
return <Link onClick={this.abandonClaim.bind(this)} icon="icon-trash" title={__('Revoke')} />;
|
||||
}
|
||||
|
||||
capitalize(string) {
|
||||
|
@ -51,9 +40,9 @@ class TransactionListItem extends React.PureComponent {
|
|||
} = transaction;
|
||||
|
||||
const dateFormat = {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -61,41 +50,25 @@ class TransactionListItem extends React.PureComponent {
|
|||
<td>
|
||||
{date ? (
|
||||
<div>
|
||||
<DateTime
|
||||
date={date}
|
||||
show={DateTime.SHOW_DATE}
|
||||
formatOptions={dateFormat}
|
||||
/>
|
||||
<DateTime date={date} show={DateTime.SHOW_DATE} formatOptions={dateFormat} />
|
||||
<div className="meta">
|
||||
<DateTime date={date} show={DateTime.SHOW_TIME} />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<span className="empty">{__("Pending")}</span>
|
||||
<span className="empty">{__('Pending')}</span>
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
<CreditAmount
|
||||
amount={amount}
|
||||
look="plain"
|
||||
label={false}
|
||||
showPlus={true}
|
||||
precision={8}
|
||||
/>
|
||||
<CreditAmount amount={amount} look="plain" label={false} showPlus precision={8} />
|
||||
<br />
|
||||
{fee != 0 && (
|
||||
<CreditAmount amount={fee} look="fee" label={false} precision={8} />
|
||||
)}
|
||||
{fee != 0 && <CreditAmount amount={fee} look="fee" label={false} precision={8} />}
|
||||
</td>
|
||||
<td>
|
||||
{this.capitalize(type)} {isRevokeable && this.getLink(type)}
|
||||
</td>
|
||||
<td>
|
||||
{reward && (
|
||||
<Link navigate="/rewards">
|
||||
{__("Reward: %s", reward.reward_title)}
|
||||
</Link>
|
||||
)}
|
||||
{reward && <Link navigate="/rewards">{__('Reward: %s', reward.reward_title)}</Link>}
|
||||
{name &&
|
||||
claimId && (
|
||||
<Link
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from "react";
|
||||
import TransactionListItem from "./internal/TransactionListItem";
|
||||
import FormField from "component/formField";
|
||||
import Link from "component/link";
|
||||
import * as icons from "constants/icons";
|
||||
import * as modals from "constants/modal_types";
|
||||
import React from 'react';
|
||||
import TransactionListItem from './internal/TransactionListItem';
|
||||
import FormField from 'component/formField';
|
||||
import Link from 'component/link';
|
||||
import * as icons from 'constants/icons';
|
||||
import * as modals from 'constants/modal_types';
|
||||
|
||||
class TransactionList extends React.PureComponent {
|
||||
constructor(props) {
|
||||
|
@ -39,48 +39,38 @@ class TransactionList extends React.PureComponent {
|
|||
render() {
|
||||
const { emptyMessage, rewards, transactions } = this.props;
|
||||
|
||||
let transactionList = transactions.filter(
|
||||
this.filterTransaction.bind(this)
|
||||
);
|
||||
const transactionList = transactions.filter(this.filterTransaction.bind(this));
|
||||
|
||||
return (
|
||||
<div>
|
||||
{(transactionList.length || this.state.filter) && (
|
||||
<span className="sort-section">
|
||||
{__("Filter")}{" "}
|
||||
<FormField
|
||||
type="select"
|
||||
onChange={this.handleFilterChanged.bind(this)}
|
||||
>
|
||||
<option value="">{__("All")}</option>
|
||||
<option value="spend">{__("Spends")}</option>
|
||||
<option value="receive">{__("Receives")}</option>
|
||||
<option value="publish">{__("Publishes")}</option>
|
||||
<option value="channel">{__("Channels")}</option>
|
||||
<option value="tip">{__("Tips")}</option>
|
||||
<option value="support">{__("Supports")}</option>
|
||||
<option value="update">{__("Updates")}</option>
|
||||
</FormField>{" "}
|
||||
<Link
|
||||
href="https://lbry.io/faq/transaction-types"
|
||||
icon={icons.HELP_CIRCLE}
|
||||
/>
|
||||
{__('Filter')}{' '}
|
||||
<FormField type="select" onChange={this.handleFilterChanged.bind(this)}>
|
||||
<option value="">{__('All')}</option>
|
||||
<option value="spend">{__('Spends')}</option>
|
||||
<option value="receive">{__('Receives')}</option>
|
||||
<option value="publish">{__('Publishes')}</option>
|
||||
<option value="channel">{__('Channels')}</option>
|
||||
<option value="tip">{__('Tips')}</option>
|
||||
<option value="support">{__('Supports')}</option>
|
||||
<option value="update">{__('Updates')}</option>
|
||||
</FormField>{' '}
|
||||
<Link href="https://lbry.io/faq/transaction-types" icon={icons.HELP_CIRCLE} />
|
||||
</span>
|
||||
)}
|
||||
{!transactionList.length && (
|
||||
<div className="empty">
|
||||
{emptyMessage || __("No transactions to list.")}
|
||||
</div>
|
||||
<div className="empty">{emptyMessage || __('No transactions to list.')}</div>
|
||||
)}
|
||||
{Boolean(transactionList.length) && (
|
||||
<table className="table-standard table-transactions table-stretch">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{__("Date")}</th>
|
||||
<th>{__("Amount (Fee)")}</th>
|
||||
<th>{__("Type")} </th>
|
||||
<th>{__("Details")} </th>
|
||||
<th>{__("Transaction")}</th>
|
||||
<th>{__('Date')}</th>
|
||||
<th>{__('Amount (Fee)')}</th>
|
||||
<th>{__('Type')} </th>
|
||||
<th>{__('Details')} </th>
|
||||
<th>{__('Transaction')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { doFetchTransactions } from "redux/actions/wallet";
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { doFetchTransactions } from 'redux/actions/wallet';
|
||||
import {
|
||||
selectBalance,
|
||||
selectRecentTransactions,
|
||||
selectHasTransactions,
|
||||
selectIsFetchingTransactions,
|
||||
} from "redux/selectors/wallet";
|
||||
} from 'redux/selectors/wallet';
|
||||
|
||||
import TransactionListRecent from "./view";
|
||||
import TransactionListRecent from './view';
|
||||
|
||||
const select = state => ({
|
||||
fetchingTransactions: selectIsFetchingTransactions(state),
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from "react";
|
||||
import { BusyMessage } from "component/common";
|
||||
import Link from "component/link";
|
||||
import TransactionList from "component/transactionList";
|
||||
import * as icons from "constants/icons";
|
||||
import React from 'react';
|
||||
import { BusyMessage } from 'component/common';
|
||||
import Link from 'component/link';
|
||||
import TransactionList from 'component/transactionList';
|
||||
import * as icons from 'constants/icons';
|
||||
|
||||
class TransactionListRecent extends React.PureComponent {
|
||||
componentWillMount() {
|
||||
|
@ -15,16 +15,14 @@ class TransactionListRecent extends React.PureComponent {
|
|||
return (
|
||||
<section className="card">
|
||||
<div className="card__title-primary">
|
||||
<h3>{__("Recent Transactions")}</h3>
|
||||
<h3>{__('Recent Transactions')}</h3>
|
||||
</div>
|
||||
<div className="card__content">
|
||||
{fetchingTransactions && (
|
||||
<BusyMessage message={__("Loading transactions")} />
|
||||
)}
|
||||
{fetchingTransactions && <BusyMessage message={__('Loading transactions')} />}
|
||||
{!fetchingTransactions && (
|
||||
<TransactionList
|
||||
transactions={transactions}
|
||||
emptyMessage={__("You have no recent transactions.")}
|
||||
emptyMessage={__('You have no recent transactions.')}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
@ -32,7 +30,7 @@ class TransactionListRecent extends React.PureComponent {
|
|||
<div className="card__actions card__actions--bottom">
|
||||
<Link
|
||||
navigate="/history"
|
||||
label={__("Full History")}
|
||||
label={__('Full History')}
|
||||
icon={icons.HISTORY}
|
||||
className="no-underline"
|
||||
button="text"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue