diff --git a/public/img/foret_placeholder.png b/public/img/foret_placeholder.png new file mode 100755 index 0000000..8a8597c Binary files /dev/null and b/public/img/foret_placeholder.png differ diff --git a/src/app/core/interceptors/app-token.interceptor.ts b/src/app/core/interceptors/app-token.interceptor.ts index 438c83c..c772b6a 100644 --- a/src/app/core/interceptors/app-token.interceptor.ts +++ b/src/app/core/interceptors/app-token.interceptor.ts @@ -24,8 +24,6 @@ export class AppTokenInterceptor implements HttpInterceptor { return next.handle(request); } - console.log('[AppTokenInterceptor]', 'intercept', request.url); - if (this.hasToken()) { request = this.addToken(request); } diff --git a/src/app/pages/mes-forets/mes-forets.component.html b/src/app/pages/mes-forets/mes-forets.component.html index fdf9148..35cb83f 100644 --- a/src/app/pages/mes-forets/mes-forets.component.html +++ b/src/app/pages/mes-forets/mes-forets.component.html @@ -25,8 +25,8 @@

Mes Forets

[description]="foret.description" [enlargeLink]="foret.enlargeLink" [hasFooter]="foret.hasFooter" [horizontal]="foret.horizontal"> - - + + diff --git a/src/app/pages/mes-forets/mes-forets.component.ts b/src/app/pages/mes-forets/mes-forets.component.ts index 9988c8b..2bb29cf 100644 --- a/src/app/pages/mes-forets/mes-forets.component.ts +++ b/src/app/pages/mes-forets/mes-forets.component.ts @@ -29,24 +29,30 @@ export class MesForetsComponent implements OnInit { private router: Router ) { } + ngOnInit(): void { this.buildBreadcrumb(); - this.foretService.list().pipe( - catchError((error) => { - console.error('error', error); - this.subcribed = false; - return this.foretService.mockList(); - }) - ).subscribe((forets) => { - console.log('subscribe((forets)', forets); + + this.foretService.mockList().subscribe((forets) => { this.foretCards = forets.map((foret) => this.cardTransformerService.fromForet(foret)); }); + + // this.foretService.list().pipe( + // catchError((error) => { + // this.subcribed = false; + // return this.foretService.mockList(); + // }) + // ).subscribe((forets) => { + // this.foretCards = forets.map((foret) => this.cardTransformerService.fromForet(foret)); + // }); } - goToRequete(foretTitle: string) { - this.router.navigate(['/', 'requete', foretTitle]); + + goToRequete(foretId: string) { + this.router.navigate(['/', 'requete', foretId]); } + private buildBreadcrumb() { this.breadcrumb = this.breadcrumbTransformerService.fromOptions({ label: 'Mes forêts', route: '' diff --git a/src/app/requete/components/requete-stepper-control/requete-stepper-control.component.html b/src/app/requete/components/requete-stepper-control/requete-stepper-control.component.html index 4b5ce23..bd431da 100644 --- a/src/app/requete/components/requete-stepper-control/requete-stepper-control.component.html +++ b/src/app/requete/components/requete-stepper-control/requete-stepper-control.component.html @@ -6,7 +6,7 @@ - + diff --git a/src/app/requete/components/requete-stepper-control/requete-stepper-control.component.ts b/src/app/requete/components/requete-stepper-control/requete-stepper-control.component.ts index 47d9699..ede4eb0 100644 --- a/src/app/requete/components/requete-stepper-control/requete-stepper-control.component.ts +++ b/src/app/requete/components/requete-stepper-control/requete-stepper-control.component.ts @@ -14,6 +14,8 @@ export class RequeteStepperControlComponent implements OnChanges { @Output() previous: EventEmitter = new EventEmitter(); + @Output() save: EventEmitter = new EventEmitter(); + previousButtonLabel = 'Précédent'; nextButtonLabel = 'Suivant'; @@ -39,8 +41,8 @@ export class RequeteStepperControlComponent implements OnChanges { } - save() { - alert('[TODO][FONCTION NEXISTE PAS] Sauvegarde effectuée'); + emitSave() { + this.save.emit(true); } diff --git a/src/app/requete/pages/requete-new/requete-new.component.html b/src/app/requete/pages/requete-new/requete-new.component.html index 7512999..d9d2bf1 100644 --- a/src/app/requete/pages/requete-new/requete-new.component.html +++ b/src/app/requete/pages/requete-new/requete-new.component.html @@ -1,16 +1,20 @@ -
+
-

Votre forêt - {{ forestId }}

+

+ Votre forêt + @if (foret) { + - {{ foret.name }} + } +

- + (next)="nextStep()" (save)="saveForet()">
diff --git a/src/app/requete/pages/requete-new/requete-new.component.ts b/src/app/requete/pages/requete-new/requete-new.component.ts index e99375e..af8b3bc 100644 --- a/src/app/requete/pages/requete-new/requete-new.component.ts +++ b/src/app/requete/pages/requete-new/requete-new.component.ts @@ -1,19 +1,20 @@ -import { Component, OnInit } from '@angular/core'; +import { AfterViewInit, Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { map } from 'rxjs'; import { MapContextService } from '../../../shared-map/services/map-context.service'; import { BreadcrumbTransformerService } from '../../../shared-design-dsfr/transformers/breadcrumb-transformer.service'; import { THEMATIC_LIST } from '../../../shared-thematic/models/thematic-list.enum'; +import { Foret } from '../../../shared/models/foret.model'; @Component({ selector: 'app-requete-new', templateUrl: './requete-new.component.html', styleUrl: './requete-new.component.css' }) -export class RequeteNewComponent implements OnInit { +export class RequeteNewComponent implements OnInit, AfterViewInit { - forestId: string = ''; + foret?: Foret; step: number = 0; @@ -26,19 +27,23 @@ export class RequeteNewComponent implements OnInit { ) { } ngOnInit(): void { - this.route.params.pipe( - map((params) => { - if (params['id']) { - this.forestId = params['id']; - this.step = 2; + + this.route.data.pipe( + map((response: any) => { + if (response && response.data) { + this.foret = response.data; } - this.buildBreadcrumb(); + this.loadPageComponent(); }) ).subscribe(); } - ngOnDestroy(): void { - this.mapContextService.destroyMap(); + ngAfterViewInit(): void { + this.loadWithForet(); + } + + saveForet() { + const geoJson = this.mapContextService.maForetToGeoJson(); } confirmSelect() { @@ -83,13 +88,26 @@ export class RequeteNewComponent implements OnInit { } } + updateThematics() { this.mapContextService.updateLayers(); } + + private loadWithForet() { + if (!this.foret) { + return; + } + if (this.foret.geometry) { + this.mapContextService.maForetFromGeoJson(this.foret.geometry); + } + this.step = 1; + this.nextStep(); + } + - private buildBreadcrumb() { - const label = this.forestId ? `Requête ${this.forestId}` : 'Nouvelle requête'; + private loadPageComponent() { + const label = this.foret ? `Requête ${this.foret}` : 'Nouvelle requête'; this.breadcrumb = this.breadcrumbTransformerService.fromOptions({ label: label, route: '' }); diff --git a/src/app/requete/requete.routes.ts b/src/app/requete/requete.routes.ts index e76aaf9..d293b17 100644 --- a/src/app/requete/requete.routes.ts +++ b/src/app/requete/requete.routes.ts @@ -1,7 +1,15 @@ -import { Routes } from '@angular/router'; +import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot, Routes } from '@angular/router'; +import { inject } from '@angular/core'; import { RequeteNewComponent } from './pages/requete-new/requete-new.component'; import { RequetePrinterComponent } from './pages/requete-printer/requete-printer.component'; +import { ForetService } from '../shared/services/foret.service'; +import { Foret } from '../shared/models/foret.model'; + + +export const resolver: ResolveFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { + return inject(ForetService).getMockForet(route.paramMap.get('id')!); +}; export const requeteRoutes: Routes = [ { @@ -12,7 +20,8 @@ export const requeteRoutes: Routes = [ { path: ':id', component: RequeteNewComponent, - title: 'Requête sur ma forêt' + title: 'Requête sur ma forêt', + resolve: { data: resolver } }, { path: 'nouvelle/impression', diff --git a/src/app/shared-design-dsfr/transformers/card-transformer.service.ts b/src/app/shared-design-dsfr/transformers/card-transformer.service.ts index 63b3c7c..c35f76d 100644 --- a/src/app/shared-design-dsfr/transformers/card-transformer.service.ts +++ b/src/app/shared-design-dsfr/transformers/card-transformer.service.ts @@ -32,7 +32,7 @@ export class CardTransformerService { imagePath: foret.imgUrl, enlargeLink: false, hasFooter: true, - horizontal: true + horizontal: true, }; return foretCard; diff --git a/src/app/shared-map/services/map-context.service.ts b/src/app/shared-map/services/map-context.service.ts index 279a33f..476ab14 100644 --- a/src/app/shared-map/services/map-context.service.ts +++ b/src/app/shared-map/services/map-context.service.ts @@ -12,6 +12,7 @@ import { extend } from 'ol/extent'; import GeoportailLayer from 'ol-ext/layer/Geoportail'; import EditBar from 'ol-ext/control/EditBar.js'; import LayerSwitcher from 'ol-ext/control/LayerSwitcher'; +import GeoJSON from 'ol/format/GeoJSON.js'; import { MAP_DEFAULT_LAYER_GROUP } from '../models/map-layers-default.enum'; import { MAP_BIODIVERISTE_LAYER_GROUP, MAP_PATRIMOINE_LAYER_GROUP } from '../../shared-thematic/models/map-thematic-layers.enum'; @@ -259,6 +260,25 @@ export class MapContextService { } return this.getLayerDessin().getSource().getFeatures(); } + + + maForetFromGeoJson(geoJson: any) { + if (!this.getLayerDessin()) { + return; + } + this.getLayerDessin().getSource().clear(); + this.getLayerDessin().getSource().addFeatures(new GeoJSON().readFeatures(geoJson)); + } + + maForetToGeoJson() { + if (!this.getLayerDessin()) { + return null; + } + const features = this.getLayerDessin().getSource().getFeatures(); + const geoJson = new GeoJSON().writeFeatures(features); + return JSON.parse(geoJson); + } + resetDessin() { this.getLayerDessin().getSource().forEachFeature((f: any) => { @@ -266,6 +286,8 @@ export class MapContextService { }); } + + centerOnDessin(map?: Map) { if (!map) { map = this.map; diff --git a/src/app/shared/models/foret.model.ts b/src/app/shared/models/foret.model.ts index 9ef477d..39b2d46 100644 --- a/src/app/shared/models/foret.model.ts +++ b/src/app/shared/models/foret.model.ts @@ -3,29 +3,43 @@ import { Serializable } from '../../core/models/serializable.model'; export class Foret implements Serializable { id: string = ''; + name: string = ''; + + adresse: any = {}; + description: string = ''; + tags: Array = []; + parcels: Array = []; + imgUrl: string = ''; + area: number = 0; + createdAt: Date = new Date(); + updatedAt: Date = new Date(); + geometry: any = {}; + constructor() { } deserialise(input: any) { Object.assign(this, { id: input.id, name: input.name, + adresse: input.adresse, description: input.description, tags: input.tags, parcels: input.parcels, imgUrl: input.imgUrl, area: input.area, createdAt: input.createdAt, - updatedAt: input.updatedAt - }); + updatedAt: input.updatedAt, + geometry: input.geometry +}); return this; } @@ -33,13 +47,15 @@ export class Foret implements Serializable { return { id: this.id, name: this.name, + adresse: this.adresse, description: this.description, tags: this.tags, parcels: this.parcels, imgUrl: this.imgUrl, area: this.area, createdAt: this.createdAt, - updatedAt: this.updatedAt + updatedAt: this.updatedAt, + geometry: this.geometry }; } diff --git a/src/app/shared/models/mock-db-foret.enum.ts b/src/app/shared/models/mock-db-foret.enum.ts index a481ee3..704ef22 100644 --- a/src/app/shared/models/mock-db-foret.enum.ts +++ b/src/app/shared/models/mock-db-foret.enum.ts @@ -1,24 +1,54 @@ export const MOCK_DB_FORETS = [ { - id: 1, - name: 'Ma foret', + id: '646e3793415f259be58fb730', + name: 'Zaminarteko borda', + adresse: { + commune: 'Ayherre', + codePostal: 64240, + lieudit: 'Zahara', + }, description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras nec gravida justo. Morbi ullamcorper ullamcorper eros, ac ultricies turpis gravida quis.', - tags: ['tag 1', 'tag 1bis'], - imgUrl: 'https://cdn.sortiraparis.com/images/80/98390/934396-je-s-appelle-groot-une-bande-annonce-pour-la-saison-2-disponible-en-septembre-sur-disney.jpg', + tags: ['Biodiversité', 'Patrimoine'], + imgUrl: '/img/foret_placeholder.png', area: 23, createdAt: new Date(), updatedAt: new Date(), - parcels: ['parcelle 1', 'parcelle 1bis'] + parcels: ['parcelle 1', 'parcelle 1bis'], + geometry: { + 'type': 'FeatureCollection', + 'features': [{ + 'type': 'Feature', + 'geometry': { + 'type': 'Polygon', + 'coordinates': [[[266519.3795145552, 6246211.478651401], [268220.1033939004, 6243517.073404348], [270379.4494429566, 6246039.495337759], [267379.2960827634, 6247625.563674676], [266519.3795145552, 6246211.478651401]]] + }, 'properties': null + }] + } }, { - id: 2, - name: 'Ma 2e foret', + id: '646dd8cc415f259be58fb17b', + name: 'Tombe-boucs', + adresse: { + commune: 'Laparade', + codePostal: 64240, + lieudit: 'D249, le plet', + }, description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras nec gravida justo. Morbi ullamcorper ullamcorper eros, ac ultricies turpis gravida quis.', - tags: ['tag 2', 'tag 2bis'], - imgUrl: 'https://cdn.sortiraparis.com/images/80/98390/934396-je-s-appelle-groot-une-bande-annonce-pour-la-saison-2-disponible-en-septembre-sur-disney.jpg', - area: 23, + tags: ['Patrimoine'], + imgUrl: '/img/foret_placeholder.png', + area: 2.8, createdAt: new Date(), updatedAt: new Date(), - parcels: ['parcelle 2', 'parcelle 2bis'] + parcels: ['parcelle 2', 'parcelle 2bis'], + geometry: { + 'type': 'FeatureCollection', + 'features': [{ + 'type': 'Feature', + 'geometry': { + 'type': 'Polygon', + 'coordinates': [[[266519.3795145552, 6246211.478651401], [268220.1033939004, 6243517.073404348], [270379.4494429566, 6246039.495337759], [267379.2960827634, 6247625.563674676], [266519.3795145552, 6246211.478651401]]] + }, 'properties': null + }] + } } ]; diff --git a/src/app/shared/services/foret.service.ts b/src/app/shared/services/foret.service.ts index 130ac75..7b5a43f 100644 --- a/src/app/shared/services/foret.service.ts +++ b/src/app/shared/services/foret.service.ts @@ -34,6 +34,11 @@ export class ForetService { ); } + getMockForet(id: string): Observable { + const forests = MOCK_DB_FORETS.map((foretProperties) => new Foret().deserialise(foretProperties)); + return of(forests.find((foret) => foret.id === id)); + } + mockList(): Observable { return of([...MOCK_DB_FORETS.map((foretProperties) => new Foret().deserialise(foretProperties))]); } diff --git a/src/app/shared/services/login.service.ts b/src/app/shared/services/login.service.ts index 2740cc2..9375c0f 100644 --- a/src/app/shared/services/login.service.ts +++ b/src/app/shared/services/login.service.ts @@ -36,7 +36,7 @@ export class LoginService { }), catchError((error) => { if (error.status === 401) { - console.warn('[TokenService]', 'refreshAccessToken', 'Votre authentification[refreshToken] est invalide ou expirée.'); + console.error('[TokenService]', 'refreshAccessToken', 'Votre authentification[refreshToken] est invalide ou expirée.'); this.logout(); } else { console.error('[TokenService]', 'refreshAccessToken', 'Une erreur serveur est survenue.');