diff --git a/src/front/Components/DesignSystem/FolderListContainer/index.tsx b/src/front/Components/DesignSystem/FolderListContainer/index.tsx index abfeb50a..47af85be 100644 --- a/src/front/Components/DesignSystem/FolderListContainer/index.tsx +++ b/src/front/Components/DesignSystem/FolderListContainer/index.tsx @@ -75,6 +75,11 @@ class FolderListContainerClass extends React.Component { ); } + public override componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { + if (prevProps.selectedFolder !== this.props.selectedFolder) { + this.setState({ filteredFolders: this.props.folders, blocks: this.getBlocks(this.props.folders) }); + } + } private getBlocks(folders: OfficeFolder[]): IBlock[] { const pendingFolders = folders .filter((folder) => { diff --git a/src/front/Components/DesignSystem/Form/DateField/classes.module.scss b/src/front/Components/DesignSystem/Form/DateField/classes.module.scss new file mode 100644 index 00000000..0fda11ae --- /dev/null +++ b/src/front/Components/DesignSystem/Form/DateField/classes.module.scss @@ -0,0 +1,102 @@ +@import "@Themes/constants.scss"; + +.root { + position: relative; + + .input { + z-index: 1; + display: flex; + flex-direction: row; + align-items: center; + padding: 24px; + gap: 10px; + width: 100%; + height: 70px; + border: 1px solid var(--grey-medium); + + &:disabled { + cursor: not-allowed; + } + + &:focus { + ~ .fake-placeholder { + transform: translateY(-35px); + } + } + + &:not([data-value=""]) { + ~ .fake-placeholder { + transform: translateY(-35px); + } + } + + &[type="number"] { + &:focus { + ~ .fake-placeholder { + transform: translateY(-35px); + } + } + + &:not([data-value=""]) { + ~ .fake-placeholder { + transform: translateY(-35px); + } + } + + &::-webkit-inner-spin-button, + &::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + + /* For Chrome, Safari, and Opera */ + &::-webkit-inner-spin-button, + &::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + + /* For IE 10+ */ + &::-ms-inner-spin-button, + &::-ms-outer-spin-button { + display: none; + } + } + + &:not([data-value=""]) { + ~ .fake-placeholder { + transform: translateY(-35px); + } + } + + ~ .fake-placeholder { + z-index: 2; + top: 35%; + margin-left: 8px; + padding: 0 16px; + pointer-events: none; + position: absolute; + background: $white; + transition: transform 0.3s ease-in-out; + } + } + + &[data-is-errored="true"] { + .input { + border: 1px solid var(--red-flash); + ~ .fake-placeholder { + color: var(--red-flash); + } + } + } + + .copy-icon { + cursor: pointer; + height: 24px; + width: 24px; + position: absolute; + top: 50%; + right: 24px; + transform: translate(0, -50%); + } +} diff --git a/src/front/Components/DesignSystem/Form/DateField/index.tsx b/src/front/Components/DesignSystem/Form/DateField/index.tsx new file mode 100644 index 00000000..0c0e892a --- /dev/null +++ b/src/front/Components/DesignSystem/Form/DateField/index.tsx @@ -0,0 +1,56 @@ +import React from "react"; +import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; +import { ReactNode } from "react"; +import CopyIcon from "@Assets/Icons/copy.svg"; +import BaseField, { IProps as IBaseFieldProps } from "../BaseField"; +import classes from "./classes.module.scss"; +import classnames from "classnames"; +import Image from "next/image"; + +export type IProps = IBaseFieldProps & { + canCopy?: boolean; +}; + +export default class DateField extends BaseField { + constructor(props: IProps) { + super(props); + this.state = this.getDefaultState(); + } + + public override render(): ReactNode { + const value = this.state.value ?? ""; + return ( + +
+ +
+ {this.props.placeholder} {!this.props.required && " (Facultatif)"} +
+ {this.props.canCopy && ( +
+ Copy icon +
+ )} +
+ {this.hasError() &&
{this.renderErrors()}
} +
+ ); + } + + private onCopyClick = (): void => { + if (this.props.canCopy) { + navigator.clipboard.writeText(this.state.value ?? ""); + } + }; +} diff --git a/src/front/Components/DesignSystem/Form/SelectField/index.tsx b/src/front/Components/DesignSystem/Form/SelectField/index.tsx index ad4b6497..20377a29 100644 --- a/src/front/Components/DesignSystem/Form/SelectField/index.tsx +++ b/src/front/Components/DesignSystem/Form/SelectField/index.tsx @@ -7,6 +7,7 @@ import React, { FormEvent, ReactNode } from "react"; import Typography, { ITypo, ITypoColor } from "../../Typography"; import classes from "./classes.module.scss"; +import { NextRouter, useRouter } from "next/router"; type IProps = { selectedOption?: IOption; @@ -16,7 +17,7 @@ type IProps = { placeholder?: string; className?: string; name: string; - disabled: boolean; + disabled?: boolean; errors?: ValidationError; }; @@ -35,7 +36,11 @@ type IState = { errors: ValidationError | null; }; -export default class SelectField extends React.Component { +type IPropsClass = IProps & { + router: NextRouter; +}; + +class SelectFieldClass extends React.Component { private contentRef = React.createRef(); private rootRef = React.createRef(); private removeOnresize = () => {}; @@ -44,7 +49,7 @@ export default class SelectField extends React.Component { disabled: false, }; - constructor(props: IProps) { + constructor(props: IPropsClass) { super(props); this.state = { isOpen: false, @@ -64,7 +69,7 @@ export default class SelectField extends React.Component {
{selectedOption && }
); } + public override componentDidMount(): void { + this.onResize(); + this.removeOnresize = WindowStore.getInstance().onResize(() => this.onResize()); + + this.props.router.events.on("routeChangeStart", () => { + this.setState({ + isOpen: false, + selectedOption: null, + listHeight: 0, + listWidth: 0, + }); + }); + } + + public override componentWillUnmount() { + this.removeOnresize(); + } public override componentDidUpdate(prevProps: IProps) { if (this.props.errors !== prevProps.errors) { @@ -140,15 +162,6 @@ export default class SelectField extends React.Component { return null; } - public override componentDidMount(): void { - this.onResize(); - this.removeOnresize = WindowStore.getInstance().onResize(() => this.onResize()); - } - - public override componentWillUnmount() { - this.removeOnresize(); - } - private onResize() { let listHeight = 0; let listWidth = 0; @@ -192,3 +205,8 @@ export default class SelectField extends React.Component { ); } } + +export default function SelectField(props: IProps) { + const router = useRouter(); + return ; +} diff --git a/src/front/Components/Elements/Rules/index.tsx b/src/front/Components/Elements/Rules/index.tsx index 889adf89..ecf66840 100644 --- a/src/front/Components/Elements/Rules/index.tsx +++ b/src/front/Components/Elements/Rules/index.tsx @@ -1,8 +1,8 @@ import React, { useCallback, useEffect } from "react"; -import { useRouter } from "next/router"; -import Module from "@Front/Config/Module"; import JwtService from "@Front/Services/JwtService/JwtService"; import { IAppRule } from "@Front/Api/Entities/rule"; +import { useRouter } from "next/router"; +import Module from "@Front/Config/Module"; export enum RulesMode { OPTIONAL = "optional", @@ -10,16 +10,18 @@ export enum RulesMode { } type IProps = { - isPage?: boolean; mode: RulesMode; rules: IAppRule[]; - no?: boolean; children: JSX.Element; + isPage?: boolean; }; export default function Rules(props: IProps) { const router = useRouter(); + const [isShowing, setIsShowing] = React.useState(false); + const [hasJwt, setHasJwt] = React.useState(false); + const getShowValue = useCallback(() => { if (props.mode === RulesMode.NECESSARY) { return props.rules.every((rule) => JwtService.getInstance().hasRule(rule.name, rule.action)); @@ -27,19 +29,18 @@ export default function Rules(props: IProps) { return !!props.rules.find((rule) => JwtService.getInstance().hasRule(rule.name, rule.action)); }, [props.mode, props.rules]); - const show = getShowValue(); - const [isShowing, setIsShowing] = React.useState(props.no ? !show : show); - useEffect(() => { - setIsShowing(props.no ? !show : show); - }, [props.no, show]); + if (!JwtService.getInstance().decodeJwt()) return; + setHasJwt(true); + setIsShowing(getShowValue()); + }, [getShowValue, isShowing]); - if (!isShowing && props.isPage) { - router.push(Module.getInstance().get().modules.pages.Home.props.path); - } - - if (!JwtService.getInstance().decodeJwt() || !isShowing) { + if (props.isPage && !isShowing) { + router.push(Module.getInstance().get().modules.pages[404].props.path); return null; } + + if (!hasJwt || !isShowing) return null; + return props.children; } diff --git a/src/front/Components/Layouts/Collaborators/CollaboratorInformations/index.tsx b/src/front/Components/Layouts/Collaborators/CollaboratorInformations/index.tsx index 6ec149a5..639617fd 100644 --- a/src/front/Components/Layouts/Collaborators/CollaboratorInformations/index.tsx +++ b/src/front/Components/Layouts/Collaborators/CollaboratorInformations/index.tsx @@ -45,9 +45,9 @@ export default function CollaboratorInformations(props: IProps) { setRoleModalOpened(false); setSelectedOption({ value: userSelected?.office_role ? userSelected?.office_role?.uid : userSelected?.role?.uid, - label: userSelected?.office_role ? userSelected?.office_role?.name : userSelected?.role?.name!, + label: userSelected?.office_role ? userSelected?.office_role?.name : "Utilisateur restreint", }); - }, [userSelected?.office_role, userSelected?.role?.name, userSelected?.role?.uid]); + }, [userSelected?.office_role, userSelected?.role?.uid]); const changeRole = useCallback(async () => { await Users.getInstance().put( @@ -133,7 +133,7 @@ export default function CollaboratorInformations(props: IProps) { setUserSelected(user); setSelectedOption({ value: user?.office_role ? user?.office_role?.uid : user?.role?.uid, - label: user?.office_role ? user?.office_role?.name : user?.role?.name!, + label: user?.office_role ? user?.office_role?.name : "Utilisateur restreint", }); } @@ -197,7 +197,6 @@ export default function CollaboratorInformations(props: IProps) { })} selectedOption={selectedOption!} onChange={handleRoleChange} - disabled={userSelected?.role?.name === "super-admin"} /> {userSelected?.role?.name !== "super-admin" && ( diff --git a/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/classes.module.scss b/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/classes.module.scss index b81e9055..7f0fcf99 100644 --- a/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/classes.module.scss +++ b/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/classes.module.scss @@ -72,6 +72,9 @@ border: 1px solid var(--grey); .container-title { + display: flex; + gap: 8px; + align-items: center; } .documents { diff --git a/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx b/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx index 78035956..b5454cab 100644 --- a/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx +++ b/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx @@ -19,6 +19,7 @@ import { useCallback, useEffect, useState } from "react"; import { MultiValue } from "react-select"; import classes from "./classes.module.scss"; +import Tooltip from "@Front/Components/DesignSystem/ToolTip"; type IProps = {}; export default function DeedTypesInformations(props: IProps) { @@ -30,6 +31,7 @@ export default function DeedTypesInformations(props: IProps) { const [selectedDocuments, setSelectedDocuments] = useState([]); const [isDeleteModalOpened, setIsDeleteModalOpened] = useState(false); + const [isSaveModalOpened, setIsSaveModalOpened] = useState(false); const openDeleteModal = useCallback(() => { setIsDeleteModalOpened(true); @@ -39,6 +41,14 @@ export default function DeedTypesInformations(props: IProps) { setIsDeleteModalOpened(false); }, []); + const openSaveModal = useCallback(() => { + setIsSaveModalOpened(true); + }, []); + + const closeSaveModal = useCallback(() => { + setIsSaveModalOpened(false); + }, []); + const deleteDeedType = useCallback(async () => { await DeedTypes.getInstance().put( deedTypeUid as string, @@ -81,14 +91,19 @@ export default function DeedTypesInformations(props: IProps) { const onSubmitHandler = useCallback( async (e: React.FormEvent | null, values: { [key: string]: string }) => { - await DeedTypes.getInstance().put(deedTypeUid as string, { - uid: deedTypeUid as string, - document_types: selectedDocuments.map((document) => DocumentType.hydrate({ uid: document.value as string })), - }); + openSaveModal(); }, - [deedTypeUid, selectedDocuments], + [openSaveModal], ); + const saveDocumentTypes = useCallback(async () => { + await DeedTypes.getInstance().put(deedTypeUid as string, { + uid: deedTypeUid as string, + document_types: selectedDocuments.map((document) => DocumentType.hydrate({ uid: document.value as string })), + }); + closeSaveModal(); + }, [closeSaveModal, deedTypeUid, selectedDocuments]); + const onDocumentChangeHandler = useCallback((values: MultiValue) => { setSelectedDocuments(values as IOption[]); }, []); @@ -137,7 +152,8 @@ export default function DeedTypesInformations(props: IProps) {
- Documents paramétrés + Sélectionner les documents associés à ce type d'acte +
+ +
+ + Les documents seront associés à ce type d'acte. + +
+
); diff --git a/src/front/Components/Layouts/DocumentTypes/DocumentTypesInformations/classes.module.scss b/src/front/Components/Layouts/DocumentTypes/DocumentTypesInformations/classes.module.scss index c471a213..7aeed370 100644 --- a/src/front/Components/Layouts/DocumentTypes/DocumentTypesInformations/classes.module.scss +++ b/src/front/Components/Layouts/DocumentTypes/DocumentTypesInformations/classes.module.scss @@ -1,6 +1,18 @@ @import "@Themes/constants.scss"; .root { + .header { + display: flex; + justify-content: space-between; + align-items: flex-start; + + @media (max-width: $screen-l) { + flex-direction: column; + align-items: flex-start; + gap: 24px; + } + } + .document-infos { display: flex; align-items: flex-start; diff --git a/src/front/Components/Layouts/DocumentTypes/DocumentTypesInformations/index.tsx b/src/front/Components/Layouts/DocumentTypes/DocumentTypesInformations/index.tsx index f07303e6..82242224 100644 --- a/src/front/Components/Layouts/DocumentTypes/DocumentTypesInformations/index.tsx +++ b/src/front/Components/Layouts/DocumentTypes/DocumentTypesInformations/index.tsx @@ -1,3 +1,4 @@ +import ChevronIcon from "@Assets/Icons/chevron.svg"; import PenICon from "@Assets/Icons/pen.svg"; import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes"; import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; @@ -10,6 +11,7 @@ import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import classes from "./classes.module.scss"; +import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button"; export default function DocumentTypesInformations() { const router = useRouter(); @@ -33,8 +35,14 @@ export default function DocumentTypesInformations() { return (
-
- Paramétrage des documents +
+ Paramétrage des listes de pièces + + +
diff --git a/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx b/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx index 397a902b..148e5772 100644 --- a/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx +++ b/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx @@ -9,7 +9,6 @@ import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography"; import BackArrow from "@Front/Components/Elements/BackArrow"; import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; import Module from "@Front/Config/Module"; -import { TextField } from "@mui/material"; import { ECivility } from "le-coffre-resources/dist/Customer/Contact"; import { Customer, OfficeFolder } from "le-coffre-resources/dist/Notary"; import Link from "next/link"; @@ -17,6 +16,7 @@ import { NextRouter, useRouter } from "next/router"; import BasePage from "../../Base"; import classes from "./classes.module.scss"; +import TextField from "@Front/Components/DesignSystem/Form/TextField"; enum ESelectedOption { EXISTING_CUSTOMER = "existing_customer", diff --git a/src/front/Components/Layouts/Folder/FolderInformation/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/index.tsx index d97cf1bd..54ecb7a5 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/index.tsx @@ -34,6 +34,7 @@ type IState = { inputArchivedDescripton: string; isValidateModalVisible: boolean; hasValidateAnchoring: boolean; + isVerifDeleteModalVisible: boolean; }; class FolderInformationClass extends BasePage { public constructor(props: IPropsClass) { @@ -44,6 +45,7 @@ class FolderInformationClass extends BasePage { inputArchivedDescripton: "", isValidateModalVisible: false, hasValidateAnchoring: false, + isVerifDeleteModalVisible: false, }; this.onSelectedFolder = this.onSelectedFolder.bind(this); this.openArchivedModal = this.openArchivedModal.bind(this); @@ -55,6 +57,8 @@ class FolderInformationClass extends BasePage { this.closeModal = this.closeModal.bind(this); this.validateAnchoring = this.validateAnchoring.bind(this); this.openValidateModal = this.openValidateModal.bind(this); + this.openVerifDeleteFolder = this.openVerifDeleteFolder.bind(this); + this.closeVerifDeleteFolder = this.closeVerifDeleteFolder.bind(this); } // TODO: Message if the user has not created any folder yet @@ -109,7 +113,7 @@ class FolderInformationClass extends BasePage { )} {!this.doesFolderHaveCustomer() && ( - + )} @@ -131,6 +135,18 @@ class FolderInformationClass extends BasePage { onChange={this.onArchivedDescriptionInputChange} /> + +
+ Cette action sera irréversible. +
+
) : (
@@ -187,6 +203,18 @@ class FolderInformationClass extends BasePage { }); } + public openVerifDeleteFolder() { + this.setState({ + isVerifDeleteModalVisible: true, + }); + } + + public closeVerifDeleteFolder() { + this.setState({ + isVerifDeleteModalVisible: false, + }); + } + private closeModal() { this.setState({ isValidateModalVisible: false, diff --git a/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx b/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx index 75501e12..6e3f30d5 100644 --- a/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx +++ b/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx @@ -13,6 +13,7 @@ import { NextRouter, useRouter } from "next/router"; import BasePage from "../../Base"; import classes from "./classes.module.scss"; +import DateField from "@Front/Components/DesignSystem/Form/DateField"; type IProps = {}; @@ -43,6 +44,8 @@ class UpdateFolderMetadataClass extends BasePage { value: this.state.selectedFolder?.deed?.deed_type?.uid, } as IOption; const openingDate = new Date(this.state.selectedFolder?.created_at ?? ""); + if (!this.state.selectedFolder?.created_at) return <>; + const defaultValue = openingDate.toISOString().split("T")[0]; return (
@@ -60,7 +63,7 @@ class UpdateFolderMetadataClass extends BasePage { defaultValue={this.state.selectedFolder?.folder_number} />