mirror of
https://github.com/bitwarden/browser
synced 2026-01-06 10:33:57 +00:00
[SG-69] Billing payment step (#3133)
* billing folder added * initial commit * [SG-74] Trial Initiation Component with Vertical Stepper (#2913) * Vertical stepper PoC * Convert stepper css to tailwind * trial component start * trial component params * tailwind-ify header * Support teams, enterprise, and families layout param and more layout ui work * Some more theming fixes * Rename TrialModule to TrialInitiationModule * Stepper fixes, plus more functionality demo * Cleanup * layout params and placeholders * Only allow trial route to be hit if not logged in * fix typo * Use background-alt2 color for header * Move vertical stepper out of trial-initiation * Create components for the different plan types * Remove width on steps * Remove content projection for label * Tailwind style fixes * Extract step content into a component * Remove layout param for now * Remove step tags * remove pointer classes from step button * Remove most tailwind important designations * Update apps/web/src/app/modules/vertical-stepper/vertical-step.component.ts Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * Tailwind and layout fixes * Remove container * lint & prettier fixes * Remove extra CdkStep declaration * Styles fixes * Style logo directly * Remove 0 margin on image * Fix tiling and responsiveness * Minor padding fixes for org pages * Update apps/web/src/app/modules/trial-initiation/trial-initiation.component.html Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * prettier fix Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * [SG-65] Reusable Registration Form (#2946) * created reusable registration form * fixed conflicts * replicated reactive form changes in other clients * removed comments * client template cleanup * client template cleanup * removed comments in template file * changed to component suffix * switched show password to use component * comments resolution * comments resolution * added toast disable functionality * removed unused locale * mode custom input validator generic * fixed button * fixed linter * removed horizontal rule * switched to button component * Added billng step * Added keys to locale * billing trial initiation step * billing trial initiation step * Dont load billing content until the step is selected * billing trial initiation step * billing trial initiation step * billing trial initiation step * made the get plans endpoint anonymous * merged with master and extra changes * major changes on billing step * billing step sub label * Made changes to billing step sub label * removed unused variable * removed unused logic * cleanup * fixed suggestions * removed unused reference * added billing sub label Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com> Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> Co-authored-by: addison <addisonbeck1@gmail.com>
This commit is contained in:
@@ -43,12 +43,14 @@ export class OrganizationPlansComponent implements OnInit {
|
||||
@Input() providerId: string;
|
||||
@Output() onSuccess = new EventEmitter();
|
||||
@Output() onCanceled = new EventEmitter();
|
||||
@Output() onTrialBillingSuccess = new EventEmitter();
|
||||
|
||||
loading = true;
|
||||
selfHosted = false;
|
||||
productTypes = ProductType;
|
||||
formPromise: Promise<any>;
|
||||
singleOrgPolicyBlock = false;
|
||||
isInTrialFlow = false;
|
||||
discount = 0;
|
||||
|
||||
formGroup = this.formBuilder.group({
|
||||
@@ -149,7 +151,7 @@ export class OrganizationPlansComponent implements OnInit {
|
||||
}
|
||||
|
||||
get selectablePlans() {
|
||||
return this.plans.filter(
|
||||
return this.plans?.filter(
|
||||
(plan) =>
|
||||
!plan.legacyYear && !plan.disabled && plan.product === this.formGroup.controls.product.value
|
||||
);
|
||||
@@ -321,10 +323,18 @@ export class OrganizationPlansComponent implements OnInit {
|
||||
|
||||
await this.apiService.refreshIdentityToken();
|
||||
await this.syncService.fullSync(true);
|
||||
if (!this.acceptingSponsorship) {
|
||||
|
||||
if (!this.acceptingSponsorship && !this.isInTrialFlow) {
|
||||
this.router.navigate(["/organizations/" + orgId]);
|
||||
}
|
||||
|
||||
if (this.isInTrialFlow) {
|
||||
this.onTrialBillingSuccess.emit({
|
||||
orgId: orgId,
|
||||
subLabelText: this.billingSubLabelText(),
|
||||
});
|
||||
}
|
||||
|
||||
return orgId;
|
||||
};
|
||||
|
||||
@@ -448,4 +458,18 @@ export class OrganizationPlansComponent implements OnInit {
|
||||
|
||||
return orgId;
|
||||
}
|
||||
|
||||
private billingSubLabelText(): string {
|
||||
const selectedPlan = this.selectedPlan;
|
||||
const price = selectedPlan.basePrice === 0 ? selectedPlan.seatPrice : selectedPlan.basePrice;
|
||||
let text = "";
|
||||
|
||||
if (selectedPlan.isAnnual) {
|
||||
text += `${this.i18nService.t("annual")} ($${price}/${this.i18nService.t("yr")})`;
|
||||
} else {
|
||||
text += `${this.i18nService.t("monthly")} ($${price}/${this.i18nService.t("monthAbbr")})`;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,11 +58,11 @@
|
||||
</div>
|
||||
<ng-container *ngIf="showMethods && method === paymentMethodType.Card">
|
||||
<div class="row">
|
||||
<div class="form-group col-4">
|
||||
<div [ngClass]="trialFlow ? 'col-4' : 'col-4'" class="form-group">
|
||||
<label for="stripe-card-number-element">{{ "number" | i18n }}</label>
|
||||
<div id="stripe-card-number-element" class="form-control stripe-form-control"></div>
|
||||
</div>
|
||||
<div class="form-group col-8 d-flex align-items-end">
|
||||
<div *ngIf="!trialFlow" class="form-group col-8 d-flex align-items-end">
|
||||
<img
|
||||
src="../../images/cards.png"
|
||||
alt="Visa, MasterCard, Discover, AmEx, JCB, Diners Club, UnionPay"
|
||||
@@ -70,11 +70,11 @@
|
||||
height="32"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group col-4">
|
||||
<div [ngClass]="trialFlow ? 'col-3' : 'col-4'" class="form-group">
|
||||
<label for="stripe-card-expiry-element">{{ "expiration" | i18n }}</label>
|
||||
<div id="stripe-card-expiry-element" class="form-control stripe-form-control"></div>
|
||||
</div>
|
||||
<div class="form-group col-4">
|
||||
<div [ngClass]="trialFlow ? 'col-5' : 'col-4'" class="form-group">
|
||||
<div class="d-flex">
|
||||
<label for="stripe-card-cvc-element">
|
||||
{{ "securityCode" | i18n }}
|
||||
|
||||
@@ -25,6 +25,7 @@ export class PaymentComponent implements OnInit, OnDestroy {
|
||||
@Input() hideBank = false;
|
||||
@Input() hidePaypal = false;
|
||||
@Input() hideCredit = false;
|
||||
@Input() trialFlow = false;
|
||||
|
||||
private destroy$: Subject<void> = new Subject<void>();
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div [ngClass]="trialFlow ? 'col-4' : 'col-3'">
|
||||
<div class="form-group">
|
||||
<label for="addressPostalCode">{{ "zipPostalCode" | i18n }}</label>
|
||||
<input
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, EventEmitter, Output } from "@angular/core";
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
@@ -12,6 +12,7 @@ import { TaxRateResponse } from "@bitwarden/common/models/response/taxRateRespon
|
||||
templateUrl: "tax-info.component.html",
|
||||
})
|
||||
export class TaxInfoComponent {
|
||||
@Input() trialFlow = false;
|
||||
@Output() onCountryChanged = new EventEmitter();
|
||||
|
||||
loading = true;
|
||||
|
||||
Reference in New Issue
Block a user