update changelog test #1994
143 changed files with 2183 additions and 2136 deletions
|
@ -39,6 +39,7 @@
|
||||||
"no-return-assign": 0,
|
"no-return-assign": 0,
|
||||||
"react/require-default-props": 0,
|
"react/require-default-props": 0,
|
||||||
"react/jsx-closing-tag-location": 0,
|
"react/jsx-closing-tag-location": 0,
|
||||||
"jsx-a11y/no-noninteractive-element-to-interactive-role": 0
|
"jsx-a11y/no-noninteractive-element-to-interactive-role": 0,
|
||||||
|
"class-methods-use-this": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,10 @@ module.name_mapper='^types\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/types\1'
|
||||||
module.name_mapper='^component\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/component\1'
|
module.name_mapper='^component\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/component\1'
|
||||||
module.name_mapper='^page\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/page\1'
|
module.name_mapper='^page\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/page\1'
|
||||||
module.name_mapper='^lbry\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/lbry\1'
|
module.name_mapper='^lbry\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/lbry\1'
|
||||||
module.name_mapper='^rewards\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/rewards\1'
|
|
||||||
module.name_mapper='^modal\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/modal\1'
|
module.name_mapper='^modal\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/modal\1'
|
||||||
module.name_mapper='^app\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/app\1'
|
module.name_mapper='^app\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/app\1'
|
||||||
module.name_mapper='^native\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/native\1'
|
module.name_mapper='^native\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/native\1'
|
||||||
module.name_mapper='^analytics\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/analytics\1'
|
module.name_mapper='^analytics\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/analytics\1'
|
||||||
|
|
||||||
|
|
||||||
[strict]
|
[strict]
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
|
.DS_Store
|
||||||
/node_modules
|
/node_modules
|
||||||
/dist
|
/dist
|
||||||
/static/daemon/lbrynet*
|
/static/daemon/lbrynet*
|
||||||
|
|
103
.travis.yml
103
.travis.yml
|
@ -1,49 +1,76 @@
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: osx
|
- os: osx
|
||||||
env: TARGET=mac
|
env: TARGET=mac
|
||||||
osx_image: xcode9.2
|
osx_image: xcode9.2
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js: "9"
|
node_js: '9'
|
||||||
- os: linux
|
- os: linux
|
||||||
env: TARGET=windows
|
env: TARGET=windows
|
||||||
services: docker
|
services: docker
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js: "9"
|
node_js: '9'
|
||||||
- os: linux
|
- os: linux
|
||||||
env: TARGET=linux
|
env: TARGET=linux
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js: "9"
|
node_js: '9'
|
||||||
cache: false
|
cache: false
|
||||||
before_install:
|
before_install:
|
||||||
- |
|
- |
|
||||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
unset TRAVIS_COMMIT_MESSAGE;
|
||||||
mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v2.3.1/git-lfs-$([ "$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-2.3.1.tar.gz | tar -xz -C /tmp/git-lfs --strip-components 1
|
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||||
export PATH="/tmp/git-lfs:$PATH"
|
mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v2.3.1/git-lfs-$([ "$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-2.3.1.tar.gz | tar -xz -C /tmp/git-lfs --strip-components 1
|
||||||
else
|
export PATH="/tmp/git-lfs:$PATH"
|
||||||
sudo apt-get -qq update
|
else
|
||||||
sudo apt-get install -y libsecret-1-dev
|
sudo apt-get -qq update
|
||||||
sudo apt-get install --no-install-recommends -y gcc-multilib g++-multilib
|
sudo apt-get install -y libsecret-1-dev
|
||||||
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.6.0
|
sudo apt-get install --no-install-recommends -y gcc-multilib g++-multilib
|
||||||
export PATH="$HOME/.yarn/bin:$PATH"
|
curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.6.0
|
||||||
fi
|
export PATH="$HOME/.yarn/bin:$PATH"
|
||||||
|
fi
|
||||||
before_script:
|
before_script:
|
||||||
- git lfs pull
|
- git lfs pull
|
||||||
script:
|
script:
|
||||||
- |
|
- |
|
||||||
if [ "$TARGET" == "windows" ]; then
|
if [ "$TARGET" == "windows" ]; then
|
||||||
docker run --rm \
|
# Remove any special characters before adding to our list of ENVs
|
||||||
--env-file <(env | grep -iE 'DEBUG|TARGET|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS|APPVEYOR_|CSC_|GH_|GITHUB_|BT_|AWS_|STRIP|BUILD_') \
|
# https://github.com/electron-userland/electron-builder/issues/2450#issuecomment-421788155
|
||||||
-v ${PWD}:/project \
|
ENVS=`env | grep -iE '(DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS|APPVEYOR_|CSC_|_TOKEN|_KEY|AWS_|STRIP|BUILD_|TARGET)([A-Z]|_)*=' | sed -n '/^[^\t]/s/=.*//p' | sed '/^$/d' | sed 's/^/-e /g' | tr '\n' ' '`
|
||||||
electronuserland/builder:wine \
|
docker run $ENVS --rm \
|
||||||
/bin/bash -c "yarn --link-duplicates --pure-lockfile && yarn build --win --publish onTag";
|
-v ${PWD}:/project \
|
||||||
fi
|
electronuserland/builder:wine \
|
||||||
- if [ "$TARGET" == "mac" ]; then yarn build --publish onTag; fi
|
/bin/bash -c "env | grep -v '\r' | grep -iE 'DEBUG|TARGET|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS|APPVEYOR_|CSC_|GH_|GITHUB_|BT_|AWS_|STRIP|BUILD_|WIN_' && yarn --link-duplicates --pure-lockfile && yarn build --win --publish onTag";
|
||||||
- if [ "$TARGET" == "linux" ]; then yarn --link-duplicates --pure-lockfile && yarn build --linux --publish onTag; fi
|
fi
|
||||||
|
- if [ "$TARGET" == "mac" ]; then yarn build --publish onTag; fi
|
||||||
|
- if [ "$TARGET" == "linux" ]; then yarn --link-duplicates --pure-lockfile && yarn
|
||||||
|
build --linux --publish onTag; fi
|
||||||
addons:
|
addons:
|
||||||
artifacts:
|
artifacts:
|
||||||
working_dir: dist
|
working_dir: dist
|
||||||
paths:
|
paths:
|
||||||
- $(git ls-files -o dist/{*.dmg,*.exe,*.deb} | tr "\n" ":")
|
- $(git ls-files -o dist/{*.dmg,*.exe,*.deb} | tr "\n" ":")
|
||||||
target_paths:
|
target_paths:
|
||||||
- /app/build-${TRAVIS_BUILD_NUMBER}_commit-${TRAVIS_COMMIT:0:7}$([ ! -z ${TRAVIS_TAG} ] && echo _tag-${TRAVIS_TAG})
|
- "/app/build-${TRAVIS_BUILD_NUMBER}_commit-${TRAVIS_COMMIT:0:7}$([ ! -z ${TRAVIS_TAG}
|
||||||
|
] && echo _tag-${TRAVIS_TAG})"
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- ARTIFACTS_REGION=us-east-1
|
||||||
|
- ARTIFACTS_BUCKET=build.lbry.io
|
||||||
|
- DANGER_GITHUB_API_TOKEN=f8b612049cbda985c251e18ae36c7a2b9c6c92df
|
||||||
|
- ARTIFACTS_DEBUG=1
|
||||||
|
- WIN_CSC_LINK=https://s3.amazonaws.com/files.lbry.io/cert/win-csc-2018-2019-08.p12
|
||||||
|
- CSC_LINK=https://s3.amazonaws.com/files.lbry.io/cert/osx-cert.p12
|
||||||
|
#AWS_SECRET_ACCESS_KEY
|
||||||
|
- secure: aF0dZ1ub0r6X5SaTH7YYRpV8cl2gkU2tA7y2tkvGZQL0+Vv2FvkhwaXREa9IM9djm7r3W7I8vEekk6Skn300kIBwQ04COxgu+Oeqjsc2a529wmF9AN5EwKExKkVQFIjMjpMBmd/fE05PD29C0vULdtIMX8uhDe5zFE+tGD1QmwKVZ+55oCxJmt7vsQwQr46s/BsPODrZhvSUPWTUG4HSsc5DJwe/XYY+35vWQsnpCkBVabAZg+lnOpqLioRNzTsBX1oSkqTX9uvOC6fN+NlpbJWetzXsBciFcMHQCx9UHxu+Ibn3W3V8FVYRuFLAinhIg+JoVQHU8mH60ggjizATpgx12riP9e/Uwho5x5bgIYmnIBf4AHqupPv40iC/THMvsS08hCQHicu+/WiAvvN8wNQ1sqpj0+RTreB+4/qdRdwTs70t4jNV83cP+nAuekMCC7uYQ08GLmFNaa+x8NgDZa3JQv7EmXU0ALWVPeJ9UEV+dhEs5iI+7bLEhTUOuvBBWo17F4pst3pfS1j7md1x4wKFRWyP7IFmjK+L1KiAH94c/LIz2Nlp5yCDfbcwU5W/wCHYAxu5c8qnAlkxeub0GpxtZ66j6oOehk1lsHYxaZcBxyn7XhM1A6Mjxgy9OG0WGyYun8iH3aa4WcY0BO21l7je75s7l0qNSRS80st8kUE=
|
||||||
|
#AWS_ACCESS_KEY_ID
|
||||||
|
- secure: HHlUGaEjk0qsW9qb/93jdFhJypiDuJ0e6Z4UClW3ciMfdZ22Ur4D0oL0mgVguigTjdkf1Yy4Z1kWtWvtvQ8DBI+mdOl5GTMpX5nMattcuK/4gFXmqz30S3c07IPkilGKkAT64JqRGT7AvQTaV/tXqNNN9BbWCTAJSnhfzYJFvZQjnSmAAQvbqzMWEEein53244fWbDio462T7vzfbEHJD1pVUSrAMrKDgFSrIKJf4GQHceUk+fqWBjAsWN8USboo88JSLXn5qhD3ZczsgtZ2gi2KTvdfrHfZ5SpOzwc2AGr8U1laQzzW8c8xsPJPmM/3dCri/clcXassa4t/+2INYTPhKbmaD9hvjFRRMpoNjMCmPRJOmojxit8tqzCrw4nSGdr3/Bt0JjpLq90mfyL83YYU4gJXF97KzTl0lCy/DFXjBiHA9riRJVaXn3CI6L0i1RLCJI+C/rT9ErFB767t0aQtXlIWSZQ+IqWaoUdp57t0e2EtbRcjK7IYIXLNgZSbR0bY/TS005D/xZkexCpAtcV9F6iqDYP3HbGyiQqC75se0MqpNrZAx1a7WsSnumOcmtuU6LRriwjM0GXEACfGLCp4w4LBzKPwrOOg4QOhewHKgxpUff8KMlfTZ+Z8B7NBNjKSPbxiMedmpsiWpPRy6VeyvwNz32PUpjdsF3tIYMk=
|
||||||
|
#GH_TOKEN
|
||||||
|
- secure: g0gSiOmCKFzxLFV//oogmex+MkumCcGJ8CtvLzojAw1qhI1P6dGRH06yuCgBNW4PQGbbrYR2tntGEeq66LZ1bU7BJ2bdkv5lBi15JPH4POpA3OSc88YebitKIyIBI2WHA3VNCkF1JEFvrfTUX+4PjP+9h6vZ9tdfzezNTpc70SrGkWMhaoe+F8u6jCL63VBpnncf0foz3WlqUFNoIdinQLYxI6S2QmHz1p1HToC+MOosBgWDufX2+6B/Efq7JDFZgx/zItFzR1OCafKx8rScUd4woAqK+8mt862IzzEbztTv6IPSdhx/hsbO7rHMcjDFk/MuDeC9TaaXqMvvKmLuvWKH+dy4BvIiJJ/WuDfzumrw+8BvTbcnXFXkEXTlkQnZD0otBZsmI4/OPH5vIGUmVIwBFXjPBcNq/Xwig8hRCxrdioEZPO4C17fMCdOn3gAx+GcMddfAIKnrlG/XK2jL8kCylL7++OEkedzYiHWA7p9eaJDjxYmIxKcfYTyF4VIMYS/wAC5W1zi1AjM5BiUhBGp/Vd+f3UUTOsqWOmS4A8cqhK/rbx4xgdwUuv2DoljeQtWd2xdZFr10L2ErmEIdfdtZBVyauaGOhhXUqpSAB5PAwSRNNWkZFCJXmqMHemih4jlfN/KS+rujh5dbyXz81BPjyxrDAziO4Q19rz7hmVI=
|
||||||
|
#ARTIFACTS_KEY
|
||||||
|
- secure: giJRkODdgvMpaLh58c3UKTy6j3IjUVQ2wVvLmECN8caVLuBnEp3U56rUT7sQPzeMoaF9goOLKXD1o+qKdGsLz2Dedi/3vFr3IXTgpYwO03eMkylYUDUwKXV1Fv14ME+wknw/Fshmty1XAc/RwlTaCks9usIRT9OE75HvV8ILVfLdSwwRR/TKFEdEDjAY/3ROVFsleDKBIe1AG/AHeN37Mwqfo39zpN5Zidm3HUegujsMsHtPQtUUCvCxiaiBtqIz79WQuiXjelLWrV53k+ulpptz4T6M8FO5jxBCL5HQMbYy4J8BhukAPHUcTVzarsDe1XEmP6xtClcAydMiHmzUBh9VbvRF8AKwGGO41g6OasgMaJ/eUlACGWTIS2AsqgkXCEgWRtswwI4edLgT/F74fKxGV82zRYLcmjWceGc9H6m2YfIIQZ2PNsDloFgTWa63oZ1sT20fWmNohD3IgVK21rjrCnMbp5/RfBdihR1+GsS8wMA15nhUW3SHfSHKV0009FZdDjxgmigjjmFt1/SM8YGZDijQc7DoUsrScR9n2JR+KVqEED3BYOviw0M0blb6b2dqK0A3+N5C1RGt8Uu8AAuAzdPDviL38m4n1UOdI1Tij1boSfr1USvfipPfQXrqSWHIY3RITMmjPREmcdj2dbhjoUEFaFfp/b3sJxUI3I4=
|
||||||
|
#ARTIFACTS_SECRET
|
||||||
|
- secure: RtPES82DBisaCkernDm10u8mzNc8K4EyyTJUCopcFFJHfFpleuJOoXNFZGXixjHXWTxqc5+IjLThBZFG6krTpD4ocftfkBNeVDXL91JsGRW6X4VBpKaJp1UJZZiYjpPZRJDwVuIb570WcX3xXmsvAwwdODkeXgBZoOw+LZIz4HV3OACi5iaWCx4+2WvQiaz/6mRkLlw9iY1m9gCGQXXUSWyY+bGWsOdGWpfp/VfzpX7mBJbcIYjvRYSnBtVUFkEzxHlaR/CFc7Jio45EUImhBKqKV8QGAiv9AowcWqQn8y2SuW8J66bkaZGbGpyEdsRQDJKUU5naRIFJ/002e4XjI2moBfSHHnFTMH/AawA4b+gCjein8jDiRugJw8AqC4KpG660SFJwC4A8IxfPcXWcykahrL6kJhs+NFbyxQEJIMUqP6UAAiPAuUr/Whq1F8x5b39pEibRZ3Vv0Bix/lUj4cWZYRBL1ckoUgSCeG7llkAdnxLuQKfDvTw+HFcWGq7yg/ye7H7CwpBJkSSOlnQ61nuucC82hVqBGoPGbFW3vjS0BqesLcaO7kwW/fdBnIxwLiWWHDWol0aLfQLEzjUzpS+tA1YYKvrG+yNMEeYtHEK9ZcltQD52uEtjK26DIY8tQU8PxMlXha6/XTOlt8MIcl8IPULmVWKT9k8LPTFQiXc=
|
||||||
|
#CSC_KEY_PASSWORD
|
||||||
|
- secure: TDKeF7/WGwR+di+JhNp29x7NPzVMO/q+72n58zB5goI1NUKaeKgjeWbfVYx9f+4G9a9/pdDVUfORt8i6OW8ZhhqYS4E8G5F56q+oX3nrjNqM8NqoK09ehZS/wdYGbenG9oTfXYenDdwusZV4Fq0BRRLjqAIXPQCKg3//MKseh/1fHDGVGXpYUimHRSCkwspbbfB/9Qw9KEBjweeXiAwB+5F+E7fPlVtqsIvtkkED1hKe0Z8HdECC6JTZ0ZHPDDFGV3aondXQDgUlfchnZ6HDdNDO5y/hPEj0laiZQ7BssenJ8Z7qjHc5O9AKXfG+6WFICHvtgjQ0+x6rk6gpvJcyI1x2+Kck/s0EcSkFY+Yz81BxdehIeKPn9U8LpGaFbtxsp01661yeaIpAqT/PqFsdj/kFXFT6gwZlGGPMBm2WgQR4A61qkOO1jokqz/z6CnY+MNeE8E1Fh4bFoZ0JwUJFJugoyDahHpVlLw5lZaSipJO6RZ1xjoZ3XGmxvtkM4dQ16xQ++Q8EgD878uCWn2jZ5YTQdKANfXYTKSiQfoEjLeX0T6I6GSdim4ZURjcolmGNMH/3jhISOXj+e2UkLc6jwO4Ek084o6ciJ2JjqEhXvXOCeRJ2I9cf2dEk7CvtbitiDly6XATo2FP4hqNdcNNWyj/jFvuTwFT6hzBqLk1BCBc=
|
||||||
|
#WIN_CSC_KEY_PASSWORD
|
||||||
|
- secure: LBwkNMw5paoxpeLcNvAbrSLghLH0kXmgctBkUK6hgqJ/6WReWKlERUCwWQp/NcAB5Nb8fUTV8hXz1UjeQG1HH65geRcxya9sf9xu446e2gRdYGfYk7AhZdIw97IlwTYv2tpnjejiVXIoClQjKRYtOkRC4BIGW+Ydun1hwEUXTVMCplOzPhpLrkJCIDDDdM4eJjWm6ZMshCKRlnt42sNdx63FHBAH72rqBnt2jd+ISIadASnWz0nQlN5aIvXR6cLZfSl8Qt/JDL+LXzWX+pNA4BegCtW3hBoLrW18QdNPxrvPCvKjRCC3LHuv+KEGbzGv/QkXg5f9BKZehIZ/hjYgxysjeHBI8yOfCoyrDafxSIso5ja2TtL9lLpW90gbkbtEFiaL2XOMUbQcwWQ6RShSoLZxgiAl6zUmrq3UtS30OjnjWgMj+WnU2BcgpmpPzU0Hz/fblX6/EnwXhPNRYZvm5JyhVRYLZypLWuV4XsWGuLbUOOrsYi7UvU+xo+3AaxbUW4A6XuQ/DUh0ZVNlpPGcVi7A2tx4/46Wm0oLwQ5NYVukHbEiHWZ4HuKqSionwtgG0T2a6/7JQdH7gb+/86z4YHmK89dd/aE84hBUGTB/pNvvtDBYBE3c60SzL0CFPJZrbz9E0gVhLfsHO+5/VCFIipgM8mYoVzsq+cONKbqUPCg=
|
||||||
|
|
29
CHANGELOG.md
29
CHANGELOG.md
|
@ -5,6 +5,28 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* Allow typing of encryption password without clicking entry box ([#1977](https://github.com/lbryio/lbry-desktop/pull/1977))
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* Make tooltip smarter ([#1979](https://github.com/lbryio/lbry-desktop/pull/1979))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Invite table cutoff with large number of invites ([#1985](https://github.com/lbryio/lbry-desktop/pull/1985))
|
||||||
|
|
||||||
|
|
||||||
|
## [0.25.1] - 2018-09-18
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Paragraph rendering now properly includes a margin for new paragraphs ([#1939](https://github.com/lbryio/lbry-desktop/pull/1939))
|
||||||
|
* Alignment of "navigate to page" input next to pagination on channel pages ([#1941](https://github.com/lbryio/lbry-desktop/pull/1941))
|
||||||
|
* Table spacing with claim name in transactions table ([#1942](https://github.com/lbryio/lbry-desktop/pull/1942))
|
||||||
|
* Ability to click away from tip screen without the cancel button ([#1944](https://github.com/lbryio/lbry-desktop/pull/1944))
|
||||||
|
* Disallow invalid tip amounts ([#1947](https://github.com/lbryio/lbry-desktop/pull/1947))
|
||||||
|
* Ensure we record views for downloaded content from subscriptions and autoplay ([#1962](https://github.com/lbryio/lbry-desktop/pull/1962))
|
||||||
|
|
||||||
|
## [0.25.0] - 2018-08-29
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
* Wallet encryption/decryption user flows in settings ([#1785](https://github.com/lbryio/lbry-desktop/pull/1785))
|
* Wallet encryption/decryption user flows in settings ([#1785](https://github.com/lbryio/lbry-desktop/pull/1785))
|
||||||
* Suggestions for recommended content on file page ([#1845](https://github.com/lbryio/lbry-desktop/pull/1845))
|
* Suggestions for recommended content on file page ([#1845](https://github.com/lbryio/lbry-desktop/pull/1845))
|
||||||
|
@ -17,15 +39,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
* 3D File viewer features and performance/memory usage improvements ([#1870](https://github.com/lbryio/lbry-desktop/pull/1870))
|
* 3D File viewer features and performance/memory usage improvements ([#1870](https://github.com/lbryio/lbry-desktop/pull/1870))
|
||||||
* Desktop notification when publish is completed ([#1892](https://github.com/lbryio/lbry-desktop/pull/1892))
|
* Desktop notification when publish is completed ([#1892](https://github.com/lbryio/lbry-desktop/pull/1892))
|
||||||
* FAQ to Publishing Area ([#1833](https://github.com/lbryio/lbry-desktop/pull/1833))
|
* FAQ to Publishing Area ([#1833](https://github.com/lbryio/lbry-desktop/pull/1833))
|
||||||
* FAQ to wallet security area ([#1917](https://github.com/lbryio/lbry-desktop/pull/1917))
|
* FAQ to wallet security area ([#1917](https://github.com/lbryio/lbry-desktop/pull/1917))
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* Upgraded LBRY Protocol to [version 0.21.2](https://github.com/lbryio/lbry/releases/tag/v0.21.2) fixing a download bug.
|
* Upgraded LBRY Protocol to [version 0.21.2](https://github.com/lbryio/lbry/releases/tag/v0.21.2) fixing a download bug.
|
||||||
* Searching now shows results by default, including direct lbry:// URL tile
|
* Searching now shows results by default, including direct lbry:// URL tile ([#1875](https://github.com/lbryio/lbry-desktop/pull/))
|
||||||
* Replaced checkboxes with toggles throughout app ([#1834](https://github.com/lbryio/lbry-desktop/pull/1834))
|
* Replaced checkboxes with toggles throughout app ([#1834](https://github.com/lbryio/lbry-desktop/pull/1834))
|
||||||
* Removed price tile when content is Free ([#1845](https://github.com/lbryio/lbry-desktop/pull/1845))
|
* Removed price tile when content is Free ([#1845](https://github.com/lbryio/lbry-desktop/pull/1845))
|
||||||
* Pass error message from spee.ch API during thumbnail upload ([#1840](https://github.com/lbryio/lbry-desktop/pull/1840))
|
* Pass error message from spee.ch API during thumbnail upload ([#1840](https://github.com/lbryio/lbry-desktop/pull/1840))
|
||||||
* Use router pattern for rendering file viewer ([#1544](https://github.com/lbryio/lbry-desktop/pull/1544))
|
* Use router pattern for rendering file viewer ([#1544](https://github.com/lbryio/lbry-desktop/pull/1544))
|
||||||
* Missing word "to" added to the Bid Help Text (#1854)
|
* Missing word "to" added to the Bid Help Text ([#1854](https://github.com/lbryio/lbry-desktop/pull/1854))
|
||||||
* Updated to electron@2 ([#1858](https://github.com/lbryio/lbry-desktop/pull/1858))
|
* Updated to electron@2 ([#1858](https://github.com/lbryio/lbry-desktop/pull/1858))
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "LBRY",
|
"name": "LBRY",
|
||||||
"version": "0.25.0",
|
"version": "0.25.1",
|
||||||
"description": "A browser for the LBRY network, a digital marketplace controlled by its users.",
|
"description": "A browser for the LBRY network, a digital marketplace controlled by its users.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"lbry"
|
"lbry"
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
"flow-defs": "flow-typed install",
|
"flow-defs": "flow-typed install",
|
||||||
"release": "yarn compile && electron-builder build",
|
"release": "yarn compile && electron-builder build",
|
||||||
"precommit": "lint-staged",
|
"precommit": "lint-staged",
|
||||||
"preinstall": "yarn cache clean lbry-redux",
|
"preinstall": "yarn cache clean lbry-redux && yarn cache clean lbryinc",
|
||||||
"postinstall": "electron-builder install-app-deps && node build/downloadDaemon.js"
|
"postinstall": "electron-builder install-app-deps && node build/downloadDaemon.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -50,7 +50,8 @@
|
||||||
"formik": "^0.10.4",
|
"formik": "^0.10.4",
|
||||||
"hast-util-sanitize": "^1.1.2",
|
"hast-util-sanitize": "^1.1.2",
|
||||||
"keytar": "^4.2.1",
|
"keytar": "^4.2.1",
|
||||||
"lbry-redux": "lbryio/lbry-redux#421321a78397251589e5a890f4caa95e79975e2b",
|
"lbry-redux": "lbryio/lbry-redux#c079b108c3bc4ba2b4fb85fb112b52cfc040c301",
|
||||||
|
"lbryinc": "lbryio/lbryinc#de7ff055605b02a24821f0f9bab1d206eb7f235d",
|
||||||
"localforage": "^1.7.1",
|
"localforage": "^1.7.1",
|
||||||
"mammoth": "^1.4.6",
|
"mammoth": "^1.4.6",
|
||||||
"mime": "^2.3.1",
|
"mime": "^2.3.1",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// @flow
|
// @flow
|
||||||
import mixpanel from 'mixpanel-browser';
|
import mixpanel from 'mixpanel-browser';
|
||||||
import Lbryio from 'lbryio';
|
import { Lbryio } from 'lbryinc';
|
||||||
import isDev from 'electron-is-dev';
|
import isDev from 'electron-is-dev';
|
||||||
|
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
|
|
|
@ -38,4 +38,7 @@ global.__ = i18n.__;
|
||||||
global.__n = i18n.__n;
|
global.__n = i18n.__n;
|
||||||
global.app = app;
|
global.app = app;
|
||||||
|
|
||||||
|
// Lbryinc needs access to the redux store for dispatching auth-releated actions
|
||||||
|
global.store = app.store;
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|
|
@ -4,9 +4,14 @@ import { clipboard } from 'electron';
|
||||||
import { FormRow } from 'component/common/form';
|
import { FormRow } from 'component/common/form';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
/*
|
||||||
|
noSnackbar added due to issue 1945
|
||||||
|
https://github.com/lbryio/lbry-desktop/issues/1945
|
||||||
|
"Snackbars and modals can't be displayed at the same time"
|
||||||
|
*/
|
||||||
type Props = {
|
type Props = {
|
||||||
address: string,
|
address: string,
|
||||||
|
noSnackbar: boolean,
|
||||||
doNotify: ({ message: string, displayType: Array<string> }) => void,
|
doNotify: ({ message: string, displayType: Array<string> }) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,7 +25,7 @@ export default class Address extends React.PureComponent<Props> {
|
||||||
input: ?HTMLInputElement;
|
input: ?HTMLInputElement;
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { address, doNotify } = this.props;
|
const { address, doNotify, noSnackbar } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormRow verticallyCentered padded stretch>
|
<FormRow verticallyCentered padded stretch>
|
||||||
|
@ -43,10 +48,12 @@ export default class Address extends React.PureComponent<Props> {
|
||||||
icon={icons.CLIPBOARD}
|
icon={icons.CLIPBOARD}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
clipboard.writeText(address);
|
clipboard.writeText(address);
|
||||||
doNotify({
|
if (!noSnackbar) {
|
||||||
message: __('Address copied'),
|
doNotify({
|
||||||
displayType: ['snackbar'],
|
message: __('Address copied'),
|
||||||
});
|
displayType: ['snackbar'],
|
||||||
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectPageTitle, selectHistoryIndex, selectActiveHistoryEntry } from 'lbry-redux';
|
import { selectPageTitle, selectHistoryIndex, selectActiveHistoryEntry } from 'lbry-redux';
|
||||||
import { doRecordScroll } from 'redux/actions/navigation';
|
import { doRecordScroll } from 'redux/actions/navigation';
|
||||||
import { selectUser } from 'redux/selectors/user';
|
import { selectUser } from 'lbryinc';
|
||||||
import { doAlertError } from 'redux/actions/app';
|
import { doAlertError } from 'redux/actions/app';
|
||||||
import App from './view';
|
import App from './view';
|
||||||
|
|
||||||
|
@ -17,4 +17,7 @@ const perform = dispatch => ({
|
||||||
recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)),
|
recordScroll: scrollPosition => dispatch(doRecordScroll(scrollPosition)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(App);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(App);
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectUserEmail } from 'redux/selectors/user';
|
import { selectUserEmail } from 'lbryinc';
|
||||||
import CardVerify from './view';
|
import CardVerify from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
email: selectUserEmail(state),
|
email: selectUserEmail(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({});
|
const perform = () => ({});
|
||||||
|
|
||||||
export default connect(select, perform)(CardVerify);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(CardVerify);
|
||||||
|
|
|
@ -79,7 +79,7 @@ class ChannelTile extends React.PureComponent<Props> {
|
||||||
'card__title--large': size === 'large',
|
'card__title--large': size === 'large',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<TruncatedText lines={1}>{channelName || uri}</TruncatedText>
|
<TruncatedText text={channelName || uri} lines={1} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={classnames('card__subtitle', {
|
className={classnames('card__subtitle', {
|
||||||
|
|
|
@ -24,9 +24,27 @@ type Props = {
|
||||||
stretch?: boolean,
|
stretch?: boolean,
|
||||||
affixClass?: string, // class applied to prefix/postfix label
|
affixClass?: string, // class applied to prefix/postfix label
|
||||||
firstInList?: boolean, // at the top of a list, no padding top
|
firstInList?: boolean, // at the top of a list, no padding top
|
||||||
|
autoFocus?: boolean,
|
||||||
|
inputProps: {
|
||||||
|
disabled?: boolean,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FormField extends React.PureComponent<Props> {
|
export class FormField extends React.PureComponent<Props> {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.input = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { autoFocus } = this.props;
|
||||||
|
const input = this.input.current;
|
||||||
|
|
||||||
|
if (input && autoFocus) {
|
||||||
|
input.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
render,
|
render,
|
||||||
|
@ -40,6 +58,7 @@ export class FormField extends React.PureComponent<Props> {
|
||||||
children,
|
children,
|
||||||
stretch,
|
stretch,
|
||||||
affixClass,
|
affixClass,
|
||||||
|
autoFocus,
|
||||||
...inputProps
|
...inputProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -79,7 +98,7 @@ export class FormField extends React.PureComponent<Props> {
|
||||||
} else if (type === 'checkbox') {
|
} else if (type === 'checkbox') {
|
||||||
input = <Toggle id={name} {...inputProps} />;
|
input = <Toggle id={name} {...inputProps} />;
|
||||||
} else {
|
} else {
|
||||||
input = <input type={type} id={name} {...inputProps} />;
|
input = <input type={type} id={name} {...inputProps} ref={this.input} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ type Props = {
|
||||||
verticallyCentered?: boolean,
|
verticallyCentered?: boolean,
|
||||||
stretch?: boolean,
|
stretch?: boolean,
|
||||||
alignRight?: boolean,
|
alignRight?: boolean,
|
||||||
|
centered?: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FormRow extends React.PureComponent<Props> {
|
export class FormRow extends React.PureComponent<Props> {
|
||||||
|
@ -17,7 +18,7 @@ export class FormRow extends React.PureComponent<Props> {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children, padded, verticallyCentered, stretch, alignRight } = this.props;
|
const { children, padded, verticallyCentered, stretch, alignRight, centered } = this.props;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames('form-row', {
|
className={classnames('form-row', {
|
||||||
|
@ -25,6 +26,7 @@ export class FormRow extends React.PureComponent<Props> {
|
||||||
'form-row--vertically-centered': verticallyCentered,
|
'form-row--vertically-centered': verticallyCentered,
|
||||||
'form-row--stretch': stretch,
|
'form-row--stretch': stretch,
|
||||||
'form-row--right': alignRight,
|
'form-row--right': alignRight,
|
||||||
|
'form-row--centered': centered,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import Tooltip from 'component/common/tooltip';
|
||||||
// These are copied from `scss/vars`, can they both come from the same source?
|
// These are copied from `scss/vars`, can they both come from the same source?
|
||||||
const RED_COLOR = '#e2495e';
|
const RED_COLOR = '#e2495e';
|
||||||
const GREEN_COLOR = '#44b098';
|
const GREEN_COLOR = '#44b098';
|
||||||
|
const BLUE_COLOR = '#49b2e2';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
icon: string,
|
icon: string,
|
||||||
|
@ -33,6 +34,8 @@ class IconComponent extends React.PureComponent<Props> {
|
||||||
return RED_COLOR;
|
return RED_COLOR;
|
||||||
case 'green':
|
case 'green':
|
||||||
return GREEN_COLOR;
|
return GREEN_COLOR;
|
||||||
|
case 'blue':
|
||||||
|
return BLUE_COLOR;
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,67 @@ class ToolTip extends React.PureComponent<Props> {
|
||||||
direction: 'bottom',
|
direction: 'bottom',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.tooltip = React.createRef();
|
||||||
|
this.state = {
|
||||||
|
direction: this.props.direction,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.handleVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
getVisibility = () => {
|
||||||
|
const node = this.tooltip.current;
|
||||||
|
const rect = node.getBoundingClientRect();
|
||||||
|
|
||||||
|
// Get parent-container
|
||||||
|
const viewport = document.getElementById('content');
|
||||||
|
|
||||||
|
const visibility = {
|
||||||
|
top: rect.top >= 0,
|
||||||
|
left: rect.left >= 0,
|
||||||
|
right: rect.right <= viewport.offsetWidth,
|
||||||
|
bottom: rect.bottom <= viewport.offsetHeight,
|
||||||
|
};
|
||||||
|
|
||||||
|
return visibility;
|
||||||
|
};
|
||||||
|
|
||||||
|
invertDirection = () => {
|
||||||
|
// Get current direction
|
||||||
|
const { direction } = this.state;
|
||||||
|
// Inverted directions
|
||||||
|
const directions = {
|
||||||
|
top: 'bottom',
|
||||||
|
left: 'right',
|
||||||
|
right: 'left',
|
||||||
|
bottom: 'top',
|
||||||
|
};
|
||||||
|
|
||||||
|
const inverted = directions[direction];
|
||||||
|
|
||||||
|
// Update direction
|
||||||
|
if (inverted) {
|
||||||
|
this.setState({ direction: inverted });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleVisibility = () => {
|
||||||
|
const { direction } = this.state;
|
||||||
|
const visibility = this.getVisibility();
|
||||||
|
|
||||||
|
// Invert direction if tooltip is outside viewport bounds
|
||||||
|
if (!visibility[direction]) {
|
||||||
|
this.invertDirection();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children, label, body, icon, direction, onComponent } = this.props;
|
const { direction } = this.state;
|
||||||
|
const { children, label, body, icon, onComponent } = this.props;
|
||||||
|
|
||||||
const tooltipContent = children || label;
|
const tooltipContent = children || label;
|
||||||
const bodyLength = body.length;
|
const bodyLength = body.length;
|
||||||
|
@ -25,6 +84,8 @@ class ToolTip extends React.PureComponent<Props> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
|
onFocus={this.handleVisibility}
|
||||||
|
onMouseOver={this.handleVisibility}
|
||||||
className={classnames('tooltip', {
|
className={classnames('tooltip', {
|
||||||
'tooltip--label': label && !icon,
|
'tooltip--label': label && !icon,
|
||||||
'tooltip--icon': icon,
|
'tooltip--icon': icon,
|
||||||
|
@ -37,6 +98,7 @@ class ToolTip extends React.PureComponent<Props> {
|
||||||
>
|
>
|
||||||
{tooltipContent}
|
{tooltipContent}
|
||||||
<span
|
<span
|
||||||
|
ref={this.tooltip}
|
||||||
className={classnames('tooltip__body', {
|
className={classnames('tooltip__body', {
|
||||||
'tooltip__body--short': isShortDescription,
|
'tooltip__body--short': isShortDescription,
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
lines: ?number,
|
text: string,
|
||||||
children: React.Node,
|
lines: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
const TruncatedText = (props: Props) => (
|
const TruncatedText = (props: Props) => (
|
||||||
<span className="truncated-text" style={{ WebkitLineClamp: props.lines }}>
|
<span title={props.text} className="truncated-text" style={{ WebkitLineClamp: props.lines }}>
|
||||||
{props.children}
|
{props.text}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,10 @@ import {
|
||||||
makeSelectClaimIsMine,
|
makeSelectClaimIsMine,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { selectRewardContentClaimIds } from 'redux/selectors/content';
|
import {
|
||||||
|
selectRewardContentClaimIds,
|
||||||
|
makeSelectContentPositionForUri,
|
||||||
|
} from 'redux/selectors/content';
|
||||||
import { selectShowNsfw } from 'redux/selectors/settings';
|
import { selectShowNsfw } from 'redux/selectors/settings';
|
||||||
import { selectPendingPublish } from 'redux/selectors/publish';
|
import { selectPendingPublish } from 'redux/selectors/publish';
|
||||||
import FileCard from './view';
|
import FileCard from './view';
|
||||||
|
@ -32,12 +35,14 @@ const select = (state, props) => {
|
||||||
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
|
rewardedContentClaimIds: selectRewardContentClaimIds(state, props),
|
||||||
...fileCardInfo,
|
...fileCardInfo,
|
||||||
pending: !!pendingPublish,
|
pending: !!pendingPublish,
|
||||||
|
position: makeSelectContentPositionForUri(props.uri)(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||||
resolveUri: uri => dispatch(doResolveUri(uri)),
|
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||||
|
clearHistoryUri: uri => dispatch(doClearContentHistoryUri(uri)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -5,13 +5,12 @@ import type { Claim, Metadata } from 'types/claim';
|
||||||
import CardMedia from 'component/cardMedia';
|
import CardMedia from 'component/cardMedia';
|
||||||
import TruncatedText from 'component/common/truncated-text';
|
import TruncatedText from 'component/common/truncated-text';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
import FilePrice from 'component/filePrice';
|
|
||||||
import UriIndicator from 'component/uriIndicator';
|
import UriIndicator from 'component/uriIndicator';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { openCopyLinkMenu } from '../../util/contextMenu';
|
import FilePrice from 'component/filePrice';
|
||||||
|
import { openCopyLinkMenu } from 'util/contextMenu';
|
||||||
|
|
||||||
// TODO: iron these out
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: string,
|
uri: string,
|
||||||
claim: ?Claim,
|
claim: ?Claim,
|
||||||
|
@ -21,11 +20,11 @@ type Props = {
|
||||||
rewardedContentClaimIds: Array<string>,
|
rewardedContentClaimIds: Array<string>,
|
||||||
obscureNsfw: boolean,
|
obscureNsfw: boolean,
|
||||||
claimIsMine: boolean,
|
claimIsMine: boolean,
|
||||||
showPrice: boolean,
|
|
||||||
pending?: boolean,
|
pending?: boolean,
|
||||||
/* eslint-disable react/no-unused-prop-types */
|
/* eslint-disable react/no-unused-prop-types */
|
||||||
resolveUri: string => void,
|
resolveUri: string => void,
|
||||||
isResolvingUri: boolean,
|
isResolvingUri: boolean,
|
||||||
|
showPrice: boolean,
|
||||||
/* eslint-enable react/no-unused-prop-types */
|
/* eslint-enable react/no-unused-prop-types */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,8 +58,8 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
rewardedContentClaimIds,
|
rewardedContentClaimIds,
|
||||||
obscureNsfw,
|
obscureNsfw,
|
||||||
claimIsMine,
|
claimIsMine,
|
||||||
showPrice,
|
|
||||||
pending,
|
pending,
|
||||||
|
showPrice,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const shouldHide = !claimIsMine && !pending && obscureNsfw && metadata && metadata.nsfw;
|
const shouldHide = !claimIsMine && !pending && obscureNsfw && metadata && metadata.nsfw;
|
||||||
|
@ -94,7 +93,7 @@ class FileCard extends React.PureComponent<Props> {
|
||||||
<CardMedia thumbnail={thumbnail} />
|
<CardMedia thumbnail={thumbnail} />
|
||||||
<div className="card__title-identity">
|
<div className="card__title-identity">
|
||||||
<div className="card__title--small card__title--file-card">
|
<div className="card__title--small card__title--file-card">
|
||||||
<TruncatedText lines={2}>{title}</TruncatedText>
|
<TruncatedText text={title} lines={2} />
|
||||||
</div>
|
</div>
|
||||||
<div className="card__subtitle">
|
<div className="card__subtitle">
|
||||||
{pending ? <div>Pending...</div> : <UriIndicator uri={uri} link />}
|
{pending ? <div>Pending...</div> : <UriIndicator uri={uri} link />}
|
||||||
|
|
|
@ -7,8 +7,7 @@ import {
|
||||||
makeSelectClaimForUri,
|
makeSelectClaimForUri,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doOpenFileInShell } from 'redux/actions/file';
|
import { doOpenFileInShell } from 'redux/actions/file';
|
||||||
import { doPurchaseUri, doStartDownload } from 'redux/actions/content';
|
import { doPurchaseUri, doStartDownload, doSetPlayingUri } from 'redux/actions/content';
|
||||||
import { doPause } from 'redux/actions/media';
|
|
||||||
import FileDownloadLink from './view';
|
import FileDownloadLink from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
|
@ -24,7 +23,7 @@ const perform = dispatch => ({
|
||||||
openInShell: path => dispatch(doOpenFileInShell(path)),
|
openInShell: path => dispatch(doOpenFileInShell(path)),
|
||||||
purchaseUri: uri => dispatch(doPurchaseUri(uri)),
|
purchaseUri: uri => dispatch(doPurchaseUri(uri)),
|
||||||
restartDownload: (uri, outpoint) => dispatch(doStartDownload(uri, outpoint)),
|
restartDownload: (uri, outpoint) => dispatch(doStartDownload(uri, outpoint)),
|
||||||
doPause: () => dispatch(doPause()),
|
pause: () => dispatch(doSetPlayingUri(null)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -22,7 +22,7 @@ type Props = {
|
||||||
restartDownload: (string, number) => void,
|
restartDownload: (string, number) => void,
|
||||||
openInShell: string => void,
|
openInShell: string => void,
|
||||||
purchaseUri: string => void,
|
purchaseUri: string => void,
|
||||||
doPause: () => void,
|
pause: () => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileDownloadLink extends React.PureComponent<Props> {
|
class FileDownloadLink extends React.PureComponent<Props> {
|
||||||
|
@ -50,14 +50,14 @@ class FileDownloadLink extends React.PureComponent<Props> {
|
||||||
purchaseUri,
|
purchaseUri,
|
||||||
costInfo,
|
costInfo,
|
||||||
loading,
|
loading,
|
||||||
doPause,
|
pause,
|
||||||
claim,
|
claim,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const openFile = () => {
|
const openFile = () => {
|
||||||
if (fileInfo) {
|
if (fileInfo) {
|
||||||
openInShell(fileInfo.download_path);
|
openInShell(fileInfo.download_path);
|
||||||
doPause();
|
pause();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,8 @@ class FileList extends React.PureComponent<Props, State> {
|
||||||
name: claimName,
|
name: claimName,
|
||||||
claim_name: claimNameDownloaded,
|
claim_name: claimNameDownloaded,
|
||||||
claim_id: claimId,
|
claim_id: claimId,
|
||||||
outpoint,
|
txid,
|
||||||
|
nout,
|
||||||
} = fileInfo;
|
} = fileInfo;
|
||||||
const uriParams = {};
|
const uriParams = {};
|
||||||
|
|
||||||
|
@ -155,6 +156,7 @@ class FileList extends React.PureComponent<Props, State> {
|
||||||
uriParams.contentName = name;
|
uriParams.contentName = name;
|
||||||
uriParams.claimId = claimId;
|
uriParams.claimId = claimId;
|
||||||
const uri = buildURI(uriParams);
|
const uri = buildURI(uriParams);
|
||||||
|
const outpoint = `${txid}:${nout}`;
|
||||||
|
|
||||||
// See https://github.com/lbryio/lbry-desktop/issues/1327 for discussion around using outpoint as the key
|
// See https://github.com/lbryio/lbry-desktop/issues/1327 for discussion around using outpoint as the key
|
||||||
content.push(<FileCard key={outpoint} uri={uri} checkPending={checkPending} />);
|
content.push(<FileCard key={outpoint} uri={uri} checkPending={checkPending} />);
|
||||||
|
|
|
@ -127,7 +127,7 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
'card__title--large': size === 'large',
|
'card__title--large': size === 'large',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<TruncatedText lines={size === 'small' ? 2 : 3}>{title || name}</TruncatedText>
|
<TruncatedText text={title || name} lines={size === 'small' ? 2 : 3} />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={classnames('card__subtitle', {
|
className={classnames('card__subtitle', {
|
||||||
|
@ -151,7 +151,7 @@ class FileTile extends React.PureComponent<Props> {
|
||||||
'card__subtext--large': size === 'large',
|
'card__subtext--large': size === 'large',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<TruncatedText lines={size === 'large' ? 4 : 3}>{description}</TruncatedText>
|
<TruncatedText text={description} lines={size === 'large' ? 4 : 3} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!name && (
|
{!name && (
|
||||||
|
|
|
@ -2,9 +2,8 @@ import { connect } from 'react-redux';
|
||||||
import * as settings from 'constants/settings';
|
import * as settings from 'constants/settings';
|
||||||
import { doChangeVolume } from 'redux/actions/app';
|
import { doChangeVolume } from 'redux/actions/app';
|
||||||
import { selectVolume } from 'redux/selectors/app';
|
import { selectVolume } from 'redux/selectors/app';
|
||||||
import { doPlayUri, doSetPlayingUri } from 'redux/actions/content';
|
import { doPlayUri, doSetPlayingUri, savePosition } from 'redux/actions/content';
|
||||||
import { doPlay, doPause, savePosition } from 'redux/actions/media';
|
import { doClaimEligiblePurchaseRewards } from 'lbryinc';
|
||||||
import { doClaimEligiblePurchaseRewards } from 'redux/actions/rewards';
|
|
||||||
import {
|
import {
|
||||||
makeSelectMetadataForUri,
|
makeSelectMetadataForUri,
|
||||||
makeSelectContentTypeForUri,
|
makeSelectContentTypeForUri,
|
||||||
|
@ -16,8 +15,7 @@ import {
|
||||||
selectSearchBarFocused,
|
selectSearchBarFocused,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { makeSelectClientSetting, selectShowNsfw } from 'redux/selectors/settings';
|
import { makeSelectClientSetting, selectShowNsfw } from 'redux/selectors/settings';
|
||||||
import { selectMediaPaused, makeSelectMediaPositionForUri } from 'redux/selectors/media';
|
import { selectPlayingUri, makeSelectContentPositionForUri } from 'redux/selectors/content';
|
||||||
import { selectPlayingUri } from 'redux/selectors/content';
|
|
||||||
import { selectFileInfoErrors } from 'redux/selectors/file_info';
|
import { selectFileInfoErrors } from 'redux/selectors/file_info';
|
||||||
import FileViewer from './view';
|
import FileViewer from './view';
|
||||||
|
|
||||||
|
@ -32,8 +30,7 @@ const select = (state, props) => ({
|
||||||
playingUri: selectPlayingUri(state),
|
playingUri: selectPlayingUri(state),
|
||||||
contentType: makeSelectContentTypeForUri(props.uri)(state),
|
contentType: makeSelectContentTypeForUri(props.uri)(state),
|
||||||
volume: selectVolume(state),
|
volume: selectVolume(state),
|
||||||
mediaPaused: selectMediaPaused(state),
|
position: makeSelectContentPositionForUri(props.uri)(state),
|
||||||
mediaPosition: makeSelectMediaPositionForUri(props.uri)(state),
|
|
||||||
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
autoplay: makeSelectClientSetting(settings.AUTOPLAY)(state),
|
||||||
searchBarFocused: selectSearchBarFocused(state),
|
searchBarFocused: selectSearchBarFocused(state),
|
||||||
fileInfoErrors: selectFileInfoErrors(state),
|
fileInfoErrors: selectFileInfoErrors(state),
|
||||||
|
@ -43,10 +40,9 @@ const perform = dispatch => ({
|
||||||
play: uri => dispatch(doPlayUri(uri)),
|
play: uri => dispatch(doPlayUri(uri)),
|
||||||
cancelPlay: () => dispatch(doSetPlayingUri(null)),
|
cancelPlay: () => dispatch(doSetPlayingUri(null)),
|
||||||
changeVolume: volume => dispatch(doChangeVolume(volume)),
|
changeVolume: volume => dispatch(doChangeVolume(volume)),
|
||||||
doPlay: () => dispatch(doPlay()),
|
|
||||||
doPause: () => dispatch(doPause()),
|
|
||||||
savePosition: (claimId, position) => dispatch(savePosition(claimId, position)),
|
|
||||||
claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()),
|
claimRewards: () => dispatch(doClaimEligiblePurchaseRewards()),
|
||||||
|
savePosition: (claimId, outpoint, position) =>
|
||||||
|
dispatch(savePosition(claimId, outpoint, position)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|
|
@ -27,9 +27,11 @@ class MediaPlayer extends React.PureComponent {
|
||||||
this.toggleFullScreenVideo = this.toggleFullScreen.bind(this);
|
this.toggleFullScreenVideo = this.toggleFullScreen.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentDidUpdate(nextProps) {
|
||||||
const el = this.refs.media.children[0];
|
const el = this.refs.media.children[0];
|
||||||
if (!this.props.paused && nextProps.paused && !el.paused) el.pause();
|
if (this.props.playingUri && !nextProps.playingUri && !el.paused) {
|
||||||
|
el.pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -86,11 +88,15 @@ class MediaPlayer extends React.PureComponent {
|
||||||
document.addEventListener('keydown', this.togglePlayListener);
|
document.addEventListener('keydown', this.togglePlayListener);
|
||||||
const mediaElement = this.media.children[0];
|
const mediaElement = this.media.children[0];
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
mediaElement.currentTime = position || 0;
|
if (position) {
|
||||||
mediaElement.addEventListener('play', () => this.props.doPlay());
|
mediaElement.currentTime = position;
|
||||||
mediaElement.addEventListener('pause', () => this.props.doPause());
|
}
|
||||||
mediaElement.addEventListener('timeupdate', () =>
|
mediaElement.addEventListener('timeupdate', () =>
|
||||||
this.props.savePosition(claim.claim_id, mediaElement.currentTime)
|
this.props.savePosition(
|
||||||
|
claim.claim_id,
|
||||||
|
`${claim.txid}:${claim.nout}`,
|
||||||
|
mediaElement.currentTime
|
||||||
|
)
|
||||||
);
|
);
|
||||||
mediaElement.addEventListener('click', this.togglePlayListener);
|
mediaElement.addEventListener('click', this.togglePlayListener);
|
||||||
mediaElement.addEventListener('loadedmetadata', loadedMetadata.bind(this), {
|
mediaElement.addEventListener('loadedmetadata', loadedMetadata.bind(this), {
|
||||||
|
@ -136,7 +142,6 @@ class MediaPlayer extends React.PureComponent {
|
||||||
if (mediaElement) {
|
if (mediaElement) {
|
||||||
mediaElement.removeEventListener('click', this.togglePlayListener);
|
mediaElement.removeEventListener('click', this.togglePlayListener);
|
||||||
}
|
}
|
||||||
this.props.doPause();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleFullScreen(event) {
|
toggleFullScreen(event) {
|
||||||
|
|
|
@ -34,11 +34,8 @@ type Props = {
|
||||||
volume: number,
|
volume: number,
|
||||||
claim: Claim,
|
claim: Claim,
|
||||||
uri: string,
|
uri: string,
|
||||||
doPlay: () => void,
|
savePosition: (string, string, number) => void,
|
||||||
doPause: () => void,
|
position: ?number,
|
||||||
savePosition: (string, number) => void,
|
|
||||||
mediaPaused: boolean,
|
|
||||||
mediaPosition: ?number,
|
|
||||||
className: ?string,
|
className: ?string,
|
||||||
obscureNsfw: boolean,
|
obscureNsfw: boolean,
|
||||||
play: string => void,
|
play: string => void,
|
||||||
|
@ -127,14 +124,14 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAutoplay = (props: Props) => {
|
handleAutoplay = (props: Props) => {
|
||||||
const { autoplay, playingUri, fileInfo, costInfo, isDownloading, uri, play, metadata } = props;
|
const { autoplay, playingUri, fileInfo, costInfo, isDownloading, uri, metadata } = props;
|
||||||
|
|
||||||
const playable = autoplay && playingUri !== uri && metadata && !metadata.nsfw;
|
const playable = autoplay && playingUri !== uri && metadata && !metadata.nsfw;
|
||||||
|
|
||||||
if (playable && costInfo && costInfo.cost === 0 && !fileInfo && !isDownloading) {
|
if (playable && costInfo && costInfo.cost === 0 && !fileInfo && !isDownloading) {
|
||||||
play(uri);
|
this.playContent();
|
||||||
} else if (playable && fileInfo && fileInfo.blobs_completed > 0) {
|
} else if (playable && fileInfo && fileInfo.blobs_completed > 0) {
|
||||||
play(uri);
|
this.playContent();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -202,11 +199,8 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
volume,
|
volume,
|
||||||
claim,
|
claim,
|
||||||
uri,
|
uri,
|
||||||
doPlay,
|
|
||||||
doPause,
|
|
||||||
savePosition,
|
savePosition,
|
||||||
mediaPaused,
|
position,
|
||||||
mediaPosition,
|
|
||||||
className,
|
className,
|
||||||
obscureNsfw,
|
obscureNsfw,
|
||||||
mediaType,
|
mediaType,
|
||||||
|
@ -251,14 +245,12 @@ class FileViewer extends React.PureComponent<Props> {
|
||||||
downloadCompleted={fileInfo.completed}
|
downloadCompleted={fileInfo.completed}
|
||||||
changeVolume={changeVolume}
|
changeVolume={changeVolume}
|
||||||
volume={volume}
|
volume={volume}
|
||||||
doPlay={doPlay}
|
|
||||||
doPause={doPause}
|
|
||||||
savePosition={savePosition}
|
savePosition={savePosition}
|
||||||
claim={claim}
|
claim={claim}
|
||||||
uri={uri}
|
uri={uri}
|
||||||
paused={mediaPaused}
|
position={position}
|
||||||
position={mediaPosition}
|
|
||||||
startedPlayingCb={this.startedPlayingCb}
|
startedPlayingCb={this.startedPlayingCb}
|
||||||
|
playingUri={playingUri}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectUserInvitees, selectUserInviteStatusIsPending } from 'redux/selectors/user';
|
import { selectUserInvitees, selectUserInviteStatusIsPending } from 'lbryinc';
|
||||||
import InviteList from './view';
|
import InviteList from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -8,6 +7,9 @@ const select = state => ({
|
||||||
isPending: selectUserInviteStatusIsPending(state),
|
isPending: selectUserInviteStatusIsPending(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({});
|
const perform = () => ({});
|
||||||
|
|
||||||
export default connect(select, perform)(InviteList);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(InviteList);
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
import RewardLink from 'component/rewardLink';
|
import RewardLink from 'component/rewardLink';
|
||||||
import rewards from 'rewards.js';
|
import { rewards } from 'lbryinc';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
|
||||||
class InviteList extends React.PureComponent {
|
type Props = {
|
||||||
|
invitees: ?Array<{
|
||||||
|
email: string,
|
||||||
|
invite_accepted: boolean,
|
||||||
|
invite_reward_claimed: boolean,
|
||||||
|
invite_reward_claimable: boolean,
|
||||||
|
}>,
|
||||||
|
};
|
||||||
|
|
||||||
|
class InviteList extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { invitees } = this.props;
|
const { invitees } = this.props;
|
||||||
|
|
||||||
|
@ -31,8 +41,8 @@ class InviteList extends React.PureComponent {
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{invitees.map((invitee, index) => (
|
{invitees.map(invitee => (
|
||||||
<tr key={index}>
|
<tr key={invitee.email}>
|
||||||
<td>{invitee.email}</td>
|
<td>{invitee.email}</td>
|
||||||
<td className="text-center">
|
<td className="text-center">
|
||||||
{invitee.invite_accepted ? (
|
{invitee.invite_accepted ? (
|
||||||
|
|
|
@ -3,8 +3,8 @@ import {
|
||||||
selectUserInvitesRemaining,
|
selectUserInvitesRemaining,
|
||||||
selectUserInviteNewIsPending,
|
selectUserInviteNewIsPending,
|
||||||
selectUserInviteNewErrorMessage,
|
selectUserInviteNewErrorMessage,
|
||||||
} from 'redux/selectors/user';
|
doUserInviteNew,
|
||||||
import { doUserInviteNew } from 'redux/actions/user';
|
} from 'lbryinc';
|
||||||
import InviteNew from './view';
|
import InviteNew from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -17,4 +17,7 @@ const perform = dispatch => ({
|
||||||
inviteNew: email => dispatch(doUserInviteNew(email)),
|
inviteNew: email => dispatch(doUserInviteNew(email)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(InviteNew);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(InviteNew);
|
||||||
|
|
|
@ -4,11 +4,10 @@ import {
|
||||||
selectPageTitle,
|
selectPageTitle,
|
||||||
selectIsBackDisabled,
|
selectIsBackDisabled,
|
||||||
selectIsForwardDisabled,
|
selectIsForwardDisabled,
|
||||||
selectNavLinks,
|
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
|
import { doNavigate, doHistoryBack, doHistoryForward } from 'redux/actions/navigation';
|
||||||
import { doDownloadUpgrade } from 'redux/actions/app';
|
import { doDownloadUpgrade } from 'redux/actions/app';
|
||||||
import { selectIsUpgradeAvailable } from 'redux/selectors/app';
|
import { selectIsUpgradeAvailable, selectNavLinks } from 'redux/selectors/app';
|
||||||
import { formatCredits } from 'util/formatCredits';
|
import { formatCredits } from 'util/formatCredits';
|
||||||
import Page from './view';
|
import Page from './view';
|
||||||
|
|
||||||
|
@ -28,4 +27,7 @@ const perform = dispatch => ({
|
||||||
downloadUpgrade: () => dispatch(doDownloadUpgrade()),
|
downloadUpgrade: () => dispatch(doDownloadUpgrade()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(Page);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(Page);
|
||||||
|
|
|
@ -1,72 +1,36 @@
|
||||||
// @flow
|
// @flow
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import Button from 'component/button';
|
|
||||||
import { buildURI } from 'lbry-redux';
|
|
||||||
import type { Claim } from 'types/claim';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
uri: ?string,
|
uri: ?string,
|
||||||
isResolvingUri: boolean,
|
isResolvingUri: boolean,
|
||||||
winningBidForClaimUri: ?number,
|
amountNeededForTakeover: ?number,
|
||||||
myClaimForUri: ?Claim,
|
|
||||||
isStillEditing: boolean,
|
|
||||||
onEditMyClaim: (any, string) => void,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BidHelpText extends React.PureComponent<Props> {
|
class BidHelpText extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const {
|
const { uri, isResolvingUri, amountNeededForTakeover } = this.props;
|
||||||
uri,
|
let bidHelpText;
|
||||||
isResolvingUri,
|
|
||||||
winningBidForClaimUri,
|
|
||||||
myClaimForUri,
|
|
||||||
onEditMyClaim,
|
|
||||||
isStillEditing,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
if (!uri) {
|
if (uri) {
|
||||||
return __('Create a URL for this content.');
|
if (isResolvingUri) {
|
||||||
|
bidHelpText = __('Checking the winning claim amount...');
|
||||||
|
} else if (!amountNeededForTakeover) {
|
||||||
|
bidHelpText = __('Any amount will give you the winning bid.');
|
||||||
|
} else {
|
||||||
|
bidHelpText = `${__('If you bid more than')} ${amountNeededForTakeover} LBC, ${__(
|
||||||
|
'when someone navigates to'
|
||||||
|
)} ${uri} ${__('it will load your published content')}. ${__(
|
||||||
|
'However, you can get a longer version of this URL for any bid'
|
||||||
|
)}.`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isStillEditing) {
|
return (
|
||||||
return __(
|
|
||||||
'You are currently editing this claim. If you change the URL, you will need to reselect a file.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isResolvingUri) {
|
|
||||||
return __('Checking the winning claim amount...');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myClaimForUri) {
|
|
||||||
const editUri = buildURI({
|
|
||||||
contentName: myClaimForUri.name,
|
|
||||||
claimId: myClaimForUri.claim_id,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
{__('You already have a claim at')}
|
|
||||||
{` ${uri} `}
|
|
||||||
<Button
|
|
||||||
button="link"
|
|
||||||
label="Edit it"
|
|
||||||
onClick={() => onEditMyClaim(myClaimForUri, editUri)}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
{__('Publishing will update your existing claim.')}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return winningBidForClaimUri ? (
|
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{__('A deposit greater than')} {winningBidForClaimUri} {__('is needed to win')}
|
{__('This LBC remains yours and the deposit can be undone at any time.')}
|
||||||
{` ${uri}. `}
|
<div>{bidHelpText}</div>
|
||||||
{__('However, you can still get this URL for any amount.')}
|
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
) : (
|
|
||||||
__('Any amount will give you the winning bid.')
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
// @flow
|
||||||
|
import * as React from 'react';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import { buildURI } from 'lbry-redux';
|
||||||
|
import type { Claim } from 'types/claim';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
uri: ?string,
|
||||||
|
myClaimForUri: ?Claim,
|
||||||
|
isStillEditing: boolean,
|
||||||
|
onEditMyClaim: (any, string) => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class NameHelpText extends React.PureComponent<Props> {
|
||||||
|
render() {
|
||||||
|
const { uri, myClaimForUri, onEditMyClaim, isStillEditing } = this.props;
|
||||||
|
|
||||||
|
let nameHelpText;
|
||||||
|
|
||||||
|
if (isStillEditing) {
|
||||||
|
nameHelpText = __(
|
||||||
|
'You are currently editing this claim. If you change the URL, you will need to reselect a file.'
|
||||||
|
);
|
||||||
|
} else if (uri && myClaimForUri) {
|
||||||
|
const editUri = buildURI({
|
||||||
|
contentName: myClaimForUri.name,
|
||||||
|
claimId: myClaimForUri.claim_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
nameHelpText = (
|
||||||
|
<React.Fragment>
|
||||||
|
{__('You already have a claim at')}
|
||||||
|
{` ${uri} `}
|
||||||
|
<Button
|
||||||
|
button="link"
|
||||||
|
label="Edit it"
|
||||||
|
onClick={() => onEditMyClaim(myClaimForUri, editUri)}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
{__('Publishing will update your existing claim.')}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <React.Fragment>{nameHelpText || __('Create a URL for this content.')}</React.Fragment>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NameHelpText;
|
|
@ -13,6 +13,7 @@ import { CHANNEL_NEW, CHANNEL_ANONYMOUS, MINIMUM_PUBLISH_BID } from 'constants/c
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
import type { Claim } from 'types/claim';
|
import type { Claim } from 'types/claim';
|
||||||
import BidHelpText from './internal/bid-help-text';
|
import BidHelpText from './internal/bid-help-text';
|
||||||
|
import NameHelpText from './internal/name-help-text';
|
||||||
import LicenseType from './internal/license-type';
|
import LicenseType from './internal/license-type';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -53,8 +54,9 @@ type Props = {
|
||||||
clearPublish: () => void,
|
clearPublish: () => void,
|
||||||
resolveUri: string => void,
|
resolveUri: string => void,
|
||||||
scrollToTop: () => void,
|
scrollToTop: () => void,
|
||||||
prepareEdit: ({ }) => void,
|
prepareEdit: ({}) => void,
|
||||||
resetThumbnailStatus: () => void,
|
resetThumbnailStatus: () => void,
|
||||||
|
amountNeededForTakeover: ?number,
|
||||||
};
|
};
|
||||||
|
|
||||||
class PublishForm extends React.PureComponent<Props> {
|
class PublishForm extends React.PureComponent<Props> {
|
||||||
|
@ -84,6 +86,7 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
// If they are midway through a channel creation, treat it as anonymous until it completes
|
// If they are midway through a channel creation, treat it as anonymous until it completes
|
||||||
const channelName = channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW ? '' : channel;
|
const channelName = channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW ? '' : channel;
|
||||||
|
|
||||||
|
// We are only going to store the full uri, but we need to resolve the uri with and without the channel name
|
||||||
let uri;
|
let uri;
|
||||||
try {
|
try {
|
||||||
uri = buildURI({ contentName: name, channelName });
|
uri = buildURI({ contentName: name, channelName });
|
||||||
|
@ -92,6 +95,11 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri) {
|
if (uri) {
|
||||||
|
if (channelName) {
|
||||||
|
// resolve without the channel name so we know the winning bid for it
|
||||||
|
const uriLessChannel = buildURI({ contentName: name });
|
||||||
|
resolveUri(uriLessChannel);
|
||||||
|
}
|
||||||
resolveUri(uri);
|
resolveUri(uri);
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
@ -295,8 +303,9 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
{name && nameError && <div>{__('The URL you created is not valid')}</div>}
|
{name && nameError && <div>{__('The URL you created is not valid')}</div>}
|
||||||
{!bid && <div>{__('A bid amount is required')}</div>}
|
{!bid && <div>{__('A bid amount is required')}</div>}
|
||||||
{!!bid && bidError && <div>{bidError}</div>}
|
{!!bid && bidError && <div>{bidError}</div>}
|
||||||
{uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS
|
{uploadThumbnailStatus === THUMBNAIL_STATUSES.IN_PROGRESS && (
|
||||||
&& <div>{__('Please wait for thumbnail to finish uploading')}</div>}
|
<div>{__('Please wait for thumbnail to finish uploading')}</div>
|
||||||
|
)}
|
||||||
{!tosAccepted && <div>{__('You must agree to the terms of service')}</div>}
|
{!tosAccepted && <div>{__('You must agree to the terms of service')}</div>}
|
||||||
{!!editingURI &&
|
{!!editingURI &&
|
||||||
!isStillEditing &&
|
!isStillEditing &&
|
||||||
|
@ -338,6 +347,7 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
thumbnailPath,
|
thumbnailPath,
|
||||||
resetThumbnailStatus,
|
resetThumbnailStatus,
|
||||||
isStillEditing,
|
isStillEditing,
|
||||||
|
amountNeededForTakeover,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const formDisabled = (!filePath && !editingURI) || publishing;
|
const formDisabled = (!filePath && !editingURI) || publishing;
|
||||||
|
@ -350,19 +360,17 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
submitLabel = !publishing ? __('Publish') : __('Publishing...');
|
submitLabel = !publishing ? __('Publish') : __('Publishing...');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const shortUri = buildURI({ contentName: name });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form onSubmit={this.handlePublish}>
|
<Form onSubmit={this.handlePublish}>
|
||||||
<section className={classnames('card card--section', { 'card--disabled': publishing })}>
|
<section className={classnames('card card--section', { 'card--disabled': publishing })}>
|
||||||
<div className="card__title">{__('Content')}</div>
|
<div className="card__title">{__('Content')}</div>
|
||||||
<div className="card__subtitle">
|
<div className="card__subtitle">
|
||||||
{isStillEditing ? __('Editing a claim') : __('What are you publishing?')}
|
{isStillEditing ? __('Editing a claim') : __('What are you publishing?')}{' '}
|
||||||
{' '}{__(
|
{__('Read our')}{' '}
|
||||||
'Read our'
|
|
||||||
)}{' '}
|
|
||||||
<Button button="link" label={__('FAQ')} href="https://lbry.io/faq/how-to-publish" />{' '}
|
<Button button="link" label={__('FAQ')} href="https://lbry.io/faq/how-to-publish" />{' '}
|
||||||
{__(
|
{__('to learn more.')}
|
||||||
'to learn more.'
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{(filePath || !!editingURI) && (
|
{(filePath || !!editingURI) && (
|
||||||
<div className="card-media__internal-links">
|
<div className="card-media__internal-links">
|
||||||
|
@ -420,12 +428,12 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
{uploadThumbnailStatus === THUMBNAIL_STATUSES.API_DOWN ? (
|
{uploadThumbnailStatus === THUMBNAIL_STATUSES.API_DOWN ? (
|
||||||
__('Enter a URL for your thumbnail.')
|
__('Enter a URL for your thumbnail.')
|
||||||
) : (
|
) : (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{__('Upload your thumbnail (.png/.jpg/.jpeg/.gif) to')}{' '}
|
{__('Upload your thumbnail (.png/.jpg/.jpeg/.gif) to')}{' '}
|
||||||
<Button button="link" label={__('spee.ch')} href="https://spee.ch/about" />.{' '}
|
<Button button="link" label={__('spee.ch')} href="https://spee.ch/about" />.{' '}
|
||||||
{__('Recommended size: 800x450 (16:9)')}
|
{__('Recommended size: 800x450 (16:9)')}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<SelectThumbnail
|
<SelectThumbnail
|
||||||
thumbnailPath={thumbnailPath}
|
thumbnailPath={thumbnailPath}
|
||||||
|
@ -496,11 +504,12 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
<FormRow>
|
<FormRow>
|
||||||
<FormField
|
<FormField
|
||||||
stretch
|
stretch
|
||||||
|
label={__('Name')}
|
||||||
prefix={`lbry://${
|
prefix={`lbry://${
|
||||||
!channel || channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW
|
!channel || channel === CHANNEL_ANONYMOUS || channel === CHANNEL_NEW
|
||||||
? ''
|
? ''
|
||||||
: `${channel}/`
|
: `${channel}/`
|
||||||
}`}
|
}`}
|
||||||
type="text"
|
type="text"
|
||||||
name="content_name"
|
name="content_name"
|
||||||
placeholder="myname"
|
placeholder="myname"
|
||||||
|
@ -508,12 +517,9 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
onChange={event => this.handleNameChange(event.target.value)}
|
onChange={event => this.handleNameChange(event.target.value)}
|
||||||
error={nameError}
|
error={nameError}
|
||||||
helper={
|
helper={
|
||||||
<BidHelpText
|
<NameHelpText
|
||||||
isStillEditing={isStillEditing}
|
isStillEditing={isStillEditing}
|
||||||
uri={uri}
|
uri={uri}
|
||||||
editingURI={editingURI}
|
|
||||||
isResolvingUri={isResolvingUri}
|
|
||||||
winningBidForClaimUri={winningBidForClaimUri}
|
|
||||||
myClaimForUri={myClaimForUri}
|
myClaimForUri={myClaimForUri}
|
||||||
onEditMyClaim={this.editExistingClaim}
|
onEditMyClaim={this.editExistingClaim}
|
||||||
/>
|
/>
|
||||||
|
@ -534,8 +540,14 @@ class PublishForm extends React.PureComponent<Props> {
|
||||||
min="0"
|
min="0"
|
||||||
disabled={!name}
|
disabled={!name}
|
||||||
onChange={event => this.handleBidChange(parseFloat(event.target.value))}
|
onChange={event => this.handleBidChange(parseFloat(event.target.value))}
|
||||||
helper={__('This LBC remains yours and the deposit can be undone at any time.')}
|
|
||||||
placeholder={winningBidForClaimUri ? winningBidForClaimUri + 0.1 : 0.1}
|
placeholder={winningBidForClaimUri ? winningBidForClaimUri + 0.1 : 0.1}
|
||||||
|
helper={
|
||||||
|
<BidHelpText
|
||||||
|
uri={shortUri}
|
||||||
|
isResolvingUri={isResolvingUri}
|
||||||
|
amountNeededForTakeover={amountNeededForTakeover}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -3,9 +3,10 @@ import {
|
||||||
makeSelectClaimRewardError,
|
makeSelectClaimRewardError,
|
||||||
makeSelectRewardByType,
|
makeSelectRewardByType,
|
||||||
makeSelectIsRewardClaimPending,
|
makeSelectIsRewardClaimPending,
|
||||||
} from 'redux/selectors/rewards';
|
doClaimRewardType,
|
||||||
|
doClaimRewardClearError,
|
||||||
|
} from 'lbryinc';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { doClaimRewardType, doClaimRewardClearError } from 'redux/actions/rewards';
|
|
||||||
import RewardLink from './view';
|
import RewardLink from './view';
|
||||||
|
|
||||||
const makeSelect = () => {
|
const makeSelect = () => {
|
||||||
|
@ -23,9 +24,12 @@ const makeSelect = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
claimReward: reward => dispatch(doClaimRewardType(reward.reward_type, true)),
|
claimReward: reward => dispatch(doClaimRewardType(reward.reward_type)),
|
||||||
clearError: reward => dispatch(doClaimRewardClearError(reward)),
|
clearError: reward => dispatch(doClaimRewardClearError(reward)),
|
||||||
navigate: path => dispatch(doNavigate(path)),
|
navigate: path => dispatch(doNavigate(path)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(makeSelect, perform)(RewardLink);
|
export default connect(
|
||||||
|
makeSelect,
|
||||||
|
perform
|
||||||
|
)(RewardLink);
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectClaimedRewards } from 'redux/selectors/rewards';
|
import { selectClaimedRewards } from 'lbryinc';
|
||||||
import RewardListClaimed from './view';
|
import RewardListClaimed from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
rewards: selectClaimedRewards(state),
|
rewards: selectClaimedRewards(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, null)(RewardListClaimed);
|
export default connect(
|
||||||
|
select,
|
||||||
|
null
|
||||||
|
)(RewardListClaimed);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectUnclaimedRewardValue, selectFetchingRewards } from 'redux/selectors/rewards';
|
import { selectUnclaimedRewardValue, selectFetchingRewards, doRewardList } from 'lbryinc';
|
||||||
import { doRewardList } from 'redux/actions/rewards';
|
|
||||||
import { doFetchRewardedContent } from 'redux/actions/content';
|
import { doFetchRewardedContent } from 'redux/actions/content';
|
||||||
import RewardSummary from './view';
|
import RewardSummary from './view';
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import { MODALS, doNotify } from 'lbry-redux';
|
||||||
import RewardTile from './view';
|
import RewardTile from './view';
|
||||||
|
|
||||||
export default connect(null, null)(RewardTile);
|
const perform = dispatch => ({
|
||||||
|
openRewardCodeModal: () => dispatch(doNotify({ id: MODALS.REWARD_GENERATED_CODE })),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
null,
|
||||||
|
perform
|
||||||
|
)(RewardTile);
|
||||||
|
|
|
@ -3,10 +3,11 @@ import React from 'react';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
import RewardLink from 'component/rewardLink';
|
import RewardLink from 'component/rewardLink';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import rewards from 'rewards';
|
import { rewards } from 'lbryinc';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
openRewardCodeModal: () => void,
|
||||||
reward: {
|
reward: {
|
||||||
id: string,
|
id: string,
|
||||||
reward_title: string,
|
reward_title: string,
|
||||||
|
@ -19,7 +20,7 @@ type Props = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const RewardTile = (props: Props) => {
|
const RewardTile = (props: Props) => {
|
||||||
const { reward } = props;
|
const { reward, openRewardCodeModal } = props;
|
||||||
const claimed = !!reward.transaction_id;
|
const claimed = !!reward.transaction_id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -27,6 +28,9 @@ const RewardTile = (props: Props) => {
|
||||||
<div className="card__title">{reward.reward_title}</div>
|
<div className="card__title">{reward.reward_title}</div>
|
||||||
<div className="card__subtitle">{reward.reward_description}</div>
|
<div className="card__subtitle">{reward.reward_description}</div>
|
||||||
<div className="card__actions">
|
<div className="card__actions">
|
||||||
|
{reward.reward_type === rewards.TYPE_GENERATED_CODE && (
|
||||||
|
<Button button="primary" onClick={openRewardCodeModal} label={__('Enter Code')} />
|
||||||
|
)}
|
||||||
{reward.reward_type === rewards.TYPE_REFERRAL && (
|
{reward.reward_type === rewards.TYPE_REFERRAL && (
|
||||||
<Button button="primary" navigate="/invite" label={__('Go To Invites')} />
|
<Button button="primary" navigate="/invite" label={__('Go To Invites')} />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import InvitePage from 'page/invite';
|
||||||
import BackupPage from 'page/backup';
|
import BackupPage from 'page/backup';
|
||||||
import SubscriptionsPage from 'page/subscriptions';
|
import SubscriptionsPage from 'page/subscriptions';
|
||||||
import SearchPage from 'page/search';
|
import SearchPage from 'page/search';
|
||||||
|
import UserHistoryPage from 'page/userHistory';
|
||||||
|
|
||||||
const route = (props, page, routesMap) => {
|
const route = (props, page, routesMap) => {
|
||||||
const component = routesMap[page];
|
const component = routesMap[page];
|
||||||
|
@ -53,6 +54,7 @@ const Router = props => {
|
||||||
wallet: <WalletPage params={params} />,
|
wallet: <WalletPage params={params} />,
|
||||||
subscriptions: <SubscriptionsPage params={params} />,
|
subscriptions: <SubscriptionsPage params={params} />,
|
||||||
search: <SearchPage {...params} />,
|
search: <SearchPage {...params} />,
|
||||||
|
user_history: <UserHistoryPage {...params} />,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -55,22 +55,34 @@ class SelectThumbnail extends React.PureComponent<Props, State> {
|
||||||
const thumbnailSrc =
|
const thumbnailSrc =
|
||||||
!thumbnail || thumbnailError ? Native.imagePath(thumbnailErrorImage) : thumbnail;
|
!thumbnail || thumbnailError ? Native.imagePath(thumbnailErrorImage) : thumbnail;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note:
|
||||||
|
We are using backgroundImage instead of an <img /> to zoom if the selected thumbnail isn't
|
||||||
|
the proper aspect ratio. This is to avoid blackbars on the side of images and inconsistent thumbnails
|
||||||
|
We still need to render the image to see if there is an error loading the url
|
||||||
|
*/
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
{status === THUMBNAIL_STATUSES.API_DOWN || status === THUMBNAIL_STATUSES.MANUAL ? (
|
{status === THUMBNAIL_STATUSES.API_DOWN || status === THUMBNAIL_STATUSES.MANUAL ? (
|
||||||
<div className="column">
|
<div className="column">
|
||||||
<img
|
<div
|
||||||
src={thumbnailSrc}
|
className="column__item thumbnail-preview card__media"
|
||||||
className="column__item thumbnail-preview"
|
style={{ backgroundImage: `url(${thumbnailSrc})` }}
|
||||||
alt={__('Thumbnail Preview')}
|
>
|
||||||
onError={() => {
|
<img
|
||||||
this.setState({
|
style={{ display: 'none' }}
|
||||||
thumbnailError: true,
|
src={thumbnailSrc}
|
||||||
thumbnailErrorImage:
|
alt={__('Thumbnail Preview')}
|
||||||
thumbnail && thumbnail.length > 0 ? 'broken.png' : 'no-thumbnail.png',
|
onError={() => {
|
||||||
});
|
this.setState({
|
||||||
}}
|
thumbnailError: true,
|
||||||
/>
|
thumbnailErrorImage:
|
||||||
|
thumbnail && thumbnail.length > 0 ? 'broken.png' : 'no-thumbnail.png',
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className="column__item">
|
<div className="column__item">
|
||||||
<FormField
|
<FormField
|
||||||
className="input--thumbnail"
|
className="input--thumbnail"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectNavLinks } from 'lbry-redux';
|
import { selectNavLinks } from 'redux/selectors/app';
|
||||||
import { selectNotifications } from 'redux/selectors/subscriptions';
|
import { selectNotifications } from 'redux/selectors/subscriptions';
|
||||||
import SideBar from './view';
|
import SideBar from './view';
|
||||||
|
|
||||||
|
|
9
src/renderer/component/socialShare/index.js
Normal file
9
src/renderer/component/socialShare/index.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { makeSelectClaimForUri } from 'lbry-redux';
|
||||||
|
import SocialShare from './view';
|
||||||
|
|
||||||
|
const select = (state, props) => ({
|
||||||
|
claim: makeSelectClaimForUri(props.uri)(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(select)(SocialShare);
|
79
src/renderer/component/socialShare/view.jsx
Normal file
79
src/renderer/component/socialShare/view.jsx
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import type { Claim } from 'types/claim';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import * as icons from 'constants/icons';
|
||||||
|
import Tooltip from 'component/common/tooltip';
|
||||||
|
import Address from 'component/address';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
claim: Claim,
|
||||||
|
onDone: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class SocialShare extends React.PureComponent<Props> {
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.input = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
input: ?HTMLInputElement;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
claim_id: claimId,
|
||||||
|
name: claimName,
|
||||||
|
channel_name: channelName,
|
||||||
|
value,
|
||||||
|
} = this.props.claim;
|
||||||
|
const channelClaimId =
|
||||||
|
value && value.publisherSignature && value.publisherSignature.certificateId;
|
||||||
|
const { onDone } = this.props;
|
||||||
|
const speechPrefix = 'http://spee.ch/';
|
||||||
|
const speechURL =
|
||||||
|
channelName && channelClaimId
|
||||||
|
? `${speechPrefix}${channelName}:${channelClaimId}/${claimName}`
|
||||||
|
: `${speechPrefix}${claimName}#${claimId}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="card__content">
|
||||||
|
<Address address={speechURL} noSnackbar />
|
||||||
|
<div className="card__actions card__actions--center">
|
||||||
|
<Tooltip onComponent body={__('Facebook')}>
|
||||||
|
<Button
|
||||||
|
iconColor="blue"
|
||||||
|
icon={icons.FACEBOOK}
|
||||||
|
button="alt"
|
||||||
|
label={__('')}
|
||||||
|
href={`https://facebook.com/sharer/sharer.php?u=${speechURL}`}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip onComponent body={__('Twitter')}>
|
||||||
|
<Button
|
||||||
|
iconColor="blue"
|
||||||
|
icon={icons.TWITTER}
|
||||||
|
button="alt"
|
||||||
|
label={__('')}
|
||||||
|
href={`https://twitter.com/home?status=${speechURL}`}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip onComponent body={__('View on Spee.ch')}>
|
||||||
|
<Button
|
||||||
|
icon={icons.GLOBE}
|
||||||
|
iconColor="blue"
|
||||||
|
button="alt"
|
||||||
|
label={__('')}
|
||||||
|
href={`${speechURL}`}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<div className="card__actions">
|
||||||
|
<Button button="link" label={__('Done')} onClick={onDone} />
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SocialShare;
|
|
@ -1,8 +1,7 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectClaimedRewardsByTransactionId } from 'redux/selectors/rewards';
|
import { selectClaimedRewardsByTransactionId } from 'lbryinc';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { doNotify } from 'lbry-redux';
|
import { selectAllMyClaimsByOutpoint, doNotify } from 'lbry-redux';
|
||||||
import { selectAllMyClaimsByOutpoint } from 'lbry-redux';
|
|
||||||
import TransactionList from './view';
|
import TransactionList from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -15,4 +14,7 @@ const perform = dispatch => ({
|
||||||
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
openModal: (modal, props) => dispatch(doNotify(modal, props)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(TransactionList);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(TransactionList);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doUserEmailNew, doUserInviteNew } from 'redux/actions/user';
|
import { selectEmailNewIsPending, selectEmailNewErrorMessage, doUserEmailNew } from 'lbryinc';
|
||||||
import { selectEmailNewIsPending, selectEmailNewErrorMessage } from 'redux/selectors/user';
|
|
||||||
import UserEmailNew from './view';
|
import UserEmailNew from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -13,4 +11,7 @@ const perform = dispatch => ({
|
||||||
addUserEmail: email => dispatch(doUserEmailNew(email)),
|
addUserEmail: email => dispatch(doUserEmailNew(email)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(UserEmailNew);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(UserEmailNew);
|
||||||
|
|
|
@ -47,7 +47,7 @@ class UserEmailNew extends React.PureComponent<Props, State> {
|
||||||
</p>
|
</p>
|
||||||
<p>{__("We'll never sell your email, and you can unsubscribe at any time.")}</p>
|
<p>{__("We'll never sell your email, and you can unsubscribe at any time.")}</p>
|
||||||
<Form onSubmit={this.handleSubmit}>
|
<Form onSubmit={this.handleSubmit}>
|
||||||
<FormRow>
|
<FormRow padded>
|
||||||
<FormField
|
<FormField
|
||||||
stretch
|
stretch
|
||||||
type="email"
|
type="email"
|
||||||
|
@ -63,6 +63,9 @@ class UserEmailNew extends React.PureComponent<Props, State> {
|
||||||
<Submit label="Submit" disabled={isPending} />
|
<Submit label="Submit" disabled={isPending} />
|
||||||
{cancelButton}
|
{cancelButton}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="card__content help">
|
||||||
|
{`${__('Your email may be used to sync usage data across devices.')} `}
|
||||||
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import {
|
|
||||||
doUserEmailVerify,
|
|
||||||
doUserEmailVerifyFailure,
|
|
||||||
doUserResendVerificationEmail,
|
|
||||||
} from 'redux/actions/user';
|
|
||||||
import {
|
import {
|
||||||
selectEmailVerifyIsPending,
|
selectEmailVerifyIsPending,
|
||||||
selectEmailToVerify,
|
selectEmailToVerify,
|
||||||
selectEmailVerifyErrorMessage,
|
selectEmailVerifyErrorMessage,
|
||||||
} from 'redux/selectors/user';
|
doUserEmailVerify,
|
||||||
|
doUserEmailVerifyFailure,
|
||||||
|
doUserResendVerificationEmail,
|
||||||
|
} from 'lbryinc';
|
||||||
import UserEmailVerify from './view';
|
import UserEmailVerify from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -23,4 +21,7 @@ const perform = dispatch => ({
|
||||||
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)),
|
resendVerificationEmail: email => dispatch(doUserResendVerificationEmail(email)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(UserEmailVerify);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(UserEmailVerify);
|
||||||
|
|
|
@ -56,7 +56,7 @@ class UserEmailVerify extends React.PureComponent<Props, State> {
|
||||||
return (
|
return (
|
||||||
<Form onSubmit={this.handleSubmit}>
|
<Form onSubmit={this.handleSubmit}>
|
||||||
<p>Please enter the verification code emailed to {email}.</p>
|
<p>Please enter the verification code emailed to {email}.</p>
|
||||||
<FormRow>
|
<FormRow padded>
|
||||||
<FormField
|
<FormField
|
||||||
stretch
|
stretch
|
||||||
name="code"
|
name="code"
|
||||||
|
|
27
src/renderer/component/userHistory/index.js
Normal file
27
src/renderer/component/userHistory/index.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { selectHistoryPageCount, makeSelectHistoryForPage } from 'redux/selectors/content';
|
||||||
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
|
import { selectCurrentParams, makeSelectCurrentParam } from 'lbry-redux';
|
||||||
|
import { doClearContentHistoryUri } from 'redux/actions/content';
|
||||||
|
import UserHistory from './view';
|
||||||
|
|
||||||
|
const select = state => {
|
||||||
|
const paramPage = Number(makeSelectCurrentParam('page')(state) || 0);
|
||||||
|
return {
|
||||||
|
pageCount: selectHistoryPageCount(state),
|
||||||
|
page: paramPage,
|
||||||
|
params: selectCurrentParams(state),
|
||||||
|
history: makeSelectHistoryForPage(paramPage)(state),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
navigate: (path, params) => dispatch(doNavigate(path, params)),
|
||||||
|
clearHistoryUri: uri => dispatch(doClearContentHistoryUri(uri)),
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(UserHistory);
|
167
src/renderer/component/userHistory/view.jsx
Normal file
167
src/renderer/component/userHistory/view.jsx
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
// @flow
|
||||||
|
import * as React from 'react';
|
||||||
|
import Button from 'component/button';
|
||||||
|
import { FormField, FormRow } from 'component/common/form';
|
||||||
|
import ReactPaginate from 'react-paginate';
|
||||||
|
import UserHistoryItem from 'component/userHistoryItem';
|
||||||
|
|
||||||
|
type HistoryItem = {
|
||||||
|
uri: string,
|
||||||
|
lastViewed: number,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
history: Array<HistoryItem>,
|
||||||
|
page: number,
|
||||||
|
pageCount: number,
|
||||||
|
navigate: (string, {}) => void,
|
||||||
|
clearHistoryUri: string => void,
|
||||||
|
params: { page: number },
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
itemsSelected: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
class UserHistoryPage extends React.PureComponent<Props, State> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
itemsSelected: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
(this: any).selectAll = this.selectAll.bind(this);
|
||||||
|
(this: any).unselectAll = this.unselectAll.bind(this);
|
||||||
|
(this: any).removeSelected = this.removeSelected.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSelect(uri: string) {
|
||||||
|
const { itemsSelected } = this.state;
|
||||||
|
|
||||||
|
const newItemsSelected = { ...itemsSelected };
|
||||||
|
if (itemsSelected[uri]) {
|
||||||
|
delete newItemsSelected[uri];
|
||||||
|
} else {
|
||||||
|
newItemsSelected[uri] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
itemsSelected: { ...newItemsSelected },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
changePage(pageNumber: number) {
|
||||||
|
const { params } = this.props;
|
||||||
|
const newParams = { ...params, page: pageNumber };
|
||||||
|
this.props.navigate('/user_history', newParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
paginate(e: SyntheticKeyboardEvent<*>) {
|
||||||
|
const pageFromInput = Number(e.currentTarget.value);
|
||||||
|
if (
|
||||||
|
pageFromInput &&
|
||||||
|
e.keyCode === 13 &&
|
||||||
|
!Number.isNaN(pageFromInput) &&
|
||||||
|
pageFromInput > 0 &&
|
||||||
|
pageFromInput <= this.props.pageCount
|
||||||
|
) {
|
||||||
|
this.changePage(pageFromInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectAll() {
|
||||||
|
const { history } = this.props;
|
||||||
|
const newSelectedState = {};
|
||||||
|
history.forEach(({ uri }) => (newSelectedState[uri] = true));
|
||||||
|
this.setState({ itemsSelected: newSelectedState });
|
||||||
|
}
|
||||||
|
|
||||||
|
unselectAll() {
|
||||||
|
this.setState({
|
||||||
|
itemsSelected: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
removeSelected() {
|
||||||
|
const { clearHistoryUri } = this.props;
|
||||||
|
const { itemsSelected } = this.state;
|
||||||
|
|
||||||
|
Object.keys(itemsSelected).forEach(uri => clearHistoryUri(uri));
|
||||||
|
this.setState({
|
||||||
|
itemsSelected: {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { history, page, pageCount } = this.props;
|
||||||
|
const { itemsSelected } = this.state;
|
||||||
|
|
||||||
|
const allSelected = Object.keys(itemsSelected).length === history.length;
|
||||||
|
const selectHandler = allSelected ? this.unselectAll : this.selectAll;
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div className="card__actions card__actions--between">
|
||||||
|
{Object.keys(itemsSelected).length ? (
|
||||||
|
<Button button="link" label={__('Delete')} onClick={this.removeSelected} />
|
||||||
|
) : (
|
||||||
|
<span>
|
||||||
|
{/* Using an empty span so spacing stays the same if the button isn't rendered */}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
button="link"
|
||||||
|
label={allSelected ? __('Cancel') : __('Select All')}
|
||||||
|
onClick={selectHandler}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{!!history.length && (
|
||||||
|
<table className="card--section table table--stretch table--history">
|
||||||
|
<tbody>
|
||||||
|
{history.map(item => (
|
||||||
|
<UserHistoryItem
|
||||||
|
key={item.uri}
|
||||||
|
uri={item.uri}
|
||||||
|
lastViewed={item.lastViewed}
|
||||||
|
selected={!!itemsSelected[item.uri]}
|
||||||
|
onSelect={() => {
|
||||||
|
this.onSelect(item.uri);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)}
|
||||||
|
{pageCount > 1 && (
|
||||||
|
<FormRow padded verticallyCentered centered>
|
||||||
|
<ReactPaginate
|
||||||
|
pageCount={pageCount}
|
||||||
|
pageRangeDisplayed={2}
|
||||||
|
previousLabel="‹"
|
||||||
|
nextLabel="›"
|
||||||
|
activeClassName="pagination__item--selected"
|
||||||
|
pageClassName="pagination__item"
|
||||||
|
previousClassName="pagination__item pagination__item--previous"
|
||||||
|
nextClassName="pagination__item pagination__item--next"
|
||||||
|
breakClassName="pagination__item pagination__item--break"
|
||||||
|
marginPagesDisplayed={2}
|
||||||
|
onPageChange={e => this.changePage(e.selected)}
|
||||||
|
forcePage={page}
|
||||||
|
initialPage={page}
|
||||||
|
containerClassName="pagination"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
className="paginate-channel"
|
||||||
|
onKeyUp={e => this.paginate(e)}
|
||||||
|
prefix={__('Go to page:')}
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
</FormRow>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default UserHistoryPage;
|
16
src/renderer/component/userHistoryItem/index.js
Normal file
16
src/renderer/component/userHistoryItem/index.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doResolveUri, makeSelectClaimForUri } from 'lbry-redux';
|
||||||
|
import UserHistoryItem from './view';
|
||||||
|
|
||||||
|
const select = (state, props) => ({
|
||||||
|
claim: makeSelectClaimForUri(props.uri)(state),
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
resolveUri: uri => dispatch(doResolveUri(uri)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(UserHistoryItem);
|
64
src/renderer/component/userHistoryItem/view.jsx
Normal file
64
src/renderer/component/userHistoryItem/view.jsx
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import type { Claim } from 'types/claim';
|
||||||
|
import moment from 'moment';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import Button from 'component/button';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
lastViewed: number,
|
||||||
|
uri: string,
|
||||||
|
claim: ?Claim,
|
||||||
|
selected: boolean,
|
||||||
|
onSelect: () => void,
|
||||||
|
resolveUri: string => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class UserHistoryItem extends React.PureComponent<Props> {
|
||||||
|
componentDidMount() {
|
||||||
|
const { claim, uri, resolveUri } = this.props;
|
||||||
|
|
||||||
|
if (!claim) {
|
||||||
|
resolveUri(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { lastViewed, selected, onSelect, claim } = this.props;
|
||||||
|
|
||||||
|
let name;
|
||||||
|
let title;
|
||||||
|
let uri;
|
||||||
|
if (claim && claim.value && claim.value.stream) {
|
||||||
|
({ name } = claim);
|
||||||
|
({ title } = claim.value.stream.metadata);
|
||||||
|
uri = claim.permanent_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr
|
||||||
|
onClick={onSelect}
|
||||||
|
className={classnames({
|
||||||
|
history__selected: selected,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<td>
|
||||||
|
<input checked={selected} type="checkbox" onClick={onSelect} />
|
||||||
|
</td>
|
||||||
|
<td>{moment(lastViewed).from(moment())}</td>
|
||||||
|
<td>{title}</td>
|
||||||
|
<td>
|
||||||
|
<Button
|
||||||
|
tourniquet
|
||||||
|
button="link"
|
||||||
|
label={name ? `lbry://${name}` : `lbry://...`}
|
||||||
|
navigate="/show"
|
||||||
|
navigateParams={{ uri }}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserHistoryItem;
|
|
@ -1,7 +1,5 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doUserPhoneNew } from 'redux/actions/user';
|
import { selectPhoneNewErrorMessage, doUserPhoneNew } from 'lbryinc';
|
||||||
import { selectPhoneNewErrorMessage } from 'redux/selectors/user';
|
|
||||||
import UserPhoneNew from './view';
|
import UserPhoneNew from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -9,7 +7,10 @@ const select = state => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
addUserPhone: (phone, country_code) => dispatch(doUserPhoneNew(phone, country_code)),
|
addUserPhone: (phone, countryCode) => dispatch(doUserPhoneNew(phone, countryCode)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(UserPhoneNew);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(UserPhoneNew);
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import React from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doUserPhoneVerify, doUserPhoneReset } from 'redux/actions/user';
|
|
||||||
import {
|
import {
|
||||||
|
doUserPhoneVerify,
|
||||||
|
doUserPhoneReset,
|
||||||
selectPhoneToVerify,
|
selectPhoneToVerify,
|
||||||
selectPhoneVerifyErrorMessage,
|
selectPhoneVerifyErrorMessage,
|
||||||
selectUserCountryCode,
|
selectUserCountryCode,
|
||||||
} from 'redux/selectors/user';
|
} from 'lbryinc';
|
||||||
import UserPhoneVerify from './view';
|
import UserPhoneVerify from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -19,4 +19,7 @@ const perform = dispatch => ({
|
||||||
verifyUserPhone: code => dispatch(doUserPhoneVerify(code)),
|
verifyUserPhone: code => dispatch(doUserPhoneVerify(code)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(UserPhoneVerify);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(UserPhoneVerify);
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doNotify, MODALS } from 'lbry-redux';
|
import { doNotify, MODALS } from 'lbry-redux';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { doUserIdentityVerify } from 'redux/actions/user';
|
|
||||||
import rewards from 'rewards';
|
|
||||||
import { makeSelectRewardByType } from 'redux/selectors/rewards';
|
|
||||||
import {
|
import {
|
||||||
|
doUserIdentityVerify,
|
||||||
|
rewards,
|
||||||
|
makeSelectRewardByType,
|
||||||
selectIdentityVerifyIsPending,
|
selectIdentityVerifyIsPending,
|
||||||
selectIdentityVerifyErrorMessage,
|
selectIdentityVerifyErrorMessage,
|
||||||
} from 'redux/selectors/user';
|
} from 'lbryinc';
|
||||||
import UserVerify from './view';
|
import UserVerify from './view';
|
||||||
|
|
||||||
const select = state => {
|
const select = state => {
|
||||||
|
@ -26,4 +26,7 @@ const perform = dispatch => ({
|
||||||
verifyPhone: () => dispatch(doNotify({ id: MODALS.PHONE_COLLECTION })),
|
verifyPhone: () => dispatch(doNotify({ id: MODALS.PHONE_COLLECTION })),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(UserVerify);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(UserVerify);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import CardVerify from 'component/cardVerify';
|
import CardVerify from 'component/cardVerify';
|
||||||
import lbryio from 'lbryio';
|
import Lbryio from 'lbryinc';
|
||||||
import * as icons from 'constants/icons';
|
import * as icons from 'constants/icons';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -51,7 +51,7 @@ class UserVerify extends React.PureComponent<Props> {
|
||||||
label={__('Perform Card Verification')}
|
label={__('Perform Card Verification')}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
token={this.onToken}
|
token={this.onToken}
|
||||||
stripeKey={lbryio.getStripeToken()}
|
stripeKey={Lbryio.getStripeToken()}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import { FormField } from 'component/common/form';
|
import { FormField } from 'component/common/form';
|
||||||
import UriIndicator from 'component/uriIndicator';
|
|
||||||
import type { Claim } from 'types/claim';
|
import type { Claim } from 'types/claim';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -18,7 +17,7 @@ type Props = {
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
tipAmount: number,
|
tipAmount: number,
|
||||||
newTipError: string,
|
tipError: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
class WalletSendTip extends React.PureComponent<Props, State> {
|
class WalletSendTip extends React.PureComponent<Props, State> {
|
||||||
|
@ -27,9 +26,8 @@ class WalletSendTip extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
tipAmount: 0,
|
tipAmount: 0,
|
||||||
newTipError: '',
|
tipError: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
(this: any).handleSendButtonClicked = this.handleSendButtonClicked.bind(this);
|
(this: any).handleSendButtonClicked = this.handleSendButtonClicked.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,65 +46,68 @@ class WalletSendTip extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
handleSupportPriceChange(event: SyntheticInputEvent<*>) {
|
handleSupportPriceChange(event: SyntheticInputEvent<*>) {
|
||||||
const { balance } = this.props;
|
const { balance } = this.props;
|
||||||
|
const regexp = RegExp(/^(\d*([.]\d{0,8})?)$/);
|
||||||
|
const validTipInput = regexp.test(event.target.value);
|
||||||
const tipAmount = parseFloat(event.target.value);
|
const tipAmount = parseFloat(event.target.value);
|
||||||
let newTipError;
|
let tipError;
|
||||||
if (tipAmount === balance) {
|
|
||||||
newTipError = __('Please decrease your tip to account for transaction fees');
|
if (!tipAmount) {
|
||||||
|
tipError = __('Tip must be a number');
|
||||||
|
} else if (tipAmount <= 0) {
|
||||||
|
tipError = __('Tip must be a positive number');
|
||||||
|
} else if (!validTipInput) {
|
||||||
|
tipError = __('Tip must have no more than 8 decimal places');
|
||||||
|
} else if (tipAmount === balance) {
|
||||||
|
tipError = __('Please decrease your tip to account for transaction fees');
|
||||||
} else if (tipAmount > balance) {
|
} else if (tipAmount > balance) {
|
||||||
newTipError = __('Not enough credits');
|
tipError = __('Not enough credits');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
tipAmount,
|
tipAmount,
|
||||||
newTipError,
|
tipError,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { title, isPending, uri, onCancel, balance } = this.props;
|
const { title, isPending, uri, onCancel } = this.props;
|
||||||
const { tipAmount, newTipError } = this.state;
|
const { tipAmount, tipError } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<section className="card__content">
|
||||||
<div className="card__title">
|
<FormField
|
||||||
<h1>
|
autoFocus
|
||||||
{__('Send a tip to')} <UriIndicator uri={uri} />
|
label={
|
||||||
</h1>
|
(tipAmount &&
|
||||||
</div>
|
tipAmount !== 0 &&
|
||||||
<div className="card__content">
|
`Tip ${tipAmount.toFixed(8).replace(/\.?0+$/, '')} LBC`) ||
|
||||||
<FormField
|
__('Amount')
|
||||||
label={__('Amount')}
|
}
|
||||||
postfix={__('LBC')}
|
postfix={__('LBC')}
|
||||||
className="input--price-amount"
|
className="input--price-amount"
|
||||||
error={newTipError}
|
error={tipError}
|
||||||
min="0"
|
min="0"
|
||||||
step="any"
|
step="any"
|
||||||
type="number"
|
type="number"
|
||||||
placeholder="1.23"
|
placeholder="1.23"
|
||||||
onChange={event => this.handleSupportPriceChange(event)}
|
onChange={event => this.handleSupportPriceChange(event)}
|
||||||
helper={
|
helper={
|
||||||
<span>
|
<span>
|
||||||
{__(`This will appear as a tip for ${title} located at ${uri}.`)}{' '}
|
{__(`This will appear as a tip for "${title}".`)}{' '}
|
||||||
<Button label={__('Learn more')} button="link" href="https://lbry.io/faq/tipping" />
|
<Button label={__('Learn more')} button="link" href="https://lbry.io/faq/tipping" />
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
/>
|
||||||
|
<div className="card__actions">
|
||||||
|
<Button
|
||||||
|
button="primary"
|
||||||
|
label={__('Send')}
|
||||||
|
disabled={isPending || tipError}
|
||||||
|
onClick={this.handleSendButtonClicked}
|
||||||
/>
|
/>
|
||||||
<div className="card__actions">
|
<Button button="link" label={__('Cancel')} onClick={onCancel} navigateParams={{ uri }} />
|
||||||
<Button
|
|
||||||
button="primary"
|
|
||||||
label={__('Send')}
|
|
||||||
disabled={isPending || tipAmount <= 0 || tipAmount > balance || tipAmount === balance}
|
|
||||||
onClick={this.handleSendButtonClicked}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
button="link"
|
|
||||||
label={__('Cancel')}
|
|
||||||
onClick={onCancel}
|
|
||||||
navigateParams={{ uri }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,11 @@ export const CREATE_CHANNEL_COMPLETED = 'CREATE_CHANNEL_COMPLETED';
|
||||||
export const PUBLISH_STARTED = 'PUBLISH_STARTED';
|
export const PUBLISH_STARTED = 'PUBLISH_STARTED';
|
||||||
export const PUBLISH_COMPLETED = 'PUBLISH_COMPLETED';
|
export const PUBLISH_COMPLETED = 'PUBLISH_COMPLETED';
|
||||||
export const PUBLISH_FAILED = 'PUBLISH_FAILED';
|
export const PUBLISH_FAILED = 'PUBLISH_FAILED';
|
||||||
export const SET_PLAYING_URI = 'PLAY_URI';
|
export const SET_PLAYING_URI = 'SET_PLAYING_URI';
|
||||||
|
export const SET_CONTENT_POSITION = 'SET_CONTENT_POSITION';
|
||||||
|
export const SET_CONTENT_LAST_VIEWED = 'SET_CONTENT_LAST_VIEWED';
|
||||||
|
export const CLEAR_CONTENT_HISTORY_URI = 'CLEAR_CONTENT_HISTORY_URI';
|
||||||
|
export const CLEAR_CONTENT_HISTORY_ALL = 'CLEAR_CONTENT_HISTORY_ALL';
|
||||||
|
|
||||||
// Files
|
// Files
|
||||||
export const FILE_LIST_STARTED = 'FILE_LIST_STARTED';
|
export const FILE_LIST_STARTED = 'FILE_LIST_STARTED';
|
||||||
|
@ -181,14 +185,6 @@ export const FETCH_SUBSCRIPTIONS_START = 'FETCH_SUBSCRIPTIONS_START';
|
||||||
export const FETCH_SUBSCRIPTIONS_FAIL = 'FETCH_SUBSCRIPTIONS_FAIL';
|
export const FETCH_SUBSCRIPTIONS_FAIL = 'FETCH_SUBSCRIPTIONS_FAIL';
|
||||||
export const FETCH_SUBSCRIPTIONS_SUCCESS = 'FETCH_SUBSCRIPTIONS_SUCCESS';
|
export const FETCH_SUBSCRIPTIONS_SUCCESS = 'FETCH_SUBSCRIPTIONS_SUCCESS';
|
||||||
|
|
||||||
// Video controls
|
|
||||||
export const SET_VIDEO_PAUSE = 'SET_VIDEO_PAUSE';
|
|
||||||
|
|
||||||
// Media controls
|
|
||||||
export const MEDIA_PLAY = 'MEDIA_PLAY';
|
|
||||||
export const MEDIA_PAUSE = 'MEDIA_PAUSE';
|
|
||||||
export const MEDIA_POSITION = 'MEDIA_POSITION';
|
|
||||||
|
|
||||||
// Publishing
|
// Publishing
|
||||||
export const CLEAR_PUBLISH = 'CLEAR_PUBLISH';
|
export const CLEAR_PUBLISH = 'CLEAR_PUBLISH';
|
||||||
export const UPDATE_PUBLISH_FORM = 'UPDATE_PUBLISH_FORM';
|
export const UPDATE_PUBLISH_FORM = 'UPDATE_PUBLISH_FORM';
|
||||||
|
|
1
src/renderer/constants/content.js
Normal file
1
src/renderer/constants/content.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const HISTORY_ITEMS_PER_PAGE = 50;
|
|
@ -30,3 +30,5 @@ export const EXTERNAL_LINK = 'ExternalLink';
|
||||||
export const GIFT = 'Gift';
|
export const GIFT = 'Gift';
|
||||||
export const EYE = 'Eye';
|
export const EYE = 'Eye';
|
||||||
export const PLAY = 'Play';
|
export const PLAY = 'Play';
|
||||||
|
export const FACEBOOK = 'Facebook';
|
||||||
|
export const TWITTER = 'Twitter';
|
||||||
|
|
|
@ -11,9 +11,10 @@ import { doConditionalAuthNavigate, doDaemonReady, doAutoUpdate } from 'redux/ac
|
||||||
import { doNotify, doBlackListedOutpointsSubscribe, isURIValid } from 'lbry-redux';
|
import { doNotify, doBlackListedOutpointsSubscribe, isURIValid } from 'lbry-redux';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings';
|
import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings';
|
||||||
import { doUserEmailVerify, doAuthenticate } from 'redux/actions/user';
|
import { doUserEmailVerify, doAuthenticate, Lbryio } from 'lbryinc';
|
||||||
import 'scss/all.scss';
|
import 'scss/all.scss';
|
||||||
import store from 'store';
|
import store from 'store';
|
||||||
|
import pjson from 'package.json';
|
||||||
import app from './app';
|
import app from './app';
|
||||||
import analytics from './analytics';
|
import analytics from './analytics';
|
||||||
import doLogWarningConsoleMessage from './logWarningConsoleMessage';
|
import doLogWarningConsoleMessage from './logWarningConsoleMessage';
|
||||||
|
@ -23,6 +24,40 @@ const APPPAGEURL = 'lbry://?';
|
||||||
|
|
||||||
autoUpdater.logger = remote.require('electron-log');
|
autoUpdater.logger = remote.require('electron-log');
|
||||||
|
|
||||||
|
// We need to override Lbryio for getting/setting the authToken
|
||||||
|
// We interect with ipcRenderer to get the auth key from a users keyring
|
||||||
|
Lbryio.setOverride('setAuthToken', status => {
|
||||||
|
Lbryio.call(
|
||||||
|
'user',
|
||||||
|
'new',
|
||||||
|
{
|
||||||
|
auth_token: '',
|
||||||
|
language: 'en',
|
||||||
|
app_id: status.installation_id,
|
||||||
|
},
|
||||||
|
'post'
|
||||||
|
).then(response => {
|
||||||
|
if (!response.auth_token) {
|
||||||
|
throw new Error(__('auth_token is missing from response'));
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcRenderer.send('set-auth-token', response.auth_token);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Lbryio.setOverride(
|
||||||
|
'getAuthToken',
|
||||||
|
() =>
|
||||||
|
new Promise(resolve => {
|
||||||
|
ipcRenderer.once('auth-token-response', (event, token) => {
|
||||||
|
Lbryio.authToken = token;
|
||||||
|
resolve(token);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.send('get-auth-token');
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
|
ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
|
||||||
if (uri && uri.startsWith('lbry://')) {
|
if (uri && uri.startsWith('lbry://')) {
|
||||||
if (uri.startsWith('lbry://?verify=')) {
|
if (uri.startsWith('lbry://?verify=')) {
|
||||||
|
@ -156,7 +191,7 @@ const init = () => {
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<SplashScreen
|
<SplashScreen
|
||||||
authenticate={() => app.store.dispatch(doAuthenticate())}
|
authenticate={() => app.store.dispatch(doAuthenticate(pjson.version))}
|
||||||
onReadyToLaunch={onDaemonReady}
|
onReadyToLaunch={onDaemonReady}
|
||||||
/>
|
/>
|
||||||
</Provider>,
|
</Provider>,
|
||||||
|
|
|
@ -1,155 +0,0 @@
|
||||||
import { ipcRenderer } from 'electron';
|
|
||||||
import { Lbry } from 'lbry-redux';
|
|
||||||
import querystring from 'querystring';
|
|
||||||
|
|
||||||
const Lbryio = {
|
|
||||||
enabled: true,
|
|
||||||
authenticationPromise: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
const CONNECTION_STRING = process.env.LBRY_APP_API_URL
|
|
||||||
? process.env.LBRY_APP_API_URL.replace(/\/*$/, '/') // exactly one slash at the end
|
|
||||||
: 'https://api.lbry.io/';
|
|
||||||
|
|
||||||
Lbryio.call = (resource, action, params = {}, method = 'get') => {
|
|
||||||
if (!Lbryio.enabled) {
|
|
||||||
console.log(__('Internal API disabled'));
|
|
||||||
return Promise.reject(new Error(__('LBRY internal API is disabled')));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(method === 'get' || method === 'post')) {
|
|
||||||
return Promise.reject(new Error(__('Invalid method')));
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkAndParse(response) {
|
|
||||||
if (response.status >= 200 && response.status < 300) {
|
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
return response.json().then(json => {
|
|
||||||
let error;
|
|
||||||
if (json.error) {
|
|
||||||
error = new Error(json.error);
|
|
||||||
} else {
|
|
||||||
error = new Error('Unknown API error signature');
|
|
||||||
}
|
|
||||||
error.response = response; // This is primarily a hack used in actions/user.js
|
|
||||||
return Promise.reject(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeRequest(url, options) {
|
|
||||||
return fetch(url, options).then(checkAndParse);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Lbryio.getAuthToken().then(token => {
|
|
||||||
const fullParams = { auth_token: token, ...params };
|
|
||||||
const qs = querystring.stringify(fullParams);
|
|
||||||
let url = `${CONNECTION_STRING}${resource}/${action}?${qs}`;
|
|
||||||
|
|
||||||
let options = {
|
|
||||||
method: 'GET',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (method === 'post') {
|
|
||||||
options = {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
},
|
|
||||||
body: qs,
|
|
||||||
};
|
|
||||||
url = `${CONNECTION_STRING}${resource}/${action}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return makeRequest(url, options).then(response => response.data);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Lbryio.authToken = null;
|
|
||||||
|
|
||||||
Lbryio.getAuthToken = () =>
|
|
||||||
new Promise(resolve => {
|
|
||||||
if (Lbryio.authToken) {
|
|
||||||
resolve(Lbryio.authToken);
|
|
||||||
} else {
|
|
||||||
ipcRenderer.once('auth-token-response', (event, token) => {
|
|
||||||
Lbryio.authToken = token;
|
|
||||||
return resolve(token);
|
|
||||||
});
|
|
||||||
ipcRenderer.send('get-auth-token');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Lbryio.setAuthToken = token => {
|
|
||||||
Lbryio.authToken = token ? token.toString().trim() : null;
|
|
||||||
ipcRenderer.send('set-auth-token', token);
|
|
||||||
};
|
|
||||||
|
|
||||||
Lbryio.getCurrentUser = () => Lbryio.call('user', 'me');
|
|
||||||
|
|
||||||
Lbryio.authenticate = () => {
|
|
||||||
if (!Lbryio.enabled) {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
resolve({
|
|
||||||
id: 1,
|
|
||||||
language: 'en',
|
|
||||||
primary_email: 'disabled@lbry.io',
|
|
||||||
has_verified_email: true,
|
|
||||||
is_identity_verified: true,
|
|
||||||
is_reward_approved: false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Lbryio.authenticationPromise === null) {
|
|
||||||
Lbryio.authenticationPromise = new Promise((resolve, reject) => {
|
|
||||||
Lbryio.getAuthToken()
|
|
||||||
.then(token => {
|
|
||||||
if (!token || token.length > 60) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check that token works
|
|
||||||
return Lbryio.getCurrentUser()
|
|
||||||
.then(() => true)
|
|
||||||
.catch(() => false);
|
|
||||||
})
|
|
||||||
.then(isTokenValid => {
|
|
||||||
if (isTokenValid) {
|
|
||||||
return reject;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Lbry.status()
|
|
||||||
.then(status =>
|
|
||||||
Lbryio.call(
|
|
||||||
'user',
|
|
||||||
'new',
|
|
||||||
{
|
|
||||||
auth_token: '',
|
|
||||||
language: 'en',
|
|
||||||
app_id: status.installation_id,
|
|
||||||
},
|
|
||||||
'post'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.then(response => {
|
|
||||||
if (!response.auth_token) {
|
|
||||||
throw new Error(__('auth_token is missing from response'));
|
|
||||||
}
|
|
||||||
return Lbryio.setAuthToken(response.auth_token);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(Lbryio.getCurrentUser)
|
|
||||||
.then(resolve, reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return Lbryio.authenticationPromise;
|
|
||||||
};
|
|
||||||
|
|
||||||
Lbryio.getStripeToken = () =>
|
|
||||||
CONNECTION_STRING.startsWith('http://localhost:')
|
|
||||||
? 'pk_test_NoL1JWL7i1ipfhVId5KfDZgo'
|
|
||||||
: 'pk_live_e8M4dRNnCCbmpZzduEUZBgJO';
|
|
||||||
|
|
||||||
export default Lbryio;
|
|
|
@ -23,6 +23,7 @@ type ModalProps = {
|
||||||
expandButtonLabel?: string,
|
expandButtonLabel?: string,
|
||||||
hideButtonLabel?: string,
|
hideButtonLabel?: string,
|
||||||
fullScreen: boolean,
|
fullScreen: boolean,
|
||||||
|
title: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Modal extends React.PureComponent<ModalProps> {
|
export class Modal extends React.PureComponent<ModalProps> {
|
||||||
|
@ -51,6 +52,7 @@ export class Modal extends React.PureComponent<ModalProps> {
|
||||||
fullScreen,
|
fullScreen,
|
||||||
className,
|
className,
|
||||||
overlayClassName,
|
overlayClassName,
|
||||||
|
title,
|
||||||
...modalProps
|
...modalProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
return (
|
return (
|
||||||
|
@ -65,6 +67,7 @@ export class Modal extends React.PureComponent<ModalProps> {
|
||||||
![null, undefined, ''].includes(overlayClassName) ? overlayClassName : 'modal-overlay'
|
![null, undefined, ''].includes(overlayClassName) ? overlayClassName : 'modal-overlay'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
<h1 className="modal__header">{title}</h1>
|
||||||
<div>{children}</div>
|
<div>{children}</div>
|
||||||
{type === 'custom' ? null : ( // custom modals define their own buttons
|
{type === 'custom' ? null : ( // custom modals define their own buttons
|
||||||
<div className="card__actions card__actions--center">
|
<div className="card__actions card__actions--center">
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import FilePrice from 'component/filePrice';
|
import FilePrice from 'component/filePrice';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
|
import type { Metadata } from 'types/claim';
|
||||||
|
|
||||||
class ModalAffirmPurchase extends React.PureComponent {
|
type Props = {
|
||||||
|
closeModal: () => void,
|
||||||
|
loadVideo: string => void,
|
||||||
|
uri: string,
|
||||||
|
cancelPurchase: () => void,
|
||||||
|
metadata: Metadata,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalAffirmPurchase extends React.PureComponent<Props> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
@ -25,15 +35,18 @@ class ModalAffirmPurchase extends React.PureComponent {
|
||||||
<Modal
|
<Modal
|
||||||
type="confirm"
|
type="confirm"
|
||||||
isOpen
|
isOpen
|
||||||
|
title={__('Confirm Purchase')}
|
||||||
contentLabel={__('Confirm Purchase')}
|
contentLabel={__('Confirm Purchase')}
|
||||||
onConfirmed={this.onAffirmPurchase}
|
onConfirmed={this.onAffirmPurchase}
|
||||||
onAborted={cancelPurchase}
|
onAborted={cancelPurchase}
|
||||||
>
|
>
|
||||||
{__('This will purchase')} <strong>{title}</strong> {__('for')}{' '}
|
<section className="card__content">
|
||||||
<strong>
|
{__('This will purchase')} <strong>{`"${title}"`}</strong> {__('for')}{' '}
|
||||||
<FilePrice uri={uri} showFullPrice inheritStyle showLBC={false} />
|
<strong>
|
||||||
</strong>{' '}
|
<FilePrice uri={uri} showFullPrice inheritStyle showLBC={false} />
|
||||||
{__('credits')}.
|
</strong>{' '}
|
||||||
|
{__('credits')}.
|
||||||
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
|
|
||||||
class ModalAuthFailure extends React.PureComponent {
|
type Props = {
|
||||||
|
close: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalAuthFailure extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { close } = this.props;
|
const { close } = this.props;
|
||||||
|
|
||||||
|
@ -9,6 +14,7 @@ class ModalAuthFailure extends React.PureComponent {
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
contentLabel={__('Unable to Authenticate')}
|
contentLabel={__('Unable to Authenticate')}
|
||||||
|
title={__('Authentication Failure')}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={__('Reload')}
|
confirmButtonLabel={__('Reload')}
|
||||||
abortButtonLabel={__('Continue')}
|
abortButtonLabel={__('Continue')}
|
||||||
|
@ -17,12 +23,13 @@ class ModalAuthFailure extends React.PureComponent {
|
||||||
}}
|
}}
|
||||||
onAborted={close}
|
onAborted={close}
|
||||||
>
|
>
|
||||||
<h3>{__('Authentication Failure')}</h3>
|
<section className="card__content">
|
||||||
<p>
|
<p>
|
||||||
{__(
|
{__(
|
||||||
'If reloading does not fix this, or you see this at every start up, please email help@lbry.io.'
|
'If reloading does not fix this, or you see this at every start up, please email help@lbry.io.'
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import { Line } from 'rc-progress';
|
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
import { ipcRenderer } from 'electron';
|
||||||
|
|
||||||
const { ipcRenderer } = require('electron');
|
type Props = {
|
||||||
|
closeModal: () => void,
|
||||||
|
declineAutoUpdate: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
class ModalAutoUpdateConfirm extends React.PureComponent {
|
class ModalAutoUpdateConfirm extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { closeModal, declineAutoUpdate } = this.props;
|
const { closeModal, declineAutoUpdate } = this.props;
|
||||||
|
|
||||||
|
@ -14,6 +18,7 @@ class ModalAutoUpdateConfirm extends React.PureComponent {
|
||||||
isOpen
|
isOpen
|
||||||
type="confirm"
|
type="confirm"
|
||||||
contentLabel={__('Update Downloaded')}
|
contentLabel={__('Update Downloaded')}
|
||||||
|
title={__('LBRY Update Ready')}
|
||||||
confirmButtonLabel={__('Upgrade')}
|
confirmButtonLabel={__('Upgrade')}
|
||||||
abortButtonLabel={__('Not now')}
|
abortButtonLabel={__('Not now')}
|
||||||
onConfirmed={() => {
|
onConfirmed={() => {
|
||||||
|
@ -24,10 +29,9 @@ class ModalAutoUpdateConfirm extends React.PureComponent {
|
||||||
closeModal();
|
closeModal();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<section>
|
<section className="card__content">
|
||||||
<h3 className="text-center">{__('LBRY Update Ready')}</h3>
|
|
||||||
<p>{__('Your LBRY update is ready. Restart LBRY now to use it!')}</p>
|
<p>{__('Your LBRY update is ready. Restart LBRY now to use it!')}</p>
|
||||||
<p className="meta text-center">
|
<p className="meta">
|
||||||
{__('Want to know what has changed?')} See the{' '}
|
{__('Want to know what has changed?')} See the{' '}
|
||||||
<Button
|
<Button
|
||||||
button="link"
|
button="link"
|
||||||
|
|
|
@ -26,6 +26,7 @@ class ModalAutoUpdateDownloaded extends React.PureComponent<Props> {
|
||||||
isOpen
|
isOpen
|
||||||
type="confirm"
|
type="confirm"
|
||||||
contentLabel={__('Update Downloaded')}
|
contentLabel={__('Update Downloaded')}
|
||||||
|
title={__('LBRY Leveled Up')}
|
||||||
confirmButtonLabel={__('Use it Now')}
|
confirmButtonLabel={__('Use it Now')}
|
||||||
abortButtonLabel={__('Upgrade on Close')}
|
abortButtonLabel={__('Upgrade on Close')}
|
||||||
confirmButtonDisabled={this.state.disabled}
|
confirmButtonDisabled={this.state.disabled}
|
||||||
|
@ -39,8 +40,7 @@ class ModalAutoUpdateDownloaded extends React.PureComponent<Props> {
|
||||||
closeModal();
|
closeModal();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<section>
|
<section className="card__content">
|
||||||
<h3 className="text-center">{__('LBRY Leveled Up')}</h3>
|
|
||||||
<p>
|
<p>
|
||||||
{__(
|
{__(
|
||||||
'A new version of LBRY has been released, downloaded, and is ready for you to use pending a restart.'
|
'A new version of LBRY has been released, downloaded, and is ready for you to use pending a restart.'
|
||||||
|
|
|
@ -25,21 +25,24 @@ class ModalConfirmThumbnailUpload extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
title={__('Upload Thumbnail')}
|
||||||
contentLabel={__('Confirm Thumbnail Upload')}
|
contentLabel={__('Confirm Thumbnail Upload')}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={__('Upload')}
|
confirmButtonLabel={__('Upload')}
|
||||||
onConfirmed={() => this.upload()}
|
onConfirmed={() => this.upload()}
|
||||||
onAborted={closeModal}
|
onAborted={closeModal}
|
||||||
>
|
>
|
||||||
<p>{__('Are you sure you want to upload this thumbnail to spee.ch')}?</p>
|
<section className="card__content">
|
||||||
<blockquote>{path}</blockquote>
|
<p>{__('Are you sure you want to upload this thumbnail to spee.ch')}?</p>
|
||||||
<FormField
|
<blockquote>{path}</blockquote>
|
||||||
type="checkbox"
|
<FormField
|
||||||
name="content_is_mature"
|
type="checkbox"
|
||||||
postfix={__('Mature audiences only')}
|
name="content_is_mature"
|
||||||
checked={nsfw}
|
postfix={__('Mature audiences only')}
|
||||||
onChange={event => updatePublishForm({ nsfw: event.target.checked })}
|
checked={nsfw}
|
||||||
/>
|
onChange={event => updatePublishForm({ nsfw: event.target.checked })}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,21 +21,20 @@ class ModalConfirmTransaction extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
title={__('Send LBC')}
|
||||||
contentLabel={__('Confirm Transaction')}
|
contentLabel={__('Confirm Transaction')}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={__('Continue')}
|
confirmButtonLabel={__('Send')}
|
||||||
onConfirmed={() => this.onConfirmed()}
|
onConfirmed={() => this.onConfirmed()}
|
||||||
onAborted={closeModal}
|
onAborted={closeModal}
|
||||||
>
|
>
|
||||||
<p>{__('Are you sure you want to ')}</p>
|
<section className="card__content">
|
||||||
<h1>
|
<p>{__('Sending: ')}</p>
|
||||||
{__('send ')} {amount} LBC
|
<blockquote>{amount} LBC</blockquote>
|
||||||
</h1>
|
<p>{__('To address: ')}</p>
|
||||||
<p>{__('Sending: ')}</p>
|
<blockquote>{address}</blockquote>
|
||||||
<blockquote>{amount} LBC</blockquote>
|
<p>{__('Once the transaction is sent, it cannot be reversed.')}</p>
|
||||||
<p>{__('To address: ')}</p>
|
</section>
|
||||||
<blockquote>{address}</blockquote>
|
|
||||||
<p>{__('Once the transaction is sent, it cannot be reversed.')}</p>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import { doSetClientSetting } from 'redux/actions/settings';
|
import { doSetClientSetting } from 'redux/actions/settings';
|
||||||
import { selectUserIsRewardApproved } from 'redux/selectors/user';
|
import { selectUserIsRewardApproved, selectUnclaimedRewardValue } from 'lbryinc';
|
||||||
import { selectBalance, doHideNotification } from 'lbry-redux';
|
import { selectBalance, doHideNotification } from 'lbry-redux';
|
||||||
import { selectUnclaimedRewardValue } from 'redux/selectors/rewards';
|
|
||||||
import * as settings from 'constants/settings';
|
import * as settings from 'constants/settings';
|
||||||
import ModalCreditIntro from './view';
|
import ModalCreditIntro from './view';
|
||||||
|
|
||||||
|
@ -25,4 +24,7 @@ const perform = dispatch => () => ({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(ModalCreditIntro);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(ModalCreditIntro);
|
||||||
|
|
|
@ -17,9 +17,8 @@ const ModalCreditIntro = (props: Props) => {
|
||||||
const totalRewardRounded = Math.floor(totalRewardValue / 10) * 10;
|
const totalRewardRounded = Math.floor(totalRewardValue / 10) * 10;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal type="custom" isOpen contentLabel="Welcome to LBRY">
|
<Modal type="custom" isOpen contentLabel="Welcome to LBRY" title={__('LBRY Credits Needed')}>
|
||||||
<section>
|
<section className="card__content">
|
||||||
<h3 className="modal__header">{__('Computer Wizard Needs Tokens Badly')}</h3>
|
|
||||||
<p>
|
<p>
|
||||||
Some actions require LBRY credits (<em>
|
Some actions require LBRY credits (<em>
|
||||||
<CurrencySymbol />
|
<CurrencySymbol />
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import { Line } from 'rc-progress';
|
import { Line } from 'rc-progress';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
|
||||||
class ModalDownloading extends React.PureComponent {
|
type Props = {
|
||||||
|
downloadProgress: ?number,
|
||||||
|
downloadComplete: boolean,
|
||||||
|
downloadItem: string,
|
||||||
|
startUpgrade: () => void,
|
||||||
|
cancelUpgrade: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalDownloading extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
downloadProgress,
|
downloadProgress,
|
||||||
|
@ -14,44 +23,49 @@ class ModalDownloading extends React.PureComponent {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen contentLabel={__('Downloading Update')} type="custom">
|
<Modal
|
||||||
{__('Downloading Update')}
|
title={__('Downloading Update')}
|
||||||
{downloadProgress ? `: ${downloadProgress}%` : null}
|
isOpen
|
||||||
<Line percent={downloadProgress || 0} strokeWidth="4" />
|
contentLabel={__('Downloading Update')}
|
||||||
{downloadComplete ? (
|
type="custom"
|
||||||
<div>
|
>
|
||||||
<br />
|
<section className="card__content">
|
||||||
<p>{__('Click "Begin Upgrade" to start the upgrade process.')}</p>
|
{downloadProgress ? `${downloadProgress}% ${__('complete')}` : null}
|
||||||
<p>
|
<Line percent={downloadProgress || 0} strokeWidth="4" />
|
||||||
{__(
|
|
||||||
'The app will close, and you will be prompted to install the latest version of LBRY.'
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
{__(
|
|
||||||
'To launch installation manually, close LBRY and run the command below in the terminal.'
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
<blockquote>sudo dpkg -i {downloadItem}</blockquote>
|
|
||||||
<p>{__('After the install is complete, please reopen the app.')}</p>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<div className="modal__buttons">
|
|
||||||
{downloadComplete ? (
|
{downloadComplete ? (
|
||||||
<Button
|
<React.Fragment>
|
||||||
button="primary"
|
<p>{__('Click "Begin Upgrade" to start the upgrade process.')}</p>
|
||||||
label={__('Begin Upgrade')}
|
<p>
|
||||||
className="modal__button"
|
{__(
|
||||||
onClick={startUpgrade}
|
'The app will close, and you will be prompted to install the latest version of LBRY.'
|
||||||
/>
|
)}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{__(
|
||||||
|
'To launch installation manually, close LBRY and run the command below in the terminal.'
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<blockquote>sudo dpkg -i {downloadItem}</blockquote>
|
||||||
|
<p>{__('After the install is complete, please reopen the app.')}</p>
|
||||||
|
</React.Fragment>
|
||||||
) : null}
|
) : null}
|
||||||
<Button
|
<div className="modal__buttons">
|
||||||
button="link"
|
{downloadComplete ? (
|
||||||
label={__('Cancel')}
|
<Button
|
||||||
className="modal__button"
|
button="primary"
|
||||||
onClick={cancelUpgrade}
|
label={__('Begin Upgrade')}
|
||||||
/>
|
className="modal__button"
|
||||||
</div>
|
onClick={startUpgrade}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
<Button
|
||||||
|
button="link"
|
||||||
|
label={__('Cancel')}
|
||||||
|
className="modal__button"
|
||||||
|
onClick={cancelUpgrade}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as settings from 'constants/settings';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doHideNotification } from 'lbry-redux';
|
import { doHideNotification } from 'lbry-redux';
|
||||||
import { doSetClientSetting } from 'redux/actions/settings';
|
import { doSetClientSetting } from 'redux/actions/settings';
|
||||||
import { selectEmailToVerify, selectUser } from 'redux/selectors/user';
|
import { selectEmailToVerify, selectUser } from 'lbryinc';
|
||||||
import ModalEmailCollection from './view';
|
import ModalEmailCollection from './view';
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
|
@ -17,4 +17,7 @@ const perform = dispatch => () => ({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(ModalEmailCollection);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(ModalEmailCollection);
|
||||||
|
|
|
@ -16,7 +16,6 @@ class ModalEmailCollection extends React.PureComponent<Props> {
|
||||||
const { closeModal, email, user } = this.props;
|
const { closeModal, email, user } = this.props;
|
||||||
|
|
||||||
const cancelButton = <Button button="link" onClick={closeModal} label={__('Not Now')} />;
|
const cancelButton = <Button button="link" onClick={closeModal} label={__('Not Now')} />;
|
||||||
|
|
||||||
if (user && !user.has_verified_email && !email) {
|
if (user && !user.has_verified_email && !email) {
|
||||||
return <UserEmailNew cancelButton={cancelButton} />;
|
return <UserEmailNew cancelButton={cancelButton} />;
|
||||||
} else if (user && !user.has_verified_email) {
|
} else if (user && !user.has_verified_email) {
|
||||||
|
@ -35,16 +34,8 @@ class ModalEmailCollection extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal type="custom" isOpen contentLabel="Email">
|
<Modal type="custom" isOpen contentLabel="Email" title={__('Can We Stay In Touch?')}>
|
||||||
<section>
|
<section className="card__content">{this.renderInner()}</section>
|
||||||
<h3 className="modal__header">Can We Stay In Touch?</h3>
|
|
||||||
<div className="card__content">{this.renderInner()}</div>
|
|
||||||
<div className="card__content">
|
|
||||||
<div className="help">
|
|
||||||
{`${__('Your email may be used to sync usage data across devices.')} `}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Native from 'native';
|
import Native from 'native';
|
||||||
import { ExpandableModal } from 'modal/modal';
|
import { ExpandableModal } from 'modal/modal';
|
||||||
|
|
||||||
class ModalError extends React.PureComponent {
|
type Props = {
|
||||||
|
error: string | { message: string },
|
||||||
|
closeModal: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalError extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { closeModal, error } = this.props;
|
const { closeModal, error } = this.props;
|
||||||
|
|
||||||
|
@ -23,37 +29,39 @@ class ModalError extends React.PureComponent {
|
||||||
const label = errorKeyLabels[key];
|
const label = errorKeyLabels[key];
|
||||||
errorInfoList.push(
|
errorInfoList.push(
|
||||||
<li key={key}>
|
<li key={key}>
|
||||||
<strong>{label}</strong>: <code>{val}</code>
|
<strong>{label}</strong>: {val}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorInfo = <ul className="error-modal__error-list">{errorInfoList}</ul>;
|
const errorInfo = <ul className="error-modal__error-list">{errorInfoList}</ul>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ExpandableModal
|
<ExpandableModal
|
||||||
isOpen
|
isOpen
|
||||||
contentLabel={__('Error')}
|
contentLabel={__('Error')}
|
||||||
className="error-modal"
|
title={
|
||||||
overlayClassName="error-modal-overlay"
|
<React.Fragment>
|
||||||
onConfirmed={closeModal}
|
{__('Error')}{' '}
|
||||||
extraContent={errorInfo}
|
|
||||||
>
|
|
||||||
<h3 className="modal__header">{__('Error')}</h3>
|
|
||||||
|
|
||||||
<div className="error-modal__content">
|
|
||||||
<div>
|
|
||||||
<img
|
<img
|
||||||
alt=""
|
alt=""
|
||||||
className="error-modal__warning-symbol"
|
className="error-modal__warning-symbol"
|
||||||
src={Native.imagePath('warning.png')}
|
src={Native.imagePath('warning.png')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</React.Fragment>
|
||||||
|
}
|
||||||
|
className="error-modal"
|
||||||
|
overlayClassName="error-modal-overlay"
|
||||||
|
onConfirmed={closeModal}
|
||||||
|
extraContent={errorInfo}
|
||||||
|
>
|
||||||
|
<section className="card__content">
|
||||||
<p>
|
<p>
|
||||||
{__(
|
{__(
|
||||||
"We're sorry that LBRY has encountered an error. This has been reported and we will investigate the problem."
|
"We're sorry that LBRY has encountered an error. This has been reported and we will investigate the problem."
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</section>
|
||||||
</ExpandableModal>
|
</ExpandableModal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,33 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
|
import type { Metadata } from 'types/claim';
|
||||||
|
|
||||||
class ModalFileTimeout extends React.PureComponent {
|
type Props = {
|
||||||
|
metadata: Metadata,
|
||||||
|
closeModal: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalFileTimeout extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
metadata: { title },
|
metadata: { title },
|
||||||
|
closeModal,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen contentLabel={__('Download failed')} onConfirmed={closeModal}>
|
<Modal
|
||||||
{__('LBRY was unable to download the stream')} <strong>{title}</strong>.
|
isOpen
|
||||||
|
title={__('Unable to Download')}
|
||||||
|
contentLabel={__('Download failed')}
|
||||||
|
onConfirmed={closeModal}
|
||||||
|
>
|
||||||
|
<section className="card__content">
|
||||||
|
<p className="card__error-msg">
|
||||||
|
{__('LBRY was unable to download the stream')}:
|
||||||
|
<div>{`"${title}"`}</div>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import rewards from 'rewards';
|
import { rewards, makeSelectRewardByType } from 'lbryinc';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doHideNotification } from 'lbry-redux';
|
import { doHideNotification } from 'lbry-redux';
|
||||||
import { makeSelectRewardByType } from 'redux/selectors/rewards';
|
|
||||||
import ModalFirstReward from './view';
|
import ModalFirstReward from './view';
|
||||||
|
|
||||||
const select = state => {
|
const select = state => {
|
||||||
|
@ -16,4 +15,7 @@ const perform = dispatch => ({
|
||||||
closeModal: () => dispatch(doHideNotification()),
|
closeModal: () => dispatch(doHideNotification()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(ModalFirstReward);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(ModalFirstReward);
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
// I"ll come back to This
|
// @flow
|
||||||
/* esline-disable */
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import CreditAmount from 'component/common/credit-amount';
|
|
||||||
|
|
||||||
class ModalFirstReward extends React.PureComponent {
|
type Props = {
|
||||||
|
closeModal: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalFirstReward extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { closeModal } = this.props;
|
const { closeModal } = this.props;
|
||||||
|
|
||||||
|
@ -14,10 +16,10 @@ class ModalFirstReward extends React.PureComponent {
|
||||||
overlayClassName="modal-overlay modal-overlay--clear"
|
overlayClassName="modal-overlay modal-overlay--clear"
|
||||||
isOpen
|
isOpen
|
||||||
contentLabel={__('Welcome to LBRY')}
|
contentLabel={__('Welcome to LBRY')}
|
||||||
|
title={__('Your First Reward')}
|
||||||
onConfirmed={closeModal}
|
onConfirmed={closeModal}
|
||||||
>
|
>
|
||||||
<section>
|
<section className="card__content">
|
||||||
<h3 className="modal__header">{__('Your First Reward')}</h3>
|
|
||||||
<p>{__('You just earned your first reward!')}</p>
|
<p>{__('You just earned your first reward!')}</p>
|
||||||
<p>
|
<p>
|
||||||
{__(
|
{__(
|
||||||
|
@ -41,4 +43,3 @@ class ModalFirstReward extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ModalFirstReward;
|
export default ModalFirstReward;
|
||||||
/* eslint-enable */
|
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
|
||||||
const ModalFirstSubscription = props => {
|
type Props = {
|
||||||
|
closeModal: () => void,
|
||||||
|
navigate: string => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ModalFirstSubscription = (props: Props) => {
|
||||||
const { closeModal, navigate } = props;
|
const { closeModal, navigate } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal type="custom" isOpen contentLabel="Subscriptions 101">
|
<Modal type="custom" isOpen contentLabel="Subscriptions 101" title={__('Subscriptions 101')}>
|
||||||
<section>
|
<section className="card__content">
|
||||||
<h3 className="modal__header">{__('Subscriptions 101')}</h3>
|
|
||||||
<p>{__('You just subscribed to your first channel. Awesome!')}</p>
|
<p>{__('You just subscribed to your first channel. Awesome!')}</p>
|
||||||
<p>{__('A few quick things to know:')}</p>
|
<p>{__('A few quick things to know:')}</p>
|
||||||
<p className="card__content">
|
<p className="card__content">
|
||||||
|
|
|
@ -15,6 +15,7 @@ class ModalIncompatibleDaemon extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
title={__('Incompatible Daemon')}
|
||||||
contentLabel={__('Incompatible daemon running')}
|
contentLabel={__('Incompatible daemon running')}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={__('Close LBRY and daemon')}
|
confirmButtonLabel={__('Close LBRY and daemon')}
|
||||||
|
@ -22,9 +23,11 @@ class ModalIncompatibleDaemon extends React.PureComponent<Props> {
|
||||||
onConfirmed={quitAnyDaemon}
|
onConfirmed={quitAnyDaemon}
|
||||||
onAborted={quit}
|
onAborted={quit}
|
||||||
>
|
>
|
||||||
{__(
|
<p>
|
||||||
'This browser is running with an incompatible version of the LBRY protocol, please close the LBRY app and rerun the installation package to repair it. '
|
{__(
|
||||||
)}
|
'This browser is running with an incompatible version of the LBRY protocol, please close the LBRY app and rerun the installation package to repair it. '
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
<Button
|
<Button
|
||||||
button="link"
|
button="link"
|
||||||
label={__('Learn more')}
|
label={__('Learn more')}
|
||||||
|
|
|
@ -23,20 +23,22 @@ class ModalOpenExternalLink extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
title={__('Warning!')}
|
||||||
contentLabel={__('Confirm External Link')}
|
contentLabel={__('Confirm External Link')}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={__('Continue')}
|
confirmButtonLabel={__('Continue')}
|
||||||
onConfirmed={() => this.openExternalLink()}
|
onConfirmed={() => this.openExternalLink()}
|
||||||
onAborted={closeModal}
|
onAborted={closeModal}
|
||||||
>
|
>
|
||||||
<h1>Warning!</h1>
|
<section className="card__content">
|
||||||
<p>{__('This link leads to an external website.')}</p>
|
<p>{__('This link leads to an external website.')}</p>
|
||||||
<blockquote>{uri}</blockquote>
|
<blockquote>{uri}</blockquote>
|
||||||
<p>
|
<p>
|
||||||
{__(
|
{__(
|
||||||
'LBRY Inc is not responsible for its content, click continue to proceed at your own risk.'
|
'LBRY Inc is not responsible for its content, click continue to proceed at your own risk.'
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
import React from 'react';
|
|
||||||
import * as settings from 'constants/settings';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doHideNotification } from 'lbry-redux';
|
import { doHideNotification } from 'lbry-redux';
|
||||||
import { doSetClientSetting } from 'redux/actions/settings';
|
import { selectPhoneToVerify, selectUser } from 'lbryinc';
|
||||||
import { selectPhoneToVerify, selectUser } from 'redux/selectors/user';
|
|
||||||
import { doNavigate } from 'redux/actions/navigation';
|
import { doNavigate } from 'redux/actions/navigation';
|
||||||
import ModalPhoneCollection from './view';
|
import ModalPhoneCollection from './view';
|
||||||
|
|
||||||
|
@ -19,4 +16,7 @@ const perform = dispatch => () => ({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(ModalPhoneCollection);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(ModalPhoneCollection);
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import UserPhoneNew from 'component/userPhoneNew';
|
import UserPhoneNew from 'component/userPhoneNew';
|
||||||
import UserPhoneVerify from 'component/userPhoneVerify';
|
import UserPhoneVerify from 'component/userPhoneVerify';
|
||||||
|
|
||||||
class ModalPhoneCollection extends React.PureComponent {
|
type Props = {
|
||||||
|
phone: ?number,
|
||||||
|
user: {
|
||||||
|
phone_number: ?number,
|
||||||
|
},
|
||||||
|
closeModal: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalPhoneCollection extends React.PureComponent<Props> {
|
||||||
renderInner() {
|
renderInner() {
|
||||||
const { closeModal, phone, user } = this.props;
|
const { closeModal, phone, user } = this.props;
|
||||||
|
|
||||||
|
@ -15,7 +24,7 @@ class ModalPhoneCollection extends React.PureComponent {
|
||||||
} else if (!user.phone_number) {
|
} else if (!user.phone_number) {
|
||||||
return <UserPhoneVerify cancelButton={cancelButton} />;
|
return <UserPhoneVerify cancelButton={cancelButton} />;
|
||||||
}
|
}
|
||||||
closeModal();
|
return closeModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -27,11 +36,8 @@ class ModalPhoneCollection extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal type="custom" isOpen contentLabel="Phone">
|
<Modal type="custom" isOpen contentLabel="Phone" title={__('Verify Your Phone')}>
|
||||||
<section>
|
<section className="card__content">{this.renderInner()}</section>
|
||||||
<h3 className="modal__header">Verify Your Phone</h3>
|
|
||||||
{this.renderInner()}
|
|
||||||
</section>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ class ModalSendTip extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
title={__('Success')}
|
||||||
contentLabel={__('File published')}
|
contentLabel={__('File published')}
|
||||||
onConfirmed={() => {
|
onConfirmed={() => {
|
||||||
clearPublish();
|
clearPublish();
|
||||||
|
@ -23,13 +24,15 @@ class ModalSendTip extends React.PureComponent<Props> {
|
||||||
closeModal();
|
closeModal();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p>{__('Your file has been published to LBRY at the address')}</p>
|
<section className="card__content">
|
||||||
<p className="card__success-msg">{uri}</p>
|
<p>{__('Your file has been published to LBRY at the address')}</p>
|
||||||
<p>
|
<p className="card__success-msg">{uri}</p>
|
||||||
{__(
|
<p>
|
||||||
'The file will take a few minutes to appear for other LBRY users. Until then it will be listed as "pending" under your published files.'
|
{__(
|
||||||
)}
|
'The file will take a few minutes to appear for other LBRY users. Until then it will be listed as "pending" under your published files.'
|
||||||
</p>
|
)}
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,34 +60,38 @@ class ModalRemoveFile extends React.PureComponent<Props, State> {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
title={__('Remove File')}
|
||||||
contentLabel={__('Confirm File Remove')}
|
contentLabel={__('Confirm File Remove')}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={__('Remove')}
|
confirmButtonLabel={__('Remove')}
|
||||||
onConfirmed={() => deleteFile(outpoint, deleteChecked, abandonClaimChecked)}
|
onConfirmed={() => deleteFile(outpoint, deleteChecked, abandonClaimChecked)}
|
||||||
onAborted={closeModal}
|
onAborted={closeModal}
|
||||||
>
|
>
|
||||||
<p>
|
<section className="card__content">
|
||||||
{__("Are you sure you'd like to remove")} <cite>{title}</cite> {__('from the LBRY app?')}
|
<p>
|
||||||
</p>
|
{__("Are you sure you'd like to remove")} <cite>{`"${title}"`}</cite>{' '}
|
||||||
|
{__('from the LBRY app?')}
|
||||||
|
</p>
|
||||||
|
|
||||||
<FormRow padded>
|
<FormRow padded>
|
||||||
<FormField
|
|
||||||
prefix={__('Also delete this file from my computer')}
|
|
||||||
type="checkbox"
|
|
||||||
checked={deleteChecked}
|
|
||||||
onChange={this.handleDeleteCheckboxClicked}
|
|
||||||
/>
|
|
||||||
</FormRow>
|
|
||||||
{claimIsMine && (
|
|
||||||
<FormRow>
|
|
||||||
<FormField
|
<FormField
|
||||||
prefix={__('Abandon the claim for this URI')}
|
prefix={__('Also delete this file from my computer')}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={abandonClaimChecked}
|
checked={deleteChecked}
|
||||||
onChange={this.handleAbandonClaimCheckboxClicked}
|
onChange={this.handleDeleteCheckboxClicked}
|
||||||
/>
|
/>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
)}
|
{claimIsMine && (
|
||||||
|
<FormRow>
|
||||||
|
<FormField
|
||||||
|
prefix={__('Abandon the claim for this URI')}
|
||||||
|
type="checkbox"
|
||||||
|
checked={abandonClaimChecked}
|
||||||
|
onChange={this.handleAbandonClaimCheckboxClicked}
|
||||||
|
/>
|
||||||
|
</FormRow>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,52 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import * as txnTypes from 'constants/transaction_types';
|
import * as txnTypes from 'constants/transaction_types';
|
||||||
|
|
||||||
class ModalRevokeClaim extends React.PureComponent {
|
type Props = {
|
||||||
constructor(props) {
|
closeModal: () => void,
|
||||||
super(props);
|
abandonClaim: (string, number) => void,
|
||||||
|
txid: string,
|
||||||
|
nout: number,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalRevokeClaim extends React.PureComponent<Props> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
(this: any).revokeClaim = this.revokeClaim.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
getButtonLabel(type) {
|
||||||
|
if (type === txnTypes.TIP) {
|
||||||
|
return 'Confirm Tip Unlock';
|
||||||
|
}
|
||||||
|
return 'Confirm Claim Revoke';
|
||||||
|
}
|
||||||
|
|
||||||
|
getMsgBody(type) {
|
||||||
|
if (type === txnTypes.TIP) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<p>{__('Are you sure you want to unlock these credits?')}</p>
|
||||||
|
<p>
|
||||||
|
{__(
|
||||||
|
'These credits are permanently yours and can be unlocked at any time. Unlocking them allows you to spend them, but can hurt the performance of your content in lookups and search results. It is recommended you leave tips locked until you need or want to spend them.'
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<p>{__('Are you sure want to revoke this claim?')}</p>
|
||||||
|
<p>
|
||||||
|
{__(
|
||||||
|
'This will prevent others from resolving and accessing the content you published. It will return the LBC to your spendable balance, less a small transaction fee.'
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
revokeClaim() {
|
revokeClaim() {
|
||||||
|
@ -14,52 +56,6 @@ class ModalRevokeClaim extends React.PureComponent {
|
||||||
this.props.abandonClaim(txid, nout);
|
this.props.abandonClaim(txid, nout);
|
||||||
}
|
}
|
||||||
|
|
||||||
getButtonLabel(type) {
|
|
||||||
if (type == txnTypes.TIP) {
|
|
||||||
return 'Confirm Tip Unlock';
|
|
||||||
}
|
|
||||||
return 'Confirm Claim Revoke';
|
|
||||||
}
|
|
||||||
|
|
||||||
getMsgBody(type) {
|
|
||||||
if (type == txnTypes.TIP) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h3>{__('Confirm Tip Unlock')}</h3>
|
|
||||||
<p>
|
|
||||||
{__('Are you sure you want to unlock these credits?')}
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
{__(
|
|
||||||
'These credits are permanently yours and can be\
|
|
||||||
unlocked at any time. Unlocking them allows you to\
|
|
||||||
spend them, but can hurt the performance of your\
|
|
||||||
content in lookups and search results. It is\
|
|
||||||
recommended you leave tips locked until you\
|
|
||||||
need or want to spend them.'
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h3>{__('Confirm Claim Revoke')}</h3>
|
|
||||||
<p>
|
|
||||||
{__('Are you sure want to revoke this claim?')}
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
{__(
|
|
||||||
'This will prevent others from resolving and\
|
|
||||||
accessing the content you published. It will return\
|
|
||||||
the LBC to your spendable balance, less a small\
|
|
||||||
transaction fee.'
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { transactionItems, txid, nout, closeModal } = this.props;
|
const { transactionItems, txid, nout, closeModal } = this.props;
|
||||||
const { type } = transactionItems.find(claim => claim.txid == txid && claim.nout == nout);
|
const { type } = transactionItems.find(claim => claim.txid == txid && claim.nout == nout);
|
||||||
|
@ -67,13 +63,14 @@ class ModalRevokeClaim extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
title={type === txnTypes.TIP ? __('Confirm Tip Unlock') : __('Confirm Claim Revoke')}
|
||||||
contentLabel={__('Confirm Claim Revoke')}
|
contentLabel={__('Confirm Claim Revoke')}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={this.getButtonLabel(type)}
|
confirmButtonLabel={this.getButtonLabel(type)}
|
||||||
onConfirmed={this.revokeClaim.bind(this)}
|
onConfirmed={this.revokeClaim}
|
||||||
onAborted={closeModal}
|
onAborted={closeModal}
|
||||||
>
|
>
|
||||||
{this.getMsgBody(type)}
|
<section className="card__content">{this.getMsgBody(type)}</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
|
|
||||||
class ModalRewardApprovalRequired extends React.PureComponent {
|
type Props = {
|
||||||
|
closeModal: () => void,
|
||||||
|
doAuth: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalRewardApprovalRequired extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { closeModal, doAuth } = this.props;
|
const { closeModal, doAuth } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
title={__('Hmm. Are you real?')}
|
||||||
contentLabel={__('Human Verification Required')}
|
contentLabel={__('Human Verification Required')}
|
||||||
onConfirmed={doAuth}
|
onConfirmed={doAuth}
|
||||||
onAborted={closeModal}
|
onAborted={closeModal}
|
||||||
|
@ -15,8 +22,7 @@ class ModalRewardApprovalRequired extends React.PureComponent {
|
||||||
confirmButtonLabel={__("I'm Totally Real")}
|
confirmButtonLabel={__("I'm Totally Real")}
|
||||||
abortButtonLabel={__('Never Mind')}
|
abortButtonLabel={__('Never Mind')}
|
||||||
>
|
>
|
||||||
<section>
|
<section className="card__content">
|
||||||
<h3 className="modal__header">{__('This is awkward. Are you real?')}</h3>
|
|
||||||
<p>
|
<p>
|
||||||
{__(
|
{__(
|
||||||
"Before we can give you any credits, we need to perform a brief check to make sure you're a new and unique person."
|
"Before we can give you any credits, we need to perform a brief check to make sure you're a new and unique person."
|
||||||
|
|
28
src/renderer/modal/modalRewardCode/index.js
Normal file
28
src/renderer/modal/modalRewardCode/index.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// @flow
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doHideNotification } from 'lbry-redux';
|
||||||
|
import {
|
||||||
|
makeSelectClaimRewardError,
|
||||||
|
doClaimRewardType,
|
||||||
|
makeSelectIsRewardClaimPending,
|
||||||
|
rewards as REWARD_TYPES,
|
||||||
|
} from 'lbryinc';
|
||||||
|
import ModalRewardCode from './view';
|
||||||
|
|
||||||
|
const select = (state): {} => ({
|
||||||
|
rewardIsPending: makeSelectIsRewardClaimPending()(state, {
|
||||||
|
reward_type: REWARD_TYPES.TYPE_REWARD_CODE,
|
||||||
|
}),
|
||||||
|
error: makeSelectClaimRewardError()(state, { reward_type: REWARD_TYPES.TYPE_REWARD_CODE }),
|
||||||
|
});
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
closeModal: () => dispatch(doHideNotification()),
|
||||||
|
submitRewardCode: (code: string) =>
|
||||||
|
dispatch(doClaimRewardType(REWARD_TYPES.TYPE_REWARD_CODE, { params: { code } })),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(ModalRewardCode);
|
81
src/renderer/modal/modalRewardCode/view.jsx
Normal file
81
src/renderer/modal/modalRewardCode/view.jsx
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// @flow
|
||||||
|
import * as React from 'react';
|
||||||
|
import { FormRow, FormField } from 'component/common/form';
|
||||||
|
import { Modal } from 'modal/modal';
|
||||||
|
import Button from 'component/button';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
closeModal: () => void,
|
||||||
|
error: ?string,
|
||||||
|
rewardIsPending: boolean,
|
||||||
|
submitRewardCode: string => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
rewardCode: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalRewardCode extends React.PureComponent<Props, State> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
rewardCode: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
(this: any).handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit() {
|
||||||
|
const { rewardCode } = this.state;
|
||||||
|
const { submitRewardCode } = this.props;
|
||||||
|
submitRewardCode(rewardCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { closeModal, rewardIsPending, error } = this.props;
|
||||||
|
const { rewardCode } = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen
|
||||||
|
title={__('Enter Reward Code')}
|
||||||
|
contentLabel={__('Enter Reward Code')}
|
||||||
|
type="confirm"
|
||||||
|
confirmButtonLabel={__('Redeem')}
|
||||||
|
abortButtonLabel={__('Cancel')}
|
||||||
|
onConfirmed={this.handleSubmit}
|
||||||
|
onAborted={closeModal}
|
||||||
|
confirmButtonDisabled={rewardIsPending}
|
||||||
|
>
|
||||||
|
<section className="card__content">
|
||||||
|
<FormRow>
|
||||||
|
<FormField
|
||||||
|
stretch
|
||||||
|
autoFocus
|
||||||
|
type="text"
|
||||||
|
label={__('Code')}
|
||||||
|
placeholder="0123abc"
|
||||||
|
error={error}
|
||||||
|
value={rewardCode}
|
||||||
|
onChange={e => this.setState({ rewardCode: e.target.value })}
|
||||||
|
helper={
|
||||||
|
<React.Fragment>
|
||||||
|
{__('Redeem a custom reward code for LBC')}
|
||||||
|
{'. '}
|
||||||
|
<Button
|
||||||
|
button="link"
|
||||||
|
href="https://lbry.io/faq/rewards#reward-code"
|
||||||
|
label={__('Learn more')}
|
||||||
|
/>.
|
||||||
|
</React.Fragment>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</FormRow>
|
||||||
|
</section>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModalRewardCode;
|
|
@ -9,7 +9,7 @@ import {
|
||||||
selectNotificationProps,
|
selectNotificationProps,
|
||||||
} from 'lbry-redux';
|
} from 'lbry-redux';
|
||||||
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
import { makeSelectClientSetting } from 'redux/selectors/settings';
|
||||||
import { selectUser, selectUserIsVerificationCandidate } from 'redux/selectors/user';
|
import { selectUser, selectUserIsVerificationCandidate } from 'lbryinc';
|
||||||
|
|
||||||
import ModalRouter from './view';
|
import ModalRouter from './view';
|
||||||
|
|
||||||
|
@ -32,4 +32,7 @@ const perform = dispatch => ({
|
||||||
openModal: notification => dispatch(doNotify(notification)),
|
openModal: notification => dispatch(doNotify(notification)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(ModalRouter);
|
export default connect(
|
||||||
|
select,
|
||||||
|
perform
|
||||||
|
)(ModalRouter);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MODALS } from 'lbry-redux';
|
import { MODALS } from 'lbry-redux';
|
||||||
import ModalError from 'modal/modalError';
|
import ModalError from 'modal/modalError';
|
||||||
|
@ -19,20 +20,23 @@ import ModalEmailCollection from 'modal/modalEmailCollection';
|
||||||
import ModalPhoneCollection from 'modal/modalPhoneCollection';
|
import ModalPhoneCollection from 'modal/modalPhoneCollection';
|
||||||
import ModalFirstSubscription from 'modal/modalFirstSubscription';
|
import ModalFirstSubscription from 'modal/modalFirstSubscription';
|
||||||
import ModalConfirmTransaction from 'modal/modalConfirmTransaction';
|
import ModalConfirmTransaction from 'modal/modalConfirmTransaction';
|
||||||
import ModalSendTip from '../modalSendTip';
|
import ModalSocialShare from 'modal/modalSocialShare';
|
||||||
import ModalPublish from '../modalPublish';
|
import ModalSendTip from 'modal/modalSendTip';
|
||||||
import ModalOpenExternalLink from '../modalOpenExternalLink';
|
import ModalPublish from 'modal/modalPublish';
|
||||||
|
import ModalOpenExternalLink from 'modal/modalOpenExternalLink';
|
||||||
import ModalConfirmThumbnailUpload from 'modal/modalConfirmThumbnailUpload';
|
import ModalConfirmThumbnailUpload from 'modal/modalConfirmThumbnailUpload';
|
||||||
import ModalWalletEncrypt from 'modal/modalWalletEncrypt';
|
import ModalWalletEncrypt from 'modal/modalWalletEncrypt';
|
||||||
import ModalWalletDecrypt from 'modal/modalWalletDecrypt';
|
import ModalWalletDecrypt from 'modal/modalWalletDecrypt';
|
||||||
import ModalWalletUnlock from 'modal/modalWalletUnlock';
|
import ModalWalletUnlock from 'modal/modalWalletUnlock';
|
||||||
|
import ModalRewardCode from 'modal/modalRewardCode';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
modal: string,
|
notification: { id: string },
|
||||||
|
notificationProps: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModalRouter extends React.PureComponent<Props> {
|
class ModalRouter extends React.PureComponent<Props> {
|
||||||
constructor(props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -50,7 +54,7 @@ class ModalRouter extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
|
|
||||||
showTransitionModals(props) {
|
showTransitionModals(props) {
|
||||||
const { modal, modalProps, openModal, page } = props;
|
const { modal, openModal, page } = props;
|
||||||
|
|
||||||
if (modal) {
|
if (modal) {
|
||||||
return;
|
return;
|
||||||
|
@ -79,6 +83,8 @@ class ModalRouter extends React.PureComponent<Props> {
|
||||||
if (!isWelcomeAcknowledged && user && !user.is_reward_approved && !user.is_identity_verified) {
|
if (!isWelcomeAcknowledged && user && !user.is_reward_approved && !user.is_identity_verified) {
|
||||||
return MODALS.WELCOME;
|
return MODALS.WELCOME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkShowEmail(props) {
|
checkShowEmail(props) {
|
||||||
|
@ -91,6 +97,8 @@ class ModalRouter extends React.PureComponent<Props> {
|
||||||
) {
|
) {
|
||||||
return MODALS.EMAIL_COLLECTION;
|
return MODALS.EMAIL_COLLECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkShowCreditIntro(props) {
|
checkShowCreditIntro(props) {
|
||||||
|
@ -103,6 +111,8 @@ class ModalRouter extends React.PureComponent<Props> {
|
||||||
) {
|
) {
|
||||||
return MODALS.INSUFFICIENT_CREDITS;
|
return MODALS.INSUFFICIENT_CREDITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
isPaidShowPage(props) {
|
isPaidShowPage(props) {
|
||||||
|
@ -160,6 +170,8 @@ class ModalRouter extends React.PureComponent<Props> {
|
||||||
return <ModalFirstSubscription {...notificationProps} />;
|
return <ModalFirstSubscription {...notificationProps} />;
|
||||||
case MODALS.SEND_TIP:
|
case MODALS.SEND_TIP:
|
||||||
return <ModalSendTip {...notificationProps} />;
|
return <ModalSendTip {...notificationProps} />;
|
||||||
|
case MODALS.SOCIAL_SHARE:
|
||||||
|
return <ModalSocialShare {...notificationProps} />;
|
||||||
case MODALS.PUBLISH:
|
case MODALS.PUBLISH:
|
||||||
return <ModalPublish {...notificationProps} />;
|
return <ModalPublish {...notificationProps} />;
|
||||||
case MODALS.CONFIRM_EXTERNAL_LINK:
|
case MODALS.CONFIRM_EXTERNAL_LINK:
|
||||||
|
@ -174,6 +186,8 @@ class ModalRouter extends React.PureComponent<Props> {
|
||||||
return <ModalWalletDecrypt {...notificationProps} />;
|
return <ModalWalletDecrypt {...notificationProps} />;
|
||||||
case MODALS.WALLET_UNLOCK:
|
case MODALS.WALLET_UNLOCK:
|
||||||
return <ModalWalletUnlock {...notificationProps} />;
|
return <ModalWalletUnlock {...notificationProps} />;
|
||||||
|
case MODALS.REWARD_GENERATED_CODE:
|
||||||
|
return <ModalRewardCode {...notificationProps} />;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import SendTip from 'component/walletSendTip';
|
import SendTip from 'component/walletSendTip';
|
||||||
|
import UriIndicator from 'component/uriIndicator';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
closeModal: () => void,
|
closeModal: () => void,
|
||||||
|
@ -13,7 +14,16 @@ class ModalSendTip extends React.PureComponent<Props> {
|
||||||
const { closeModal, uri } = this.props;
|
const { closeModal, uri } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen type="custom">
|
<Modal
|
||||||
|
onAborted={closeModal}
|
||||||
|
isOpen
|
||||||
|
type="custom"
|
||||||
|
title={
|
||||||
|
<React.Fragment>
|
||||||
|
{__('Send a tip to')} <UriIndicator uri={uri} />
|
||||||
|
</React.Fragment>
|
||||||
|
}
|
||||||
|
>
|
||||||
<SendTip uri={uri} onCancel={closeModal} sendTipCallback={closeModal} />
|
<SendTip uri={uri} onCancel={closeModal} sendTipCallback={closeModal} />
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
12
src/renderer/modal/modalSocialShare/index.js
Normal file
12
src/renderer/modal/modalSocialShare/index.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { doHideNotification } from 'lbry-redux';
|
||||||
|
import ModalSocialShare from './view';
|
||||||
|
|
||||||
|
const perform = dispatch => ({
|
||||||
|
closeModal: () => dispatch(doHideNotification()),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
null,
|
||||||
|
perform
|
||||||
|
)(ModalSocialShare);
|
22
src/renderer/modal/modalSocialShare/view.jsx
Normal file
22
src/renderer/modal/modalSocialShare/view.jsx
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
import { Modal } from 'modal/modal';
|
||||||
|
import SocialShare from 'component/socialShare';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
closeModal: () => void,
|
||||||
|
uri: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalSocialShare extends React.PureComponent<Props> {
|
||||||
|
render() {
|
||||||
|
const { closeModal, uri } = this.props;
|
||||||
|
return (
|
||||||
|
<Modal isOpen onAborted={closeModal} type="custom" title={__('Share')}>
|
||||||
|
<SocialShare uri={uri} onDone={closeModal} />
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModalSocialShare;
|
|
@ -1,14 +1,22 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
|
|
||||||
class ModalTransactionFailed extends React.PureComponent {
|
type Props = {
|
||||||
|
closeModal: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalTransactionFailed extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { closeModal } = this.props;
|
const { closeModal } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen contentLabel={__('Transaction failed')} onConfirmed={closeModal}>
|
<Modal
|
||||||
{__('Transaction failed.')}:
|
isOpen
|
||||||
</Modal>
|
contentLabel={__('Transaction failed')}
|
||||||
|
title={__('Transaction Failed')}
|
||||||
|
onConfirmed={closeModal}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
|
||||||
class ModalUpgrade extends React.PureComponent {
|
type Props = {
|
||||||
|
downloadUpgrade: () => void,
|
||||||
|
skipUpgrade: () => void,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModalUpgrade extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { downloadUpgrade, skipUpgrade } = this.props;
|
const { downloadUpgrade, skipUpgrade } = this.props;
|
||||||
|
|
||||||
|
@ -10,26 +16,27 @@ class ModalUpgrade extends React.PureComponent {
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
contentLabel={__('Upgrade available')}
|
contentLabel={__('Upgrade available')}
|
||||||
|
title={__('LBRY Leveled Up')}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={__('Upgrade')}
|
confirmButtonLabel={__('Upgrade')}
|
||||||
abortButtonLabel={__('Skip')}
|
abortButtonLabel={__('Skip')}
|
||||||
onConfirmed={downloadUpgrade}
|
onConfirmed={downloadUpgrade}
|
||||||
onAborted={skipUpgrade}
|
onAborted={skipUpgrade}
|
||||||
>
|
>
|
||||||
<h3 className="text-center">{__('LBRY Leveled Up')}</h3>
|
<div className="card__content">
|
||||||
<br />
|
<p>
|
||||||
<p>
|
{__('An updated version of LBRY is now available.')}{' '}
|
||||||
{__('An updated version of LBRY is now available.')}{' '}
|
{__('Your version is out of date and may be unreliable or insecure.')}
|
||||||
{__('Your version is out of date and may be unreliable or insecure.')}
|
</p>
|
||||||
</p>
|
<p className="meta">
|
||||||
<p className="meta text-center">
|
{__('Want to know what has changed?')} See the{' '}
|
||||||
{__('Want to know what has changed?')} See the{' '}
|
<Button
|
||||||
<Button
|
button="link"
|
||||||
button="link"
|
label={__('release notes')}
|
||||||
label={__('release notes')}
|
href="https://github.com/lbryio/lbry-desktop/releases"
|
||||||
href="https://github.com/lbryio/lbry-desktop/releases"
|
/>.
|
||||||
/>.
|
</p>
|
||||||
</p>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
// @flow
|
// @flow
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Form, FormRow, FormField } from 'component/common/form';
|
import { Form } from 'component/common/form';
|
||||||
import { Modal } from 'modal/modal';
|
import { Modal } from 'modal/modal';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
closeModal: () => void,
|
closeModal: () => void,
|
||||||
unlockWallet: string => void,
|
decryptWallet: () => void,
|
||||||
walletDecryptSucceded: boolean,
|
walletDecryptSucceded: boolean,
|
||||||
updateWalletStatus: boolean,
|
updateWalletStatus: boolean,
|
||||||
};
|
};
|
||||||
|
@ -16,11 +16,6 @@ class ModalWalletDecrypt extends React.PureComponent<Props> {
|
||||||
submitted: false, // Prior actions could be marked complete
|
submitted: false, // Prior actions could be marked complete
|
||||||
};
|
};
|
||||||
|
|
||||||
submitDecryptForm() {
|
|
||||||
this.setState({ submitted: true });
|
|
||||||
this.props.decryptWallet();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
const { props, state } = this;
|
const { props, state } = this;
|
||||||
|
|
||||||
|
@ -30,12 +25,18 @@ class ModalWalletDecrypt extends React.PureComponent<Props> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
submitDecryptForm() {
|
||||||
|
this.setState({ submitted: true });
|
||||||
|
this.props.decryptWallet();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { closeModal, walletDecryptSucceded } = this.props;
|
const { closeModalgaa } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
title={__('Decrypt Wallet')}
|
||||||
contentLabel={__('Decrypt Wallet')}
|
contentLabel={__('Decrypt Wallet')}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={__('Decrypt Wallet')}
|
confirmButtonLabel={__('Decrypt Wallet')}
|
||||||
|
@ -43,18 +44,22 @@ class ModalWalletDecrypt extends React.PureComponent<Props> {
|
||||||
onConfirmed={() => this.submitDecryptForm()}
|
onConfirmed={() => this.submitDecryptForm()}
|
||||||
onAborted={closeModal}
|
onAborted={closeModal}
|
||||||
>
|
>
|
||||||
<Form onSubmit={() => this.submitDecryptForm()}>
|
<section className="card__content">
|
||||||
{__(
|
<Form onSubmit={() => this.submitDecryptForm()}>
|
||||||
'Your wallet has been encrypted with a local password, performing this action will remove this password.'
|
<p>
|
||||||
)}
|
{__(
|
||||||
<div className="card__actions">
|
'Your wallet has been encrypted with a local password, performing this action will remove this password.'
|
||||||
<Button
|
)}
|
||||||
button="link"
|
</p>
|
||||||
label={__('Learn more')}
|
<div className="card__actions">
|
||||||
href="https://lbry.io/faq/wallet-encryption"
|
<Button
|
||||||
/>
|
button="link"
|
||||||
</div>
|
label={__('Learn more')}
|
||||||
</Form>
|
href="https://lbry.io/faq/wallet-encryption"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ class ModalWalletEncrypt extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
title={__('Encrypt Wallet')}
|
||||||
contentLabel={__('Encrypt Wallet')}
|
contentLabel={__('Encrypt Wallet')}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
confirmButtonLabel={__('Encrypt Wallet')}
|
confirmButtonLabel={__('Encrypt Wallet')}
|
||||||
|
@ -89,53 +90,59 @@ class ModalWalletEncrypt extends React.PureComponent<Props> {
|
||||||
onConfirmed={() => this.submitEncryptForm()}
|
onConfirmed={() => this.submitEncryptForm()}
|
||||||
onAborted={closeModal}
|
onAborted={closeModal}
|
||||||
>
|
>
|
||||||
<Form onSubmit={() => this.submitEncryptForm()}>
|
<section className="card__content">
|
||||||
{__(
|
<Form onSubmit={() => this.submitEncryptForm()}>
|
||||||
'Encrypting your wallet will require a password to access your local wallet data when LBRY starts. Please enter a new password for your wallet.'
|
<p>
|
||||||
)}
|
{__(
|
||||||
<FormRow padded>
|
'Encrypting your wallet will require a password to access your local wallet data when LBRY starts. Please enter a new password for your wallet.'
|
||||||
<FormField
|
)}
|
||||||
stretch
|
</p>
|
||||||
error={passwordMismatch === true ? 'Passwords do not match' : false}
|
<FormRow padded>
|
||||||
label={__('New Password')}
|
<FormField
|
||||||
type="password"
|
stretch
|
||||||
name="wallet-new-password"
|
autoFocus
|
||||||
onChange={event => this.onChangeNewPassword(event)}
|
error={passwordMismatch === true ? 'Passwords do not match' : false}
|
||||||
/>
|
label={__('New Password')}
|
||||||
</FormRow>
|
type="password"
|
||||||
<FormRow padded>
|
name="wallet-new-password"
|
||||||
<FormField
|
onChange={event => this.onChangeNewPassword(event)}
|
||||||
stretch
|
/>
|
||||||
error={passwordMismatch === true ? 'Passwords do not match' : false}
|
</FormRow>
|
||||||
label={__('Confirm Password')}
|
<FormRow padded>
|
||||||
type="password"
|
<FormField
|
||||||
name="wallet-new-password-confirm"
|
stretch
|
||||||
onChange={event => this.onChangeNewPasswordConfirm(event)}
|
error={passwordMismatch === true ? 'Passwords do not match' : false}
|
||||||
/>
|
label={__('Confirm Password')}
|
||||||
</FormRow>
|
type="password"
|
||||||
<br />
|
name="wallet-new-password-confirm"
|
||||||
{__(
|
onChange={event => this.onChangeNewPasswordConfirm(event)}
|
||||||
'If your password is lost, it cannot be recovered. You will not be able to access your wallet without a password.'
|
/>
|
||||||
)}
|
</FormRow>
|
||||||
<FormRow padded>
|
<p>
|
||||||
<FormField
|
{__(
|
||||||
stretch
|
'If your password is lost, it cannot be recovered. You will not be able to access your wallet without a password.'
|
||||||
error={understandError === true ? 'You must enter "I understand"' : false}
|
)}
|
||||||
label={__('Enter "I understand"')}
|
</p>
|
||||||
type="text"
|
<FormRow padded>
|
||||||
name="wallet-understand"
|
<FormField
|
||||||
onChange={event => this.onChangeUnderstandConfirm(event)}
|
stretch
|
||||||
/>
|
error={understandError === true ? 'You must enter "I understand"' : false}
|
||||||
</FormRow>
|
label={__('Enter "I understand"')}
|
||||||
<div className="card__actions">
|
type="text"
|
||||||
<Button
|
name="wallet-understand"
|
||||||
button="link"
|
onChange={event => this.onChangeUnderstandConfirm(event)}
|
||||||
label={__('Learn more')}
|
/>
|
||||||
href="https://lbry.io/faq/wallet-encryption"
|
</FormRow>
|
||||||
/>
|
<div className="card__actions">
|
||||||
</div>
|
<Button
|
||||||
{failMessage && <div className="error-text">{__(failMessage)}</div>}
|
button="link"
|
||||||
</Form>
|
label={__('Learn more')}
|
||||||
|
href="https://lbry.io/faq/wallet-encryption"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{failMessage && <div className="error-text">{__(failMessage)}</div>}
|
||||||
|
</Form>
|
||||||
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ class ModalWalletUnlock extends React.PureComponent<Props> {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen
|
isOpen
|
||||||
|
title={__('Unlock Wallet')}
|
||||||
contentLabel={__('Unlock Wallet')}
|
contentLabel={__('Unlock Wallet')}
|
||||||
type="confirm"
|
type="confirm"
|
||||||
shouldCloseOnOverlayClick={false}
|
shouldCloseOnOverlayClick={false}
|
||||||
|
@ -44,28 +45,33 @@ class ModalWalletUnlock extends React.PureComponent<Props> {
|
||||||
onConfirmed={() => unlockWallet(password)}
|
onConfirmed={() => unlockWallet(password)}
|
||||||
onAborted={quit}
|
onAborted={quit}
|
||||||
>
|
>
|
||||||
<Form onSubmit={() => unlockWallet(password)}>
|
<section className="card__content">
|
||||||
{__(
|
<Form onSubmit={() => unlockWallet(password)}>
|
||||||
'Your wallet has been encrypted with a local password. Please enter your wallet password to proceed.'
|
<p>
|
||||||
)}
|
{__(
|
||||||
<FormRow padded>
|
'Your wallet has been encrypted with a local password. Please enter your wallet password to proceed.'
|
||||||
<FormField
|
)}
|
||||||
stretch
|
</p>
|
||||||
error={walletUnlockSucceded === false ? 'Incorrect Password' : false}
|
<FormRow padded>
|
||||||
label={__('Wallet Password')}
|
<FormField
|
||||||
type="password"
|
stretch
|
||||||
name="wallet-password"
|
autoFocus
|
||||||
onChange={event => this.onChangePassword(event)}
|
error={walletUnlockSucceded === false ? 'Incorrect Password' : false}
|
||||||
/>
|
label={__('Wallet Password')}
|
||||||
</FormRow>
|
type="password"
|
||||||
<div className="card__actions">
|
name="wallet-password"
|
||||||
<Button
|
onChange={event => this.onChangePassword(event)}
|
||||||
button="link"
|
/>
|
||||||
label={__('Learn more')}
|
</FormRow>
|
||||||
href="https://lbry.io/faq/wallet-encryption"
|
<div className="card__actions">
|
||||||
/>
|
<Button
|
||||||
</div>
|
button="link"
|
||||||
</Form>
|
label={__('Learn more')}
|
||||||
|
href="https://lbry.io/faq/wallet-encryption"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,8 @@ const ModalWelcome = props => {
|
||||||
const { closeModal } = props;
|
const { closeModal } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal type="custom" isOpen contentLabel="Welcome to LBRY">
|
<Modal type="custom" isOpen contentLabel="Welcome to LBRY" title={__('Welcome to LBRY')}>
|
||||||
<section>
|
<section className="card__content">
|
||||||
<h3 className="modal__header">{__('Welcome to LBRY')}</h3>
|
|
||||||
<p>
|
<p>
|
||||||
{__('Using LBRY is like dating a centaur. Totally normal up top, and')}{' '}
|
{__('Using LBRY is like dating a centaur. Totally normal up top, and')}{' '}
|
||||||
<em>{__('way different')}</em> {__('underneath.')}
|
<em>{__('way different')}</em> {__('underneath.')}
|
||||||
|
@ -18,7 +17,7 @@ const ModalWelcome = props => {
|
||||||
{__('Below, LBRY is controlled by users -- you -- via blockchain and decentralization.')}
|
{__('Below, LBRY is controlled by users -- you -- via blockchain and decentralization.')}
|
||||||
</p>
|
</p>
|
||||||
<div className="modal__buttons">
|
<div className="modal__buttons">
|
||||||
<Button button="primary" onClick={closeModal} label={__("Blockchain Centaurs? I'm In")} />
|
<Button button="primary" onClick={closeModal} label={__("I'm In")} />
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue