diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4fce8137e2c5d0f363eda55e1963035a8f52a375..b40915a21022451d5093fe1095baa75843109795 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,20 +3,36 @@ stages: - build - deploy +default: + services: + - name: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09-dind + alias: docker + +variables: + DEPENDENCY_PROXY: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/ + build_branch: + variables: + DOCKER_TLS_CERTDIR: '' + DOCKER_HOST: tcp://docker:2375/ + DOCKER_DRIVER: overlay2 image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09 - services: - - docker:18.09-dind stage: build + except: + - master + - recette + - dev script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - - docker build --pull -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" --build-arg conf=prod . - - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" + - docker build --pull -t "$CI_REGISTRY_IMAGE/feat:$CI_COMMIT_REF_SLUG" --build-arg conf=prod . + - docker push "$CI_REGISTRY_IMAGE/feat:$CI_COMMIT_REF_SLUG" build: + variables: + DOCKER_TLS_CERTDIR: '' + DOCKER_HOST: tcp://docker:2375/ + DOCKER_DRIVER: overlay2 image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09 - services: - - docker:18.09-dind stage: build only: - master @@ -26,30 +42,33 @@ build: - docker build --pull -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" --build-arg conf=prod . - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" -build_dev: +build-release: + variables: + DOCKER_TLS_CERTDIR: '' + DOCKER_HOST: tcp://docker:2375/ + DOCKER_DRIVER: overlay2 image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09 - services: - - docker:18.09-dind stage: build only: - - dev + - tags script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - - docker build --pull -t "$CI_REGISTRY_IMAGE:dev" --build-arg conf=dev . - - docker push "$CI_REGISTRY_IMAGE:dev" + - docker build --pull -t "$CI_REGISTRY_IMAGE/tags:$CI_COMMIT_TAG" --build-arg conf=prod . + - docker push "$CI_REGISTRY_IMAGE/tags:$CI_COMMIT_TAG" -build_json_server: +build_dev: + variables: + DOCKER_TLS_CERTDIR: '' + DOCKER_HOST: tcp://docker:2375/ + DOCKER_DRIVER: overlay2 image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09 - services: - - docker:18.09-dind stage: build only: - dev script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - - docker build --pull -t "$CI_REGISTRY_IMAGE:json_server" ./api/ - - docker push "$CI_REGISTRY_IMAGE:json_server" - when: manual + - docker build --pull -t "$CI_REGISTRY_IMAGE:dev" --build-arg conf=dev . + - docker push "$CI_REGISTRY_IMAGE:dev" deploy_dev: stage: deploy @@ -63,19 +82,9 @@ deploy_dev: - docker-compose pull web-app - docker-compose up -d web-app - docker system prune -a -f - -deploy_mobile: - stage: deploy - tags: - - deploy - only: - - mobile - script: - - cd /home/mps/ram - - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - - docker-compose pull web-app - - docker-compose up -d web-app - - docker system prune -a -f + environment: + name: dev + url: https://resin-dev.grandlyon.com deploy_rec: stage: deploy @@ -89,6 +98,10 @@ deploy_rec: - docker-compose pull web-app-rec - docker-compose up -d web-app-rec - docker system prune -a -f + when: manual + environment: + name: rec + url: https://resin-rec.grandlyon.com # code_analysis: # image: skilldlabs/sonar-scanner:3.4.0 @@ -112,26 +125,14 @@ deploy_rec: # -Dsonar.login=${SONAR_TOKEN} mr: + variables: + DOCKER_TLS_CERTDIR: '' + DOCKER_HOST: tcp://docker:2375/ + DOCKER_DRIVER: overlay2 image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09 - services: - - docker:18.09-dind stage: build only: - merge_requests script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker build --pull -t "$CI_REGISTRY_IMAGE:dev" --build-arg conf=dev . - -# Job for auto building pwa in case of issue -# Juste create a new branche 'pwa' -pwa-build: - image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09 - services: - - docker:18.09-dind - stage: build - only: - - feat/poc-pwa - script: - - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - - docker build --pull -t "$CI_REGISTRY_IMAGE:pwa" --build-arg conf=dev . - - docker push "$CI_REGISTRY_IMAGE:pwa" diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ec95edb12782182a02ab8bdafa4eee53463f75f..72bd552650f263026a13f8ff214f99a50ea68eba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,41 @@ 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. +## [1.14.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/compare/v1.13.0...v1.14.0) (2022-02-21) + + +### Features + +* **carto:** enable pop-up autopan for markers in order to have a better display on small screen ([758b319](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/758b3193f1263bb31bf46d45a67b136e5fcdaa9f)) +* **carto:** put selected and hover marker on top of the others ([cc3c16c](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/cc3c16c34682f8baaed15caaf8ba70a91ecf4024)) +* **cicd:** rework on automation. Add feature and tag build. Better handling of dependencie proxy ([b9a6764](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/b9a67640b4c7aae589019ae57330d734e5ce3300)) +* **nginx:** new conf for PWA handling ([a38b929](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/a38b929207e0543857867efa355c7c014e96a99e)) +* **orientation-form:** change orientation form design ([1946312](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/1946312fe8b9e1a025693c53ecea6c08d21e5031)) +* **post:** display attachment in post ([020c192](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/020c192182d3d275ecfecd27cdc59bdabe1e0387)) +* **previewImages:** Manage post preview image independantly from post details images ([1761f74](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/1761f7412c9b2645925a6ed925a585fdae8326f9)) +* **print-orientation:** graphic update for the print at the end of the orientation ([335ba0a](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/335ba0af1e97893ba2f3107366598eb67a9fd1fd)) +* **reset-password:** add notification when reset email is sent ([ed857c5](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/ed857c5ca45086ac30a4f1977ac5ae524b15161a)) +* **searchResults:** Add page descriptions ([c15012f](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/c15012fc12aaa9d43e27d273d75b12f77ac90e44)) + + +### Bug Fixes + +* **admin:** broken link in structure was making admin panel crash ([51ffbb4](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/51ffbb429cbf546c44765cf7f80e37e2dae48d0c)) +* **cicd:** fix deploy issue after variables adding ([0d9f2fc](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/0d9f2fca8ed2ee8aca43d839f8ceb69053f7359a)) +* **cicd:** job build issue on service ([74c091f](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/74c091f0486b2f7db555b825c15189b32967e581)) +* **cicd:** variable usage was making deploy job fail ([2461c64](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/2461c64b7a88dd2f6cd5f90ad530be726c5537da)) +* missing label on footer button ([9662f7e](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/9662f7e78b8ba74a0e2c182bd670b088891baf9b)) +* **news:** change updated date display to created date ([b4c323c](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/b4c323c464ef361b0568af56d550c8a4953be2e1)) +* **news:** created date in post list ([6d2ada7](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/6d2ada7c02b4c1efdb83c0f2e2770a385f4856a2)) +* **news:** issue in responsive, width of post-container is now fixed ([8fa4923](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/8fa492345262bdcea440010d467d0a0179d49ae3)) +* **news:** issue on news display, tag duplication and page display were broken ([7099003](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/70990035c6c417ad82f00c5d560e239c7d9a86fe)) +* **news:** tag refactor for 'a-la-une' tag. This tag is no longer display if there is another tag on the same post. ([9d0be47](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/9d0be47f1e6fe7a4cd684d6c2b65299bc6ccb0f0)) +* **orientation-form:** fix formation list ([2b5a449](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/2b5a4490f8287d045be49481ab475027cf596219)) +* **orientation-form:** remove geoloc button in carto from orientation form ([070d15d](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/070d15d913900a40186ab06f43504880b3b1b20e)) +* **posts:** remove image width forced to 100% in post details ([055e9cb](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/055e9cbe0db90f9409192d7d03b6363ee0f9a2a3)) +* **print-orientation:** progression percentage is 100% when printing ([5a2c196](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/5a2c196462a126646d2ae1e0b76760dd338876ab)) +* typo in mobile menu ([cb3ebc7](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/commit/cb3ebc7a5dc6c20d9451a0cee1558f5241554f63)) + ## [1.13.0](https://forge.grandlyon.com/web-et-numerique/pamn_plateforme-des-acteurs-de-la-mediation-numerique/pamn_client/compare/v1.12.0...v1.13.0) (2022-02-07) diff --git a/Dockerfile b/Dockerfile index 493f745e93832ffd75b90e7a992bc066c1368919..ed43a52e792b667e1a3e60c707bc8f8ddbabecfc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,6 @@ # Stage 0, based on Node.js, to build and compile Angular -FROM node:14.18-slim as build +ARG DEPENDENCY_PROXY= +FROM ${DEPENDENCY_PROXY}node:14.18-slim as build WORKDIR /app @@ -24,7 +25,7 @@ ARG conf RUN npm run build:prod # Stage 1, based on Nginx, to have only the compiled app -FROM nginx +FROM ${DEPENDENCY_PROXY}nginx # copy artifact build from the 'build environment' RUN apt-get update diff --git a/nginx/dev.conf b/nginx/dev.conf index d99a0f6f5025a621a88aca2ea0001194c01c18e9..ea0c2185e9c1fc86b802cb2beea015163ee221f1 100644 --- a/nginx/dev.conf +++ b/nginx/dev.conf @@ -48,8 +48,7 @@ server { } location /api { - rewrite ^/api/(.*) /$1 break; - proxy_pass http://service-ram:3000/api; + proxy_pass http://service-ram:3000; } location /base-adresse/base-adresse-nationale/streets { diff --git a/ngsw-config.json b/ngsw-config.json index e5b82fb2a06d7f3e43ca5fcfefcaf93972d9664c..100ac9f30659ea6e16d3bc2f5a5dfc653003f910 100644 --- a/ngsw-config.json +++ b/ngsw-config.json @@ -28,6 +28,16 @@ "maxAge": "12h", "timeout": "5s" } + }, + { + "name": "api", + "urls": ["/api/**"], + "cacheConfig": { + "strategy": "freshness", + "maxSize": 10000, + "maxAge": "12h", + "timeout": "5s" + } } ] } diff --git a/package-lock.json b/package-lock.json index 820b6fdb1a25c7f3d1ccd6f5d36c8ecbc23fb10b..17360dfd87dc1adc47011a52dd9e86f5c11553f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "pamn", - "version": "1.13.0", + "version": "1.14.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -9878,6 +9878,12 @@ "vary": "^1" } }, + "corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true + }, "cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -12074,6 +12080,12 @@ "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", "dev": true }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "hosted-git-info": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", @@ -12095,6 +12107,15 @@ "wbuf": "^1.1.0" } }, + "html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "requires": { + "whatwg-encoding": "^2.0.0" + } + }, "html-entities": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", @@ -12257,6 +12278,78 @@ } } }, + "http-server": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.0.tgz", + "integrity": "sha512-5lYsIcZtf6pdR8tCtzAHTWrAveo4liUlJdWc7YafwK/maPgYHs+VNP6KpCClmUnSorJrARVMXqtT055zBv11Yg==", + "dev": true, + "requires": { + "basic-auth": "^2.0.1", + "chalk": "^4.1.2", + "corser": "^2.0.1", + "he": "^1.2.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy": "^1.18.1", + "mime": "^1.6.0", + "minimist": "^1.2.5", + "opener": "^1.5.1", + "portfinder": "^1.0.28", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -14746,6 +14839,12 @@ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", "dev": true }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true + }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -16694,6 +16793,12 @@ "get-assigned-identifiers": "^1.1.0" } }, + "secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -18196,6 +18301,15 @@ } } }, + "union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "requires": { + "qs": "^6.4.0" + } + }, "unique-filename": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", @@ -18316,6 +18430,12 @@ "punycode": "^2.1.0" } }, + "url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true + }, "url-parse-lax": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", @@ -18733,6 +18853,26 @@ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, + "whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "requires": { + "iconv-lite": "0.6.3" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/package.json b/package.json index 8356afdb9b0672272ce72f8d60b45a17967451a6..e978d75bb56e522c587a00eefb1208b043aad48d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pamn", - "version": "1.13.0", + "version": "1.14.0", "scripts": { "ng": "ng", "start": "ng serve --configuration=fr --proxy-config proxy.conf.json", diff --git a/src/app/admin/components/manage-users/administred-structures/administred-structures.component.html b/src/app/admin/components/manage-users/administred-structures/administred-structures.component.html index 5943c02508cc249d4af1f7e050cf1602f76b7585..1755b8225b65b98da7502ea5d8aed3eac2a6677f 100644 --- a/src/app/admin/components/manage-users/administred-structures/administred-structures.component.html +++ b/src/app/admin/components/manage-users/administred-structures/administred-structures.component.html @@ -1,5 +1,5 @@ <div id="structure-list" *ngIf="structures.data.structures && structures.data.structures.length != 0"> <p *ngFor="let structure of structures.data.structures"> - <a href="/acteurs?id={{ structure._id }}" target="_blank">{{ structure.structureName }}</a> + <a *ngIf="structure" href="/acteurs?id={{ structure._id }}" target="_blank">{{ structure.structureName }}</a> </p> </div> diff --git a/src/app/app.module.ts b/src/app/app.module.ts index c07a408ad7ddde68a67ca634ef0af0d68143f35b..eb67d95d7956a67be8b559beaaf6874c73cfc22e 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -39,6 +39,7 @@ import { OrientationFormComponent } from './form/orientation-form/orientation-fo import { StructureDetailPrintComponent } from './form/orientation-form/component/structure-detail-print/structure-detail-print.component'; import { StructureListPrintComponent } from './form/orientation-form/component/structure-list-print/structure-list-print.component'; import { StructurePrintHeaderComponent } from './form/orientation-form/component/structure-print-header/structure-print-header.component'; +import { OrientationComponent } from './form/orientation-form/component/orientation-modal/orientation-modal.component'; import { ServiceWorkerModule } from '@angular/service-worker'; import { environment } from '../environments/environment'; import { StructureResolver } from './resolvers/structure.resolver'; @@ -71,6 +72,7 @@ import { UpdateService } from './services/update.service'; StructureDetailPrintComponent, StructureListPrintComponent, StructurePrintHeaderComponent, + OrientationComponent, ], imports: [ BrowserModule, diff --git a/src/app/carto/carto.component.scss b/src/app/carto/carto.component.scss index eb5f97b21e571114d361a3e105a98e9e0bdbc8fa..3fcf8948f75926feca5fb9e426e93f6a9372ec45 100644 --- a/src/app/carto/carto.component.scss +++ b/src/app/carto/carto.component.scss @@ -29,7 +29,7 @@ height: calc(100vh - #{$header-height} - #{$footer-height}); @media #{$tablet} { padding: 0; - height: 100%; + height: calc(100vh - #{$header-height}); } } .btnSwitch { diff --git a/src/app/carto/carto.component.ts b/src/app/carto/carto.component.ts index 52857d854d48f3ef0e0635e3b81c38172ea3e0cd..3c6d3289a6217ba7043c4189954ff48219fe70b6 100644 --- a/src/app/carto/carto.component.ts +++ b/src/app/carto/carto.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit } from '@angular/core'; +import { Meta } from '@angular/platform-browser'; const { DateTime } = require('luxon'); import * as _ from 'lodash'; @@ -30,7 +31,8 @@ export class CartoComponent implements OnInit { constructor( private structureService: StructureService, private geoJsonService: GeojsonService, - private activatedRoute: ActivatedRoute + private activatedRoute: ActivatedRoute, + private meta: Meta ) {} ngOnInit(): void { @@ -45,6 +47,11 @@ export class CartoComponent implements OnInit { if (history.state.data) { this.currentStructure = new Structure(history.state.data); } + + this.meta.updateTag({ + name: 'description', + content: 'Recense tous les lieux, accompagnements et ateliers de médiation numérique de la Métropole de Lyon.', + }); } public getStructures(filters: Filter[]): void { diff --git a/src/app/contact/contact.component.ts b/src/app/contact/contact.component.ts index 367ec8eca317d810079db2f3aed8218312e7aff3..c2e9bfcc490484111d01c7363bd78e8c9a07d043 100644 --- a/src/app/contact/contact.component.ts +++ b/src/app/contact/contact.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Router } from '@angular/router'; +import { Meta } from '@angular/platform-browser'; import { ContactMessage } from '../models/contact-message.model'; import { AuthService } from '../services/auth.service'; import { ContactService } from '../services/contact.service'; @@ -23,7 +24,8 @@ export class ContactComponent implements OnInit { private router: Router, private authService: AuthService, private notificationService: NotificationService, - public utils: Utils + public utils: Utils, + private meta: Meta ) {} ngOnInit(): void { @@ -37,6 +39,12 @@ export class ContactComponent implements OnInit { subject: ['', Validators.required], message: ['', Validators.required], }); + + this.meta.updateTag({ + name: 'description', + content: + "Formulaire pour contacter Rés'IN, le Réseau des acteurs de l'inclusion numérique de la métropole de Lyon", + }); } public get isLoggedIn(): boolean { diff --git a/src/app/form/footer-form/footer-form.component.html b/src/app/form/footer-form/footer-form.component.html index 6157b4a2cf76c62bb6919885cc21aba3e5aa80b0..3ced43e02bdf2f2ec863da05bd66847ed1c36a86 100644 --- a/src/app/form/footer-form/footer-form.component.html +++ b/src/app/form/footer-form/footer-form.component.html @@ -1,5 +1,5 @@ -<div fxLayout="row" fxLayoutGap="10px" fxLayoutAlign="center center"> - <button class="btn-primary small previous" (click)="goToPreviousPage()"> +<div fxLayout="row" [ngClass]="{ column: hasFinishButton() }" fxLayoutGap="10px" fxLayoutAlign="center center"> + <button *ngIf="displayPreviousButton" class="btn-primary small previous" (click)="goToPreviousPage()"> <div class="rowBtn" fxLayout="row" fxLayoutAlign="center center"> <svg class="chevronLeft" aria-hidden="true"> <use [attr.xlink:href]="'assets/form/sprite.svg#chevronLeft'"></use> @@ -7,6 +7,16 @@ {{ btnName[0] }} </div> </button> + + <button *ngIf="hasFinishButton()" class="btn-primary small previous" (click)="finishedModal()"> + <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 class="btn-primary small next" (click)="goToNextPage()" @@ -14,9 +24,15 @@ type="submit" [ngClass]="{ invalid: !isValid }" > - <div class="rowBtn" fxLayout="row" fxLayoutAlign="center center"> - {{ btnName[1] - }}<svg class="chevronRight" aria-hidden="true"> + <div *ngIf="btnName[1] == 'Imprimer'" fxLayout="row" fxLayoutAlign="center center"> + <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> diff --git a/src/app/form/footer-form/footer-form.component.scss b/src/app/form/footer-form/footer-form.component.scss index 6ebf95c44d942324b2dd9b9465419bbed1d9d809..1fb5bf38121a68fe52fe0b7352466ddfe76b551a 100644 --- a/src/app/form/footer-form/footer-form.component.scss +++ b/src/app/form/footer-form/footer-form.component.scss @@ -1,18 +1,35 @@ @import '../../../assets/scss/color'; @import '../../../assets/scss/typography'; +@import '../../../assets/scss/breakpoint'; .btn-primary { &.previous { - background-color: initial; + background-color: $white; color: $grey-2; + border: solid $grey-4 1px; } + &.invalid { + opacity: 0.4; + } + + &:focus .print { + background-color: $secondary-color; + } + &.next { .rowBtn { margin-left: 24px; } } - &.invalid { - opacity: 0.4; +} + +.column { + @media #{$phone} { + flex-direction: column !important; + button { + margin-bottom: 10px !important; + margin-right: 0 !important; + } } } @@ -25,6 +42,22 @@ .chevronRight { height: 24px; width: 24px; - stroke: inherit; margin-left: 10px; } + +.print { + stroke: $white; + width: 20px; + height: 20px; + padding-right: 20px; + background-color: $white; + mask: url(/assets/ico/print.svg) no-repeat center; +} +.flag { + padding-right: 10px; + stroke: $black; + width: 20px; + height: 20px; + background-color: $grey-1; + mask: url(/assets/ico/flag.svg) no-repeat center; +} diff --git a/src/app/form/footer-form/footer-form.component.ts b/src/app/form/footer-form/footer-form.component.ts index 15a5456ff32156d608f712a4c9cf4ae4a9cefd42..3a0fa92375dcdc6b1dcd5b752c6c2eb3e7b201bc 100644 --- a/src/app/form/footer-form/footer-form.component.ts +++ b/src/app/form/footer-form/footer-form.component.ts @@ -5,19 +5,26 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; templateUrl: './footer-form.component.html', styleUrls: ['./footer-form.component.scss'], }) -export class FooterFormComponent implements OnInit { +export class FooterFormComponent { @Input() isValid: boolean; @Input() btnName: string[]; + @Input() displayPreviousButton: boolean = true; @Output() nextPage = new EventEmitter<any>(); @Output() previousPage = new EventEmitter<any>(); - constructor() {} - - ngOnInit(): void {} + @Output() endPage = new EventEmitter<any>(); public goToNextPage(): void { this.nextPage.emit(); } + public goToPreviousPage(): void { this.previousPage.emit(); } + + public hasFinishButton(): boolean { + return this.btnName.length == 3; + } + public finishedModal(): void { + this.endPage.emit(); + } } diff --git a/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.html b/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.html new file mode 100644 index 0000000000000000000000000000000000000000..0e8de2f855b37255e61665e2cd8d8138bf214c3a --- /dev/null +++ b/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.html @@ -0,0 +1,30 @@ +<div *ngIf="openned" class="modalBackground"> + <div class="modal"> + <div + (clickOutside)="closeModal(false)" + class="contentModal" + fxLayout="row-reverse" + fxLayoutAlign="space-around start" + > + <div class="ico-close"> + <div class="ico-close-wrapper"> + <div (click)="closeModal()" class="ico-close-details"></div> + </div> + </div> + + <div class="modalContent"> + <h3 fxLayoutAlign="center center">Souhaitez-vous terminer cette orientation ?</h3> + + <div class="footerModal" fxLayout="row" fxLayoutAlign="space-around center"> + <button type="button" class="btn confirm" (click)="goToPreviousPage()">Revenir aux résultats</button> + <button class="btn-primary small previous" routerLink="../home"> + <div class="rowBtn" fxLayout="row" fxLayoutAlign="center center"> + <img class="flag" src="/assets/ico/flag.svg" alt /> + Terminer + </div> + </button> + </div> + </div> + </div> + </div> +</div> diff --git a/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.scss b/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..2fd7659609b185b92662b82f47dd90bd0b0bbe02 --- /dev/null +++ b/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.scss @@ -0,0 +1,27 @@ +@import '../../../../../assets/scss/typography'; +@import '../../../../../assets/scss/color'; + +.ico-close-details { + margin-right: 16px; +} +h3 { + margin: 8% 15%; + text-align: center; + @include cn-regular-18; + color: $grey-2; +} +.modalContent { + margin: 0 32px; + width: 100%; +} +.footerModal { + margin: 25px; +} +.modalBackground .modal .footerModal .btn.confirm { + font-size: 14px; + font-weight: normal; +} +.flag { + padding-right: 10px; + stroke: $white; +} diff --git a/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.spec.ts b/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..4950443e763585bea53e1c6e726ff28237c62c17 --- /dev/null +++ b/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.spec.ts @@ -0,0 +1,26 @@ +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OrientationComponent } from './orientation-modal.component'; + +describe('OrientationModalComponent', () => { + let component: OrientationComponent; + let fixture: ComponentFixture<OrientationComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [OrientationComponent], + imports: [HttpClientTestingModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(OrientationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.ts b/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..dfc3f86ab6009526323f58e93686670090f7c237 --- /dev/null +++ b/src/app/form/orientation-form/component/orientation-modal/orientation-modal.component.ts @@ -0,0 +1,20 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'app-orientation-modal', + templateUrl: './orientation-modal.component.html', + styleUrls: ['./orientation-modal.component.scss'], +}) +export class OrientationComponent { + @Input() public openned: boolean; + @Output() closed = new EventEmitter(); + @Output() previousPage = new EventEmitter(); + + public closeModal(): void { + this.closed.emit(); + } + public goToPreviousPage(): void { + this.closeModal(); + this.previousPage.emit(); + } +} diff --git a/src/app/form/orientation-form/component/structure-detail-print/structure-detail-print.component.html b/src/app/form/orientation-form/component/structure-detail-print/structure-detail-print.component.html index b6e5929554c2048fb14fa11bdf3e15825df6f743..eb6736c0ea987b2c9256626c44e4dd2c79704ea0 100644 --- a/src/app/form/orientation-form/component/structure-detail-print/structure-detail-print.component.html +++ b/src/app/form/orientation-form/component/structure-detail-print/structure-detail-print.component.html @@ -3,76 +3,18 @@ <div fxLayout="row" class="structure-details-block" fxLayoutAlign="baseline baseline" fxLayoutGap="8px"> <div fxLayout="column" fxLayoutGap="10px" fxFlex="100%"> <div fxLayout="column" class="no-margin" fxLayoutAlign="space-between start"> - <h2 class="bold">{{ structure.structureName }}</h2> - </div> - <div fxLayout="row" fxLayoutAlign="space-between center"> - <div class="typeInformationHeader" fxLayout="column"> - <h3>{{ structure.getLabelTypeStructure() }}</h3> - </div> + <h3 class="bold">{{ structure.structureName }}</h3> </div> <div class="mobile-column"> - <div fxLayout="column" fxFlex="50%"> + <div fxLayout="column" fxFlex="100%"> <div *ngIf="structure.address" fxLayout="row" fxLayoutAlign="none flex-end" fxLayoutGap="13px"> <app-svg-icon [type]="'ico'" [icon]="'adress'" [title]="'Adresse'"></app-svg-icon> <p>{{ structure.address.numero }} {{ structure.address.street }}, {{ structure.address.commune }}</p> </div> - <div *ngIf="structure.website" fxLayout="row" fxLayoutAlign="none flex-end" fxLayoutGap="13px"> - <app-svg-icon [type]="'ico'" [icon]="'web'" [title]="'Site web'"></app-svg-icon> - <a - target="_blank" - class="custom-link" - rel="noopener noreferrer" - [href]="structure.website.includes('http') ? structure.website : 'http://' + structure.website" - >{{ structure.website | url }}</a - > - </div> - <div *ngIf="structure.hasSocialNetwork()" fxLayout="row" fxLayoutAlign="none baseline" fxLayoutGap="13px"> - <app-svg-icon [type]="'ico'" [icon]="'network'"></app-svg-icon> - <div fxLayout="row" fxLayoutAlign="none baseline" fxLayoutGap="8px"> - <a - *ngIf="structure.facebook" - target="_blank" - class="custom-link" - rel="noopener noreferrer" - [href]="'http://' + structure.facebook" - > - <app-svg-icon [type]="'ico'" [icon]="'facebook'" [title]="'Facebook'"></app-svg-icon - ></a> - <a - *ngIf="structure.twitter" - target="_blank" - class="custom-link" - rel="noopener noreferrer" - [href]="'http://' + structure.twitter" - > - <app-svg-icon [type]="'ico'" [icon]="'twitter'" [title]="'Twitter'"></app-svg-icon - ></a> - <a - *ngIf="structure.instagram" - target="_blank" - class="custom-link" - rel="noopener noreferrer" - [href]="'http://' + structure.instagram" - > - <app-svg-icon [type]="'ico'" [icon]="'instagram'" [title]="'Instagram'"></app-svg-icon - ></a> - <a - *ngIf="structure.linkedin" - target="_blank" - class="custom-link" - rel="noopener noreferrer" - [href]="'http://' + structure.linkedin" - > - <app-svg-icon [type]="'ico'" [icon]="'linkedin'" [title]="'Linkedin'"></app-svg-icon - ></a> - </div> - </div> <div *ngIf="structure.contactPhone" fxLayout="row" fxLayoutAlign="none flex-end" fxLayoutGap="13px"> <app-svg-icon [type]="'ico'" [icon]="'tel'" [title]="'Téléphone'"></app-svg-icon> <p>{{ structure.contactPhone | phone }}</p> </div> - </div> - <div fxLayout="column" fxFlex="50%"> <div *ngIf="structure.contactMail && structure.contactMail !== 'unknown@unknown.com'" fxLayout="row" @@ -82,23 +24,8 @@ <app-svg-icon [type]="'ico'" [iconClass]="'grey-1'" [icon]="'email'" [title]="'Email'"></app-svg-icon> <p>{{ structure.contactMail }}</p> </div> - <div *ngIf="structure.hasPassNumeric()" fxLayout="row" fxLayoutAlign="none center" fxLayoutGap="13px"> - <app-svg-icon [type]="'ico'" [icon]="'pass'" [title]="'Pass numérique'"></app-svg-icon> - <p>agréé Pass Numérique</p> - </div> - <div fxLayout="row" fxLayoutAlign="none flex-end" fxLayoutGap="13px"> - <app-svg-icon [type]="'ico'" [icon]="'calendar'"></app-svg-icon> - <p>Mise à jour le {{ structure.updatedAt | date: 'mediumDate' }}</p> - </div> </div> </div> - - <div> - {{ structure.description }} - </div> - <div class="info"> - {{ structure.lockdownActivity }} - </div> </div> </div> <!-- Accueil --> @@ -119,7 +46,9 @@ <h4>{{ day.key | day }}</h4> <div class="opening-time" fxLayout="row" fxLayoutAlign="none flex-end"> <div *ngFor="let timeRange of day.value.time; let isFirst = first"> - <p *ngIf="isFirst && timeRange.opening">de {{ timeRange.formatOpeningDate() }} à {{ timeRange.formatClosingDate() }}</p> + <p *ngIf="isFirst && timeRange.opening"> + de {{ timeRange.formatOpeningDate() }} à {{ timeRange.formatClosingDate() }} + </p> <p *ngIf="!isFirst && timeRange.opening"> et de {{ timeRange.formatOpeningDate() }} à {{ timeRange.formatClosingDate() }} </p> diff --git a/src/app/form/orientation-form/component/structure-detail-print/structure-detail-print.component.scss b/src/app/form/orientation-form/component/structure-detail-print/structure-detail-print.component.scss index 8e3d713f56d01ddf9364710bc9634e373594c4ca..8a463c255bf77b578ac9c5d1dc165d1e8fa85dd8 100644 --- a/src/app/form/orientation-form/component/structure-detail-print/structure-detail-print.component.scss +++ b/src/app/form/orientation-form/component/structure-detail-print/structure-detail-print.component.scss @@ -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; diff --git a/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.html b/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.html index 1c55aece536b001ef45e3800ac5959cbefbda2e9..0a11c4df1ed0cee744165f6a2332d6128793368f 100644 --- a/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.html +++ b/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.html @@ -1,12 +1,15 @@ -<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> diff --git a/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.scss b/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.scss index 768bc8ad13e45d4a93af2e169e6cfd8f1cb26a79..50e6aa8ff93645af826eece98ba904d790b33616 100644 --- a/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.scss +++ b/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.scss @@ -1,3 +1,6 @@ +@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; + } } diff --git a/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.ts b/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.ts index 540db118a50b17302bb3bd4981e59e893726d56d..dc15a3df0d69e9e8c23574b7efe04899def8f0d5 100644 --- a/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.ts +++ b/src/app/form/orientation-form/component/structure-list-print/structure-list-print.component.ts @@ -1,16 +1,13 @@ 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> {} } diff --git a/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.html b/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.html index b1c83faf20514cedd941fe0526457082fe65eedc..7c09be92799f365e0fd65b12ceaa7647836d95f0 100644 --- a/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.html +++ b/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.html @@ -1,67 +1,77 @@ <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> diff --git a/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.scss b/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.scss index 0c9a98b49fafadf2d5a3437ce62e37d26ff2786e..d825109880b684f035d5d959629cb810246c58ff 100644 --- a/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.scss +++ b/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.scss @@ -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; + } +} diff --git a/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.ts b/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.ts index 20c827dec9dac2a4ce7f091ed254cea05685aac9..ee7b51cf1d9c8a0327cac110d73303a0fdadef44 100644 --- a/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.ts +++ b/src/app/form/orientation-form/component/structure-print-header/structure-print-header.component.ts @@ -1,9 +1,7 @@ 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; diff --git a/src/app/form/orientation-form/orientation-form.component.html b/src/app/form/orientation-form/orientation-form.component.html index 02e379de356b8ee287989f4d09fe319b15ed7719..3174a45f00bed4ff424ec5da32265f60c05d7c32 100644 --- a/src/app/form/orientation-form/orientation-form.component.html +++ b/src/app/form/orientation-form/orientation-form.component.html @@ -1,10 +1,10 @@ -<div *ngIf="!multiPrint" class="form" fxLayout="column"> +<div id="body" *ngIf="!multiPrint" class="form" fxLayout="column"> <app-modal-confirmation [openned]="showConfirmationModal" [content]="'Il vous faudra de nouveau remplir le formulaire si vous quittez'" (closed)="hasRedirectionAccepted($event)" ></app-modal-confirmation> - <div class="content"> + <div class="progress-container"> <div class="progressBar" fxLayout="row" fxLayoutAlign="space-between center" fxLayoutGap="20px"> <label [ngClass]="{ validate: currentPage == nbPagesForm }" for="progressForm" >{{ progressStatus | number: '1.0-0' }}% @@ -16,6 +16,8 @@ [value]="progressStatus" ></progress> </div> + </div> + <div class="content" *ngIf="currentPage != pageTypeEnum.structuresSelection"> <!-- BESOIN BENEFICIAIRE --> <div *ngIf="currentPage == pageTypeEnum.beneficiaryNeed" class="page"> <div class="titleInfo"> @@ -23,7 +25,7 @@ Merci de remplir ces quelques questions qui vous permettront d'identifier le lieu à proximité le plus adapté. </div> <div class="title"> - <h3>De quoi le bénéficiaire a-t-il besoin ?</h3> + <h3>Quels sont les besoins du bénéficiaire ?</h3> </div> <div class="collapse" [ngClass]="{ notCollapsed: !showEquipments }"> <div fxLayout="column"> @@ -119,73 +121,8 @@ </div> </div> <div *ngIf="showFormation" class="tags"> - <p class="titleCateg">{{ baseSkillssReferentiel.name }}</p> - <button - *ngFor="let choice of baseSkillssReferentiel.modules" - (click)="updateChoice(choice.id, 'formation')" - [ngClass]="{ selectedChoice: isInArray(choice.id, 'formation') }" - > - <div fxLayout="row" fxLayoutAlign=" center"> - <svg class="validate" aria-hidden="true"> - <use [attr.xlink:href]="'assets/form/sprite.svg#checkVector'"></use> - </svg> - <div class="textBtn"> - {{ choice.text }} - </div> - </div> - </button> - - <p class="titleCateg">{{ accessRightsReferentiel.name }}</p> - <button - *ngFor="let choice of accessRightsReferentiel.modules" - (click)="updateChoice(choice.id, 'formation')" - [ngClass]="{ selectedChoice: isInArray(choice.id, 'formation') }" - > - <div fxLayout="row" fxLayoutAlign=" center"> - <svg class="validate" aria-hidden="true"> - <use [attr.xlink:href]="'assets/form/sprite.svg#checkVector'"></use> - </svg> - <div class="textBtn"> - {{ choice.text }} - </div> - </div> - </button> - - <p class="titleCateg">{{ digitalCultureSecuritysReferentiel.name }}</p> - <button - *ngFor="let choice of digitalCultureSecuritysReferentiel.modules" - (click)="updateChoice(choice.id, 'formation')" - [ngClass]="{ selectedChoice: isInArray(choice.id, 'formation') }" - > - <div fxLayout="row" fxLayoutAlign=" center"> - <svg class="validate" aria-hidden="true"> - <use [attr.xlink:href]="'assets/form/sprite.svg#checkVector'"></use> - </svg> - <div class="textBtn"> - {{ choice.text }} - </div> - </div> - </button> - - <p class="titleCateg">{{ parentingHelpsReferentiel.name }}</p> - <button - *ngFor="let choice of parentingHelpsReferentiel.modules" - (click)="updateChoice(choice.id, 'formation')" - [ngClass]="{ selectedChoice: isInArray(choice.id, 'formation') }" - > - <div fxLayout="row" fxLayoutAlign=" center"> - <svg class="validate" aria-hidden="true"> - <use [attr.xlink:href]="'assets/form/sprite.svg#checkVector'"></use> - </svg> - <div class="textBtn"> - {{ choice.text }} - </div> - </div> - </button> - - <p class="titleCateg">{{ socialAndProfessionalsReferentiel.name }}</p> <button - *ngFor="let choice of socialAndProfessionalsReferentiel.modules" + *ngFor="let choice of selectedFormations" (click)="updateChoice(choice.id, 'formation')" [ngClass]="{ selectedChoice: isInArray(choice.id, 'formation') }" > @@ -193,139 +130,62 @@ <svg class="validate" aria-hidden="true"> <use [attr.xlink:href]="'assets/form/sprite.svg#checkVector'"></use> </svg> - <div class="textBtn"> - {{ choice.text }} - </div> + <div class="textBtn">{{ choice.name }} ({{ choice.surname }}...)</div> </div> </button> </div> </div> </div> </div> - <!-- NUMERIC PASS --> - <div *ngIf="currentPage == pageTypeEnum.beneficiaryPassNumeric" class="page"> - <div class="title"> - <h3>Le bénéficiaire possède-t-il un Pass numérique ?</h3> - </div> - <app-radio-form - [selectedOption]="getOrientationControl('passNumeric').value" - [horizontal]="true" - (selectedEvent)="onRadioBtnChange('passNumeric', $event)" - > - </app-radio-form> - </div> <!-- PROFIL BENEFICIAIRE --> <div *ngIf="currentPage == pageTypeEnum.beneficiaryInfo" class="page"> <div class="title"> - <h3>Autour de quelle adresse chercher une structure ?</h3> + <h3>Quel est le profil du bénéficiaire ?</h3> </div> - <div class="form-group" fxLayout="column"> - <label for="address">Adresse</label> - + <div class="section"> + <label>Nom</label> <div class="inputRow" fxLayout="row" fxLayoutGap="13px"> - <app-address-autocomplete - [address]="getOrientationControl('address').valid ? getOrientationControl('address').value : null" - (inputAddress)="setAddressBeneficiary()" - (selectedAddress)="setAddressBeneficiary($event)" - ></app-address-autocomplete> - <app-svg-icon - *ngIf="getOrientationControl('address').valid && !isLoading" - [iconClass]="'validation'" - [type]="'form'" - [icon]="'validate'" - class="validateIcon" - ></app-svg-icon> - <div *ngIf="!getOrientationControl('address').valid && !isLoading" (click)="getAddress()"> - <app-svg-icon [type]="'ico'" [icon]="'locateMe'" class="markerIcon"></app-svg-icon> - </div> - <div *ngIf="isLoading"> - <img class="loader-gif" src="/assets/gif/loader_circle.gif" alt /> - </div> + <input + type="text" + [value]="getOrientationControl('beneficiaryName').value" + (input)="setBeneficiaryName($event.target.value)" + class="form-input" + /> </div> </div> - <div class="title"> - <h3>Le bénéficiaire a-t-il un profil spécifique ?</h3> - <p class="notRequired">facultatif</p> + <div class="section"> + <label>Possède-t-il un Pass numérique ?</label> + <app-radio-form [horizontal]="true" (selectedEvent)="onRadioBtnChange('passNumeric', $event)"> </app-radio-form> </div> - - <div class="tags"> - <button - *ngFor="let choice of specificProfile.modules" - (click)="updateChoice(choice.id, 'specificProfile')" - [ngClass]="{ selectedChoice: isInArray(choice.id, 'specificProfile') }" - > - <div fxLayout="row" fxLayoutAlign=" center"> - <svg class="validate" aria-hidden="true"> - <use [attr.xlink:href]="'assets/form/sprite.svg#checkVector'"></use> - </svg> - <div class="textBtn"> - {{ choice.text }} + <div class="section"> + <label>A-t-il un profil spécifique ?</label> + <div class="tags"> + <button + (click)="updateChoice(null, 'specificProfile')" + [ngClass]="{ selectedChoice: isEmpty('specificProfile') }" + > + <div fxLayout="row" fxLayoutAlign=" center"> + <svg class="validate" aria-hidden="true"> + <use [attr.xlink:href]="'assets/form/sprite.svg#checkVector'"></use> + </svg> + <div class="textBtn">Aucun</div> </div> - </div> - </button> - </div> - </div> - <!-- STRUCTURE SEARCH --> - <div *ngIf="currentPage == pageTypeEnum.structuresSelection" class="page"> - Filtres séléctionnés - <div fxLayout="row wrap" fxLayoutGap="16px"> - <div *ngFor="let filter of filters" class="tags-cloud" fxLayout="row" (click)="removeFilter(filter)"> - {{ filter.text ? filter.text : filter.value }} - <app-svg-icon [type]="'ico'" [icon]="'delete'" [iconColor]="'white'"></app-svg-icon> - </div> - <div - *ngFor="let uncheckedFilter of uncheckedFilters" - class="tags-cloud unchecked" - fxLayout="row" - (click)="restoreFilter(uncheckedFilter)" - > - {{ uncheckedFilter.text ? uncheckedFilter.text : uncheckedFilter.value }} - <app-svg-icon [type]="'ico'" [icon]="'validate'" [iconColor]="'white'"></app-svg-icon> - </div> - </div> - <div fxLayout="row" class="content-container"> - <div class="nbStructure-panel left-pane" [ngClass]="{ mapPhone: isMapPhone == true }"> - <div class="nbStructuresLabel" [ngPlural]="structuresList.length"> - <ng-template ngPluralCase="0">0 structure trouvée</ng-template> - <ng-template ngPluralCase="1">1 structure trouvée</ng-template> - <ng-template ngPluralCase="other">{{ structuresList.length }} structures trouvées</ng-template> - </div> - <div id="listCard" (mouseleave)="mouseLeave()"> - <app-card - *ngFor="let structure of structuresList" - [structure]="structure" - [isOrientation]="true" - [isSelected]="isInPrintList(structure._id)" - (addToList)="addToList($event, structure)" - (hover)="handleCardHover($event)" - (showDetails)="showDetails($event)" - ></app-card> - <p *ngIf="structureList && structureList.length <= 0"> - Il n'y a aucune réponse correspondant à votre recherche - </p> - </div> - </div> - <div class="btnSwitch"> - <app-button - [style]="'roundedButton'" - [text]="isMapPhone ? 'Liste' : 'Carte'" - [iconBtn]="isMapPhone ? 'liste' : 'map-marker'" - (action)="switchMapList()" - ></app-button> + </button> + <button + *ngFor="let choice of specificProfile.modules" + (click)="updateChoice(choice.id, 'specificProfile')" + [ngClass]="{ selectedChoice: isInArray(choice.id, 'specificProfile') }" + > + <div fxLayout="row" fxLayoutAlign=" center"> + <svg class="validate" aria-hidden="true"> + <use [attr.xlink:href]="'assets/form/sprite.svg#checkVector'"></use> + </svg> + <div class="textBtn"> + {{ choice.text }} + </div> + </div> + </button> </div> - <app-map - [structures]="structuresList" - [structuresToPrint]="structuresToPrint" - [toogleToolTipId]="displayMapMarkerId" - [selectedMarkerId]="selectedMarkerId" - [locate]="locate" - (locatationTrigger)="locatationTrigger($event)" - (selectedStructure)="showDetails($event)" - [isMapPhone]="isMapPhone" - [searchedValue]="searchedValue" - class="right-pane deep-map" - [ngClass]="{ mapPhone: isMapPhone == true }" - ></app-map> </div> </div> <!-- BENEFICIARY ACCOMPANIMENT --> @@ -333,59 +193,95 @@ <div class="title"> <h3>Qui oriente le bénéficiaire ?</h3> </div> - <label>Votre structure (MDM, Caf, Pôle Emploi...)</label> - <div class="inputRow" fxLayout="row" fxLayoutGap="13px"> - <input - type="text" - [value]="getOrientationControl('structureAccompaniment').value" - (input)="setStructureAccompaniment($event.target.value)" - class="form-input" - /> + <div class="section"> + <label>De quelle structure êtes-vous ? (MDM, Caf, Pôle Emploi...)</label> + <div class="inputRow" fxLayout="row" fxLayoutGap="13px"> + <input + type="text" + [value]="getOrientationControl('structureAccompaniment').value" + (input)="setStructureAccompaniment($event.target.value)" + class="form-input" + /> + </div> </div> - - <div class="title"> - <h3>Comment contacter cette structure ?</h3> + <div class="section"> + <label>Courriel de votre structure</label> <p class="notRequired">facultatif</p> + <div class="inputRow" fxLayout="row" fxLayoutGap="13px"> + <input + type="text" + [value]="getOrientationControl('contactAccompanimentEmail').value" + placeholder="exemple: prenom.nom@grandlyon.com" + (input)="setContactAccompanimentEmail($event.target.value)" + class="form-input" + /> + <app-svg-icon + *ngIf=" + getOrientationControl('contactAccompanimentEmail').valid && + getOrientationControl('contactAccompanimentEmail').value + " + [iconClass]="'validation'" + [type]="'form'" + [icon]="'validate'" + ></app-svg-icon> + <app-svg-icon + *ngIf=" + getOrientationControl('contactAccompanimentEmail').invalid && + getOrientationControl('contactAccompanimentEmail').value + " + [iconClass]="'validation'" + [type]="'form'" + [icon]="'notValidate'" + ></app-svg-icon> + </div> </div> - <label>Contact (email ou n° de téléphone)</label> - <div class="inputRow" fxLayout="row" fxLayoutGap="13px"> - <input - type="text" - [value]="getOrientationControl('contactAccompaniment').value" - (input)="setContactAccompaniment($event.target.value)" - class="form-input" - /> - </div> - - <div class="title"> - <h3>Qui est le bénéficiaire ?</h3> + <div class="section"> + <label>Téléphone de votre structure</label> <p class="notRequired">facultatif</p> - </div> - <label>Nom du bénéficiaire</label> - <div class="inputRow" fxLayout="row" fxLayoutGap="13px"> - <input - type="text" - [value]="getOrientationControl('beneficiaryName').value" - (input)="setBeneficiaryName($event.target.value)" - class="form-input" - /> + <div class="inputRow" fxLayout="row" fxLayoutGap="13px"> + <input + type="text" + [value]="getOrientationControl('contactAccompanimentPhone').value" + (input)="setContactAccompanimentPhone($event.target.value)" + class="form-input" + /> + <app-svg-icon + *ngIf=" + getOrientationControl('contactAccompanimentPhone').value && + getOrientationControl('contactAccompanimentPhone').valid + " + [iconClass]="'validation'" + [type]="'form'" + [icon]="'validate'" + ></app-svg-icon> + <app-svg-icon + *ngIf=" + getOrientationControl('contactAccompanimentPhone').invalid && + getOrientationControl('contactAccompanimentPhone').value + " + [iconClass]="'validation'" + [type]="'form'" + [icon]="'notValidate'" + ></app-svg-icon> + </div> </div> </div> <!-- BENEFICIARY NEEDS COMMENTARY --> <div *ngIf="currentPage == pageTypeEnum.beneficiaryNeedCommentary" class="page"> <div class="title"> - <h3>Précisez le besoin</h3> - <p class="notRequired">facultatif</p> + <h3>Avez-vous des précisions à apporter ?</h3> + <p class="notRequired lg">facultatif</p> </div> - <label>Ces informations sont à destination de la structure</label> + <label>Ces informations accompagneront la fiche d'orientation du bénéficiaire</label> <div class="textareaBlock" fxLayout="column"> <textarea rows="8" maxlength="500" + placeholder="Exemple: le bénéficiaire n'a pas d'adresse e-mail" [value]="getOrientationControl('beneficiaryNeedCommentary').value" (input)="setBeneficiaryNeedCommentary($event.target.value)" ></textarea> - <p> + <p class="textarea-char"> {{ getOrientationControl('beneficiaryNeedCommentary').value ? getOrientationControl('beneficiaryNeedCommentary').value.length @@ -394,73 +290,147 @@ </p> </div> </div> + <!-- ADDRESS SEARCH --> + <div *ngIf="currentPage == pageTypeEnum.beneficiaryAddress" class="page"> + <div class="title"> + <h3>Autour de quelle adresse chercher une structure ?</h3> + <p class="notRequired lg">facultatif</p> + </div> + <div class="form-group" fxLayout="column"> + <div class="inputRow" fxLayout="row" fxLayoutGap="13px"> + <app-address-autocomplete + [address]="getOrientationControl('address').valid ? getOrientationControl('address').value : null" + (inputAddress)="setAddressBeneficiary()" + (selectedAddress)="setAddressBeneficiary($event)" + ></app-address-autocomplete> + <app-svg-icon + *ngIf="getOrientationControl('address').valid && !isLoading" + [iconClass]="'validation'" + [type]="'form'" + [icon]="'validate'" + class="validateIcon" + ></app-svg-icon> + </div> + </div> + </div> <!-- PRINT RESULTS --> - <div *ngIf="currentPage == pageTypeEnum.printResults" class="page"> + <div *ngIf="currentPage == pageTypeEnum.printResults" class="last-page"> <div class="title"> <app-structure-print-header - [beneficiaryNeedCommentary]="getOrientationControl('beneficiaryNeedCommentary').value" - [beneficiaryName]="getOrientationControl('beneficiaryName').value" - [structureAccompaniment]="getOrientationControl('structureAccompaniment').value" - [beneficiaryPassNumeric]="getOrientationControl('passNumeric').value" - [contactAccompaniment]="getOrientationControl('contactAccompaniment').value" + [beneficiaryNeedCommentary]=" + getOrientationControl('beneficiaryNeedCommentary') + ? getOrientationControl('beneficiaryNeedCommentary').value + : '' + " + [beneficiaryName]="getOrientationControl('beneficiaryName')?.value" + [structureAccompaniment]="getOrientationControl('structureAccompaniment')?.value" + [beneficiaryPassNumeric]="getOrientationControl('passNumeric')?.value" + [contactAccompaniment]="getOrientationControl('contactAccompanimentEmail')?.value" + [contactAccompanimentPhone]="getOrientationControl('contactAccompanimentPhone')?.value" [filters]="filters" ></app-structure-print-header> <app-structure-detail-print *ngFor="let structure of structuresToPrint" [structure]="structure" + class="print-structure-container" ></app-structure-detail-print> </div> </div> </div> - <!-- FOOTER AVEC SUIVANT / PRECEDENT ET VALIDATION --> - <div *ngIf="currentPage == 0" class="footer desktop" fxLayout="column" fxLayoutAlign="space-between"> - <div fxLayout="row" fxLayoutAlign="center center"> - <app-footer-form - [btnName]="['Précédent', 'Suivant']" - (previousPage)="previousUrl()" - (nextPage)="nextPage()" - [isValid]="isPageValid" - ></app-footer-form> + <!-- STRUCTURE SEARCH --> + <div *ngIf="currentPage == pageTypeEnum.structuresSelection" class="carto"> + <div class="left-col" [ngClass]="{ mapPhone: isMapPhone == true }"> + <div class="filters"> + <span class="filters-title">Filtre(s) séléctionné(s)</span> + <div fxLayout="row wrap" fxLayoutGap="4px"> + <div + class="tags-cloud" + *ngFor="let filter of filters" + [class.unchecked]="!filter.checked" + fxLayout="row" + (click)="checkFilter(filter)" + > + <app-svg-icon + *ngIf="filter.checked" + [type]="'ico'" + [icon]="'validate'" + [iconColor]="'white'" + ></app-svg-icon> + <app-svg-icon *ngIf="!filter.checked" [type]="'ico'" [icon]="'delete'" [iconColor]="'white'"></app-svg-icon> + <div>{{ filter.text ? filter.text : filter.value }}</div> + </div> + </div> + </div> + <div class="nbStructuresLabel" [ngPlural]="structuresList.length"> + <ng-template ngPluralCase="0">0 structure</ng-template> + <ng-template ngPluralCase="1">1 structure</ng-template> + <ng-template ngPluralCase="other">{{ structuresList.length }} structures</ng-template> + </div> + <div fxLayout="row" class="content-container"> + <div class="nbStructure-panel left-pane"> + <div id="listCard" (mouseleave)="mouseLeave()"> + <app-card + *ngFor="let structure of structuresList" + [structure]="structure" + [isOrientation]="true" + [isSelected]="isInPrintList(structure._id)" + (addToList)="addToList($event, structure)" + (hover)="handleCardHover($event)" + (showDetails)="showDetails($event)" + class="structure-card" + ></app-card> + <p *ngIf="structureList && structureList.length <= 0"> + Il n'y a aucune réponse correspondant à votre recherche + </p> + </div> + </div> + </div> </div> - </div> - <div *ngIf="currentPage != 0 && currentPage != pageTypeEnum.printResults" class="footer desktop"> - <div fxLayout="row" fxLayoutAlign="center center"> - <app-footer-form - [btnName]="['Précédent', 'Suivant']" - (previousPage)="previousPage()" - (nextPage)="nextPage()" - [isValid]="isPageValid" - ></app-footer-form> + <div class="btnSwitch"> + <app-button + [style]="'roundedButton'" + [text]="isMapPhone ? 'Liste' : 'Carte'" + [iconBtn]="isMapPhone ? 'liste' : 'map-marker'" + (action)="switchMapList()" + ></app-button> </div> - </div> - <div *ngIf="currentPage == pageTypeEnum.printResults" class="footer desktop"> - <div fxLayout="row" fxLayoutAlign="center center"> - <app-footer-form - [btnName]="['Précédent', 'Imprimer']" - (previousPage)="previousPage()" - (nextPage)="runMultiPrint(true)" - [isValid]="isPageValid" - ></app-footer-form> + <div class="right-col" [ngClass]="{ mapPhone: isMapPhone == true }"> + <app-map + [isOrientationForm]="true" + [structures]="structuresList" + [structuresToPrint]="structuresToPrint" + [toogleToolTipId]="displayMapMarkerId" + [selectedMarkerId]="selectedMarkerId" + [locate]="locate" + (selectedStructure)="showDetails($event)" + [isMapPhone]="isMapPhone" + [searchedValue]="userLocation" + (onOrientationButtonClick)="addToList($event, structure)" + class="right-pane deep-map" + [ngClass]="{ mapPhone: isMapPhone == true }" + ></app-map> </div> </div> - - <div *ngIf="currentPage != 0 && currentPage != pageTypeEnum.printResults" class="footer phone"> + <!-- FOOTER AVEC SUIVANT / PRECEDENT ET VALIDATION --> + <div *ngIf="currentPage != pageTypeEnum.printResults" class="form-footer"> <div fxLayout="row" fxLayoutAlign="center center"> <app-footer-form [btnName]="['Précédent', 'Suivant']" (previousPage)="previousPage()" + [displayPreviousButton]="currentPage !== pageTypeEnum.beneficiaryNeed" (nextPage)="nextPage()" [isValid]="isPageValid" ></app-footer-form> </div> </div> - <div *ngIf="currentPage == pageTypeEnum.printResults" class="footer phone"> + <div *ngIf="currentPage == pageTypeEnum.printResults" class="form-footer"> <div fxLayout="row" fxLayoutAlign="center center"> <app-footer-form - [btnName]="['Précédent', 'Imprimer']" + [btnName]="['Précédent', 'Imprimer', 'Terminer']" (previousPage)="previousPage()" (nextPage)="runMultiPrint(true)" + (endPage)="displayFinishModal()" [isValid]="isPageValid" ></app-footer-form> </div> @@ -474,7 +444,7 @@ [beneficiaryName]="getOrientationControl('beneficiaryName').value" [structureAccompaniment]="getOrientationControl('structureAccompaniment').value" [beneficiaryPassNumeric]="getOrientationControl('passNumeric').value" - [contactAccompaniment]="getOrientationControl('contactAccompaniment').value" + [contactAccompaniment]="getOrientationControl('contactAccompanimentPhone').value" [filters]="filters" ></app-structure-list-print> @@ -483,3 +453,10 @@ [structure]="selectedStructure" (closeDetails)="closeDetails()" ></app-structure-details> + +<app-orientation-modal + *ngIf="displayModal" + [openned]="true" + (closed)="closeFinishModal($event)" + (previousPage)="previousPage()" +></app-orientation-modal> diff --git a/src/app/form/orientation-form/orientation-form.component.scss b/src/app/form/orientation-form/orientation-form.component.scss index dbeffc59d2c335187f455df2261603f35235f3c9..c0d9b713d54af3fc20bab1f1f5edad14bbadaa5f 100644 --- a/src/app/form/orientation-form/orientation-form.component.scss +++ b/src/app/form/orientation-form/orientation-form.component.scss @@ -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; } } diff --git a/src/app/form/orientation-form/orientation-form.component.ts b/src/app/form/orientation-form/orientation-form.component.ts index a76082df793cdbf61c3d03a9ba1fe18943dd1521..31b2c36d0739011568ed088b17966434370f4175 100644 --- a/src/app/form/orientation-form/orientation-form.component.ts +++ b/src/app/form/orientation-form/orientation-form.component.ts @@ -1,6 +1,7 @@ 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; + } } diff --git a/src/app/form/orientation-form/pageType.enum.ts b/src/app/form/orientation-form/pageType.enum.ts index 1a0fc933a378f3b45f4c73b2037cfde20983c050..e7f68bb8e3d9a04acd053c992cbca8ea367ce55d 100644 --- a/src/app/form/orientation-form/pageType.enum.ts +++ b/src/app/form/orientation-form/pageType.enum.ts @@ -1,9 +1,9 @@ export enum PageTypeEnum { beneficiaryNeed, - beneficiaryPassNumeric, beneficiaryInfo, - structuresSelection, beneficiaryAccompaniment, beneficiaryNeedCommentary, + beneficiaryAddress, + structuresSelection, printResults, } diff --git a/src/app/form/structure-form/form.component.scss b/src/app/form/structure-form/form.component.scss index 79d9304e1114bb5358e5b5f0a359acc905a4f8b4..1fabc2e2c2515cffee34567922f311566e0615b6 100644 --- a/src/app/form/structure-form/form.component.scss +++ b/src/app/form/structure-form/form.component.scss @@ -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; } diff --git a/src/app/form/structure-form/form.component.ts b/src/app/form/structure-form/form.component.ts index c454231a2b91d92d21b946726565a9f0cdd0bb84..d0b4d04ad4ca17c273a65e371e2b448155d36986 100644 --- a/src/app/form/structure-form/form.component.ts +++ b/src/app/form/structure-form/form.component.ts @@ -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(); } } diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html index 51dd7c81d9695c5d7f2bc3509fe34efd52c77bac..87949d944f159266ce125637ab1e35abf099715a 100644 --- a/src/app/header/header.component.html +++ b/src/app/header/header.component.html @@ -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> diff --git a/src/app/legal-notice/legal-notice.component.ts b/src/app/legal-notice/legal-notice.component.ts index 8e018f4ab937e0c7fd0e17198d51cfb3a173e73b..e211a76427a9fcd1f687945c8ec20748fff745d0 100644 --- a/src/app/legal-notice/legal-notice.component.ts +++ b/src/app/legal-notice/legal-notice.component.ts @@ -1,15 +1,18 @@ 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", + }); } - } diff --git a/src/app/map/components/layers.enum.ts b/src/app/map/components/layers.enum.ts new file mode 100644 index 0000000000000000000000000000000000000000..3878af93cdc11e780d3563cdeb364bc63b407b51 --- /dev/null +++ b/src/app/map/components/layers.enum.ts @@ -0,0 +1,5 @@ +export enum Layers { + mdm = 'mdm', + user = 'user', + structure = 'structure', +} diff --git a/src/app/map/components/map.component.html b/src/app/map/components/map.component.html index 3af397dbb80481e93b5289f39a0bf16c72831435..1c4483bc5a04111c5301c0cc5f970ba502216cb3 100644 --- a/src/app/map/components/map.component.html +++ b/src/app/map/components/map.component.html @@ -1,3 +1,10 @@ <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> diff --git a/src/app/map/components/map.component.scss b/src/app/map/components/map.component.scss index 2da18137b39d352f0a3123a470c164de3791f37f..3fe53bca3ae14806fc29bd6fa6806e2dc3e4162d 100644 --- a/src/app/map/components/map.component.scss +++ b/src/app/map/components/map.component.scss @@ -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; +} diff --git a/src/app/map/components/map.component.ts b/src/app/map/components/map.component.ts index de19908091eb228988dcfe4f5861fe84c2010f51..35f1387f229a45b0b8ab7597f72b1f8b81f8e951 100644 --- a/src/app/map/components/map.component.ts +++ b/src/app/map/components/map.component.ts @@ -1,4 +1,4 @@ -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: '© <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], }; } diff --git a/src/app/map/components/markerType.enum.ts b/src/app/map/components/markerType.enum.ts index 9d6c395c7d5ad7d50a22fa3d664827da05c7c335..ade600852dfb0fc14221e0b73e6e8efc8638dbff 100644 --- a/src/app/map/components/markerType.enum.ts +++ b/src/app/map/components/markerType.enum.ts @@ -2,4 +2,5 @@ export enum MarkerType { structure = 0, mdm = 1, conseillerFrance = 2, + user = 3, } diff --git a/src/app/map/components/zoomLevel.enum.ts b/src/app/map/components/zoomLevel.enum.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe020b772f172ac8fc926271fe7d10bb4e035449 --- /dev/null +++ b/src/app/map/components/zoomLevel.enum.ts @@ -0,0 +1,6 @@ +export enum ZoomLevel { + min = 10, + regular = 12, + userPosition = 15, + max = 19, +} diff --git a/src/app/map/services/map.service.ts b/src/app/map/services/map.service.ts index 9db3a9ef475732fff3ca758b281f817cd95e8e65..c65d925857a3a09c795e8bb28e1868a160ab939a 100644 --- a/src/app/map/services/map.service.ts +++ b/src/app/map/services/map.service.ts @@ -1,17 +1,15 @@ import { Injectable } from '@angular/core'; import { DivIcon, divIcon, Map, Marker } from 'leaflet'; +import { Layers } from '../components/layers.enum'; import { MarkerType } from '../components/markerType.enum'; import { markerIcon, markerIconActive, markerIconAddedToList, - markerIconFranceService, - markerIconFranceServiceActive, - markerIconFranceServiceAddedToList, - markerIconFranceServiceHover, markerIconHover, markerIconMdm, markerIconMdmActive, + userLocationIcon, } from './marker'; @Injectable({ providedIn: 'root', @@ -35,9 +33,7 @@ export class MapService { }); if (tooltip) { - marker.bindPopup(tooltip, { - autoPan: false, - }); + marker.bindPopup(tooltip); // handle icon change when unselect marker.getPopup().on('remove', (evt) => { @@ -53,51 +49,63 @@ export class MapService { private getLayerAttributton(markerType: MarkerType): string { if (markerType === MarkerType.mdm) { - return 'mdm'; + return Layers.mdm; + } else if (markerType === MarkerType.user) { + return Layers.user; } else { - return 'structure'; + return Layers.structure; } } // Note: Marke IconFranceService has been removed temporarly on order to rework on buisness needs. // This comment is applied for the next 4 methods private getMarkerIcon(markerType: MarkerType): DivIcon { - if (markerType === MarkerType.mdm) { - return markerIconMdm; - } else if (markerType === MarkerType.conseillerFrance) { - // return markerIconFranceService; - return markerIcon; - } else { - return markerIcon; + switch (markerType) { + case MarkerType.mdm: + return markerIconMdm; + case MarkerType.conseillerFrance: + return markerIcon; + case MarkerType.user: + return userLocationIcon; + default: + return markerIcon; } } private getActiveMarkerIcon(markerType: MarkerType): DivIcon { - if (markerType === MarkerType.mdm) { - return markerIconMdmActive; - } else if (markerType === MarkerType.conseillerFrance) { - // return markerIconFranceServiceActive; - return markerIconActive; - } else { - return markerIconActive; + switch (markerType) { + case MarkerType.mdm: + return markerIconMdmActive; + case MarkerType.conseillerFrance: + // return markerIconFranceServiceActive; + return markerIconActive; + case MarkerType.user: + return userLocationIcon; + default: + return markerIconActive; } } private getAddedToListMarkerIcon(markerType: MarkerType): DivIcon { - if (markerType === MarkerType.conseillerFrance) { - // return markerIconFranceServiceAddedToList; - return markerIconAddedToList; - } else { - return markerIconAddedToList; + switch (markerType) { + case MarkerType.conseillerFrance: + // return markerIconFranceServiceAddedToList; + return markerIconAddedToList; + case MarkerType.user: + return userLocationIcon; + default: + return markerIconAddedToList; } } private getHoverMarkerIcon(markerType: MarkerType): DivIcon { - if (markerType === MarkerType.conseillerFrance) { - // return markerIconFranceServiceHover; - return markerIconHover; - } else { - return markerIconHover; + switch (markerType) { + case MarkerType.conseillerFrance: + return markerIconHover; + case MarkerType.user: + return userLocationIcon; + default: + return markerIconHover; } } @@ -163,7 +171,7 @@ export class MapService { MapService.markersList = {}; if (map) { map.eachLayer((layer) => { - if (layer instanceof Marker && layer.options.attribution !== 'mdm') { + if (layer instanceof Marker && layer.options.attribution == Layers.structure) { map.removeLayer(layer); } }); diff --git a/src/app/map/services/marker.ts b/src/app/map/services/marker.ts index b33008e4e0c0746c02e1e73b4964bf7baadcee2b..e458b0b9d096a0f09a87a62721f80c16d37c6228 100644 --- a/src/app/map/services/marker.ts +++ b/src/app/map/services/marker.ts @@ -8,14 +8,14 @@ export const markerIcon = divIcon({ popupAnchor: [0, -48], }); export const markerIconActive = divIcon({ - className: null, + className: 'on-top-marker', html: '<svg width="48" height="48"><use xlink:href="assets/ico/sprite.svg#map-markerSelected"></use></svg>', iconSize: [48, 48], iconAnchor: [24, 48], popupAnchor: [0, -48], }); export const markerIconHover = divIcon({ - className: null, + className: 'on-top-marker', html: '<svg width="48" height="48"><use xlink:href="assets/ico/sprite.svg#map-markerHover"></use></svg>', iconSize: [48, 48], iconAnchor: [24, 48], @@ -28,6 +28,12 @@ export const markerIconAddedToList = divIcon({ iconAnchor: [24, 48], popupAnchor: [0, -48], }); +export const userLocationIcon = divIcon({ + className: null, + html: '<svg width="34" height="34"><use xlink:href="assets/ico/sprite.svg#user-location"></use></svg>', + iconSize: [34, 34], + iconAnchor: [17, 0], +}); export const markerIconMdm = divIcon({ className: null, html: diff --git a/src/app/models/address.model.ts b/src/app/models/address.model.ts index d04d83abedde79b20dbf1d7ae484d34c5e4c4b57..0b30ddc1cfb70325d383260bd511831f61d8fcb8 100644 --- a/src/app/models/address.model.ts +++ b/src/app/models/address.model.ts @@ -2,4 +2,5 @@ export class Address { numero: string = null; street: string = null; commune: string = null; + coordinates? = []; } diff --git a/src/app/models/orientation-filter.object.ts b/src/app/models/orientation-filter.object.ts index 48a52e4acdcc4aab2dbff383d92d2c39ae3e880c..49fe9ca54662b52e32c1a6fe7afc51396d1e5a2c 100644 --- a/src/app/models/orientation-filter.object.ts +++ b/src/app/models/orientation-filter.object.ts @@ -7,7 +7,8 @@ export class OrientationFormFilters { handicap: boolean; passNumeric: boolean; structureAccompaniment: string; - contactAccompaniment: string; + contactAccompanimentPhone: string; + contactAccompanimentEmail: string; beneficiaryName: string; beneficiaryNeedCommentary: string; address: Address; diff --git a/src/app/newsletter-subscription/newsletter-subscription.component.scss b/src/app/newsletter-subscription/newsletter-subscription.component.scss index 4bf4d917c132c8e05d6f45442a96b8d198ac0eae..f3c913b2c5ab4829e1c3c171b741d211cfb5f2a7 100644 --- a/src/app/newsletter-subscription/newsletter-subscription.component.scss +++ b/src/app/newsletter-subscription/newsletter-subscription.component.scss @@ -10,7 +10,7 @@ } .form-input { - background-color: white; + background-color: $white; width: 100%; } diff --git a/src/app/page/models/page.model.ts b/src/app/page/models/page.model.ts index 3ee6825384dcb172c6573a09b1dc8390f17566a6..ce9655c604c35a8d257fa83793dd9179f544ff8c 100644 --- a/src/app/page/models/page.model.ts +++ b/src/app/page/models/page.model.ts @@ -10,6 +10,7 @@ export class Page { feature_image: string; html: string; safeHtml: SafeHtml; + meta_description: string; constructor(obj?: any) { Object.assign(this, obj); diff --git a/src/app/page/page.component.ts b/src/app/page/page.component.ts index 7f29dce2618c6fe4aa4596340148c3d66c1445d0..3915c15239f24e27a6e3d895ab053e4245e03db2 100644 --- a/src/app/page/page.component.ts +++ b/src/app/page/page.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { DomSanitizer } from '@angular/platform-browser'; +import { Meta } from '@angular/platform-browser'; import packageJson from '../../../package.json'; import { Page } from './models/page.model'; import { PageService } from './services/page.service'; @@ -17,7 +18,12 @@ export class PageComponent implements OnInit { private slugPage: string; private quiSommesNous = PageEnum.quiSommesNous; - constructor(private sanitizer: DomSanitizer, private route: ActivatedRoute, private pageService: PageService) {} + constructor( + private sanitizer: DomSanitizer, + private route: ActivatedRoute, + private pageService: PageService, + private meta: Meta + ) {} ngOnInit(): void { this.route.params.subscribe((routeParams) => { @@ -25,6 +31,10 @@ export class PageComponent implements OnInit { this.pageService.getPage(this.slugPage).subscribe((page) => { this.page = page.pages[0]; this.page.safeHtml = this.sanitizer.bypassSecurityTrustHtml(this.page.html); + this.meta.updateTag({ + name: 'description', + content: this.page.meta_description, + }); }); // Display version number in 'About' page only this.slugPage == this.quiSommesNous ? (this.version = packageJson.version) : (this.version = ''); diff --git a/src/app/post/components/post-card/post-card.component.html b/src/app/post/components/post-card/post-card.component.html index 22ebc401e4b4a26874a180af62597c9cf2c30f97..ab4f7654d1f3d3a5587714e31858730d75c14f81 100644 --- a/src/app/post/components/post-card/post-card.component.html +++ b/src/app/post/components/post-card/post-card.component.html @@ -17,20 +17,14 @@ /> </div> <div fxLayout="column" fxLayoutGap="8px" fxLayoutAlign="center"> - <div fxLayout="row" class="tag" fxLayoutAlign=" center" fxLayoutGap="12px" *ngIf="post.tags[0]"> - <span>{{ post.tags[0].name }}</span> - </div> - <div fxLayout="row" class="tag" fxLayoutAlign=" center" fxLayoutGap="12px" *ngIf="!post.tags[0]"> - <span>info</span> - </div> - + <app-post-tag [post]="post"></app-post-tag> <div fxLayout="row" class="title"> {{ post.title }} </div> <div fxLayout="column" class="informations"> <div>{{ post.author }}</div> <div> - {{ post.updated_at | date: 'd MMM y' }} + {{ post.created_at | date: 'd MMM y' }} </div> </div> </div> diff --git a/src/app/post/components/post-card/post-card.component.scss b/src/app/post/components/post-card/post-card.component.scss index 68ff9e687b92e8a7bd271972ac59470a774c877b..7eb738f674dd2754aafa45c5dc3143585803365a 100644 --- a/src/app/post/components/post-card/post-card.component.scss +++ b/src/app/post/components/post-card/post-card.component.scss @@ -15,13 +15,7 @@ } } } - .tag { - @include cn-bold-16; - text-transform: uppercase; - color: $secondary-color; - fill: $secondary-color; - stroke: $secondary-color; - } + .title { @media #{$large-phone} { @include cn-bold-18; diff --git a/src/app/post/components/post-card/post-card.component.ts b/src/app/post/components/post-card/post-card.component.ts index 36ce0ea85b5ab0cb5e0bc0a370ba37806d55ca64..fb67224b27e6f11a05c3a64617cfd967dd25cca7 100644 --- a/src/app/post/components/post-card/post-card.component.ts +++ b/src/app/post/components/post-card/post-card.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input } from '@angular/core'; import { Router } from '@angular/router'; import { TagEnum } from '../../enum/tag.enum'; import { Post } from '../../models/post.model'; @@ -19,6 +19,6 @@ export class PostCardComponent { } public isAppelAProjet(): boolean { - return this.post.tags[0].slug === this.tagEnum.appels; + return this.post.tags[0] && this.post.tags[0].slug === this.tagEnum.appels; } } diff --git a/src/app/post/components/post-details/post-details.component.html b/src/app/post/components/post-details/post-details.component.html index 8877f2920cbe669594c18c3792f2f224f5765598..f46dad6223ab782740b6db783a67e0dd3dcfa621 100644 --- a/src/app/post/components/post-details/post-details.component.html +++ b/src/app/post/components/post-details/post-details.component.html @@ -9,26 +9,15 @@ </div> <div class="gh-canvas"> <div fxLayout="column" fxLayoutAlign="center none"> - <div *ngIf="post.tags[0]" fxLayout="row" class="tag" fxLayoutAlign=" center" fxLayoutGap="12px"> - <span>{{ post.tags[0].name }}</span> - </div> - <div *ngIf="!post.tags[0]" fxLayout="row" class="tag" fxLayoutAlign=" center" fxLayoutGap="12px"> - <span>Infos</span> - </div> - <div fxLayout="row" class="title"> - {{ post.title }} - </div> + <app-post-tag [post]="post"></app-post-tag> + <div fxLayout="row" class="title">{{ post.title }}</div> <div fxLayout="column" class="informations"> <div>{{ post.author }}</div> <div> - {{ post.updated_at | date: 'dd MMM y' }} + {{ post.created_at | date: 'dd MMM y' }} </div> </div> </div> - - <div fxLayout="row" class="article-image" *ngIf="post.feature_image"> - <img class="image" alt="image about the news" [src]="post.feature_image" /> - </div> <div fxLayout="row" class="description"> <div [innerHtml]="post.safeHtml"></div> </div> diff --git a/src/app/post/components/post-details/post-details.component.scss b/src/app/post/components/post-details/post-details.component.scss index 71b1f8516e7e14d8ffac34c0940d82d8b6b3701d..56d471bb1debe7412cdbe32c6d26500d046e0aca 100644 --- a/src/app/post/components/post-details/post-details.component.scss +++ b/src/app/post/components/post-details/post-details.component.scss @@ -14,13 +14,6 @@ } } -.tag { - @include cn-bold-16; - text-transform: uppercase; - color: $secondary-color; - fill: $secondary-color; - stroke: $secondary-color; -} .informations { @include cn-regular-16; div:nth-child(2n) { @@ -30,7 +23,6 @@ .description { ::ng-deep img { - width: 100%; height: 100%; } ::ng-deep figure { diff --git a/src/app/post/components/post-list/post-list.component.scss b/src/app/post/components/post-list/post-list.component.scss index 805a63eed491779b723932ff421cca726bc6cda3..6e13a58170bdc044eeee2bf5f6b922e0b2aef762 100644 --- a/src/app/post/components/post-list/post-list.component.scss +++ b/src/app/post/components/post-list/post-list.component.scss @@ -130,6 +130,7 @@ h2 { grid-template-columns: repeat(auto-fill, minmax(7%, 1fr)); grid-column-gap: 1%; grid-row-gap: 40px; + max-width: 1080px; .col:nth-child(6n + 1) { @include big-container; @media #{$news-max} { diff --git a/src/app/post/components/post-list/post-list.component.ts b/src/app/post/components/post-list/post-list.component.ts index e0e7f0e46066abf99f8aade78cd5ad8cf5553245..38cad37daf6d207eb936368d670172180e72a887 100644 --- a/src/app/post/components/post-list/post-list.component.ts +++ b/src/app/post/components/post-list/post-list.component.ts @@ -68,14 +68,20 @@ export class PostListComponent implements OnInit { }); } + /** + * Fill articles list with headline handling + * @param news {PostWithMeta} + */ public fillArticles(news: PostWithMeta): void { this.setNews(news); - const headLineTag = this.allPosts.filter((post: Post) => post.tags.some((tag) => tag.slug === TagEnum.aLaUne)); + const headLineTag = this.allPosts.filter((post: Post) => + post.tags.some((tag) => tag && tag.slug === TagEnum.aLaUne) + ); const headIndex = this.allPosts.findIndex((post) => post.id === headLineTag[0].id); this.allPosts.splice(headIndex, 1); - this.allPosts = [...headLineTag, ...this.allPosts]; + this.allPosts = [...headLineTag, ..._.difference(this.allPosts, headLineTag)]; } public getPosts(filters?: Tag[]): void { diff --git a/src/app/post/components/post-tag/post-tag.component.html b/src/app/post/components/post-tag/post-tag.component.html new file mode 100644 index 0000000000000000000000000000000000000000..d25174f3589e978e81eb3a3375130161c3e13d3a --- /dev/null +++ b/src/app/post/components/post-tag/post-tag.component.html @@ -0,0 +1,8 @@ +<div> + <div fxLayout="row" class="tag" fxLayoutAlign=" center" fxLayoutGap="12px" *ngIf="post.tags[0]"> + <span>{{ displayTag(post) }}</span> + </div> + <div fxLayout="row" class="tag" fxLayoutAlign=" center" fxLayoutGap="12px" *ngIf="!post.tags[0]"> + <span>infos</span> + </div> +</div> diff --git a/src/app/post/components/post-tag/post-tag.component.scss b/src/app/post/components/post-tag/post-tag.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..6ea1a32bd9e425e5ad3e338bf1a571ae3f82dc98 --- /dev/null +++ b/src/app/post/components/post-tag/post-tag.component.scss @@ -0,0 +1,10 @@ +@import '../../../../assets/scss/typography'; +@import '../../../../assets/scss/color'; + +.tag { + @include cn-bold-16; + text-transform: uppercase; + color: $secondary-color; + fill: $secondary-color; + stroke: $secondary-color; +} diff --git a/src/app/post/components/post-tag/post-tag.component.spec.ts b/src/app/post/components/post-tag/post-tag.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b1c7b465cdd4e571bbd1c4ee5e21fa5395448fa --- /dev/null +++ b/src/app/post/components/post-tag/post-tag.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PostTagComponent } from './post-tag.component'; + +describe('PostTagComponent', () => { + let component: PostTagComponent; + let fixture: ComponentFixture<PostTagComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ PostTagComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PostTagComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/post/components/post-tag/post-tag.component.ts b/src/app/post/components/post-tag/post-tag.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..c39b2fb6fc3da4f561d539ec66684f17bc81ecb1 --- /dev/null +++ b/src/app/post/components/post-tag/post-tag.component.ts @@ -0,0 +1,19 @@ +import { Component, Input } from '@angular/core'; +import { TagEnum } from '../../enum/tag.enum'; +import { Post } from '../../models/post.model'; + +@Component({ + selector: 'app-post-tag', + templateUrl: './post-tag.component.html', + styleUrls: ['./post-tag.component.scss'], +}) +export class PostTagComponent { + @Input() post: Post; + + public displayTag(post: Post): string { + if (post.tags.length > 1) { + return post.tags.filter((tag) => tag.slug !== TagEnum.aLaUne)[0].name; + } + return post.tags[0].name; + } +} diff --git a/src/app/post/post.module.ts b/src/app/post/post.module.ts index a4f19045817563190f78f433ecca44d8bf0b1cf1..984af52e1dac1df97998968cd40071811e856207 100644 --- a/src/app/post/post.module.ts +++ b/src/app/post/post.module.ts @@ -10,6 +10,7 @@ import { PostCardComponent } from './components/post-card/post-card.component'; import { PostPublishComponent } from './components/post-publish/post-publish.component'; import { PostModalFiltersComponent } from './components/post-modal-filters/post-modal-filters.component'; import { TagResolver } from './resolvers/tags.resolver'; +import { PostTagComponent } from './components/post-tag/post-tag.component'; @NgModule({ declarations: [ @@ -20,6 +21,7 @@ import { TagResolver } from './resolvers/tags.resolver'; PostCardComponent, PostModalFiltersComponent, PostPublishComponent, + PostTagComponent, ], imports: [CommonModule, PostRoutingModule, SharedModule], providers: [TagResolver], diff --git a/src/app/reset-password/reset-password.component.ts b/src/app/reset-password/reset-password.component.ts index 627cff9ba6559c3f4f2c4427c8144e6d58648620..4744261e970781fa2b7fca80b57c404c230b4be0 100644 --- a/src/app/reset-password/reset-password.component.ts +++ b/src/app/reset-password/reset-password.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { AuthService } from '../services/auth.service'; +import { NotificationService } from '../services/notification.service'; @Component({ selector: 'app-reset-password', @@ -21,7 +22,8 @@ export class ResetPasswordComponent implements OnInit { private formBuilder: FormBuilder, private authService: AuthService, private router: Router, - private activatedRoute: ActivatedRoute + private activatedRoute: ActivatedRoute, + private notificationService: NotificationService ) {} ngOnInit(): void { @@ -50,6 +52,10 @@ export class ResetPasswordComponent implements OnInit { this.loading = true; this.authService.resetPassword(this.f.email.value).subscribe( () => { + this.notificationService.showSuccess( + 'Un mail de confirmation de modification de votre mot de passe vous a été envoyé.', + '' + ); this.router.navigate(['']); }, () => { diff --git a/src/app/shared/components/address-autocomplete/address-autocomplete.component.ts b/src/app/shared/components/address-autocomplete/address-autocomplete.component.ts index 10f2efed1de1e07cdf8e838ab8bac1ba735fb01a..a1115c3acfb124518e39b3e1a87b538c1a048523 100644 --- a/src/app/shared/components/address-autocomplete/address-autocomplete.component.ts +++ b/src/app/shared/components/address-autocomplete/address-autocomplete.component.ts @@ -59,6 +59,7 @@ export class AddressAutocompleteComponent implements OnInit { address.numero = hit.properties.housenumber ? hit.properties.housenumber : null; address.street = hit.properties.street; address.commune = hit.properties.city; + address.coordinates = hit.geometry.coordinates; const value = this.parseHitToAddress(hit); // Set input value this.searchAddress.nativeElement.value = value; diff --git a/src/app/shared/components/svg-icon/svg-icon.component.scss b/src/app/shared/components/svg-icon/svg-icon.component.scss index bed7e3e0d741f9d08735c2df410fbda5c61eff4c..0ce39a373506e5a1f2d12852c1194876db231904 100644 --- a/src/app/shared/components/svg-icon/svg-icon.component.scss +++ b/src/app/shared/components/svg-icon/svg-icon.component.scss @@ -51,6 +51,10 @@ fill: $grey-1; stroke: $grey-1; } + &.green { + fill: $green-1; + stroke: $green-1; + } } svg { diff --git a/src/app/structure-list/components/card/card.component.html b/src/app/structure-list/components/card/card.component.html index bfe44fd1aa4821884d0784b90fa9fc3b415361bf..eae83fda6712d15160c9faaeda89809be95405ed 100644 --- a/src/app/structure-list/components/card/card.component.html +++ b/src/app/structure-list/components/card/card.component.html @@ -1,42 +1,57 @@ -<div class="structure" fxLayout="column" (click)="cardClicked()" (mouseenter)="cardHover()"> - <div class="headerStructure" fxLayout="row" fxLayoutAlign="space-between baseline" fxLayoutGap="16px"> - <div fxLayout="column" fxLayoutAlign="end"> - <span class="structure-name" [ngClass]="{ notClaimed: !isClaimed }">{{ structure.structureName }}</span> - <span class="typeStructure">{{ structure.getLabelTypeStructure() }}</span> - </div> - <div class="distanceStructure" fxLayout="column" fxLayoutAlign="none end"> - <div *ngIf="!isOrientation"> - {{ this.structure.address.commune }} - </div> - <div - fxLayout="row" - *ngIf="isOrientation && !isSelected" - class="selection-button selected" - (click)="cardAddToList(); $event.stopPropagation()" - > - <app-svg-icon [type]="'ico'" [icon]="'add'" [iconColor]="'black'"></app-svg-icon>ajouter à la liste +<div + class="structure" + fxLayout="column" + (click)="cardClicked()" + (mouseenter)="cardHover()" + [ngClass]="{ orientation: isOrientation }" +> + <div class="left"> + <div fxLayout="row" fxLayoutAlign="space-between baseline" fxLayoutGap="16px"> + <div fxLayout="column" fxLayoutAlign="end"> + <span class="structure-name" [ngClass]="{ notClaimed: !isClaimed }">{{ structure.structureName }}</span> + <span class="typeStructure">{{ structure.getLabelTypeStructure() }}</span> </div> - <div - fxLayout="row" - *ngIf="isOrientation && isSelected" - class="selection-button to-select" - (click)="cardAddToList(); $event.stopPropagation()" - > - <app-svg-icon [type]="'ico'" [icon]="'validate'" [iconColor]="'white'"></app-svg-icon> - retirer de la liste - </div> - <div *ngIf="structure.distance"> - {{ this.formatDistance() }} + <div class="distanceStructure" fxLayout="column" fxLayoutAlign="none end"> + <div *ngIf="!isOrientation"> + {{ this.structure.address.commune }} + </div> </div> </div> + <div + fxLayout="row" + fxLayoutAlign="none flex-end" + fxLayoutGap="7px" + *ngIf="structure.hasEquipments() && !isOrientation" + > + <app-svg-icon + *ngFor="let equipement of filterOnlyEquipments(structure.equipmentsAndServices)" + [type]="'ico'" + [iconColor]="'grey'" + [icon]="structure.getEquipmentsIcon(equipement)" + [title]="structure.getEquipmentsTitle(equipement)" + ></app-svg-icon> + </div> + <div class="distance" *ngIf="structure.distance"> + {{ this.formatDistance() }} + </div> </div> - <div fxLayout="row" fxLayoutAlign="none flex-end" fxLayoutGap="7px" *ngIf="structure.hasEquipments()"> - <app-svg-icon - *ngFor="let equipement of filterOnlyEquipments(structure.equipmentsAndServices)" - [type]="'ico'" - [iconColor]="'grey'" - [icon]="structure.getEquipmentsIcon(equipement)" - [title]="structure.getEquipmentsTitle(equipement)" - ></app-svg-icon> + <div class="actions right" *ngIf="isOrientation"> + <div + fxLayout="row" + *ngIf="!isSelected" + class="selection-button selected" + (click)="cardAddToList(); $event.stopPropagation()" + > + <app-svg-icon class="add-icon" [type]="'ico'" [icon]="'add'" [iconColor]="'green'"></app-svg-icon>Ajouter + </div> + <div + fxLayout="row" + *ngIf="isSelected" + class="selection-button to-select" + (click)="cardAddToList(); $event.stopPropagation()" + > + <app-svg-icon class="add-icon" [type]="'ico'" [icon]="'validate'" [iconColor]="'white'"></app-svg-icon> + Ajouté + </div> </div> </div> diff --git a/src/app/structure-list/components/card/card.component.scss b/src/app/structure-list/components/card/card.component.scss index 7b5fb40ae91f94ee499af869a86bd2cbc5be9814..220adda5872c14700c31c9c628470945fd8f6ff4 100644 --- a/src/app/structure-list/components/card/card.component.scss +++ b/src/app/structure-list/components/card/card.component.scss @@ -30,9 +30,6 @@ color: $grey-3; width: 50%; } - &:last-child { - border-bottom: none; - } } .selection-button { @@ -40,22 +37,44 @@ font-weight: bold; justify-content: center; align-items: center; - min-width: 180px; - height: 30px; + min-width: 120px; + height: 40px; border-radius: 20px; - padding: 3px 10px; - margin-bottom: 10px; } .selected { - border-style: solid; - border-width: 2px; + border: solid 1px $grey-3; background-color: $white; - border-color: $black; color: $black; } .to-select { - color: white; + color: $white; border-style: none; background: #47c562; } + +.distance { + color: $grey-3; +} + +.add-icon { + color: $green-1; +} + +.orientation { + flex-direction: row !important; + + .left { + display: flex; + flex-direction: column; + justify-content: space-between; + width: 70%; + } + + .right { + margin-top: 6%; + @media #{$large-phone} { + margin-left: unset; + } + } +} diff --git a/src/app/structure-list/components/structure-details/structure-details.component.scss b/src/app/structure-list/components/structure-details/structure-details.component.scss index de1fd0ab8c32a1deac7791a88c6ede405516a3dc..2b5a439e1bff52c30b5e88c5bc51233f51dde5ff 100644 --- a/src/app/structure-list/components/structure-details/structure-details.component.scss +++ b/src/app/structure-list/components/structure-details/structure-details.component.scss @@ -22,13 +22,13 @@ a { padding: 0px 24px; overflow: auto; @media #{$tablet} { - width: calc(100% - 2 * 24px); - position: inherit; - height: 100%; - overflow: unset; .printButton { display: none !important; } + + .ico-close { + margin-left: 16px; + } } .printButton { margin-right: 75px; diff --git a/src/app/structure-list/components/structure-details/structure-details.component.ts b/src/app/structure-list/components/structure-details/structure-details.component.ts index 5ccbc64f40a8bfc410b34233d07bbc201da618bb..cae5b0b60b3aae1e9ac58aa95f6371ad76f6da7e 100644 --- a/src/app/structure-list/components/structure-details/structure-details.component.ts +++ b/src/app/structure-list/components/structure-details/structure-details.component.ts @@ -94,7 +94,6 @@ export class StructureDetailsComponent implements OnInit { this.socialAndProfessionalsReferentiel = referentiel; } }); - this.setServiceCategories(); if (this.printMode) { this.printService.onDataReady(); } @@ -250,24 +249,6 @@ export class StructureDetailsComponent implements OnInit { } } - public setServiceCategories(): void { - this.baseSkills = this.structure.baseSkills.map((skill) => - _.find(this.baseSkillssReferentiel.modules, { id: skill }) - ); - this.accessRights = this.structure.accessRight.map((rights) => - _.find(this.accessRightsReferentiel.modules, { id: rights }) - ); - this.parentingHelp = this.structure.parentingHelp.map((help) => - _.find(this.parentingHelpsReferentiel.modules, { id: help }) - ); - this.socialAndProfessional = this.structure.socialAndProfessional.map((skill) => - _.find(this.socialAndProfessionalsReferentiel.modules, { id: skill }) - ); - this.digitalCultureSecurity = this.structure.digitalCultureSecurity.map((skill) => - _.find(this.digitalCultureSecuritysReferentiel.modules, { id: skill }) - ); - } - public keepOriginalOrder = (a, b) => a.key; public isBaseSkills(): boolean { diff --git a/src/app/structure-list/models/category.model.ts b/src/app/structure-list/models/category.model.ts index 2aa78bbf3c1c2628005ce2c2fa5c5c829492e726..b130dc1337cd4025a75a758db57e6ec79e610bae 100644 --- a/src/app/structure-list/models/category.model.ts +++ b/src/app/structure-list/models/category.model.ts @@ -2,6 +2,7 @@ import { Module } from './module.model'; export class Category { name: string; + surname: string; id: string; modules: Module[]; diff --git a/src/app/structure-list/models/filter.model.ts b/src/app/structure-list/models/filter.model.ts index 9ca53612448c628b8a1b18cfe2514e5cd4e591e3..25d7ff8253cb742637510467035c853e8c7a77f0 100644 --- a/src/app/structure-list/models/filter.model.ts +++ b/src/app/structure-list/models/filter.model.ts @@ -2,10 +2,12 @@ export class Filter { name: string; value: string; text?: string; + checked: boolean; constructor(name: string, value: any, text?: string) { this.name = name; this.value = value.toString(); this.text = text; + this.checked = true; } } diff --git a/src/app/structure-list/structure-list.component.html b/src/app/structure-list/structure-list.component.html index 1b39ec645a918b527da515ed058348472ef6b30f..9f2fc1b206a4a915a0d64697ccae0326f5b2de04 100644 --- a/src/app/structure-list/structure-list.component.html +++ b/src/app/structure-list/structure-list.component.html @@ -18,6 +18,7 @@ [structure]="structure" (showDetails)="showDetails($event, filters)" (hover)="handleCardHover($event)" + class="structure-card" ></app-card> <p *ngIf="structureList && structureList.length <= 0">Il n'y a aucune réponse correspondant à votre recherche</p> </div> diff --git a/src/app/structure-list/structure-list.component.scss b/src/app/structure-list/structure-list.component.scss index 1817ffba9980908d95a4864559669e85be195863..56305e76cfc58596f43f3dd1fcce6d26fa56d2dd 100644 --- a/src/app/structure-list/structure-list.component.scss +++ b/src/app/structure-list/structure-list.component.scss @@ -12,11 +12,16 @@ padding-left: 9px; margin: 0 16px; } + .listCard { overflow-y: auto; padding: 0 25px; } +::ng-deep .structure-card:last-child .structure { + border-bottom: unset !important; +} + @media print { .listCard { display: none; diff --git a/src/app/utils/utils.ts b/src/app/utils/utils.ts index e37ab99dd002bdcbe9cc54dd725e2f88e14349c3..a949f40fd15cdf46fe384a456588812f97ef008b 100644 --- a/src/app/utils/utils.ts +++ b/src/app/utils/utils.ts @@ -14,4 +14,15 @@ export class Utils { form.get(controlName).setValue(phoneNoSpace.replace(/(?!^)(?=(?:\d{2})+$)/g, ' ')); //NOSONAR } } + + public modifyPhoneValue(phoneNumber: string): string { + // Take length of phone number without spaces. + const phoneNoSpace = phoneNumber.replace(/\s/g, ''); + // Check to refresh every 2 number. + if (phoneNoSpace.length % 2 === 0) { + // Add space every 2 number + return phoneNoSpace.replace(/(?!^)(?=(?:\d{2})+$)/g, ' '); //NOSONAR + } + return phoneNumber; + } } diff --git a/src/assets/form/sprite.svg b/src/assets/form/sprite.svg index 356b83c16fc634ba7604cb491f44f0464d6f3d1a..f159036d9887f022758e673369fe9394e5421571 100644 --- a/src/assets/form/sprite.svg +++ b/src/assets/form/sprite.svg @@ -382,5 +382,35 @@ <path fill-rule="evenodd" clip-rule="evenodd" stroke="none" d="M0 9C0 8.44772 0.447715 8 1 8H21C21.5523 8 22 8.44772 22 9V23C22 23.5523 21.5523 24 21 24H14V25.6L16.3685 26.3106C16.7433 26.423 17 26.768 17 27.1593C17 27.6487 16.6033 28.0454 16.1139 28.0454H5.88612C5.39673 28.0454 5 27.6487 5 27.1593C5 26.768 5.25668 26.423 5.63149 26.3106L8 25.6V24H1C0.447716 24 0 23.5523 0 23V9ZM1 9H21V21H1V9Z" fill="#333333"/> </symbol> +<symbol id="grandLyonLaMetropole" width="189" height="43" viewBox="0 0 189 43" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0_5084_112181)"> +<path d="M14.6188 24.1594C13.8364 25.1028 12.8909 25.8619 11.8386 26.3915C10.7863 26.921 9.64874 27.2102 8.49363 27.2418C7.33852 27.2733 6.18949 27.0467 5.11498 26.5753C4.04046 26.1039 3.06242 25.3974 2.23911 24.4978C0.0358825 22.0532 1.03355e-07 19.6802 7.15522e-08 13.6244C3.9749e-08 7.56856 0.043059 5.19162 2.23911 2.74699C3.03301 1.87136 3.97472 1.17801 5.01036 0.706612C6.04601 0.235214 7.15526 -0.00498298 8.27465 -0.000236215C12.516 -0.000236237 15.7706 3.08541 16.5278 7.82736L14.6977 7.82736C13.9801 4.14051 11.5436 1.80736 8.28541 1.80736C7.4372 1.79871 6.59591 1.97729 5.81047 2.33273C5.02504 2.68816 4.31114 3.21334 3.71031 3.87773C1.96998 5.81273 1.83722 7.86717 1.83722 13.6244C1.83722 19.3816 1.97357 21.452 3.70314 23.3671C4.30384 24.0316 5.01772 24.5569 5.80318 24.9124C6.58864 25.2678 7.43 25.4463 8.27824 25.4375C9.23644 25.4435 10.1839 25.2138 11.0526 24.765C11.9212 24.3161 12.6894 23.6592 13.3019 22.8415C14.3461 21.4122 14.7551 19.8315 14.7551 17.5382L14.7551 15.1294L8.27465 15.1294L8.27465 13.3218L16.5852 13.3218L16.5852 17.7014C16.5852 20.4885 16.0433 22.4792 14.6188 24.1753" fill="#FF0101"/> +<path d="M31.9782 2.03265L24.8554 2.03265L24.8554 12.8702L31.9782 12.8702C35.0642 12.8702 37.3033 11.1383 37.3033 7.45144C37.3033 3.76459 35.0642 2.03265 31.9782 2.03265ZM37.2674 27.0204L31.501 14.6778L24.8554 14.6778L24.8554 27.0204L23.0254 27.0204L23.0254 0.237L32.2151 0.236999C36.1622 0.236999 39.1333 2.75728 39.1333 7.42357C39.1333 11.4051 36.9624 14.0089 33.5714 14.65L39.4024 27.0324L37.2674 27.0204Z" fill="#FF0101"/> +<path d="M51.7832 2.93246L46.7308 18.6991L56.8355 18.6991L51.7832 2.93246ZM59.516 27.0164L57.4133 20.5067L46.1531 20.5067L44.0504 27.0164L42.084 27.0164L50.9686 0.236999L52.5977 0.236999L61.4824 27.0324L59.516 27.0164Z" fill="#FF0101"/> +<path d="M81.4838 27.0166L67.5468 3.72496L67.5468 27.0166L65.7168 27.0166L65.7168 0.221252L67.5468 0.221252L81.4838 23.4413L81.4838 0.221252L83.3175 0.221252L83.3175 27.0166L81.4838 27.0166Z" fill="#FF0101"/> +<path d="M103.623 4.09904C102.234 2.50644 100.368 2.03265 98.4342 2.03265L92.5996 2.03265L92.5996 25.2088L98.4306 25.2088C100.365 25.2088 102.231 24.7191 103.619 23.1385C105.55 20.9566 105.413 16.2147 105.413 13.2445C105.413 10.2743 105.546 6.28487 103.619 4.08709L103.623 4.09904ZM104.907 24.5599C103.472 26.1525 101.384 27.0045 98.872 27.0045L90.7695 27.0045L90.7695 0.237L98.8755 0.236999C101.387 0.236999 103.487 1.10496 104.911 2.68561C107.355 5.39302 107.251 9.64524 107.251 13.2604C107.251 16.8756 107.355 21.8604 104.911 24.5718L104.907 24.5599Z" fill="#FF0101"/> +<path d="M112.846 27.0166L112.846 0.221252L117.561 0.221252L117.561 22.3503L128.516 22.3503L128.516 27.0166L112.846 27.0166Z" fill="#333333"/> +<path d="M138.852 16.0277L138.852 27.0166L134.173 27.0166L134.173 16.0277L126.914 0.221252L132.035 0.221252L136.545 11.027L140.991 0.221252L146.108 0.221252L138.852 16.0277Z" fill="#333333"/> +<path d="M159.805 6.09478C159.424 5.62814 158.957 5.25868 158.436 5.0119C157.914 4.76512 157.35 4.64691 156.783 4.66543C156.212 4.64699 155.643 4.76508 155.116 5.01168C154.59 5.25829 154.117 5.62767 153.73 6.09478C152.815 7.22154 152.578 8.48367 152.578 13.6198C152.578 18.7559 152.815 20.014 153.73 21.1448C154.117 21.6117 154.59 21.9809 155.117 22.2275C155.643 22.4741 156.212 22.5923 156.783 22.5741C157.35 22.5924 157.914 22.4741 158.435 22.2273C158.957 21.9805 159.424 21.6112 159.805 21.1448C160.72 20.014 160.992 18.7559 160.992 13.6198C160.992 8.48367 160.723 7.22154 159.805 6.09478ZM163.311 24.3101C161.561 26.1934 159.219 27.2467 156.782 27.2467C154.344 27.2467 152.002 26.1934 150.253 24.3101C147.813 21.6026 147.877 18.2502 147.877 13.6238C147.877 8.99728 147.813 5.6608 150.253 2.93747C152.002 1.05412 154.344 0.000793424 156.782 0.000793411C159.219 0.000793399 161.561 1.05412 163.311 2.93747C165.754 5.64487 165.718 8.9933 165.718 13.6238C165.718 18.2542 165.74 21.6026 163.311 24.3101Z" fill="#333333"/> +<path d="M184.79 27.0166L175.227 10.5731L175.227 27.0166L170.516 27.0166L170.516 0.221252L174.721 0.221252L184.284 16.6289L184.284 0.221252L188.999 0.221252L188.999 27.0166L184.79 27.0166Z" fill="#333333"/> +<path d="M160.242 35.4745L160.264 35.4745C160.376 35.2188 160.553 35.0047 160.773 34.8578C160.992 34.7108 161.246 34.6374 161.502 34.6464C162.363 34.6464 163.239 35.0445 163.239 37.6524C163.239 39.1414 163.196 40.8575 161.444 40.8575C161.208 40.8618 160.974 40.7976 160.766 40.6712C160.559 40.5449 160.384 40.3607 160.26 40.1368L160.228 40.1368L160.228 42.9995L159.363 42.9995L159.363 34.7658L160.239 34.7658L160.242 35.4745ZM162.324 37.6524C162.324 36.7526 162.324 35.4387 161.226 35.4387C160.128 35.4387 160.246 37.095 160.246 38.0067C160.246 38.803 160.289 40.0651 161.258 40.0651C162.227 40.0651 162.324 39.2569 162.324 37.6643L162.324 37.6524Z" fill="#333333"/> +<path d="M99.992 39.8734L99.9705 39.8734C99.8752 40.1805 99.6905 40.4438 99.4457 40.6218C99.2008 40.7998 98.9095 40.8825 98.6177 40.8568C97.4766 40.8568 97.1465 40.0406 97.1465 38.8939C97.1465 37.0824 98.7469 37.0027 99.9705 37.0346C99.992 36.2383 100.003 35.3783 99.0627 35.3783C98.9391 35.3673 98.815 35.3884 98.7001 35.44C98.5853 35.4916 98.4828 35.5722 98.401 35.6754C98.3191 35.7786 98.26 35.9016 98.2285 36.0345C98.197 36.1675 98.1939 36.3068 98.2194 36.4414L97.2864 36.4414C97.3295 35.1036 97.9682 34.6417 99.1093 34.6417C100.494 34.6417 100.857 35.438 100.857 36.4414L100.857 39.316C100.86 39.7921 100.896 40.2672 100.964 40.7374L100.006 40.7374L99.992 39.8734ZM98.022 38.9616C98.022 39.5389 98.2768 40.0605 98.8617 40.0605C99.4466 40.0605 100.057 39.6942 99.9705 37.7632C99.1416 37.7791 98.022 37.6995 98.022 38.9656L98.022 38.9616Z" fill="#333333"/> +<path d="M115.722 40.7375L115.722 36.5968C115.722 35.9916 115.572 35.4382 114.868 35.4382C114.724 35.4407 114.581 35.4776 114.451 35.5462C114.32 35.6149 114.204 35.7138 114.111 35.8363C113.976 36.1038 113.905 36.4056 113.907 36.7123L113.907 40.7336L113.038 40.7336L113.038 36.0075C113.038 35.6094 113.017 35.1794 112.984 34.7653L113.91 34.7653L113.91 35.5099L113.932 35.5099C114.042 35.2248 114.232 34.9868 114.474 34.8311C114.715 34.6755 114.996 34.6105 115.274 34.6459C115.528 34.6248 115.783 34.6862 116.006 34.8226C116.23 34.959 116.413 35.1646 116.533 35.4143C116.652 35.1581 116.838 34.9478 117.067 34.8107C117.295 34.6736 117.556 34.6162 117.814 34.6459C118.381 34.6459 119.285 34.7892 119.285 36.1947L119.285 40.7375L118.41 40.7375L118.41 36.5968C118.41 35.9916 118.263 35.4382 117.556 35.4382C117.438 35.4175 117.317 35.4268 117.203 35.4654C117.088 35.504 116.983 35.5709 116.896 35.6612C116.684 35.9597 116.579 36.3334 116.598 36.7123L116.598 40.7336L115.722 40.7375Z" fill="#333333"/> +<path d="M125.656 38.063C125.656 39.7313 126.061 40.0538 126.732 40.0538C127.328 40.0538 127.64 39.5203 127.669 38.9191L128.627 38.9191C128.627 40.2449 127.881 40.8461 126.75 40.8461C125.62 40.8461 124.705 40.4479 124.705 37.8281C124.705 36.0763 124.884 34.6429 126.75 34.6429C128.286 34.6429 128.67 35.5786 128.67 37.5534L128.67 38.063L125.656 38.063ZM127.755 37.3304C127.755 35.5905 127.317 35.3795 126.679 35.3795C126.126 35.3795 125.667 35.6741 125.656 37.3304L127.755 37.3304ZM127.97 32.1943L126.575 33.8626L125.857 33.8626L126.808 32.1943L127.97 32.1943Z" fill="#333333"/> +<path d="M134.605 34.7658L134.605 33.6191L135.481 33.1812L135.481 34.7737L136.654 34.7737L136.654 35.5063L135.481 35.5063L135.481 39.1613C135.481 39.5595 135.481 40.0253 136.281 40.0253C136.346 40.0253 136.482 40.0014 136.676 39.9775L136.676 40.7221C136.389 40.746 136.098 40.8176 135.811 40.8176C134.979 40.8176 134.605 40.4195 134.605 39.7546L134.605 35.4984L133.723 35.4984L133.723 34.7658L134.605 34.7658Z" fill="#333333"/> +<path d="M143.185 35.674L143.217 35.674C143.576 34.7623 144.028 34.6588 144.879 34.6588L144.879 35.6661L144.646 35.6302C144.568 35.6157 144.49 35.6077 144.412 35.6063C143.443 35.6063 143.196 36.4226 143.196 37.2268L143.196 40.7544L142.32 40.7544L142.32 34.7822L143.196 34.7822L143.185 35.674Z" fill="#333333"/> +<path d="M149.852 37.84C149.852 36.0882 150.031 34.6548 151.897 34.6548C153.763 34.6548 153.942 36.1001 153.942 37.84C153.942 40.4797 153.034 40.858 151.897 40.858C150.759 40.858 149.852 40.4797 149.852 37.84ZM153.027 37.4419C153.027 35.8095 152.568 35.4511 151.897 35.4511C151.226 35.4511 150.767 35.8055 150.767 37.4419C150.767 39.3809 150.993 40.0816 151.897 40.0816C152.801 40.0816 153.031 39.3649 153.031 37.426L153.027 37.4419Z" fill="#333333"/> +<path d="M168.586 37.84C168.586 36.0882 168.765 34.6548 170.631 34.6548C172.497 34.6548 172.68 36.1001 172.68 37.84C172.68 40.4797 171.772 40.858 170.631 40.858C169.49 40.858 168.586 40.4797 168.586 37.84ZM171.762 37.4419C171.762 35.8095 171.302 35.4511 170.631 35.4511C169.96 35.4511 169.501 35.8055 169.501 37.4419C169.501 39.3809 169.723 40.0816 170.631 40.0816C171.539 40.0816 171.765 39.3649 171.765 37.426L171.762 37.4419Z" fill="#333333"/> +<path d="M179.221 40.7386L178.346 40.7386L178.346 32.1983L179.218 32.1983L179.221 40.7386Z" fill="#333333"/> +<path d="M185.674 38.0618C185.674 39.7301 186.079 40.0526 186.75 40.0526C187.346 40.0526 187.658 39.519 187.687 38.9178L188.645 38.9178C188.645 40.2437 187.898 40.8449 186.768 40.8449C185.638 40.8449 184.723 40.4467 184.723 37.8269C184.723 36.0751 184.902 34.6417 186.768 34.6417C188.304 34.6417 188.688 35.5774 188.688 37.5522L188.688 38.0618L185.674 38.0618ZM187.773 37.3292C187.773 35.5893 187.335 35.3783 186.696 35.3783C186.144 35.3783 185.684 35.6729 185.674 37.3292L187.773 37.3292Z" fill="#333333"/> +<path d="M92.1236 40.7386L91.248 40.7386L91.248 32.1983L92.1236 32.1983L92.1236 40.7386Z" fill="#333333"/> +</g> +<defs> +<clipPath id="clip0_5084_112181"> +<rect width="189" height="43" fill="white"/> +</clipPath> +</defs> +</symbol> + </svg> diff --git a/src/assets/ico/flag.svg b/src/assets/ico/flag.svg new file mode 100644 index 0000000000000000000000000000000000000000..af8498d85fd3d40b1b3e71454666c69ca8a426c8 --- /dev/null +++ b/src/assets/ico/flag.svg @@ -0,0 +1,16 @@ +<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg"> +<rect x="6.01176" y="2.61237" width="1" height="17" rx="0.5" transform="rotate(15 6.01176 2.61237)" stroke="white"/> +<rect x="6.90824" y="6.99372" width="1" height="1" transform="rotate(15 6.90824 6.99372)" stroke="white"/> +<rect x="5.87308" y="10.8574" width="1" height="1" transform="rotate(15 5.87308 10.8574)" stroke="white"/> +<rect x="10.7715" y="8.029" width="1" height="1" transform="rotate(15 10.7715 8.029)" stroke="white"/> +<rect x="9.73637" y="11.8926" width="1" height="1" transform="rotate(15 9.73637 11.8926)" stroke="white"/> +<rect x="14.6348" y="9.06428" width="1" height="1" transform="rotate(15 14.6348 9.06428)" stroke="white"/> +<rect x="13.5996" y="12.9279" width="1" height="1" transform="rotate(15 13.5996 12.9279)" stroke="white"/> +<rect x="8.3223" y="9.44318" width="1" height="1" transform="rotate(15 8.3223 9.44318)" stroke="white"/> +<rect x="12.1856" y="10.4785" width="1" height="1" transform="rotate(15 12.1856 10.4785)" stroke="white"/> +<rect x="16.0489" y="11.5137" width="1" height="1" transform="rotate(15 16.0489 11.5137)" stroke="white"/> +<rect x="9.35746" y="5.57941" width="1" height="1" transform="rotate(15 9.35746 5.57941)" stroke="white"/> +<rect x="13.2207" y="6.61469" width="1" height="1" transform="rotate(15 13.2207 6.61469)" stroke="white"/> +<rect x="17.086" y="7.64997" width="1" height="1" transform="rotate(15 17.086 7.64997)" stroke="white"/> +<rect x="6.71879" y="3.8371" width="13" height="9" transform="rotate(15 6.71879 3.8371)" stroke="white"/> +</svg> diff --git a/src/assets/ico/sprite.svg b/src/assets/ico/sprite.svg index e7b918e0ff25552775f070c554ab7edc1a0ed435..81f91788f649e343d97a9634e6ba9dde58d39eab 100644 --- a/src/assets/ico/sprite.svg +++ b/src/assets/ico/sprite.svg @@ -292,6 +292,13 @@ <path fill-rule="evenodd" clip-rule="evenodd" d="M17.3405 17.1848C16.2256 17.652 15.5 18.7428 15.5 19.9517V34.6087L22.5 34.6087V30.1087C22.5 29.2802 23.1716 28.6087 24 28.6087C24.8284 28.6087 25.5 29.2802 25.5 30.1087V34.6087L32.5 34.6087V20.0123C32.5 18.7731 31.7381 17.6614 30.5823 17.2143L29.0555 16.6237C28.6291 16.4588 28.246 16.1986 27.9355 15.863L25.4183 13.1419C24.6451 12.3061 23.3312 12.2834 22.5297 13.0921L19.6982 15.9488C19.4206 16.2289 19.0906 16.4515 18.7269 16.6039L17.3405 17.1848ZM25.5 16.1087C25.5 16.9371 24.8284 17.6087 24 17.6087C23.1716 17.6087 22.5 16.9371 22.5 16.1087C22.5 15.2802 23.1716 14.6087 24 14.6087C24.8284 14.6087 25.5 15.2802 25.5 16.1087ZM18.75 27.544C18.0406 27.6631 17.5 28.2801 17.5 29.0233V30.3587H18.75V27.544ZM17.5 33.5233V30.8587H18.75V33.5233H17.5ZM19.25 33.5233V30.8587H20.5V33.5233H19.25ZM20.5 29.0233V30.3587H19.25V27.544C19.9594 27.6631 20.5 28.2801 20.5 29.0233ZM27.5 29.0233C27.5 28.2801 28.0406 27.6631 28.75 27.544V30.3587H27.5V29.0233ZM27.5 30.8587V33.5233H28.75V30.8587H27.5ZM29.25 30.8587V33.5233H30.5V30.8587H29.25ZM30.5 30.3587V29.0233C30.5 28.2801 29.9594 27.6631 29.25 27.544V30.3587H30.5ZM28.75 19.6087C28.0406 19.7277 27.5 20.3447 27.5 21.0879V22.4233H28.75V19.6087ZM27.5 25.5879V22.9233H28.75V25.5879H27.5ZM29.25 25.5879V22.9233H30.5V25.5879H29.25ZM30.5 21.0879V22.4233H29.25V19.6087C29.9594 19.7277 30.5 20.3447 30.5 21.0879ZM22.5 21.0879C22.5 20.3447 23.0406 19.7277 23.75 19.6087V22.4233H22.5V21.0879ZM22.5 22.9233V25.5879H23.75V22.9233H22.5ZM24.25 22.9233V25.5879H25.5V22.9233H24.25ZM25.5 22.4233V21.0879C25.5 20.3447 24.9594 19.7277 24.25 19.6087V22.4233H25.5ZM18.75 19.6087C18.0406 19.7277 17.5 20.3447 17.5 21.0879V22.4233H18.75V19.6087ZM17.5 25.5879V22.9233H18.75V25.5879H17.5ZM19.25 25.5879V22.9233H20.5V25.5879H19.25ZM20.5 21.0879V22.4233H19.25V19.6087C19.9594 19.7277 20.5 20.3447 20.5 21.0879Z" fill="#BD9E6A"/> </symbol> +<symbol id="user-location" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg"> +<circle cx="17" cy="17" r="16.5" fill="#ED3939" fill-opacity="0.15" stroke="white"/> +<circle cx="17" cy="17" r="6" fill="#ED3939"/> +<path opacity="0.35" d="M19.625 12.9167C18.1502 12.2215 16.7083 12.0417 15.25 12.9167C16.4166 12.9167 18.7694 14.3782 19.3737 15.1918C20.5 16.7084 20.6016 19.0553 20.2083 19.3334C20.4541 19.4724 21.5026 18.3063 21.6666 17C21.8306 15.6948 21.0998 13.6119 19.625 12.9167Z" fill="white"/> +</symbol> + + <symbol id="conseillerFranceService" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg"> <path d="M24.1752 4.3111L12 11.3612V25.4094L23.5247 45.3111H24.8255L36.3503 25.4094V11.3612L24.1752 4.3111Z"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M24.1752 2L38.3503 10.2083V25.9467L25.9785 47.3111H22.3718L10 25.9467V10.2082L24.1752 2ZM12 25.4094V11.3612L24.1752 4.31111L36.3503 11.3612V25.4094L24.8255 45.3111H23.5247L12 25.4094Z" fill="white"/> diff --git a/src/assets/logos/grandLyonLaMetropole.svg b/src/assets/logos/grandLyonLaMetropole.svg new file mode 100644 index 0000000000000000000000000000000000000000..9d443ffa294345095ed947265dd4f705f5122729 --- /dev/null +++ b/src/assets/logos/grandLyonLaMetropole.svg @@ -0,0 +1,29 @@ +<svg width="189" height="43" viewBox="0 0 189 43" fill="none" xmlns="http://www.w3.org/2000/svg"> +<g clip-path="url(#clip0_5084_112181)"> +<path d="M14.6188 24.1594C13.8364 25.1028 12.8909 25.8619 11.8386 26.3915C10.7863 26.921 9.64874 27.2102 8.49363 27.2418C7.33852 27.2733 6.18949 27.0467 5.11498 26.5753C4.04046 26.1039 3.06242 25.3974 2.23911 24.4978C0.0358825 22.0532 1.03355e-07 19.6802 7.15522e-08 13.6244C3.9749e-08 7.56856 0.043059 5.19162 2.23911 2.74699C3.03301 1.87136 3.97472 1.17801 5.01036 0.706612C6.04601 0.235214 7.15526 -0.00498298 8.27465 -0.000236215C12.516 -0.000236237 15.7706 3.08541 16.5278 7.82736L14.6977 7.82736C13.9801 4.14051 11.5436 1.80736 8.28541 1.80736C7.4372 1.79871 6.59591 1.97729 5.81047 2.33273C5.02504 2.68816 4.31114 3.21334 3.71031 3.87773C1.96998 5.81273 1.83722 7.86717 1.83722 13.6244C1.83722 19.3816 1.97357 21.452 3.70314 23.3671C4.30384 24.0316 5.01772 24.5569 5.80318 24.9124C6.58864 25.2678 7.43 25.4463 8.27824 25.4375C9.23644 25.4435 10.1839 25.2138 11.0526 24.765C11.9212 24.3161 12.6894 23.6592 13.3019 22.8415C14.3461 21.4122 14.7551 19.8315 14.7551 17.5382L14.7551 15.1294L8.27465 15.1294L8.27465 13.3218L16.5852 13.3218L16.5852 17.7014C16.5852 20.4885 16.0433 22.4792 14.6188 24.1753" fill="#FF0101"/> +<path d="M31.9782 2.03265L24.8554 2.03265L24.8554 12.8702L31.9782 12.8702C35.0642 12.8702 37.3033 11.1383 37.3033 7.45144C37.3033 3.76459 35.0642 2.03265 31.9782 2.03265ZM37.2674 27.0204L31.501 14.6778L24.8554 14.6778L24.8554 27.0204L23.0254 27.0204L23.0254 0.237L32.2151 0.236999C36.1622 0.236999 39.1333 2.75728 39.1333 7.42357C39.1333 11.4051 36.9624 14.0089 33.5714 14.65L39.4024 27.0324L37.2674 27.0204Z" fill="#FF0101"/> +<path d="M51.7832 2.93246L46.7308 18.6991L56.8355 18.6991L51.7832 2.93246ZM59.516 27.0164L57.4133 20.5067L46.1531 20.5067L44.0504 27.0164L42.084 27.0164L50.9686 0.236999L52.5977 0.236999L61.4824 27.0324L59.516 27.0164Z" fill="#FF0101"/> +<path d="M81.4838 27.0166L67.5468 3.72496L67.5468 27.0166L65.7168 27.0166L65.7168 0.221252L67.5468 0.221252L81.4838 23.4413L81.4838 0.221252L83.3175 0.221252L83.3175 27.0166L81.4838 27.0166Z" fill="#FF0101"/> +<path d="M103.623 4.09904C102.234 2.50644 100.368 2.03265 98.4342 2.03265L92.5996 2.03265L92.5996 25.2088L98.4306 25.2088C100.365 25.2088 102.231 24.7191 103.619 23.1385C105.55 20.9566 105.413 16.2147 105.413 13.2445C105.413 10.2743 105.546 6.28487 103.619 4.08709L103.623 4.09904ZM104.907 24.5599C103.472 26.1525 101.384 27.0045 98.872 27.0045L90.7695 27.0045L90.7695 0.237L98.8755 0.236999C101.387 0.236999 103.487 1.10496 104.911 2.68561C107.355 5.39302 107.251 9.64524 107.251 13.2604C107.251 16.8756 107.355 21.8604 104.911 24.5718L104.907 24.5599Z" fill="#FF0101"/> +<path d="M112.846 27.0166L112.846 0.221252L117.561 0.221252L117.561 22.3503L128.516 22.3503L128.516 27.0166L112.846 27.0166Z" fill="#333333"/> +<path d="M138.852 16.0277L138.852 27.0166L134.173 27.0166L134.173 16.0277L126.914 0.221252L132.035 0.221252L136.545 11.027L140.991 0.221252L146.108 0.221252L138.852 16.0277Z" fill="#333333"/> +<path d="M159.805 6.09478C159.424 5.62814 158.957 5.25868 158.436 5.0119C157.914 4.76512 157.35 4.64691 156.783 4.66543C156.212 4.64699 155.643 4.76508 155.116 5.01168C154.59 5.25829 154.117 5.62767 153.73 6.09478C152.815 7.22154 152.578 8.48367 152.578 13.6198C152.578 18.7559 152.815 20.014 153.73 21.1448C154.117 21.6117 154.59 21.9809 155.117 22.2275C155.643 22.4741 156.212 22.5923 156.783 22.5741C157.35 22.5924 157.914 22.4741 158.435 22.2273C158.957 21.9805 159.424 21.6112 159.805 21.1448C160.72 20.014 160.992 18.7559 160.992 13.6198C160.992 8.48367 160.723 7.22154 159.805 6.09478ZM163.311 24.3101C161.561 26.1934 159.219 27.2467 156.782 27.2467C154.344 27.2467 152.002 26.1934 150.253 24.3101C147.813 21.6026 147.877 18.2502 147.877 13.6238C147.877 8.99728 147.813 5.6608 150.253 2.93747C152.002 1.05412 154.344 0.000793424 156.782 0.000793411C159.219 0.000793399 161.561 1.05412 163.311 2.93747C165.754 5.64487 165.718 8.9933 165.718 13.6238C165.718 18.2542 165.74 21.6026 163.311 24.3101Z" fill="#333333"/> +<path d="M184.79 27.0166L175.227 10.5731L175.227 27.0166L170.516 27.0166L170.516 0.221252L174.721 0.221252L184.284 16.6289L184.284 0.221252L188.999 0.221252L188.999 27.0166L184.79 27.0166Z" fill="#333333"/> +<path d="M160.242 35.4745L160.264 35.4745C160.376 35.2188 160.553 35.0047 160.773 34.8578C160.992 34.7108 161.246 34.6374 161.502 34.6464C162.363 34.6464 163.239 35.0445 163.239 37.6524C163.239 39.1414 163.196 40.8575 161.444 40.8575C161.208 40.8618 160.974 40.7976 160.766 40.6712C160.559 40.5449 160.384 40.3607 160.26 40.1368L160.228 40.1368L160.228 42.9995L159.363 42.9995L159.363 34.7658L160.239 34.7658L160.242 35.4745ZM162.324 37.6524C162.324 36.7526 162.324 35.4387 161.226 35.4387C160.128 35.4387 160.246 37.095 160.246 38.0067C160.246 38.803 160.289 40.0651 161.258 40.0651C162.227 40.0651 162.324 39.2569 162.324 37.6643L162.324 37.6524Z" fill="#333333"/> +<path d="M99.992 39.8734L99.9705 39.8734C99.8752 40.1805 99.6905 40.4438 99.4457 40.6218C99.2008 40.7998 98.9095 40.8825 98.6177 40.8568C97.4766 40.8568 97.1465 40.0406 97.1465 38.8939C97.1465 37.0824 98.7469 37.0027 99.9705 37.0346C99.992 36.2383 100.003 35.3783 99.0627 35.3783C98.9391 35.3673 98.815 35.3884 98.7001 35.44C98.5853 35.4916 98.4828 35.5722 98.401 35.6754C98.3191 35.7786 98.26 35.9016 98.2285 36.0345C98.197 36.1675 98.1939 36.3068 98.2194 36.4414L97.2864 36.4414C97.3295 35.1036 97.9682 34.6417 99.1093 34.6417C100.494 34.6417 100.857 35.438 100.857 36.4414L100.857 39.316C100.86 39.7921 100.896 40.2672 100.964 40.7374L100.006 40.7374L99.992 39.8734ZM98.022 38.9616C98.022 39.5389 98.2768 40.0605 98.8617 40.0605C99.4466 40.0605 100.057 39.6942 99.9705 37.7632C99.1416 37.7791 98.022 37.6995 98.022 38.9656L98.022 38.9616Z" fill="#333333"/> +<path d="M115.722 40.7375L115.722 36.5968C115.722 35.9916 115.572 35.4382 114.868 35.4382C114.724 35.4407 114.581 35.4776 114.451 35.5462C114.32 35.6149 114.204 35.7138 114.111 35.8363C113.976 36.1038 113.905 36.4056 113.907 36.7123L113.907 40.7336L113.038 40.7336L113.038 36.0075C113.038 35.6094 113.017 35.1794 112.984 34.7653L113.91 34.7653L113.91 35.5099L113.932 35.5099C114.042 35.2248 114.232 34.9868 114.474 34.8311C114.715 34.6755 114.996 34.6105 115.274 34.6459C115.528 34.6248 115.783 34.6862 116.006 34.8226C116.23 34.959 116.413 35.1646 116.533 35.4143C116.652 35.1581 116.838 34.9478 117.067 34.8107C117.295 34.6736 117.556 34.6162 117.814 34.6459C118.381 34.6459 119.285 34.7892 119.285 36.1947L119.285 40.7375L118.41 40.7375L118.41 36.5968C118.41 35.9916 118.263 35.4382 117.556 35.4382C117.438 35.4175 117.317 35.4268 117.203 35.4654C117.088 35.504 116.983 35.5709 116.896 35.6612C116.684 35.9597 116.579 36.3334 116.598 36.7123L116.598 40.7336L115.722 40.7375Z" fill="#333333"/> +<path d="M125.656 38.063C125.656 39.7313 126.061 40.0538 126.732 40.0538C127.328 40.0538 127.64 39.5203 127.669 38.9191L128.627 38.9191C128.627 40.2449 127.881 40.8461 126.75 40.8461C125.62 40.8461 124.705 40.4479 124.705 37.8281C124.705 36.0763 124.884 34.6429 126.75 34.6429C128.286 34.6429 128.67 35.5786 128.67 37.5534L128.67 38.063L125.656 38.063ZM127.755 37.3304C127.755 35.5905 127.317 35.3795 126.679 35.3795C126.126 35.3795 125.667 35.6741 125.656 37.3304L127.755 37.3304ZM127.97 32.1943L126.575 33.8626L125.857 33.8626L126.808 32.1943L127.97 32.1943Z" fill="#333333"/> +<path d="M134.605 34.7658L134.605 33.6191L135.481 33.1812L135.481 34.7737L136.654 34.7737L136.654 35.5063L135.481 35.5063L135.481 39.1613C135.481 39.5595 135.481 40.0253 136.281 40.0253C136.346 40.0253 136.482 40.0014 136.676 39.9775L136.676 40.7221C136.389 40.746 136.098 40.8176 135.811 40.8176C134.979 40.8176 134.605 40.4195 134.605 39.7546L134.605 35.4984L133.723 35.4984L133.723 34.7658L134.605 34.7658Z" fill="#333333"/> +<path d="M143.185 35.674L143.217 35.674C143.576 34.7623 144.028 34.6588 144.879 34.6588L144.879 35.6661L144.646 35.6302C144.568 35.6157 144.49 35.6077 144.412 35.6063C143.443 35.6063 143.196 36.4226 143.196 37.2268L143.196 40.7544L142.32 40.7544L142.32 34.7822L143.196 34.7822L143.185 35.674Z" fill="#333333"/> +<path d="M149.852 37.84C149.852 36.0882 150.031 34.6548 151.897 34.6548C153.763 34.6548 153.942 36.1001 153.942 37.84C153.942 40.4797 153.034 40.858 151.897 40.858C150.759 40.858 149.852 40.4797 149.852 37.84ZM153.027 37.4419C153.027 35.8095 152.568 35.4511 151.897 35.4511C151.226 35.4511 150.767 35.8055 150.767 37.4419C150.767 39.3809 150.993 40.0816 151.897 40.0816C152.801 40.0816 153.031 39.3649 153.031 37.426L153.027 37.4419Z" fill="#333333"/> +<path d="M168.586 37.84C168.586 36.0882 168.765 34.6548 170.631 34.6548C172.497 34.6548 172.68 36.1001 172.68 37.84C172.68 40.4797 171.772 40.858 170.631 40.858C169.49 40.858 168.586 40.4797 168.586 37.84ZM171.762 37.4419C171.762 35.8095 171.302 35.4511 170.631 35.4511C169.96 35.4511 169.501 35.8055 169.501 37.4419C169.501 39.3809 169.723 40.0816 170.631 40.0816C171.539 40.0816 171.765 39.3649 171.765 37.426L171.762 37.4419Z" fill="#333333"/> +<path d="M179.221 40.7386L178.346 40.7386L178.346 32.1983L179.218 32.1983L179.221 40.7386Z" fill="#333333"/> +<path d="M185.674 38.0618C185.674 39.7301 186.079 40.0526 186.75 40.0526C187.346 40.0526 187.658 39.519 187.687 38.9178L188.645 38.9178C188.645 40.2437 187.898 40.8449 186.768 40.8449C185.638 40.8449 184.723 40.4467 184.723 37.8269C184.723 36.0751 184.902 34.6417 186.768 34.6417C188.304 34.6417 188.688 35.5774 188.688 37.5522L188.688 38.0618L185.674 38.0618ZM187.773 37.3292C187.773 35.5893 187.335 35.3783 186.696 35.3783C186.144 35.3783 185.684 35.6729 185.674 37.3292L187.773 37.3292Z" fill="#333333"/> +<path d="M92.1236 40.7386L91.248 40.7386L91.248 32.1983L92.1236 32.1983L92.1236 40.7386Z" fill="#333333"/> +</g> +<defs> +<clipPath id="clip0_5084_112181"> +<rect width="189" height="43" fill="white"/> +</clipPath> +</defs> +</svg> \ No newline at end of file diff --git a/src/assets/scss/_color.scss b/src/assets/scss/_color.scss index 7b72d6a99b74d8253d4dd1dd61560951700cd455..ad54ee5500cbec3ee1c1a60b717a3b90378fcf3e 100644 --- a/src/assets/scss/_color.scss +++ b/src/assets/scss/_color.scss @@ -1,6 +1,8 @@ //TODO: Clean colors when design is properly setup $black: #000000; $white: #ffff; +$white-1: #e5e5e5; +$white-2: #cacccb; /* GREYS */ $grey: #b4bbbf; $grey-1: #333333; diff --git a/src/assets/scss/_ghost.scss b/src/assets/scss/_ghost.scss index 15de6a5c2fa5e6d2fd199f2d478e4de559f3bc6d..548ed6c463fc4da6eea0e5f587877868104eff82 100644 --- a/src/assets/scss/_ghost.scss +++ b/src/assets/scss/_ghost.scss @@ -85,6 +85,74 @@ $margin-post: 20px; margin-right: auto; } } + ::ng-deep .kg-file-card { + margin-top: 6vmin; + ::ng-deep .kg-file-card-container { + display: flex; + justify-content: space-between; + color: inherit; + padding: 6px; + border: 1px solid rgb(124 139 154/25%); + border-radius: 3px; + text-decoration: none; + ::ng-deep .kg-file-card-contents { + margin: 4px 8px; + ::ng-deep .kg-file-card-title + .kg-file-card-caption { + margin-top: -3px; + } + ::ng-deep .kg-file-card-title { + font-size: 1.15em; + line-height: 1.3em; + } + ::ng-deep .kg-file-card-caption, + .kg-file-card-filesize { + font-weight: normal; + font-size: 0.95em; + opacity: 0.6; + } + ::ng-deep .kg-file-card-filesize { + display: inline-block; + } + ::ng-deep .kg-file-card-metadata { + font-size: 0.825em; + margin-top: 4px; + ::ng-deep .kg-file-card-filename { + display: inline; + font-weight: 500; + } + ::ng-deep .kg-file-card-filesize:before { + display: inline-block; + content: '\2022'; + margin-right: 4px; + } + } + } + ::ng-deep .kg-file-card-icon { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 80px; + } + ::ng-deep .kg-file-card-icon:before { + position: absolute; + display: block; + content: ''; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: currentColor; + opacity: 0.06; + border-radius: 2px; + } + ::ng-deep .kg-file-card-icon svg { + width: 24px; + height: 24px; + color: $red; + } + } + } ::ng-deep .kg-bookmark-card { margin-top: 30px; font: inherit; diff --git a/src/assets/scss/_icons.scss b/src/assets/scss/_icons.scss index c93d6aa78a2a9bf383c0e684b9484fbbd62aacb3..4cc84a175397bff5bf3d4e647ab9eb3b1d262337 100644 --- a/src/assets/scss/_icons.scss +++ b/src/assets/scss/_icons.scss @@ -61,7 +61,7 @@ width: 7px; height: 7px; border-radius: 4px; - background-color: white; + background-color: $white; } } .ico-dot-available { @@ -589,3 +589,125 @@ bottom: -6px; } } + +.ico-gg-eye-alt { + position: relative; + display: block; + transform: scale(var(--ggs, 1)); + width: 24px; + height: 18px; + border-bottom-right-radius: 100px; + border-bottom-left-radius: 100px; + overflow: hidden; + box-sizing: border-box; +} +.ico-gg-eye-alt::after, +.ico-gg-eye-alt::before { + content: ''; + display: block; + border-radius: 100px; + position: absolute; + box-sizing: border-box; +} +.ico-gg-eye-alt::after { + top: 2px; + box-shadow: inset 0 -8px 0 2px $grey-3, inset 0 0 0 2px $grey-3; + width: 24px; + height: 24px; +} +.ico-gg-eye-alt::before { + width: 8px; + height: 8px; + border: 2px solid $grey-3; + bottom: 4px; + left: 8px; + background-color: $grey-3; +} + +.ico-gg-add { + box-sizing: border-box; + position: relative; + display: block; + color: $green-1; + width: 32px; + height: 32px; +} +.ico-gg-add::after, +.ico-gg-add::before { + content: ''; + display: block; + box-sizing: border-box; + position: absolute; + width: 14px; + height: 2px; + background: currentColor; + border-radius: 5px; + top: 8px; + left: 0px; +} +.ico-gg-add::after { + width: 2px; + height: 14px; + top: 2px; + left: 6px; +} + +.gg-eye-alt { + position: relative; + display: block; + width: 18px; + height: 12px; + border-bottom-right-radius: 100px; + border-bottom-left-radius: 100px; + overflow: hidden; + box-sizing: border-box; +} +.gg-eye-alt::after, +.gg-eye-alt::before { + content: ''; + display: block; + border-radius: 100px; + position: absolute; + box-sizing: border-box; +} +.gg-eye-alt::after { + top: 2px; + box-shadow: inset 0 -8px 0 2px, inset 0 0 0 2px; + width: 18px; + height: 18px; +} +.gg-eye-alt::before { + width: 2px; + height: 2px; + border: 2px solid black; + bottom: 3px; + left: 7px; + background-color: black; +} + +.ico-gg-check { + box-sizing: border-box; + position: relative; + display: block; + transform: scale(var(--ggs, 1)); + width: 22px; + height: 22px; + border: 1px solid transparent; + border-radius: 100px; + color: $white; +} +.ico-gg-check::after { + content: ''; + display: block; + box-sizing: border-box; + position: absolute; + left: 5px; + top: -3px; + width: 7px; + height: 12px; + border-width: 0 2px 2px 0; + border-style: solid; + transform-origin: bottom left; + transform: rotate(45deg); + color: $white; +} diff --git a/src/assets/scss/_z-index.scss b/src/assets/scss/_z-index.scss index fc1ca81b6c627868b3859b58b1ae03543000d7b1..956dfa77b40550d03a46a9d10462b65241e0dee6 100644 --- a/src/assets/scss/_z-index.scss +++ b/src/assets/scss/_z-index.scss @@ -1,3 +1,4 @@ +$map-selected-marker: 600; // Phone view $btn-phone-switch-map-list-z-index: 1002; $menu-phone-z-index: 1003; diff --git a/src/index.html b/src/index.html index 9a66f6a01e7f17fc1d3061b1201c188cb95bc409..78caed151ffbfd74023d064f96288f725cb686f8 100644 --- a/src/index.html +++ b/src/index.html @@ -11,10 +11,11 @@ <meta name="title" content="Rés'In | Réseau des acteurs de l'inclusion numérique de la métropole de Lyon" /> <meta name="description" - content="Retrouver tous les lieux de la médiation numérique de la métropole mais aussi les actualités, projets, ressources, études et appels à projet liès à l'inclusion numérique..." + content="Dédiée aux acteurs de l'inclusion numérique de la Métropole de Lyon, Rés'IN recense tous les lieux qui propose une offre de médiation numérique sur le territoire et vise à permettre une meilleure orientation des usagers. Actualités, appels à projets, outils et ressources en ligne sont également proposés pour faciliter l'accompagnement des personnes en fragilité numérique." /> <meta name="image" content="https://resin.grandlyon.com/assets/logos/resin-logo-1024x512.png" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> + <meta name="google-site-verification" content="gam2SZSqu_MO1xoHwcvhqPCXNsXf60qxXPalwPVKfLM" /> <!-- Open Graph general --> <meta property="og:title" content="Rés'In | Réseau des acteurs de l'inclusion numérique de la métropole de Lyon" />