diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1e67572be845ace79a947544e64ac4fa9d0bd67d..81d4c9a1a891d93983a0c08eaf04270d6f391854 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -76,7 +76,9 @@ import { StructureJoinComponent } from './structure/structure-join/structure-joi MapModule, CartoModule, BrowserAnimationsModule, - ToastrModule.forRoot(), + ToastrModule.forRoot({ + enableHtml: true, + }), FormViewModule, OrientationModule, ServiceWorkerModule.register('ngsw-worker.js', { diff --git a/src/app/profile/edit/edit.component.html b/src/app/profile/edit/edit.component.html index 62a0118b7deb7e705ac1e669e2f130b2170494ab..b2e991a978c40d987ebf58afd79283c0e64774a3 100644 --- a/src/app/profile/edit/edit.component.html +++ b/src/app/profile/edit/edit.component.html @@ -111,7 +111,7 @@ <app-appointment-choice *ngIf="hasPersonalOffer" - [selectedRdvChoice]="selectedRdvChoice === undefined ? null : selectedRdvChoice" + [selectedRdvChoice]="selectedRdvChoice$ | async" (rdvChoice)="onRdvRadioChange($event)" (validateForm)="isPageValid()" /> diff --git a/src/app/profile/edit/edit.component.ts b/src/app/profile/edit/edit.component.ts index cf4779b71a4a225124bbcdba3ecee45fe86b5d11..f859851c64d4dab97e5cee0764324a024eb8eff9 100644 --- a/src/app/profile/edit/edit.component.ts +++ b/src/app/profile/edit/edit.component.ts @@ -1,7 +1,7 @@ import { HttpErrorResponse } from '@angular/common/http'; import { Component, Input, OnInit, signal } from '@angular/core'; import { Router } from '@angular/router'; -import { lastValueFrom } from 'rxjs'; +import { BehaviorSubject, lastValueFrom } from 'rxjs'; import { Employer } from '../../models/employer.model'; import { Job } from '../../models/job.model'; import { User } from '../../models/user.model'; @@ -54,12 +54,15 @@ export class EditComponent implements OnInit { public selectedEmployer: Employer; public employerName: string; public isNewEmployer: boolean; - public selectedRdvChoice: boolean; public isAlreadySearching = false; public hasPersonalOffer = false; public errorChangeEmail = false; public statusCode = 200; + private selectedRdvChoiceSubject = new BehaviorSubject<boolean>(false); + selectedRdvChoice$ = this.selectedRdvChoiceSubject.asObservable(); + private currentToastId: number | null = null; + // Modal canExit var public isEmailModalOpen = signal(false); public isPasswordModalOpen = signal(false); @@ -82,7 +85,7 @@ export class EditComponent implements OnInit { this.currentTab = tabsEnum.description; } this.profileService.getProfile().then((profile) => { - if (profile.hasOwnProperty('withAppointment')) this.selectedRdvChoice = profile.withAppointment; + if (profile.hasOwnProperty('withAppointment')) this.selectedRdvChoiceSubject.next(profile.withAppointment); this.userProfile = new User(profile); this.userProfile.description = this.userProfile.description || ''; this.initialUserProfile = new User({ ...profile }); @@ -282,7 +285,7 @@ export class EditComponent implements OnInit { } this.profileService - .updateProfile(this.selectedEmployer.name, this.selectedJob.name, this.selectedRdvChoice) + .updateProfile(this.selectedEmployer.name, this.selectedJob.name, this.selectedRdvChoiceSubject.getValue()) .subscribe({ next: () => { this.router.navigate(['/profil']); @@ -296,7 +299,20 @@ export class EditComponent implements OnInit { } public onRdvRadioChange(value: boolean): void { - this.selectedRdvChoice = value; + if (this.userProfile.personalOffers?.length === 0 && value === true) { + const profileUrl = this.router.serializeUrl(this.router.createUrlTree(['/profil'])); + const errorMessage = `Vous n'avez pas d'offre personnelle, pour sélectionner cette option merci d'en créer une en modifiant une structure dans <a href="${profileUrl}">votre profil</a>`; + this.selectedRdvChoiceSubject.next(false); + // Remove existing toast if there is one + if (this.currentToastId !== null) { + this.notificationService.removeToast(this.currentToastId); + } + // Show a new error toast and store its ID + const newToast = this.notificationService.showError(null, errorMessage, 0, { enableHtml: true }); + this.currentToastId = newToast.toastId; + } else { + this.selectedRdvChoiceSubject.next(value); + } } public confirmDescription(): void { @@ -404,7 +420,7 @@ export class EditComponent implements OnInit { if (this.hasPendingChanges() && !this.canDeactivate) { return new Promise((resolve) => this.showPendingChangesModal(resolve)); } - if (this.hasPersonalOffer && this.selectedRdvChoice === undefined) { + if (this.hasPersonalOffer && this.selectedRdvChoiceSubject.getValue() === undefined) { return new Promise(() => this.isAppointmentModalOpen.set(true)); } return Promise.resolve(true); @@ -423,7 +439,7 @@ export class EditComponent implements OnInit { if (!this.selectedEmployer || !this.selectedJob) { return false; } - if (this.hasPersonalOffer && this.selectedRdvChoice === undefined) { + if (this.hasPersonalOffer && this.selectedRdvChoiceSubject.getValue() === undefined) { return false; } return true; @@ -434,7 +450,7 @@ export class EditComponent implements OnInit { return ( this.selectedEmployer?.name !== this.initialUserProfile.employer?.name || this.selectedJob?.name !== this.initialUserProfile.job?.name || - (this.hasPersonalOffer && this.selectedRdvChoice !== this.initialUserProfile.withAppointment) + (this.hasPersonalOffer && this.selectedRdvChoiceSubject.getValue() !== this.initialUserProfile.withAppointment) ); } diff --git a/src/app/services/notification.service.ts b/src/app/services/notification.service.ts index e23db1f78f2d983299041488806daec78dd1b0cc..6df03a5c3757fee1e2e4ebf77359fe8d04c045ed 100644 --- a/src/app/services/notification.service.ts +++ b/src/app/services/notification.service.ts @@ -24,13 +24,19 @@ export class NotificationService { /** * By default, the error is displayed until clicked on. */ - public showError(title: string, message = '', timeOut = 0): ActiveToast<unknown> { + public showError(title: string, message = '', timeOut = 0, options?: any): ActiveToast<unknown> { return this.toastr.error(message, title, { timeOut: timeOut, disableTimeOut: timeOut === 0, + enableHtml: true, + ...options, }); } + public removeToast(toastId: number): void { + this.toastr.remove(toastId); + } + public showInfo(title: string, message = '', timeOut = 10000): ActiveToast<unknown> { return this.toastr.info(message, title, { timeOut: timeOut, diff --git a/src/app/shared/components/appointment-choice/appointment-choice.component.ts b/src/app/shared/components/appointment-choice/appointment-choice.component.ts index 1ac69cd1e35ac0b819670c6c6a063825ebe8adc6..efa6ea2925a9319d03084a56363bc4c355e276d1 100644 --- a/src/app/shared/components/appointment-choice/appointment-choice.component.ts +++ b/src/app/shared/components/appointment-choice/appointment-choice.component.ts @@ -1,5 +1,4 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Job } from '../../../models/job.model'; @Component({ selector: 'app-appointment-choice', @@ -7,13 +6,12 @@ import { Job } from '../../../models/job.model'; styleUrls: ['./appointment-choice.component.scss'], }) export class AppointmentChoiceComponent { - @Input() selectedRdvChoice: boolean; - @Output() validateForm = new EventEmitter<Job>(); + @Input() selectedRdvChoice: boolean | null; + @Output() validateForm = new EventEmitter<any>(); @Output() rdvChoice = new EventEmitter<boolean>(); public onRdvChoiceChange(value: boolean): void { - this.selectedRdvChoice = value; - this.rdvChoice.emit(this.selectedRdvChoice); + this.rdvChoice.emit(value); this.validateForm.emit(); } } 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 d5291e02fe7fa011c15961f546c32620be1549cd..6f2e5d878fbc4a0a4427acb69de3397cf2fb0970 100644 --- a/src/app/shared/components/yes-no/yes-no.component.html +++ b/src/app/shared/components/yes-no/yes-no.component.html @@ -1,16 +1,16 @@ <div class="content"> <app-tag-item - [iconName]="selected ? 'check' : null" + [iconName]="selected === true ? 'check' : null" [label]="'Oui'" - [color]="selected ? 'black' : 'white'" + [color]="selected === true ? 'black' : 'white'" [clickable]="true" - (action)="selected = true; clicked()" + (action)="clicked(true)" /> <app-tag-item - [iconName]="selected !== null && !selected ? 'check' : null" + [iconName]="selected === false ? 'check' : null" [label]="'Non'" - [color]="selected !== null && !selected ? 'black' : 'white'" + [color]="selected === false ? 'black' : 'white'" [clickable]="true" - (action)="selected = false; clicked()" + (action)="clicked(false)" /> </div> diff --git a/src/app/shared/components/yes-no/yes-no.component.ts b/src/app/shared/components/yes-no/yes-no.component.ts index e8b0867da341970395c833051bb966a6b1444d36..c1461790add62bfc7ddab9387e3d73c4c9483e43 100644 --- a/src/app/shared/components/yes-no/yes-no.component.ts +++ b/src/app/shared/components/yes-no/yes-no.component.ts @@ -7,11 +7,10 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; }) export class YesNoComponent { /** Selected or not */ - @Input({ required: true }) selected: boolean = null; - + @Input() selected: boolean | null = null; @Output() selectedEvent = new EventEmitter<boolean>(); - public clicked(): void { - this.selectedEvent.emit(this.selected); + public clicked(value: boolean): void { + this.selectedEvent.emit(value); } } diff --git a/src/styles.scss b/src/styles.scss index 3c155b8cef15cfb620babc6ca942bc1030c25a2b..7cc4b6a6b95230a4c4a9de0bfa9ee2e899b37cc0 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -100,6 +100,9 @@ a { border: solid 1px $info-error; color: $info-error; background-image: url('assets/ico/toast-error.svg'); + a { + color: $info-error; + } } &.toast-info { border: solid 1px $info-blue;