diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 63f714e89e..77fb246843 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -101,7 +101,24 @@ export class AppComponent implements OnDestroy, OnInit { break; case 'syncCompleted': break; + case 'upgradeOrganization': + const upgradeConfirmed = await this.platformUtilsService.showDialog( + this.i18nService.t('upgradeOrganizationDesc'), this.i18nService.t('upgradeOrganization'), + this.i18nService.t('upgradeOrganization'), this.i18nService.t('cancel')); + if (upgradeConfirmed) { + this.router.navigate(['organizations', message.organizationId, 'settings', 'billing']); + } + break; + case 'premiumRequired': + const premiumConfirmed = await this.platformUtilsService.showDialog( + this.i18nService.t('premiumRequiredDesc'), this.i18nService.t('premiumRequired'), + this.i18nService.t('learnMore'), this.i18nService.t('cancel')); + if (premiumConfirmed) { + this.router.navigate(['settings/premium']); + } + break; default: + break; } }); }); diff --git a/src/app/organizations/vault/add-edit.component.ts b/src/app/organizations/vault/add-edit.component.ts index 9a23bc9321..fada8af1d0 100644 --- a/src/app/organizations/vault/add-edit.component.ts +++ b/src/app/organizations/vault/add-edit.component.ts @@ -11,6 +11,7 @@ import { AuditService } from 'jslib/abstractions/audit.service'; import { CipherService } from 'jslib/abstractions/cipher.service'; import { FolderService } from 'jslib/abstractions/folder.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; +import { MessagingService } from 'jslib/abstractions/messaging.service'; import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { StateService } from 'jslib/abstractions/state.service'; @@ -36,9 +37,11 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit { analytics: Angulartics2, toasterService: ToasterService, auditService: AuditService, stateService: StateService, tokenService: TokenService, totpService: TotpService, - passwordGenerationService: PasswordGenerationService, private apiService: ApiService) { + passwordGenerationService: PasswordGenerationService, private apiService: ApiService, + messagingService: MessagingService) { super(cipherService, folderService, i18nService, platformUtilsService, analytics, - toasterService, auditService, stateService, tokenService, totpService, passwordGenerationService); + toasterService, auditService, stateService, tokenService, totpService, passwordGenerationService, + messagingService); } protected async loadCipher() { diff --git a/src/app/organizations/vault/vault.component.ts b/src/app/organizations/vault/vault.component.ts index ddeb4696d9..dac4e895b3 100644 --- a/src/app/organizations/vault/vault.component.ts +++ b/src/app/organizations/vault/vault.component.ts @@ -12,6 +12,7 @@ import { } from '@angular/router'; import { I18nService } from 'jslib/abstractions/i18n.service'; +import { MessagingService } from 'jslib/abstractions/messaging.service'; import { SyncService } from 'jslib/abstractions/sync.service'; import { UserService } from 'jslib/abstractions/user.service'; @@ -50,7 +51,7 @@ export class VaultComponent implements OnInit { constructor(private route: ActivatedRoute, private userService: UserService, private location: Location, private router: Router, private syncService: SyncService, private i18nService: I18nService, - private componentFactoryResolver: ComponentFactoryResolver) { } + private componentFactoryResolver: ComponentFactoryResolver, private messagingService: MessagingService) { } ngOnInit() { this.route.parent.params.subscribe(async (params) => { @@ -139,6 +140,11 @@ export class VaultComponent implements OnInit { } editCipherAttachments(cipher: CipherView) { + if (this.organization.maxStorageGb == null || this.organization.maxStorageGb === 0) { + this.messagingService.send('upgradeOrganization', { organizationId: cipher.organizationId }); + return; + } + if (this.modal != null) { this.modal.close(); } diff --git a/src/app/settings/two-factor-setup.component.html b/src/app/settings/two-factor-setup.component.html index c04fc7c324..385c0e87a5 100644 --- a/src/app/settings/two-factor-setup.component.html +++ b/src/app/settings/two-factor-setup.component.html @@ -20,7 +20,7 @@

{{p.name}} - + {{'premium' | i18n}}

diff --git a/src/app/settings/two-factor-setup.component.ts b/src/app/settings/two-factor-setup.component.ts index 32403329b2..d49deeacfd 100644 --- a/src/app/settings/two-factor-setup.component.ts +++ b/src/app/settings/two-factor-setup.component.ts @@ -8,6 +8,7 @@ import { } from '@angular/core'; import { ApiService } from 'jslib/abstractions/api.service'; +import { MessagingService } from 'jslib/abstractions/messaging.service'; import { TokenService } from 'jslib/abstractions/token.service'; import { TwoFactorProviders } from 'jslib/services/auth.service'; @@ -42,7 +43,7 @@ export class TwoFactorSetupComponent implements OnInit { private modal: ModalComponent = null; constructor(private apiService: ApiService, private tokenService: TokenService, - private componentFactoryResolver: ComponentFactoryResolver) { } + private componentFactoryResolver: ComponentFactoryResolver, private messagingService: MessagingService) { } async ngOnInit() { this.premium = this.tokenService.getPremium(); @@ -125,6 +126,14 @@ export class TwoFactorSetupComponent implements OnInit { this.openModal(this.recoveryModalRef, TwoFactorRecoveryComponent); } + async premiumRequired() { + const premium = await this.tokenService.getPremium(); + if (!premium) { + this.messagingService.send('premiumRequired'); + return; + } + } + private openModal(ref: ViewContainerRef, type: Type): T { if (this.modal != null) { this.modal.close(); diff --git a/src/app/vault/add-edit.component.html b/src/app/vault/add-edit.component.html index 9e577b011c..c65fea9242 100644 --- a/src/app/vault/add-edit.component.html +++ b/src/app/vault/add-edit.component.html @@ -50,8 +50,7 @@ - + @@ -81,6 +80,12 @@
+ + {{'premium' | i18n}} + + + {{'upgrade' | i18n}} +
@@ -364,8 +369,8 @@ - diff --git a/src/app/vault/add-edit.component.ts b/src/app/vault/add-edit.component.ts index d4b87c552b..40a537d6fc 100644 --- a/src/app/vault/add-edit.component.ts +++ b/src/app/vault/add-edit.component.ts @@ -12,6 +12,7 @@ import { AuditService } from 'jslib/abstractions/audit.service'; import { CipherService } from 'jslib/abstractions/cipher.service'; import { FolderService } from 'jslib/abstractions/folder.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; +import { MessagingService } from 'jslib/abstractions/messaging.service'; import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { StateService } from 'jslib/abstractions/state.service'; @@ -40,7 +41,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit { analytics: Angulartics2, toasterService: ToasterService, auditService: AuditService, stateService: StateService, protected tokenService: TokenService, protected totpService: TotpService, - protected passwordGenerationService: PasswordGenerationService) { + protected passwordGenerationService: PasswordGenerationService, protected messagingService: MessagingService) { super(cipherService, folderService, i18nService, platformUtilsService, analytics, toasterService, auditService, stateService); } @@ -94,6 +95,18 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit { return confirmed; } + async premiumRequired() { + const premium = await this.tokenService.getPremium(); + if (!premium) { + this.messagingService.send('premiumRequired'); + return; + } + } + + async upgradeOrganization() { + this.messagingService.send('upgradeOrganization', { organizationId: this.cipher.organizationId }); + } + protected cleanUp() { if (this.totpInterval) { window.clearInterval(this.totpInterval); diff --git a/src/app/vault/vault.component.html b/src/app/vault/vault.component.html index 3b77360813..d715ca47f9 100644 --- a/src/app/vault/vault.component.html +++ b/src/app/vault/vault.component.html @@ -49,6 +49,17 @@
+
+
+ {{'updateKeyTitle' | i18n}} +
+
+

{{'updateEncryptionKeyShortDesc' | i18n}}

+ +
+
@@ -61,17 +72,6 @@
-
-
- {{'updateKeyTitle' | i18n}} -
-
-

{{'updateEncryptionKeyShortDesc' | i18n}}

- -
-
{{'organizations' | i18n}} diff --git a/src/app/vault/vault.component.ts b/src/app/vault/vault.component.ts index 900ceedeeb..eff835fee9 100644 --- a/src/app/vault/vault.component.ts +++ b/src/app/vault/vault.component.ts @@ -32,8 +32,10 @@ import { ShareComponent } from './share.component'; import { CryptoService } from 'jslib/abstractions/crypto.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; +import { MessagingService } from 'jslib/abstractions/messaging.service'; import { SyncService } from 'jslib/abstractions/sync.service'; import { TokenService } from 'jslib/abstractions/token.service'; +import { UserService } from 'jslib/abstractions/user.service'; @Component({ selector: 'app-vault', @@ -66,7 +68,8 @@ export class VaultComponent implements OnInit { constructor(private syncService: SyncService, private route: ActivatedRoute, private router: Router, private location: Location, private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver, - private tokenService: TokenService, private cryptoService: CryptoService) { } + private tokenService: TokenService, private cryptoService: CryptoService, + private messagingService: MessagingService, private userService: UserService) { } async ngOnInit() { this.showVerifyEmail = !(await this.tokenService.getEmailVerified()); @@ -157,7 +160,19 @@ export class VaultComponent implements OnInit { this.ciphersComponent.searchText = searchText; } - editCipherAttachments(cipher: CipherView) { + async editCipherAttachments(cipher: CipherView) { + const premium = await this.tokenService.getPremium(); + if (cipher.organizationId == null && !premium) { + this.messagingService.send('premiumRequired'); + return; + } else if (cipher.organizationId != null) { + const org = await this.userService.getOrganization(cipher.organizationId); + if (org != null && (org.maxStorageGb == null || org.maxStorageGb === 0)) { + this.messagingService.send('upgradeOrganization', { organizationId: cipher.organizationId }); + return; + } + } + if (this.modal != null) { this.modal.close(); } diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index f64c8de09e..f2df3710a4 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -1026,6 +1026,12 @@ "premiumMembership": { "message": "Premium Membership" }, + "premiumRequired": { + "message": "Premium Required" + }, + "premiumRequiredDesc": { + "message": "A premium membership is required to use this feature." + }, "manage": { "message": "Manage" }, @@ -2301,5 +2307,14 @@ }, "loading": { "message": "Loading" + }, + "upgrade": { + "message": "Upgrade" + }, + "upgradeOrganization": { + "message": "Upgrade Organization" + }, + "upgradeOrganizationDesc": { + "message": "This feature is not available for free organizations. Switch to a paid plan to unlock more features." } }