mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 22:33:35 +00:00
95 lines
2.9 KiB
TypeScript
95 lines
2.9 KiB
TypeScript
import { CurrencyPipe } from "@angular/common";
|
|
import { Component, computed, input, signal } from "@angular/core";
|
|
|
|
import { TypographyModule, IconButtonModule } from "@bitwarden/components";
|
|
import { I18nPipe } from "@bitwarden/ui-common";
|
|
|
|
export type LineItem = {
|
|
quantity: number;
|
|
name: string;
|
|
cost: number;
|
|
cadence: "month" | "year";
|
|
};
|
|
|
|
/**
|
|
* A reusable UI-only component that displays a cart summary with line items.
|
|
* This component has no external dependencies and performs minimal logic -
|
|
* it only displays data and allows expanding/collapsing of line items.
|
|
*/
|
|
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
|
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
|
@Component({
|
|
selector: "billing-cart-summary",
|
|
templateUrl: "./cart-summary.component.html",
|
|
imports: [TypographyModule, IconButtonModule, CurrencyPipe, I18nPipe],
|
|
})
|
|
export class CartSummaryComponent {
|
|
// Required inputs
|
|
readonly passwordManager = input.required<LineItem>();
|
|
readonly additionalStorage = input<LineItem>();
|
|
readonly secretsManager = input<{ seats: LineItem; additionalServiceAccounts?: LineItem }>();
|
|
readonly estimatedTax = input.required<number>();
|
|
|
|
// UI state
|
|
readonly isExpanded = signal(true);
|
|
|
|
/**
|
|
* Calculates total for password manager line item
|
|
*/
|
|
readonly passwordManagerTotal = computed<number>(() => {
|
|
return this.passwordManager().quantity * this.passwordManager().cost;
|
|
});
|
|
|
|
/**
|
|
* Calculates total for additional storage line item if present
|
|
*/
|
|
readonly additionalStorageTotal = computed<number>(() => {
|
|
const storage = this.additionalStorage();
|
|
return storage ? storage.quantity * storage.cost : 0;
|
|
});
|
|
|
|
/**
|
|
* Calculates total for secrets manager seats if present
|
|
*/
|
|
readonly secretsManagerSeatsTotal = computed<number>(() => {
|
|
const sm = this.secretsManager();
|
|
return sm?.seats ? sm.seats.quantity * sm.seats.cost : 0;
|
|
});
|
|
|
|
/**
|
|
* Calculates total for secrets manager service accounts if present
|
|
*/
|
|
readonly additionalServiceAccountsTotal = computed<number>(() => {
|
|
const sm = this.secretsManager();
|
|
return sm?.additionalServiceAccounts
|
|
? sm.additionalServiceAccounts.quantity * sm.additionalServiceAccounts.cost
|
|
: 0;
|
|
});
|
|
|
|
/**
|
|
* Calculates the total of all line items
|
|
*/
|
|
readonly total = computed<number>(() => this.getTotalCost());
|
|
|
|
/**
|
|
* Toggles the expanded/collapsed state of the cart items
|
|
*/
|
|
toggleExpanded(): void {
|
|
this.isExpanded.update((value: boolean) => !value);
|
|
}
|
|
|
|
/**
|
|
* Gets the total cost of all line items in the cart
|
|
* @returns The total cost as a number
|
|
*/
|
|
private getTotalCost(): number {
|
|
return (
|
|
this.passwordManagerTotal() +
|
|
this.additionalStorageTotal() +
|
|
this.secretsManagerSeatsTotal() +
|
|
this.additionalServiceAccountsTotal() +
|
|
this.estimatedTax()
|
|
);
|
|
}
|
|
}
|