diff --git a/css/views/payment-timed-out.css b/css/views/payment-timed-out.css
new file mode 100644
index 00000000..d81000b2
--- /dev/null
+++ b/css/views/payment-timed-out.css
@@ -0,0 +1,75 @@
+.view.payment-timed-out {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ box-sizing: border-box;
+ padding: 0;
+ padding-bottom: 4rem;
+}
+
+.view.payment-timed-out .timed-out-image {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ width: 16rem;
+ height: 16rem;
+ max-width: 90%;
+ max-height: 90%;
+ background: #D8000C;
+ border-radius: 50%;
+ -webkit-animation: scale .5s ease-in-out;
+ animation: scale .5s ease-in-out;
+ margin: 0 auto;
+}
+
+.view.payment-timed-out .timed-out-message {
+ color: #fff;
+ font-size: 6.2rem;
+ font-weight: 100;
+ text-align: center;
+}
+
+.timed-out-message-text {
+ color: #fff;
+ font-size: 2rem;
+}
+
+@-webkit-keyframes scale {
+ 0% {
+ -webkit-transform: scale(0) translateZ(0);
+ transform: scale(0) translateZ(0);
+ }
+ 20% {
+ -webkit-transform: scale(1.5) translateZ(0);
+ transform: scale(1.5) translateZ(0);
+ }
+ 60% {
+ -webkit-transform: scale(0.75) translateZ(0);
+ transform: scale(0.75) translateZ(0);
+ }
+ 100% {
+ -webkit-transform: scale(1) translateZ(0);
+ transform: scale(1) translateZ(0);
+ }
+}
+
+@keyframes scale {
+ 0% {
+ -webkit-transform: scale(0) translateZ(0);
+ transform: scale(0) translateZ(0);
+ }
+ 20% {
+ -webkit-transform: scale(1.5) translateZ(0);
+ transform: scale(1.5) translateZ(0);
+ }
+ 60% {
+ -webkit-transform: scale(0.75) translateZ(0);
+ transform: scale(0.75) translateZ(0);
+ }
+ 100% {
+ -webkit-transform: scale(1) translateZ(0);
+ transform: scale(1) translateZ(0);
+ }
+}
\ No newline at end of file
diff --git a/html/templates/payment-timed-out.html b/html/templates/payment-timed-out.html
new file mode 100644
index 00000000..92adfee1
--- /dev/null
+++ b/html/templates/payment-timed-out.html
@@ -0,0 +1,7 @@
+
+
☹
+
{{i18n "payment-timed-out.message"}}
+
+
diff --git a/js/config.js b/js/config.js
index 0299184a..47e55221 100644
--- a/js/config.js
+++ b/js/config.js
@@ -82,6 +82,9 @@ app.config = (function() {
minLength: 1,
unlockTime: 5 * 60 * 1000,
},
+ paymentRequest: {
+ timedOut: 5 * 60 * 1000,
+ },
settings: [
{
name: 'configurableCryptoCurrencies',
diff --git a/js/lang/en.js b/js/lang/en.js
index ccfee6ad..aeef36cc 100644
--- a/js/lang/en.js
+++ b/js/lang/en.js
@@ -54,6 +54,8 @@ app.lang['en'] = (function() {
'pin-required.instructions': 'Enter the admin PIN to continue',
'pin-required.incorrect': 'The PIN you entered was incorrect',
'device.camera.not-available': 'Device camera not available',
+ 'payment-timed-out.message': 'Timed out',
+ 'payment-timed-out.ok': 'Ok',
};
})();
diff --git a/js/router.js b/js/router.js
index af4501b1..d494ace0 100644
--- a/js/router.js
+++ b/js/router.js
@@ -32,6 +32,7 @@ app.Router = (function() {
routes: {
'pay': 'pay',
'confirmed': 'paymentConfirmation',
+ 'timed-out': 'paymentTimedOut',
'pay/:amount': 'choosePaymentMethod',
'pay/:amount/:method': 'displayPaymentAddress',
'payment-details/:paymentId': 'paymentDetails',
@@ -162,6 +163,12 @@ app.Router = (function() {
app.mainView.renderView('PaymentDetails', {
paymentId: paymentId
});
+ },
+
+ paymentTimedOut: function() {
+
+ app.mainView.renderView('PaymentTimedOut');
+
}
});
diff --git a/js/views/display-payment-address.js b/js/views/display-payment-address.js
index 4a5b15ba..b9d1bb69 100644
--- a/js/views/display-payment-address.js
+++ b/js/views/display-payment-address.js
@@ -17,6 +17,8 @@ app.views.DisplayPaymentAddress = (function() {
'quicktouch .back': 'back',
},
+ timerForTimeOut: false,
+
serializeData: function() {
return {
@@ -147,6 +149,7 @@ app.views.DisplayPaymentAddress = (function() {
var paymentMethod = app.paymentMethods[this.options.method];
var paymentRequest = this.paymentRequest.toJSON();
var received = false;
+ var timedOut = false;
var errorWhileWaiting;
paymentMethod.listenForPayment(paymentRequest, function(error, wasReceived) {
@@ -160,6 +163,7 @@ app.views.DisplayPaymentAddress = (function() {
var done = _.bind(function(error) {
this.stopListeningForPayment();
+ clearTimeout(this.timerForTimeOut);
if (error) {
return app.mainView.showMessage(error);
@@ -171,12 +175,20 @@ app.views.DisplayPaymentAddress = (function() {
// Show success screen.
app.router.navigate('confirmed', { trigger: true });
} else {
- app.mainView.showMessage(new Error(app.i18n.t('pay-address.timeout')));
+ // Update the status of the payment request.
+ this.paymentRequest.save({ status: 'timed-out' });
+ // Show timed-out screen.
+ app.router.navigate('timed-out', { trigger: true });
}
}, this);
- async.until(function() { return received; }, function(next) {
+ this.timerForTimeOut = setTimeout(function() {
+ timedOut = true;
+ }, app.config.paymentRequest.timedOut)
+
+ async.until(function() { return received || timedOut; }, function(next) {
+
if (errorWhileWaiting) {
return next(errorWhileWaiting);
} else {
@@ -228,6 +240,7 @@ app.views.DisplayPaymentAddress = (function() {
onClose: function() {
this.stopListeningForPayment();
+ clearTimeout(this.timerForTimeOut);
},
onBackButton: function() {
diff --git a/js/views/payment-timed-out.js b/js/views/payment-timed-out.js
new file mode 100644
index 00000000..2102bddd
--- /dev/null
+++ b/js/views/payment-timed-out.js
@@ -0,0 +1,36 @@
+var app = app || {};
+
+app.views = app.views || {};
+
+app.views.PaymentTimedOut= (function() {
+
+ 'use strict';
+
+ return app.abstracts.BaseView.extend({
+
+ className: 'payment-timed-out',
+
+ template: '#template-payment-timed-out',
+
+ events: {
+ 'quicktouch .done': 'done',
+ },
+
+ done: function(evt) {
+
+ if (evt && evt.preventDefault) {
+ evt.preventDefault();
+ }
+
+ // Navigate back to the homescreen
+ app.router.navigate('main', { trigger: true });
+ },
+
+ onBackButton: function() {
+
+ this.done();
+ }
+
+ });
+
+})();
\ No newline at end of file