diff --git a/package-lock.json b/package-lock.json index c29f24b2..0f49a8ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "eslint-config-next": "13.2.4", "form-data": "^4.0.0", "jwt-decode": "^3.1.2", - "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.89", + "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.90", "next": "13.2.4", "prettier": "^2.8.7", "react": "18.2.0", @@ -496,14 +496,14 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, "node_modules/@mui/base": { - "version": "5.0.0-beta.17", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.17.tgz", - "integrity": "sha512-xNbk7iOXrglNdIxFBN0k3ySsPIFLWCnFxqsAYl7CIcDkD9low4kJ7IUuy6ctwx/HAy2fenrT3KXHr1sGjAMgpQ==", + "version": "5.0.0-beta.18", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.18.tgz", + "integrity": "sha512-e9ZCy/ndhyt5MTshAS3qAUy/40UiO0jX+kAo6a+XirrPJE+rrQW+mKPSI0uyp+5z4Vh+z0pvNoJ2S2gSrNz3BQ==", "dependencies": { - "@babel/runtime": "^7.22.15", + "@babel/runtime": "^7.23.1", "@floating-ui/react-dom": "^2.0.2", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.11", + "@mui/types": "^7.2.5", + "@mui/utils": "^5.14.12", "@popperjs/core": "^2.11.8", "clsx": "^2.0.0", "prop-types": "^15.8.1" @@ -527,25 +527,25 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.14.11", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.11.tgz", - "integrity": "sha512-uY8FLQURhXe3f3O4dS5OSGML9KDm9+IE226cBu78jarVIzdQGPlXwGIlSI9VJR8MvZDA6C0+6XfWDhWCHruC5Q==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.12.tgz", + "integrity": "sha512-WZhCkKqhrXaSVBzoC6LNcVkIawS000OOt7gmnp4g9HhyvN0PSclRXc/JrkC7EwfzUAZJh+hiK2LaVsbtOpNuOg==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui" } }, "node_modules/@mui/material": { - "version": "5.14.11", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.11.tgz", - "integrity": "sha512-DnSdJzcR7lwG12JA5L2t8JF+RDzMygu5rCNW+logWb/KW2/TRzwLyVWO+CorHTBjBRd38DBxnwOCDiYkDd+N3A==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.12.tgz", + "integrity": "sha512-EelF2L46VcVqhg3KjzIGBBpOtcBgRh0MMy9Efuk6Do81QdcZsFC9RebCVAflo5jIdbHiBmxBs5/l5Q9NjONozg==", "dependencies": { - "@babel/runtime": "^7.22.15", - "@mui/base": "5.0.0-beta.17", - "@mui/core-downloads-tracker": "^5.14.11", - "@mui/system": "^5.14.11", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.11", + "@babel/runtime": "^7.23.1", + "@mui/base": "5.0.0-beta.18", + "@mui/core-downloads-tracker": "^5.14.12", + "@mui/system": "^5.14.12", + "@mui/types": "^7.2.5", + "@mui/utils": "^5.14.12", "@types/react-transition-group": "^4.4.6", "clsx": "^2.0.0", "csstype": "^3.1.2", @@ -580,12 +580,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.14.11", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.11.tgz", - "integrity": "sha512-MSnNNzTu9pfKLCKs1ZAKwOTgE4bz+fQA0fNr8Jm7NDmuWmw0CaN9Vq2/MHsatE7+S0A25IAKby46Uv1u53rKVQ==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.12.tgz", + "integrity": "sha512-TWwm+9+BgHFpoR3w04FG+IqID4ALa74A27RuKq2CEaWgxliBZB24EVeI6djfjFt5t4FYmIb8BMw2ZJEir7YjLQ==", "dependencies": { - "@babel/runtime": "^7.22.15", - "@mui/utils": "^5.14.11", + "@babel/runtime": "^7.23.1", + "@mui/utils": "^5.14.12", "prop-types": "^15.8.1" }, "engines": { @@ -606,11 +606,11 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.14.11", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.11.tgz", - "integrity": "sha512-jdUlqRgTYQ8RMtPX4MbRZqar6W2OiIb6J5KEFbIu4FqvPrk44Each4ppg/LAqp1qNlBYq5i+7Q10MYLMpDxX9A==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.12.tgz", + "integrity": "sha512-bocxt1nDmXfB3gpLfCCmFCyJ7sVmscFs+PuheO210QagZwHVp47UIRT1AiswLDYSQo1ZqmVGn7KLEJEYK0d4Xw==", "dependencies": { - "@babel/runtime": "^7.22.15", + "@babel/runtime": "^7.23.1", "@emotion/cache": "^11.11.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -637,15 +637,15 @@ } }, "node_modules/@mui/system": { - "version": "5.14.11", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.11.tgz", - "integrity": "sha512-yl8xV+y0k7j6dzBsHabKwoShmjqLa8kTxrhUI3JpqLG358VRVMJRW/ES0HhvfcCi4IVXde+Tc2P3K1akGL8zoA==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.12.tgz", + "integrity": "sha512-6DXfjjLhW0/ia5qU3Crke7j+MnfDbMBOHlLIrqbrEqNs0AuSBv8pXniEGb+kqO0H804NJreRTEJRjCngwOX5CA==", "dependencies": { - "@babel/runtime": "^7.22.15", - "@mui/private-theming": "^5.14.11", - "@mui/styled-engine": "^5.14.11", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.14.11", + "@babel/runtime": "^7.23.1", + "@mui/private-theming": "^5.14.12", + "@mui/styled-engine": "^5.14.12", + "@mui/types": "^7.2.5", + "@mui/utils": "^5.14.12", "clsx": "^2.0.0", "csstype": "^3.1.2", "prop-types": "^15.8.1" @@ -676,11 +676,11 @@ } }, "node_modules/@mui/types": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz", - "integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.5.tgz", + "integrity": "sha512-S2BwfNczr7VwS6ki8GoAXJyARoeSJDLuxOEPs3vEMyTALlf9PrdHv+sluX7kk3iKrCg/ML2mIWwapZvWbkMCQA==", "peerDependencies": { - "@types/react": "*" + "@types/react": "^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -689,12 +689,12 @@ } }, "node_modules/@mui/utils": { - "version": "5.14.11", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.11.tgz", - "integrity": "sha512-fmkIiCPKyDssYrJ5qk+dime1nlO3dmWfCtaPY/uVBqCRMBZ11JhddB9m8sjI2mgqQQwRJG5bq3biaosNdU/s4Q==", + "version": "5.14.12", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.12.tgz", + "integrity": "sha512-RFNXnhKQlzIkIUig6mmv0r5VbtjPdWoaBPYicq25LETdZux59HAqoRdWw15T7lp3c7gXOoE8y67+hTB8C64m2g==", "dependencies": { - "@babel/runtime": "^7.22.15", - "@types/prop-types": "^15.7.5", + "@babel/runtime": "^7.23.1", + "@types/prop-types": "^15.7.7", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -1507,9 +1507,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001543", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001543.tgz", - "integrity": "sha512-qxdO8KPWPQ+Zk6bvNpPeQIOH47qZSYdFZd6dXQzb2KzhnSXju4Kd7H1PkSJx6NICSMgo/IhRZRhhfPTHYpJUCA==", + "version": "1.0.30001546", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz", + "integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==", "funding": [ { "type": "opencollective", @@ -2518,11 +2518,11 @@ } }, "node_modules/flat-cache": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", - "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", + "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", "dependencies": { - "flatted": "^3.2.7", + "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" }, @@ -2685,9 +2685,9 @@ } }, "node_modules/globals": { - "version": "13.22.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz", - "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dependencies": { "type-fest": "^0.20.2" }, @@ -2764,12 +2764,9 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" }, "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", "engines": { "node": ">= 0.4.0" } @@ -3340,9 +3337,9 @@ "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" }, "node_modules/keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dependencies": { "json-buffer": "3.0.1" } @@ -3361,7 +3358,7 @@ } }, "node_modules/le-coffre-resources": { - "resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#a100398ef5c1984ba74cb1c8c182648315accc3e", + "resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#16baf46d39953bb19fa5b9e614ae4f72895aff31", "license": "MIT", "dependencies": { "class-transformer": "^0.5.1", @@ -3382,9 +3379,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.10.45", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.45.tgz", - "integrity": "sha512-eeHcvGafEYCaKB4fo2uBINfG7j7PcGwBHUaTVfbwl/6KcjCgIKNlIOsSXVRp9BH10NQwmvvk+nQ1e/Yp4BGB7w==" + "version": "1.10.47", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.47.tgz", + "integrity": "sha512-b4t7VQDV29xx/ni+58yl9KWPGjnDLDXCeCTLrD4V8vDpObXZRZBrg7uX/HWZ7YXiJKqdBDGgc+barUUTNB6Slw==" }, "node_modules/lines-and-columns": { "version": "1.2.4", @@ -4297,9 +4294,9 @@ } }, "node_modules/sass": { - "version": "1.68.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.68.0.tgz", - "integrity": "sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==", + "version": "1.69.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.0.tgz", + "integrity": "sha512-l3bbFpfTOGgQZCLU/gvm1lbsQ5mC/WnLz3djL2v4WCJBDrWm58PO+jgngcGRNnKUh6wSsdm50YaovTqskZ0xDQ==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", diff --git a/package.json b/package.json index 7d306a4d..9d3fba5b 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "eslint-config-next": "13.2.4", "form-data": "^4.0.0", "jwt-decode": "^3.1.2", - "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.89", + "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.90", "next": "13.2.4", "prettier": "^2.8.7", "react": "18.2.0", diff --git a/src/front/Api/Auth/IdNot/User.ts b/src/front/Api/Auth/IdNot/User.ts index 96c54a77..1854979a 100644 --- a/src/front/Api/Auth/IdNot/User.ts +++ b/src/front/Api/Auth/IdNot/User.ts @@ -27,7 +27,6 @@ export default class User extends BaseApiService { } public async verifyJwt(jwt: string) { - console.log(this.baseURl); const url = new URL(`${this.baseURl}/verify-token/${jwt}`); try { return await this.postRequest(url); diff --git a/src/front/Api/Auth/IdNot/index.ts b/src/front/Api/Auth/IdNot/index.ts index 58cd9933..b358b6c8 100644 --- a/src/front/Api/Auth/IdNot/index.ts +++ b/src/front/Api/Auth/IdNot/index.ts @@ -16,7 +16,6 @@ export default class Auth extends BaseApiService { public async logOutWithIdNot() { const variables = FrontendVariables.getInstance(); const url = new URL(`${variables.IDNOT_BASE_URL}/user/auth/logout?post_logout_redirect_uri=${variables.FRONT_APP_HOST}`); - console.log(url.toString()) try { return await fetch(url); } catch (err) { diff --git a/src/front/Api/LeCoffreApi/Notary/Documents/Documents.ts b/src/front/Api/LeCoffreApi/Notary/Documents/Documents.ts index 45e68b9e..3edc218b 100644 --- a/src/front/Api/LeCoffreApi/Notary/Documents/Documents.ts +++ b/src/front/Api/LeCoffreApi/Notary/Documents/Documents.ts @@ -71,6 +71,18 @@ export default class Documents extends BaseNotary { } } + public async refuse(uid: string, refused_reason: string): Promise { + const url = new URL(this.baseURl.concat(`/${uid}/refuse`)); + try { + return await this.putRequest(url, { + refused_reason, + }); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + public async put(uid: string, body: IPutDocumentsParams): Promise { const url = new URL(this.baseURl.concat(`/${uid}`)); try { diff --git a/src/front/Api/LeCoffreApi/Notary/Folders/Folders.ts b/src/front/Api/LeCoffreApi/Notary/Folders/Folders.ts index 800d3c96..b7aa1342 100644 --- a/src/front/Api/LeCoffreApi/Notary/Folders/Folders.ts +++ b/src/front/Api/LeCoffreApi/Notary/Folders/Folders.ts @@ -1,7 +1,6 @@ import { type OfficeFolder } from "le-coffre-resources/dist/Notary"; import BaseNotary from "../BaseNotary"; -import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus"; // TODO Type get query params -> Where + inclue + orderby export interface IGetFoldersParams { @@ -97,20 +96,32 @@ export default class Folders extends BaseNotary { } } - public async archive(uid: string, body: Partial): Promise { - body.status = EFolderStatus.ARCHIVED; + public async archive(uid: string, archived_description: string): Promise { try { - return await this.put(uid, body); + const url = new URL(this.baseURl.concat(`/${uid}/archive`)); + try { + return await this.putRequest(url, { + archived_description, + }); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } } catch (err) { this.onError(err); return Promise.reject(err); } } - public async restore(uid: string, body: Partial): Promise { - body.status = EFolderStatus.LIVE; + public async restore(uid: string): Promise { try { - return await this.put(uid, body); + const url = new URL(this.baseURl.concat(`/${uid}/restore`)); + try { + return await this.putRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } } catch (err) { this.onError(err); return Promise.reject(err); diff --git a/src/front/Components/DesignSystem/DepositOtherDocument/index.tsx b/src/front/Components/DesignSystem/DepositOtherDocument/index.tsx index 7d84c26b..d2192944 100644 --- a/src/front/Components/DesignSystem/DepositOtherDocument/index.tsx +++ b/src/front/Components/DesignSystem/DepositOtherDocument/index.tsx @@ -121,7 +121,6 @@ export default class DepositOtherDocument extends React.Component 0 && (
{this.state.currentFiles.map((file) => { - console.log(file); const fileObj = file.file; @@ -237,9 +236,6 @@ export default class DepositOtherDocument extends React.Component file.index === parseInt(indexToRemove)); diff --git a/src/front/Components/DesignSystem/FolderBoxInformation/index.tsx b/src/front/Components/DesignSystem/FolderBoxInformation/index.tsx index a2e95014..48529ede 100644 --- a/src/front/Components/DesignSystem/FolderBoxInformation/index.tsx +++ b/src/front/Components/DesignSystem/FolderBoxInformation/index.tsx @@ -8,11 +8,13 @@ import React from "react"; import Typography, { ITypo } from "../Typography"; import classes from "./classes.module.scss"; +import { AnchorStatus } from "@Front/Components/Layouts/Folder/FolderInformation"; type IProps = { folder: OfficeFolder; type: EFolderBoxInformationType; isArchived?: boolean; + anchorStatus: AnchorStatus; }; export enum EFolderBoxInformationType { @@ -34,7 +36,7 @@ export default function FolderBoxInformation(props: IProps) { return (
{renderContentByType(props.folder, type)}
- {!isArchived && ( + {!isArchived && props.anchorStatus === AnchorStatus.NOT_ANCHORED && ( edit informations diff --git a/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/classes.module.scss b/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/classes.module.scss index b8af1a78..1e7bcdf7 100644 --- a/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/classes.module.scss +++ b/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/classes.module.scss @@ -30,6 +30,17 @@ cursor: pointer; } } + + .notification-subheader { + display: flex; + align-items: center; + gap: 8px; + text-decoration: underline; + text-underline-offset: 2px; + color: var(--pink-flash); + cursor: pointer; + } + .notification-body { margin-top: 24px; overflow: hidden; diff --git a/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/index.tsx b/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/index.tsx index e0a9c9d1..56c15f11 100644 --- a/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/index.tsx +++ b/src/front/Components/DesignSystem/Header/Notifications/NotificationModal/index.tsx @@ -5,6 +5,7 @@ import CloseIcon from "@Assets/Icons/cross.svg"; import Image from "next/image"; import ToastHandler from "@Front/Components/DesignSystem/Toasts/ToastsHandler"; import Toasts, { IToast } from "@Front/Stores/Toasts"; +import Check from "@Front/Components/Elements/Icons/Check"; type IProps = { isOpen: boolean; @@ -23,6 +24,7 @@ export default class NotificationModal extends React.Component { toastList: Toasts.getInstance().toasts, }; this.handleToastChange = this.handleToastChange.bind(this); + this.readAllNotifications = this.readAllNotifications.bind(this); } public override render(): JSX.Element | null { @@ -37,10 +39,15 @@ export default class NotificationModal extends React.Component { Close notification modal
- ; +
+ + Tout marquer comme lu + + +
<> - {Toasts.getInstance().toasts.length === 0 ? ( + {!this.state.toastList || this.state.toastList.length === 0 ? (
Vous n'avez pas de notifications. @@ -64,6 +71,11 @@ export default class NotificationModal extends React.Component { this.removeOnToastChange(); } + private readAllNotifications() { + Toasts.getInstance().closeAll(); + this.props.closeModal(); + } + private handleToastChange(toastList: IToast[] | null) { this.setState({ toastList, diff --git a/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/classes.module.scss b/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/classes.module.scss index ee50f75c..73aceb7f 100644 --- a/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/classes.module.scss +++ b/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/classes.module.scss @@ -95,6 +95,7 @@ font-size: 14px; line-height: 20px; color: var(--color-neutral-500); + word-break: break-word; } a { diff --git a/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/index.tsx b/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/index.tsx index 8474ef5e..834009ad 100644 --- a/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/index.tsx +++ b/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/index.tsx @@ -109,7 +109,6 @@ class ToastElementClass extends React.Component { } private async handleClick(e: React.MouseEvent) { - console.log('redirectUrl', this.props.toast.redirectUrl); if (this.props.toast.redirectUrl) { this.onClose(e); await this.props.router.push(this.props.toast.redirectUrl); diff --git a/src/front/Components/DesignSystem/UserFolder/classes.module.scss b/src/front/Components/DesignSystem/UserFolder/classes.module.scss index ecaffe07..453861ac 100644 --- a/src/front/Components/DesignSystem/UserFolder/classes.module.scss +++ b/src/front/Components/DesignSystem/UserFolder/classes.module.scss @@ -54,7 +54,8 @@ .content { display: grid; grid-template-columns: 1fr 1fr; - gap: 64px; + column-gap: 64px; + row-gap: 16px; margin-top: 32px; @media (max-width: $screen-s) { @@ -63,7 +64,7 @@ flex-direction: column; } - .documents-asked{ + .documents-asked { order: -1; } @@ -73,7 +74,7 @@ gap: 32px; margin-top: 16px; - @media(max-width: $screen-s){ + @media (max-width: $screen-s) { order: -1; } } diff --git a/src/front/Components/DesignSystem/UserFolder/index.tsx b/src/front/Components/DesignSystem/UserFolder/index.tsx index 3e2ca7da..0ff66682 100644 --- a/src/front/Components/DesignSystem/UserFolder/index.tsx +++ b/src/front/Components/DesignSystem/UserFolder/index.tsx @@ -16,6 +16,7 @@ import QuantityProgressBar from "../QuantityProgressBar"; import classes from "./classes.module.scss"; import DocumentList from "./DocumentList"; import UserFolderHeader from "./UserFolderHeader"; +import { AnchorStatus } from "@Front/Components/Layouts/Folder/FolderInformation"; type IProps = { customer: Customer; @@ -24,6 +25,8 @@ type IProps = { isArchived?: boolean; isOpened: boolean; onChange: (id: string) => void; + anchorStatus: AnchorStatus; + getFolderCallback: () => Promise; }; type IState = { isOpenDeletionModal: boolean; @@ -89,32 +92,44 @@ export default class UserFolder extends React.Component { currentNumber={this.calculateDocumentsPercentageProgress()} />
- + {this.props.anchorStatus === AnchorStatus.NOT_ANCHORED && ( + + )} + 0 - ? "Vous avez des documents à valider." + ? this.props.anchorStatus !== AnchorStatus.NOT_ANCHORED + ? "" + : "Vous avez des documents à valider." : "Vous n'avez aucun document à valider" } openDeletionModal={this.openDeletionModal} folderUid={this.props.folder.uid!} /> - {!this.props.isArchived && ( + + {!this.props.isArchived && this.props.anchorStatus === AnchorStatus.NOT_ANCHORED && (
-
)}
@@ -131,7 +146,7 @@ export default class UserFolder extends React.Component { private async deleteAskedDocument() { try { await Documents.getInstance().delete(this.state.selectedDocumentToDelete); - window.location.reload(); + await this.props.getFolderCallback(); } catch (e) { console.error(e); } diff --git a/src/front/Components/Elements/Icons/Check/index.tsx b/src/front/Components/Elements/Icons/Check/index.tsx new file mode 100644 index 00000000..b3ec1825 --- /dev/null +++ b/src/front/Components/Elements/Icons/Check/index.tsx @@ -0,0 +1,19 @@ +import { ITypoColor } from "@Front/Components/DesignSystem/Typography"; + +type IProps = { + color?: ITypoColor; +}; + +export default function Check(props: IProps) { + return ( + + + + ); +} diff --git a/src/front/Components/Layouts/ClientDashboard/index.tsx b/src/front/Components/Layouts/ClientDashboard/index.tsx index 5e1d82b6..1f7bce1e 100644 --- a/src/front/Components/Layouts/ClientDashboard/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/index.tsx @@ -19,6 +19,7 @@ export default function ClientDashboard(props: IProps) { const router = useRouter(); let { folderUid } = router.query; const [documents, setDocuments] = useState(null); + const [customer, setCustomer] = useState(null); const [folder, setFolder] = useState(null); const [isAddDocumentModalVisible, setIsAddDocumentModalVisible] = useState(false); diff --git a/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx b/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx index 8aa0c509..ddf1418d 100644 --- a/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx +++ b/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx @@ -10,13 +10,14 @@ import BackArrow from "@Front/Components/Elements/BackArrow"; import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; import Module from "@Front/Config/Module"; import { ECivility } from "le-coffre-resources/dist/Customer/Contact"; -import { Customer, OfficeFolder } from "le-coffre-resources/dist/Notary"; +import { Contact, Customer, OfficeFolder } from "le-coffre-resources/dist/Notary"; import Link from "next/link"; import { NextRouter, useRouter } from "next/router"; import BasePage from "../../Base"; import classes from "./classes.module.scss"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; +import { ValidationError } from "class-validator"; enum ESelectedOption { EXISTING_CUSTOMER = "existing_customer", @@ -29,6 +30,7 @@ type IState = { selectedCustomers: readonly IOption[]; existingCustomers: IOption[]; isLoaded: boolean; + validationError: ValidationError[]; }; type IPropsClass = IProps & { @@ -44,6 +46,7 @@ class AddClientToFolderClass extends BasePage { selectedCustomers: [], existingCustomers: [], isLoaded: false, + validationError: [], }; this.onExistingClientSelected = this.onExistingClientSelected.bind(this); this.onNewClientSelected = this.onNewClientSelected.bind(this); @@ -105,10 +108,28 @@ class AddClientToFolderClass extends BasePage { {this.state.selectedOption === "new_customer" && (
- - - - + error.property === "last_name")} + /> + error.property === "first_name")} + /> + error.property === "email")} + /> + error.property === "cell_phone_number", + )} + />
@@ -207,11 +228,29 @@ class AddClientToFolderClass extends BasePage { }) as Partial[]; if (this.state.selectedOption === "new_customer") { - const customer: Customer = await Customers.getInstance().post({ - contact: values, - }); - if (!customer.uid) return; - customersToLink?.push({ uid: customer.uid } as Partial); + try { + const contactToCreate = Contact.hydrate(values); + await contactToCreate.validateOrReject?.({ groups: ["createCustomer"], forbidUnknownValues: false }); + } catch (validationErrors) { + console.log(validationErrors); + this.setState({ + validationError: validationErrors as ValidationError[], + }); + return; + } + + try { + const customer: Customer = await Customers.getInstance().post({ + contact: values, + }); + if (!customer.uid) return; + customersToLink?.push({ uid: customer.uid } as Partial); + } catch (backError) { + if (!Array.isArray(backError)) return; + this.setState({ + validationError: backError as ValidationError[], + }); + } } if (customersToLink) { diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientSection/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientSection/index.tsx index 95e24b4d..15b06256 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientSection/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientSection/index.tsx @@ -8,9 +8,12 @@ import Link from "next/link"; import React from "react"; import classes from "./classes.module.scss"; +import { AnchorStatus } from ".."; type IProps = { folder: OfficeFolder; + anchorStatus: AnchorStatus; + getFolderCallback: () => Promise; }; type IState = { openedCustomer: string; @@ -35,11 +38,13 @@ export default class ClientSection extends React.Component { {this.doesFolderHaveCustomer() ? ( <>
{this.renderCustomerFolders()}
- - - + {this.props.anchorStatus === AnchorStatus.NOT_ANCHORED && ( + + + + )} ) : (
@@ -48,11 +53,13 @@ export default class ClientSection extends React.Component { Aucun client n'est associé au dossier.
- - - + {this.props.anchorStatus === AnchorStatus.NOT_ANCHORED && ( + + + + )}
)}
@@ -69,6 +76,8 @@ export default class ClientSection extends React.Component { key={customer.uid} isOpened={this.state.openedCustomer === customer.uid} onChange={this.changeUserFolder} + anchorStatus={this.props.anchorStatus} + getFolderCallback={this.props.getFolderCallback} /> ); }); diff --git a/src/front/Components/Layouts/Folder/FolderInformation/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/index.tsx index 9c116b19..2a17a3b7 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/index.tsx @@ -20,10 +20,9 @@ import ValidateAnchoringGif from "@Front/Assets/images/validate_anchoring.gif"; import BasePage from "../../Base"; import classes from "./classes.module.scss"; import ClientSection from "./ClientSection"; -import CheckBox from "@Front/Components/DesignSystem/CheckBox"; import Loader from "@Front/Components/DesignSystem/Loader"; -enum AnchorStatus { +export enum AnchorStatus { "VERIFIED_ON_CHAIN" = "VERIFIED_ON_CHAIN", "ANCHORING" = "ANCHORING", "NOT_ANCHORED" = "NOT_ANCHORED", @@ -38,6 +37,7 @@ type IPropsClass = IProps & { isLoading: boolean; selectedFolder: OfficeFolder | null; getAnchoringStatus: () => Promise; + getFolderCallback: () => Promise; }; type IState = { @@ -97,11 +97,13 @@ class FolderInformationClass extends BasePage {
@@ -113,10 +115,22 @@ class FolderInformationClass extends BasePage { currentNumber={this.getCompletionNumber()} />
- {this.doesFolderHaveCustomer() && } + {this.doesFolderHaveCustomer() && ( + + )}
- {!this.doesFolderHaveCustomer() && } + {!this.doesFolderHaveCustomer() && ( + + )}
)} {this.props.isAnchored === AnchorStatus.ANCHORING && ( @@ -204,7 +218,7 @@ class FolderInformationClass extends BasePage { onAccept={this.closePreventArchiveModal} onClose={this.closePreventArchiveModal} closeBtn - header={"Vous devez valider et certifier un dossier avant de pouvoir l'archiver"} + header={"Vous devez valider et ancrer un dossier avant de pouvoir l'archiver"} cancelText={"Annuler"} confirmText={"J'ai compris"}>
@@ -244,9 +258,6 @@ class FolderInformationClass extends BasePage { rédaction d'acte. Anchoring animation -
- -
)}
@@ -372,7 +383,7 @@ class FolderInformationClass extends BasePage { } private openArchivedModal(): void { - if (this.everyDocumentValidated() && this.props.isAnchored) { + if (this.everyDocumentValidated() && this.props.isAnchored === AnchorStatus.VERIFIED_ON_CHAIN) { this.setState({ isArchivedModalOpen: true }); } else { this.setState({ isPreventArchiveModalOpen: true }); @@ -389,9 +400,7 @@ class FolderInformationClass extends BasePage { private async onArchivedModalAccepted() { if (!this.props.selectedFolder) return; - const ressourceFolder = OfficeFolder.hydrate(this.props.selectedFolder); - ressourceFolder.archived_description = this.state.inputArchivedDescripton; - await Folders.getInstance().archive(this.props.selectedFolder.uid ?? "", ressourceFolder); + await Folders.getInstance().archive(this.props.selectedFolder.uid ?? "", this.state.inputArchivedDescripton); this.closeArchivedModal(); this.props.router.push(Module.getInstance().get().modules.pages.Folder.props.path); } @@ -471,6 +480,7 @@ export default function FolderInformation(props: IProps) { isLoading={isLoading} selectedFolder={selectedFolder} getAnchoringStatus={getAnchoringStatus} + getFolderCallback={getFolder} /> ); } diff --git a/src/front/Components/Layouts/Folder/UpdateClient/index.tsx b/src/front/Components/Layouts/Folder/UpdateClient/index.tsx index df51d182..2c19e02b 100644 --- a/src/front/Components/Layouts/Folder/UpdateClient/index.tsx +++ b/src/front/Components/Layouts/Folder/UpdateClient/index.tsx @@ -5,7 +5,7 @@ import TextField from "@Front/Components/DesignSystem/Form/TextField"; import Confirm from "@Front/Components/DesignSystem/Modal/Confirm"; import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography"; import BackArrow from "@Front/Components/Elements/BackArrow"; -import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; +import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; import Module from "@Front/Config/Module"; import { Contact, Customer, OfficeFolder } from "le-coffre-resources/dist/Notary"; import Link from "next/link"; @@ -14,6 +14,8 @@ import { ChangeEvent } from "react"; import BasePage from "../../Base"; import classes from "./classes.module.scss"; +import { Address } from "le-coffre-resources/dist/Customer"; +import { ValidationError } from "class-validator"; type IProps = {}; @@ -34,6 +36,7 @@ type IState = { inputAddress: string; folder: OfficeFolder | null; customer: Customer | null; + validationError: ValidationError[]; }; class UpdateClientClass extends BasePage { constructor(props: IPropsClass) { @@ -50,6 +53,7 @@ class UpdateClientClass extends BasePage { inputAddress: "", folder: null, customer: null, + validationError: [], }; this.onSelectedFolder = this.onSelectedFolder.bind(this); this.onChangeNameInput = this.onChangeNameInput.bind(this); @@ -83,24 +87,28 @@ class UpdateClientClass extends BasePage { placeholder="Nom" onChange={this.onChangeNameInput} defaultValue={this.state.customer?.contact?.first_name} + validationError={this.state.validationError.find((error) => error.property === "first_name")} /> error.property === "last_name")} /> error.property === "email")} /> error.property === "cell_phone_number")} /> { required={false} onChange={this.onChangeBirthDateInput} defaultValue={this.state.customer?.contact?.birthdate?.toString() ?? ""} + validationError={this.state.validationError.find((error) => error.property === "birthdate")} /> { [key: string]: string; }, ) { - const contact = { + const contact = Contact.hydrate({ first_name: values["first_name"], last_name: values["last_name"], email: values["email"], cell_phone_number: values["cell_phone_number"], - birthdate: values["birthdate"] === "" ? null : values["birthdate"], - address: - values["address"] === "" - ? null - : { - address: values["address"], - }, - } as Contact; + birthdate: values["birthdate"] === "" ? null : new Date(values["birthdate"]!), + address: values["address"] ? Address.hydrate
({ address: values["address"] }) : undefined, + }); + + try { + await contact.validateOrReject?.({ groups: ["createCustomer"], forbidUnknownValues: false }); + } catch (validationErrors) { + console.log(validationErrors); + this.setState({ + validationError: validationErrors as ValidationError[], + }); + return; + } try { await Customers.getInstance().put(this.props.customerUid, { contact }); this.props.router.push(this.backwardPath); - } catch (e) { - console.error(e); + } catch (backError) { + if (!Array.isArray(backError)) return; + this.setState({ + validationError: backError as ValidationError[], + }); } } diff --git a/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx b/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx index 3dc4d9d1..b84a18ec 100644 --- a/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx @@ -275,10 +275,7 @@ class ViewDocumentsClass extends BasePage { private async refuseDocument() { try { - await Documents.getInstance().put(this.props.documentUid, { - document_status: EDocumentStatus.REFUSED, - refused_reason: this.state.refuseText, - }); + await Documents.getInstance().refuse(this.props.documentUid, this.state.refuseText); this.props.router.push( Module.getInstance() diff --git a/src/front/Components/Layouts/FolderArchived/FolderInformation/ClientSection/index.tsx b/src/front/Components/Layouts/FolderArchived/FolderInformation/ClientSection/index.tsx index 2c2b7918..bd084620 100644 --- a/src/front/Components/Layouts/FolderArchived/FolderInformation/ClientSection/index.tsx +++ b/src/front/Components/Layouts/FolderArchived/FolderInformation/ClientSection/index.tsx @@ -3,9 +3,12 @@ import classes from "./classes.module.scss"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; import UserFolder from "@Front/Components/DesignSystem/UserFolder"; +import { AnchorStatus } from "@Front/Components/Layouts/Folder/FolderInformation"; type IProps = { folder: OfficeFolder; + anchorStatus: AnchorStatus; + getFolderCallback: () => Promise; }; type IState = { openedCustomer: string; @@ -49,7 +52,9 @@ export default class ClientSection extends React.Component { key={customer.uid} isOpened={this.state.openedCustomer === customer.uid} onChange={this.changeUserFolder} + anchorStatus={this.props.anchorStatus} isArchived + getFolderCallback={this.props.getFolderCallback} /> ); }); diff --git a/src/front/Components/Layouts/FolderArchived/FolderInformation/classes.module.scss b/src/front/Components/Layouts/FolderArchived/FolderInformation/classes.module.scss index a1052297..d3eba151 100644 --- a/src/front/Components/Layouts/FolderArchived/FolderInformation/classes.module.scss +++ b/src/front/Components/Layouts/FolderArchived/FolderInformation/classes.module.scss @@ -86,4 +86,16 @@ .modal-title { margin-bottom: 24px; } +} + +.loader-container { + display: flex; + flex: 1; + align-items: center; + justify-content: center; + height: 100%; + .loader { + width: 40px; + height: 40px; + } } \ No newline at end of file diff --git a/src/front/Components/Layouts/FolderArchived/FolderInformation/index.tsx b/src/front/Components/Layouts/FolderArchived/FolderInformation/index.tsx index 8376f0a4..453b86ea 100644 --- a/src/front/Components/Layouts/FolderArchived/FolderInformation/index.tsx +++ b/src/front/Components/Layouts/FolderArchived/FolderInformation/index.tsx @@ -13,12 +13,20 @@ import BasePage from "../../Base"; import classes from "./classes.module.scss"; import ClientSection from "./ClientSection"; import Link from "next/link"; +import { AnchorStatus } from "../../Folder/FolderInformation"; +import { useCallback, useEffect, useState } from "react"; +import OfficeFolderAnchors from "@Front/Api/LeCoffreApi/Notary/OfficeFolderAnchors/OfficeFolderAnchors"; +import Loader from "@Front/Components/DesignSystem/Loader"; type IProps = {}; type IPropsClass = IProps & { router: NextRouter; selectedFolderUid: string; + isLoading: boolean; + selectedFolder: OfficeFolder | null; + isAnchored: AnchorStatus; + getFolderCallback: () => Promise; }; type IState = { @@ -46,65 +54,89 @@ class FolderInformationClass extends BasePage { .modules.pages.Folder.pages.EditCollaborators.props.path.replace("[folderUid]", this.props.selectedFolderUid); return ( -
- {this.state.selectedFolder ? ( -
-
-
-
- Informations du dossier + {!this.props.isLoading && ( +
+ {this.state.selectedFolder ? ( +
+
+
+
+ Informations du dossier +
+ + +
- - - -
- -
+
+ +
+
+ +
+ +
+ +
+ {this.doesFolderHaveCustomer() && ( + + )}
-
- + )} + +
+
- -
- +
+ ) : ( +
+ Informations du dossier +
+ + Aucun dossier sélectionné +
- {this.doesFolderHaveCustomer() && } -
- - {!this.doesFolderHaveCustomer() && } - -
-
+ )} +
+ )} + {this.props.isLoading && ( +
+
+
- ) : ( -
- Informations du dossier -
- - Aucun dossier sélectionné - -
-
- )} -
+
+ )} ); } @@ -123,9 +155,7 @@ class FolderInformationClass extends BasePage { private async restoreFolder() { if (!this.state.selectedFolder) return; - const ressourceFolder = OfficeFolder.hydrate(this.state.selectedFolder); - ressourceFolder.archived_description = null; - await Folders.getInstance().restore(this.state.selectedFolder.uid ?? "", ressourceFolder); + await Folders.getInstance().restore(this.state.selectedFolder.uid ?? ""); this.props.router.push( Module.getInstance() .get() @@ -156,7 +186,79 @@ class FolderInformationClass extends BasePage { export default function FolderInformation(props: IProps) { const router = useRouter(); + const [isAnchored, setIsAnchored] = useState(AnchorStatus.NOT_ANCHORED); + const [isLoading, setIsLoading] = useState(true); + const [selectedFolder, setSelectedFolder] = useState(null); + let { folderUid } = router.query; folderUid = folderUid as string; - return ; + + const getAnchoringStatus = useCallback(async () => { + if (!folderUid) return; + setIsLoading(true); + try { + const anchorStatus = await OfficeFolderAnchors.getInstance().getByUid(folderUid as string); + setIsAnchored(anchorStatus.status === "VERIFIED_ON_CHAIN" ? AnchorStatus.VERIFIED_ON_CHAIN : AnchorStatus.ANCHORING); + } catch (e) { + setIsAnchored(AnchorStatus.NOT_ANCHORED); + } + setIsLoading(false); + }, [folderUid]); + + const getFolder = useCallback(async () => { + if (!folderUid) return; + setIsLoading(true); + const query = { + q: { + deed: { include: { deed_type: true } }, + office: true, + customers: { + include: { + contact: true, + documents: { + include: { + folder: true, + document_type: true, + files: true, + }, + }, + }, + }, + documents: { + include: { + depositor: { + include: { + contact: true, + }, + }, + }, + }, + folder_anchor: true, + }, + }; + const folder = await Folders.getInstance().getByUid(folderUid as string, query); + if (folder) { + setSelectedFolder(folder); + getAnchoringStatus(); + } + + setIsLoading(false); + }, [folderUid, getAnchoringStatus]); + + useEffect(() => { + setIsLoading(true); + getFolder(); + }, [getFolder]); + + return ( + + ); } diff --git a/src/front/Components/Layouts/Login/index.tsx b/src/front/Components/Layouts/Login/index.tsx index e6e60bd7..36609094 100644 --- a/src/front/Components/Layouts/Login/index.tsx +++ b/src/front/Components/Layouts/Login/index.tsx @@ -5,15 +5,19 @@ import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography"; import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; import Image from "next/image"; import { useRouter } from "next/router"; -import { useCallback } from "react"; +import { useCallback, useEffect, useState } from "react"; import classes from "./classes.module.scss"; import LandingImage from "./landing-connect.jpeg"; import { FrontendVariables } from "@Front/Config/VariablesFront"; import Link from "next/link"; +import Confirm from "@Front/Components/DesignSystem/Modal/Confirm"; export default function Login() { const router = useRouter(); + const error = router.query["error"]; + + const [isErrorModalOpen, setIsErrorModalOpen] = useState(false); const redirectUserOnConnection = useCallback(() => { const variables = FrontendVariables.getInstance(); @@ -24,6 +28,18 @@ export default function Login() { ); }, [router]); + const openErrorModal = useCallback(() => { + setIsErrorModalOpen(true); + }, []); + + const closeErrorModal = useCallback(() => { + setIsErrorModalOpen(false); + }, []); + + useEffect(() => { + if (error === "1") openErrorModal(); + }, [error, openErrorModal]); + return (
@@ -41,6 +57,20 @@ export default function Login() {
+ +
+ + Une erreur est survenue lors de la connexion. Veuillez réessayer. + +
+
); } diff --git a/src/front/Components/Layouts/LoginCallback/index.tsx b/src/front/Components/Layouts/LoginCallback/index.tsx index 12d2293c..3ca30a34 100644 --- a/src/front/Components/Layouts/LoginCallback/index.tsx +++ b/src/front/Components/Layouts/LoginCallback/index.tsx @@ -22,10 +22,11 @@ export default function LoginCallBack() { if (!code) return; try { const token = await Auth.getInstance().getIdnotJwt(code as string); + if (!token) return router.push(Module.getInstance().get().modules.pages.Login.props.path); await UserStore.instance.connect(token.accessToken, token.refreshToken); return router.push(Module.getInstance().get().modules.pages.Folder.props.path); } catch (e) { - console.error(e); + router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1"); return; } } diff --git a/src/front/Components/Layouts/Users/UserInformations/classes.module.scss b/src/front/Components/Layouts/Users/UserInformations/classes.module.scss index 6dd2a010..cc483aa2 100644 --- a/src/front/Components/Layouts/Users/UserInformations/classes.module.scss +++ b/src/front/Components/Layouts/Users/UserInformations/classes.module.scss @@ -83,3 +83,15 @@ .remove-my-vote { margin-top: 16px; } + +.loader-container { + display: flex; + flex: 1; + align-items: center; + justify-content: center; + height: 100%; + .loader { + width: 40px; + height: 40px; + } +} diff --git a/src/front/Components/Layouts/Users/UserInformations/index.tsx b/src/front/Components/Layouts/Users/UserInformations/index.tsx index 9962f139..b55e45d5 100644 --- a/src/front/Components/Layouts/Users/UserInformations/index.tsx +++ b/src/front/Components/Layouts/Users/UserInformations/index.tsx @@ -4,20 +4,21 @@ import Roles from "@Front/Api/LeCoffreApi/Admin/Roles/Roles"; import LiveVotes from "@Front/Api/LeCoffreApi/SuperAdmin/LiveVotes/LiveVotes"; import Users from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users"; import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button"; -import SelectField, { IOption } from "@Front/Components/DesignSystem/Form/SelectField"; import Confirm from "@Front/Components/DesignSystem/Modal/Confirm"; import Switch from "@Front/Components/DesignSystem/Switch"; import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; import DefaultUserDashboard from "@Front/Components/LayoutTemplates/DefaultUserDashboard"; import JwtService from "@Front/Services/JwtService/JwtService"; import Toasts from "@Front/Stores/Toasts"; -import User, { Appointment, OfficeRole, Vote } from "le-coffre-resources/dist/SuperAdmin"; +import User, { Appointment, Vote } from "le-coffre-resources/dist/SuperAdmin"; import { EAppointmentStatus, EVote } from "le-coffre-resources/dist/SuperAdmin/Appointment"; import Image from "next/image"; import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; import classes from "./classes.module.scss"; +import OfficeRoles from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles"; +import Loader from "@Front/Components/DesignSystem/Loader"; type IProps = {}; export default function UserInformations(props: IProps) { @@ -25,9 +26,7 @@ export default function UserInformations(props: IProps) { let { userUid } = router.query; const [userSelected, setUserSelected] = useState(null); - const [availableRoles, setAvailableRoles] = useState([]); - const [roleModalOpened, setRoleModalOpened] = useState(false); const [isSuperAdminModalOpened, setIsSuperAdminModalOpened] = useState(false); const [superAdminModalType, setSuperAdminModalType] = useState<"add" | "remove">("add"); const [adminModalType, setAdminModalType] = useState<"add" | "remove">("add"); @@ -36,19 +35,14 @@ export default function UserInformations(props: IProps) { const [isAdminChecked, setIsAdminChecked] = useState(false); const [isAdminModalOpened, setIsAdminModalOpened] = useState(false); - const [selectedOption, setSelectedOption] = useState(null); - const [currentAppointment, setCurrentAppointment] = useState(null); - const handleRoleChange = useCallback((option: IOption) => { - setSelectedOption(option); - setRoleModalOpened(true); - }, []); - + const [isLoading, setIsLoading] = useState(true); /** When page change, get the user of the page */ const getUser = useCallback(async () => { if (!userUid) return; + setIsLoading(true); const user = await Users.getInstance().getByUid(userUid as string, { q: { contact: true, @@ -68,11 +62,14 @@ export default function UserInformations(props: IProps) { }, }); if (!user) return; - const roles = await Roles.getInstance().get({ - where: {NOT: {OR:[{name: "super-admin"}, {name: "admin"}]}}, + const roles = await OfficeRoles.getInstance().get({ + where: { + office: { uid: user.office_membership?.uid }, + NOT: { OR: [{ name: "super-admin" }, { name: "admin" }] }, + }, }); - if (!roles) return - setAvailableRoles(roles.map((role) => ({ value: role.uid, label: role.label }))); + if (!roles) return; + setIsLoading(false); setUserSelected(user); }, [userUid]); @@ -140,8 +137,9 @@ export default function UserInformations(props: IProps) { }), ); } + getUser(); setIsAdminModalOpened(false); - }, [userSelected, adminModalType]); + }, [userSelected, adminModalType, getUser]); /** Functions for the super admin modal */ const openSuperAdminModal = () => { @@ -165,7 +163,7 @@ export default function UserInformations(props: IProps) { let vote = Vote.hydrate({ appointment: Appointment.hydrate({ uid: currentAppointment?.uid ?? undefined, - targeted_user: User.hydrate({ + user: User.hydrate({ uid: userSelected.uid, }), choice: superAdminModalType === "add" ? EVote.NOMINATE : EVote.DISMISS, @@ -183,28 +181,6 @@ export default function UserInformations(props: IProps) { setIsSuperAdminModalOpened(false); }, [userSelected, currentAppointment, superAdminModalType, getUser]); - const closeRoleModal = useCallback(() => { - setRoleModalOpened(false); - setSelectedOption({ - value: userSelected?.office_role ? userSelected?.office_role?.uid : userSelected?.role?.uid, - label: userSelected?.office_role ? userSelected?.office_role?.name : userSelected?.role?.label!, - }); - }, [userSelected?.office_role, userSelected?.role?.label, userSelected?.role?.uid]); - - const changeRole = useCallback(async () => { - await Users.getInstance().put( - userSelected?.uid as string, - User.hydrate({ - uid: userSelected?.uid as string, - office_role: OfficeRole.hydrate({ - uid: selectedOption?.value as string, - }), - }), - ); - setRoleModalOpened(false); - getUser(); - }, [getUser, selectedOption?.value, userSelected?.uid]); - /** Reset switch state when userSelect change */ useEffect(() => { if (!userSelected) return; @@ -229,157 +205,146 @@ export default function UserInformations(props: IProps) { return ( -
-
- {userSelected?.contact?.first_name + " " + userSelected?.contact?.last_name} - - Office {userSelected?.office_membership?.name.toLocaleUpperCase()} - -
-
-
- - Nom + {!isLoading && ( +
+
+ + {userSelected?.contact?.first_name + " " + userSelected?.contact?.last_name} - {userSelected?.contact?.first_name} -
-
- - Prénom + + Office {userSelected?.office_membership?.name.toLocaleUpperCase()} - {userSelected?.contact?.last_name}
-
- - Numéro de téléphone - - {userSelected?.contact?.phone_number} +
+
+ + Nom + + {userSelected?.contact?.first_name} +
+
+ + Prénom + + {userSelected?.contact?.last_name} +
+
+ + Numéro de téléphone + + {userSelected?.contact?.phone_number} +
+
+ + Email + + {userSelected?.contact?.email} +
-
- - Email - - {userSelected?.contact?.email} -
-
-
-
-
- Rôle au sein de son office +
+
+
+ Rôle au sein de son office +
+
+ + {userSelected?.office_role ? userSelected?.office_role?.name : "Utilisateur restreint"} + +
-
- role.label !== "admin")} - onChange={handleRoleChange} - selectedOption={{ - value: userSelected?.office_role ? userSelected?.office_role?.uid : userSelected?.role?.uid, - label: userSelected?.office_role ? userSelected?.office_role?.name : "Utilisateur restreint", - }} - /> -
-
-
-
- Attribuer un titre -
-
- {!isSuperAdminChecked && ( - - )} +
+
+ Attribuer un titre +
+
+ {!isSuperAdminChecked && !currentAppointment && ( + + )} - - {currentAppointment && ( -
-
- warning -
-
-
- {currentAppointment.votes?.length}/3 + + {currentAppointment && ( +
+
+ warning
-
- - {currentAppointment.choice === EVote.NOMINATE - ? `Un ou des collaborateurs souhaitent attribuer le titre de Super Admin à ce collaborateur. Il manque ${ - 3 - currentAppointment.votes?.length! - } vote(s) pour que le collaborateur se voit attribuer le titre.` - : `Un ou des collaborateurs souhaitent retirer le titre de Super Admin à ce collaborateur. Il manque ${ - 3 - currentAppointment.votes?.length! - } vote(s) pour que le collaborateur se voit retirer le titre.`} - -
- {userHasVoted() && ( -
- +
+
+ {currentAppointment.votes?.length}/3
- )} +
+ + {currentAppointment.choice === EVote.NOMINATE + ? `Un ou des collaborateurs souhaitent attribuer le titre de Super Admin à ce collaborateur. Il manque ${ + 3 - currentAppointment.votes?.length! + } vote(s) pour que le collaborateur se voit attribuer le titre.` + : `Un ou des collaborateurs souhaitent retirer le titre de Super Admin à ce collaborateur. Il manque ${ + 3 - currentAppointment.votes?.length! + } vote(s) pour que le collaborateur se voit retirer le titre.`} + +
+ {userHasVoted() && ( +
+ +
+ )} +
-
- )} + )} +
+ +
+ + {superAdminModalType === "add" ? "Nommer" : "Retirer"} une personne Super Administrateur nécessite 3 votes + de super administrateurs existants. Souhaitez-vous attribuer un vote ? + +
+
+ +
+
- -
- - Attribuer le rôle de {selectedOption?.label} à{" "} - {userSelected?.contact?.first_name} {userSelected?.contact?.last_name} ? - + )} + {isLoading && ( +
+
+
- - -
- - {superAdminModalType === "add" ? "Nommer" : "Retirer"} une personne Super Administrateur nécessite 3 votes de - super administrateurs existants. Souhaitez-vous attribuer un vote ? - -
-
- -
-
-
+
+ )} ); } diff --git a/src/front/Stores/Toasts.tsx b/src/front/Stores/Toasts.tsx index 439e8537..126461a3 100644 --- a/src/front/Stores/Toasts.tsx +++ b/src/front/Stores/Toasts.tsx @@ -97,6 +97,15 @@ export default class Toasts { this.event.emit("change", this.toastList); } + public async closeAll() { + for (let i = 0; i < this.toastList.length; i++) { + await Notifications.getInstance().put(this.toastList[i]?.uid as string, { + read: true, + }); + } + this.event.emit("change", []); + } + /** * An utility static method you can use to quickly display an error toast * with a custom error message.