Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • web-et-numerique/factory/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client
1 result
Show changes
Showing
with 840 additions and 545 deletions
......@@ -10,15 +10,10 @@ a {
}
.structrue-details-container {
border-right: solid 1px $grey-4;
page-break-after: always;
background-color: $white;
top: 0;
left: 0;
max-width: 980px;
width: 100%;
margin-bottom: 50px;
padding: 10px 24px;
width: 64%;
margin-top: 1%;
float: right;
@media #{$tablet} {
width: calc(100% - 2 * 24px);
position: inherit;
......@@ -33,8 +28,6 @@ a {
}
.structrue-details-container > .structure-details-block {
padding: 0px 0px 24px 0;
border-bottom: 1px dashed $grey-2;
.subtitle {
text-transform: uppercase;
@include cn-bold-16;
......@@ -132,7 +125,7 @@ p,
height: 25px;
border-radius: 20px;
padding: 5px 15px;
color: white;
color: $white;
border-style: none;
margin-top: 15px;
background: #348899;
......
<app-structure-print-header
class="multi-print"
[beneficiaryNeedCommentary]="beneficiaryNeedCommentary"
[beneficiaryName]="beneficiaryName"
[structureAccompaniment]="structureAccompaniment"
[beneficiaryPassNumeric]="beneficiaryPassNumeric"
[contactAccompaniment]="contactAccompaniment"
[filters]="filters"
></app-structure-print-header>
<div class="multi-print" *ngFor="let structure of structures">
<app-structure-print-header
[beneficiaryNeedCommentary]="beneficiaryNeedCommentary"
[beneficiaryName]="beneficiaryName"
[structureAccompaniment]="structureAccompaniment"
[beneficiaryPassNumeric]="beneficiaryPassNumeric"
[contactAccompaniment]="contactAccompaniment"
[filters]="filters"
></app-structure-print-header>
<app-structure-detail-print [structure]="structure"></app-structure-detail-print>
</div>
<div class="loader">
<img class="loader-gif" src="/assets/gif/loader_circle.gif" alt />
<p>Liste en cours d'impression</p>
</div>
@import '../../../../../assets/scss/color';
@import '../../../../../assets/scss/layout';
.list-to-print {
height: 600px;
overflow-x: hidden;
......@@ -5,14 +8,42 @@
}
.multi-print {
:host {
background-color: $grey-6;
}
::ng-deep {
.structrue-details-container {
page-break-after: always;
height: 100%;
margin-top: 2%;
margin-left: 34%;
height: 98%;
}
.print-header {
page-break-after: always;
height: 100%;
}
}
page-break-after: always;
-webkit-print-color-adjust: exact;
width: 50%;
margin-left: 23%;
margin-right: 23%;
padding-left: 2%;
padding-right: 2%;
height: 100%;
overflow-x: hidden;
background-color: $white;
@media screen {
display: none;
}
@media print {
width: 100%;
margin: 0;
padding: 0;
}
}
.loader {
height: calc(100vh - #{$header-height} - #{$footer-height});
@media print {
display: none;
}
}
import { Component, Input, OnInit } from '@angular/core';
import { Structure } from '../../../../models/structure.model';
import * as _ from 'lodash';
import { ActivatedRoute } from '@angular/router';
import { PrintService } from '../../../../shared/service/print.service';
import { Filter } from '../../../../structure-list/models/filter.model';
import Module from 'module';
@Component({
selector: 'app-structure-list-print',
templateUrl: './structure-list-print.component.html',
styleUrls: ['./structure-list-print.component.scss'],
})
export class StructureListPrintComponent implements OnInit {
export class StructureListPrintComponent {
@Input() public structures: Structure[];
@Input() public filters: Filter[];
@Input() public beneficiaryNeedCommentary: string;
......@@ -18,8 +15,4 @@ export class StructureListPrintComponent implements OnInit {
@Input() public structureAccompaniment: string;
@Input() public beneficiaryPassNumeric: boolean;
@Input() public contactAccompaniment: string;
constructor(private printService: PrintService, private route: ActivatedRoute) {}
async ngOnInit(): Promise<void> {}
}
<div class="print-header" fxLayout="column">
<div class="header-print" fxLayout="row" fxLayoutAlign="space-between center">
<h3>Fiche d'orientation</h3>
<h4 class="typeInformationHeader">{{ date }}</h4>
</div>
<!-- Name -->
<div *ngIf="beneficiaryName">
<p class="bold">{{ beneficiaryName }}</p>
</div>
<!-- Accompaniment -->
<div *ngIf="structureAccompaniment">
<div class="typeInformationHeader">Orienté par</div>
<div class="contactAccompaniment" fxLayout="row" fxLayoutAlign="space-between center">
<div class="bold">{{ structureAccompaniment }}</div>
<!-- Contact -->
<div class="bold" *ngIf="contactAccompaniment">{{ contactAccompaniment }}</div>
</div>
</div>
<!-- Needs -->
<div *ngIf="equipments.length > 0">
<p class="typeInformationHeader">Besoins en matériel</p>
<div fxLayout="row wrap" fxLayoutGap="16px">
<div *ngFor="let equipmentTag of equipments" class="tags-cloud" fxLayout="row">
{{ equipmentTag.text ? equipmentTag.text : equipmentTag.value }}
<div class="header-print">
<div class="header-infos">
<svg aria-hidden="true" aria-hidden="true">
<use [attr.xlink:href]="'assets/form/sprite.svg#grandLyonLaMetropole'"></use>
</svg>
<div class="header-title">
<div>RES’IN : Réseau des acteurs de l'inclusion numérique de la Métropole de Lyon</div>
<h3>Fiche d'orientation</h3>
</div>
</div>
<p class="informationHeader date">{{ date }}</p>
</div>
<div *ngIf="formations.length > 0">
<p class="typeInformationHeader">Besoins en formation</p>
<div fxLayout="row wrap" fxLayoutGap="16px">
<div *ngFor="let formationTag of formations" class="tags-cloud" fxLayout="row">
{{ formationTag.text ? formationTag.text : formationTag.value }}
</div>
</div>
</div>
<div *ngIf="assistances.length > 0">
<p class="typeInformationHeader">Besoins d'accompagnement</p>
<div fxLayout="row wrap" fxLayoutGap="16px">
<div *ngFor="let assistanceTag of assistances" class="tags-cloud" fxLayout="row">
{{ assistanceTag.text ? assistanceTag.text : assistanceTag.value }}
<div class="informations">
<div class="helper">
<!-- Accompaniment -->
<div *ngIf="structureAccompaniment">
<div class="informationHeader">{{ 'Orienté par' | uppercase }}</div>
<p class="bold">{{ structureAccompaniment }}</p>
<!-- Contact -->
<p class="bold" *ngIf="contactAccompaniment">{{ contactAccompaniment }}</p>
<p class="bold" *ngIf="contactAccompanimentPhone">{{ contactAccompanimentPhone }}</p>
</div>
</div>
</div>
<div *ngIf="specificNeeds.length > 0">
<div class="typeInformationHeader">Besoins spécifiques'</div>
<div fxLayout="row wrap" fxLayoutGap="16px">
<div *ngFor="let specificNeed of specificNeeds" class="tags-cloud" fxLayout="row">
{{ specificNeed.text ? specificNeed.text : specificNeed.value }}
</div>
<div class="beneficiary">
<div class="informationHeader">{{ 'Bénéficiaire' | uppercase }}</div>
<!-- Name -->
<table class="beneficiaryNeeds">
<tr>
<td class="informationHeader">Nom</td>
<td class="bold">{{ beneficiaryName }}</td>
</tr>
<tr *ngIf="equipments.length > 0">
<td class="informationHeader">Besoin(s) en matériel</td>
<td class="bold">
<div *ngFor="let equipmentTag of equipments">
{{ equipmentTag.text ? equipmentTag.text : equipmentTag.value }}
</div>
</td>
</tr>
<tr *ngIf="assistances.length > 0">
<td class="informationHeader">Besoin(s) en formation</td>
<td class="bold">
<div *ngFor="let assistanceTag of assistances">
{{ assistanceTag.text ? assistanceTag.text : assistanceTag.value }}
</div>
</td>
</tr>
<tr *ngIf="formations.length > 0">
<td class="informationHeader">Besoin(s) d'accompagnement</td>
<td class="bold">
<div *ngFor="let formationTag of formations">
{{ formationTag.text ? formationTag.text : formationTag.value }}
</div>
</td>
</tr>
<tr *ngIf="specificNeeds.length > 0">
<td class="informationHeader">Besoin(s) spécifiques</td>
<td class="bold">
<div *ngFor="let specificNeed of specificNeeds">
{{ specificNeed.text ? specificNeed.text : specificNeed.value }}
</div>
</td>
</tr>
<tr *ngIf="beneficiaryPassNumeric">
<td class="informationHeader">Pass Numérique</td>
<td class="bold">Oui</td>
</tr>
<tr *ngIf="beneficiaryNeedCommentary">
<td class="informationHeader">Informations</td>
<td class="bold">{{ beneficiaryNeedCommentary }}</td>
</tr>
</table>
</div>
</div>
<!-- Pass Numeric -->
<div *ngIf="beneficiaryPassNumeric" class="inputRow" fxLayout="row" fxLayoutGap="13px">
<app-svg-icon [type]="'ico'" [icon]="'passNumeric'"></app-svg-icon>
<p class="bold">Pass Numérique</p>
</div>
<!-- Comments -->
<div *ngIf="beneficiaryNeedCommentary">
<div class="typeInformationHeader">Informations à destination de la structure</div>
<p>{{ beneficiaryNeedCommentary }}</p>
</div>
</div>
......@@ -9,17 +9,54 @@
margin-top: 20px;
margin-bottom: 20px;
width: 100%;
border-bottom: solid black 1px;
}
.print-header {
page-break-after: always;
height: 100%;
.header-infos {
height: 80px;
display: flex;
.header-title {
width: 70%;
float: left;
}
h3 {
margin-top: 3px;
}
svg {
max-width: fit-content;
width: 30%;
}
}
.date {
float: right;
}
.beneficiaryNeeds {
td {
vertical-align: top;
}
border-collapse: separate;
border-spacing: 10px 15px;
}
.informationsHeader {
min-width: 35%;
margin-bottom: 5px;
color: $black;
}
.typeInformationHeader {
@include cn-bold-16;
margin-bottom: 5px;
color: $grey-3;
&.date {
color: $grey-3;
font-style: italic;
}
}
.contactAccompaniment {
......@@ -33,7 +70,7 @@
height: 28px;
border-radius: 20px;
padding: 5px 15px;
color: white;
color: $white;
border-style: none;
margin-top: 5px;
background: #348899;
......@@ -58,3 +95,26 @@
text-align: right;
}
}
.informations {
width: 100%;
display: flex;
.helper {
max-height: 300px;
background-color: $grey-6;
width: 30%;
height: fit-content;
padding: 2%;
}
.beneficiary {
background-color: $grey-6;
margin-left: 2%;
padding: 2%;
width: 70%;
}
tr {
margin-bottom: 8px;
}
}
import { Component, Input, OnInit } from '@angular/core';
import { Structure } from '../../../../models/structure.model';
import * as _ from 'lodash';
import { ActivatedRoute } from '@angular/router';
import { PrintService } from '../../../../shared/service/print.service';
import Module from 'module';
import { Filter } from '../../../../structure-list/models/filter.model';
@Component({
selector: 'app-structure-print-header',
......@@ -16,6 +14,7 @@ export class StructurePrintHeaderComponent implements OnInit {
@Input() public structureAccompaniment: string;
@Input() public beneficiaryPassNumeric: boolean;
@Input() public contactAccompaniment: string | null;
@Input() public contactAccompanimentPhone: string | null;
@Input() public filters: Filter[];
public date: string;
......
......@@ -4,61 +4,24 @@
@import '../../../assets/scss/color';
@import '../../../assets/scss/typography';
.title {
margin-top: 20px;
}
.body-wrap {
height: 400px;
}
.left-pane {
width: 529px;
min-width: 500px;
height: 600px;
overflow: auto;
overflow-x: hidden;
padding: 0 25px 0 0;
@media #{$tablet} {
width: 100%;
min-width: unset;
&.mapPhone {
display: none !important;
}
}
}
.right-pane {
width: 400px;
max-height: 400px;
padding: 0 16px;
@media #{$tablet} {
display: none;
&.mapPhone {
display: block;
}
width: 100%;
padding: 0;
}
}
.deep-map ::ng-deep #map {
height: 380px;
}
.tags-cloud {
cursor: pointer;
font-style: normal;
justify-content: center;
align-items: center;
height: 28px;
border-radius: 20px;
padding: 5px 15px;
color: white;
padding: 4px 12px;
color: $white;
border-style: none;
margin-top: 15px;
background: #348899;
margin-top: 4px;
background: $blue;
&.unchecked {
background: #bdbdbd;
background: $grey-4;
}
}
......@@ -89,42 +52,38 @@
}
.nbStructuresLabel {
color: $white;
@include cn-regular-16;
display: grid;
align-items: center;
display: flex;
text-align: center;
height: 32px;
background-color: $grey-4;
padding-left: 9px;
color: $grey-3;
width: 100%;
align-items: center;
@media #{$large-phone} {
padding-left: unset;
}
}
.footer {
.nbStructuresLabel::before,
.nbStructuresLabel::after {
border-top: 0.0625em solid;
content: '';
flex: 1;
margin: 0 0.5em;
}
.form-footer {
padding: 17px 0;
width: 100%;
max-width: 960px;
margin: 20px auto;
text-align: center;
&.desktop {
@media #{$tablet} {
display: none;
}
}
&.phone {
display: none;
@media #{$tablet} {
margin: 0 auto;
border-top: 1px solid $grey-4;
display: block;
}
}
z-index: calc($btn-phone-switch-map-list-z-index - 1);
background: $grey-6;
}
.btnSwitch {
position: fixed;
left: 50%;
bottom: $footer-height + 5px;
bottom: 0;
transform: translate(-50%, -50%);
margin: 0 auto;
display: none;
......@@ -132,25 +91,213 @@
display: block;
opacity: 0.8;
z-index: $btn-phone-switch-map-list-z-index;
margin-bottom: 60px;
}
@media #{$large-phone} {
}
#body {
background-color: $grey-6;
}
.content {
min-height: 450px;
background-color: $white;
margin-left: 25%;
margin-right: 24%;
@media #{$tablet} {
width: 100%;
height: 100vh !important;
margin: 0;
border-bottom: $grey-4 solid 1px;
min-height: unset;
}
p {
&.notRequired {
font-size: 14px;
margin-top: 0px;
font-style: italic;
color: $secondary-color;
&.lg {
font-size: 17px;
}
}
}
}
.loader-gif {
@media #{$desktop} {
width: 20%;
.content-container {
width: 97%;
float: right;
height: 58vh;
padding: unset;
// height: 100%;
@media #{$tablet} {
height: 57vh !important;
}
@media #{$large-desktop} {
width: 20%;
@media #{$desktop} {
height: 100%;
}
@media #{$large-phone} {
width: 100%;
::ng-deep .structure-card .structure {
margin-right: 16px;
}
@media #{$small-phone} {
width: 100%;
::ng-deep .structure-card:last-child .structure {
border-bottom: unset !important;
}
}
::ng-deep #search-address {
width: 400px !important;
@media #{$phone} {
width: 250px !important;
}
}
.progress-container {
margin-top: 1%;
margin-left: 25.5%;
width: 50%;
@media #{$tablet} {
margin: 0 16px;
width: calc(100% - 32px);
}
.progressBar {
height: #{$progressBar-height};
progress {
height: 6px;
border-radius: 7px;
&::-webkit-progress-bar {
background-color: $white-1;
}
&::-webkit-progress-value {
background-color: $secondary-color;
border-radius: 12px;
}
&.validate {
&::-webkit-progress-value {
background-color: $green-1;
}
}
}
}
}
.title {
margin-top: 20px;
padding-bottom: 3%;
}
.last-page {
width: 96%;
margin-left: 2%;
}
.page {
float: left;
padding-top: 2%;
padding-bottom: 5%;
textarea {
margin-top: 1%;
}
.textarea-char {
font-style: italic;
color: $grey-3;
}
.section {
margin-top: 0.5%;
}
@media #{$tablet} {
width: calc(100vw - 32px);
}
}
.left-pane {
width: 100%;
height: 100%;
overflow: auto;
overflow-x: hidden;
@media #{$tablet} {
width: 100%;
min-width: unset;
}
}
.carto {
display: flex;
float: left;
min-height: 500px;
width: 100%;
border-bottom: $grey-4 solid 1px;
@media #{$tablet} {
min-height: 50vh;
}
.left-col {
padding-left: 16px;
margin-left: 1%;
background-color: $white;
padding-right: 16px;
width: 30%;
@media #{$tablet} {
width: 100%;
min-width: unset;
height: 100vh;
&.mapPhone {
display: none !important;
}
}
}
.right-col {
width: 67%;
padding-left: 2%;
padding-right: 2%;
margin-bottom: 2%;
@media #{$tablet} {
display: none;
height: 100vh;
&.mapPhone {
display: block;
}
width: 100%;
padding: 0;
}
}
.filters {
margin-bottom: 1%;
margin-top: 7%;
.filters-title {
color: $grey-3;
}
}
}
input {
width: 400px;
&.email-placeholder::placeholder {
color: $white-2;
font-style: italic;
}
}
.print-structure-container {
::ng-deep .structrue-details-container {
border-bottom: solid 1px $grey-3;
margin-bottom: 4%;
}
}
.print-structure-container:last-child {
::ng-deep .structrue-details-container {
border-bottom: none;
}
}
import { stringify } from '@angular/compiler/src/util';
import { Component, EventEmitter, HostListener, OnInit, Output } from '@angular/core';
import { AbstractControl, Form, FormArray, FormControl, FormGroup, Validators } from '@angular/forms';
import { Meta } from '@angular/platform-browser';
import { GeoJson } from '../../map/models/geojson.model';
import { Address } from '../../models/address.model';
import { OrientationFormFilters } from '../../models/orientation-filter.object';
......@@ -15,6 +16,8 @@ import { Filter } from '../../structure-list/models/filter.model';
import { Module } from '../../structure-list/models/module.model';
import { SearchService } from '../../structure-list/services/search.service';
import { PageTypeEnum } from './pageType.enum';
import { Utils } from '../../utils/utils';
import { CustomRegExp } from '../../utils/CustomRegExp';
@Component({
selector: 'app-orientation-form',
......@@ -29,6 +32,9 @@ export class OrientationFormComponent implements OnInit {
public isMapPhone = false;
public isLoading = false;
// Map auto locate with address
public userLocation = [];
public orientationForm: FormGroup;
// Page and progress var
......@@ -51,11 +57,11 @@ export class OrientationFormComponent implements OnInit {
public numberAssistanceChecked;
public filters: Filter[] = [];
public uncheckedFilters: Filter[] = [];
public equipments: Module[] = [];
public assistance: Module[] = [];
public formation: Module[] = [];
public selectedFormations: Category[] = [];
public baseSkillssReferentiel: Category;
public accessRightsReferentiel: Category;
public digitalCultureSecuritysReferentiel: Category;
......@@ -71,6 +77,7 @@ export class OrientationFormComponent implements OnInit {
public showFormation: boolean;
public multiPrint: boolean = false;
public displayModal = false;
public structuresList: Structure[];
public structuresToPrint: Structure[] = [];
......@@ -79,13 +86,20 @@ export class OrientationFormComponent implements OnInit {
private routerListener: RouterListenerService,
private searchService: SearchService,
private structureService: StructureService,
private geoJsonService: GeojsonService
private geoJsonService: GeojsonService,
private meta: Meta,
public utils: Utils
) {}
ngOnInit(): void {
this.orientationForm = this.createOrientationForm(new OrientationFormFilters());
this.setValidationsForm();
this.setCategories();
this.meta.updateTag({
name: 'description',
content:
"Permet aux professionnels d'être aidés dans l'accompagnement d'un usager en fragilité numérique pour trouver une réponse adaptée.",
});
}
private async setCategories(): Promise<void> {
......@@ -95,6 +109,7 @@ export class OrientationFormComponent implements OnInit {
});
const categs = await this.searchService.getCategoriesTraining().toPromise();
categs.forEach((categ) => {
this.selectedFormations.push(categ);
categ.modules.forEach((module) => {
this.formation.push(module);
});
......@@ -150,8 +165,15 @@ export class OrientationFormComponent implements OnInit {
commune: new FormControl('', Validators.required),
}),
structureAccompaniment: new FormControl(orientationFormFilters.structureAccompaniment, Validators.required),
contactAccompaniment: new FormControl(orientationFormFilters.contactAccompaniment),
beneficiaryName: new FormControl(orientationFormFilters.beneficiaryName),
contactAccompanimentPhone: new FormControl(
orientationFormFilters.contactAccompanimentPhone,
Validators.pattern(CustomRegExp.PHONE)
),
contactAccompanimentEmail: new FormControl(
orientationFormFilters.contactAccompanimentEmail,
Validators.pattern(CustomRegExp.EMAIL)
),
beneficiaryName: new FormControl(orientationFormFilters.beneficiaryName, Validators.required),
beneficiaryNeedCommentary: new FormControl(orientationFormFilters.beneficiaryNeedCommentary),
});
}
......@@ -169,33 +191,21 @@ export class OrientationFormComponent implements OnInit {
if (this.currentPage === this.nbPagesForm - 1) {
this.validateForm();
} else {
if (
this.currentPage === this.pageTypeEnum.beneficiaryNeed &&
this.orientationForm.get('assistance').value.length + this.orientationForm.get('formation').value.length == 0 &&
this.orientationForm.get('equipments').value.length > 0
) {
this.noPassNumeric = true;
this.getOrientationControl('passNumeric').setValue(false);
this.currentPage++;
this.progressStatus += 100 / this.nbPagesForm;
}
this.currentPage++;
this.progressStatus += 100 / this.nbPagesForm;
this.updatePageValid();
document.getElementsByClassName('content')[0].scrollTo(0, 0);
}
}
public previousPage(): void {
// Check if going to the first page
if (this.currentPage === 0) {
//go back to home ? previous page
this.previousUrl();
} else {
if (this.currentPage === this.pageTypeEnum.beneficiaryInfo && this.noPassNumeric) {
this.currentPage--;
}
if (this.currentPage == this.nbPagesForm - 1) this.progressStatus -= (100 / this.nbPagesForm) * 2;
else this.progressStatus -= 100 / this.nbPagesForm;
this.currentPage--;
this.progressStatus -= 100 / this.nbPagesForm;
this.setStructuresAndCoord();
this.updatePageValid();
}
......@@ -224,19 +234,27 @@ export class OrientationFormComponent implements OnInit {
this.orientationForm.get('formation').value.length >
0,
};
this.pagesValidation[PageTypeEnum.beneficiaryPassNumeric] = {
valid: this.getOrientationControl('passNumeric').valid,
this.pagesValidation[PageTypeEnum.beneficiaryInfo] = {
valid:
this.getOrientationControl('passNumeric').value != null &&
this.getOrientationControl('beneficiaryName').value &&
this.getOrientationControl('beneficiaryName').value.length != 0,
};
this.pagesValidation[PageTypeEnum.beneficiaryInfo] = { valid: this.orientationForm.get('address').valid };
this.pagesValidation[PageTypeEnum.beneficiaryAccompaniment] = {
valid:
this.getOrientationControl('structureAccompaniment').valid &&
this.getOrientationControl('contactAccompaniment').valid &&
this.getOrientationControl('beneficiaryName').valid,
this.getOrientationControl('contactAccompanimentPhone').valid &&
this.getOrientationControl('contactAccompanimentEmail').valid,
};
this.pagesValidation[PageTypeEnum.beneficiaryNeedCommentary] = {
valid: this.getOrientationControl('beneficiaryNeedCommentary').valid,
};
this.pagesValidation[PageTypeEnum.beneficiaryAddress] = {
valid: true,
};
this.pagesValidation[PageTypeEnum.beneficiaryAddress] = {
valid: true,
};
this.pagesValidation[PageTypeEnum.printResults] = { valid: true };
this.pagesValidation[PageTypeEnum.structuresSelection] = { valid: this.structuresToPrint.length > 0 };
......@@ -285,7 +303,18 @@ export class OrientationFormComponent implements OnInit {
}
public updateChoice(choice: string, controlName: string): void {
this.onCheckChange(!this.isInArray(choice, controlName), controlName, choice);
if (choice == null) this.unCheckAll(controlName);
else this.onCheckChange(!this.isInArray(choice, controlName), controlName, choice);
}
public isEmpty(formControlName: string): boolean {
const formArray: FormArray = this.orientationForm.get(formControlName) as FormArray;
return formArray.length < 1;
}
public unCheckAll(formControlName: string) {
const formArray: FormArray = this.orientationForm.get(formControlName) as FormArray;
formArray.clear();
}
public onCheckChange(event: boolean, formControlName: string, value: string): void {
......@@ -315,8 +344,10 @@ export class OrientationFormComponent implements OnInit {
this.getOrientationControl('address').get('numero').setValue(address.numero);
this.getOrientationControl('address').get('street').setValue(address.street);
this.getOrientationControl('address').get('commune').setValue(address.commune);
this.userLocation = address.coordinates;
} else {
this.orientationForm.get('address').reset();
this.userLocation = null;
}
this.setValidationsForm();
}
......@@ -326,8 +357,13 @@ export class OrientationFormComponent implements OnInit {
this.setValidationsForm();
}
public setContactAccompaniment(contact: string): void {
this.getOrientationControl('contactAccompaniment').setValue(contact);
public setContactAccompanimentPhone(phone: string): void {
this.getOrientationControl('contactAccompanimentPhone').setValue(this.utils.modifyPhoneValue(phone));
this.setValidationsForm();
}
public setContactAccompanimentEmail(email: string): void {
this.getOrientationControl('contactAccompanimentEmail').setValue(email);
this.setValidationsForm();
}
......@@ -358,7 +394,7 @@ export class OrientationFormComponent implements OnInit {
this.filters.push(new Filter('equipmentsAndServices', element, this.findEquipmentName(element)));
});
this.orientationForm.get('formation').value.forEach((element) => {
this.orientationForm.get('formation');
this.findTrainingCategoryForSkill(element);
// Put higher cat like accessRight and so on here
this.filters.push(
new Filter(
......@@ -368,15 +404,6 @@ export class OrientationFormComponent implements OnInit {
)
);
});
// todo - fix
this.removeDoublonFilters();
}
public removeDoublonFilters(): void {
this.uncheckedFilters.forEach((elem) => {
this.filters = this.filters.filter((filter) => filter.value != elem.value);
});
this.setStructuresAndCoord();
}
......@@ -403,34 +430,10 @@ export class OrientationFormComponent implements OnInit {
public findTrainingCategoryForSkill(skill): any {
let infos = { categ: '', name: '' };
this.baseSkillssReferentiel.modules.forEach((elem) => {
this.selectedFormations.forEach((elem) => {
if (elem.id === skill) {
infos.categ = this.baseSkillssReferentiel.id;
infos.name = elem.text;
}
});
this.accessRightsReferentiel.modules.forEach((elem) => {
if (elem.id === skill) {
infos.categ = this.accessRightsReferentiel.id;
infos.name = elem.text;
}
});
this.parentingHelpsReferentiel.modules.forEach((elem) => {
if (elem.id === skill) {
infos.categ = this.parentingHelpsReferentiel.id;
infos.name = elem.text;
}
});
this.socialAndProfessionalsReferentiel.modules.forEach((elem) => {
if (elem.id === skill) {
infos.categ = this.socialAndProfessionalsReferentiel.id;
infos.name = elem.text;
}
});
this.digitalCultureSecuritysReferentiel.modules.forEach((elem) => {
if (elem.id === skill) {
infos.categ = this.digitalCultureSecuritysReferentiel.id;
infos.name = elem.text;
infos.categ = '';
infos.name = elem.name;
}
});
return infos;
......@@ -440,7 +443,7 @@ export class OrientationFormComponent implements OnInit {
this.geoJsonService
.getCoord(this.orientationForm.value.address.numero, this.orientationForm.value.address.street, '69000')
.subscribe((res) => {
this.structureService.getStructures(this.filters).subscribe((data) => {
this.structureService.getStructures(this.filters.filter((elem) => elem.checked == true)).subscribe((data) => {
data.map((structure) => {
structure.distance = parseInt(
this.geoJsonService.getDistance(
......@@ -494,15 +497,10 @@ export class OrientationFormComponent implements OnInit {
this.showStructureDetails = false;
}
public removeFilter(filter: Filter): void {
this.filters = this.filters.filter((elem) => elem != filter);
this.uncheckedFilters.push(filter);
this.setStructuresAndCoord();
}
public restoreFilter(filter: Filter): void {
this.uncheckedFilters = this.uncheckedFilters.filter((elem) => elem != filter);
this.filters.push(filter);
public checkFilter(filter: Filter): void {
this.filters.forEach((element) => {
if (element == filter) element.checked = !element.checked;
});
this.setStructuresAndCoord();
}
......@@ -535,6 +533,7 @@ export class OrientationFormComponent implements OnInit {
this.multiPrint = event;
setTimeout(() => {
window.print();
this.progressStatus = 100;
}, 1000);
}
......@@ -542,4 +541,12 @@ export class OrientationFormComponent implements OnInit {
onWindowAfterPrint() {
this.multiPrint = false;
}
public displayFinishModal(): void {
this.displayModal = true;
}
public closeFinishModal(): void {
this.displayModal = false;
}
}
export enum PageTypeEnum {
beneficiaryNeed,
beneficiaryPassNumeric,
beneficiaryInfo,
structuresSelection,
beneficiaryAccompaniment,
beneficiaryNeedCommentary,
beneficiaryAddress,
structuresSelection,
printResults,
}
......@@ -19,7 +19,7 @@ h4 {
}
.form {
background: white;
background: $white;
width: 100vw;
height: calc(var(--vh, 1vh) * 100 - #{$header-height} - #{$footer-height});
top: #{$header-height};
......@@ -46,7 +46,7 @@ h4 {
display: none;
@media #{$tablet} {
margin: 0 auto;
border-top: 1px solid $grey-4;
//border-top: 1px solid $grey-4;
display: block;
}
}
......@@ -96,7 +96,6 @@ h4 {
) !important; // -1px because of header border
}
@media #{$tablet} {
height: 100%;
&.editMode {
.page {
height: calc(
......@@ -131,11 +130,6 @@ h4 {
.page {
max-width: 960px;
margin: auto;
@media #{$tablet} {
height: calc(
100vh - #{$header-height-phone} - #{$progressBar-height} - #{$footer-height-phone} - 1px
); // -1px because of header border
}
height: auto;
color: $grey-1;
&.home {
......@@ -307,7 +301,7 @@ h4 {
input {
&.email-placeholder::placeholder {
color: #cacccb;
color: $white-2;
font-style: italic;
}
&.phone {
......@@ -335,6 +329,9 @@ img {
border: 1px solid $grey-4;
border-radius: 4px;
margin-bottom: 13px;
@media #{$small-phone} {
width: 95% !important;
}
@media #{$tablet} {
width: 296px;
}
......
......@@ -744,6 +744,7 @@ export class FormComponent implements OnInit {
} else {
this.currentPage++;
this.progressStatus += 100 / this.nbPagesForm;
document.getElementsByClassName('content')[0].scrollTo(0, 0);
this.updatePageValid();
}
}
......
......@@ -37,9 +37,13 @@
</div>
<div fxLayout="column" class="right-header" fxLayoutAlign="none baseline" fxLayoutGap="5vw">
<a routerLink="/news" [routerLinkActive]="'active'" (click)="closeMenu()" i18n>Actualités</a>
<a routerLink="/acteurs" [routerLinkActive]="'active'" (click)="closeMenu()" i18n>Cartographie de acteurs</a>
<a routerLink="/orientation" [routerLinkActive]="'active'" i18n>Orienter un bénéficiaire</a>
<a routerLink="/page/qui-sommes-nous" [routerLinkActive]="'active'" i18n>Qui sommes-nous ?</a>
<a routerLink="/acteurs" [routerLinkActive]="'active'" (click)="closeMenu()" i18n>Cartographie des acteurs</a>
<a routerLink="/orientation" [routerLinkActive]="'active'" (click)="closeMenu()" i18n
>Orienter un bénéficiaire</a
>
<a routerLink="/page/qui-sommes-nous" [routerLinkActive]="'active'" (click)="closeMenu()" i18n
>Qui sommes-nous ?</a
>
<a *ngIf="isAdmin" routerLink="/admin" [routerLinkActive]="'active'" (click)="closeMenu()">Administration</a>
</div>
</div>
......
import { Component, OnInit } from '@angular/core';
import { Meta } from '@angular/platform-browser';
@Component({
selector: 'app-legal-notice',
templateUrl: './legal-notice.component.html',
styleUrls: ['./legal-notice.component.scss']
styleUrls: ['./legal-notice.component.scss'],
})
export class LegalNoticeComponent implements OnInit {
constructor() { }
constructor(private meta: Meta) {}
ngOnInit(): void {
this.meta.updateTag({
name: 'description',
content: "Mentions légales de Rés'IN, le Réseau des acteurs de l'inclusion numérique de la métropole de Lyon",
});
}
}
export enum Layers {
mdm = 'mdm',
user = 'user',
structure = 'structure',
}
<div class="map-wrapper">
<div id="map" class="body-wrap" leaflet [leafletOptions]="mapOptions" (leafletMapReady)="onMapReady($event)"></div>
<div
id="map"
class="body-wrap"
[ngClass]="{ orientation: isOrientationForm }"
leaflet
[leafletOptions]="mapOptions"
(leafletMapReady)="onMapReady($event)"
></div>
</div>
......@@ -5,6 +5,7 @@
@import '../../../assets/scss/shapes';
@import '../../../assets/scss/buttons';
@import '../../../assets/scss/breakpoint';
@import '../../../assets/scss/z-index';
.map-wrapper {
border-radius: 6px;
......@@ -22,6 +23,9 @@
@media #{$large-phone} {
height: calc(100vh - #{$header-height} - 28px);
}
&.orientation {
height: calc(96vh - #{$header-height} - #{$footer-height} - 68px - #{$footer-height-phone});
}
}
::ng-deep .leaflet-popup-close-button {
......@@ -86,6 +90,7 @@
}
}
&:hover {
z-index: calc($map-selected-marker - 1) !important;
svg {
fill: $blue-hover;
&.mdm {
......@@ -130,15 +135,33 @@
.pop-up {
text-align: center;
padding-top: 20px;
&.orientation {
padding: 0;
text-align: -webkit-center;
}
button {
@include btn-search-filter;
@include cn-bold-14;
font-size: 16px;
}
.orientationButton {
display: flex;
padding: 10px 20px;
border-radius: 20px;
margin: 0 4px;
color: $black;
background-color: $white;
border: solid 1px $grey-3;
min-width: 120px;
}
}
span {
display: inline-block;
margin-right: 4px;
&.eye {
margin-right: 11px;
}
}
}
::ng-deep .leaflet-popup-content-wrapper {
......@@ -160,3 +183,7 @@
.body-wrap {
height: 400px;
}
::ng-deep .on-top-marker {
z-index: $map-selected-marker !important;
}
import { Component, EventEmitter, HostListener, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { Component, EventEmitter, HostListener, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { latLng, MapOptions, geoJSON, tileLayer, Map, latLngBounds, layerGroup } from 'leaflet';
import { Structure } from '../../models/structure.model';
import { GeojsonService } from '../../services/geojson.service';
......@@ -9,6 +9,7 @@ import { MarkerType } from './markerType.enum';
import metropole from '../../../assets/geojson/metropole.json';
import L from 'leaflet';
import 'leaflet.locatecontrol';
import { ZoomLevel } from './zoomLevel.enum';
@Component({
selector: 'app-map',
......@@ -16,14 +17,16 @@ import 'leaflet.locatecontrol';
styleUrls: ['./map.component.scss'],
})
export class MapComponent implements OnChanges {
@Input() public isOrientationForm = false;
@Input() public structures: Structure[] = [];
@Input() public structuresToPrint: Structure[] = [];
@Input() public toogleToolTipId: string;
@Input() public selectedMarkerId: string;
@Input() public isMapPhone: boolean;
@Input() public locate = false;
@Input() public searchedValue: string;
@Output() selectedStructure: EventEmitter<Structure> = new EventEmitter<Structure>();
@Input() public searchedValue: string | [number, number];
@Output() public selectedStructure: EventEmitter<Structure> = new EventEmitter<Structure>();
@Output() public onOrientationButtonClick: EventEmitter<Structure> = new EventEmitter<Structure>();
@Output() locatationTrigger: EventEmitter<boolean> = new EventEmitter<boolean>();
private lc; // Locate control
private currentStructure: Structure;
......@@ -45,6 +48,10 @@ export class MapComponent implements OnChanges {
if (event.target.classList.contains('btnShowDetails')) {
this.selectedStructure.emit(this.currentStructure);
}
if (event.target.classList.contains('add')) {
this.onOrientationButtonClick.emit(this.currentStructure);
this.getStructuresPositions(this.structures);
}
}
constructor(private mapService: MapService, private geoJsonService: GeojsonService) {
......@@ -119,7 +126,7 @@ export class MapComponent implements OnChanges {
if (changes.structuresToPrint) {
if (changes.structuresToPrint.currentValue < changes.structuresToPrint.previousValue) {
this.mapService.setUnactiveMarker(
this.mapService?.setUnactiveMarker(
this.toogleToolTipId,
this.getMarkerTypeByStructureId(changes.structuresToPrint.previousValue)
);
......@@ -144,6 +151,15 @@ export class MapComponent implements OnChanges {
);
}
/**
* Create a user position marcker and center the map on it with a zoom level defined in ZoomLevel
* @param coords {[number, number]} Map center position
*/
public centerOnCoordinates(coords: [number, number]): void {
this.mapService.createMarker(coords[1], coords[0], MarkerType.user, 'userLocation').addTo(this.map);
this.map.setView(new L.LatLng(coords[1], coords[0]), ZoomLevel.userPosition);
}
/**
* Get structures positions and add marker corresponding to those positons on the map
*/
......@@ -174,7 +190,7 @@ export class MapComponent implements OnChanges {
* @returns {MarkerType}
*/
private getMarkerType(structure: Structure): MarkerType {
return structure.labelsQualifications.includes('conseillerNumFranceServices')
return structure?.labelsQualifications?.includes('conseillerNumFranceServices')
? MarkerType.conseillerFrance
: MarkerType.structure;
}
......@@ -230,12 +246,18 @@ export class MapComponent implements OnChanges {
'</h1>' +
'<p>' +
structure.getLabelTypeStructure() +
'</p><div>' +
'<span class="ico-dot-' +
cssAvailabilityClass +
'"></span><span>' +
structure.openDisplay() +
'</span></div><div class="pop-up"><button type="button" class="btnShowDetails">Voir</button></div>'
'</p>' +
(this.isOrientationForm
? ''
: '<div>' +
'<span class="ico-dot-' +
cssAvailabilityClass +
'"></span><span>' +
structure.openDisplay() +
'</span></div>') +
(this.isOrientationForm
? '<div class="pop-up orientation"><button type="button" class="orientationButton btnShowDetails"><span class="ico-gg-eye-alt eye"></span>Voir</button></div>'
: '<div class="pop-up"><button type="button" class="btnShowDetails">Voir</button></div>')
);
}
......@@ -250,10 +272,18 @@ export class MapComponent implements OnChanges {
public onMapReady(map: Map): void {
this.map = map;
// Handle location
this.lc = L.control.locate(this.locateOptions).addTo(this.map);
this.map.on('locationfound', () => {
this.locatationTrigger.emit(true);
});
if (!this.isOrientationForm) {
this.lc = L.control.locate(this.locateOptions).addTo(this.map);
this.map.on('locationfound', () => {
this.locatationTrigger.emit(true);
});
}
if (this.searchedValue) {
if (Array.isArray(this.searchedValue)) {
this.centerOnCoordinates(this.searchedValue);
}
}
}
/**
......@@ -268,15 +298,15 @@ export class MapComponent implements OnChanges {
layerGroup();
const carteLayer = tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', {
attribution: '&copy; <a href="https://carto.com/attributions">CARTO</a>',
maxZoom: 19,
maxZoom: ZoomLevel.max,
});
// Center is set on townhall
// Zoom is blocked on 11 to prevent people to zoom out from metropole
this.mapOptions = {
center: latLng(45.764043, 4.835659),
maxZoom: 19,
zoom: 12,
minZoom: 10,
maxZoom: ZoomLevel.max,
zoom: ZoomLevel.regular,
minZoom: ZoomLevel.min,
layers: [carteLayer],
};
}
......
......@@ -2,4 +2,5 @@ export enum MarkerType {
structure = 0,
mdm = 1,
conseillerFrance = 2,
user = 3,
}