From 00bbe4cf98a8e5f3056b1a0ea2b65d2203153e17 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Mon, 9 Apr 2018 09:55:48 -0400 Subject: [PATCH 01/19] feat(Recurring Buy): starts reimplementation; redo announcement; narrow frequency options --- app/partials/coinify/checkout.pug | 8 +++++++- app/templates/exchange/checkout.pug | 3 +-- .../components/exchange/exchange-checkout.component.js | 4 ++-- .../controllers/coinify/coinifyCheckout.controller.js | 8 +++++--- locales/en-human.json | 10 +++++++--- 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/app/partials/coinify/checkout.pug b/app/partials/coinify/checkout.pug index 9c2919721c..d82761746e 100644 --- a/app/partials/coinify/checkout.pug +++ b/app/partials/coinify/checkout.pug @@ -31,7 +31,13 @@ bc-tabs(tab="tabs.selectedTab" tab-options="tabs.options" on-select="tabs.select i.pointer.ti-close.f-14.mid-grey(ng-click="dismissRecurringBuyIntro()") p.f-12.mt-10(translate="RECURRING_INTRO_1") p.f-12(translate="RECURRING_INTRO_2") - p.f-12(translate="RECURRING_INTRO_3") + div.mb-10 + span.f-12(translate="RECURRING_INTRO_3") + |   + a.f-12(translate="ORDERS" ng-click="tabs.select('ORDER_HISTORY')") + span.f-12(translate="RECURRING_INTRO_4") + |   + a.f-12(translate="LEARN_MORE_HERE" ng-click="goToFaq()") kyc-status(ng-if="pendingKYC()" kyc="pendingKYC()" on-trigger="openKYC()" currency="buyFiat.code") .flex-row.flex-column-tablet.flex-column-mobile(ng-show="tabs.selectedTab === 'SELL_BITCOIN'") //- SELL diff --git a/app/templates/exchange/checkout.pug b/app/templates/exchange/checkout.pug index 0ad09db166..c7384c16d5 100644 --- a/app/templates/exchange/checkout.pug +++ b/app/templates/exchange/checkout.pug @@ -87,8 +87,7 @@ form.bc-form( .group.inline.mt-10(ng-if="$ctrl.frequencies && !trading().isDisabled && $ctrl.showRecurringBuy") .item.inline.check input(type="checkbox" id="frequencyCheck" name="frequencyCheck" ng-model="state.frequencyCheck" ng-disabled="checkoutForm.fiat.$viewValue > $ctrl.recurringBuyLimit() || $ctrl.recurringBuyLimit() < min.fiat") - label(for="frequencyCheck") Make this a recurring order - helper-button(content="{{ provider + '.recurring_buy' + ($ctrl.recurringBuyLimit() < min.fiat ? '.disabled' : '.enabled') | translate:{cardLimit: $ctrl.recurringBuyLimit(), currency: fiat.code } }}" append="true") + label(for="frequencyCheck" translate="MAKE_RECURRING_ORDER") .group.mt-10.recurring-buy(ng-if="state.frequencyCheck && !trading().isDisabled && checkoutForm.fiat.$viewValue <= $ctrl.recurringBuyLimit()") .group span.colon.f-13.em-500(translate="FREQUENCY") diff --git a/assets/js/components/exchange/exchange-checkout.component.js b/assets/js/components/exchange/exchange-checkout.component.js index 9c2dd1e5e2..ffe3b9718e 100644 --- a/assets/js/components/exchange/exchange-checkout.component.js +++ b/assets/js/components/exchange/exchange-checkout.component.js @@ -28,7 +28,7 @@ angular controllerAs: '$ctrl' }); -function ExchangeCheckoutController (Env, AngularHelper, $scope, $rootScope, $timeout, $q, currency, Wallet, MyWalletHelpers, modals, $uibModal, formatTrade, recurringTrade, Exchange) { +function ExchangeCheckoutController (Env, AngularHelper, $scope, $rootScope, $timeout, $q, currency, Wallet, MyWalletHelpers, modals, $uibModal, formatTrade, recurringTrade, Exchange, MyWallet) { $scope.date = new Date(); $scope.toSatoshi = currency.convertToSatoshi; $scope.format = currency.formatCurrencyForView; @@ -175,7 +175,7 @@ function ExchangeCheckoutController (Env, AngularHelper, $scope, $rootScope, $ti Env.then(env => { $scope.qaDebugger = env.qaDebugger; - this.showRecurringBuy = env.partners.coinify.showRecurringBuy; + this.showRecurringBuy = env.partners.coinify.showRecurringBuy && MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK'; }); $scope.$on('$destroy', $scope.cancelRefresh); AngularHelper.installLock.call($scope); diff --git a/assets/js/controllers/coinify/coinifyCheckout.controller.js b/assets/js/controllers/coinify/coinifyCheckout.controller.js index f5d63c7cd4..a68b0014d0 100644 --- a/assets/js/controllers/coinify/coinifyCheckout.controller.js +++ b/assets/js/controllers/coinify/coinifyCheckout.controller.js @@ -42,7 +42,7 @@ function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, Angul $scope.pendingTrades = () => coinify.trades.filter((t) => coinify.tradeStateIn(coinify.states.pending)(t) && !t.tradeSubscriptionId); $scope.completedTrades = () => coinify.trades.filter((t) => coinify.tradeStateIn(coinify.states.completed)(t) && !t.tradeSubscriptionId); $scope.recurringTrades = () => coinify.trades.filter((t) => t.tradeSubscriptionId); - $scope.frequencyOptions = coinify.buyReason === 'user_needs_account' || !coinify.trades.length ? ['Weekly', 'Monthly'] : ['Daily', 'Weekly', 'Monthly']; + $scope.frequencyOptions = coinify.buyReason === 'user_needs_account' || ['Weekly', 'Monthly']; $scope.hasDismissedRecurringBuyIntro = () => localStorageService.get('dismissedRecurringBuyIntro'); $scope.dismissRecurringBuyIntro = () => localStorageService.set('dismissedRecurringBuyIntro', true); @@ -58,14 +58,16 @@ function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, Angul $state.params.selectedTab = this.selectedTab; } }; - $scope.showRecurringBuy = env.partners.coinify.showRecurringBuy; + $scope.showRecurringBuy = MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK' && env.partners.coinify.showRecurringBuy; if (env.qaDebugger) { $scope.qaDebugger = env.qaDebugger; - $scope.frequencyOptions = ['Hourly', 'Daily', 'Weekly', 'Monthly']; + $scope.frequencyOptions = ['Hourly', 'Weekly', 'Monthly']; } }); + $scope.goToFaq = () => $state.go('wallet.common.faq'); + coinify.pollUserLevel(); AngularHelper.installLock.call($scope); } diff --git a/locales/en-human.json b/locales/en-human.json index c4918061ce..d4a2497d02 100644 --- a/locales/en-human.json +++ b/locales/en-human.json @@ -2116,10 +2116,14 @@ "TITLE": "Feature Disabled", "BODY": "This feature has been temporarily disabled. Please check back later when we are back up and running!" }, - "RECURRING_INTRO_HEADER": "Introducing Recurring Orders", - "RECURRING_INTRO_1": "You can now create recurring bitcoin purchases from within your wallet.", + "RECURRING_INTRO_HEADER": "About Recurring Orders", + "RECURRING_INTRO_1": "You can now create recurring bitcoin purchases from within your wallet after verifying your account.", "RECURRING_INTRO_2": "Select 'Make this a recurring order', set your recurring preferences, and continue with your purchase as normal. Each time an order is processed you will receive an email to notify you.", - "RECURRING_INTRO_3": "Recurring orders can be canceled at anytime.", + "RECURRING_INTRO_3": "Recurring orders can be canceled at anytime from", + "RECURRING_INTRO_4": "Want to know more about Recurring Orders?", + "ORDERS": "Orders.", + "LEARN_MORE_HERE": "Learn more here.", + "MAKE_RECURRING_ORDER": "Make this a recurring order", "FINISH_PAYMENT": "Finish Payment", "SUBSCRIPTION_ID": "Recurring Order ID", "RECURRING_BUY": "Recurring Buy", From b0037e1f406c7979d2fb3841b6aa3b3311964f03 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Mon, 9 Apr 2018 10:50:48 -0400 Subject: [PATCH 02/19] feat(Recurring Buy): use new tradeSubscriptionsAllowed flag --- app/partials/coinify-modal.pug | 1 + app/partials/coinify/checkout.pug | 1 + assets/js/components/exchange/exchange-checkout.component.js | 3 ++- assets/js/controllers/coinify/coinifyCheckout.controller.js | 2 +- assets/js/routes.js | 2 +- 5 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/partials/coinify-modal.pug b/app/partials/coinify-modal.pug index dd2ecb18e1..1e138e243b 100644 --- a/app/partials/coinify-modal.pug +++ b/app/partials/coinify-modal.pug @@ -15,6 +15,7 @@ span(ng-if="vm.trade && vm.trade.sendAmount") ({{ vm.trade.sendAmount / 100 | format }} {{ vm.trade.inCurrency }}) countdown.mid-grey(ng-if="vm.quote && vm.quote.id && vm.medium !== 'bank'" time-to-expiration="vm.timeToExpiration" on-expiration="vm.refreshQuote()" debug="vm.qaDebugger" message="'RATE_GUARANTEED'") countdown.mid-grey(ng-if="vm.trade && vm.trade.expiresAt && !vm.state.trade.expired && vm.trade.medium !== 'bank'" time-to-expiration="vm.timeToExpiration" on-expiration="vm.expireTrade()" debug="vm.qaDebugger" message="'RATE_GUARANTEED'") + //- coinify-recurring-confirm(ng-if="vm.onStep('confirmRecurring')" on-complete="vm.goTo()") coinify-email(ng-if="vm.onStep('email')" on-complete="vm.goTo('signup')" on-close="vm.close(0)" email="vm.user.email" valid-email="vm.state.email.valid" verified="vm.user.isEmailVerified" on-email-change="vm.onEmailChange(true)") coinify-signup(ng-if="vm.onStep('signup')" on-complete="vm.onSignupComplete()" on-error="vm.goTo('email')" on-close="vm.close(0)" email="vm.user.email" valid-email="vm.state.email.valid" on-email-change="vm.onEmailChange(false)" fiat-currency="vm.fiatCurrency()") div(ng-if="vm.onStep('select-payment-medium')" ng-controller="CoinifyMediumController" ng-include="'partials/coinify/medium.pug'") diff --git a/app/partials/coinify/checkout.pug b/app/partials/coinify/checkout.pug index d82761746e..dd9c04b0e7 100644 --- a/app/partials/coinify/checkout.pug +++ b/app/partials/coinify/checkout.pug @@ -20,6 +20,7 @@ bc-tabs(tab="tabs.selectedTab" tab-options="tabs.options" on-select="tabs.select frequencies="frequencyOptions" on-success="buyHandler(quote, null, frequency, endTime)" recurring-buy-limit="recurringBuyLimit()" + show-recurring="showRecurringBuy" handle-quote="buyQuoteHandler(amount, baseCurr, quoteCurr)") .flex-column.ml-60.col-md-5.col-sm-12.col-xs-12.pln.prn.pv-10-mobile.no-margin-mobile.hidden-xs .mb-20(ng-show="showRecurringBuy && !hasDismissedRecurringBuyIntro()") diff --git a/assets/js/components/exchange/exchange-checkout.component.js b/assets/js/components/exchange/exchange-checkout.component.js index ffe3b9718e..ee3c1901c1 100644 --- a/assets/js/components/exchange/exchange-checkout.component.js +++ b/assets/js/components/exchange/exchange-checkout.component.js @@ -17,6 +17,7 @@ angular fiatOptions: '<', frequencies: '<', collapseSummary: '<', + showRecurring: '<', recurringBuyLimit: '&', onSuccess: '&', fiatChange: '&', @@ -175,7 +176,7 @@ function ExchangeCheckoutController (Env, AngularHelper, $scope, $rootScope, $ti Env.then(env => { $scope.qaDebugger = env.qaDebugger; - this.showRecurringBuy = env.partners.coinify.showRecurringBuy && MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK'; + this.showRecurringBuy = this.showRecurring; }); $scope.$on('$destroy', $scope.cancelRefresh); AngularHelper.installLock.call($scope); diff --git a/assets/js/controllers/coinify/coinifyCheckout.controller.js b/assets/js/controllers/coinify/coinifyCheckout.controller.js index a68b0014d0..9f03262957 100644 --- a/assets/js/controllers/coinify/coinifyCheckout.controller.js +++ b/assets/js/controllers/coinify/coinifyCheckout.controller.js @@ -58,7 +58,7 @@ function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, Angul $state.params.selectedTab = this.selectedTab; } }; - $scope.showRecurringBuy = MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK' && env.partners.coinify.showRecurringBuy; + $scope.showRecurringBuy = MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK' && env.partners.coinify.showRecurringBuy && $scope.exchange.profile.tradeSubscriptionsAllowed; if (env.qaDebugger) { $scope.qaDebugger = env.qaDebugger; diff --git a/assets/js/routes.js b/assets/js/routes.js index e08cd89754..773024bc6a 100644 --- a/assets/js/routes.js +++ b/assets/js/routes.js @@ -264,7 +264,7 @@ function AppRouter ($stateProvider, $urlRouterProvider) { accounts ($injector, $q) { let MyWallet = $injector.has('MyWallet') && $injector.get('MyWallet'); let sfox = MyWallet.wallet && MyWallet.wallet.external && MyWallet.wallet.external.sfox; - + return sfox && sfox.hasAccount ? $q.resolve([]) .then(() => sfox.getBuyMethods()).catch(console.log) From 746b4b3a99927837e4b9882c77b7f5abe97398ae Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Mon, 9 Apr 2018 12:12:11 -0400 Subject: [PATCH 03/19] feat(Recurring Buy): set up confirm modal --- app/partials/coinify-modal.pug | 4 ++-- app/partials/coinify/recurring-confirm.pug | 9 +++++++++ .../coinify/recurring-confirm.component.js | 18 ++++++++++++++++++ .../controllers/coinify/coinify.controller.js | 5 +++-- locales/en-human.json | 4 ++++ 5 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 app/partials/coinify/recurring-confirm.pug create mode 100644 assets/js/components/coinify/recurring-confirm.component.js diff --git a/app/partials/coinify-modal.pug b/app/partials/coinify-modal.pug index 1e138e243b..2a34271a34 100644 --- a/app/partials/coinify-modal.pug +++ b/app/partials/coinify-modal.pug @@ -1,4 +1,5 @@ -#buy(ng-class="{rendered:rendered}" data-preflight-tag="BuyModal") +coinify-recurring-confirm(ng-if="vm.onStep('confirm-recurring')" end-time="vm.endTime" frequency="vm.frequency" on-proceed="vm.goTo('select-payment-medium')" on-cancel="vm.cancel()") +#buy(ng-if="!vm.onStep('confirm-recurring')" ng-class="{rendered:rendered}" data-preflight-tag="BuyModal") .modal-header.bc-modal-header.flex-between.flex-center(ng-class="{'no-border': isPendingBankTransfer()}") .flex-1(ng-class="inMobileBuy ? 'flex-row-reverse flex-center flex-between' : 'flex-column'") .flex-row.flex-between.flex-center @@ -15,7 +16,6 @@ span(ng-if="vm.trade && vm.trade.sendAmount") ({{ vm.trade.sendAmount / 100 | format }} {{ vm.trade.inCurrency }}) countdown.mid-grey(ng-if="vm.quote && vm.quote.id && vm.medium !== 'bank'" time-to-expiration="vm.timeToExpiration" on-expiration="vm.refreshQuote()" debug="vm.qaDebugger" message="'RATE_GUARANTEED'") countdown.mid-grey(ng-if="vm.trade && vm.trade.expiresAt && !vm.state.trade.expired && vm.trade.medium !== 'bank'" time-to-expiration="vm.timeToExpiration" on-expiration="vm.expireTrade()" debug="vm.qaDebugger" message="'RATE_GUARANTEED'") - //- coinify-recurring-confirm(ng-if="vm.onStep('confirmRecurring')" on-complete="vm.goTo()") coinify-email(ng-if="vm.onStep('email')" on-complete="vm.goTo('signup')" on-close="vm.close(0)" email="vm.user.email" valid-email="vm.state.email.valid" verified="vm.user.isEmailVerified" on-email-change="vm.onEmailChange(true)") coinify-signup(ng-if="vm.onStep('signup')" on-complete="vm.onSignupComplete()" on-error="vm.goTo('email')" on-close="vm.close(0)" email="vm.user.email" valid-email="vm.state.email.valid" on-email-change="vm.onEmailChange(false)" fiat-currency="vm.fiatCurrency()") div(ng-if="vm.onStep('select-payment-medium')" ng-controller="CoinifyMediumController" ng-include="'partials/coinify/medium.pug'") diff --git a/app/partials/coinify/recurring-confirm.pug b/app/partials/coinify/recurring-confirm.pug new file mode 100644 index 0000000000..8e2652d4b9 --- /dev/null +++ b/app/partials/coinify/recurring-confirm.pug @@ -0,0 +1,9 @@ +.pv-25.ph-25 + .flex-column + span.f-18.mb-15.em-400(translate="RECURRING_CONFIRM_HEADER") + span.f-14.em-300(ng-if="$ctrl.endTime" translate="RECURRING_CONFIRM_BODY_WITH_ENDTIME" translate-values="{timing: $ctrl.recurringTiming(), end: $ctrl.endTime.toDateString()}") + span.f-14.em-300(ng-if="!$ctrl.endTime" translate="RECURRING_CONFIRM_BODY" translate-values="{timing: $ctrl.recurringTiming()}") +.modal-footer.flex-end.flex-row + .flex-1.flex-end + button.button-muted.mrm(ng-click="$ctrl.onCancel()" translate="GO_BACK") + button.button-primary(translate="PROCEED_WITH_MY_ORDER" ng-click="$ctrl.onProceed()") diff --git a/assets/js/components/coinify/recurring-confirm.component.js b/assets/js/components/coinify/recurring-confirm.component.js new file mode 100644 index 0000000000..62c63dbbc4 --- /dev/null +++ b/assets/js/components/coinify/recurring-confirm.component.js @@ -0,0 +1,18 @@ +angular + .module('walletApp') + .component('coinifyRecurringConfirm', { + bindings: { + frequency: '<', + endTime: '<', + onCancel: '&', + onProceed: '&' + }, + templateUrl: 'partials/coinify/recurring-confirm.pug', + controller: CoinifyRecurringConfirmController, + controllerAs: '$ctrl' + }); + +function CoinifyRecurringConfirmController (recurringTrade) { + this.date = new Date() + this.recurringTiming = () => recurringTrade.getTimespan(this.date, this.frequency); +} diff --git a/assets/js/controllers/coinify/coinify.controller.js b/assets/js/controllers/coinify/coinify.controller.js index c7e38034d5..334dd8015a 100644 --- a/assets/js/controllers/coinify/coinify.controller.js +++ b/assets/js/controllers/coinify/coinify.controller.js @@ -102,8 +102,9 @@ function CoinifyController ($rootScope, $scope, $q, $state, $timeout, $uibModalI this.onStep = (...steps) => steps.some(s => this.step === this.steps[s]); this.currentStep = () => Object.keys(this.steps).filter(this.onStep)[0]; this.goTo = (step) => this.step = this.steps[step]; - - if (!this.user.isEmailVerified && !this.exchange.user) { + if (frequency) { + this.goTo('confirm-recurring') + } else if (!this.user.isEmailVerified && !this.exchange.user) { this.goTo('email'); } else if (!this.exchange.user) { this.goTo('signup'); diff --git a/locales/en-human.json b/locales/en-human.json index d4a2497d02..a8051744fd 100644 --- a/locales/en-human.json +++ b/locales/en-human.json @@ -2121,6 +2121,10 @@ "RECURRING_INTRO_2": "Select 'Make this a recurring order', set your recurring preferences, and continue with your purchase as normal. Each time an order is processed you will receive an email to notify you.", "RECURRING_INTRO_3": "Recurring orders can be canceled at anytime from", "RECURRING_INTRO_4": "Want to know more about Recurring Orders?", + "RECURRING_CONFIRM_HEADER": "You're About To Set Up A Recurring Order", + "RECURRING_CONFIRM_BODY_WITH_ENDTIME": "This Recurring Order will happen today and every {{::timing}} until {{::end}} or you reach your limit, whichever happens first.", + "RECURRING_CONFIRM_BODY": "This Recurring Order will happen today and every {{::timing}} until you cancel or reach your limit, whichever happens first.", + "PROCEED_WITH_MY_ORDER": "Proceed with my Order", "ORDERS": "Orders.", "LEARN_MORE_HERE": "Learn more here.", "MAKE_RECURRING_ORDER": "Make this a recurring order", From 6812de0e91a84f32431d847d81923f4b308ae862 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Mon, 9 Apr 2018 15:19:04 -0400 Subject: [PATCH 04/19] feat(Recurring Buy): adds cancel button; fix step logic --- app/partials/trade-summary.pug | 4 ++-- app/templates/exchange/recurring-trades.pug | 5 +++-- app/templates/exchange/recurring.pug | 19 +++++++++++++++---- .../exchange/exchange-recurring.component.js | 3 ++- .../controllers/coinify/coinify.controller.js | 3 ++- locales/en-human.json | 7 +++++++ 6 files changed, 31 insertions(+), 10 deletions(-) diff --git a/app/partials/trade-summary.pug b/app/partials/trade-summary.pug index fae2dbdfd6..ff3cae5ef6 100644 --- a/app/partials/trade-summary.pug +++ b/app/partials/trade-summary.pug @@ -7,14 +7,14 @@ label.em-500.flex-start.mb-15(ng-hide="isPendingBankTransfer && isPendingBankTransfer()" translate="{{isKYC || needsKyc() ? 'DETAILS' : 'ORDER_DETAILS'}}") ul.em-300.bg-grey.border-top.pan.mb-15(ng-class="{'bank-transfer': isPendingBankTransfer && isPendingBankTransfer()}") li.pam.border-right.border-left.border-bottom-light.flex-between(ng-repeat="(prop, val) in formattedTrade.tx track by $index" ng-if="val") - span.em-300.colon(translate="{{prop}}" ng-class="{'em-500': prop === 'TOTAL_COST'}") + span.em-300(translate="{{prop}}" ng-class="{'em-500': prop === 'TOTAL_COST'}") span.em-300.right-align.capitalize(ng-bind="val" ng-class="{'em-500': prop === 'TOTAL_COST', 'capitalize' : prop !== 'RECEIVING_ADDRESS'}") span.security-red.plm(ng-if="$last && isPendingBankTransfer()" translate="ORDER_ID_REFERENCE") p.security-red.pointer.ng-hide(ng-show="vm.qaDebugger && vm.trade.bankAccount && vm.trade.state === 'awaiting_transfer_in'") i.ti-search.mrm span(ng-click="fakeBankTransfer()" translate="QA: Click here to fake a bank transfer") .mtm - exchange-recurring(ng-if="vm.frequency" frequency="vm.frequency" end-time="vm.endTime" t="trade" dollars="dollars") + exchange-recurring(ng-if="vm.frequency" frequency="vm.frequency" end-time="vm.endTime" t="trade" dollars="dollars" on-close="$close()") .flex-row.flex-between.pt-20 .flex-start.flex-center a(ng-show="tradeIsPending()" ng-click="editRef()" ng-class="{ 'link-disabled mid-grey': disableLink }" translate="EDIT_REF") diff --git a/app/templates/exchange/recurring-trades.pug b/app/templates/exchange/recurring-trades.pug index 79bf6ae8f8..492e659ab7 100644 --- a/app/templates/exchange/recurring-trades.pug +++ b/app/templates/exchange/recurring-trades.pug @@ -3,6 +3,7 @@ span.pl-25.ph-10-mobile.flex-row.flex-center.pointer(ng-click="state.toggled = !state.toggled") i.icon-down_arrow.f-8.mr-5(ng-class="{rotated: !state.toggled}") span(class="{{$ctrl.subscription.isActive ? 'transfer' : 'state-danger-text'}}") {{ $ctrl.subscription.isActive ? 'Active' : 'Inactive' }} + a.em-400(translate="MANAGE_THIS_ORDER" ng-click="state.toggled = !state.toggled" ng-class="{'opacity-5': state.toggled}") .exchange-date.pv-15 span.capitalize {{ $ctrl.subscription.frequency }} .exchange-exchanged.pv-15 @@ -36,5 +37,5 @@ span {{ trade.sendAmount / 100 }} {{ trade.inCurrency }} span(ng-if="canCancel(trade)") i.ti-trash.mls.pointer.state-danger-text(ng-click="cancelTrade(trade); $event.stopPropagation();" ng-show="canCancel" uib-tooltip="{{'CLICK_TO_CANCEL' | translate}}") - .width-100.flex-end(ng-show="state.toggled") - .span.pv-15.state-danger-text.pointer(ng-show="$ctrl.subscription.isActive" ng-click="cancel()") Cancel Recurring Order + .width-100.flex-end.mv-20(ng-show="state.toggled") + .button-danger.f-13(ng-show="$ctrl.subscription.isActive" ng-click="cancel()" translate="CANCEL_RECURRING_ORDER") diff --git a/app/templates/exchange/recurring.pug b/app/templates/exchange/recurring.pug index 482c7108dc..3a44bc6a0c 100644 --- a/app/templates/exchange/recurring.pug +++ b/app/templates/exchange/recurring.pug @@ -1,14 +1,25 @@ .flex-row.flex-between.mbm - span.primary.em-500 This is a Recurring Order + div + span.primary.em-500 This is a Recurring Order + helper-button(content="RECURRING_HELPER") a.em-300.text-danger.underline(ng-show="$ctrl.showRemove" ng-click="$ctrl.onRemove()") Remove Recurring Order .pam.bg-ultralight-blue.border-light-blue - .flex-row.pam + .mv-5.phm(ng-hide="$ctrl.trade") + span.f-13(translate="RECURRING_REMINDER" translate-values="{time: $ctrl.frequency}") + .flex-row.phm.pv-5 span.flex-1.primary.colon(translate="AMOUNT") span.flex-5.ph-5-mobile {{ format($ctrl.trade.fiatAmount, $ctrl.dollars, true) }} - .flex-row.pam + .flex-row.phm.pv-5 span.flex-1.primary.colon(translate="FREQUENCY") span.flex-5.ph-5-mobile(translate="FREQUENCY_INFO" translate-values="{timespan: timespan}") - .flex-row.pam + .flex-row.phm.pv-5 span.flex-1.primary.colon(translate="DURATION") span.flex-5.ph-5-mobile(ng-show="endTime" translate="DURATION_INFO" translate-values="{endTime: endTime}") span.flex-5.ph-5-mobile(ng-show="!endTime") Until you cancel or reach your limit, whichever happens first. +.flex-column.mtm(ng-if="$ctrl.trade.state === 'completed'") + .mb-10 + span.f-12(translate="RECURRING_EMAIL_RECEIVE") + a(ng-click="$ctrl.onClose()")  Orders  + span.f-12(translate="TAB") + div + span.f-12(translate="AMOUNT_VARIATION_NOTE") diff --git a/assets/js/components/exchange/exchange-recurring.component.js b/assets/js/components/exchange/exchange-recurring.component.js index 99df274e44..b027be3166 100644 --- a/assets/js/components/exchange/exchange-recurring.component.js +++ b/assets/js/components/exchange/exchange-recurring.component.js @@ -7,7 +7,8 @@ angular endTime: '<', frequency: '<', showRemove: '<', - onRemove: '&' + onRemove: '&', + onClose: '&' }, templateUrl: 'templates/exchange/recurring.pug', controller: ExchangeRecurringController, diff --git a/assets/js/controllers/coinify/coinify.controller.js b/assets/js/controllers/coinify/coinify.controller.js index 334dd8015a..50688f4bb6 100644 --- a/assets/js/controllers/coinify/coinify.controller.js +++ b/assets/js/controllers/coinify/coinify.controller.js @@ -102,7 +102,8 @@ function CoinifyController ($rootScope, $scope, $q, $state, $timeout, $uibModalI this.onStep = (...steps) => steps.some(s => this.step === this.steps[s]); this.currentStep = () => Object.keys(this.steps).filter(this.onStep)[0]; this.goTo = (step) => this.step = this.steps[step]; - if (frequency) { + + if (frequency && this.quote) { this.goTo('confirm-recurring') } else if (!this.user.isEmailVerified && !this.exchange.user) { this.goTo('email'); diff --git a/locales/en-human.json b/locales/en-human.json index a8051744fd..a9710e53d0 100644 --- a/locales/en-human.json +++ b/locales/en-human.json @@ -2128,6 +2128,13 @@ "ORDERS": "Orders.", "LEARN_MORE_HERE": "Learn more here.", "MAKE_RECURRING_ORDER": "Make this a recurring order", + "RECURRING_HELPER": "Recurring Orders will be placed automatically on a regular basis from your linked credit card", + "RECURRING_REMINDER": "You are about to set up a {{time}} Recurring Order. To cancel a Recurring Order, visit the Order History tab.", + "RECURRING_EMAIL_RECEIVE": "You will receive an email each time an order is completed. You can check or cancel your orders at any time in your", + "TAB": "tab", + "AMOUNT_VARIATION_NOTE": "Note: The amount of bitcoin purchased will vary each time depending on the market price.", + "MANAGE_THIS_ORDER": "Manage This Order", + "CANCEL_RECURRING_ORDER": "Cancel Recurring Order", "FINISH_PAYMENT": "Finish Payment", "SUBSCRIPTION_ID": "Recurring Order ID", "RECURRING_BUY": "Recurring Buy", From 02f44663dc4620175b3aab4ee9fcf89d79ee0891 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Mon, 9 Apr 2018 17:24:15 -0400 Subject: [PATCH 05/19] feat(Recurring Buy): flow for user without KYC --- app/partials/coinify-modal.pug | 2 +- app/partials/coinify/checkout.pug | 1 + app/partials/coinify/recurring-confirm.pug | 11 +++++++---- app/partials/coinify/summary.pug | 2 +- app/templates/exchange/recurring.pug | 2 +- .../components/coinify/recurring-confirm.component.js | 2 ++ .../exchange/exchange-recurring.component.js | 1 + assets/js/controllers/coinify/coinify.controller.js | 2 ++ .../controllers/coinify/coinifyCheckout.controller.js | 2 +- locales/en-human.json | 3 +++ 10 files changed, 20 insertions(+), 8 deletions(-) diff --git a/app/partials/coinify-modal.pug b/app/partials/coinify-modal.pug index 2a34271a34..2e5fc45b0f 100644 --- a/app/partials/coinify-modal.pug +++ b/app/partials/coinify-modal.pug @@ -1,4 +1,4 @@ -coinify-recurring-confirm(ng-if="vm.onStep('confirm-recurring')" end-time="vm.endTime" frequency="vm.frequency" on-proceed="vm.goTo('select-payment-medium')" on-cancel="vm.cancel()") +coinify-recurring-confirm(ng-if="vm.onStep('confirm-recurring')" end-time="vm.endTime" frequency="vm.frequency" on-proceed="vm.needsKYCForRecurring ? vm.triggerKYCForRecurring() : vm.goTo('select-payment-medium')" on-cancel="vm.cancel()" exchange="vm.exchange" needs-kyc="vm.needsKYCForRecurring") #buy(ng-if="!vm.onStep('confirm-recurring')" ng-class="{rendered:rendered}" data-preflight-tag="BuyModal") .modal-header.bc-modal-header.flex-between.flex-center(ng-class="{'no-border': isPendingBankTransfer()}") .flex-1(ng-class="inMobileBuy ? 'flex-row-reverse flex-center flex-between' : 'flex-column'") diff --git a/app/partials/coinify/checkout.pug b/app/partials/coinify/checkout.pug index dd9c04b0e7..76f1ef88d5 100644 --- a/app/partials/coinify/checkout.pug +++ b/app/partials/coinify/checkout.pug @@ -23,6 +23,7 @@ bc-tabs(tab="tabs.selectedTab" tab-options="tabs.options" on-select="tabs.select show-recurring="showRecurringBuy" handle-quote="buyQuoteHandler(amount, baseCurr, quoteCurr)") .flex-column.ml-60.col-md-5.col-sm-12.col-xs-12.pln.prn.pv-10-mobile.no-margin-mobile.hidden-xs + exchange-recurring(ng-if="scheduledRecurring" frequency="vm.frequency" end-time="vm.endTime" t="trade" dollars="dollars" payment-fee="trade.fee") .mb-20(ng-show="showRecurringBuy && !hasDismissedRecurringBuyIntro()") .flex-between span.f-24.blue.f-14-mobile diff --git a/app/partials/coinify/recurring-confirm.pug b/app/partials/coinify/recurring-confirm.pug index 8e2652d4b9..c1327a5d14 100644 --- a/app/partials/coinify/recurring-confirm.pug +++ b/app/partials/coinify/recurring-confirm.pug @@ -1,9 +1,12 @@ .pv-25.ph-25 .flex-column - span.f-18.mb-15.em-400(translate="RECURRING_CONFIRM_HEADER") - span.f-14.em-300(ng-if="$ctrl.endTime" translate="RECURRING_CONFIRM_BODY_WITH_ENDTIME" translate-values="{timing: $ctrl.recurringTiming(), end: $ctrl.endTime.toDateString()}") - span.f-14.em-300(ng-if="!$ctrl.endTime" translate="RECURRING_CONFIRM_BODY" translate-values="{timing: $ctrl.recurringTiming()}") + span.f-18.mb-15.em-400(ng-hide="$ctrl.needsKyc" translate="RECURRING_CONFIRM_HEADER") + span.f-18.mb-15.em-400(ng-show="$ctrl.needsKyc" translate="RECURRING_CONFIRM_NEED_IDENTITY_HEADER") + span.f-14.em-300(ng-if="$ctrl.endTime && !$ctrl.needsKyc" translate="RECURRING_CONFIRM_BODY_WITH_ENDTIME" translate-values="{timing: $ctrl.recurringTiming(), end: $ctrl.endTime.toDateString()}") + span.f-14.em-300(ng-if="!$ctrl.endTime && !$ctrl.needsKyc" translate="RECURRING_CONFIRM_BODY" translate-values="{timing: $ctrl.recurringTiming()}") + span.f-14.em-300(ng-if="$ctrl.needsKyc" translate="RECURRING_CONFIRM_NEED_IDENTITY_BODY") .modal-footer.flex-end.flex-row .flex-1.flex-end button.button-muted.mrm(ng-click="$ctrl.onCancel()" translate="GO_BACK") - button.button-primary(translate="PROCEED_WITH_MY_ORDER" ng-click="$ctrl.onProceed()") + button.button-primary(ng-if="!$ctrl.needsKyc" translate="PROCEED_WITH_MY_ORDER" ng-click="$ctrl.onProceed()") + button.button-primary(ng-if="$ctrl.needsKyc" translate="PROCEED_TO_KYC" ng-click="$ctrl.onProceed()") diff --git a/app/partials/coinify/summary.pug b/app/partials/coinify/summary.pug index 43428e9694..8ab3930878 100644 --- a/app/partials/coinify/summary.pug +++ b/app/partials/coinify/summary.pug @@ -56,7 +56,7 @@ form.bc-form.modal-body.fade.clearfix(id="summaryForm" name="summaryForm" role=" div label.mlm.em-300(translate="ACCEPT_COINIFY_RATE" for="rate") .mtl - exchange-recurring(ng-if="vm.frequency" frequency="vm.frequency" end-time="vm.endTime" t="trade" dollars="dollars" show-remove="state.editAmount" on-remove="vm.cancelSubscription()") + exchange-recurring(ng-if="vm.frequency" frequency="vm.frequency" end-time="vm.endTime" t="trade" dollars="dollars" show-remove="state.editAmount" on-remove="vm.cancelSubscription()" payment-fee="trade.fee") .flex-row.flex-between.pt-20 button.button-muted(type="button" ng-hide="inMobileBuy" ng-click="vm.goTo('select-payment-medium')" translate="GO_BACK") button.button-primary(type="submit" form="summaryForm" ng-disabled="summaryForm.$invalid || locked" translate="{{state.editAmount ? 'UPDATE' : 'CONFIRM'}}") diff --git a/app/templates/exchange/recurring.pug b/app/templates/exchange/recurring.pug index 3a44bc6a0c..9006d4f864 100644 --- a/app/templates/exchange/recurring.pug +++ b/app/templates/exchange/recurring.pug @@ -8,7 +8,7 @@ span.f-13(translate="RECURRING_REMINDER" translate-values="{time: $ctrl.frequency}") .flex-row.phm.pv-5 span.flex-1.primary.colon(translate="AMOUNT") - span.flex-5.ph-5-mobile {{ format($ctrl.trade.fiatAmount, $ctrl.dollars, true) }} + span.flex-5.ph-5-mobile {{ format($ctrl.trade.fiatAmount, $ctrl.dollars, true) }} (+ {{ $ctrl.paymentFee | format }} {{ $ctrl.dollars.code }} Payment Fee) .flex-row.phm.pv-5 span.flex-1.primary.colon(translate="FREQUENCY") span.flex-5.ph-5-mobile(translate="FREQUENCY_INFO" translate-values="{timespan: timespan}") diff --git a/assets/js/components/coinify/recurring-confirm.component.js b/assets/js/components/coinify/recurring-confirm.component.js index 62c63dbbc4..d4d6cbc0ca 100644 --- a/assets/js/components/coinify/recurring-confirm.component.js +++ b/assets/js/components/coinify/recurring-confirm.component.js @@ -4,6 +4,8 @@ angular bindings: { frequency: '<', endTime: '<', + exchange: '<', + needsKyc: '<', onCancel: '&', onProceed: '&' }, diff --git a/assets/js/components/exchange/exchange-recurring.component.js b/assets/js/components/exchange/exchange-recurring.component.js index b027be3166..827199c679 100644 --- a/assets/js/components/exchange/exchange-recurring.component.js +++ b/assets/js/components/exchange/exchange-recurring.component.js @@ -7,6 +7,7 @@ angular endTime: '<', frequency: '<', showRemove: '<', + paymentFee: '<', onRemove: '&', onClose: '&' }, diff --git a/assets/js/controllers/coinify/coinify.controller.js b/assets/js/controllers/coinify/coinify.controller.js index 50688f4bb6..c67bce0aba 100644 --- a/assets/js/controllers/coinify/coinify.controller.js +++ b/assets/js/controllers/coinify/coinify.controller.js @@ -21,6 +21,8 @@ function CoinifyController ($rootScope, $scope, $q, $state, $timeout, $uibModalI this.fiatAmount = () => this.baseFiat() ? Math.abs(this.quote.baseAmount) : Math.abs(this.quote.quoteAmount); this.transactionFee = () => this.mediums ? this.mediums[this.medium || 'card'].outFixedFees['BTC'] * 1e8 : 0; this.timeToExpiration = () => this.quote ? this.quote.expiresAt - this.now() : this.trade.expiresAt - this.now(); + this.needsKYCForRecurring = this.exchange.profile.level && this.exchange.profile.level.name < 2 + this.triggerKYCForRecurring = () => { coinify.getOpenKYC(); this.trade = exchange.kycs[0]; this.goTo('isx') } this.refreshQuote = () => { if (this.baseFiat()) return $q.resolve(coinify.getQuote(this.fiatAmount() * 100, this.quote.baseCurrency)).then((q) => this.quote = q); else return $q.resolve(coinify.getQuote(this.BTCAmount(), this.quote.baseCurrency, this.quote.quoteCurrency)).then((q) => this.quote = q); diff --git a/assets/js/controllers/coinify/coinifyCheckout.controller.js b/assets/js/controllers/coinify/coinifyCheckout.controller.js index 9f03262957..7ff4f2b182 100644 --- a/assets/js/controllers/coinify/coinifyCheckout.controller.js +++ b/assets/js/controllers/coinify/coinifyCheckout.controller.js @@ -58,7 +58,7 @@ function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, Angul $state.params.selectedTab = this.selectedTab; } }; - $scope.showRecurringBuy = MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK' && env.partners.coinify.showRecurringBuy && $scope.exchange.profile.tradeSubscriptionsAllowed; + $scope.showRecurringBuy = MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK' && env.partners.coinify.showRecurringBuy && $scope.exchange.profile.email; /* && $scope.exchange.profile.tradeSubscriptionsAllowed */ if (env.qaDebugger) { $scope.qaDebugger = env.qaDebugger; diff --git a/locales/en-human.json b/locales/en-human.json index a9710e53d0..a48634aa8b 100644 --- a/locales/en-human.json +++ b/locales/en-human.json @@ -2122,9 +2122,12 @@ "RECURRING_INTRO_3": "Recurring orders can be canceled at anytime from", "RECURRING_INTRO_4": "Want to know more about Recurring Orders?", "RECURRING_CONFIRM_HEADER": "You're About To Set Up A Recurring Order", + "RECURRING_CONFIRM_NEED_IDENTITY_HEADER": "Verify Your Identity", "RECURRING_CONFIRM_BODY_WITH_ENDTIME": "This Recurring Order will happen today and every {{::timing}} until {{::end}} or you reach your limit, whichever happens first.", "RECURRING_CONFIRM_BODY": "This Recurring Order will happen today and every {{::timing}} until you cancel or reach your limit, whichever happens first.", + "RECURRING_CONFIRM_NEED_IDENTITY_BODY": "To set up a recurring order, you first need to verify your identity", "PROCEED_WITH_MY_ORDER": "Proceed with my Order", + "PROCEED_TO_KYC": "Proceed To Verify My Identity", "ORDERS": "Orders.", "LEARN_MORE_HERE": "Learn more here.", "MAKE_RECURRING_ORDER": "Make this a recurring order", From 54d1bbd34c330b5005f16976ce0e6585f5756f56 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 06:48:15 -0400 Subject: [PATCH 06/19] feat(Recurring Buy): disable recurring if pendingKYC; redesign KYC component --- app/partials/coinify/checkout.pug | 1 + app/templates/exchange/checkout.pug | 2 +- app/templates/kyc-status.pug | 11 +++++------ .../exchange/exchange-checkout.component.js | 1 + assets/js/controllers/coinify/coinify.controller.js | 2 +- .../controllers/coinify/coinifyCheckout.controller.js | 1 + 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/partials/coinify/checkout.pug b/app/partials/coinify/checkout.pug index 76f1ef88d5..3f5ee41530 100644 --- a/app/partials/coinify/checkout.pug +++ b/app/partials/coinify/checkout.pug @@ -21,6 +21,7 @@ bc-tabs(tab="tabs.selectedTab" tab-options="tabs.options" on-select="tabs.select on-success="buyHandler(quote, null, frequency, endTime)" recurring-buy-limit="recurringBuyLimit()" show-recurring="showRecurringBuy" + disable-recurring="disableRecurring" handle-quote="buyQuoteHandler(amount, baseCurr, quoteCurr)") .flex-column.ml-60.col-md-5.col-sm-12.col-xs-12.pln.prn.pv-10-mobile.no-margin-mobile.hidden-xs exchange-recurring(ng-if="scheduledRecurring" frequency="vm.frequency" end-time="vm.endTime" t="trade" dollars="dollars" payment-fee="trade.fee") diff --git a/app/templates/exchange/checkout.pug b/app/templates/exchange/checkout.pug index c7384c16d5..500eefe158 100644 --- a/app/templates/exchange/checkout.pug +++ b/app/templates/exchange/checkout.pug @@ -86,7 +86,7 @@ form.bc-form( a(href='mailto:support@sfox.com').f-12 support@sfox.com .group.inline.mt-10(ng-if="$ctrl.frequencies && !trading().isDisabled && $ctrl.showRecurringBuy") .item.inline.check - input(type="checkbox" id="frequencyCheck" name="frequencyCheck" ng-model="state.frequencyCheck" ng-disabled="checkoutForm.fiat.$viewValue > $ctrl.recurringBuyLimit() || $ctrl.recurringBuyLimit() < min.fiat") + input(type="checkbox" id="frequencyCheck" name="frequencyCheck" ng-model="state.frequencyCheck" ng-disabled="checkoutForm.fiat.$viewValue > $ctrl.recurringBuyLimit() || $ctrl.recurringBuyLimit() < min.fiat || $ctrl.disableRecurring") label(for="frequencyCheck" translate="MAKE_RECURRING_ORDER") .group.mt-10.recurring-buy(ng-if="state.frequencyCheck && !trading().isDisabled && checkoutForm.fiat.$viewValue <= $ctrl.recurringBuyLimit()") .group diff --git a/app/templates/kyc-status.pug b/app/templates/kyc-status.pug index 0590eadabf..55d9d59360 100644 --- a/app/templates/kyc-status.pug +++ b/app/templates/kyc-status.pug @@ -1,9 +1,8 @@ -.kyc-status.flex-column.flex-center.flex-justify.border.pbl.ptl.phm(ng-show="$ctrl.getState() && $ctrl.level < 2") +.flex-center.flex-justify.border-light-blue.pbl.ptl.phm(ng-show="$ctrl.getState() && $ctrl.level < 2") div h1.mbn.mtn - i.type-h4(ng-class="$ctrl.getState().i") - .flex-column.flex-center.flex-justify.ph-25 - span.type-h5.mbs.mts(translate="{{$ctrl.getState().ns}}.TITLE") - span.center.type-sm(ng-show="$ctrl.currency" translate="{{$ctrl.getState().ns}}.BODY" translate-values="{ccmax: $ctrl.getCardMax()}") - .flex-center + i.type-h4.primary(ng-class="$ctrl.getState().i") + .flex-column.flex-justify.ph-25 + span.type-h5.em-400.mbs.mts(translate="{{$ctrl.getState().ns}}.TITLE") + span.type-sm(ng-show="$ctrl.currency" translate="{{$ctrl.getState().ns}}.BODY" translate-values="{ccmax: $ctrl.getCardMax()}") a.underline.type-sm.ptm(translate="{{$ctrl.getState().ns}}.LINK" ng-click="$ctrl.onTrigger()") diff --git a/assets/js/components/exchange/exchange-checkout.component.js b/assets/js/components/exchange/exchange-checkout.component.js index ee3c1901c1..88dc5d25fa 100644 --- a/assets/js/components/exchange/exchange-checkout.component.js +++ b/assets/js/components/exchange/exchange-checkout.component.js @@ -18,6 +18,7 @@ angular frequencies: '<', collapseSummary: '<', showRecurring: '<', + disableRecurring: '<', recurringBuyLimit: '&', onSuccess: '&', fiatChange: '&', diff --git a/assets/js/controllers/coinify/coinify.controller.js b/assets/js/controllers/coinify/coinify.controller.js index c67bce0aba..677e030da8 100644 --- a/assets/js/controllers/coinify/coinify.controller.js +++ b/assets/js/controllers/coinify/coinify.controller.js @@ -105,7 +105,7 @@ function CoinifyController ($rootScope, $scope, $q, $state, $timeout, $uibModalI this.currentStep = () => Object.keys(this.steps).filter(this.onStep)[0]; this.goTo = (step) => this.step = this.steps[step]; - if (frequency && this.quote) { + if (frequency && this.quote) { // TODO might need something here if KYC pending this.goTo('confirm-recurring') } else if (!this.user.isEmailVerified && !this.exchange.user) { this.goTo('email'); diff --git a/assets/js/controllers/coinify/coinifyCheckout.controller.js b/assets/js/controllers/coinify/coinifyCheckout.controller.js index 7ff4f2b182..bc6e87a6e8 100644 --- a/assets/js/controllers/coinify/coinifyCheckout.controller.js +++ b/assets/js/controllers/coinify/coinifyCheckout.controller.js @@ -59,6 +59,7 @@ function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, Angul } }; $scope.showRecurringBuy = MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK' && env.partners.coinify.showRecurringBuy && $scope.exchange.profile.email; /* && $scope.exchange.profile.tradeSubscriptionsAllowed */ + $scope.disableRecurring = coinify.getPendingKYC() if (env.qaDebugger) { $scope.qaDebugger = env.qaDebugger; From 64ba9f8d0c81d321facfaed721fa8a9494db46c2 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 08:13:28 -0400 Subject: [PATCH 07/19] feat(Recurring Buy): tooltip to explain recurring orders are disabled --- app/templates/exchange/checkout.pug | 2 +- locales/en-human.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/templates/exchange/checkout.pug b/app/templates/exchange/checkout.pug index 500eefe158..a9b3bd0e36 100644 --- a/app/templates/exchange/checkout.pug +++ b/app/templates/exchange/checkout.pug @@ -87,7 +87,7 @@ form.bc-form( .group.inline.mt-10(ng-if="$ctrl.frequencies && !trading().isDisabled && $ctrl.showRecurringBuy") .item.inline.check input(type="checkbox" id="frequencyCheck" name="frequencyCheck" ng-model="state.frequencyCheck" ng-disabled="checkoutForm.fiat.$viewValue > $ctrl.recurringBuyLimit() || $ctrl.recurringBuyLimit() < min.fiat || $ctrl.disableRecurring") - label(for="frequencyCheck" translate="MAKE_RECURRING_ORDER") + label(for="frequencyCheck" translate="MAKE_RECURRING_ORDER" uib-tooltip="{{'RECURRING_DISABLED_TOOLTIP'|translate}}" tooltip-enable="$ctrl.disableRecurring" tooltip-placement="top") .group.mt-10.recurring-buy(ng-if="state.frequencyCheck && !trading().isDisabled && checkoutForm.fiat.$viewValue <= $ctrl.recurringBuyLimit()") .group span.colon.f-13.em-500(translate="FREQUENCY") diff --git a/locales/en-human.json b/locales/en-human.json index a48634aa8b..32865c2f66 100644 --- a/locales/en-human.json +++ b/locales/en-human.json @@ -2131,6 +2131,7 @@ "ORDERS": "Orders.", "LEARN_MORE_HERE": "Learn more here.", "MAKE_RECURRING_ORDER": "Make this a recurring order", + "RECURRING_DISABLED_TOOLTIP": "Recurring orders are disabled while Identity Verificiation is pending.", "RECURRING_HELPER": "Recurring Orders will be placed automatically on a regular basis from your linked credit card", "RECURRING_REMINDER": "You are about to set up a {{time}} Recurring Order. To cancel a Recurring Order, visit the Order History tab.", "RECURRING_EMAIL_RECEIVE": "You will receive an email each time an order is completed. You can check or cancel your orders at any time in your", From 8d9fd4bc3bcf14f1627ffeb17ee61ad3b7b8284e Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 11:09:43 -0400 Subject: [PATCH 08/19] feat(Recurring Buy): copy for recurring confirm --- app/partials/coinify/recurring-confirm.pug | 15 +++++----- .../coinify/recurring-confirm.component.js | 13 +++++++-- .../controllers/coinify/coinify.controller.js | 2 +- .../coinify/coinifyCheckout.controller.js | 2 +- locales/en-human.json | 28 +++++++++++++++---- 5 files changed, 42 insertions(+), 18 deletions(-) diff --git a/app/partials/coinify/recurring-confirm.pug b/app/partials/coinify/recurring-confirm.pug index c1327a5d14..f9fb3b1eda 100644 --- a/app/partials/coinify/recurring-confirm.pug +++ b/app/partials/coinify/recurring-confirm.pug @@ -1,12 +1,11 @@ .pv-25.ph-25 .flex-column - span.f-18.mb-15.em-400(ng-hide="$ctrl.needsKyc" translate="RECURRING_CONFIRM_HEADER") - span.f-18.mb-15.em-400(ng-show="$ctrl.needsKyc" translate="RECURRING_CONFIRM_NEED_IDENTITY_HEADER") - span.f-14.em-300(ng-if="$ctrl.endTime && !$ctrl.needsKyc" translate="RECURRING_CONFIRM_BODY_WITH_ENDTIME" translate-values="{timing: $ctrl.recurringTiming(), end: $ctrl.endTime.toDateString()}") - span.f-14.em-300(ng-if="!$ctrl.endTime && !$ctrl.needsKyc" translate="RECURRING_CONFIRM_BODY" translate-values="{timing: $ctrl.recurringTiming()}") - span.f-14.em-300(ng-if="$ctrl.needsKyc" translate="RECURRING_CONFIRM_NEED_IDENTITY_BODY") + .f-18.mb-15.em-400 + span.f-18.mb-15.em-400(translate="{{ 'RECURRING_CONFIRM' + '.' + $ctrl.state + '.' + 'HEADER' }}") + .f-14.em-300 + span.f-14.em-300(translate="{{ 'RECURRING_CONFIRM' + '.' + $ctrl.state + '.' + 'BODY' }}" translate-values="{timing: $ctrl.recurringTiming()}") .modal-footer.flex-end.flex-row .flex-1.flex-end - button.button-muted.mrm(ng-click="$ctrl.onCancel()" translate="GO_BACK") - button.button-primary(ng-if="!$ctrl.needsKyc" translate="PROCEED_WITH_MY_ORDER" ng-click="$ctrl.onProceed()") - button.button-primary(ng-if="$ctrl.needsKyc" translate="PROCEED_TO_KYC" ng-click="$ctrl.onProceed()") + button.button-muted.mrm(ng-if="$ctrl.state !== 'NEEDS_TRADES'" ng-click="$ctrl.onCancel()" translate="GO_BACK") + button.button-primary(ng-if="$ctrl.state !== 'NEEDS_TRADES'" translate="{{ 'RECURRING_CONFIRM' + '.' + $ctrl.state + '.' + 'BUTTON' }}" ng-click="$ctrl.onProceed()") + button.button-primary(ng-if="$ctrl.state === 'NEEDS_TRADES'" translate="{{ 'RECURRING_CONFIRM' + '.' + $ctrl.state + '.' + 'BUTTON' }}" ng-click="$ctrl.onCancel()") diff --git a/assets/js/components/coinify/recurring-confirm.component.js b/assets/js/components/coinify/recurring-confirm.component.js index d4d6cbc0ca..2c969aa6c1 100644 --- a/assets/js/components/coinify/recurring-confirm.component.js +++ b/assets/js/components/coinify/recurring-confirm.component.js @@ -14,7 +14,16 @@ angular controllerAs: '$ctrl' }); -function CoinifyRecurringConfirmController (recurringTrade) { - this.date = new Date() +function CoinifyRecurringConfirmController (recurringTrade, coinify) { + this.date = new Date(); this.recurringTiming = () => recurringTrade.getTimespan(this.date, this.frequency); + this.needsMoreTrades = coinify.trades.filter((t) => coinify.tradeStateIn(coinify.states.completed)(t) && !t.tradeSubscriptionId && t.medium === 'card').length < 3; + + const determineState = () => { + if (this.needsKyc && this.needsMoreTrades) return 'NEEDS_KYC_AND_TRADES' + if (this.needsKyc) return 'NEEDS_KYC'; + if (this.needsMoreTrades) return 'NEEDS_TRADES'; + return 'PROCEED'; + } + this.state = determineState(); } diff --git a/assets/js/controllers/coinify/coinify.controller.js b/assets/js/controllers/coinify/coinify.controller.js index 677e030da8..b9474d75dd 100644 --- a/assets/js/controllers/coinify/coinify.controller.js +++ b/assets/js/controllers/coinify/coinify.controller.js @@ -21,7 +21,7 @@ function CoinifyController ($rootScope, $scope, $q, $state, $timeout, $uibModalI this.fiatAmount = () => this.baseFiat() ? Math.abs(this.quote.baseAmount) : Math.abs(this.quote.quoteAmount); this.transactionFee = () => this.mediums ? this.mediums[this.medium || 'card'].outFixedFees['BTC'] * 1e8 : 0; this.timeToExpiration = () => this.quote ? this.quote.expiresAt - this.now() : this.trade.expiresAt - this.now(); - this.needsKYCForRecurring = this.exchange.profile.level && this.exchange.profile.level.name < 2 + this.needsKYCForRecurring = this.exchange.profile.level && this.exchange.profile.level.name < 2; this.triggerKYCForRecurring = () => { coinify.getOpenKYC(); this.trade = exchange.kycs[0]; this.goTo('isx') } this.refreshQuote = () => { if (this.baseFiat()) return $q.resolve(coinify.getQuote(this.fiatAmount() * 100, this.quote.baseCurrency)).then((q) => this.quote = q); diff --git a/assets/js/controllers/coinify/coinifyCheckout.controller.js b/assets/js/controllers/coinify/coinifyCheckout.controller.js index bc6e87a6e8..d1fcea7f9e 100644 --- a/assets/js/controllers/coinify/coinifyCheckout.controller.js +++ b/assets/js/controllers/coinify/coinifyCheckout.controller.js @@ -46,6 +46,7 @@ function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, Angul $scope.hasDismissedRecurringBuyIntro = () => localStorageService.get('dismissedRecurringBuyIntro'); $scope.dismissRecurringBuyIntro = () => localStorageService.set('dismissedRecurringBuyIntro', true); + $scope.disableRecurring = coinify.getPendingKYC(); Env.then(env => { $scope.tabs = { @@ -59,7 +60,6 @@ function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, Angul } }; $scope.showRecurringBuy = MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK' && env.partners.coinify.showRecurringBuy && $scope.exchange.profile.email; /* && $scope.exchange.profile.tradeSubscriptionsAllowed */ - $scope.disableRecurring = coinify.getPendingKYC() if (env.qaDebugger) { $scope.qaDebugger = env.qaDebugger; diff --git a/locales/en-human.json b/locales/en-human.json index 32865c2f66..8cf58c1281 100644 --- a/locales/en-human.json +++ b/locales/en-human.json @@ -2116,18 +2116,34 @@ "TITLE": "Feature Disabled", "BODY": "This feature has been temporarily disabled. Please check back later when we are back up and running!" }, + "RECURRING_CONFIRM": { + "NEEDS_KYC_AND_TRADES": { + "HEADER": "Verify Your Identity and Complete 3 Orders", + "BODY": "To unlock the recurring buy feature, verify your identity and complete 3 credit card orders.", + "BUTTON": "Proceed To Verify My Identity" + }, + "NEEDS_KYC": { + "HEADER": "Verify Your Identity", + "BODY": "To set up a recurring order, you first need to verify your identity", + "BUTTON": "Proceed To Verify My Identity" + }, + "NEEDS_TRADES": { + "HEADER": "Complete 3 Orders", + "BODY": "To set up Recurring Orders you first need to complete 3 credit card orders with the same card.", + "BUTTON": "Close" + }, + "PROCEED": { + "HEADER": "You're About To Set Up A Recurring Order", + "BODY": "This Recurring Order will happen today and every {{::timing}} until you cancel or reach your limit, whichever happens first.", + "BUTTON": "Proceed with my Order" + } + }, "RECURRING_INTRO_HEADER": "About Recurring Orders", "RECURRING_INTRO_1": "You can now create recurring bitcoin purchases from within your wallet after verifying your account.", "RECURRING_INTRO_2": "Select 'Make this a recurring order', set your recurring preferences, and continue with your purchase as normal. Each time an order is processed you will receive an email to notify you.", "RECURRING_INTRO_3": "Recurring orders can be canceled at anytime from", "RECURRING_INTRO_4": "Want to know more about Recurring Orders?", - "RECURRING_CONFIRM_HEADER": "You're About To Set Up A Recurring Order", - "RECURRING_CONFIRM_NEED_IDENTITY_HEADER": "Verify Your Identity", "RECURRING_CONFIRM_BODY_WITH_ENDTIME": "This Recurring Order will happen today and every {{::timing}} until {{::end}} or you reach your limit, whichever happens first.", - "RECURRING_CONFIRM_BODY": "This Recurring Order will happen today and every {{::timing}} until you cancel or reach your limit, whichever happens first.", - "RECURRING_CONFIRM_NEED_IDENTITY_BODY": "To set up a recurring order, you first need to verify your identity", - "PROCEED_WITH_MY_ORDER": "Proceed with my Order", - "PROCEED_TO_KYC": "Proceed To Verify My Identity", "ORDERS": "Orders.", "LEARN_MORE_HERE": "Learn more here.", "MAKE_RECURRING_ORDER": "Make this a recurring order", From 00b115dee3ef757ec195d278253a430cede9a234 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 12:36:49 -0400 Subject: [PATCH 09/19] feat(Recurring Buy): add next recurring component to checkout screen; hide announcement if kyc pending --- app/partials/coinify/checkout.pug | 13 ++++++++++++- .../coinify/coinifyCheckout.controller.js | 10 ++++++++-- assets/js/services/coinify.service.js | 15 +++++++++++++++ locales/en-human.json | 2 ++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/app/partials/coinify/checkout.pug b/app/partials/coinify/checkout.pug index 3f5ee41530..55badd741b 100644 --- a/app/partials/coinify/checkout.pug +++ b/app/partials/coinify/checkout.pug @@ -24,7 +24,18 @@ bc-tabs(tab="tabs.selectedTab" tab-options="tabs.options" on-select="tabs.select disable-recurring="disableRecurring" handle-quote="buyQuoteHandler(amount, baseCurr, quoteCurr)") .flex-column.ml-60.col-md-5.col-sm-12.col-xs-12.pln.prn.pv-10-mobile.no-margin-mobile.hidden-xs - exchange-recurring(ng-if="scheduledRecurring" frequency="vm.frequency" end-time="vm.endTime" t="trade" dollars="dollars" payment-fee="trade.fee") + .mb-20.flex-column.pv-20.ph-20.bg-footer-blue(ng-show="nextRecurring().frequency && nextRecurring().amount") + span.f-14(translate="RECURRING_NEXT_SCHEDULED") + .flex-row.pt-10 + span.f-14 Amount:  + span.f-14 {{ nextRecurring().amount }} + |  + span.em-200.f-14 {{ nextRecurring().currency }} (+ {{ nextRecurring().fee }} {{ nextRecurring().currency }} Payment Fee) + .flex-row.pt-10 + span.f-14 Frequency:  + span.f-14.em-200(translate="RECURRING_NEXT_TRADE" translate-values="{timespan: nextRecurringTimespan()}") + .flex-row.pt-20.flex-end + a(translate="MANAGE_THIS_ORDER" ng-click="tabs.select('ORDER_HISTORY')") .mb-20(ng-show="showRecurringBuy && !hasDismissedRecurringBuyIntro()") .flex-between span.f-24.blue.f-14-mobile diff --git a/assets/js/controllers/coinify/coinifyCheckout.controller.js b/assets/js/controllers/coinify/coinifyCheckout.controller.js index d1fcea7f9e..f0d54777e5 100644 --- a/assets/js/controllers/coinify/coinifyCheckout.controller.js +++ b/assets/js/controllers/coinify/coinifyCheckout.controller.js @@ -2,7 +2,7 @@ angular .module('walletApp') .controller('CoinifyCheckoutController', CoinifyCheckoutController); -function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, AngularHelper, MyWallet, $state, Wallet, currency, coinify, Exchange, modals, localStorageService) { +function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, AngularHelper, MyWallet, $state, Wallet, currency, coinify, Exchange, modals, localStorageService, recurringTrade) { $scope.trades = coinify.trades; $scope.exchange = coinify.exchange; $scope.subscriptions = () => coinify.subscriptions; @@ -24,6 +24,9 @@ function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, Angul }); $scope.recurringBuyLimit = () => $scope.exchange.user ? coinify.limits.card.inRemaining[$scope.buyFiat.code] : 300; + $scope.nextRecurring = () => coinify.getNextRecurringTrade(); + $scope.nextRecurringTimespan = () => $scope.nextRecurring().date && recurringTrade.getTimespan(new Date($scope.nextRecurring().date), $scope.nextRecurring().frequency) + $scope.selling = coinify.selling; $scope.sellHandler = modals.openSellView; $scope.sellQuoteHandler = coinify.getSellQuote; @@ -59,7 +62,10 @@ function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, Angul $state.params.selectedTab = this.selectedTab; } }; - $scope.showRecurringBuy = MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK' && env.partners.coinify.showRecurringBuy && $scope.exchange.profile.email; /* && $scope.exchange.profile.tradeSubscriptionsAllowed */ + $scope.showRecurringBuy = MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK' && + env.partners.coinify.showRecurringBuy && + $scope.exchange.profile.email && + !coinify.getPendingKYC(); if (env.qaDebugger) { $scope.qaDebugger = env.qaDebugger; diff --git a/assets/js/services/coinify.service.js b/assets/js/services/coinify.service.js index 998df10fd8..8ef48e2740 100644 --- a/assets/js/services/coinify.service.js +++ b/assets/js/services/coinify.service.js @@ -219,5 +219,20 @@ function coinify (Env, BrowserHelper, $timeout, $q, $state, $uibModal, $uibModal MyBlockchainApi.incrementBuyDropoff(step); }; + service.getNextRecurringTrade = () => { + if (service.subscriptions.length) { + let activeSub = service.subscriptions.filter(s => s.isActive); + let matchingTrades = service.trades.filter(t => t.tradeSubscriptionId === activeSub[0].id); + let trade = matchingTrades.sort((a, b) => a.createdAt < b.createdAt); + const fee = (trade[0].sendAmount / 100) - (trade[0].inAmount / 100); + return {amount: trade[0].inAmount / 100, + currency: trade[0].inCurrency, + date: trade[0].createdAt, + frequency: activeSub[0].frequency, + fee: fee.toFixed(2)}; + } + return false + } + return service; } diff --git a/locales/en-human.json b/locales/en-human.json index 8cf58c1281..adb5a84fc9 100644 --- a/locales/en-human.json +++ b/locales/en-human.json @@ -2138,6 +2138,8 @@ "BUTTON": "Proceed with my Order" } }, + "RECURRING_NEXT_SCHEDULED": "Your Next Recurring Order is Scheduled", + "RECURRING_NEXT_TRADE": "This order will happen every {{::timespan}}", "RECURRING_INTRO_HEADER": "About Recurring Orders", "RECURRING_INTRO_1": "You can now create recurring bitcoin purchases from within your wallet after verifying your account.", "RECURRING_INTRO_2": "Select 'Make this a recurring order', set your recurring preferences, and continue with your purchase as normal. Each time an order is processed you will receive an email to notify you.", From f81a4033012f4a2636809d94abc0259f70f1a8c3 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 12:42:13 -0400 Subject: [PATCH 10/19] feat(Recurring Buy): hide announcement but not checkbox --- app/partials/coinify/checkout.pug | 2 +- assets/js/controllers/coinify/coinifyCheckout.controller.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/partials/coinify/checkout.pug b/app/partials/coinify/checkout.pug index 55badd741b..3236e37283 100644 --- a/app/partials/coinify/checkout.pug +++ b/app/partials/coinify/checkout.pug @@ -36,7 +36,7 @@ bc-tabs(tab="tabs.selectedTab" tab-options="tabs.options" on-select="tabs.select span.f-14.em-200(translate="RECURRING_NEXT_TRADE" translate-values="{timespan: nextRecurringTimespan()}") .flex-row.pt-20.flex-end a(translate="MANAGE_THIS_ORDER" ng-click="tabs.select('ORDER_HISTORY')") - .mb-20(ng-show="showRecurringBuy && !hasDismissedRecurringBuyIntro()") + .mb-20(ng-show="showRecurringBuy && !hasDismissedRecurringBuyIntro() && !disableRecurring") .flex-between span.f-24.blue.f-14-mobile i.icon-buy-sell.h3.mrm diff --git a/assets/js/controllers/coinify/coinifyCheckout.controller.js b/assets/js/controllers/coinify/coinifyCheckout.controller.js index f0d54777e5..68a923d164 100644 --- a/assets/js/controllers/coinify/coinifyCheckout.controller.js +++ b/assets/js/controllers/coinify/coinifyCheckout.controller.js @@ -64,8 +64,7 @@ function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, Angul }; $scope.showRecurringBuy = MyWallet.wallet.accountInfo.countryCodeGuess !== 'UK' && env.partners.coinify.showRecurringBuy && - $scope.exchange.profile.email && - !coinify.getPendingKYC(); + $scope.exchange.profile.email; if (env.qaDebugger) { $scope.qaDebugger = env.qaDebugger; From 007a8325b76500c9d88f55aa3193bf6cd2b84da4 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 14:36:06 -0400 Subject: [PATCH 11/19] feat(Recurring Buy): fix next recurring; add icons --- app/partials/coinify/checkout.pug | 4 +++- app/templates/exchange/recurring.pug | 5 +++-- .../js/components/exchange/exchange-recurring.component.js | 1 + assets/js/services/coinify.service.js | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/partials/coinify/checkout.pug b/app/partials/coinify/checkout.pug index 3236e37283..57715f2387 100644 --- a/app/partials/coinify/checkout.pug +++ b/app/partials/coinify/checkout.pug @@ -98,7 +98,9 @@ bc-tabs(tab="tabs.selectedTab" tab-options="tabs.options" on-select="tabs.select trade="trade") div(ng-show="recurringTrades().length") .flex-row.flex-between.flex-center.mtl - h4.type-h5 Recurring Orders + .flex-row.flex-center + i.icon-recurring.mr-5 + h4.type-h5 Recurring Orders div(ng-hide="pendingTrades().length") span.hidden-xs(ng-show="exchange.profile.email") Coinify Account: {{ exchange.profile.email }} .width-100 diff --git a/app/templates/exchange/recurring.pug b/app/templates/exchange/recurring.pug index 9006d4f864..0834a3777c 100644 --- a/app/templates/exchange/recurring.pug +++ b/app/templates/exchange/recurring.pug @@ -1,5 +1,6 @@ .flex-row.flex-between.mbm - div + .flex + i.icon-recurring.mr-5 span.primary.em-500 This is a Recurring Order helper-button(content="RECURRING_HELPER") a.em-300.text-danger.underline(ng-show="$ctrl.showRemove" ng-click="$ctrl.onRemove()") Remove Recurring Order @@ -8,7 +9,7 @@ span.f-13(translate="RECURRING_REMINDER" translate-values="{time: $ctrl.frequency}") .flex-row.phm.pv-5 span.flex-1.primary.colon(translate="AMOUNT") - span.flex-5.ph-5-mobile {{ format($ctrl.trade.fiatAmount, $ctrl.dollars, true) }} (+ {{ $ctrl.paymentFee | format }} {{ $ctrl.dollars.code }} Payment Fee) + span.flex-5.ph-5-mobile {{ format($ctrl.trade.fiatAmount, $ctrl.dollars, true) }} (+ {{ paymentFee | format }} {{ $ctrl.dollars.code }} Payment Fee) .flex-row.phm.pv-5 span.flex-1.primary.colon(translate="FREQUENCY") span.flex-5.ph-5-mobile(translate="FREQUENCY_INFO" translate-values="{timespan: timespan}") diff --git a/assets/js/components/exchange/exchange-recurring.component.js b/assets/js/components/exchange/exchange-recurring.component.js index 827199c679..c3e65bb544 100644 --- a/assets/js/components/exchange/exchange-recurring.component.js +++ b/assets/js/components/exchange/exchange-recurring.component.js @@ -26,4 +26,5 @@ function ExchangeRecurringController ($scope, currency, recurringTrade) { $scope.endTime = this.endTime && new Date(this.endTime).toDateString(); $scope.timespan = recurringTrade.getTimespan($scope.date, frequency); + $scope.paymentFee = this.paymentFee || parseFloat((this.trade.sendAmount / 100).toFixed(2)) - this.trade.fiatAmount } diff --git a/assets/js/services/coinify.service.js b/assets/js/services/coinify.service.js index 8ef48e2740..b6ba9d20fc 100644 --- a/assets/js/services/coinify.service.js +++ b/assets/js/services/coinify.service.js @@ -220,8 +220,8 @@ function coinify (Env, BrowserHelper, $timeout, $q, $state, $uibModal, $uibModal }; service.getNextRecurringTrade = () => { - if (service.subscriptions.length) { - let activeSub = service.subscriptions.filter(s => s.isActive); + let activeSub = service.subscriptions.filter(s => s.isActive); + if (activeSub.length) { let matchingTrades = service.trades.filter(t => t.tradeSubscriptionId === activeSub[0].id); let trade = matchingTrades.sort((a, b) => a.createdAt < b.createdAt); const fee = (trade[0].sendAmount / 100) - (trade[0].inAmount / 100); From 22c747302bce29ea272102dc7d1841650cddc24f Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 14:42:54 -0400 Subject: [PATCH 12/19] fix(Recurring Buy): remove todo note --- assets/js/controllers/coinify/coinify.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/js/controllers/coinify/coinify.controller.js b/assets/js/controllers/coinify/coinify.controller.js index b9474d75dd..c1c1ca13c0 100644 --- a/assets/js/controllers/coinify/coinify.controller.js +++ b/assets/js/controllers/coinify/coinify.controller.js @@ -105,7 +105,7 @@ function CoinifyController ($rootScope, $scope, $q, $state, $timeout, $uibModalI this.currentStep = () => Object.keys(this.steps).filter(this.onStep)[0]; this.goTo = (step) => this.step = this.steps[step]; - if (frequency && this.quote) { // TODO might need something here if KYC pending + if (frequency && this.quote) { this.goTo('confirm-recurring') } else if (!this.user.isEmailVerified && !this.exchange.user) { this.goTo('email'); From f57d7753e4cd5e84a175798209105a11786138a7 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 14:45:21 -0400 Subject: [PATCH 13/19] fix(Recurring Buy): fix test --- tests/controllers/coinify/coinify_ctrl_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/controllers/coinify/coinify_ctrl_spec.js b/tests/controllers/coinify/coinify_ctrl_spec.js index 02a67ed181..bc25b9ac72 100644 --- a/tests/controllers/coinify/coinify_ctrl_spec.js +++ b/tests/controllers/coinify/coinify_ctrl_spec.js @@ -191,7 +191,7 @@ describe('CoinifyController', () => { Wallet.user.isEmailVerified = true; MyWallet.wallet.external.coinify = ({ profile: {}, user: 1 }); let ctrl = getController(quote, null); - expect(ctrl.currentStep()).toBe('select-payment-medium'); + expect(ctrl.currentStep()).toBe('email'); })); it('should ask user to complete isx after a trade is created', inject(function (Wallet, MyWallet) { From b0a8a295bcb8eb52c6794a98d63d4ebbf7306c58 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 14:53:39 -0400 Subject: [PATCH 14/19] fix(Recurring Buy): forgotten semis --- assets/js/components/coinify/recurring-confirm.component.js | 4 ++-- assets/js/components/exchange/exchange-recurring.component.js | 2 +- assets/js/controllers/coinify/coinify.controller.js | 4 ++-- assets/js/controllers/coinify/coinifyCheckout.controller.js | 2 +- assets/js/services/coinify.service.js | 4 ++-- assets/js/services/wallet.service.js | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/assets/js/components/coinify/recurring-confirm.component.js b/assets/js/components/coinify/recurring-confirm.component.js index 2c969aa6c1..4e108c83b2 100644 --- a/assets/js/components/coinify/recurring-confirm.component.js +++ b/assets/js/components/coinify/recurring-confirm.component.js @@ -20,10 +20,10 @@ function CoinifyRecurringConfirmController (recurringTrade, coinify) { this.needsMoreTrades = coinify.trades.filter((t) => coinify.tradeStateIn(coinify.states.completed)(t) && !t.tradeSubscriptionId && t.medium === 'card').length < 3; const determineState = () => { - if (this.needsKyc && this.needsMoreTrades) return 'NEEDS_KYC_AND_TRADES' + if (this.needsKyc && this.needsMoreTrades) return 'NEEDS_KYC_AND_TRADES'; if (this.needsKyc) return 'NEEDS_KYC'; if (this.needsMoreTrades) return 'NEEDS_TRADES'; return 'PROCEED'; - } + }; this.state = determineState(); } diff --git a/assets/js/components/exchange/exchange-recurring.component.js b/assets/js/components/exchange/exchange-recurring.component.js index c3e65bb544..99942b727c 100644 --- a/assets/js/components/exchange/exchange-recurring.component.js +++ b/assets/js/components/exchange/exchange-recurring.component.js @@ -26,5 +26,5 @@ function ExchangeRecurringController ($scope, currency, recurringTrade) { $scope.endTime = this.endTime && new Date(this.endTime).toDateString(); $scope.timespan = recurringTrade.getTimespan($scope.date, frequency); - $scope.paymentFee = this.paymentFee || parseFloat((this.trade.sendAmount / 100).toFixed(2)) - this.trade.fiatAmount + $scope.paymentFee = this.paymentFee || parseFloat((this.trade.sendAmount / 100).toFixed(2)) - this.trade.fiatAmount; } diff --git a/assets/js/controllers/coinify/coinify.controller.js b/assets/js/controllers/coinify/coinify.controller.js index c1c1ca13c0..c0c7332201 100644 --- a/assets/js/controllers/coinify/coinify.controller.js +++ b/assets/js/controllers/coinify/coinify.controller.js @@ -22,7 +22,7 @@ function CoinifyController ($rootScope, $scope, $q, $state, $timeout, $uibModalI this.transactionFee = () => this.mediums ? this.mediums[this.medium || 'card'].outFixedFees['BTC'] * 1e8 : 0; this.timeToExpiration = () => this.quote ? this.quote.expiresAt - this.now() : this.trade.expiresAt - this.now(); this.needsKYCForRecurring = this.exchange.profile.level && this.exchange.profile.level.name < 2; - this.triggerKYCForRecurring = () => { coinify.getOpenKYC(); this.trade = exchange.kycs[0]; this.goTo('isx') } + this.triggerKYCForRecurring = () => { coinify.getOpenKYC(); this.trade = exchange.kycs[0]; this.goTo('isx'); }; this.refreshQuote = () => { if (this.baseFiat()) return $q.resolve(coinify.getQuote(this.fiatAmount() * 100, this.quote.baseCurrency)).then((q) => this.quote = q); else return $q.resolve(coinify.getQuote(this.BTCAmount(), this.quote.baseCurrency, this.quote.quoteCurrency)).then((q) => this.quote = q); @@ -106,7 +106,7 @@ function CoinifyController ($rootScope, $scope, $q, $state, $timeout, $uibModalI this.goTo = (step) => this.step = this.steps[step]; if (frequency && this.quote) { - this.goTo('confirm-recurring') + this.goTo('confirm-recurring'); } else if (!this.user.isEmailVerified && !this.exchange.user) { this.goTo('email'); } else if (!this.exchange.user) { diff --git a/assets/js/controllers/coinify/coinifyCheckout.controller.js b/assets/js/controllers/coinify/coinifyCheckout.controller.js index 68a923d164..a1d498d63a 100644 --- a/assets/js/controllers/coinify/coinifyCheckout.controller.js +++ b/assets/js/controllers/coinify/coinifyCheckout.controller.js @@ -25,7 +25,7 @@ function CoinifyCheckoutController ($scope, $rootScope, $stateParams, Env, Angul $scope.recurringBuyLimit = () => $scope.exchange.user ? coinify.limits.card.inRemaining[$scope.buyFiat.code] : 300; $scope.nextRecurring = () => coinify.getNextRecurringTrade(); - $scope.nextRecurringTimespan = () => $scope.nextRecurring().date && recurringTrade.getTimespan(new Date($scope.nextRecurring().date), $scope.nextRecurring().frequency) + $scope.nextRecurringTimespan = () => $scope.nextRecurring().date && recurringTrade.getTimespan(new Date($scope.nextRecurring().date), $scope.nextRecurring().frequency); $scope.selling = coinify.selling; $scope.sellHandler = modals.openSellView; diff --git a/assets/js/services/coinify.service.js b/assets/js/services/coinify.service.js index b6ba9d20fc..e217b07828 100644 --- a/assets/js/services/coinify.service.js +++ b/assets/js/services/coinify.service.js @@ -231,8 +231,8 @@ function coinify (Env, BrowserHelper, $timeout, $q, $state, $uibModal, $uibModal frequency: activeSub[0].frequency, fee: fee.toFixed(2)}; } - return false - } + return false; + }; return service; } diff --git a/assets/js/services/wallet.service.js b/assets/js/services/wallet.service.js index cc07e91859..6ce47b492e 100644 --- a/assets/js/services/wallet.service.js +++ b/assets/js/services/wallet.service.js @@ -292,7 +292,7 @@ function Wallet ($http, $window, $timeout, $location, $injector, Alerts, MyWalle history.push(wallet.my.wallet.getHistory()); if (BlockchainConstants.NETWORK === 'testnet') { - didFetchTransactions() + didFetchTransactions(); } else { let Ethereum = $injector.get('Ethereum'); if (Ethereum.eth) history.push(Ethereum.fetchHistory()); From 2fc34341bec1636c06689b76a7bccd2781eca8b9 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 15:51:01 -0400 Subject: [PATCH 15/19] fix(Recurring Buy): fix getNextRecurring --- assets/js/services/coinify.service.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/js/services/coinify.service.js b/assets/js/services/coinify.service.js index e217b07828..ccdffa695b 100644 --- a/assets/js/services/coinify.service.js +++ b/assets/js/services/coinify.service.js @@ -220,8 +220,8 @@ function coinify (Env, BrowserHelper, $timeout, $q, $state, $uibModal, $uibModal }; service.getNextRecurringTrade = () => { - let activeSub = service.subscriptions.filter(s => s.isActive); - if (activeSub.length) { + let activeSub = service.subscriptions && service.subscriptions.filter(s => s.isActive); + if (activeSub) { let matchingTrades = service.trades.filter(t => t.tradeSubscriptionId === activeSub[0].id); let trade = matchingTrades.sort((a, b) => a.createdAt < b.createdAt); const fee = (trade[0].sendAmount / 100) - (trade[0].inAmount / 100); From 13782e516b0cbb3d3160a5e0cfc7b6f72042ccc7 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 16:14:37 -0400 Subject: [PATCH 16/19] fix(Recurring Buy): promisify triggerKYC --- assets/js/controllers/coinify/coinify.controller.js | 6 +++++- assets/js/services/coinify.service.js | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/assets/js/controllers/coinify/coinify.controller.js b/assets/js/controllers/coinify/coinify.controller.js index c0c7332201..5fd6845204 100644 --- a/assets/js/controllers/coinify/coinify.controller.js +++ b/assets/js/controllers/coinify/coinify.controller.js @@ -22,7 +22,11 @@ function CoinifyController ($rootScope, $scope, $q, $state, $timeout, $uibModalI this.transactionFee = () => this.mediums ? this.mediums[this.medium || 'card'].outFixedFees['BTC'] * 1e8 : 0; this.timeToExpiration = () => this.quote ? this.quote.expiresAt - this.now() : this.trade.expiresAt - this.now(); this.needsKYCForRecurring = this.exchange.profile.level && this.exchange.profile.level.name < 2; - this.triggerKYCForRecurring = () => { coinify.getOpenKYC(); this.trade = exchange.kycs[0]; this.goTo('isx'); }; + this.triggerKYCForRecurring = () => { + $q.resolve(coinify.getOpenKYC()) + .then(() => this.trade = exchange.kycs[0]) + .then(() => this.goTo('isx')) + }; this.refreshQuote = () => { if (this.baseFiat()) return $q.resolve(coinify.getQuote(this.fiatAmount() * 100, this.quote.baseCurrency)).then((q) => this.quote = q); else return $q.resolve(coinify.getQuote(this.BTCAmount(), this.quote.baseCurrency, this.quote.quoteCurrency)).then((q) => this.quote = q); diff --git a/assets/js/services/coinify.service.js b/assets/js/services/coinify.service.js index ccdffa695b..af25b3c6f0 100644 --- a/assets/js/services/coinify.service.js +++ b/assets/js/services/coinify.service.js @@ -220,8 +220,9 @@ function coinify (Env, BrowserHelper, $timeout, $q, $state, $uibModal, $uibModal }; service.getNextRecurringTrade = () => { + if (!service.subscriptions) return false; let activeSub = service.subscriptions && service.subscriptions.filter(s => s.isActive); - if (activeSub) { + if (activeSub.length) { let matchingTrades = service.trades.filter(t => t.tradeSubscriptionId === activeSub[0].id); let trade = matchingTrades.sort((a, b) => a.createdAt < b.createdAt); const fee = (trade[0].sendAmount / 100) - (trade[0].inAmount / 100); From 2ee381b2f8d9783b11734d11bf0d4d470f16e3b1 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 16:42:22 -0400 Subject: [PATCH 17/19] fix(Recurring Buy): dont show recurring component after kyc --- app/partials/trade-summary.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/partials/trade-summary.pug b/app/partials/trade-summary.pug index ff3cae5ef6..8488c18b8c 100644 --- a/app/partials/trade-summary.pug +++ b/app/partials/trade-summary.pug @@ -14,7 +14,7 @@ i.ti-search.mrm span(ng-click="fakeBankTransfer()" translate="QA: Click here to fake a bank transfer") .mtm - exchange-recurring(ng-if="vm.frequency" frequency="vm.frequency" end-time="vm.endTime" t="trade" dollars="dollars" on-close="$close()") + exchange-recurring(ng-if="vm.frequency && trade.sendAmount" frequency="vm.frequency" end-time="vm.endTime" t="trade" dollars="dollars" on-close="$close()") .flex-row.flex-between.pt-20 .flex-start.flex-center a(ng-show="tradeIsPending()" ng-click="editRef()" ng-class="{ 'link-disabled mid-grey': disableLink }" translate="EDIT_REF") From e4d5e32294fecce98cc041a8d1763aafa4b52633 Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 17:00:26 -0400 Subject: [PATCH 18/19] fix(Recurring Buy): include string with endtime --- app/partials/coinify/recurring-confirm.pug | 3 ++- locales/en-human.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/partials/coinify/recurring-confirm.pug b/app/partials/coinify/recurring-confirm.pug index f9fb3b1eda..45a9abc6a7 100644 --- a/app/partials/coinify/recurring-confirm.pug +++ b/app/partials/coinify/recurring-confirm.pug @@ -3,7 +3,8 @@ .f-18.mb-15.em-400 span.f-18.mb-15.em-400(translate="{{ 'RECURRING_CONFIRM' + '.' + $ctrl.state + '.' + 'HEADER' }}") .f-14.em-300 - span.f-14.em-300(translate="{{ 'RECURRING_CONFIRM' + '.' + $ctrl.state + '.' + 'BODY' }}" translate-values="{timing: $ctrl.recurringTiming()}") + span.f-14.em-300(ng-if="!$ctrl.endTime" translate="{{ 'RECURRING_CONFIRM' + '.' + $ctrl.state + '.' + 'BODY' }}" translate-values="{timing: $ctrl.recurringTiming()}") + span.f-14.em-300(ng-if="$ctrl.endTime" translate="{{ 'RECURRING_CONFIRM' + '.' + $ctrl.state + '.' + 'BODY_WITH_ENDTIME' }}" translate-values="{timing: $ctrl.recurringTiming(), end: $ctrl.endTime.toDateString()}") .modal-footer.flex-end.flex-row .flex-1.flex-end button.button-muted.mrm(ng-if="$ctrl.state !== 'NEEDS_TRADES'" ng-click="$ctrl.onCancel()" translate="GO_BACK") diff --git a/locales/en-human.json b/locales/en-human.json index adb5a84fc9..d9ca4de2c0 100644 --- a/locales/en-human.json +++ b/locales/en-human.json @@ -2135,6 +2135,7 @@ "PROCEED": { "HEADER": "You're About To Set Up A Recurring Order", "BODY": "This Recurring Order will happen today and every {{::timing}} until you cancel or reach your limit, whichever happens first.", + "BODY_WITH_ENDTIME": "This Recurring Order will happen today and every {{::timing}} until {{::end}} or you reach your limit, whichever happens first.", "BUTTON": "Proceed with my Order" } }, @@ -2145,7 +2146,6 @@ "RECURRING_INTRO_2": "Select 'Make this a recurring order', set your recurring preferences, and continue with your purchase as normal. Each time an order is processed you will receive an email to notify you.", "RECURRING_INTRO_3": "Recurring orders can be canceled at anytime from", "RECURRING_INTRO_4": "Want to know more about Recurring Orders?", - "RECURRING_CONFIRM_BODY_WITH_ENDTIME": "This Recurring Order will happen today and every {{::timing}} until {{::end}} or you reach your limit, whichever happens first.", "ORDERS": "Orders.", "LEARN_MORE_HERE": "Learn more here.", "MAKE_RECURRING_ORDER": "Make this a recurring order", From fb579279b82093c6738d0d235a5ed37be7d8037b Mon Sep 17 00:00:00 2001 From: Philip Welber Date: Tue, 10 Apr 2018 17:36:31 -0400 Subject: [PATCH 19/19] fix(Recurring Buy): font size change --- app/partials/coinify/checkout.pug | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/partials/coinify/checkout.pug b/app/partials/coinify/checkout.pug index 57715f2387..23f37d2f77 100644 --- a/app/partials/coinify/checkout.pug +++ b/app/partials/coinify/checkout.pug @@ -25,15 +25,15 @@ bc-tabs(tab="tabs.selectedTab" tab-options="tabs.options" on-select="tabs.select handle-quote="buyQuoteHandler(amount, baseCurr, quoteCurr)") .flex-column.ml-60.col-md-5.col-sm-12.col-xs-12.pln.prn.pv-10-mobile.no-margin-mobile.hidden-xs .mb-20.flex-column.pv-20.ph-20.bg-footer-blue(ng-show="nextRecurring().frequency && nextRecurring().amount") - span.f-14(translate="RECURRING_NEXT_SCHEDULED") + span.f-13(translate="RECURRING_NEXT_SCHEDULED") .flex-row.pt-10 - span.f-14 Amount:  - span.f-14 {{ nextRecurring().amount }} + span.f-13 Amount:  + span.f-13 {{ nextRecurring().amount }} |  - span.em-200.f-14 {{ nextRecurring().currency }} (+ {{ nextRecurring().fee }} {{ nextRecurring().currency }} Payment Fee) + span.em-200.f-13 {{ nextRecurring().currency }} (+ {{ nextRecurring().fee }} {{ nextRecurring().currency }} Payment Fee) .flex-row.pt-10 - span.f-14 Frequency:  - span.f-14.em-200(translate="RECURRING_NEXT_TRADE" translate-values="{timespan: nextRecurringTimespan()}") + span.f-13 Frequency:  + span.f-13.em-200(translate="RECURRING_NEXT_TRADE" translate-values="{timespan: nextRecurringTimespan()}") .flex-row.pt-20.flex-end a(translate="MANAGE_THIS_ORDER" ng-click="tabs.select('ORDER_HISTORY')") .mb-20(ng-show="showRecurringBuy && !hasDismissedRecurringBuyIntro() && !disableRecurring")