diff --git a/jslib b/jslib index 4228277d235..1cb3447bdd3 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 4228277d23503d563560b44a652293d23233aa1b +Subproject commit 1cb3447bdd3531d08eb77a8b7a0ad65124428a09 diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a1ebf397f58..c5b65c90750 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -52,6 +52,7 @@ import { UserAddEditComponent as OrgUserAddEditComponent } from './organizations import { UserGroupsComponent as OrgUserGroupsComponent } from './organizations/manage/user-groups.component'; import { AccountComponent as OrgAccountComponent } from './organizations/settings/account.component'; +import { AdjustSeatsComponent } from './organizations/settings/adjust-seats.component'; import { DeleteOrganizationComponent } from './organizations/settings/delete-organization.component'; import { OrganizationBillingComponent } from './organizations/settings/organization-billing.component'; import { SettingsComponent as OrgSettingComponent } from './organizations/settings/settings.component'; @@ -149,6 +150,7 @@ import { SearchPipe } from 'jslib/angular/pipes/search.pipe'; AccountComponent, AddEditComponent, AdjustPaymentComponent, + AdjustSeatsComponent, AdjustStorageComponent, ApiActionDirective, AppComponent, diff --git a/src/app/organizations/settings/adjust-seats.component.html b/src/app/organizations/settings/adjust-seats.component.html new file mode 100644 index 00000000000..c5a033bc5d7 --- /dev/null +++ b/src/app/organizations/settings/adjust-seats.component.html @@ -0,0 +1,26 @@ +
+
+

{{(add ? 'addSeats' : 'removeSeats') | i18n}}

+
+
+ + +
+
+
+ {{'total' | i18n}}: {{seatAdjustment || 0}} × {{seatPrice | currency:'$'}} = {{adjustedSeatTotal + | currency:'$'}} /{{interval | i18n}} +
+ + + + {{(add ? 'seatsAddNote' : 'seatsRemoveNote') | i18n}} + +
+
diff --git a/src/app/organizations/settings/adjust-seats.component.ts b/src/app/organizations/settings/adjust-seats.component.ts new file mode 100644 index 00000000000..9540119460b --- /dev/null +++ b/src/app/organizations/settings/adjust-seats.component.ts @@ -0,0 +1,58 @@ +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 { SeatRequest } from 'jslib/models/request/seatRequest'; + +@Component({ + selector: 'app-adjust-seats', + templateUrl: 'adjust-seats.component.html', +}) +export class AdjustSeatsComponent { + @Input() seatPrice = 0; + @Input() add = true; + @Input() organizationId: string; + @Input() interval = 'year'; + @Output() onAdjusted = new EventEmitter(); + @Output() onCanceled = new EventEmitter(); + + seatAdjustment = 0; + formPromise: Promise; + + constructor(private apiService: ApiService, private i18nService: I18nService, + private analytics: Angulartics2, private toasterService: ToasterService) { } + + async submit() { + try { + const request = new SeatRequest(); + request.seatAdjustment = this.seatAdjustment; + if (!this.add) { + request.seatAdjustment *= -1; + } + + this.formPromise = this.apiService.postOrganizationSeat(this.organizationId, request); + await this.formPromise; + this.analytics.eventTrack.next({ action: this.add ? 'Added Seats' : 'Removed Seats' }); + this.toasterService.popAsync('success', null, + this.i18nService.t('adjustedSeats', request.seatAdjustment.toString())); + this.onAdjusted.emit(this.seatAdjustment); + } catch { } + } + + cancel() { + this.onCanceled.emit(); + } + + get adjustedSeatTotal(): number { + return this.seatAdjustment * this.seatAdjustment; + } +} diff --git a/src/app/organizations/settings/organization-billing.component.html b/src/app/organizations/settings/organization-billing.component.html index b5316ea6ca0..cd83cefc8d7 100644 --- a/src/app/organizations/settings/organization-billing.component.html +++ b/src/app/organizations/settings/organization-billing.component.html @@ -90,6 +90,22 @@ {{'cancelSubscription' | i18n}} +

{{'userSeats' | i18n}}

+

{{'subscriptionUserSeats' | i18n : billing.seats}}

+ +
+
+ + +
+ +
+

{{'storage' | i18n}}

{{'subscriptionStorage' | i18n : billing.maxStorageGb || 0 : billing.storageName || '0 MB'}}

diff --git a/src/app/organizations/settings/organization-billing.component.ts b/src/app/organizations/settings/organization-billing.component.ts index 7e3a394914e..0f95d077d8c 100644 --- a/src/app/organizations/settings/organization-billing.component.ts +++ b/src/app/organizations/settings/organization-billing.component.ts @@ -30,6 +30,8 @@ export class OrganizationBillingComponent implements OnInit { loading = false; firstLoaded = false; organizationId: string; + adjustSeatsAdd = true; + showAdjustSeats = false; adjustStorageAdd = true; showAdjustStorage = false; showAdjustPayment = false; @@ -146,6 +148,18 @@ export class OrganizationBillingComponent implements OnInit { } } + adjustSeats(add: boolean) { + this.adjustSeatsAdd = add; + this.showAdjustSeats = true; + } + + closeSeats(load: boolean) { + this.showAdjustSeats = false; + if (load) { + this.load(); + } + } + adjustStorage(add: boolean) { this.adjustStorageAdd = add; this.showAdjustStorage = true; @@ -216,6 +230,23 @@ export class OrganizationBillingComponent implements OnInit { } get seatPrice() { - return 4; + switch (this.billing.planType) { + case PlanType.EnterpriseMonthly: + return 4; + case PlanType.EnterpriseAnnually: + return 3; + case PlanType.TeamsMonthly: + return 2.5; + case PlanType.TeamsAnnually: + return 2; + default: + return 0; + } + } + + get canAdjustSeats() { + return this.billing.planType === PlanType.EnterpriseMonthly || + this.billing.planType === PlanType.EnterpriseAnnually || + this.billing.planType === PlanType.TeamsMonthly || this.billing.planType === PlanType.TeamsAnnually; } } diff --git a/src/app/settings/adjust-storage.component.html b/src/app/settings/adjust-storage.component.html index f4ed1f5fdbf..993d9e325ab 100644 --- a/src/app/settings/adjust-storage.component.html +++ b/src/app/settings/adjust-storage.component.html @@ -5,7 +5,7 @@
+ min="0" max="99" step="1" required>
diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index edfd40306cc..558309f7566 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -1445,10 +1445,10 @@ "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." + "message": "Adding storage 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." + "message": "Removing storage will result in adjustments to your billing totals that will be prorated as credits toward your next billing charge." }, "adjustedStorage": { "message": "Adjusted $AMOUNT$ GB of storage.", @@ -2222,5 +2222,43 @@ }, "enterInstallationId": { "message": "Enter your installation id" + }, + "addSeats": { + "message": "Add Seats", + "description": "Seat = User Seat" + }, + "removeSeats": { + "message": "Remove Seats", + "description": "Seat = User Seat" + }, + "subscriptionUserSeats": { + "message": "Your subscription allows for a total of $COUNT$ users.", + "placeholders": { + "count": { + "content": "$1", + "example": "50" + } + } + }, + "seatsToAdd": { + "message": "Seats To Add" + }, + "seatsToRemove": { + "message": "Seats To Remove" + }, + "seatsAddNote": { + "message": "Adding user seats 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." + }, + "seatsRemoveNote": { + "message": "Removing user seats will result in adjustments to your billing totals that will be prorated as credits toward your next billing charge." + }, + "adjustedSeats": { + "message": "Adjusted $AMOUNT$ user seats.", + "placeholders": { + "amount": { + "content": "$1", + "example": "15" + } + } } }