Setup ESLint and Prettier and apply changes to sources #891

Merged
IGassmann merged 22 commits from issue/763 into master 2017-12-27 21:22:51 +01:00
298 changed files with 6769 additions and 7403 deletions

34
.eslintrc.json Normal file
View 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
View file

@ -12,6 +12,7 @@
/lbry-app
/lbry-venv
/static/daemon/lbrynet*
/static/locales
/daemon/build
/daemon/venv
/daemon/requirements.txt

12
.lintstagedrc Normal file
View 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
View file

@ -0,0 +1,5 @@
{
"trailingComma": "es5",
"printWidth": 100,
"singleQuote": true
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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"

View file

@ -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);
}
return cb(new Error('debian package not installed'));
});
}
}
}
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);
});
} 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,80 +375,131 @@ 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 => {
const req = Https.get(Object.assign(opts, Url.parse(LATEST_RELEASE_API_URL)), res => {
res.on('data', data => {
result += data;
});
res.on("end", () => {
res.on('end', () => {
const tagName = JSON.parse(result).tag_name;
const [_, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
const [, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
if (!remoteVersion) {
if (win) {
win.webContents.send("version-info-received", null);
if (rendererWindow) {
rendererWindow.webContents.send('version-info-received', null);
}
} else {
const upgradeAvailable = semver.gt(
formatRc(remoteVersion),
formatRc(localVersion)
);
if (win) {
win.webContents.send("version-info-received", {
const upgradeAvailable = Semver.gt(formatRc(remoteVersion), formatRc(localVersion));
if (rendererWindow) {
rendererWindow.webContents.send('version-info-received', {
remoteVersion,
localVersion,
upgradeAvailable,
@ -587,30 +507,22 @@ ipcMain.on("version-info-requested", () => {
}
}
});
}
);
});
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);
});

View file

@ -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);
},
};

View 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);
}

View file

@ -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);
export default () => {
const template = baseTemplate.slice();
if (process.platform === 'darwin') {
template.unshift(macOSAppMenuTemplate);
}
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
};

View file

@ -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;

View file

@ -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,

View file

@ -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>

View file

@ -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),

View file

@ -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() {

View file

@ -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 => ({});

View file

@ -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>

View file

@ -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),

View file

@ -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)}
/>
);

View file

@ -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),

View file

@ -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>

View file

@ -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 (

View file

@ -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 (
export default ({ dark, className }) => (
<div
className={classnames(
"spinner",
'spinner',
{
"spinner--dark": dark,
'spinner--dark': dark,
},
className
)}
/>
);
};
);

View file

@ -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 => ({

View file

@ -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>
);
}

View file

@ -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>

View file

@ -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),
});

View file

@ -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 }}

View file

@ -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),

View file

@ -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>

View file

@ -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),

View file

@ -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>
)}

View file

@ -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),

View file

@ -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,12 +76,12 @@ class FileDownloadLink extends React.PureComponent {
);
} else if (fileInfo === null && !downloading) {
if (!costInfo) {
return <BusyMessage message={__("Fetching cost info")} />;
} else {
return <BusyMessage message={__('Fetching cost info')} />;
}
return (
<Link
button="text"
label={__("Download")}
label={__('Download')}
icon="icon-download"
className="no-underline"
onClick={() => {
@ -91,11 +89,10 @@ class FileDownloadLink extends React.PureComponent {
}}
/>
);
}
} else if (fileInfo && fileInfo.download_path) {
return (
<Link
label={__("Open")}
label={__('Open')}
button="text"
icon="icon-external-link-square"
className="no-underline"

View file

@ -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 => ({});

View file

@ -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,24 +28,20 @@ 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 }) {
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;
} else {
return 0;
}
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}

View file

@ -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),

View file

@ -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} />

View file

@ -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),

View file

@ -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}
/>
);

View file

@ -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),

View file

@ -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>

View file

@ -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>
);

View file

@ -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);

View file

@ -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>
);

View file

@ -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);

View file

@ -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>
);

View file

@ -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),

View file

@ -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>

View file

@ -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);

View file

@ -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} />;
}

View file

@ -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),

View file

@ -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 (
{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>
<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}
/>
<RewardLink label={__('claim')} reward_type={rewards.TYPE_REFERRAL} />
) : (
<span className="empty">{__("unclaimable")}</span>
<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>

View file

@ -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();

View file

@ -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>
);

View file

@ -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)),

View file

@ -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;

View file

@ -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);

View file

@ -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} />;

View file

@ -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>

View file

@ -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">

View file

@ -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);

View file

@ -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 (
const NsfwOverlay = props => (
<div className="card-overlay">
<p>
{__(
"This content is Not Safe For Work. To view adult content, please change your"
)}{" "}
{__('This content is Not Safe For Work. To view adult content, please change your')}{' '}
<Link
className="button-text"
onClick={() => props.navigateSettings()}
label={__("Settings")}
label={__('Settings')}
/>.
</p>
</div>
);
};
);
export default NsfwOverlay;

View file

@ -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),

View file

@ -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}

View file

@ -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,7 +483,7 @@ class PublishForm extends React.PureComponent {
)}
</span>
);
} else {
}
return (
<span>
{__(
@ -515,9 +494,7 @@ class PublishForm extends React.PureComponent {
</span>
);
}
} else {
return "";
}
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>
);

View file

@ -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();

View file

@ -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>
);

View file

@ -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),

View file

@ -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 (
{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>
<td>{reward.created_at.replace('Z', ' ').replace('T', ' ')}</td>
</tr>
);
})}
))}
</tbody>
</table>
</div>

View file

@ -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),

View file

@ -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>
);

View file

@ -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);

View file

@ -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} />

View file

@ -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),

View file

@ -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];

View file

@ -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),

View file

@ -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>
)}

View file

@ -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>

View file

@ -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>
);

View file

@ -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>

View file

@ -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()),

View file

@ -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>
);

View file

@ -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 {
const select = state => ({
modal: selectCurrentModal(state),
daemonVersionMatched: selectDaemonVersionMatched(state),
};
};
});
const perform = dispatch => ({
checkDaemonVersion: () => dispatch(doCheckDaemonVersion()),

View file

@ -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>
);
}

View file

@ -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),

View file

@ -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}

View file

@ -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);

View file

@ -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({
onClick={() =>
subscriptionHandler({
channelName,
uri,
})}
})
}
/>
</div>
) : null;
}
};

View file

@ -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),

View file

@ -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;

View file

@ -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();
}}

View file

@ -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),

View file

@ -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

View file

@ -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>

View file

@ -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),

View file

@ -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