From bc138ef26cd9411c917bf298fd6832e56883ccd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marl=C3=A8ne=20SIMONDANT?= <msimondant@grandlyon.com> Date: Tue, 23 Jul 2024 14:59:33 +0000 Subject: [PATCH] change(employers&jobs) : new way of choosing an employer and a job (profile + onboarding) --- .../profile-employer-selection.component.html | 35 ++---- .../profile-employer-selection.component.ts | 38 +++---- .../profile-job-selection.component.html | 22 ++-- .../profile-job-selection.component.ts | 51 ++++----- src/app/profile/edit/edit.component.html | 55 +++------- src/app/profile/edit/edit.component.scss | 6 ++ src/app/profile/edit/edit.component.ts | 101 +++++------------- src/app/profile/services/profile.service.ts | 4 +- src/app/shared/components/index.ts | 3 + .../select-or-create.component.html | 51 +++++++++ .../select-or-create.component.scss | 48 +++++++++ .../select-or-create.component.ts | 72 +++++++++++++ .../components/yes-no/yes-no.component.html | 8 +- src/app/shared/shared.module.ts | 2 + 14 files changed, 285 insertions(+), 211 deletions(-) create mode 100644 src/app/shared/components/select-or-create/select-or-create.component.html create mode 100644 src/app/shared/components/select-or-create/select-or-create.component.scss create mode 100644 src/app/shared/components/select-or-create/select-or-create.component.ts diff --git a/src/app/form/form-view/profile-form/profile-employer-selection/profile-employer-selection.component.html b/src/app/form/form-view/profile-form/profile-employer-selection/profile-employer-selection.component.html index 890809ea3..ec57eeb83 100644 --- a/src/app/form/form-view/profile-form/profile-employer-selection/profile-employer-selection.component.html +++ b/src/app/form/form-view/profile-form/profile-employer-selection/profile-employer-selection.component.html @@ -6,30 +6,13 @@ Si vous êtes bénévole, recherchez la structure dans laquelle vous intervenez </p> </div> - <div> - <app-input - id="search-employer" - label="Employeur" - description="Recherchez votre employeur dans la liste suivante" - placeholder="Exemple : employeur" - size="large" - [wide]="true" - [value]="profileForm.get('employer').value.name" - (valueChange)="onSearchChange($event)" - (click)="onSearchChange(profileForm.get('employer').value.name)" - /> - <div class="scroll"> - <div *ngIf="!isAlreadySearching" class="autocomplete-items"> - <div - *ngFor="let employer of employers" - role="button" - tabindex="0" - (click)="selectedResult(employer)" - (keyup.enter)="selectedResult(employer)" - > - <p>{{ employer.name }}</p> - </div> - </div> - </div> - </div> + + <app-select-or-create + [autocompleteFunction]="profileService.getEmployers.bind(profileService)" + [name]="'Employeur'" + [value]="employerName" + (valueChange)="onValueChange()" + (selectItem)="selectedResult($event)" + (createValueChange)="onCreateValueChange($event)" + /> </form> diff --git a/src/app/form/form-view/profile-form/profile-employer-selection/profile-employer-selection.component.ts b/src/app/form/form-view/profile-form/profile-employer-selection/profile-employer-selection.component.ts index e305630b3..abc2f8548 100644 --- a/src/app/form/form-view/profile-form/profile-employer-selection/profile-employer-selection.component.ts +++ b/src/app/form/form-view/profile-form/profile-employer-selection/profile-employer-selection.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { UntypedFormGroup } from '@angular/forms'; import { Employer } from '../../../../models/employer.model'; import { ProfileService } from '../../../../profile/services/profile.service'; @@ -7,16 +7,19 @@ import { ProfileService } from '../../../../profile/services/profile.service'; selector: 'app-profile-employer-selection', templateUrl: './profile-employer-selection.component.html', }) -export class ProfileEmployerSelectionComponent { +export class ProfileEmployerSelectionComponent implements OnInit { @Input() profileForm: UntypedFormGroup; @Output() validateForm = new EventEmitter<Employer>(); - public employers: Employer[]; - public isAlreadySearching = false; - constructor(private profileService: ProfileService) {} + public employerName: string; - public onSearchChange(searchString: string): void { - this.getEmployers(searchString); + constructor(public profileService: ProfileService) {} + + ngOnInit(): void { + this.employerName = this.profileForm.get('employer').value.name; + } + + public onCreateValueChange(searchString: string): void { this.profileForm.get('employer').patchValue({ name: searchString, validated: false, @@ -26,20 +29,19 @@ export class ProfileEmployerSelectionComponent { public selectedResult(employer: Employer): void { this.profileForm.get('employer').patchValue({ - name: employer.name, - validated: employer.validated, + name: employer?.name, + validated: employer?.validated, }); - this.employers = []; + this.employerName = employer?.name; this.validateForm.emit(); } - private getEmployers(searchString = ''): void { - if (!this.isAlreadySearching) { - this.isAlreadySearching = true; - this.profileService.getEmployers(searchString).subscribe((employers) => { - this.employers = employers; - this.isAlreadySearching = false; - }); - } + public onValueChange(): void { + // If the user changes the value in the autocomplete input, set an empty employer to invalidate the form + this.profileForm.get('employer').patchValue({ + name: '', + validated: false, + }); + this.validateForm.emit(); } } diff --git a/src/app/form/form-view/profile-form/profile-job-selection/profile-job-selection.component.html b/src/app/form/form-view/profile-form/profile-job-selection/profile-job-selection.component.html index 196904711..0ad3d4696 100644 --- a/src/app/form/form-view/profile-form/profile-job-selection/profile-job-selection.component.html +++ b/src/app/form/form-view/profile-form/profile-job-selection/profile-job-selection.component.html @@ -4,19 +4,15 @@ <p>Cette information sera visible dans l’annuaire des acteurs, accessible uniquement en version connectée</p> </div> - <div class="tagList"> - <app-tag-item - *ngFor="let job of jobs" - [iconFolder]="'ico'" - [iconName]="isSelectedJob(job) ? 'tag-checked' : 'tag-unchecked'" - [label]="job.name" - [color]="isSelectedJob(job) ? 'green' : 'white'" - [size]="'medium'" - [clickable]="true" - (action)="selectedResult(job)" - /> - </div> - <app-input *ngIf="isUnexistingJob()" label="Quelle fonction occupez-vous ?" (valueChange)="newJob($event)" /> + <app-select-or-create + [name]="'Fonction'" + [isFeminineWord]="true" + [autocompleteFunction]="profileService.getJobs.bind(profileService)" + [value]="jobName" + (valueChange)="onValueChange()" + (selectItem)="selectedResult($event)" + (createValueChange)="onCreateValueChange($event)" + /> <app-appointment-choice *ngIf="hasPersonalOffer" diff --git a/src/app/form/form-view/profile-form/profile-job-selection/profile-job-selection.component.ts b/src/app/form/form-view/profile-form/profile-job-selection/profile-job-selection.component.ts index 69476c8f0..911872da3 100644 --- a/src/app/form/form-view/profile-form/profile-job-selection/profile-job-selection.component.ts +++ b/src/app/form/form-view/profile-form/profile-job-selection/profile-job-selection.component.ts @@ -11,51 +11,40 @@ export class ProfileJobSelectionComponent implements OnInit { @Input() profileForm: UntypedFormGroup; @Output() validateForm = new EventEmitter<Job>(); - public jobs: Job[]; + public jobName: string; public selectedJob: Job; public selectedRdvChoice: boolean; public hasPersonalOffer = false; - constructor(private profileService: ProfileService) {} + constructor(public profileService: ProfileService) {} ngOnInit(): void { - // getJobs - this.profileService.getJobs().subscribe((jobs) => { - this.jobs = [...jobs, new Job({ name: 'Autre' })]; - }); + this.jobName = this.profileForm.get('job').value.name; } - public selectedResult(job: Job): void { - this.selectedJob = job; - if (!this.isUnexistingJob()) { - this.profileForm.get('job').setValue({ - name: job.name, - validated: job.validated, - hasPersonalOffer: job.hasPersonalOffer, - }); - } else { - this.profileForm.get('job').setValue({ - name: '', - validated: false, - hasPersonalOffer: true, - }); - } - this.hasPersonalOffer = job.hasPersonalOffer; + public onCreateValueChange(searchString: string): void { + this.profileForm.get('job').patchValue({ + name: searchString, + validated: false, + }); this.validateForm.emit(); } - public isSelectedJob(job: Job): boolean { - if (this.selectedJob?.name === job.name) return true; - return false; - } - - public isUnexistingJob(): boolean { - return this.selectedJob && this.selectedJob.name === 'Autre'; + public selectedResult(job: Job): void { + this.profileForm.get('job').patchValue({ + name: job?.name, + validated: job?.validated, + hasPersonalOffer: job?.hasPersonalOffer, + }); + this.jobName = job?.name; + this.hasPersonalOffer = job?.hasPersonalOffer; + this.validateForm.emit(); } - public newJob(value: string): void { + public onValueChange(): void { + // If the user changes the value in the autocomplete input, set an empty job to invalidate the form this.profileForm.get('job').patchValue({ - name: value, + name: '', validated: false, }); this.validateForm.emit(); diff --git a/src/app/profile/edit/edit.component.html b/src/app/profile/edit/edit.component.html index 2dcc37c18..eb8bf52c3 100644 --- a/src/app/profile/edit/edit.component.html +++ b/src/app/profile/edit/edit.component.html @@ -124,49 +124,24 @@ </div> <div *ngIf="currentTab === tabsEnum.employer" class="employerJob"> - <div> - <app-input - id="search-employer" - label="Employeur" - description="Recherchez votre employeur dans la liste suivante" - [value]="selectedEmployer?.name" - (valueChange)="onSearchChange($event)" - (click)="onSearchChange(selectedEmployer?.name || '')" - /> - - <div class="structureResults"> - <div *ngIf="!isAlreadySearching" class="autocomplete-items"> - <div - *ngFor="let employer of employers" - role="button" - tabindex="0" - (click)="selectEmployer(employer)" - (keyup.enter)="selectEmployer(employer)" - > - <p>{{ employer.name }}</p> - </div> - </div> - </div> - </div> + <app-select-or-create + [autocompleteFunction]="profileService.getEmployers.bind(profileService)" + [name]="'Employeur'" + [(value)]="employerName" + (selectItem)="selectEmployer($event)" + (createValueChange)="onCreateValueChangeEmployer($event)" + /> <div> - <p class="subTitle">Fonction</p> - <div class="tagList"> - <app-tag-item - *ngFor="let job of jobs" - [iconName]="isSelectedJob(job) ? 'tag-checked' : 'tag-unchecked'" - [label]="job.name" - [color]="isSelectedJob(job) ? 'green' : 'white'" - [clickable]="true" - (action)="selectJob(job)" - /> - </div> + <app-select-or-create + [name]="'Fonction'" + [isFeminineWord]="true" + [autocompleteFunction]="profileService.getJobs.bind(profileService)" + [(value)]="jobName" + (selectItem)="selectJob($event)" + (createValueChange)="onCreateValueChangeJob($event)" + /> </div> - <app-input - *ngIf="isUnexistingJob()" - label="Quelle fonction occupez-vous ?" - (valueChange)="updateNewJob($event)" - /> <app-appointment-choice *ngIf="hasPersonalOffer" diff --git a/src/app/profile/edit/edit.component.scss b/src/app/profile/edit/edit.component.scss index a54db44f4..793ed01e9 100644 --- a/src/app/profile/edit/edit.component.scss +++ b/src/app/profile/edit/edit.component.scss @@ -102,6 +102,12 @@ gap: 1.5rem; } + ::ng-deep .selectOrCreate { + gap: 24px; + padding: 24px; + border: 1px solid $grey-6; + } + .credentialsTab { display: flex; flex-direction: column; diff --git a/src/app/profile/edit/edit.component.ts b/src/app/profile/edit/edit.component.ts index 0f0676f75..2fe8d98a2 100644 --- a/src/app/profile/edit/edit.component.ts +++ b/src/app/profile/edit/edit.component.ts @@ -1,5 +1,5 @@ import { HttpErrorResponse } from '@angular/common/http'; -import { ChangeDetectorRef, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { lastValueFrom } from 'rxjs'; import { Employer } from '../../models/employer.model'; @@ -49,14 +49,14 @@ export class EditComponent implements OnInit { newPasswordConfirm: false, }; public ShowPassword = showPasswordEnum; - public jobs: Job[]; - private newJob: Job = null; - private selectedJob: Job; - public employers: Employer[]; + public selectedJob: Job; + public jobName: string; + public isNewJob: boolean; public selectedEmployer: Employer; + public employerName: string; + public isNewEmployer: boolean; public selectedRdvChoice: boolean; public isAlreadySearching = false; - public isNewEmployer: boolean; public hasPersonalOffer = false; public errorChangeEmail = false; public statusCode = 200; @@ -70,12 +70,9 @@ export class EditComponent implements OnInit { private canDeactivate = false; public appointmentModal = false; - @ViewChild('newJobInput') newJobInput: ElementRef; - constructor( - private profileService: ProfileService, + public profileService: ProfileService, private notificationService: NotificationService, - private cdr: ChangeDetectorRef, private authService: AuthService, private utils: Utils, private router: Router, @@ -91,19 +88,10 @@ export class EditComponent implements OnInit { this.userProfile.description = this.userProfile.description || ''; this.initialUserProfile = new User({ ...profile }); this.selectedEmployer = { ...profile.employer }; + this.employerName = this.selectedEmployer?.name; + this.selectedJob = { ...profile.job }; + this.jobName = this.selectedJob?.name; this.hasPersonalOffer = profile.job?.hasPersonalOffer; - const otherJob = new Job({ name: 'Autre' }); - this.profileService.getJobs().subscribe((jobs) => { - this.jobs = [...jobs, otherJob]; - - // Select "Autre" job and set the job's name - if (jobs.some((job) => job.name === profile.job?.name)) { - this.selectedJob = { ...profile.job }; - } else { - this.selectedJob = otherJob; - this.newJob = profile.job; - } - }); }); } @@ -194,11 +182,6 @@ export class EditComponent implements OnInit { public navigateTo(tab: tabsEnum): void { this.currentTab = tab; - if (tab === tabsEnum.employer) { - this.cdr.detectChanges(); - this.selectEmployer(this.userProfile.employer); - if (this.newJob) this.newJobInput.nativeElement.value = this.userProfile.job.name; - } } public cancel(): void { @@ -287,9 +270,7 @@ export class EditComponent implements OnInit { } public async confirmEmployer(): Promise<void> { - if (this.newJob) { - this.selectedJob = this.newJob; - + if (this.isNewJob) { await lastValueFrom(this.profileService.createJob(this.selectedJob)); } if (this.isNewEmployer) { @@ -392,57 +373,27 @@ export class EditComponent implements OnInit { // Jobs public selectJob(job: Job): void { this.selectedJob = job; - this.newJob = null; - this.hasPersonalOffer = job.hasPersonalOffer; - } - - public isSelectedJob(job: Job): boolean { - if (this.selectedJob?.name === job.name) this.hasPersonalOffer = job.hasPersonalOffer; - return this.selectedJob && this.selectedJob.name === job.name; - } - - public isUnexistingJob(): boolean { - return this.selectedJob?.name === 'Autre'; + this.jobName = this.selectedJob?.name; + this.isNewJob = false; + this.hasPersonalOffer = job?.hasPersonalOffer; } - public updateNewJob(value: string): void { - if (value) { - this.newJob = new Job({ name: value, validated: false, hasPersonalOffer: true }); - } else { - this.newJob = null; - } - this.hasPersonalOffer = this.newJob?.hasPersonalOffer; + public onCreateValueChangeJob(value: string): void { + this.selectedJob = new Job({ name: value, validated: false, hasPersonalOffer: true }); + this.isNewJob = true; + this.hasPersonalOffer = this.selectedJob?.hasPersonalOffer; } // Employer - public onSearchChange(searchString: string): void { - this.getEmployers(searchString); - if (!searchString) { - this.selectedEmployer = null; - } else { - this.selectedEmployer = new Employer({ name: searchString, validated: false }); - if (!this.employers.map((employer) => employer.name).includes(this.selectedEmployer?.name)) { - this.isNewEmployer = true; - } else { - this.isNewEmployer = false; - } - } - } - public selectEmployer(employer: Employer): void { this.selectedEmployer = employer; - this.employers = []; + this.employerName = this.selectedEmployer?.name; this.isNewEmployer = false; } - private getEmployers(searchString = ''): void { - if (!this.isAlreadySearching) { - this.isAlreadySearching = true; - this.profileService.getEmployers(searchString).subscribe((employers) => { - this.employers = employers; - this.isAlreadySearching = false; - }); - } + public onCreateValueChangeEmployer(value: string): void { + this.selectedEmployer = new Employer({ name: value, validated: false }); + this.isNewEmployer = true; } public canExit(): Promise<boolean> { @@ -464,13 +415,10 @@ export class EditComponent implements OnInit { } private employerAndJobValid(): boolean { - // Check if mandatory fields are set (with newJob defined if needed, and rdv defined if needed) + // Check if mandatory fields are set (with rdv defined if needed) if (!this.selectedEmployer || !this.selectedJob) { return false; } - if (this.selectedJob.name === 'Autre' && this.newJob === null) { - return false; - } if (this.hasPersonalOffer && this.selectedRdvChoice === undefined) { return false; } @@ -478,11 +426,10 @@ export class EditComponent implements OnInit { } private employerOrJobHasChanged(): boolean { - // Check if any field has changed : employer or job, or newJob or rdv choice if applicable + // Check if any field has changed : employer or job, or rdv choice if applicable return ( this.selectedEmployer?.name !== this.initialUserProfile.employer?.name || this.selectedJob?.name !== this.initialUserProfile.job?.name || - (this.selectedJob.name === 'Autre' && this.newJob?.name !== this.userProfile.job.name) || (this.hasPersonalOffer && this.selectedRdvChoice !== this.initialUserProfile.withAppointment) ); } diff --git a/src/app/profile/services/profile.service.ts b/src/app/profile/services/profile.service.ts index 363580320..b1baf54e7 100644 --- a/src/app/profile/services/profile.service.ts +++ b/src/app/profile/services/profile.service.ts @@ -94,8 +94,8 @@ export class ProfileService { return this.http.get<Employer[]>(`api/employer?search=${searchString}`); } - public getJobs(): Observable<Job[]> { - return this.http.get<Job[]>(`api/jobs`); + public getJobs(searchString = ''): Observable<Job[]> { + return this.http.get<Job[]>(`api/jobs?search=${searchString}`); } public createJob(value: Job): Observable<Job> { diff --git a/src/app/shared/components/index.ts b/src/app/shared/components/index.ts index 564fa4c38..c30311533 100644 --- a/src/app/shared/components/index.ts +++ b/src/app/shared/components/index.ts @@ -25,6 +25,7 @@ import { PrintStructuresGridComponent } from './print-structures-grid/print-stru import { RadioOptionComponent } from './radio-option/radio-option.component'; import { RadioComponent } from './radio/radio.component'; import { SearchBarComponent } from './search-bar/search-bar.component'; +import { SelectOrCreateComponent } from './select-or-create/select-or-create.component'; import { StructureHoursListComponent } from './structure-hours/structure-hours-list.component'; import { StructurePmrComponent } from './structure-pmr/structure-pmr.component'; import { SvgIconComponent } from './svg-icon/svg-icon.component'; @@ -54,6 +55,7 @@ export { PrintStructuresGridComponent, ProgressBarComponent, RadioOptionComponent, + SelectOrCreateComponent, StructureHoursListComponent, StructurePmrComponent, StructurePublicTargetComponent, @@ -92,6 +94,7 @@ export const SharedComponents = [ RadioOptionComponent, RadioComponent, SearchBarComponent, + SelectOrCreateComponent, StructurePmrComponent, StructurePublicTargetComponent, SvgIconComponent, diff --git a/src/app/shared/components/select-or-create/select-or-create.component.html b/src/app/shared/components/select-or-create/select-or-create.component.html new file mode 100644 index 000000000..67aad1246 --- /dev/null +++ b/src/app/shared/components/select-or-create/select-or-create.component.html @@ -0,0 +1,51 @@ +<div class="selectOrCreate"> + <div class="select"> + <app-input + autocomplete="off" + size="large" + [placeholder]="'exemple : ' + name.toLowerCase()" + [label]="name" + [wide]="true" + [disabled]="isAddingNewItem" + [status]="!isAddingNewItem ? (isSelectedItem ? 'success' : 'error') : null" + [description]="'Recherchez votre ' + name.toLowerCase() + ' dans la liste suivante'" + [value]="isAddingNewItem ? null : value" + (valueChange)="onAutocompleteValueChange($event)" + (click)="onAutocompleteValueChange(value || '')" + /> + <div *ngIf="!isAlreadySearching && !isAddingNewItem" role="list" class="autocomplete-items"> + <div + *ngFor="let hit of data" + role="listitem" + tabindex="0" + (click)="selectResult(hit)" + (keyup.enter)="selectResult(hit)" + > + <p tabindex="none" role="button">{{ hit.name }}</p> + </div> + </div> + </div> + <div class="create"> + <p>Vous ne trouvez pas votre {{ name.toLowerCase() }} ? Créez-l{{ isFeminineWord ? 'a' : 'e' }} ici :</p> + <app-button + *ngIf="!isAddingNewItem" + [variant]="'primaryBlack'" + [label]="'Ajouter ' + (isFeminineWord ? 'la ' : 'l\'') + name.toLowerCase()" + [iconName]="'plus'" + [wide]="true" + (click)="toggleAddItem()" + /> + <div *ngIf="isAddingNewItem" class="createForm"> + <app-input + autocomplete="off" + size="large" + [label]="'Nom de ' + (isFeminineWord ? 'la ' : 'l\'') + (name | lowercase)" + [placeholder]="'exemple : ' + name.toLowerCase()" + [description]="'Renseignez le nom de votre ' + name.toLowerCase()" + [status]="isFieldValid() ? 'success' : 'error'" + (valueChange)="onCreateValueChange($event)" + /> + <app-button label="Annuler la création" [variant]="'primaryBlack'" (click)="toggleAddItem()" /> + </div> + </div> +</div> diff --git a/src/app/shared/components/select-or-create/select-or-create.component.scss b/src/app/shared/components/select-or-create/select-or-create.component.scss new file mode 100644 index 000000000..3b28dfc46 --- /dev/null +++ b/src/app/shared/components/select-or-create/select-or-create.component.scss @@ -0,0 +1,48 @@ +@import 'breakpoint'; +@import 'color'; +@import 'typography'; + +.selectOrCreate { + display: flex; + flex-direction: column; + gap: 40px; + + .select { + .autocomplete-items { + top: -28px; + position: relative; + > div { + border-bottom: 1px solid $grey-7; + } + p { + width: auto; + } + @media #{$phone} { + max-width: 300px; + } + } + } + + .create { + display: flex; + flex-direction: column; + gap: 16px; + .createForm { + display: flex; + flex-direction: row; + gap: 16px; + align-items: center; + flex-grow: 1; + } + p { + @include font-regular-16; + color: $grey-3; + } + app-input { + width: 300px; + } + app-button { + padding-top: 16px; + } + } +} diff --git a/src/app/shared/components/select-or-create/select-or-create.component.ts b/src/app/shared/components/select-or-create/select-or-create.component.ts new file mode 100644 index 000000000..d5be19c9e --- /dev/null +++ b/src/app/shared/components/select-or-create/select-or-create.component.ts @@ -0,0 +1,72 @@ +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; + +@Component({ + selector: 'app-select-or-create', + templateUrl: './select-or-create.component.html', + styleUrls: ['./select-or-create.component.scss'], +}) +export class SelectOrCreateComponent implements OnInit { + @Input() public name: string; + @Input() public value: string; + @Input() public isFeminineWord?: boolean; + @Input() private autocompleteFunction: Function; + + @Output() selectItem = new EventEmitter<any>(); + @Output() valueChange = new EventEmitter<any>(); + @Output() createValueChange = new EventEmitter<any>(); + + public data = []; + public isAlreadySearching = false; + public searchString: string; + public isAddingNewItem = false; + public isSelectedItem = false; + public createValue: string; + + ngOnInit(): void { + if (this.value) { + this.isSelectedItem = true; + } + } + + public onAutocompleteValueChange(value: string): void { + this.isSelectedItem = false; + this.selectItem.emit(null); + this.searchString = value; + if (!this.isAlreadySearching) { + this.isAlreadySearching = true; + this.autocompleteFunction(value).subscribe((data) => { + this.data = data; + this.isAlreadySearching = false; + + // If user typed another string meanwhile, relaunch the search for this new string + if (this.searchString !== value) { + this.onAutocompleteValueChange(this.searchString); + } + }); + } + this.valueChange.emit(value); + } + + public onCreateValueChange(value: string): void { + this.createValue = value; + this.createValueChange.emit(value); + } + + public toggleAddItem(): void { + this.isAddingNewItem = !this.isAddingNewItem; + } + + public selectResult(hit: any): void { + this.isSelectedItem = true; + // Set input value + this.searchString = hit.name; + // Reset autocomplete + this.data = []; + // Emit chosen value + this.selectItem.emit(hit); + } + + public isFieldValid(): boolean { + return this.createValue && this.createValue !== ''; + } +} diff --git a/src/app/shared/components/yes-no/yes-no.component.html b/src/app/shared/components/yes-no/yes-no.component.html index 1db6aa362..d5291e02f 100644 --- a/src/app/shared/components/yes-no/yes-no.component.html +++ b/src/app/shared/components/yes-no/yes-no.component.html @@ -1,15 +1,15 @@ <div class="content"> <app-tag-item - [iconName]="selected ? 'tag-checked' : 'tag-unchecked'" + [iconName]="selected ? 'check' : null" [label]="'Oui'" - [color]="selected ? 'green' : 'white'" + [color]="selected ? 'black' : 'white'" [clickable]="true" (action)="selected = true; clicked()" /> <app-tag-item - [iconName]="selected !== null && !selected ? 'tag-checked' : 'tag-unchecked'" + [iconName]="selected !== null && !selected ? 'check' : null" [label]="'Non'" - [color]="selected !== null && !selected ? 'green' : 'white'" + [color]="selected !== null && !selected ? 'black' : 'white'" [clickable]="true" (action)="selected = false; clicked()" /> diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 792bd3e1e..741c7c8ef 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -10,6 +10,7 @@ import { HourPickerComponent } from './components/hour-picker/hour-picker.compon import { InputComponent } from './components/input/input.component'; import { RadioOptionComponent } from './components/radio-option/radio-option.component'; import { RadioComponent } from './components/radio/radio.component'; +import { SelectOrCreateComponent } from './components/select-or-create/select-or-create.component'; import { TextareaComponent } from './components/textarea/textarea.component'; import { YesNoComponent } from './components/yes-no/yes-no.component'; import { SharedDirectives } from './directives'; @@ -28,6 +29,7 @@ import { SharedPipes } from './pipes'; InputComponent, TextareaComponent, RadioOptionComponent, + SelectOrCreateComponent, YesNoComponent, ], exports: [ -- GitLab