Skip to content

Commit

Permalink
Merge branch 'develop' into Liuboff/History-of-search-queries-and-oth…
Browse files Browse the repository at this point in the history
…er-related-with-search
  • Loading branch information
Liuboff authored Dec 22, 2024
2 parents 266e33f + 007b0cf commit e51d8db
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 58 deletions.
4 changes: 4 additions & 0 deletions src/app/shared/models/tag.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface Tag {
id: number;
name: string;
}
3 changes: 3 additions & 0 deletions src/app/shared/models/workshop.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export abstract class WorkshopBase {
providerId: string;
providerTitle: string;
providerLicenseStatus: LicenseStatuses;
tagIds: number[];

constructor(about: WorkshopAbout, description: Description, address: Address, teachers: Teacher[], provider: Provider, id?: string) {
this.title = about.title;
Expand All @@ -66,6 +67,7 @@ export abstract class WorkshopBase {
this.teachers = teachers;
this.providerId = provider.id;
this.providerTitle = provider.fullTitle;
this.tagIds = description.tagIds;

if (id) {
this.id = id;
Expand Down Expand Up @@ -216,4 +218,5 @@ interface Description {
keyWords: string[];
imageIds?: string[];
imageFiles?: File[];
tagIds: number[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { NgxsModule } from '@ngxs/store';
import { TagService } from './tag-workshop.service';

describe('TagService', () => {
let service: TagService;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, NgxsModule.forRoot([])]
});
service = TestBed.inject(TagService);
});

it('should be created', () => {
expect(service).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Tag } from 'shared/models/tag.model';
import { Util } from 'shared/utils/utils';

@Injectable({
providedIn: 'root'
})
export class TagService {
constructor(private http: HttpClient) {}

getTags(): Observable<Tag[]> {

Check warning on line 13 in src/app/shared/services/workshops/tag-workshop/tag-workshop.service.ts

View workflow job for this annotation

GitHub Actions / build_and_test

Missing accessibility modifier on method definition getTags
return this.http.get<Tag[]>('/api/v1/Tag/Get', {
params: {
localization: Util.getCurrentLocalization()
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,33 @@
</app-validation-hint>
</mat-radio-group>

<ng-container>
<mat-form-field appearance="none">
<label class="step-label">{{ 'FORMS.LABELS.USER_TAGS' | translate }}</label>
<mat-select
#select
multiple
disableOptionCentering
panelClass="dropdown-panel"
class="step-input list-of-tags"
[compareWith]="compareItems"
[formControl]="tagsControl">
<mat-select-trigger>
<mat-chip-set #chipSet>
<mat-chip *ngFor="let tag of tagsControl.value" (removed)="onRemoveItem(tag)">
<img class="min-logo" src="../../assets/icons/icon_painting.svg" alt="Link" />
<span>{{ tag.name }}</span>
<mat-icon matChipRemove>cancel</mat-icon>
</mat-chip>
</mat-chip-set>
</mat-select-trigger>
<mat-option class="dropdown-option" *ngFor="let tag of tags" [value]="tag">
{{ tag.name }}
</mat-option>
</mat-select>
</mat-form-field>
</ng-container>

<div class="step-label-combined">
<label class="step-label">{{ 'FORMS.LABELS.KEYWORDS' | translate }}</label>
<label class="step-characters-count">{{ keyWords.length }}/{{ validationConstants.MAX_KEYWORDS_LENGTH }}</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,12 @@
.step-label-title {
padding-top: 5px;
}

.min-logo {
width: 20px;
height: 20px;
}

.list-of-tags {
margin: 10px 0 0 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,61 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
import { Component, Input } from '@angular/core';
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 { 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';
import { MatTooltipModule } from '@angular/material/tooltip';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateModule } from '@ngx-translate/core';
import { NgxsModule } from '@ngxs/store';
import { Workshop } from 'shared/models/workshop.model';

import { MaterialModule } from 'shared/modules/material.module';
import { ImageFormControlComponent } from 'shared/components/image-form-control/image-form-control.component';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { forwardRef } from '@angular/core';
import { CreateDescriptionFormComponent } from './create-description-form.component';

@Component({
selector: 'app-validation-hint',
template: ''
})
class MockValidationHintAboutComponent {
@Input() validationFormControl!: FormControl; // required for validation
@Input() minCharacters!: number;
@Input() maxCharacters!: number;
@Input() minMaxDate!: boolean;
}

@Component({
selector: 'app-info-form',
template: ''
})
class MockInfoFormComponent {
@Input() InfoEditFormGroup!: FormGroup;
@Input() index!: number;
@Input() formAmount!: number;
@Input() maxDescriptionLength!: number;
}

describe('CreateDescriptionFormComponent', () => {
let component: CreateDescriptionFormComponent;
let fixture: ComponentFixture<CreateDescriptionFormComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
FormsModule,
ReactiveFormsModule,
FormsModule,
HttpClientTestingModule,
MatFormFieldModule,
MatChipsModule,
NgxsModule.forRoot([]),
MatInputModule,
BrowserAnimationsModule,
MatIconModule,
MatRadioModule,
MatGridListModule,
MatTooltipModule,
MaterialModule,
NgxsModule.forRoot([]),
TranslateModule.forRoot()
],
declarations: [CreateDescriptionFormComponent, ImageFormControlComponent, MockValidationHintAboutComponent, MockInfoFormComponent]
declarations: [CreateDescriptionFormComponent, ImageFormControlComponent, MockValidationHintAboutComponent, MockInfoFormComponent],
providers: [
{
provide: NG_VALUE_ACCESSOR,
// eslint-disable-next-line @angular-eslint/no-forward-ref
useExisting: forwardRef(() => ImageFormControlComponent),
multi: true
}
]
}).compileComponents();
});

Expand All @@ -55,16 +74,10 @@ describe('CreateDescriptionFormComponent', () => {
imageIds: new FormControl(['id1', 'id2', 'id3']),
description: new FormControl(''),
disabilityOptionsDesc: new FormControl(''),
head: new FormControl(''),
keyWords: new FormControl(''),
website: new FormControl(''),
facebook: new FormControl(''),
instagram: new FormControl(''),
formOfLearning: new FormControl(''),
competitiveSelection: new FormControl(''),
categories: new FormControl(''),
institutionHierarchyId: new FormControl(''),
institutionId: new FormControl('')
tagIds: new FormControl([])
});
fixture.detectChanges();
});
Expand All @@ -73,7 +86,7 @@ describe('CreateDescriptionFormComponent', () => {
expect(component).toBeTruthy();
});

it('should add keyword', () => {
it('should add a keyword', () => {
component.keyWordsCtrl.setValue('Test');

component.onKeyWordsInput();
Expand All @@ -82,49 +95,72 @@ describe('CreateDescriptionFormComponent', () => {
expect(component.keyWordsCtrl.value).toBe('');
});

it('should disable input if keyword limit is reached', () => {
it('should disable input if the keyword limit is reached', () => {
component.keyWords = ['one', 'two', 'three', 'four'];
component.keyWordsCtrl.setValue('Test');
component.keyWordsCtrl.setValue('five');

component.onKeyWordsInput();

expect(component.keyWordsCtrl.disabled).toBeTruthy();
});

it('should enable input if keyword limit is less than 5', () => {
it('should enable input if the 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');
it('should remove a keyword', () => {
component.keyWords = ['one', 'two', 'three', 'four'];

component.onRemoveKeyWord('four');

expect(component.keyWords.length).toBe(4);
expect(component.keyWords.length).toBe(3);
});
});

@Component({
selector: 'app-validation-hint',
template: ''
})
class MockValidationHintAboutComponent {
@Input() validationFormControl: FormControl; // required for validation
@Input() minCharacters: number;
@Input() maxCharacters: number;
@Input() minMaxDate: boolean;
}
it('should remove tag from selection', () => {
const mockTag = { id: 1, name: 'TestTag' };
component.tagsControl.setValue([mockTag]);
component.onRemoveItem(mockTag);
expect(component.tagsControl.value).toEqual([]);
});

@Component({
selector: 'app-info-form',
template: ''
})
class MockInfoFormComponent {
@Input() InfoEditFormGroup: FormGroup;
@Input() index: number;
@Input() formAmount: number;
@Input() maxDescriptionLength: number;
}
it('should activate edit mode with workshop data', () => {
component.workshop = {
id: 1,
keywords: ['test'],
withDisabilityOptions: true,
workshopDescriptionItems: [
{
sectionName: 'test section',
description: 'test description'
}
]
} as any;

component.activateEditMode();
expect(component.keyWords).toContain('test');
expect(component.disabilityOptionRadioBtn.value).toBe(true);
});

it('should update tagIds in form group', () => {
const mockTags = [
{ id: 1, name: 'tag1' },
{ id: 2, name: 'tag2' }
];

(component as any).updateTagIds(mockTags);

expect(component.DescriptionFormGroup.get('tagIds').value).toBe(JSON.stringify([1, 2]));
});

it('should mark form as dirty after deletion', () => {
component.onAddForm();
component.DescriptionFormGroup.markAsPristine();
component.onDeleteForm(0);

expect(component.DescriptionFormGroup.dirty).toBe(true);
});
});
Loading

0 comments on commit e51d8db

Please sign in to comment.