Edit document types working

This commit is contained in:
Maxime Lalo 2023-07-24 14:53:07 +02:00
parent 9acb1a7dd2
commit af7d26ffe7
18 changed files with 735 additions and 3 deletions

View File

@ -37,10 +37,12 @@ export default class DocumentTypes extends BaseSuperAdmin {
}
}
public async get(q: IGetDocumentTypesparams): Promise<DocumentType[]> {
public async get(q?: IGetDocumentTypesparams): Promise<DocumentType[]> {
const url = new URL(this.baseURl);
if (q) {
const query = { q };
if (q) Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
}
try {
return await this.getRequest<DocumentType[]>(url);
} catch (err) {

View File

@ -0,0 +1,21 @@
@import "@Themes/constants.scss";
.root {
width: calc(100vh - 83px);
display: flex;
flex-direction: column;
justify-content: space-between;
.header {
flex: 1;
}
.searchbar {
padding: 40px 24px 24px 24px;
}
.folderlist-container {
height: 100%;
border-right: 1px solid var(--grey-medium);
}
}

View File

@ -0,0 +1,62 @@
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
import Module from "@Front/Config/Module";
import { DocumentType } from "le-coffre-resources/dist/SuperAdmin";
import { useRouter } from "next/router";
import React, { useCallback, useState } from "react";
import classes from "./classes.module.scss";
type IProps = {
documentTypes: DocumentType[];
onSelectedDocumentType?: (documentType: DocumentType) => void;
onCloseLeftSide?: () => void;
};
export default function DocumentTypeListContainer(props: IProps) {
const [filteredDocumentTypes, setFilteredDocumentTypes] = useState<DocumentType[]>(props.documentTypes);
const router = useRouter();
const { documentTypeUid } = router.query;
const filterDocumentTypes = useCallback(
(input: string) => {
const filteredDocumentTypes = props.documentTypes.filter((documentType) => {
return documentType.name.toLowerCase().includes(input.toLowerCase());
});
setFilteredDocumentTypes(filteredDocumentTypes);
},
[props.documentTypes],
);
const onSelectedBlock = useCallback(
(block: IBlock) => {
props.onCloseLeftSide && props.onCloseLeftSide();
console.log("Block selected :", block);
const redirectPath = Module.getInstance().get().modules.pages.DocumentTypes.pages.Edit.props.path;
router.push(redirectPath.replace("[uid]", block.id));
},
[props, router],
);
return (
<div className={classes["root"]}>
<div className={classes["header"]}>
<div className={classes["searchbar"]}>
<SearchBar onChange={filterDocumentTypes} placeholder="Chercher un document" />
</div>
<div className={classes["folderlist-container"]}>
<BlockList
blocks={filteredDocumentTypes.map((documentType) => {
return {
name: documentType.name,
id: documentType.uid!,
selected: documentType.uid === documentTypeUid,
};
})}
onSelectedBlock={onSelectedBlock}
/>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,117 @@
@import "@Themes/constants.scss";
@keyframes growWidth {
0% {
width: 100%;
}
100% {
width: 200%;
}
}
.root {
.content {
display: flex;
overflow: hidden;
height: calc(100vh - 83px);
.overlay {
position: absolute;
width: 100%;
height: 100%;
background-color: var(--white);
opacity: 0.5;
z-index: 2;
transition: all 0.3s $custom-easing;
}
.left-side {
background-color: $white;
z-index: 3;
display: flex;
width: 389px;
min-width: 389px;
transition: all 0.3s $custom-easing;
overflow: hidden;
@media (max-width: ($screen-m - 1px)) {
width: 56px;
min-width: 56px;
transform: translateX(-389px);
&.opened {
transform: translateX(0px);
width: 389px;
min-width: 389px;
}
}
@media (max-width: $screen-s) {
width: 0px;
min-width: 0px;
&.opened {
width: 100vw;
min-width: 100vw;
}
}
}
.closable-left-side {
position: absolute;
background-color: $white;
z-index: 0;
display: flex;
justify-content: center;
min-width: 56px;
max-width: 56px;
height: calc(100vh - 83px);
border-right: 1px $grey-medium solid;
@media (min-width: $screen-m) {
display: none;
}
.chevron-icon {
margin-top: 21px;
transform: rotate(180deg);
cursor: pointer;
}
@media (max-width: $screen-s) {
display: none;
}
}
.right-side {
min-width: calc(100vw - 389px);
padding: 64px 48px;
overflow-y: auto;
@media (max-width: ($screen-m - 1px)) {
min-width: calc(100vw - 56px);
}
@media (max-width: $screen-s) {
padding: 40px 16px 64px 16px;
flex: 1;
min-width: unset;
}
.back-arrow-mobile {
display: none;
@media (max-width: $screen-s) {
display: block;
margin-bottom: 24px;
}
}
.back-arrow-desktop {
@media (max-width: $screen-s) {
display: none;
}
}
}
}
}

View File

@ -0,0 +1,118 @@
import ChevronIcon from "@Assets/Icons/chevron.svg";
import DocumentTypes from "@Front/Api/LeCoffreApi/SuperAdmin/DocumentTypes/DocumentTypes";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Header from "@Front/Components/DesignSystem/Header";
import Version from "@Front/Components/DesignSystem/Version";
import BackArrow from "@Front/Components/Elements/BackArrow";
import WindowStore from "@Front/Stores/WindowStore";
import classNames from "classnames";
import { DocumentType } from "le-coffre-resources/dist/Notary";
import Image from "next/image";
import React, { ReactNode } from "react";
import classes from "./classes.module.scss";
import DocumentTypeListContainer from "./DocumentTypeListContainer";
type IProps = {
title: string;
children?: ReactNode;
onSelectedDocumentType: (documentType: DocumentType) => void;
hasBackArrow: boolean;
backArrowUrl?: string;
mobileBackText?: string;
};
type IState = {
documentTypes: DocumentType[] | null;
isLeftSideOpen: boolean;
leftSideCanBeClosed: boolean;
};
export default class DefaultDocumentTypesDashboard extends React.Component<IProps, IState> {
private onWindowResize = () => {};
public static defaultProps: Partial<IProps> = {
hasBackArrow: false,
};
public constructor(props: IProps) {
super(props);
this.state = {
documentTypes: null,
isLeftSideOpen: false,
leftSideCanBeClosed: typeof window !== "undefined" ? window.innerWidth < 1024 : false,
};
this.onOpenLeftSide = this.onOpenLeftSide.bind(this);
this.onCloseLeftSide = this.onCloseLeftSide.bind(this);
}
public override render(): JSX.Element {
return (
<div className={classes["root"]}>
<Header isUserConnected={true} />
<div className={classes["content"]}>
{this.state.isLeftSideOpen && <div className={classes["overlay"]} onClick={this.onCloseLeftSide} />}
<div className={classNames(classes["left-side"], this.state.isLeftSideOpen && classes["opened"])}>
{this.state.documentTypes && (
<DocumentTypeListContainer documentTypes={this.state.documentTypes} onCloseLeftSide={this.onCloseLeftSide} />
)}
</div>
<div className={classNames(classes["closable-left-side"])}>
<Image alt="open side menu" src={ChevronIcon} className={classes["chevron-icon"]} onClick={this.onOpenLeftSide} />
</div>
<div className={classes["right-side"]}>
{this.props.hasBackArrow && (
<div className={classes["back-arrow-desktop"]}>
<BackArrow url={this.props.backArrowUrl ?? ""} />
</div>
)}
{this.props.mobileBackText && (
<div className={classes["back-arrow-mobile"]}>
<Button
icon={ChevronIcon}
iconposition={"left"}
iconstyle={{ transform: "rotate(180deg)", width: "22px", height: "22px" }}
variant={EButtonVariant.LINE}
onClick={this.onOpenLeftSide}>
{this.props.mobileBackText ?? "Retour"}
</Button>
</div>
)}
{this.props.children}
</div>
</div>
<Version />
</div>
);
}
public override async componentDidMount() {
this.onWindowResize = WindowStore.getInstance().onResize((window) => this.onResize(window));
const documentTypes = await DocumentTypes.getInstance().get({
where: {
office_uid: "6981326f-8a0a-4437-b15c-4cd5c4d80f6e",
},
});
this.setState({ documentTypes });
}
public override componentWillUnmount() {
this.onWindowResize();
}
private onOpenLeftSide() {
this.setState({ isLeftSideOpen: true });
}
private onCloseLeftSide() {
if (!this.state.leftSideCanBeClosed) return;
this.setState({ isLeftSideOpen: false });
}
private onResize(window: Window) {
if (window.innerWidth > 1023) {
if (!this.state.leftSideCanBeClosed) return;
this.setState({ leftSideCanBeClosed: false });
}
this.setState({ leftSideCanBeClosed: true });
}
}

View File

@ -0,0 +1,24 @@
@import "@Themes/constants.scss";
.root {
.header {
margin-top: 24px;
}
.form-container {
margin-top: 32px;
display: flex;
flex-direction: column;
gap: 32px;
}
.buttons-container {
display: flex;
gap: 32px;
@media (max-width: $screen-s) {
flex-direction: column-reverse;
gap: 16px;
}
}
}

View File

@ -0,0 +1,32 @@
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import DefaultDeedTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDeedTypeDashboard";
import { useCallback } from "react";
import classes from "./classes.module.scss";
import TextField from "@Front/Components/DesignSystem/Form/TextField";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
type IProps = {};
export default function DeedTypesCreate(props: IProps) {
const onSubmitHandler = useCallback(async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {}, []);
return (
<DefaultDeedTypesDashboard mobileBackText={"Liste des types d'actes"} hasBackArrow title="Créer un type d'acte">
<div className={classes["root"]}>
<div className={classes["header"]}>
<Typography typo={ITypo.H1Bis}>Créer un type d'acte</Typography>
</div>
<Form onSubmit={onSubmitHandler} className={classes["form-container"]}>
<TextField name="name" placeholder="Nom de l'acte" />
<TextAreaField name="description" placeholder="Description" />
<div className={classes["buttons-container"]}>
<Button variant={EButtonVariant.GHOST}>Annuler</Button>
<Button type="submit">Créer le type d'acte</Button>
</div>
</Form>
</div>
</DefaultDeedTypesDashboard>
);
}

View File

@ -0,0 +1,24 @@
@import "@Themes/constants.scss";
.root {
.header {
margin-top: 24px;
}
.form-container {
margin-top: 32px;
display: flex;
flex-direction: column;
gap: 32px;
}
.buttons-container {
display: flex;
gap: 32px;
@media (max-width: $screen-s) {
flex-direction: column-reverse;
gap: 16px;
}
}
}

View File

@ -0,0 +1,58 @@
import DocumentTypes from "@Front/Api/LeCoffreApi/Admin/DocumentTypes/DocumentTypes";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
import TextField from "@Front/Components/DesignSystem/Form/TextField";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import DefaultDocumentTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDocumentTypesDashboard";
import { DocumentType } from "le-coffre-resources/dist/Admin";
import { useRouter } from "next/router";
import { useCallback, useEffect, useState } from "react";
import classes from "./classes.module.scss";
export default function DocumentTypesEdit() {
const router = useRouter();
let { documentTypeUid } = router.query;
const [documentTypeSelected, setDocumentTypeSelected] = useState<DocumentType | null>(null);
useEffect(() => {
async function getDocumentType() {
if (!documentTypeUid) return;
const documentType = await DocumentTypes.getInstance().getByUid(documentTypeUid as string);
setDocumentTypeSelected(documentType);
}
getDocumentType();
}, [documentTypeUid]);
const onSubmitHandler = useCallback(async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {}, []);
return (
<DefaultDocumentTypesDashboard mobileBackText={"Liste des documents"} hasBackArrow title="Modifier un type de doucment">
<div className={classes["root"]}>
<div className={classes["header"]}>
<Typography typo={ITypo.H1Bis}>Paramétrage des documents</Typography>
</div>
<Form onSubmit={onSubmitHandler} className={classes["form-container"]}>
<TextField name="name" placeholder="Nom du document" defaultValue={documentTypeSelected?.name} />
<TextAreaField
name="private_description"
placeholder="Description visible par les collaborateurs de l'office"
defaultValue={documentTypeSelected?.private_description ?? ""}
/>
<TextAreaField
name="public_description"
placeholder="Description visible par les clients de loffice"
defaultValue={documentTypeSelected?.public_description}
/>
<div className={classes["buttons-container"]}>
<Button variant={EButtonVariant.GHOST}>Annuler</Button>
<Button type="submit">Enregistrer</Button>
</div>
</Form>
</div>
</DefaultDocumentTypesDashboard>
);
}

View File

@ -0,0 +1,91 @@
@import "@Themes/constants.scss";
.root {
.header {
display: flex;
justify-content: space-between;
align-items: flex-end;
@media (max-width: $screen-l) {
flex-direction: column;
align-items: flex-start;
gap: 24px;
}
}
.subtitle {
margin-top: 32px;
}
.deed-type-container {
margin-top: 32px;
display: flex;
gap: 100px;
justify-content: space-between;
padding: 24px;
background-color: var(--grey-soft);
@media (max-width: $screen-l) {
gap: 80px;
}
@media (max-width: $screen-m) {
flex-direction: column;
gap: 32px;
}
.infos {
display: flex;
gap: 100px;
flex: 1;
@media (max-width: $screen-l) {
flex-direction: column;
gap: 32px;
}
.box {
.box-title {
margin-bottom: 8px;
opacity: 0.4;
}
}
.middle-box {
flex: 1;
}
}
.pencil {
align-self: center;
@media (max-width: $screen-m) {
align-self: flex-start;
}
}
}
.documents-container {
margin-top: 32px;
padding: 32px 16px;
border: 1px solid var(--grey);
.container-title {
}
.documents {
margin-top: 32px;
}
.button-container {
margin-top: 32px;
}
}
.delete-container {
display: flex;
justify-content: center;
margin-top: 32px;
}
}

View File

@ -0,0 +1,90 @@
import ChevronIcon from "@Assets/Icons/chevron.svg";
import PenICon from "@Assets/Icons/pen.svg";
import DocumentTypes from "@Front/Api/LeCoffreApi/Admin/DocumentTypes/DocumentTypes";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import DefaultDocumentTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDocumentTypesDashboard";
import Module from "@Front/Config/Module";
import classNames from "classnames";
import { DocumentType } from "le-coffre-resources/dist/Admin";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { useCallback, useEffect, useState } from "react";
import classes from "./classes.module.scss";
type IProps = {};
export default function DocumentTypesInformations(props: IProps) {
const router = useRouter();
let { documentTypeUid } = router.query;
const [documentTypeSelected, setDocumentTypeSelected] = useState<DocumentType | null>(null);
useEffect(() => {
async function getDocumentType() {
if (!documentTypeUid) return;
const documentType = await DocumentTypes.getInstance().getByUid(documentTypeUid as string);
setDocumentTypeSelected(documentType);
}
getDocumentType();
}, [documentTypeUid]);
const onSubmitHandler = useCallback(async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {}, []);
return (
<DefaultDocumentTypesDashboard mobileBackText={"Liste des types d'actes"}>
<div className={classes["root"]}>
<div className={classes["header"]}>
<Typography typo={ITypo.H1Bis}>Paramétrage des listes de pièces</Typography>
<Button variant={EButtonVariant.LINE}>
Modifier la liste des documents
<Image src={ChevronIcon} alt="Chevron" />
</Button>
</div>
<div className={classes["subtitle"]}>
<Typography typo={ITypo.H3}>{documentTypeSelected?.name}</Typography>
</div>
<div className={classes["deed-type-container"]}>
<div className={classes["infos"]}>
<div className={classes["box"]}>
<Typography typo={ITypo.NAV_INPUT_16} className={classes["box-title"]} color={ITypoColor.BLACK}>
Nom du type d'acte
</Typography>
<Typography typo={ITypo.P_18}>{documentTypeSelected?.name}</Typography>
</div>
<div className={classNames(classes["middle-box"], classes["box"])}>
<Typography typo={ITypo.NAV_INPUT_16} className={classes["box-title"]} color={ITypoColor.BLACK}>
Description
</Typography>
</div>
</div>
<div className={classes["pencil"]}>
<Link
href={Module.getInstance()
.get()
.modules.pages.DocumentTypes.pages.Edit.props.path.replace("[uid]", documentTypeUid as string)}
className={classes["edit-icon-container"]}>
<Image src={PenICon} alt="éditer le type d'acte" />
</Link>
</div>
</div>
<div className={classes["documents-container"]}>
<Form onSubmit={onSubmitHandler}>
<div className={classes["container-title"]}>
<Typography typo={ITypo.P_SB_18}>Documents paramétrés</Typography>
</div>
<div className={classes["button-container"]}>
<Button type="submit">Enregistrer</Button>
</div>
</Form>
</div>
<div className={classes["delete-container"]}>
<Button variant={EButtonVariant.GHOST}>Supprimer</Button>
</div>
</div>
</DefaultDocumentTypesDashboard>
);
}

View File

@ -0,0 +1,17 @@
@import "@Themes/constants.scss";
.root {
display: flex;
align-items: center;
flex-direction: column;
min-height: 100%;
.no-role-selected {
width: 100%;
.choose-a-role {
margin-top: 96px;
text-align: center;
}
}
}

View File

@ -0,0 +1,26 @@
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import DefaultDocumentTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDocumentTypesDashboard";
import BasePage from "../Base";
import classes from "./classes.module.scss";
type IProps = {};
type IState = {};
export default class DocumentTypes extends BasePage<IProps, IState> {
public override render(): JSX.Element {
return (
<DefaultDocumentTypesDashboard mobileBackText={"Liste des documentss"}>
<div className={classes["root"]}>
<div className={classes["no-role-selected"]}>
<Typography typo={ITypo.H1Bis}>Paramétrage des documents</Typography>
<div className={classes["choose-a-role"]}>
<Typography typo={ITypo.P_18} color={ITypoColor.GREY}>
Sélectionnez un document
</Typography>
</div>
</div>
</div>
</DefaultDocumentTypesDashboard>
);
}
}

View File

@ -213,6 +213,36 @@
}
}
},
"DocumentTypes": {
"enabled": true,
"props": {
"path": "/document-types",
"labelKey": "documentTypes"
},
"pages": {
"DocumentTypesInformations": {
"enabled": true,
"props": {
"path": "/document-types/[uid]",
"labelKey": "documentInformations"
}
},
"Create": {
"enabled": true,
"props": {
"path": "/document-types/create",
"labelKey": "createDocumentType"
}
},
"Edit": {
"enabled": true,
"props": {
"path": "/document-types/[uid]/edit",
"labelKey": "editDocumentType"
}
}
}
},
"404": {
"enabled": true,
"props": {

View File

@ -0,0 +1,5 @@
import DocumentTypesEdit from "@Front/Components/Layouts/DocumentTypes/DocumentTypesEdit";
export default function Route() {
return <DocumentTypesEdit />;
}

View File

@ -0,0 +1,5 @@
import DocumentTypesInformations from "@Front/Components/Layouts/DocumentTypes/DocumentTypesInformations";
export default function Route() {
return <DocumentTypesInformations />;
}

View File

@ -0,0 +1,5 @@
import DocumentTypesCreate from "@Front/Components/Layouts/DocumentTypes/DocumentTypesCreate";
export default function Route() {
return <DocumentTypesCreate />;
}

View File

@ -0,0 +1,5 @@
import DocumentTypes from "@Front/Components/Layouts/DocumentTypes";
export default function Route() {
return <DocumentTypes />;
}