From 37026e556fdc79e41ecb1532143a3cef6ba233fc Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Fri, 29 Jun 2018 23:41:35 -0400 Subject: [PATCH] adjust storage implementation --- jslib | 2 +- src/app/app.module.ts | 2 + .../settings/adjust-storage.component.html | 25 ++++++++ src/app/settings/adjust-storage.component.ts | 60 +++++++++++++++++++ src/app/settings/user-billing.component.html | 16 +++-- src/app/settings/user-billing.component.ts | 14 +++++ src/locales/en/messages.json | 21 +++++++ 7 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 src/app/settings/adjust-storage.component.html create mode 100644 src/app/settings/adjust-storage.component.ts diff --git a/jslib b/jslib index ef897695..c0e7e588 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit ef897695e9b5bfecbfcbbd4ad3aec62b4ecdca25 +Subproject commit c0e7e588ed59832a6f579ff63d85bfcdfb400d78 diff --git a/src/app/app.module.ts b/src/app/app.module.ts index d4761812..50c2be5b 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -33,6 +33,7 @@ import { TwoFactorOptionsComponent } from './accounts/two-factor-options.compone import { TwoFactorComponent } from './accounts/two-factor.component'; import { AccountComponent } from './settings/account.component'; +import { AdjustStorageComponent } from './settings/adjust-storage.component'; import { ChangeEmailComponent } from './settings/change-email.component'; import { ChangePasswordComponent } from './settings/change-password.component'; import { DeauthorizeSessionsComponent } from './settings/deauthorize-sessions.component'; @@ -106,6 +107,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe'; declarations: [ AccountComponent, AddEditComponent, + AdjustStorageComponent, ApiActionDirective, AppComponent, AttachmentsComponent, diff --git a/src/app/settings/adjust-storage.component.html b/src/app/settings/adjust-storage.component.html new file mode 100644 index 00000000..02c9eb2b --- /dev/null +++ b/src/app/settings/adjust-storage.component.html @@ -0,0 +1,25 @@ +
+
+
+
+ + +
+
+
+ {{'total' | i18n}}: {{storageAdjustment || 0}} GB × {{storageGbPrice | currency:'$'}} = {{adjustedStorageTotal + | currency:'$'}} /{{interval | i18n}} +
+ + + + {{(add ? 'storageAddNote' : 'storageRemoveNote') | i18n}} + +
+
diff --git a/src/app/settings/adjust-storage.component.ts b/src/app/settings/adjust-storage.component.ts new file mode 100644 index 00000000..7ac6f6c3 --- /dev/null +++ b/src/app/settings/adjust-storage.component.ts @@ -0,0 +1,60 @@ +import { + Component, + EventEmitter, + Input, + Output, +} from '@angular/core'; + +import { ToasterService } from 'angular2-toaster'; +import { Angulartics2 } from 'angulartics2'; + +import { ApiService } from 'jslib/abstractions/api.service'; +import { I18nService } from 'jslib/abstractions/i18n.service'; + +import { StorageRequest } from 'jslib/models/request/storageRequest'; + +@Component({ + selector: 'app-adjust-storage', + templateUrl: 'adjust-storage.component.html', +}) +export class AdjustStorageComponent { + @Input() storageGbPrice = 0; + @Input() add = true; + @Input() user = true; + @Input() interval = 'year'; + @Output() onAdjusted = new EventEmitter(); + @Output() onCanceled = new EventEmitter(); + + storageAdjustment = 0; + formPromise: Promise; + + constructor(private apiService: ApiService, private i18nService: I18nService, + private analytics: Angulartics2, private toasterService: ToasterService) { } + + async submit() { + try { + const request = new StorageRequest(); + request.storageGbAdjustment = this.storageAdjustment; + if (!this.add) { + request.storageGbAdjustment *= -1; + } + + if (this.user) { + this.formPromise = this.apiService.postAccountStorage(request); + } + await this.formPromise; + this.analytics.eventTrack.next({ action: this.add ? 'Added Storage' : 'Removed Storage' }); + this.toasterService.popAsync('success', null, + this.i18nService.t('adjustedStorage', request.storageGbAdjustment.toString())); + this.onAdjusted.emit(this.storageAdjustment); + } catch { } + } + + cancel() { + this.onCanceled.emit(); + } + + get adjustedStorageTotal(): number { + return this.storageGbPrice * this.storageAdjustment; + } +} diff --git a/src/app/settings/user-billing.component.html b/src/app/settings/user-billing.component.html index 9b01a2d5..789940cb 100644 --- a/src/app/settings/user-billing.component.html +++ b/src/app/settings/user-billing.component.html @@ -69,12 +69,16 @@
- - + + + + +

{{'paymentMethod' | i18n}}

diff --git a/src/app/settings/user-billing.component.ts b/src/app/settings/user-billing.component.ts index 54b6773f..2e8d03a0 100644 --- a/src/app/settings/user-billing.component.ts +++ b/src/app/settings/user-billing.component.ts @@ -15,6 +15,8 @@ import { TokenService } from 'jslib/abstractions/token.service'; import { PaymentMethodType } from 'jslib/enums/paymentMethodType'; +import { AdjustStorageComponent } from './adjust-storage.component'; + @Component({ selector: 'app-user-billing', templateUrl: 'user-billing.component.html', @@ -23,6 +25,8 @@ export class UserBillingComponent implements OnInit { premium = false; loading = false; firstLoaded = false; + adjustStorageAdd = true; + showAdjustStorage = false; billing: BillingResponse; paymentMethodType = PaymentMethodType; @@ -101,7 +105,17 @@ export class UserBillingComponent implements OnInit { } adjustStorage(add: boolean) { + this.adjustStorageAdd = add; + this.showAdjustStorage = true; + } + adjustedStorage(gbAmount: number) { + this.showAdjustStorage = false; + this.load(); + } + + canceledAdjustStorage() { + this.showAdjustStorage = false; } changePayment() { diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index 344c73f7..936f77f5 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -1383,5 +1383,26 @@ "example": "BITWARDEN" } } + }, + "gbStorageAdd": { + "message": "GB of Storage To Add" + }, + "gbStorageRemove": { + "message": "GB of Storage To Remove" + }, + "storageAddNote": { + "message": "Adding storage to your plan will result in adjustments to your billing totals and immediately charge your payment method on file. The first charge will be prorated for the remainder of the current billing cycle." + }, + "storageRemoveNote": { + "message": "Removing storage will result in adjustments to your billing totals that will be prorated as credits to your next billing charge." + }, + "adjustedStorage": { + "message": "Adjusted $AMOUNT$ GB of storage.", + "placeholders": { + "amount": { + "content": "$1", + "example": "5" + } + } } }