diff --git a/dist/index.html b/dist/index.html index 3ecc0a4d2..2bc0d6e83 100644 --- a/dist/index.html +++ b/dist/index.html @@ -20,8 +20,9 @@
- - + + + @@ -32,6 +33,7 @@ + diff --git a/js/app.js b/js/app.js index 1306ae5c7..fc6392ef7 100644 --- a/js/app.js +++ b/js/app.js @@ -11,35 +11,37 @@ var App = React.createClass({ viewingPage: viewingPage, drawerOpen: drawerOpenRaw !== null ? JSON.parse(drawerOpenRaw) : true, pageArgs: val, + modal: null, + startNotice: null, + updateUrl: null, + isOldOSX: null, }; }, componentDidMount: function() { lbry.getStartNotice(function(notice) { if (notice) { - alert(notice); + this.setState({ + modal: 'startNotice', + startNotice: notice + }); } }); }, componentWillMount: function() { - lbry.checkNewVersionAvailable(function(isAvailable) { - + lbry.checkNewVersionAvailable((isAvailable) => { if (!isAvailable || sessionStorage.getItem('upgradeSkipped')) { return; } - var message = 'The version of LBRY you\'re using is not up to date.\n\n' + - 'Choose "OK" to download the latest version.'; - - lbry.getVersionInfo(function(versionInfo) { + lbry.getVersionInfo((versionInfo) => { + var isOldOSX = false; if (versionInfo.os_system == 'Darwin') { var updateUrl = 'https://lbry.io/get/lbry.dmg'; var maj, min, patch; [maj, min, patch] = versionInfo.lbrynet_version.split('.'); if (maj == 0 && min <= 2 && patch <= 2) { - // On OS X with version <= 0.2.2, we need to notify user to close manually close LBRY - message += '\n\nBefore installing the new version, make sure to exit LBRY, if you started the app ' + - 'click that LBRY icon in your status bar and choose "Quit."'; + isOldOSX = true; } } else if (versionInfo.os_system == 'Linux') { var updateUrl = 'https://lbry.io/get/lbry.deb'; @@ -49,13 +51,11 @@ var App = React.createClass({ var updateUrl = 'https://lbry.io/get'; } - if (window.confirm(message)) - { - lbry.stop(); - window.location = updateUrl; - } else { - sessionStorage.setItem('upgradeSkipped', true); - }; + this.setState({ + modal: 'upgrade', + isOldOSX: isOldOSX, + updateUrl: updateUrl, + }) }); }); }, @@ -67,6 +67,21 @@ var App = React.createClass({ sessionStorage.setItem('drawerOpen', false); this.setState({ drawerOpen: false }); }, + closeModal: function() { + this.setState({ + modal: null, + }); + }, + handleUpgradeClicked: function() { + lbry.stop(); + window.location = this.state.updateUrl; + }, + handleSkipClicked: function() { + sessionStorage.setItem('upgradeSkipped', true); + this.setState({ + modal: null, + }); + }, onSearch: function(term) { this.setState({ viewingPage: 'discover', @@ -151,6 +166,17 @@ var App = React.createClass({
{mainContent} + + {this.state.startNotice} + + +

The version of LBRY you're using is not up to date. Choose "Upgrade" to get the latest version.

+ {this.state.isOldOSX + ?

Before installing the new version, make sure to exit LBRY. If you started the app, click the LBRY icon in your status bar and choose "Quit."

+ : null} + +
); } diff --git a/js/component/link.js b/js/component/link.js index 0243d5bed..8f9b8cde7 100644 --- a/js/component/link.js +++ b/js/component/link.js @@ -93,13 +93,22 @@ var DownloadLink = React.createClass({ getInitialState: function() { return { downloading: false, + filePath: null, + modal: null, } }, + closeModal: function() { + this.setState({ + modal: null, + }) + }, handleClick: function() { lbry.getCostEstimate(this.props.streamName, (amount) => { lbry.getBalance((balance) => { if (amount > balance) { - alert("You don't have enough LBRY credits to pay for this stream."); + this.setState({ + modal: 'notEnoughCredits', + }); } else { this.startDownload(); } @@ -113,15 +122,27 @@ var DownloadLink = React.createClass({ }); lbry.getStream(this.props.streamName, (streamInfo) => { - alert('Downloading to ' + streamInfo.path); - console.log(streamInfo); + this.setState({ + modal: 'downloadStarted', + filePath: streamInfo.path, + }); }); } }, render: function() { var label = (!this.state.downloading ? this.props.label : this.props.downloadingLabel); - return ; + return ( + + + + Downloading to {this.state.filePath} + + + You don't have enough LBRY credits to pay for this stream. + + + ); } }); @@ -138,22 +159,40 @@ var WatchLink = React.createClass({ lbry.getCostEstimate(this.props.streamName, (amount) => { lbry.getBalance((balance) => { if (amount > balance) { - alert("You don't have enough LBRY credits to pay for this stream."); + this.setState({ + modal: 'notEnoughCredits', + }); } else { window.location = '?watch=' + this.props.streamName; } }); }); }, + getInitialState: function() { + return { + modal: null, + }; + }, + closeModal: function() { + this.setState({ + modal: null, + }); + }, getDefaultProps: function() { return { icon: 'icon-play', label: 'Watch', } }, - render: function() { - return ; + return ( + + + + You don't have enough LBRY credits to pay for this stream. + + + ); } }); \ No newline at end of file diff --git a/js/component/modal.js b/js/component/modal.js new file mode 100644 index 000000000..b1bb5065f --- /dev/null +++ b/js/component/modal.js @@ -0,0 +1,57 @@ +var Modal = React.createClass({ + propTypes: { + type: React.PropTypes.oneOf(['alert', 'confirm', 'custom']), + onConfirmed: React.PropTypes.func, + onAborted: React.PropTypes.func, + confirmButtonLabel: React.PropTypes.string, + abortButtonLabel: React.PropTypes.string, + confirmButtonDisabled: React.PropTypes.bool, + abortButtonDisabled: React.PropTypes.bool, + }, + getDefaultProps: function() { + return { + type: 'alert', + confirmButtonLabel: 'OK', + abortButtonLabel: 'Cancel', + confirmButtonDisabled: false, + abortButtonDisabled: false, + }; + }, + render: function() { + var props = Object.assign({}, this.props); + + if (typeof props.className == 'undefined') { + props.className = 'modal'; + } else { + props.className += ' modal'; + } + + if (typeof props.overlayClassName == 'undefined') { + props.overlayClassName = 'modal-overlay'; + } else { + props.overlayClassName += ' modal-overlay'; + } + + props.onCloseRequested = props.onAborted || props.onConfirmed; + + if (this.props.type == 'custom') { + var buttons = null; + } else { + var buttons = ( +
+ {this.props.type == 'confirm' + ? + : null} + +
+ ); + } + + return ( + + {this.props.children} + {buttons} + + ); + } +}); diff --git a/js/page/claim_code.js b/js/page/claim_code.js index d904703a9..1655d37da 100644 --- a/js/page/claim_code.js +++ b/js/page/claim_code.js @@ -14,6 +14,10 @@ var ClaimCodePage = React.createClass({ getInitialState: function() { return { submitting: false, + modal: null, + referralCredits: null, + activationCredits: null, + failureReason: null, } }, handleSubmit: function(event) { @@ -22,15 +26,19 @@ var ClaimCodePage = React.createClass({ } if (!this.refs.code.value) { - alert('Please enter an invitation code or choose "Skip."'); + this.setState({ + modal: 'missingCode', + }); return; } else if (!this.refs.email.value) { - alert('Please enter an email address or choose "Skip."'); + this.setState({ + modal: 'missingEmail', + }); return; } this.setState({ - submitting: true + submitting: true, }); lbry.getNewAddress((address) => { @@ -42,33 +50,25 @@ var ClaimCodePage = React.createClass({ var response = JSON.parse(xhr.responseText); if (response.success) { - var redeemMessage = 'Your invite code has been redeemed. '; - if (response.referralCredits > 0) { - redeemMessage += 'You have also earned ' + response.referralCredits + ' credits from referrals. A total of ' + - (response.activationCredits + response.referralCredits) + ' will be added to your balance shortly.'; - } else if(response.activationCredits > 0) { - redeemMessage += response.activationCredits + ' credits will be added to your balance shortly.'; - } else { - redeemMessage += 'The credits will be added to your balance shortly.'; - } - alert(redeemMessage); - localStorage.setItem('claimCodeDone', true); - window.location = '?home'; - } else { - alert(response.reason); this.setState({ - submitting: false + modal: 'codeRedeemed', + referralCredits: response.referralCredits, + activationCredits: response.activationCredits, + }); + } else { + this.setState({ + submitting: false, + modal: 'codeRedeemFailed', + failureReason: response.reason, }); } }); xhr.addEventListener('error', () => { this.setState({ - submitting: false + submitting: false, + modal: 'couldNotConnect', }); - alert('LBRY couldn\'t connect to our servers to confirm your invitation code. Please check your ' + - 'internet connection. If you continue to have problems, you can still browse LBRY and ' + - 'visit the Settings page to redeem your code later.'); }); xhr.open('POST', 'https://invites.lbry.io', true); @@ -78,10 +78,19 @@ var ClaimCodePage = React.createClass({ }); }, handleSkip: function() { - alert('Welcome to LBRY! You can visit the Wallet page to redeem an invite code at any time.'); + this.setState({ + modal: 'skipped', + }); + }, + handleFinished: function() { localStorage.setItem('claimCodeDone', true); window.location = '?home'; }, + closeModal: function() { + this.setState({ + modal: null, + }); + }, render: function() { return (
@@ -105,6 +114,31 @@ var ClaimCodePage = React.createClass({ + + Please enter an invitation code or choose "Skip." + + + Please enter an email address or choose "Skip." + + + {this.state.failureReason} + + + Your invite code has been redeemed. + {this.state.referralCredits > 0 + ? `You have also earned {referralCredits} credits from referrals. A total of {activationCredits + referralCredits} + will be added to your balance shortly.` + : (this.state.activationCredits > 0 + ? `{this.state.activationCredits} credits will be added to your balance shortly.` + : 'The credits will be added to your balance shortly.')} + + + Welcome to LBRY! You can visit the Wallet page to redeem an invite code at any time. + + +

LBRY couldn't connect to our servers to confirm your invitation code. Please check your internet connection.

+ If you continue to have problems, you can still browse LBRY and visit the Settings page to redeem your code later. +
); } diff --git a/js/page/my_files.js b/js/page/my_files.js index fe60cbaa2..26d5fed42 100644 --- a/js/page/my_files.js +++ b/js/page/my_files.js @@ -5,31 +5,48 @@ var moreMenuStyle = { right: '13px', }; var MyFilesRowMoreMenu = React.createClass({ - onRevealClicked: function() { + propTypes: { + title: React.PropTypes.string.isRequired, + path: React.PropTypes.string.isRequired, + completed: React.PropTypes.bool.isRequired, + lbryUri: React.PropTypes.string.isRequired, + }, + handleRevealClicked: function() { lbry.revealFile(this.props.path); }, - onRemoveClicked: function() { + handleRemoveClicked: function() { lbry.deleteFile(this.props.lbryUri, false); }, - onDeleteClicked: function() { - var alertText = 'Are you sure you\'d like to delete "' + this.props.title + '?" This will ' + - (this.completed ? ' stop the download and ' : '') + - 'permanently remove the file from your system.'; - - if (confirm(alertText)) { - lbry.deleteFile(this.props.lbryUri); - } + handleDeleteClicked: function() { + this.setState({ + modal: 'confirmDelete', + }); + }, + handleDeleteConfirmed: function() { + lbry.deleteFile(this.props.lbryUri); + lbry.setState({ + modal: null, + }); + }, + getInitialState: function() { + return { + modal: null, + }; }, render: function() { return (
- {/* @TODO: Switch to OS specific wording */} - - + {/* @TODO: Switch to OS specific wording */} + +
+ + Are you sure you'd like to delete {this.props.title}? This will {this.props.completed ? ' stop the download and ' : ''} + permanently remove the file from your system. +
); } @@ -123,8 +140,8 @@ var MyFilesRow = React.createClass({
+ completed={this.props.completed} lbryUri={this.props.lbryUri} + fileName={this.props.fileName} path={this.props.path}/>
} diff --git a/js/page/publish.js b/js/page/publish.js index a21d6516a..adb2adb29 100644 --- a/js/page/publish.js +++ b/js/page/publish.js @@ -81,14 +81,8 @@ var PublishPage = React.createClass({ console.log(publishArgs); lbry.publish(publishArgs, (message) => { this.handlePublishStarted(); - this.setState({ - submitting: false, - }); }, null, (error) => { this.handlePublishError(error); - this.setState({ - submitting: false, - }); }); }; @@ -125,18 +119,26 @@ var PublishPage = React.createClass({ otherLicenseUrl: '', uploadProgress: 0.0, uploaded: false, + errorMessage: null, tempFileReady: false, submitting: false, + modal: null, }; }, handlePublishStarted: function() { - alert(`Your file ${this.refs.meta_title.getValue()} has been published to LBRY at the address lbry://${this.state.name}!\n\n` + - `You will now be taken to your My Files page, where your newly published file will be listed. Your file will take a few minutes to appear for other LBRY users; until then it will be listed as "pending."`); + this.setState({ + modal: 'publishStarted', + }); + }, + handlePublishStartedConfirmed: function() { window.location = "?published"; }, handlePublishError: function(error) { - alert(`The following error occurred when attempting to publish your file:\n\n` + - error.message); + this.setState({ + submitting: false, + modal: 'error', + errorMessage: error.message, + }); }, handleNameChange: function(event) { var rawName = event.target.value; @@ -463,6 +465,14 @@ var PublishPage = React.createClass({ + + +

Your file has been published to LBRY at the address lbry://{this.state.name}!

+ You will now be taken to your My Files page, where your newly published file will be listed. The file will take a few minutes to appear for other LBRY users; until then it will be listed as "pending." +
+ + The following error occurred when attempting to publish your file: {this.state.errorMessage} + ); } diff --git a/js/page/referral.js b/js/page/referral.js index 0c7337d1d..4cbcf930d 100644 --- a/js/page/referral.js +++ b/js/page/referral.js @@ -14,6 +14,9 @@ var ReferralPage = React.createClass({ getInitialState: function() { return { submitting: false, + modal: null, + referralCredits: null, + failureReason: null, } }, handleSubmit: function(event) { @@ -22,15 +25,17 @@ var ReferralPage = React.createClass({ } if (!this.refs.code.value) { - alert('Please enter a referral code.'); - return; + this.setState({ + modal: 'missingCode', + }); } else if (!this.refs.email.value) { - alert('Please enter an email address.'); - return; + this.setState({ + modal: 'missingEmail', + }); } this.setState({ - submitting: true + submitting: true, }); lbry.getNewAddress((address) => { @@ -42,29 +47,24 @@ var ReferralPage = React.createClass({ var response = JSON.parse(xhr.responseText); if (response.success) { - if (response.referralCredits > 0) { - alert('You have earned ' + response.referralCredits + ' credits from referrals. ' + - 'We will credit your account shortly. Thanks!'); - } else { - alert('You have not earned any new referral credits since the last time you checked. ' + - 'Please check back in a week or two.'); - } - - window.location = '?home'; - } else { - alert(response.reason); this.setState({ - submitting: false + modal: 'referralInfo', + referralCredits: response.referralCredits, + }); + } else { + this.setState({ + submitting: false, + modal: 'lookupFailed', + failureReason: response.reason, }); } }); xhr.addEventListener('error', () => { this.setState({ - submitting: false + submitting: false, + modal: 'couldNotConnect', }); - alert('LBRY couldn\'t connect to our servers to confirm your referral code. Please check your ' + - 'internet connection.'); }); xhr.open('POST', 'https://invites.lbry.io/check', true); @@ -73,6 +73,15 @@ var ReferralPage = React.createClass({ '&email=' + encodeURIComponent(email)); }); }, + closeModal: function() { + this.setState({ + modal: null, + }); + }, + handleFinished: function() { + localStorage.setItem('claimCodeDone', true); + window.location = '?home'; + }, render: function() { return (
@@ -94,6 +103,17 @@ var ReferralPage = React.createClass({ + + {this.state.referralCredits > 0 + ? `You have earned {response.referralCredits} credits from referrals. We will credit your account shortly. Thanks!` + : 'You have not earned any new referral credits since the last time you checked. Please check back in a week or two.'} + + + {this.state.failureReason} + + + LBRY couldn't connect to our servers to confirm your referral code. Please check your internet connection. +
); } diff --git a/js/page/report.js b/js/page/report.js index af10ae71c..ac9751857 100644 --- a/js/page/report.js +++ b/js/page/report.js @@ -6,9 +6,9 @@ var ReportPage = React.createClass({ }); lbry.reportBug(this._messageArea.value, () => { this.setState({ - submitting: false + submitting: false, + modal: 'submitted', }); - alert("Your bug report has been submitted! Thank you for your feedback."); }); this._messageArea.value = ''; } @@ -16,9 +16,15 @@ var ReportPage = React.createClass({ componentDidMount: function() { document.title = "Report an Issue"; }, + closeModal: function() { + this.setState({ + modal: null, + }) + }, getInitialState: function() { return { submitting: false, + modal: null, } }, render: function() { @@ -38,6 +44,9 @@ var ReportPage = React.createClass({

Developer?

You can also . + + Your bug report has been submitted! Thank you for your feedback. + ); } diff --git a/js/page/wallet.js b/js/page/wallet.js index a6eaa690c..6f55d0876 100644 --- a/js/page/wallet.js +++ b/js/page/wallet.js @@ -17,6 +17,7 @@ var AddressSection = React.createClass({ getInitialState: function() { return { address: null, + modal: null, } }, componentWillMount: function() { @@ -58,7 +59,9 @@ var SendToAddressSection = React.createClass({ if ((this.state.balance - this.state.amount) < 1) { - alert("Insufficient balance: after this transaction you would have less than 1 LBC in your wallet.") + this.setState({ + modal: 'insufficientBalance', + }); return; } @@ -85,6 +88,11 @@ var SendToAddressSection = React.createClass({ }) }); }, + closeModal: function() { + this.setState({ + modal: null, + }); + }, getInitialState: function() { return { address: "", @@ -136,6 +144,9 @@ var SendToAddressSection = React.createClass({ : '' } + + Insufficient balance: after this transaction you would have less than 1 LBC in your wallet. + ); } diff --git a/scss/_gui.scss b/scss/_gui.scss index 09a1b950a..8db305454 100644 --- a/scss/_gui.scss +++ b/scss/_gui.scss @@ -132,6 +132,13 @@ input[type="text"], input[type="search"] } } +.button-container { + + .button-container + { + margin-left: 12px; + } +} + .button-block { cursor: pointer; @@ -143,10 +150,6 @@ input[type="text"], input[type="search"] text-align: center; border-radius: 2px; text-transform: uppercase; - + .button-block - { - margin-left: 12px; - } .icon { top: 0em; @@ -225,3 +228,43 @@ input[type="text"], input[type="search"] margin-top: $spacing-vertical; } } + +.modal-overlay { + position: fixed; + display: flex; + justify-content: center; + align-items: center; + + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + background-color: rgba(255, 255, 255, 0.74902); + z-index: 9999; +} + +.modal { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + border: 1px solid rgb(204, 204, 204); + background: rgb(255, 255, 255); + overflow: auto; + border-radius: 4px; + outline: none; + padding: 40px; + max-width: 250px; +} + +.modal__buttons { + display: flex; + flex-direction: row; + justify-content: center; + margin-top: 15px; +} + +.modal__button { + margin: 0px 6px; +}