diff --git a/jslib b/jslib index 4228277d..1cb3447b 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 a1ebf397..c5b65c90 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 00000000..c5a033bc --- /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 00000000..95401194 --- /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 b5316ea6..cd83cefc 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 7e3a3949..0f95d077 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 f4ed1f5f..993d9e32 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 edfd4030..558309f7 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" + } + } } }