diff --git a/package.json b/package.json index edcdf0882d..bcfd2aba7e 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "dependencies": { "@angular-slider/ngx-slider": "^16.0.1", "@angular/animations": "^16.2.12", - "@angular/cdk": "^16.2.14", + "@angular/cdk": "16.2.14", "@angular/common": "^16.2.12", "@angular/compiler": "^16.2.12", "@angular/core": "^16.2.12", diff --git a/src/app/shared/modules/material.module.ts b/src/app/shared/modules/material.module.ts index 5afa56e450..302db6551d 100644 --- a/src/app/shared/modules/material.module.ts +++ b/src/app/shared/modules/material.module.ts @@ -11,7 +11,7 @@ import { MatLegacyAutocompleteModule as MatAutocompleteModule } from '@angular/m import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button'; import { MatLegacyCardModule as MatCardModule } from '@angular/material/legacy-card'; import { MatLegacyCheckboxModule as MatCheckboxModule } from '@angular/material/legacy-checkbox'; -import { MatLegacyChipsModule as MatChipsModule } from '@angular/material/legacy-chips'; +import { MatChipsModule } from '@angular/material/chips'; import { MatDialogModule } from '@angular/material/dialog'; import { MatLegacyFormFieldModule as MatFormFieldModule } from '@angular/material/legacy-form-field'; import { MatLegacyInputModule as MatInputModule } from '@angular/material/legacy-input'; diff --git a/src/app/shared/styles/create-form.scss b/src/app/shared/styles/create-form.scss index 0e28396c2a..36eb0c317e 100644 --- a/src/app/shared/styles/create-form.scss +++ b/src/app/shared/styles/create-form.scss @@ -108,11 +108,11 @@ button:focus { height: auto; } -.mat-chip-list ::ng-deep .mat-chip-list-wrapper { +.mat-set ::ng-deep .mat-chip-set-wrapper { padding-right: 10px; } -.mat-chip-list ::ng-deep .mat-chip { +.mat-chip-set ::ng-deep .mat-chip { span { overflow: hidden; text-overflow: ellipsis; diff --git a/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.html b/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.html index 656f1b440e..eb650bfc67 100644 --- a/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.html +++ b/src/app/shell/admin-tools/data/directions-wrapper/directions-institution-hierarchies-edit-form/directions-institution-hierarchies-edit-form.component.html @@ -38,13 +38,13 @@

{{ 'TITLES.EDIT_INSTITUTION_HIERARCHY_FORM_TITLE' | tr [compareWith]="compareItems" [formControl]="this.directionsControl"> - + - + {{ direction.title }} cancel - + {{ direction.title }} diff --git a/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.html b/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.html index a87aa20c01..6f21758652 100644 --- a/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.html +++ b/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.html @@ -68,12 +68,12 @@ [compareWith]="compareSocialGroups" [formControl]="socialGroupControl"> - + {{ group.name }} cancel - + {{ group.name }} diff --git a/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.spec.ts b/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.spec.ts index 0b8dea6999..e1407f9384 100644 --- a/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.spec.ts +++ b/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.spec.ts @@ -10,7 +10,7 @@ import { MatLegacyInputModule as MatInputModule } from '@angular/material/legacy import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select'; import { MatRadioModule } from '@angular/material/radio'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { TranslateModule } from '@ngx-translate/core'; +import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { NgxsModule } from '@ngxs/store'; import { KeyFilterDirective } from 'shared/directives/key-filter.directive'; @@ -19,6 +19,7 @@ import { ChildFormComponent } from './child-form.component'; describe('ChildFormComponent', () => { let component: ChildFormComponent; let fixture: ComponentFixture; + let translate: TranslateService; beforeEach(async () => { await TestBed.configureTestingModule({ @@ -56,13 +57,23 @@ describe('ChildFormComponent', () => { placeOfLiving: new FormControl(''), certificateOfBirth: new FormControl('') }); - + translate = TestBed.inject(TranslateService); fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); + + it('should remove all chips when language changes', () => { + const mockChip = { remove: jest.fn() }; + + (component as any).chipSet = { _chips: [mockChip] }; + + translate.use('uk'); + + expect(mockChip.remove).toHaveBeenCalled(); + }); }); @Component({ diff --git a/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.ts b/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.ts index ee32774925..9543b37df0 100644 --- a/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.ts +++ b/src/app/shell/personal-cabinet/parent/create-child/child-form/child-form.component.ts @@ -1,6 +1,6 @@ import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { AbstractControl, FormControl, FormGroup } from '@angular/forms'; -import { MatLegacyChipList as MatChipList } from '@angular/material/legacy-chips'; +import { MatChipSet } from '@angular/material/chips'; import { MatLegacyOption as MatOption } from '@angular/material/legacy-core'; import { MatLegacySelect as MatSelect } from '@angular/material/legacy-select'; import { LangChangeEvent, TranslateService } from '@ngx-translate/core'; @@ -34,9 +34,9 @@ export class ChildFormComponent implements OnInit, OnDestroy { @ViewChild('select') private select: MatSelect; - @ViewChild('chipList') - private chipList: MatChipList; + @ViewChild('chipSet') + private chipSet: MatChipSet; public readonly validationConstants = ValidationConstants; public socialGroupControl: FormControl = new FormControl([]); @@ -63,7 +63,9 @@ export class ChildFormComponent implements OnInit, OnDestroy { this.translateService.onLangChange.pipe(takeUntil(this.destroy$)).subscribe(({ lang }: LangChangeEvent) => { this.store.dispatch(new GetSocialGroup(lang)); - this.chipList.chips.forEach((chip) => chip.remove()); + this.chipSet._chips.forEach((chip) => { + chip.remove(); + }); }); } diff --git a/src/app/shell/personal-cabinet/provider/create-achievement/create-achievement.component.html b/src/app/shell/personal-cabinet/provider/create-achievement/create-achievement.component.html index 0223516fcf..de101da389 100644 --- a/src/app/shell/personal-cabinet/provider/create-achievement/create-achievement.component.html +++ b/src/app/shell/personal-cabinet/provider/create-achievement/create-achievement.component.html @@ -45,7 +45,7 @@

{{ 'FORMS.HEADERS.ADD_ACHIEVEMENT' | translate }}

placeholder="{{ 'FORMS.PLACEHOLDERS.CHILDREN' | translate }}" [compareWith]="compareEntities"> - + {{ 'FORMS.HEADERS.ADD_ACHIEVEMENT' | translate }}

cancel - +
{{ 'FORMS.HEADERS.ADD_ACHIEVEMENT' | translate }} placeholder="{{ 'FORMS.PLACEHOLDERS.SELECT_TEACHER' | translate }}" [compareWith]="compareEntities"> - +
{{ 'FORMS.HEADERS.ADD_ACHIEVEMENT' | translate }}
cancel
-
+
diff --git a/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.html b/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.html index 70c304e5c8..e4ce47462e 100644 --- a/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.html +++ b/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.html @@ -56,28 +56,27 @@
- {{ 'FORMS.PLACEHOLDERS.KEYWORDS_START' | translate }} {{ validationConstants.MAX_KEYWORDS_LENGTH }} {{ 'FORMS.PLACEHOLDERS.KEYWORDS_END' | translate }} - - + +
{{ keyWord }}
close -
- + -
+
diff --git a/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.spec.ts b/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.spec.ts index d5c10591ff..64b9bf4c50 100644 --- a/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.spec.ts +++ b/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.spec.ts @@ -4,7 +4,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatGridListModule } from '@angular/material/grid-list'; import { MatIconModule } from '@angular/material/icon'; -import { MatLegacyChipsModule as MatChipsModule } from '@angular/material/legacy-chips'; +import { MatChipsModule } from '@angular/material/chips'; import { MatLegacyFormFieldModule as MatFormFieldModule } from '@angular/material/legacy-form-field'; import { MatLegacyInputModule as MatInputModule } from '@angular/material/legacy-input'; import { MatRadioModule } from '@angular/material/radio'; @@ -64,6 +64,39 @@ describe('CreateDescriptionFormComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should add keyword', () => { + component.keyWordsCtrl.setValue('Test'); + + component.onKeyWordsInput(); + + expect(component.keyWords).toEqual(['test']); + expect(component.keyWordsCtrl.value).toBe(''); + }); + + it('should disable input if keyword limit is reached', () => { + component.keyWords = ['one', 'two', 'three', 'four']; + component.keyWordsCtrl.setValue('Test'); + + component.onKeyWordsInput(); + + expect(component.keyWordsCtrl.disabled).toBeTruthy(); + }); + + it('should enable input if keyword limit is less than 5', () => { + component.keyWords = ['one', 'two', 'three', 'four', 'five']; + + component.onRemoveKeyWord('one'); + + expect(component.keyWordsCtrl.disabled).toBeFalsy(); + }); + it('should remove keyword', () => { + component.keyWords = ['one', 'two', 'three', 'four', 'five']; + + component.onRemoveKeyWord('five'); + + expect(component.keyWords.length).toBe(4); + }); }); @Component({ diff --git a/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.ts b/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.ts index 9d77878fd9..9891ef1d2e 100644 --- a/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.ts +++ b/src/app/shell/personal-cabinet/provider/create-workshop/create-description-form/create-description-form.component.ts @@ -2,7 +2,7 @@ import { Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; - +import { COMMA, ENTER } from '@angular/cdk/keycodes'; import { CropperConfigurationConstants } from 'shared/constants/constants'; import { MUST_CONTAIN_LETTERS } from 'shared/constants/regex-constants'; import { ValidationConstants } from 'shared/constants/validation'; @@ -44,8 +44,8 @@ export class CreateDescriptionFormComponent implements OnInit, OnDestroy { public keyWord: string; public disabilityOptionRadioBtn: FormControl = new FormControl(false); - public disabledKeyWordsInput = false; + public separatorKeysCodes = [COMMA, ENTER]; private destroy$: Subject = new Subject(); constructor(private formBuilder: FormBuilder) { @@ -81,11 +81,11 @@ export class CreateDescriptionFormComponent implements OnInit, OnDestroy { * @param word */ public onRemoveKeyWord(word: string): void { - if (this.keyWords.indexOf(word) >= 0) { - this.disabledKeyWordsInput = false; - this.keyWords.splice(this.keyWords.indexOf(word), 1); + if (this.keyWords.includes(word)) { + this.keyWords = this.keyWords.filter((kw) => kw !== word); + this.updateKeywordsInputState(); if (this.keyWords.length) { - this.DescriptionFormGroup.get('keyWords').setValue([...this.keyWords]); + this.DescriptionFormGroup.get('keyWords').setValue(this.keyWords); } else { this.DescriptionFormGroup.get('keyWords').reset(); } @@ -94,22 +94,13 @@ export class CreateDescriptionFormComponent implements OnInit, OnDestroy { public onKeyWordsInput(isEditMode: boolean = true): void { this.DescriptionFormGroup.get('keyWords').markAsTouched(); - if (this.keyWord) { - const inputKeyWord = this.keyWord.trim().toLowerCase(); - if (!!this.keyWord.trim() && !this.keyWords.includes(inputKeyWord)) { - if (this.keyWords.length < 5) { - this.keyWords.push(inputKeyWord); - this.DescriptionFormGroup.get('keyWords').setValue([...this.keyWords], { emitEvent: isEditMode }); - this.keyWordsCtrl.setValue(null); - this.keyWord = ''; - } - this.disabledKeyWordsInput = this.keyWords.length >= 5; - // TODO: Find better workaround for FormControl disable - if (this.disabledKeyWordsInput) { - this.keyWordsCtrl.disable({ emitEvent: false }); - } else { - this.keyWordsCtrl.enable({ emitEvent: false }); - } + const inputKeyWord = this.keyWordsCtrl.value?.trim().toLowerCase(); + if (inputKeyWord && !this.keyWords.includes(inputKeyWord)) { + if (this.keyWords.length < this.validationConstants.MAX_KEYWORDS_LENGTH) { + this.keyWords = [...this.keyWords, inputKeyWord]; + this.updateKeywordsInputState(); + this.DescriptionFormGroup.get('keyWords').setValue(this.keyWords, { emitEvent: isEditMode }); + this.keyWordsCtrl.setValue(''); } } } @@ -238,4 +229,12 @@ export class CreateDescriptionFormComponent implements OnInit, OnDestroy { this.DescriptionFormGroup.markAsDirty({ onlySelf: true }); } } + + private updateKeywordsInputState(): void { + if (this.keyWords.length >= this.validationConstants.MAX_KEYWORDS_LENGTH) { + this.keyWordsCtrl.disable({ emitEvent: false }); + } else { + this.keyWordsCtrl.enable({ emitEvent: false }); + } + } } diff --git a/yarn.lock b/yarn.lock index 939e38dd7e..b1283b51d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -218,7 +218,7 @@ dependencies: tslib "^2.3.0" -"@angular/cdk@^16.2.14": +"@angular/cdk@16.2.14": version "16.2.14" resolved "https://registry.yarnpkg.com/@angular/cdk/-/cdk-16.2.14.tgz#d26f8f1e7d2466b509e60489b6acf31bfe923acf" integrity sha512-n6PrGdiVeSTEmM/HEiwIyg6YQUUymZrb5afaNLGFRM5YL0Y8OBqd+XhCjb0OfD/AfgCUtedVEPwNqrfW8KzgGw== @@ -5626,7 +5626,7 @@ enquirer@~2.3.6: dependencies: ansi-colors "^4.1.1" -entities@^4.2.0, entities@^4.3.0, entities@^4.4.0: +entities@^4.2.0, entities@^4.3.0, entities@^4.4.0, entities@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== @@ -9486,13 +9486,20 @@ parse5@6.0.1: resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== -parse5@^7.0.0, parse5@^7.1.1, parse5@^7.1.2: +parse5@^7.0.0, parse5@^7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== dependencies: entities "^4.4.0" +parse5@^7.1.2: + version "7.2.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.1.tgz#8928f55915e6125f430cc44309765bf17556a33a" + integrity sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ== + dependencies: + entities "^4.5.0" + parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -10685,7 +10692,16 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -10772,7 +10788,14 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -11719,7 +11742,7 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -11737,6 +11760,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"