mirror of
https://github.com/bitwarden/browser
synced 2026-02-06 03:33:30 +00:00
implement the ticket requirement
This commit is contained in:
@@ -2,6 +2,7 @@ import { NgModule } from "@angular/core";
|
||||
|
||||
import { BaseCardComponent } from "@bitwarden/components";
|
||||
import { PricingCardComponent } from "@bitwarden/pricing";
|
||||
import { AdditionalOptionsCardComponent, StorageCardComponent } from "@bitwarden/subscription";
|
||||
import {
|
||||
EnterBillingAddressComponent,
|
||||
EnterPaymentMethodComponent,
|
||||
@@ -24,6 +25,8 @@ import { UserSubscriptionComponent } from "./user-subscription.component";
|
||||
EnterBillingAddressComponent,
|
||||
PricingCardComponent,
|
||||
BaseCardComponent,
|
||||
StorageCardComponent,
|
||||
AdditionalOptionsCardComponent,
|
||||
],
|
||||
declarations: [SubscriptionComponent, BillingHistoryViewComponent, UserSubscriptionComponent],
|
||||
})
|
||||
|
||||
@@ -138,47 +138,28 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
<div class="tw-max-w-[1340px]" *ngIf="!selfHosted">
|
||||
<h3 bitTypography="h3" class="tw-mt-8">{{ "storage" | i18n }}</h3>
|
||||
<p bitTypography="body1">
|
||||
{{ "subscriptionStorage" | i18n: sub.maxStorageGb || 0 : sub.storageName || "0 MB" }}
|
||||
</p>
|
||||
<bit-progress [barWidth]="storagePercentage" bgColor="success" size="default"></bit-progress>
|
||||
<ng-container *ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel">
|
||||
<div class="tw-mt-3">
|
||||
<div class="tw-flex tw-gap-4">
|
||||
<button bitButton type="button" buttonType="secondary" (click)="adjustStorage(true)">
|
||||
{{ "addStorage" | i18n }}
|
||||
</button>
|
||||
<button bitButton type="button" buttonType="secondary" (click)="adjustStorage(false)">
|
||||
{{ "removeStorage" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
<h3 bitTypography="h3" class="tw-mt-16">{{ "additionalOptions" | i18n }}</h3>
|
||||
<p bitTypography="body1" class="tw-mt-3">{{ "additionalOptionsDesc" | i18n }}</p>
|
||||
<div class="tw-flex tw-gap-4 tw-mt-3">
|
||||
<button
|
||||
bitButton
|
||||
type="button"
|
||||
buttonType="secondary"
|
||||
(click)="downloadLicense()"
|
||||
*ngIf="!subscription || !subscription.cancelled"
|
||||
>
|
||||
{{ "downloadLicense" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
bitButton
|
||||
#cancelBtn
|
||||
type="button"
|
||||
buttonType="danger"
|
||||
(click)="cancelSubscription()"
|
||||
[appApiAction]="cancelPromise"
|
||||
[disabled]="$any(cancelBtn).loading()"
|
||||
*ngIf="subscription && !subscription.cancelled && !subscriptionMarkedForCancel"
|
||||
>
|
||||
{{ "cancelSubscription" | i18n }}
|
||||
</button>
|
||||
<div class="tw-mt-10">
|
||||
<app-storage-card
|
||||
[maxStorageGb]="sub.maxStorageGb"
|
||||
[storageName]="sub.storageName"
|
||||
[storagePercentage]="storagePercentage"
|
||||
[showActions]="subscription && !subscription.cancelled && !subscriptionMarkedForCancel"
|
||||
[isSubscriptionCancelled]="subscription?.cancelled || subscriptionMarkedForCancel"
|
||||
(addStorage)="adjustStorage(true)"
|
||||
(removeStorage)="adjustStorage(false)"
|
||||
></app-storage-card>
|
||||
</div>
|
||||
|
||||
<div class="tw-mt-10">
|
||||
<app-additional-options-card
|
||||
[showDownloadLicense]="!subscription || !subscription.cancelled"
|
||||
[showCancelSubscription]="
|
||||
subscription && !subscription.cancelled && !subscriptionMarkedForCancel
|
||||
"
|
||||
[cancelPromise]="cancelPromise"
|
||||
(downloadLicense)="downloadLicense()"
|
||||
(cancelSubscription)="cancelSubscription()"
|
||||
></app-additional-options-card>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { StorageRequest } from "../../../models/request/storage.request";
|
||||
import {
|
||||
BillingInvoiceResponse,
|
||||
BillingTransactionResponse,
|
||||
@@ -9,4 +10,6 @@ export abstract class AccountBillingApiServiceAbstraction {
|
||||
startAfter?: string,
|
||||
): Promise<BillingInvoiceResponse[]>;
|
||||
abstract getBillingTransactions(startAfter?: string): Promise<BillingTransactionResponse[]>;
|
||||
abstract getUserLicense(): Promise<any>;
|
||||
abstract putAccountStorage(request: StorageRequest): Promise<any>;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ApiService } from "../../../abstractions/api.service";
|
||||
import { StorageRequest } from "../../../models/request/storage.request";
|
||||
import { AccountBillingApiServiceAbstraction } from "../../abstractions/account/account-billing-api.service.abstraction";
|
||||
import {
|
||||
BillingInvoiceResponse,
|
||||
@@ -45,4 +46,12 @@ export class AccountBillingApiService implements AccountBillingApiServiceAbstrac
|
||||
);
|
||||
return r?.map((i: any) => new BillingTransactionResponse(i)) || [];
|
||||
}
|
||||
|
||||
async getUserLicense(): Promise<any> {
|
||||
return await this.apiService.send("GET", "/account/billing/vnext/license", null, true, true);
|
||||
}
|
||||
|
||||
async putAccountStorage(request: StorageRequest): Promise<any> {
|
||||
return await this.apiService.send("PUT", "/account/billing/vnext/storage", request, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<bit-card>
|
||||
<h3 bitTypography="h3" class="tw-mt-0">{{ "additionalOptions" | i18n }}</h3>
|
||||
<p bitTypography="body1">{{ "additionalOptionsDesc" | i18n }}</p>
|
||||
<div class="tw-flex tw-gap-4 tw-mt-3">
|
||||
<button
|
||||
bitButton
|
||||
type="button"
|
||||
buttonType="secondary"
|
||||
(click)="onDownloadLicense()"
|
||||
*ngIf="showDownloadLicense()"
|
||||
>
|
||||
{{ "downloadLicense" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
bitButton
|
||||
#cancelBtn
|
||||
type="button"
|
||||
buttonType="danger"
|
||||
(click)="onCancelSubscription()"
|
||||
[appApiAction]="cancelPromise()"
|
||||
[disabled]="$any(cancelBtn).loading()"
|
||||
*ngIf="showCancelSubscription()"
|
||||
>
|
||||
{{ "cancelSubscription" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</bit-card>
|
||||
@@ -0,0 +1,29 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, ChangeDetectionStrategy, input, output } from "@angular/core";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { CardComponent, TypographyModule, ButtonModule } from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
selector: "app-additional-options-card",
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule, CardComponent, TypographyModule, ButtonModule, JslibModule],
|
||||
templateUrl: "./additional-options-card.component.html",
|
||||
})
|
||||
export class AdditionalOptionsCardComponent {
|
||||
readonly showDownloadLicense = input<boolean>(true);
|
||||
readonly showCancelSubscription = input<boolean>(true);
|
||||
readonly cancelPromise = input<Promise<any> | null>(null);
|
||||
|
||||
readonly downloadLicense = output<void>();
|
||||
readonly cancelSubscription = output<void>();
|
||||
|
||||
onDownloadLicense() {
|
||||
this.downloadLicense.emit();
|
||||
}
|
||||
|
||||
onCancelSubscription() {
|
||||
this.cancelSubscription.emit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<bit-card>
|
||||
<h3 bitTypography="h3" class="tw-mt-0">{{ "storage" | i18n }}</h3>
|
||||
<p bitTypography="body1">
|
||||
{{ "subscriptionStorage" | i18n: maxStorageGb() || 0 : storageName() || "0 MB" }}
|
||||
</p>
|
||||
<bit-progress [barWidth]="storagePercentage()" bgColor="success" size="default"></bit-progress>
|
||||
|
||||
<ng-container *ngIf="showActions() && !isSubscriptionCancelled()">
|
||||
<div class="tw-mt-3">
|
||||
<div class="tw-flex tw-gap-4">
|
||||
<button bitButton type="button" buttonType="secondary" (click)="onAddStorage()">
|
||||
{{ "addStorage" | i18n }}
|
||||
</button>
|
||||
<button bitButton type="button" buttonType="secondary" (click)="onRemoveStorage()">
|
||||
{{ "removeStorage" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</bit-card>
|
||||
@@ -0,0 +1,43 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, ChangeDetectionStrategy, input, output } from "@angular/core";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import {
|
||||
ProgressModule,
|
||||
CardComponent,
|
||||
TypographyModule,
|
||||
ButtonModule,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
@Component({
|
||||
selector: "app-storage-card",
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [
|
||||
CommonModule,
|
||||
CardComponent,
|
||||
TypographyModule,
|
||||
ButtonModule,
|
||||
ProgressModule,
|
||||
JslibModule,
|
||||
],
|
||||
templateUrl: "./storage-card.component.html",
|
||||
})
|
||||
export class StorageCardComponent {
|
||||
readonly maxStorageGb = input<number>();
|
||||
readonly storageName = input<string>();
|
||||
readonly storagePercentage = input<number>();
|
||||
readonly showActions = input<boolean>(true);
|
||||
readonly isSubscriptionCancelled = input<boolean>(false);
|
||||
|
||||
readonly addStorage = output<void>();
|
||||
readonly removeStorage = output<void>();
|
||||
|
||||
onAddStorage() {
|
||||
this.addStorage.emit();
|
||||
}
|
||||
|
||||
onRemoveStorage() {
|
||||
this.removeStorage.emit();
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
export type Placeholder = unknown;
|
||||
export { StorageCardComponent } from "./components/storage-card/storage-card.component";
|
||||
export { AdditionalOptionsCardComponent } from "./components/additional-options-card/additional-options-card.component";
|
||||
|
||||
Reference in New Issue
Block a user