diff --git a/src/app/organizations/settings/delete-organization.component.html b/src/app/organizations/settings/delete-organization.component.html index 17af9539be..2c3cae47a3 100644 --- a/src/app/organizations/settings/delete-organization.component.html +++ b/src/app/organizations/settings/delete-organization.component.html @@ -6,6 +6,7 @@ (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate + *ngIf="loaded" > diff --git a/src/app/organizations/settings/delete-organization.component.ts b/src/app/organizations/settings/delete-organization.component.ts index 6bdb6fbb76..799d916a8b 100644 --- a/src/app/organizations/settings/delete-organization.component.ts +++ b/src/app/organizations/settings/delete-organization.component.ts @@ -1,19 +1,58 @@ -import { Component, EventEmitter, Output } from "@angular/core"; +import { Component, EventEmitter, OnInit, Output } from "@angular/core"; import { ApiService } from "jslib-common/abstractions/api.service"; +import { CipherService } from "jslib-common/abstractions/cipher.service"; import { I18nService } from "jslib-common/abstractions/i18n.service"; import { LogService } from "jslib-common/abstractions/log.service"; +import { OrganizationService } from "jslib-common/abstractions/organization.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { UserVerificationService } from "jslib-common/abstractions/userVerification.service"; +import { CipherType } from "jslib-common/enums/cipherType"; +import { Utils } from "jslib-common/misc/utils"; +import { CipherView } from "jslib-common/models/view/cipherView"; import { Verification } from "jslib-common/types/verification"; +class CountBasedLocalizationKey { + singular: string; + plural: string; + + getKey(count: number) { + return count == 1 ? this.singular : this.plural; + } + + constructor(singular: string, plural: string) { + this.singular = singular; + this.plural = plural; + } +} + +class OrganizationContentSummaryItem { + count: number; + get localizationKey(): string { + return this.localizationKeyOptions.getKey(this.count); + } + private localizationKeyOptions: CountBasedLocalizationKey; + constructor(count: number, localizationKeyOptions: CountBasedLocalizationKey) { + this.count = count; + this.localizationKeyOptions = localizationKeyOptions; + } +} + +class OrganizationContentSummary { + totalItemCount = 0; + itemCountByType: OrganizationContentSummaryItem[] = []; +} + @Component({ selector: "app-delete-organization", templateUrl: "delete-organization.component.html", }) -export class DeleteOrganizationComponent { +export class DeleteOrganizationComponent implements OnInit { organizationId: string; - descriptionKey = "deleteOrganizationDesc"; + loaded: boolean; + deleteOrganizationRequestType: "InvalidFamiliesForEnterprise" | "RegularDelete" = "RegularDelete"; + organizationName: string; + organizationContentSummary: OrganizationContentSummary = new OrganizationContentSummary(); @Output() onSuccess: EventEmitter = new EventEmitter(); masterPassword: Verification; @@ -24,9 +63,15 @@ export class DeleteOrganizationComponent { private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, private userVerificationService: UserVerificationService, - private logService: LogService + private logService: LogService, + private cipherService: CipherService, + private organizationService: OrganizationService ) {} + async ngOnInit(): Promise { + await this.load(); + } + async submit() { try { this.formPromise = this.userVerificationService @@ -43,4 +88,44 @@ export class DeleteOrganizationComponent { this.logService.error(e); } } + + private async load() { + this.organizationName = (await this.organizationService.get(this.organizationId)).name; + this.organizationContentSummary = await this.buildOrganizationContentSummary(); + this.loaded = true; + } + + private async buildOrganizationContentSummary(): Promise { + const organizationContentSummary = new OrganizationContentSummary(); + const organizationItems = ( + await this.cipherService.getAllFromApiForOrganization(this.organizationId) + ).filter((item) => item.deletedDate == null); + + if (organizationItems.length < 1) { + return organizationContentSummary; + } + + organizationContentSummary.totalItemCount = organizationItems.length; + for (const cipherType of Utils.iterateEnum(CipherType)) { + const count = this.getOrganizationItemCountByType(organizationItems, cipherType); + if (count > 0) { + organizationContentSummary.itemCountByType.push( + new OrganizationContentSummaryItem( + count, + this.getOrganizationItemLocalizationKeysByType(CipherType[cipherType]) + ) + ); + } + } + + return organizationContentSummary; + } + + private getOrganizationItemCountByType(items: CipherView[], type: CipherType) { + return items.filter((item) => item.type == type).length; + } + + private getOrganizationItemLocalizationKeysByType(type: string): CountBasedLocalizationKey { + return new CountBasedLocalizationKey(`type${type}`, `type${type}Plural`); + } } diff --git a/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts b/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts index 36b92b61fe..ee99d19eed 100644 --- a/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts +++ b/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts @@ -129,7 +129,7 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit { this.deleteModalRef, (comp) => { comp.organizationId = organizationId; - comp.descriptionKey = "orgCreatedSponsorshipInvalid"; + comp.deleteOrganizationRequestType = "InvalidFamiliesForEnterprise"; comp.onSuccess.subscribe(() => { this.router.navigate(["/"]); }); diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index 147f78340b..612bf822f2 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -300,6 +300,18 @@ "typeSecureNote": { "message": "Secure Note" }, + "typeLoginPlural": { + "message": "Logins" + }, + "typeCardPlural": { + "message": "Cards" + }, + "typeIdentityPlural": { + "message": "Identities" + }, + "typeSecureNotePlural": { + "message": "Secure Notes" + }, "folders": { "message": "Folders" }, @@ -2782,11 +2794,26 @@ "deleteOrganization": { "message": "Delete Organization" }, - "deleteOrganizationDesc": { - "message": "Proceed below to delete this organization and all associated data. Individual user accounts will remain, though they will not be associated to this organization anymore. " + "deletingOrganizationContentWarning": { + "message": "Enter the master password to confirm deletion of $ORGANIZATION$ and all associated data. Vault data in $ORGANIZATION$ includes:", + "placeholders": { + "organization": { + "content": "$1", + "example": "My Org Name" + } + } }, - "deleteOrganizationWarning": { - "message": "Deleting the organization is permanent. It cannot be undone." + "deletingOrganizationActiveUserAccountsWarning": { + "message": "User accounts will remain active after deletion but will no longer be associated to this organization." + }, + "deletingOrganizationIsPermanentWarning": { + "message": "Deleting $ORGANIZATION$ is permanent and irreversible.", + "placeholders": { + "organization": { + "content": "$1", + "example": "My Org Name" + } + } }, "organizationDeleted": { "message": "Organization Deleted"