mirror of
https://github.com/bitwarden/web
synced 2025-12-06 00:03:28 +00:00
adjust storage implementation
This commit is contained in:
2
jslib
2
jslib
Submodule jslib updated: ef897695e9...c0e7e588ed
@@ -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,
|
||||
|
||||
25
src/app/settings/adjust-storage.component.html
Normal file
25
src/app/settings/adjust-storage.component.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<form #form class="card" (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="form-group col-6">
|
||||
<label for="storageAdjustment">{{(add ? 'gbStorageAdd' : 'gbStorageRemove') | i18n}}</label>
|
||||
<input id="storageAdjustment" class="form-control" type="number" name="StroageGbAdjustment" [(ngModel)]="storageAdjustment"
|
||||
min="0" max="99" step="1">
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="add" class="mb-3">
|
||||
<strong>{{'total' | i18n}}:</strong> {{storageAdjustment || 0}} GB × {{storageGbPrice | currency:'$'}} = {{adjustedStorageTotal
|
||||
| currency:'$'}} /{{interval | i18n}}
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<span>{{'submit' | i18n}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="cancel()">
|
||||
{{'cancel' | i18n}}
|
||||
</button>
|
||||
<small class="d-block text-muted mt-3">
|
||||
{{(add ? 'storageAddNote' : 'storageRemoveNote') | i18n}}
|
||||
</small>
|
||||
</div>
|
||||
</form>
|
||||
60
src/app/settings/adjust-storage.component.ts
Normal file
60
src/app/settings/adjust-storage.component.ts
Normal file
@@ -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<number>();
|
||||
@Output() onCanceled = new EventEmitter();
|
||||
|
||||
storageAdjustment = 0;
|
||||
formPromise: Promise<any>;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -69,12 +69,16 @@
|
||||
</div>
|
||||
<ng-container *ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel && paymentSource">
|
||||
<div class="mt-3">
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="adjustStorage(true)">
|
||||
{{'addStorage' | i18n}}
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="adjustStorage(false)">
|
||||
{{'removeStorage' | i18n}}
|
||||
</button>
|
||||
<ng-container *ngIf="!showAdjustStorage">
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="adjustStorage(true)">
|
||||
{{'addStorage' | i18n}}
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="adjustStorage(false)">
|
||||
{{'removeStorage' | i18n}}
|
||||
</button>
|
||||
</ng-container>
|
||||
<app-adjust-storage [storageGbPrice]="4" [add]="adjustStorageAdd" [user]="true" (onAdjusted)="adjustedStorage($event)" (onCanceled)="canceledAdjustStorage()"
|
||||
*ngIf="showAdjustStorage"></app-adjust-storage>
|
||||
</div>
|
||||
</ng-container>
|
||||
<h2 class="spaced-header">{{'paymentMethod' | i18n}}</h2>
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user