diff --git a/.env.example b/.env.example index 37b401bb..21f4903a 100644 --- a/.env.example +++ b/.env.example @@ -39,8 +39,6 @@ NEXT_PUBLIC_DOCAPOSTE_API_URL= NEXT_PUBLIC_API_URL=https://dev4.4nkweb.com/api NEXT_PUBLIC_DEFAULT_VALIDATOR_ID=28c9a3a8151bef545ebf700ca5222c63d0031ad593097e95c1de202464304a99 NEXT_PUBLIC_DEFAULT_STORAGE_URLS=https://dev4.4nkweb.com/storage -NEXT_PUBLIC_HOTJAR_SITE_ID=0 -NEXT_PUBLIC_HOTJAR_VERSION= SIGNER_BASE_URL=https://dev3.4nkweb.com/signer/ # WS diff --git a/docs/analyse.md b/docs/analyse.md new file mode 100644 index 00000000..cc1ba780 --- /dev/null +++ b/docs/analyse.md @@ -0,0 +1,44 @@ +### Objet +Analyse synthétique de `lecoffre-front` (Next.js) : périmètre, dépendances, configuration, intégrations et points d’attention. + +### Périmètre et stack +- **Framework**: Next.js 14 (React 18), rendu côté serveur désactivable selon pages +- **Langage**: TypeScript +- **Styles**: SCSS + MUI (@mui/material), Emotion +- **Bundle**: `output: 'standalone'`, `basePath: '/lecoffre'` + +### Arborescence notable +- **`src/front/`**: API client (services, entités, SDK) et composants UI (DesignSystem, Layouts, Elements) +- **`pages/`**: routes Next (tableau client, gestion utilisateurs, dossiers, documents, souscriptions) +- **`src/common/Api/LeCoffreApi`**: modules Admin/Customer/Notary/SuperAdmin et `sdk` +- **`src/front/Stores/`**: stores locaux (User, Customer, Window, Toasts) +- **`src/front/Services/`**: services utilitaires (JWT, PDF, Watermark, Crypto, Cookie) + +### Configuration et variables +- **`next.config.js`**: publie `NEXT_PUBLIC_*` aux clients et serveur; `reactStrictMode: false`; `ignoreBuildErrors: true` +- **BasePath**: `/lecoffre` (impacte le routage et les assets) +- **Intégrations**: Hotjar, GTM, Docaposte, 4NK (iframe/URL), Idnot (OAuth) + +### Dépendances clés +- **UI**: `@mui/material`, `@emotion/*`, `react-select`, `react-toastify` +- **Utilitaires**: `jwt-decode`, `file-saver`, `jszip`, `pdf-lib`, `sass`, `sharp` +- **Ressources**: `le-coffre-resources` (dépôt Git 4NK) + +### Intégrations externes (indiciaires) +- **Back**: via `NEXT_PUBLIC_BACK_API_*` et `NEXT_PUBLIC_API_URL` +- **Idnot**: endpoints OAuth (authorize, base_url, redirect_uri) +- **Docaposte**: `NEXT_PUBLIC_DOCAPOSTE_API_URL` + +### Points d’attention +- **TypeScript**: `ignoreBuildErrors: true` masque des erreurs de typage +- **BasePath**: vérifier la cohérence côté Nginx et lors du déploiement +- **Ressources Git**: accès SSH requis pour `le-coffre-resources` +- **Sécurité**: exposition de multiples `NEXT_PUBLIC_*` (vérifier qu’aucun secret n’est divulgué) + +### Tests et qualité +- **Scripts**: `build` sans lint, `lint` séparé, `format` ciblé `src/` +- **`tests/`**: présent (à enrichir avec scénarios e2e/smoke sur pages principales) + +### Déploiement +- **Dockerfile**: présent (build Next standalone) +- **Intégration**: orchestré via `lecoffre_node` (voir analyse dédiée) diff --git a/next.config.js b/next.config.js index b5dd7383..a0616746 100644 --- a/next.config.js +++ b/next.config.js @@ -21,8 +21,6 @@ const nextConfig = { NEXT_PUBLIC_IDNOT_BASE_URL: process.env.NEXT_PUBLIC_IDNOT_BASE_URL, NEXT_PUBLIC_IDNOT_REDIRECT_URI: process.env.NEXT_PUBLIC_IDNOT_REDIRECT_URI, NEXT_PUBLIC_DOCAPOSTE_API_URL: process.env.NEXT_PUBLIC_DOCAPOSTE_API_URL, - NEXT_PUBLIC_HOTJAR_SITE_ID: process.env.NEXT_PUBLIC_HOTJAR_SITE_ID, - NEXT_PUBLIC_HOTJAR_VERSION: process.env.NEXT_PUBLIC_HOTJAR_VERSION, NEXT_PUBLIC_4NK_URL: process.env.NEXT_PUBLIC_4NK_URL, NEXT_PUBLIC_4NK_IFRAME_URL: process.env.NEXT_PUBLIC_4NK_IFRAME_URL, NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, @@ -43,8 +41,6 @@ const nextConfig = { NEXT_PUBLIC_IDNOT_BASE_URL: process.env.NEXT_PUBLIC_IDNOT_BASE_URL, NEXT_PUBLIC_IDNOT_REDIRECT_URI: process.env.NEXT_PUBLIC_IDNOT_REDIRECT_URI, NEXT_PUBLIC_DOCAPOSTE_API_URL: process.env.NEXT_PUBLIC_DOCAPOSTE_API_URL, - NEXT_PUBLIC_HOTJAR_SITE_ID: process.env.NEXT_PUBLIC_HOTJAR_SITE_ID, - NEXT_PUBLIC_HOTJAR_VERSION: process.env.NEXT_PUBLIC_HOTJAR_VERSION, NEXT_PUBLIC_4NK_URL: process.env.NEXT_PUBLIC_4NK_URL, NEXT_PUBLIC_4NK_IFRAME_URL: process.env.NEXT_PUBLIC_4NK_IFRAME_URL, NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, @@ -65,8 +61,6 @@ const nextConfig = { NEXT_PUBLIC_IDNOT_BASE_URL: process.env.NEXT_PUBLIC_IDNOT_BASE_URL, NEXT_PUBLIC_IDNOT_REDIRECT_URI: process.env.NEXT_PUBLIC_IDNOT_REDIRECT_URI, NEXT_PUBLIC_DOCAPOSTE_API_URL: process.env.NEXT_PUBLIC_DOCAPOSTE_API_URL, - NEXT_PUBLIC_HOTJAR_SITE_ID: process.env.NEXT_PUBLIC_HOTJAR_SITE_ID, - NEXT_PUBLIC_HOTJAR_VERSION: process.env.NEXT_PUBLIC_HOTJAR_VERSION, NEXT_PUBLIC_4NK_URL: process.env.NEXT_PUBLIC_4NK_URL, NEXT_PUBLIC_4NK_IFRAME_URL: process.env.NEXT_PUBLIC_4NK_IFRAME_URL, NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, diff --git a/package.json b/package.json index 1c92da65..b294be8a 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-gtm-module": "^2.0.11", - "react-hotjar": "^6.3.1", + "react-select": "^5.7.2", "react-toastify": "^9.1.3", "sass": "^1.59.2", diff --git a/src/front/Api/BaseApiService.ts b/src/front/Api/BaseApiService.ts index 062b82cc..4a499d65 100644 --- a/src/front/Api/BaseApiService.ts +++ b/src/front/Api/BaseApiService.ts @@ -16,13 +16,15 @@ export default abstract class BaseApiService { protected readonly variables = FrontendVariables.getInstance(); protected constructor() { - BaseApiService.baseUrl ??= - this.variables.BACK_API_PROTOCOL + - this.variables.BACK_API_HOST + - ':' + - this.variables.BACK_API_PORT + - this.variables.BACK_API_ROOT_URL + - this.variables.BACK_API_VERSION; + if (!BaseApiService.baseUrl) { + const protocol = (this.variables.BACK_API_PROTOCOL || '').replace(/:\/\/$/, ''); + const host = (this.variables.BACK_API_HOST || '').replace(/\/$/, ''); + const port = this.variables.BACK_API_PORT ? `:${this.variables.BACK_API_PORT.replace(/^:/, '')}` : ''; + const root = `/${(this.variables.BACK_API_ROOT_URL || '')}`.replace(/\/+/g, '/').replace(/\/$/, ''); + const version = `/${(this.variables.BACK_API_VERSION || '')}`.replace(/\/+/g, '/'); + + BaseApiService.baseUrl = `${protocol}://${host}${port}${root}${version}`; + } } protected getBaseUrl(): string { diff --git a/src/front/Components/Layouts/Login/StepEmail/index.tsx b/src/front/Components/Layouts/Login/StepEmail/index.tsx index 1598e87b..c09e223a 100644 --- a/src/front/Components/Layouts/Login/StepEmail/index.tsx +++ b/src/front/Components/Layouts/Login/StepEmail/index.tsx @@ -117,13 +117,12 @@ export default function StepEmail(props: IProps) { showCancelButton={false} onAccept={closeErrorModal} closeBtn - header={"Abonnement Manquant"} - confirmText={"Fermer"}> + header={"Problème de connexion"} + confirmText={"Fermer"}>
- - Vous ne disposez pas d'un abonnement actif. Veuillez demander au référent de votre étude de souscrire à un - abonnement pour activer cette fonctionnalité. Pour toute question, contactez-nous à support@lecoffre.io. - + + Une erreur est survenue lors de la connexion. Veuillez réessayer ou contacter le support si le problème persiste. + Contactez le support diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index c86ffe22..4597a416 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -6,7 +6,6 @@ import type { AppType, AppProps } from "next/app"; import { useEffect, useState, type ReactElement, type ReactNode } from "react"; import getConfig from "next/config"; import { GoogleTagManager } from "@next/third-parties/google"; -import { hotjar } from "react-hotjar"; import Loader from "src/common/Api/LeCoffreApi/sdk/Loader"; @@ -35,8 +34,6 @@ type AppPropsWithLayout = AppProps & { fcAuthorizeEndpoint: string; fcClientId: string; docaposteApiUrl: string; - hotjarSiteId: number; - hotjarVersion: number; _4nkUrl: string; _4nkIframeUrl?: string; apiUrl: string; @@ -59,8 +56,6 @@ const MyApp = (({ fcAuthorizeEndpoint, fcClientId, docaposteApiUrl, - hotjarSiteId, - hotjarVersion, _4nkUrl, apiUrl, }: AppPropsWithLayout) => { @@ -80,8 +75,6 @@ const MyApp = (({ instance.FC_AUTHORIZE_ENDPOINT = fcAuthorizeEndpoint; instance.FC_CLIENT_ID = fcClientId; instance.DOCAPOST_API_URL = docaposteApiUrl; - instance.HOTJAR_SITE_ID = hotjarSiteId; - instance.HOTJAR_VERSION = hotjarVersion; instance._4NK_URL = _4nkUrl; instance.API_URL = apiUrl; @@ -124,17 +117,7 @@ const MyApp = (({ return () => { }; }, []); - useEffect(() => { - if (!hotjarSiteId || !hotjarVersion) { - console.warn("No hotjar site id or version provided"); - return; - } - console.log("Intializing hotjar"); - hotjar.initialize({ - id: hotjarSiteId, - sv: hotjarVersion, - }); - }, [hotjarSiteId, hotjarVersion]); + // Hotjar supprimé return getLayout( <> @@ -165,8 +148,6 @@ MyApp.getInitialProps = async () => { fcAuthorizeEndpoint: publicRuntimeConfig.NEXT_PUBLIC_FC_AUTHORIZE_ENDPOINT, fcClientId: publicRuntimeConfig.NEXT_PUBLIC_FC_CLIENT_ID, docaposteApiUrl: publicRuntimeConfig.NEXT_PUBLIC_DOCAPOST_API_URL, - hotjarSiteId: publicRuntimeConfig.NEXT_PUBLIC_HOTJAR_SITE_ID, - hotjarVersion: publicRuntimeConfig.NEXT_PUBLIC_HOTJAR_VERSION, _4nkUrl: publicRuntimeConfig.NEXT_PUBLIC_4NK_URL, _4nkIframeUrl: publicRuntimeConfig.NEXT_PUBLIC_4NK_IFRAME_URL, apiUrl: publicRuntimeConfig.NEXT_PUBLIC_API_URL, diff --git a/tests/analyse.md b/tests/analyse.md new file mode 100644 index 00000000..8e473e84 --- /dev/null +++ b/tests/analyse.md @@ -0,0 +1,26 @@ +### Objet +Axes de tests pour `lecoffre-front` (sans exemples d’implémentation). + +### Couverture prioritaire +- **Routage**: accessibilité des pages clés sous `basePath` `/lecoffre` +- **Auth**: parcours login client et callbacks (Id360/IdNot) +- **Tableau client**: chargement données, états vides, erreurs +- **Dossiers/Documents**: création/affichage, téléchargements, filigrane +- **Souscription**: parcours complet (erreur/succès/gestion) +- **Notifications/Toasts**: affichage cohérent des erreurs + +### Données et intégrations +- **API Back**: validation des URL via `NEXT_PUBLIC_BACK_API_*` et `NEXT_PUBLIC_API_URL` +- **Idnot/Docaposte**: vérification des redirections et scopes + +### Non-régressions UI/UX +- **DesignSystem**: composants critiques (boutons, tabs, formulaires) +- **Accessibilité**: focus, contrastes, navigation clavier + +### Performance +- **Chargement initial**: taille bundle avec `React.lazy`/`Suspense` si applicable +- **Rendu**: éviter re-renders via stores et mémoïsations locales + +### Sécurité +- **Données sensibles**: absence de secrets dans `NEXT_PUBLIC_*` +- **JWT**: décodage côté client limité aux besoins