Merge branch 'dev-without-id-not' into dev
This commit is contained in:
commit
26d597411f
@ -75,6 +75,11 @@ class FolderListContainerClass extends React.Component<IPropsClass, IState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override componentDidUpdate(prevProps: Readonly<IPropsClass>, prevState: Readonly<IState>, 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[] {
|
private getBlocks(folders: OfficeFolder[]): IBlock[] {
|
||||||
const pendingFolders = folders
|
const pendingFolders = folders
|
||||||
.filter((folder) => {
|
.filter((folder) => {
|
||||||
|
@ -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%);
|
||||||
|
}
|
||||||
|
}
|
56
src/front/Components/DesignSystem/Form/DateField/index.tsx
Normal file
56
src/front/Components/DesignSystem/Form/DateField/index.tsx
Normal file
@ -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<IProps> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = this.getDefaultState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override render(): ReactNode {
|
||||||
|
const value = this.state.value ?? "";
|
||||||
|
return (
|
||||||
|
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
|
||||||
|
<div className={classes["root"]} data-is-errored={this.hasError().toString()}>
|
||||||
|
<input
|
||||||
|
onChange={this.onChange}
|
||||||
|
data-value={value}
|
||||||
|
data-has-validation-errors={(this.state.validationError === null).toString()}
|
||||||
|
className={classnames(classes["input"], this.props.className)}
|
||||||
|
value={value}
|
||||||
|
onFocus={this.onFocus}
|
||||||
|
onBlur={this.onBlur}
|
||||||
|
name={this.props.name}
|
||||||
|
disabled={this.props.disabled}
|
||||||
|
type={"date"}
|
||||||
|
/>
|
||||||
|
<div className={classes["fake-placeholder"]}>
|
||||||
|
{this.props.placeholder} {!this.props.required && " (Facultatif)"}
|
||||||
|
</div>
|
||||||
|
{this.props.canCopy && (
|
||||||
|
<div className={classes["copy-icon"]} onClick={this.onCopyClick}>
|
||||||
|
<Image src={CopyIcon} alt="Copy icon" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{this.hasError() && <div className={classes["errors-container"]}>{this.renderErrors()}</div>}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onCopyClick = (): void => {
|
||||||
|
if (this.props.canCopy) {
|
||||||
|
navigator.clipboard.writeText(this.state.value ?? "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -7,6 +7,7 @@ import React, { FormEvent, ReactNode } from "react";
|
|||||||
|
|
||||||
import Typography, { ITypo, ITypoColor } from "../../Typography";
|
import Typography, { ITypo, ITypoColor } from "../../Typography";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import { NextRouter, useRouter } from "next/router";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
selectedOption?: IOption;
|
selectedOption?: IOption;
|
||||||
@ -16,7 +17,7 @@ type IProps = {
|
|||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
name: string;
|
name: string;
|
||||||
disabled: boolean;
|
disabled?: boolean;
|
||||||
errors?: ValidationError;
|
errors?: ValidationError;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,7 +36,11 @@ type IState = {
|
|||||||
errors: ValidationError | null;
|
errors: ValidationError | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class SelectField extends React.Component<IProps, IState> {
|
type IPropsClass = IProps & {
|
||||||
|
router: NextRouter;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SelectFieldClass extends React.Component<IPropsClass, IState> {
|
||||||
private contentRef = React.createRef<HTMLUListElement>();
|
private contentRef = React.createRef<HTMLUListElement>();
|
||||||
private rootRef = React.createRef<HTMLDivElement>();
|
private rootRef = React.createRef<HTMLDivElement>();
|
||||||
private removeOnresize = () => {};
|
private removeOnresize = () => {};
|
||||||
@ -44,7 +49,7 @@ export default class SelectField extends React.Component<IProps, IState> {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: IProps) {
|
constructor(props: IPropsClass) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
@ -64,7 +69,7 @@ export default class SelectField extends React.Component<IProps, IState> {
|
|||||||
<div
|
<div
|
||||||
className={classNames(classes["root"], this.props.className)}
|
className={classNames(classes["root"], this.props.className)}
|
||||||
ref={this.rootRef}
|
ref={this.rootRef}
|
||||||
data-disabled={this.props.disabled.toString()}
|
data-disabled={this.props.disabled?.toString()}
|
||||||
data-errored={(this.state.errors !== null).toString()}>
|
data-errored={(this.state.errors !== null).toString()}>
|
||||||
{selectedOption && <input type="text" defaultValue={selectedOption.value as string} name={this.props.name} hidden />}
|
{selectedOption && <input type="text" defaultValue={selectedOption.value as string} name={this.props.name} hidden />}
|
||||||
<label
|
<label
|
||||||
@ -116,6 +121,23 @@ export default class SelectField extends React.Component<IProps, IState> {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
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) {
|
public override componentDidUpdate(prevProps: IProps) {
|
||||||
if (this.props.errors !== prevProps.errors) {
|
if (this.props.errors !== prevProps.errors) {
|
||||||
@ -140,15 +162,6 @@ export default class SelectField extends React.Component<IProps, IState> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
|
||||||
this.onResize();
|
|
||||||
this.removeOnresize = WindowStore.getInstance().onResize(() => this.onResize());
|
|
||||||
}
|
|
||||||
|
|
||||||
public override componentWillUnmount() {
|
|
||||||
this.removeOnresize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private onResize() {
|
private onResize() {
|
||||||
let listHeight = 0;
|
let listHeight = 0;
|
||||||
let listWidth = 0;
|
let listWidth = 0;
|
||||||
@ -192,3 +205,8 @@ export default class SelectField extends React.Component<IProps, IState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function SelectField(props: IProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
return <SelectFieldClass {...props} router={router} />;
|
||||||
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React, { useCallback, useEffect } from "react";
|
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 JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
import { IAppRule } from "@Front/Api/Entities/rule";
|
import { IAppRule } from "@Front/Api/Entities/rule";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import Module from "@Front/Config/Module";
|
||||||
|
|
||||||
export enum RulesMode {
|
export enum RulesMode {
|
||||||
OPTIONAL = "optional",
|
OPTIONAL = "optional",
|
||||||
@ -10,16 +10,18 @@ export enum RulesMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
isPage?: boolean;
|
|
||||||
mode: RulesMode;
|
mode: RulesMode;
|
||||||
rules: IAppRule[];
|
rules: IAppRule[];
|
||||||
no?: boolean;
|
|
||||||
children: JSX.Element;
|
children: JSX.Element;
|
||||||
|
isPage?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Rules(props: IProps) {
|
export default function Rules(props: IProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const [isShowing, setIsShowing] = React.useState(false);
|
||||||
|
const [hasJwt, setHasJwt] = React.useState(false);
|
||||||
|
|
||||||
const getShowValue = useCallback(() => {
|
const getShowValue = useCallback(() => {
|
||||||
if (props.mode === RulesMode.NECESSARY) {
|
if (props.mode === RulesMode.NECESSARY) {
|
||||||
return props.rules.every((rule) => JwtService.getInstance().hasRule(rule.name, rule.action));
|
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));
|
return !!props.rules.find((rule) => JwtService.getInstance().hasRule(rule.name, rule.action));
|
||||||
}, [props.mode, props.rules]);
|
}, [props.mode, props.rules]);
|
||||||
|
|
||||||
const show = getShowValue();
|
|
||||||
const [isShowing, setIsShowing] = React.useState(props.no ? !show : show);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsShowing(props.no ? !show : show);
|
if (!JwtService.getInstance().decodeJwt()) return;
|
||||||
}, [props.no, show]);
|
setHasJwt(true);
|
||||||
|
setIsShowing(getShowValue());
|
||||||
|
}, [getShowValue, isShowing]);
|
||||||
|
|
||||||
if (!isShowing && props.isPage) {
|
if (props.isPage && !isShowing) {
|
||||||
router.push(Module.getInstance().get().modules.pages.Home.props.path);
|
router.push(Module.getInstance().get().modules.pages[404].props.path);
|
||||||
}
|
|
||||||
|
|
||||||
if (!JwtService.getInstance().decodeJwt() || !isShowing) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hasJwt || !isShowing) return null;
|
||||||
|
|
||||||
return props.children;
|
return props.children;
|
||||||
}
|
}
|
||||||
|
@ -45,9 +45,9 @@ export default function CollaboratorInformations(props: IProps) {
|
|||||||
setRoleModalOpened(false);
|
setRoleModalOpened(false);
|
||||||
setSelectedOption({
|
setSelectedOption({
|
||||||
value: userSelected?.office_role ? userSelected?.office_role?.uid : userSelected?.role?.uid,
|
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 () => {
|
const changeRole = useCallback(async () => {
|
||||||
await Users.getInstance().put(
|
await Users.getInstance().put(
|
||||||
@ -133,7 +133,7 @@ export default function CollaboratorInformations(props: IProps) {
|
|||||||
setUserSelected(user);
|
setUserSelected(user);
|
||||||
setSelectedOption({
|
setSelectedOption({
|
||||||
value: user?.office_role ? user?.office_role?.uid : user?.role?.uid,
|
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!}
|
selectedOption={selectedOption!}
|
||||||
onChange={handleRoleChange}
|
onChange={handleRoleChange}
|
||||||
disabled={userSelected?.role?.name === "super-admin"}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{userSelected?.role?.name !== "super-admin" && (
|
{userSelected?.role?.name !== "super-admin" && (
|
||||||
|
@ -72,6 +72,9 @@
|
|||||||
border: 1px solid var(--grey);
|
border: 1px solid var(--grey);
|
||||||
|
|
||||||
.container-title {
|
.container-title {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.documents {
|
.documents {
|
||||||
|
@ -19,6 +19,7 @@ import { useCallback, useEffect, useState } from "react";
|
|||||||
import { MultiValue } from "react-select";
|
import { MultiValue } from "react-select";
|
||||||
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import Tooltip from "@Front/Components/DesignSystem/ToolTip";
|
||||||
|
|
||||||
type IProps = {};
|
type IProps = {};
|
||||||
export default function DeedTypesInformations(props: IProps) {
|
export default function DeedTypesInformations(props: IProps) {
|
||||||
@ -30,6 +31,7 @@ export default function DeedTypesInformations(props: IProps) {
|
|||||||
const [selectedDocuments, setSelectedDocuments] = useState<IOption[]>([]);
|
const [selectedDocuments, setSelectedDocuments] = useState<IOption[]>([]);
|
||||||
|
|
||||||
const [isDeleteModalOpened, setIsDeleteModalOpened] = useState<boolean>(false);
|
const [isDeleteModalOpened, setIsDeleteModalOpened] = useState<boolean>(false);
|
||||||
|
const [isSaveModalOpened, setIsSaveModalOpened] = useState<boolean>(false);
|
||||||
|
|
||||||
const openDeleteModal = useCallback(() => {
|
const openDeleteModal = useCallback(() => {
|
||||||
setIsDeleteModalOpened(true);
|
setIsDeleteModalOpened(true);
|
||||||
@ -39,6 +41,14 @@ export default function DeedTypesInformations(props: IProps) {
|
|||||||
setIsDeleteModalOpened(false);
|
setIsDeleteModalOpened(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const openSaveModal = useCallback(() => {
|
||||||
|
setIsSaveModalOpened(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const closeSaveModal = useCallback(() => {
|
||||||
|
setIsSaveModalOpened(false);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const deleteDeedType = useCallback(async () => {
|
const deleteDeedType = useCallback(async () => {
|
||||||
await DeedTypes.getInstance().put(
|
await DeedTypes.getInstance().put(
|
||||||
deedTypeUid as string,
|
deedTypeUid as string,
|
||||||
@ -81,13 +91,18 @@ export default function DeedTypesInformations(props: IProps) {
|
|||||||
|
|
||||||
const onSubmitHandler = useCallback(
|
const onSubmitHandler = useCallback(
|
||||||
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
||||||
|
openSaveModal();
|
||||||
|
},
|
||||||
|
[openSaveModal],
|
||||||
|
);
|
||||||
|
|
||||||
|
const saveDocumentTypes = useCallback(async () => {
|
||||||
await DeedTypes.getInstance().put(deedTypeUid as string, {
|
await DeedTypes.getInstance().put(deedTypeUid as string, {
|
||||||
uid: deedTypeUid as string,
|
uid: deedTypeUid as string,
|
||||||
document_types: selectedDocuments.map((document) => DocumentType.hydrate<DocumentType>({ uid: document.value as string })),
|
document_types: selectedDocuments.map((document) => DocumentType.hydrate<DocumentType>({ uid: document.value as string })),
|
||||||
});
|
});
|
||||||
},
|
closeSaveModal();
|
||||||
[deedTypeUid, selectedDocuments],
|
}, [closeSaveModal, deedTypeUid, selectedDocuments]);
|
||||||
);
|
|
||||||
|
|
||||||
const onDocumentChangeHandler = useCallback((values: MultiValue<IOption>) => {
|
const onDocumentChangeHandler = useCallback((values: MultiValue<IOption>) => {
|
||||||
setSelectedDocuments(values as IOption[]);
|
setSelectedDocuments(values as IOption[]);
|
||||||
@ -137,7 +152,8 @@ export default function DeedTypesInformations(props: IProps) {
|
|||||||
<div className={classes["documents-container"]}>
|
<div className={classes["documents-container"]}>
|
||||||
<Form onSubmit={onSubmitHandler}>
|
<Form onSubmit={onSubmitHandler}>
|
||||||
<div className={classes["container-title"]}>
|
<div className={classes["container-title"]}>
|
||||||
<Typography typo={ITypo.P_SB_18}>Documents paramétrés</Typography>
|
<Typography typo={ITypo.P_SB_18}>Sélectionner les documents associés à ce type d'acte</Typography>
|
||||||
|
<Tooltip text="Si vous ne trouvez pas le document que vous souhaitez dans la liste, cliquez sur « Modifier la liste des documents » pour créer ce type de document à la liste" />
|
||||||
</div>
|
</div>
|
||||||
<div className={classes["documents"]}>
|
<div className={classes["documents"]}>
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
@ -171,6 +187,20 @@ export default function DeedTypesInformations(props: IProps) {
|
|||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</Confirm>
|
</Confirm>
|
||||||
|
<Confirm
|
||||||
|
isOpen={isSaveModalOpened}
|
||||||
|
onClose={closeSaveModal}
|
||||||
|
onAccept={saveDocumentTypes}
|
||||||
|
closeBtn
|
||||||
|
header={"Enregistrer les modifications ?"}
|
||||||
|
confirmText={"Enregistrer"}
|
||||||
|
cancelText={"Annuler"}>
|
||||||
|
<div className={classes["modal-content"]}>
|
||||||
|
<Typography typo={ITypo.P_16} className={classes["text"]}>
|
||||||
|
Les documents seront associés à ce type d'acte.
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</Confirm>
|
||||||
</div>
|
</div>
|
||||||
</DefaultDeedTypesDashboard>
|
</DefaultDeedTypesDashboard>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,18 @@
|
|||||||
@import "@Themes/constants.scss";
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
.root {
|
.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 {
|
.document-infos {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
import PenICon from "@Assets/Icons/pen.svg";
|
import PenICon from "@Assets/Icons/pen.svg";
|
||||||
import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes";
|
import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes";
|
||||||
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
@ -10,6 +11,7 @@ import { useRouter } from "next/router";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
|
|
||||||
export default function DocumentTypesInformations() {
|
export default function DocumentTypesInformations() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -33,8 +35,14 @@ export default function DocumentTypesInformations() {
|
|||||||
return (
|
return (
|
||||||
<DefaultDocumentTypesDashboard mobileBackText={"Liste des collaborateurs"}>
|
<DefaultDocumentTypesDashboard mobileBackText={"Liste des collaborateurs"}>
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<div className={classes["folder-header"]}>
|
<div className={classes["header"]}>
|
||||||
<Typography typo={ITypo.H1Bis}>Paramétrage des documents</Typography>
|
<Typography typo={ITypo.H1Bis}>Paramétrage des listes de pièces</Typography>
|
||||||
|
<Link href={Module.getInstance().get().modules.pages.DeedTypes.props.path}>
|
||||||
|
<Button variant={EButtonVariant.LINE}>
|
||||||
|
Retour au paramétrage des types d'actes
|
||||||
|
<Image src={ChevronIcon} alt="Chevron" />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes["document-infos"]}>
|
<div className={classes["document-infos"]}>
|
||||||
<div className={classes["left"]}>
|
<div className={classes["left"]}>
|
||||||
|
@ -9,7 +9,6 @@ import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
|||||||
import BackArrow from "@Front/Components/Elements/BackArrow";
|
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 Module from "@Front/Config/Module";
|
||||||
import { TextField } from "@mui/material";
|
|
||||||
import { ECivility } from "le-coffre-resources/dist/Customer/Contact";
|
import { ECivility } from "le-coffre-resources/dist/Customer/Contact";
|
||||||
import { Customer, OfficeFolder } from "le-coffre-resources/dist/Notary";
|
import { Customer, OfficeFolder } from "le-coffre-resources/dist/Notary";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
@ -17,6 +16,7 @@ import { NextRouter, useRouter } from "next/router";
|
|||||||
|
|
||||||
import BasePage from "../../Base";
|
import BasePage from "../../Base";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import TextField from "@Front/Components/DesignSystem/Form/TextField";
|
||||||
|
|
||||||
enum ESelectedOption {
|
enum ESelectedOption {
|
||||||
EXISTING_CUSTOMER = "existing_customer",
|
EXISTING_CUSTOMER = "existing_customer",
|
||||||
|
@ -34,6 +34,7 @@ type IState = {
|
|||||||
inputArchivedDescripton: string;
|
inputArchivedDescripton: string;
|
||||||
isValidateModalVisible: boolean;
|
isValidateModalVisible: boolean;
|
||||||
hasValidateAnchoring: boolean;
|
hasValidateAnchoring: boolean;
|
||||||
|
isVerifDeleteModalVisible: boolean;
|
||||||
};
|
};
|
||||||
class FolderInformationClass extends BasePage<IPropsClass, IState> {
|
class FolderInformationClass extends BasePage<IPropsClass, IState> {
|
||||||
public constructor(props: IPropsClass) {
|
public constructor(props: IPropsClass) {
|
||||||
@ -44,6 +45,7 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
|
|||||||
inputArchivedDescripton: "",
|
inputArchivedDescripton: "",
|
||||||
isValidateModalVisible: false,
|
isValidateModalVisible: false,
|
||||||
hasValidateAnchoring: false,
|
hasValidateAnchoring: false,
|
||||||
|
isVerifDeleteModalVisible: false,
|
||||||
};
|
};
|
||||||
this.onSelectedFolder = this.onSelectedFolder.bind(this);
|
this.onSelectedFolder = this.onSelectedFolder.bind(this);
|
||||||
this.openArchivedModal = this.openArchivedModal.bind(this);
|
this.openArchivedModal = this.openArchivedModal.bind(this);
|
||||||
@ -55,6 +57,8 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
|
|||||||
this.closeModal = this.closeModal.bind(this);
|
this.closeModal = this.closeModal.bind(this);
|
||||||
this.validateAnchoring = this.validateAnchoring.bind(this);
|
this.validateAnchoring = this.validateAnchoring.bind(this);
|
||||||
this.openValidateModal = this.openValidateModal.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
|
// TODO: Message if the user has not created any folder yet
|
||||||
@ -109,7 +113,7 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{!this.doesFolderHaveCustomer() && (
|
{!this.doesFolderHaveCustomer() && (
|
||||||
<span className={classes["delete-folder"]} onClick={this.deleteFolder}>
|
<span className={classes["delete-folder"]} onClick={this.openVerifDeleteFolder}>
|
||||||
<Button variant={EButtonVariant.SECONDARY}>Supprimer le dossier</Button>
|
<Button variant={EButtonVariant.SECONDARY}>Supprimer le dossier</Button>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@ -131,6 +135,18 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
|
|||||||
onChange={this.onArchivedDescriptionInputChange}
|
onChange={this.onArchivedDescriptionInputChange}
|
||||||
/>
|
/>
|
||||||
</Confirm>
|
</Confirm>
|
||||||
|
<Confirm
|
||||||
|
isOpen={this.state.isVerifDeleteModalVisible}
|
||||||
|
onAccept={this.deleteFolder}
|
||||||
|
onClose={this.closeVerifDeleteFolder}
|
||||||
|
closeBtn
|
||||||
|
header={"Êtes-vous sûr de vouloir supprimer ce dossier ?"}
|
||||||
|
cancelText={"Annuler"}
|
||||||
|
confirmText={"Confirmer"}>
|
||||||
|
<div className={classes["modal-title"]}>
|
||||||
|
<Typography typo={ITypo.P_16}>Cette action sera irréversible.</Typography>
|
||||||
|
</div>
|
||||||
|
</Confirm>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className={classes["no-folder-selected"]}>
|
<div className={classes["no-folder-selected"]}>
|
||||||
@ -187,6 +203,18 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public openVerifDeleteFolder() {
|
||||||
|
this.setState({
|
||||||
|
isVerifDeleteModalVisible: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeVerifDeleteFolder() {
|
||||||
|
this.setState({
|
||||||
|
isVerifDeleteModalVisible: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private closeModal() {
|
private closeModal() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isValidateModalVisible: false,
|
isValidateModalVisible: false,
|
||||||
|
@ -13,6 +13,7 @@ import { NextRouter, useRouter } from "next/router";
|
|||||||
|
|
||||||
import BasePage from "../../Base";
|
import BasePage from "../../Base";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import DateField from "@Front/Components/DesignSystem/Form/DateField";
|
||||||
|
|
||||||
type IProps = {};
|
type IProps = {};
|
||||||
|
|
||||||
@ -43,6 +44,8 @@ class UpdateFolderMetadataClass extends BasePage<IPropsClass, IState> {
|
|||||||
value: this.state.selectedFolder?.deed?.deed_type?.uid,
|
value: this.state.selectedFolder?.deed?.deed_type?.uid,
|
||||||
} as IOption;
|
} as IOption;
|
||||||
const openingDate = new Date(this.state.selectedFolder?.created_at ?? "");
|
const openingDate = new Date(this.state.selectedFolder?.created_at ?? "");
|
||||||
|
if (!this.state.selectedFolder?.created_at) return <></>;
|
||||||
|
const defaultValue = openingDate.toISOString().split("T")[0];
|
||||||
return (
|
return (
|
||||||
<DefaultNotaryDashboard title={"Ajouter client(s)"} onSelectedFolder={this.onSelectedFolder}>
|
<DefaultNotaryDashboard title={"Ajouter client(s)"} onSelectedFolder={this.onSelectedFolder}>
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
@ -60,7 +63,7 @@ class UpdateFolderMetadataClass extends BasePage<IPropsClass, IState> {
|
|||||||
defaultValue={this.state.selectedFolder?.folder_number}
|
defaultValue={this.state.selectedFolder?.folder_number}
|
||||||
/>
|
/>
|
||||||
<Select name="deed" options={[]} placeholder={"Type d'acte"} selectedOption={deedOption} disabled />
|
<Select name="deed" options={[]} placeholder={"Type d'acte"} selectedOption={deedOption} disabled />
|
||||||
<TextField placeholder="Ouverture du dossier" defaultValue={openingDate.toLocaleDateString("fr-FR")} disabled />
|
<DateField name="opening_date" placeholder="Ouverture du dossier" defaultValue={defaultValue} disabled />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={classes["button-container"]}>
|
<div className={classes["button-container"]}>
|
||||||
|
@ -49,6 +49,7 @@ export default class ClientSection extends React.Component<IProps, IState> {
|
|||||||
key={customer.uid}
|
key={customer.uid}
|
||||||
isOpened={this.state.openedCustomer === customer.uid}
|
isOpened={this.state.openedCustomer === customer.uid}
|
||||||
onChange={this.changeUserFolder}
|
onChange={this.changeUserFolder}
|
||||||
|
isArchived
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -12,6 +12,8 @@ import { useCallback, useState } from "react";
|
|||||||
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import JwtService from "@Front/Services/JwtService/JwtService";
|
import JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
|
import Rules, { RulesMode } from "@Front/Components/Elements/Rules";
|
||||||
|
import { AppRuleActions, AppRuleNames } from "@Front/Api/Entities/rule";
|
||||||
|
|
||||||
type IProps = {};
|
type IProps = {};
|
||||||
export default function RolesCreate(props: IProps) {
|
export default function RolesCreate(props: IProps) {
|
||||||
@ -61,6 +63,14 @@ export default function RolesCreate(props: IProps) {
|
|||||||
}, [hasChanged, redirect]);
|
}, [hasChanged, redirect]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Rules
|
||||||
|
mode={RulesMode.NECESSARY}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
action: AppRuleActions.create,
|
||||||
|
name: AppRuleNames.officeRoles,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
<DefaultRolesDashboard mobileBackText={"Liste des rôles"} hasBackArrow title="Créer un rôle">
|
<DefaultRolesDashboard mobileBackText={"Liste des rôles"} hasBackArrow title="Créer un rôle">
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<div className={classes["header"]}>
|
<div className={classes["header"]}>
|
||||||
@ -91,5 +101,6 @@ export default function RolesCreate(props: IProps) {
|
|||||||
</Confirm>
|
</Confirm>
|
||||||
</div>
|
</div>
|
||||||
</DefaultRolesDashboard>
|
</DefaultRolesDashboard>
|
||||||
|
</Rules>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,11 @@ export default function UserInformations(props: IProps) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!userSelected) return;
|
if (!userSelected) return;
|
||||||
setCurrentAppointment(userSelected?.appointment?.find((appointment) => appointment.status === EAppointmentStatus.OPEN && appointment.votes?.length != 0) ?? null);
|
setCurrentAppointment(
|
||||||
|
userSelected?.appointment?.find(
|
||||||
|
(appointment) => appointment.status === EAppointmentStatus.OPEN && appointment.votes?.length != 0,
|
||||||
|
) ?? null,
|
||||||
|
);
|
||||||
}, [userSelected]);
|
}, [userSelected]);
|
||||||
|
|
||||||
/** Functions for the admin modal */
|
/** Functions for the admin modal */
|
||||||
@ -271,7 +275,7 @@ export default function UserInformations(props: IProps) {
|
|||||||
onChange={handleRoleChange}
|
onChange={handleRoleChange}
|
||||||
selectedOption={{
|
selectedOption={{
|
||||||
value: userSelected?.office_role ? userSelected?.office_role?.uid : userSelected?.role?.uid,
|
value: userSelected?.office_role ? userSelected?.office_role?.uid : userSelected?.role?.uid,
|
||||||
label: userSelected?.office_role ? userSelected?.office_role?.name : userSelected?.role?.label!,
|
label: userSelected?.office_role ? userSelected?.office_role?.name : "Utilisateur restreint",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -282,7 +286,12 @@ export default function UserInformations(props: IProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className={classes["second-line"]}>
|
<div className={classes["second-line"]}>
|
||||||
<Switch label="Admin de son office" checked={isAdminChecked} onChange={handleAdminChanged} />
|
<Switch label="Admin de son office" checked={isAdminChecked} onChange={handleAdminChanged} />
|
||||||
<Switch label="Super-admin LeCoffre.io" checked={isSuperAdminChecked} disabled={userHasVoted()} onChange={handleSuperAdminChanged} />
|
<Switch
|
||||||
|
label="Super-admin LeCoffre.io"
|
||||||
|
checked={isSuperAdminChecked}
|
||||||
|
disabled={userHasVoted()}
|
||||||
|
onChange={handleSuperAdminChanged}
|
||||||
|
/>
|
||||||
{currentAppointment && (
|
{currentAppointment && (
|
||||||
<div className={classes["votes-block"]}>
|
<div className={classes["votes-block"]}>
|
||||||
<div className={classes["left"]}>
|
<div className={classes["left"]}>
|
||||||
|
@ -68,10 +68,8 @@ export default class JwtService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public hasRule(name: string, action: string) {
|
public hasRule(name: string, action: string) {
|
||||||
const accessToken = CookieService.getInstance().getCookie("leCoffreAccessToken");
|
const token = this.decodeJwt();
|
||||||
if (!accessToken) return false;
|
if (!token) return false;
|
||||||
const decodedToken = this.decodeJwt();
|
return token?.rules?.some((rule: string) => rule === `${action} ${name}`);
|
||||||
if (!decodedToken) return false;
|
|
||||||
return decodedToken?.rules?.some((rule: string) => rule === `${action} ${name}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,22 +22,6 @@ export async function middleware(request: NextRequest) {
|
|||||||
return NextResponse.redirect(new URL("/login", request.url));
|
return NextResponse.redirect(new URL("/login", request.url));
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestUrlPath = request.nextUrl.pathname;
|
|
||||||
if (
|
|
||||||
requestUrlPath.startsWith("/collaborators") ||
|
|
||||||
requestUrlPath.startsWith("/deed-types") ||
|
|
||||||
requestUrlPath.startsWith("/customer") ||
|
|
||||||
requestUrlPath.startsWith("/offices") ||
|
|
||||||
requestUrlPath.startsWith("/roles") ||
|
|
||||||
requestUrlPath.startsWith("/users")
|
|
||||||
) {
|
|
||||||
if (userDecodedToken.role !== "admin" && userDecodedToken.role !== "super-admin")
|
|
||||||
return NextResponse.redirect(new URL("/404", request.url));
|
|
||||||
}
|
|
||||||
if ((requestUrlPath.startsWith("/my-account") || requestUrlPath.startsWith("/document-types")) && !userDecodedToken)
|
|
||||||
return NextResponse.redirect(new URL("/404", request.url));
|
|
||||||
if (requestUrlPath.startsWith("/client-dashboard") && !customerDecodedToken) return NextResponse.redirect(new URL("/404", request.url));
|
|
||||||
|
|
||||||
return NextResponse.next();
|
return NextResponse.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user