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
Commits on Source (22)
Showing
with 858 additions and 166 deletions
...@@ -76,6 +76,7 @@ deploy_dev: ...@@ -76,6 +76,7 @@ deploy_dev:
- deploy - deploy
only: only:
- dev - dev
- branches
script: script:
- cd /home/mps/ram - cd /home/mps/ram
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
......
...@@ -2,6 +2,36 @@ ...@@ -2,6 +2,36 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [2.0.0-beta1](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/compare/v1.16.0...v2.0.0-beta1) (2022-03-29)
### ⚠ BREAKING CHANGES
* **onboarding:** Some fileds are now added to user structure, there is no coming back
### Features
* **carto:** rework carto, search bar and structure detail screen ([aa058b5](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/aa058b5d18fb3d90aa77d0aab700424babeff93e))
* **cicd:** temp remove of mr jobs ([5c9a74a](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/5c9a74ad2916b986a7626ffb8726db3260d8990a))
* **cicd:** update deploy for V2.0 ([4440154](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/4440154a4bac74f32da1f79178acab19ba89b83a))
* **cicd:** update wrong prop ([d311dd9](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/d311dd9f5539f9187672d6e5dbc350d121d00729))
* **onboarding:** form refactor for structure and account creation. Add new onboarding cases for profile and personal offer. ([bb89936](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/bb89936f2869564cfa6bc0e1de239aac53315c0a))
* **style:** add tertiary and icon onlybutton. Update logo and header. Button refacto with enum ([276dc59](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/276dc594376cf4054490ccea327323e391bd1571))
* **style:** change colors, buttons, header, typo ([38629d8](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/38629d8ca71eaaa831109b101f71971bb94f53c4))
### Bug Fixes
* add missing layout import ([621d77d](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/621d77d1610e02a47bc4e6b29d8c973e68d6cebe))
* **carto:** review icons and font ([60d23c3](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/60d23c3c00c0f957aad6eaea627f3196fa9d9361))
* **cicd:** change to branches ([79bf80f](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/79bf80f4bb377e3910b9f04e952c814ecbba3ca4))
* **cicd:** wrong job targeted ([0237564](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/0237564284901f584a122d69f5815836a4acca41))
* **filters:** review more filter background ([da44d38](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/da44d38716db680299a27c46a60a4cff79098b9b))
* **gitalb-ci:** autodeploy for V2.0 ([cd1d43d](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/cd1d43d0da89798a175d77179b0a72d346ee520c))
* secondary button width ([375adfe](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/375adfe94efa04e5e1d193e669a75f3d805d9f34))
* **style:** button hover ([122fcfc](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/122fcfc1412282af29734f33985f375b83606b30))
* **style:** update button style ([c8ade31](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/c8ade31b7d4f187a2c9cb0db321dd5355e7ebb88))
## [1.16.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/compare/v1.15.0...v1.16.0) (2022-03-18) ## [1.16.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/compare/v1.15.0...v1.16.0) (2022-03-18)
......
{ {
"name": "pamn", "name": "pamn",
"version": "1.16.0", "version": "2.0.0-beta1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
......
{ {
"name": "pamn", "name": "pamn",
"version": "1.16.0", "version": "2.0.0-beta1",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve --configuration=fr --proxy-config proxy.conf.json", "start": "ng serve --configuration=fr --proxy-config proxy.conf.json",
......
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; import { Routes, RouterModule, Route } from '@angular/router';
import { PageComponent } from './page/page.component'; import { PageComponent } from './page/page.component';
import { ContactComponent } from './contact/contact.component'; import { ContactComponent } from './contact/contact.component';
import { FormComponent } from './form/structure-form/form.component'; import { FormComponent } from './form/structure-form/form.component';
...@@ -14,20 +14,42 @@ import { TempUserResolver } from './resolvers/temp-user.resolver'; ...@@ -14,20 +14,42 @@ import { TempUserResolver } from './resolvers/temp-user.resolver';
import { StructureJoinComponent } from './structure-join/structure-join.component'; import { StructureJoinComponent } from './structure-join/structure-join.component';
import { StructureDetailsComponent } from './structure-list/components/structure-details/structure-details.component'; import { StructureDetailsComponent } from './structure-list/components/structure-details/structure-details.component';
import { StructureListComponent } from './structure-list/structure-list.component'; import { StructureListComponent } from './structure-list/structure-list.component';
import { UserVerificationComponent } from './user-verification/user-verification.component';
import { NewsletterSubscriptionComponent } from './newsletter-subscription/newsletter-subscription.component'; import { NewsletterSubscriptionComponent } from './newsletter-subscription/newsletter-subscription.component';
import { OrientationFormComponent } from './form/orientation-form/orientation-form.component'; import { OrientationFormComponent } from './form/orientation-form/orientation-form.component';
import { StructureListPrintComponent } from './form/orientation-form/component/structure-list-print/structure-list-print.component'; import { StructureListPrintComponent } from './form/orientation-form/component/structure-list-print/structure-list-print.component';
import { StructureResolver } from './resolvers/structure.resolver'; import { StructureResolver } from './resolvers/structure.resolver';
import { RoleGuard } from './guards/role.guard'; import { RoleGuard } from './guards/role.guard';
import { RouteRole } from './shared/enum/routeRole.enum'; import { RouteRole } from './shared/enum/routeRole.enum';
import { LoginComponent } from './login/login.component';
import { PasswordFormComponent } from './shared/components';
import { FooterComponent } from './footer/footer.component';
const footerOutletRoute: Route = {
path: '',
outlet: 'footer',
component: FooterComponent,
};
const routes: Routes = [ const routes: Routes = [
{ path: 'print', outlet: 'print', children: [{ path: 'structure', component: StructureDetailsComponent }] }, {
{ path: 'print', outlet: 'print', children: [{ path: 'structures', component: StructureListPrintComponent }] }, path: 'print',
outlet: 'print',
children: [{ path: 'structure', component: StructureDetailsComponent }, footerOutletRoute],
},
{
path: 'print',
outlet: 'print',
children: [{ path: 'structures', component: StructureListPrintComponent }, footerOutletRoute],
},
{ {
path: 'orientation', path: 'orientation',
component: OrientationFormComponent, children: [
{
path: '',
component: OrientationFormComponent,
},
footerOutletRoute,
],
}, },
{ {
path: 'acteurs', path: 'acteurs',
...@@ -35,86 +57,196 @@ const routes: Routes = [ ...@@ -35,86 +57,196 @@ const routes: Routes = [
}, },
{ {
path: 'login', path: 'login',
component: CartoComponent, children: [
{
path: '',
component: LoginComponent,
},
footerOutletRoute,
],
}, },
{ {
path: 'structures', path: 'structures',
component: StructureListComponent, children: [
{
path: '',
component: StructureListComponent,
},
footerOutletRoute,
],
}, },
{ {
path: 'legal-notice', path: 'legal-notice',
component: LegalNoticeComponent, children: [
{
path: '',
component: LegalNoticeComponent,
},
footerOutletRoute,
],
}, },
{ {
path: 'page/:slugPage', path: 'page/:slugPage',
component: PageComponent, children: [
{
path: '',
component: PageComponent,
},
footerOutletRoute,
],
}, },
{ {
path: 'contact', path: 'contact',
component: ContactComponent, children: [
{
path: '',
component: ContactComponent,
},
footerOutletRoute,
],
}, },
{ {
path: 'users/verify/:id', path: 'users/verify/:id',
component: UserVerificationComponent, children: [
{
path: '',
component: LoginComponent,
},
footerOutletRoute,
],
}, },
{ {
path: 'register', path: 'register',
component: FormComponent, children: [
canDeactivate: [DeactivateGuard], {
resolve: { path: '',
user: TempUserResolver, component: FormComponent,
}, canDeactivate: [DeactivateGuard],
resolve: {
user: TempUserResolver,
},
},
footerOutletRoute,
],
}, },
{ {
path: 'change-email/:id', path: 'change-email/:id',
component: ResetEmailComponent, children: [
{
path: '',
component: ResetEmailComponent,
},
footerOutletRoute,
],
}, },
{ {
path: 'profile', path: 'profile',
canActivate: [AuthGuard], children: [
loadChildren: () => import('./profile/profile.module').then((m) => m.ProfileModule), {
path: '',
canActivate: [AuthGuard],
loadChildren: () => import('./profile/profile.module').then((m) => m.ProfileModule),
},
footerOutletRoute,
],
}, },
{ {
path: 'join', path: 'join',
canActivate: [AuthGuard], children: [
component: StructureJoinComponent, {
path: '',
canActivate: [AuthGuard],
component: StructureJoinComponent,
},
footerOutletRoute,
],
}, },
{ {
path: 'reset-password', path: 'reset-password',
component: ResetPasswordComponent, children: [
{
path: '',
component: ResetPasswordComponent,
},
footerOutletRoute,
],
},
{
path: 'new-password',
component: PasswordFormComponent,
}, },
{ {
path: 'create-structure', path: 'create-structure',
component: FormComponent, children: [
canDeactivate: [DeactivateGuard], {
path: '',
component: FormComponent,
canDeactivate: [DeactivateGuard],
},
footerOutletRoute,
],
}, },
{ {
path: 'create-structure/:id', path: 'create-structure/:id',
component: FormComponent, children: [
canDeactivate: [DeactivateGuard], {
canActivate: [RoleGuard], path: '',
data: { allowedRoles: [RouteRole.structureAdmin] }, component: FormComponent,
resolve: { canDeactivate: [DeactivateGuard],
structure: StructureResolver, canActivate: [RoleGuard],
}, data: { allowedRoles: [RouteRole.structureAdmin] },
resolve: {
structure: StructureResolver,
},
},
footerOutletRoute,
],
}, },
{ {
path: 'newsletter', path: 'newsletter',
component: NewsletterSubscriptionComponent, children: [
{
path: '',
component: NewsletterSubscriptionComponent,
},
footerOutletRoute,
],
}, },
{ {
path: 'newsletter-unsubscribe', path: 'newsletter-unsubscribe',
component: NewsletterSubscriptionComponent, children: [
{
path: '',
component: NewsletterSubscriptionComponent,
},
footerOutletRoute,
],
}, },
{ {
path: 'news', path: 'news',
loadChildren: () => import('./post/post.module').then((m) => m.PostModule), children: [
{
path: '',
loadChildren: () => import('./post/post.module').then((m) => m.PostModule),
},
footerOutletRoute,
],
}, },
{ {
path: 'admin', path: 'admin',
canActivate: [AdminGuard], children: [
loadChildren: () => import('./admin/admin.module').then((m) => m.AdminModule), {
path: '',
canActivate: [AdminGuard],
loadChildren: () => import('./admin/admin.module').then((m) => m.AdminModule),
},
footerOutletRoute,
],
},
{
path: 'form',
loadChildren: () => import('./form/form-view/form-view.module').then((m) => m.FormViewModule),
}, },
{ {
path: 'home', path: 'home',
......
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
<div (scroll)="onScrollDown($event)" class="app-body"> <div (scroll)="onScrollDown($event)" class="app-body">
<router-outlet></router-outlet> <router-outlet></router-outlet>
<router-outlet name="print"></router-outlet> <router-outlet name="print"></router-outlet>
<app-footer></app-footer> <router-outlet name="footer"></router-outlet>
</div> </div>
</div> </div>
...@@ -17,20 +17,17 @@ import { StructureListComponent } from './structure-list/structure-list.componen ...@@ -17,20 +17,17 @@ import { StructureListComponent } from './structure-list/structure-list.componen
import { CardComponent } from './structure-list/components/card/card.component'; import { CardComponent } from './structure-list/components/card/card.component';
import { StructureListSearchComponent } from './structure-list/components/structure-list-search/structure-list-search.component'; import { StructureListSearchComponent } from './structure-list/components/structure-list-search/structure-list-search.component';
import { StructureDetailsComponent } from './structure-list/components/structure-details/structure-details.component'; import { StructureDetailsComponent } from './structure-list/components/structure-details/structure-details.component';
import { StructureOpeningStatusComponent } from './structure-list/components/structure-opening-status/structure-opening-status.component';
import { ModalFilterComponent } from './structure-list/components/modal-filter/modal-filter.component'; import { ModalFilterComponent } from './structure-list/components/modal-filter/modal-filter.component';
import { LegalNoticeComponent } from './legal-notice/legal-notice.component'; import { LegalNoticeComponent } from './legal-notice/legal-notice.component';
import { PageComponent } from './page/page.component'; import { PageComponent } from './page/page.component';
import { ContactComponent } from './contact/contact.component'; import { ContactComponent } from './contact/contact.component';
import { FormComponent } from './form/structure-form/form.component'; import { FormComponent } from './form/structure-form/form.component';
import { UserVerificationComponent } from './user-verification/user-verification.component';
import { AuthGuard } from './guards/auth.guard'; import { AuthGuard } from './guards/auth.guard';
import { CustomHttpInterceptor } from './config/http-interceptor'; import { CustomHttpInterceptor } from './config/http-interceptor';
import { ResetEmailComponent } from './reset-email/reset-email.component'; import { ResetEmailComponent } from './reset-email/reset-email.component';
import { ResetPasswordComponent } from './reset-password/reset-password.component'; import { ResetPasswordComponent } from './reset-password/reset-password.component';
import { AdminGuard } from './guards/admin.guard'; import { AdminGuard } from './guards/admin.guard';
import { DeactivateGuard } from './guards/deactivate.guard'; import { DeactivateGuard } from './guards/deactivate.guard';
import { FooterFormComponent } from './form/footer-form/footer-form.component';
import { TempUserResolver } from './resolvers/temp-user.resolver'; import { TempUserResolver } from './resolvers/temp-user.resolver';
import { StructureJoinComponent } from './structure-join/structure-join.component'; import { StructureJoinComponent } from './structure-join/structure-join.component';
import { RouterListenerService } from './services/routerListener.service'; import { RouterListenerService } from './services/routerListener.service';
...@@ -46,6 +43,8 @@ import { StructureResolver } from './resolvers/structure.resolver'; ...@@ -46,6 +43,8 @@ import { StructureResolver } from './resolvers/structure.resolver';
import { RoleGuard } from './guards/role.guard'; import { RoleGuard } from './guards/role.guard';
import { UpdateService } from './services/update.service'; import { UpdateService } from './services/update.service';
import { DataShareConsentComponent } from './shared/components/data-share-consent/data-share-consent.component'; import { DataShareConsentComponent } from './shared/components/data-share-consent/data-share-consent.component';
import { FormViewModule } from './form/form-view/form-view.module';
import { LoginComponent } from './login/login.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
...@@ -58,15 +57,12 @@ import { DataShareConsentComponent } from './shared/components/data-share-consen ...@@ -58,15 +57,12 @@ import { DataShareConsentComponent } from './shared/components/data-share-consen
StructureListSearchComponent, StructureListSearchComponent,
ModalFilterComponent, ModalFilterComponent,
StructureDetailsComponent, StructureDetailsComponent,
StructureOpeningStatusComponent,
LegalNoticeComponent, LegalNoticeComponent,
PageComponent, PageComponent,
ContactComponent, ContactComponent,
UserVerificationComponent,
ResetEmailComponent, ResetEmailComponent,
ResetPasswordComponent, ResetPasswordComponent,
FormComponent, FormComponent,
FooterFormComponent,
StructureJoinComponent, StructureJoinComponent,
NewsletterSubscriptionComponent, NewsletterSubscriptionComponent,
OrientationFormComponent, OrientationFormComponent,
...@@ -75,6 +71,7 @@ import { DataShareConsentComponent } from './shared/components/data-share-consen ...@@ -75,6 +71,7 @@ import { DataShareConsentComponent } from './shared/components/data-share-consen
StructurePrintHeaderComponent, StructurePrintHeaderComponent,
DataShareConsentComponent, DataShareConsentComponent,
OrientationComponent, OrientationComponent,
LoginComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
...@@ -84,6 +81,7 @@ import { DataShareConsentComponent } from './shared/components/data-share-consen ...@@ -84,6 +81,7 @@ import { DataShareConsentComponent } from './shared/components/data-share-consen
MapModule, MapModule,
BrowserAnimationsModule, BrowserAnimationsModule,
ToastrModule.forRoot(), ToastrModule.forRoot(),
FormViewModule,
ServiceWorkerModule.register('ngsw-worker.js', { ServiceWorkerModule.register('ngsw-worker.js', {
enabled: environment.production, enabled: environment.production,
}), }),
......
<div fxLayout="row" class="content-container"> <div class="content-container">
<app-structure-list <div class="hide-on-print">
(searchEvent)="getStructures($event)" <app-structure-list-search (searchEvent)="getStructures($event)"></app-structure-list-search>
[structureList]="structures" </div>
[location]="currentLocation" <div class="panes-container" fxLayout="row">
[locate]="locate" <app-structure-list
(displayMapMarkerId)="setMapMarkerId($event)" (searchEvent)="getStructures($event)"
(selectedMarkerId)="setSelectedMarkerId($event)" [structureList]="structures"
[selectedStructure]="currentStructure" [location]="currentLocation"
(updatedStructure)="updateStructures($event)" (displayMapMarkerId)="setMapMarkerId($event)"
(locatationReset)="locatationReset()" (selectedMarkerId)="setSelectedMarkerId($event)"
(locatationTrigger)="locatationTrigger(null)" [selectedStructure]="currentStructure"
class="left-pane" (updatedStructure)="updateStructures($event)"
[ngClass]="{ mapPhone: isMapPhone == true }" class="left-pane"
fxLayout="column" [ngClass]="{ mapPhone: isMapPhone == true }"
></app-structure-list> fxLayout="column"
<div class="btnSwitch"> ></app-structure-list>
<app-button <div class="btnSwitch">
[style]="'roundedButton'" <app-button
[text]="isMapPhone ? 'Liste' : 'Carte'" [style]="buttonTypeEnum.ButtonPhone"
[iconBtn]="isMapPhone ? 'liste' : 'map-marker'" [text]="isMapPhone ? 'Liste' : 'Carte'"
(action)="switchMapList()" [iconBtn]="isMapPhone ? 'liste' : 'map-markerButtonPhone'"
></app-button> (action)="switchMapList()"
></app-button>
</div>
<app-map
[structures]="structures"
[toogleToolTipId]="displayMarkerId"
[selectedMarkerId]="selectedMarkerId"
(selectedStructure)="showDetailStructure($event)"
[isMapPhone]="isMapPhone"
[searchedValue]="searchedValue"
class="right-pane"
[ngClass]="{ mapPhone: isMapPhone == true }"
></app-map>
</div> </div>
<app-map
[structures]="structures"
[toogleToolTipId]="displayMarkerId"
[selectedMarkerId]="selectedMarkerId"
[locate]="locate"
(selectedStructure)="showDetailStructure($event)"
(locatationTrigger)="locatationTrigger($event)"
[isMapPhone]="isMapPhone"
[searchedValue]="searchedValue"
class="right-pane"
[ngClass]="{ mapPhone: isMapPhone == true }"
></app-map>
</div> </div>
@import '../../assets/scss/breakpoint'; @import '../../assets/scss/breakpoint';
@import '../../assets/scss/layout'; @import '../../assets/scss/layout';
@import '../../assets/scss/z-index'; @import '../../assets/scss/z-index';
@import '../../assets/scss/color';
::ng-deep .footer { ::ng-deep .footer {
@media #{$tablet} { @media #{$tablet} {
...@@ -8,36 +9,48 @@ ...@@ -8,36 +9,48 @@
} }
} }
.left-pane { .content-container {
width: 640px; height: calc(100vh - #{$header-height});
min-width: 640px; background: $white;
@media #{$tablet} { padding-top: 0.6rem;
width: 100%; display: flex;
min-width: unset; flex-direction: column;
&.mapPhone {
display: none !important;
}
}
} }
.right-pane {
width: 80%; .panes-container {
padding: 0 16px; width: 100%;
@media #{$tablet} { position: relative;
display: none; flex: 1;
&.mapPhone { overflow-y: hidden;
display: block; overflow-x: hidden;
.left-pane {
height: 100%;
width: 600px;
min-width: 600px;
overflow-y: auto;
border-right: 1px solid $grey-4;
@media #{$tablet} {
width: 100%;
min-width: unset;
border-right: none;
&.mapPhone {
display: none !important;
}
} }
width: 100%;
padding: 0;
} }
} .right-pane {
.content-container { height: 100%;
height: calc(100vh - #{$header-height} - #{$footer-height}); width: 100%;
@media #{$tablet} { @media #{$tablet} {
padding: 0; display: none;
height: calc(100vh - #{$header-height}); &.mapPhone {
display: block;
}
padding: 0;
}
} }
} }
.btnSwitch { .btnSwitch {
position: fixed; position: fixed;
left: 50%; left: 50%;
......
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Meta } from '@angular/platform-browser'; import { Meta } from '@angular/platform-browser';
const { DateTime } = require('luxon');
import * as _ from 'lodash'; import * as _ from 'lodash';
import { Structure } from '../models/structure.model'; import { Structure } from '../models/structure.model';
...@@ -10,6 +9,7 @@ import { GeoJson } from '../map/models/geojson.model'; ...@@ -10,6 +9,7 @@ import { GeoJson } from '../map/models/geojson.model';
import { GeojsonService } from '../services/geojson.service'; import { GeojsonService } from '../services/geojson.service';
import { CustomRegExp } from '../utils/CustomRegExp'; import { CustomRegExp } from '../utils/CustomRegExp';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { ButtonType } from '../shared/components/button/buttonType.enum';
@Component({ @Component({
selector: 'app-carto', selector: 'app-carto',
...@@ -17,6 +17,7 @@ import { ActivatedRoute } from '@angular/router'; ...@@ -17,6 +17,7 @@ import { ActivatedRoute } from '@angular/router';
styleUrls: ['./carto.component.scss'], styleUrls: ['./carto.component.scss'],
}) })
export class CartoComponent implements OnInit { export class CartoComponent implements OnInit {
public filters: Filter[] = [];
public structures: Structure[] = []; public structures: Structure[] = [];
public displayMarkerId: string; public displayMarkerId: string;
public selectedMarkerId: string; public selectedMarkerId: string;
...@@ -27,7 +28,7 @@ export class CartoComponent implements OnInit { ...@@ -27,7 +28,7 @@ export class CartoComponent implements OnInit {
public userLongitude: number; public userLongitude: number;
public isMapPhone = false; public isMapPhone = false;
public searchedValue = null; public searchedValue = null;
public locate = false; // Use to sync location between search and map public buttonTypeEnum = ButtonType;
constructor( constructor(
private structureService: StructureService, private structureService: StructureService,
private geoJsonService: GeojsonService, private geoJsonService: GeojsonService,
...@@ -207,17 +208,4 @@ export class CartoComponent implements OnInit { ...@@ -207,17 +208,4 @@ export class CartoComponent implements OnInit {
public switchMapList(): void { public switchMapList(): void {
this.isMapPhone = !this.isMapPhone; this.isMapPhone = !this.isMapPhone;
} }
public locatationTrigger(event: any): void {
if (event && event !== this.locate) {
this.locate = !this.locate;
}
if (!event) {
this.locate = true;
}
}
public locatationReset(): void {
this.locate = false;
}
} }
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
color: $white; color: $white;
margin: 0px 0px 0px 10px; margin: 0px 0px 0px 10px;
text-decoration: none; text-decoration: none;
@include cn-regular-12; @include lato-regular-12;
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
} }
......
<div fxLayout="row" [ngClass]="{ column: hasFinishButton() }" fxLayoutGap="10px" fxLayoutAlign="center center"> <div
<button *ngIf="displayPreviousButton" class="btn-primary small previous" (click)="goToPreviousPage()"> class="footerForm"
<div class="rowBtn" fxLayout="row" fxLayoutAlign="center center"> fxLayout="row"
<svg class="chevronLeft" aria-hidden="true"> [ngClass]="{ column: hasFinishButton() }"
<use [attr.xlink:href]="'assets/form/sprite.svg#chevronLeft'"></use> fxLayoutGap="10px"
</svg> fxLayoutAlign="center center"
{{ btnName[0] }} >
</div> <app-button
</button> *ngIf="!isLastFormStep && !isNextFormTransition && !isStructureLastPage() && !isPersonalOfferFirstPage()"
(action)="prevPage()"
[text]="btnName[0]"
[iconType]="'form'"
[iconBtn]="'chevronLeft'"
></app-button>
<button *ngIf="hasFinishButton()" class="btn-primary small previous" (click)="finishedModal()"> <app-button *ngIf="isLastFormStep" (action)="goToHome()" [text]="'Ok'" [style]="buttonTypeEnum.Primary"></app-button>
<div class="rowBtn" fxLayout="row" fxLayoutAlign="center center">
<svg class="flag" aria-hidden="true">
<use [attr.xlink:href]="'/assets/ico/flag.svg'"></use>
</svg>
{{ btnName[2] }}
</div>
</button>
<button <app-button
class="btn-primary small next" *ngIf="!isLastFormStep && !isNextFormTransition"
(click)="goToNextPage()" (action)="nextPage()"
[disabled]="!isValid" [disabled]="!isValid"
type="submit" [text]="btnName[1]"
[ngClass]="{ invalid: !isValid }" [iconBtn]="btnName[1] == 'Imprimer' ? 'print' : 'chevronRight'"
[iconType]="'form'"
[iconPos]="'right'"
[style]="buttonTypeEnum.Primary"
> >
<div *ngIf="btnName[1] == 'Imprimer'" fxLayout="row" fxLayoutAlign="center center"> </app-button>
<svg class="print" aria-hidden="true">
<use [attr.xlink:href]="'/assets/ico/print.svg'"></use>
</svg>
{{ btnName[1] }}
</div>
<div *ngIf="btnName[1] != 'Imprimer'" class="rowBtn" fxLayout="row" fxLayoutAlign="center center">
{{ btnName[1] }}
<svg class="chevronRight" aria-hidden="true">
<use [attr.xlink:href]="'assets/form/sprite.svg#chevronRight'"></use>
</svg>
</div>
</button>
</div> </div>
...@@ -2,18 +2,22 @@ ...@@ -2,18 +2,22 @@
@import '../../../assets/scss/typography'; @import '../../../assets/scss/typography';
@import '../../../assets/scss/breakpoint'; @import '../../../assets/scss/breakpoint';
.footerForm {
padding: 20px 0;
}
.btn-primary { .btn-primary {
&.previous { &.previous {
background-color: $white; background-color: $white;
color: $grey-2; color: $grey-1;
border: solid $grey-4 1px; border: 1px solid $grey-1;
} }
&.invalid { &.invalid {
opacity: 0.4; opacity: 0.4;
} }
&:focus .print { &:focus .print {
background-color: $secondary-color; background-color: $primary-color;
} }
&.next { &.next {
......
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Router } from '@angular/router';
import { User } from '../../models/user.model';
import { ProfileService } from '../../profile/services/profile.service';
import { AuthService } from '../../services/auth.service';
import { NewsletterService } from '../../services/newsletter.service';
import { StructureService } from '../../services/structure.service';
import { ButtonType } from '../../shared/components/button/buttonType.enum';
import { Utils } from '../../utils/utils';
import { accountFormStep } from '../form-view/account-form/accountFormStep.enum';
import { formType } from '../form-view/formType.enum';
import { personalOfferFormStep } from '../form-view/personal-offer-form/personalOfferFormStep.enum';
import { profileFormStep } from '../form-view/profile-form/profileFormStep.enum';
import { structureFormStep } from '../form-view/structure-form/structureFormStep.enum';
@Component({ @Component({
selector: 'app-footer-form', selector: 'app-footer-form',
templateUrl: './footer-form.component.html', templateUrl: './footer-form.component.html',
styleUrls: ['./footer-form.component.scss'], styleUrls: ['./footer-form.component.scss'],
}) })
export class FooterFormComponent { export class FooterFormComponent implements OnChanges {
@Input() currentForm: formType;
@Input() isValid: boolean; @Input() isValid: boolean;
@Input() isClaimMode: boolean;
@Input() isAccountMode: boolean;
@Input() btnName: string[]; @Input() btnName: string[];
@Input() displayPreviousButton: boolean = true; @Input() nbPagesForm: number;
@Output() nextPage = new EventEmitter<any>(); @Input() form: FormGroup;
@Output() previousPage = new EventEmitter<any>(); @Input() linkedStructureId: Array<string> = null;
@Input() acceptNewsletter: boolean;
@Input() currentStep: accountFormStep | profileFormStep | structureFormStep | personalOfferFormStep;
@Input() hasOtherPersonalOffer: boolean;
@Output() goNext = new EventEmitter<any>();
@Output() goPrev = new EventEmitter<any>();
@Output() endPage = new EventEmitter<any>(); @Output() endPage = new EventEmitter<any>();
@Output() endForm = new EventEmitter<any>();
@Output() changeCurrentStep = new EventEmitter<any>();
public isLastFormStep: boolean = false;
public isNextFormTransition: boolean = false;
public buttonTypeEnum = ButtonType;
constructor(
private authService: AuthService,
public utils: Utils,
private router: Router,
private structureService: StructureService,
private profileService: ProfileService,
private newsletterService: NewsletterService
) {}
public goToNextPage(): void { public goToNextPage(): void {
this.nextPage.emit(); this.goNext.emit();
}
async ngOnChanges(changes: SimpleChanges): Promise<void> {
if (changes.currentStep) {
if (this.currentStep === accountFormStep.confirmEmailSentInfo && this.currentForm === formType.account) {
this.isLastFormStep = true;
}
if (
this.currentForm === formType.personaloffer &&
this.currentStep === personalOfferFormStep.personalOfferFinishedInfo &&
!this.hasOtherPersonalOffer
) {
this.isNextFormTransition = true;
}
if (this.currentForm === formType.structure && this.currentStep === structureFormStep.mailSentInfo) {
const user: User = await this.profileService.getProfile();
if (!user.job.hasPersonalOffer) {
this.isLastFormStep = true;
}
}
}
} }
public goToPreviousPage(): void { public goToPreviousPage(): void {
this.previousPage.emit(); this.goPrev.emit();
} }
public hasFinishButton(): boolean { public hasFinishButton(): boolean {
...@@ -27,4 +84,94 @@ export class FooterFormComponent { ...@@ -27,4 +84,94 @@ export class FooterFormComponent {
public finishedModal(): void { public finishedModal(): void {
this.endPage.emit(); this.endPage.emit();
} }
public goToHome(): void {
this.router.navigateByUrl('news');
}
public prevPage(): void {
if (this.currentForm === formType.structure && this.currentStep === structureFormStep.structureType) {
this.changeCurrentStep.emit(structureFormStep.structureFormTime);
return;
}
this.goToPreviousPage();
}
public async nextPage(): Promise<void> {
if (this.currentForm === formType.account && this.currentStep === accountFormStep.accountNewsletter) {
const user = new User(this.form.value);
// Create user with structure
user.structuresLink = this.linkedStructureId;
this.authService.register(user).subscribe(() => {});
this.newsletterService.newsletterSubscribe(user.email).subscribe(() => {});
document.getElementsByClassName('page')[0].scrollTo(0, 0);
}
if (this.isProfileLastPage()) {
this.endForm.emit({ formType: this.currentForm });
return;
}
if (this.currentForm === formType.structure) {
if (this.currentStep === structureFormStep.structureChoiceCompletion) {
const chooseCompleteStructInfo = this.form.get('choiceCompletion').value;
if (!chooseCompleteStructInfo) {
this.changeCurrentStep.emit(structureFormStep.structureContactCompletion);
return;
}
}
if (this.currentStep === structureFormStep.structureFormTime) {
this.changeCurrentStep.emit(structureFormStep.structureType);
return;
}
if (this.currentStep === structureFormStep.structureContactCompletion) {
//TODO Go to send mail page and send the mail
return;
}
if (this.currentStep === structureFormStep.structureConsent) {
const user: User = await this.profileService.getProfile();
this.structureService.createStructure(this.form.value, user).subscribe(() => {});
}
}
if (this.isPersonalOfferpage()) {
this.endForm.emit({ formType: this.currentForm });
return;
}
if (this.isStructureChoiceValid()) {
this.endForm.emit({ formType: this.currentForm, formStep: this.currentStep });
return;
}
if (this.isStructureLastPage()) {
this.endForm.emit({ formType: this.currentForm, formStep: this.currentStep });
return;
}
this.goToNextPage();
}
private isStructureChoiceValid(): boolean {
return (
this.currentForm === formType.structure &&
this.currentStep === structureFormStep.structureChoice &&
this.form.value._id
);
}
public isStructureLastPage(): boolean {
return (
this.currentForm === formType.structure &&
(this.currentStep === structureFormStep.mailSentInfo ||
this.currentStep === structureFormStep.structureCreationFinishedInfo)
);
}
private isProfileLastPage(): boolean {
return this.currentForm === formType.profile && this.currentStep === profileFormStep.profileJobSelection;
}
private isPersonalOfferpage(): boolean {
return (
this.currentForm === formType.personaloffer &&
this.currentStep === personalOfferFormStep.personalOfferStructureChoice
);
}
public isPersonalOfferFirstPage(): boolean {
return this.currentStep === personalOfferFormStep.personalOfferAccompaniment;
}
} }
<form
[formGroup]="accountForm"
*ngIf="accountForm && !profile"
(keyup.enter)="isPageValid && !isEditMode ? nextPage() : null"
>
<div class="title">
<h3>Quels identifiants utiliserez-vous pour vous connecter&nbsp;?</h3>
</div>
<div class="form-group" fxLayout="column">
<label for="email">Email du compte</label>
<p class="special invalid" *ngIf="this.accountForm.get('email').hasError('alreadyExist')">
L'email est déja utilisé.
</p>
<div fxLayout="row" fxLayoutGap="13px">
<input
type="text"
(input)="setValidationsForm()"
(keyup)="verifyUserExist($event.target.value)"
formControlName="email"
placeholder="exemple: prenom.nom@grandlyon.com"
class="form-input email-placeholder"
[readonly]="isAccountMode"
[ngClass]="{ disabled: isAccountMode }"
/>
<app-svg-icon
*ngIf="accountForm.get('email').valid"
[iconClass]="'icon-26'"
[type]="'form'"
[icon]="'validate'"
></app-svg-icon>
<app-svg-icon
*ngIf="accountForm.get('email').invalid && accountForm.get('email').value"
[iconClass]="'icon-26'"
[type]="'form'"
[icon]="'notValidate'"
></app-svg-icon>
</div>
</div>
<div class="form-group" fxLayout="column">
<p
class="special"
[ngClass]="{ invalid: accountForm.get('password').invalid && accountForm.get('password').value }"
>
Le mot de passe doit contenir au minimum
</p>
<ul>
<li
fxLayout="row"
fxLayoutAlign="start center"
fxLayoutGap="10px"
[ngClass]="{
invalid: accountForm.get('password').value.length < 8,
valid: accountForm.get('password').value.length >= 8
}"
class=""
>
<app-svg-icon
*ngIf="accountForm.get('password').value.length >= 8"
[iconClass]="'icon-16'"
[type]="'form'"
[icon]="'validate'"
></app-svg-icon>
<app-svg-icon
*ngIf="accountForm.get('password').value.length < 8"
[iconClass]="'icon-16'"
[type]="'form'"
[icon]="'notValidate'"
></app-svg-icon>
<p>8 caractères</p>
</li>
<li
fxLayout="row"
fxLayoutAlign="start center"
fxLayoutGap="10px"
[ngClass]="{
invalid: !checkIfPasswordHasSpecialChar(accountForm.get('password').value),
valid: checkIfPasswordHasSpecialChar(accountForm.get('password').value)
}"
>
<app-svg-icon
*ngIf="checkIfPasswordHasSpecialChar(accountForm.get('password').value)"
[iconClass]="'icon-16'"
[type]="'form'"
[icon]="'validate'"
></app-svg-icon>
<app-svg-icon
*ngIf="!checkIfPasswordHasSpecialChar(accountForm.get('password').value)"
[iconClass]="'icon-16'"
[type]="'form'"
[icon]="'notValidate'"
></app-svg-icon>
<p>un caractère spécial</p>
</li>
<li
fxLayout="row"
fxLayoutAlign="start center"
fxLayoutGap="10px"
[ngClass]="{
invalid: !checkIfPasswordHasLowerCase(accountForm.get('password').value),
valid: checkIfPasswordHasLowerCase(accountForm.get('password').value)
}"
>
<app-svg-icon
*ngIf="checkIfPasswordHasLowerCase(accountForm.get('password').value)"
[iconClass]="'icon-16'"
[type]="'form'"
[icon]="'validate'"
></app-svg-icon>
<app-svg-icon
*ngIf="!checkIfPasswordHasLowerCase(accountForm.get('password').value); s"
[iconClass]="'icon-16'"
[type]="'form'"
[icon]="'notValidate'"
></app-svg-icon>
<p>un caractère en minuscule</p>
</li>
<li
fxLayout="row"
fxLayoutAlign="start center"
fxLayoutGap="10px"
[ngClass]="{
invalid: !checkIfPasswordHasUpperCase(accountForm.get('password').value),
valid: checkIfPasswordHasUpperCase(accountForm.get('password').value)
}"
>
<app-svg-icon
*ngIf="checkIfPasswordHasUpperCase(accountForm.get('password').value)"
[iconClass]="'icon-16'"
[type]="'form'"
[icon]="'validate'"
></app-svg-icon>
<app-svg-icon
*ngIf="!checkIfPasswordHasUpperCase(accountForm.get('password').value); s"
[iconClass]="'icon-16'"
[type]="'form'"
[icon]="'notValidate'"
></app-svg-icon>
<p>un caractère en majuscule</p>
</li>
<li
fxLayout="row"
fxLayoutAlign="start center"
fxLayoutGap="10px"
[ngClass]="{
invalid: !checkIfPasswordHasDigit(accountForm.get('password').value),
valid: checkIfPasswordHasDigit(accountForm.get('password').value)
}"
>
<app-svg-icon
*ngIf="checkIfPasswordHasDigit(accountForm.get('password').value)"
[iconClass]="'icon-16'"
[type]="'form'"
[icon]="'validate'"
></app-svg-icon>
<app-svg-icon
*ngIf="!checkIfPasswordHasDigit(accountForm.get('password').value)"
[iconClass]="'icon-16'"
[type]="'form'"
[icon]="'notValidate'"
></app-svg-icon>
<p>un chiffre</p>
</li>
</ul>
<div fxLayout="row" fxLayoutAlign="none center" fxLayoutGap="13px">
<input
[type]="isShowPassword ? 'text' : 'password'"
formControlName="password"
class="form-input password"
(input)="setValidationsForm()"
autocomplete="on"
/>
<app-svg-icon
[iconClass]="'icon-26 grey hover'"
[type]="'form'"
[icon]="'eyePassword'"
(click)="showPassword()"
></app-svg-icon>
<app-svg-icon
*ngIf="accountForm.get('password').valid"
[iconClass]="'icon-26'"
[type]="'form'"
[icon]="'validate'"
></app-svg-icon>
<app-svg-icon
*ngIf="accountForm.get('password').invalid && accountForm.get('password').value"
[iconClass]="'icon-26'"
[type]="'form'"
[icon]="'notValidate'"
></app-svg-icon>
</div>
</div>
<div class="form-group" fxLayout="column">
<label for="confirmPassword">Vérification du mot de passe</label>
<div fxLayout="row" fxLayoutAlign="none center" fxLayoutGap="13px">
<input
[type]="isShowConfirmPassword ? 'text' : 'password'"
formControlName="confirmPassword"
class="form-input password"
(input)="setValidationsForm()"
autocomplete="on"
/>
<app-svg-icon
[iconClass]="'icon-26 grey hover'"
[type]="'form'"
[icon]="'eyePassword'"
(click)="showConfirmPassword()"
></app-svg-icon>
<app-svg-icon
*ngIf="accountForm.get('confirmPassword').valid && accountForm.get('confirmPassword').value"
[iconClass]="'icon-26'"
[type]="'form'"
[icon]="'validate'"
></app-svg-icon>
<app-svg-icon
*ngIf="accountForm.get('confirmPassword').invalid && accountForm.get('confirmPassword').value"
[iconClass]="'icon-26'"
[type]="'form'"
[icon]="'notValidate'"
></app-svg-icon>
</div>
</div>
</form>
@import '../../../../../assets/scss/color';
@import '../../../../../assets/scss/typography';
p.special {
@include lato-regular-14;
color: $grey-3;
margin: 4px 0 8px 0;
width: 280px;
&.invalid {
color: $orange-warning;
}
}
ul {
padding-left: 0;
margin: 0 0 8px 8px;
li {
display: flex;
margin: 4px 0 0 0;
font-size: small;
align-items: center;
p {
margin-top: unset;
margin-bottom: 0;
@include lato-regular-14;
}
&.valid {
color: $green;
}
&.invalid {
color: $orange-warning;
}
}
}
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AccountCredentialsComponent } from './account-credentials.component';
describe('AccountCredentialsComponent', () => {
let component: AccountCredentialsComponent;
let fixture: ComponentFixture<AccountCredentialsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AccountCredentialsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AccountCredentialsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { User } from '../../../../models/user.model';
import { CustomRegExp } from '../../../../utils/CustomRegExp';
@Component({
selector: 'app-account-credentials',
templateUrl: './account-credentials.component.html',
styleUrls: ['./account-credentials.component.scss'],
})
export class AccountCredentialsComponent {
@Input() accountForm: FormGroup;
@Input() isAccountMode: boolean;
@Input() profile: User;
@Output() validateForm = new EventEmitter<any>();
@Output() userExists = new EventEmitter<any>();
public isShowConfirmPassword = false;
public isShowPassword = false;
public showPassword(): void {
this.isShowPassword = !this.isShowPassword;
}
public showConfirmPassword(): void {
this.isShowConfirmPassword = !this.isShowConfirmPassword;
}
public checkIfPasswordHasSpecialChar(password: string): boolean {
if (password.match(CustomRegExp.SPECHAR)) return true;
return false;
}
public checkIfPasswordHasDigit(password: string): boolean {
if (password.match(CustomRegExp.DIGIT)) return true;
return false;
}
public checkIfPasswordHasUpperCase(password: string): boolean {
if (password.match(CustomRegExp.UPPERCASE)) return true;
return false;
}
public checkIfPasswordHasLowerCase(password: string): boolean {
if (password.match(CustomRegExp.LOWERCASE)) return true;
return false;
}
public setValidationsForm() {
this.validateForm.emit();
}
public verifyUserExist(value: string) {
this.userExists.emit(value);
}
}
<div class="no-max-width">
<ng-container *ngIf="currentStep === accountFormStepEnum.accountInfo">
<app-account-info
[accountForm]="accountForm"
[isClaimMode]="isClaimMode"
[profile]="profile"
(validateForm)="setValidationsForm($event)"
></app-account-info>
</ng-container>
<ng-container *ngIf="currentStep === accountFormStepEnum.accountCredentials">
<app-account-credentials
[accountForm]="accountForm"
[profile]="profile"
(validateForm)="setValidationsForm($event)"
(userExists)="verifyUserExist($event)"
></app-account-credentials>
</ng-container>
<ng-container *ngIf="currentStep === accountFormStepEnum.accountNewsletter">
<app-account-newsletter
[accountForm]="accountForm"
[profile]="profile"
(acceptNewsletter)="acceptReceiveNewsletter($event)"
></app-account-newsletter>
</ng-container>
<ng-container *ngIf="currentStep === accountFormStepEnum.confirmEmailSentInfo">
<app-information-step
[step]="accountFormStepEnum.confirmEmailSentInfo"
[formType]="formType.account"
></app-information-step>
</ng-container>
</div>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AccountFormComponent } from './account-form.component';
describe('AccountFormComponent', () => {
let component: AccountFormComponent;
let fixture: ComponentFixture<AccountFormComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AccountFormComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AccountFormComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});