Front end Componentss (#5)
1) Progress Bar https://app.ora.pm/p/fb56ed95daa7456b888d266a050b9afa?v=86662&s=28564&t=k&c=2c1d4ce11f4747b7bcd9814336a8e882 2) Folder Component https://app.ora.pm/p/fb56ed95daa7456b888d266a050b9afa?v=86662&s=28564&t=k&c=1abbfeae008a486facf59e3cb2ccdd86 3) Api frontend (pas de tickets correspondants) 4) Ask/Pending/Validated/ documents (pas de tickets correspondants) 5) Multiselect [WIP] -> Error message not displaying when the user search and didn't find in the corresponding options https://app.ora.pm/p/fb56ed95daa7456b888d266a050b9afa?v=86662&s=28564&t=k&c=1d5ec1f29d2644d3ac7a0c309608c6e3 6) Document Notary Component https://app.ora.pm/p/fb56ed95daa7456b888d266a050b9afa?v=86662&s=28564&t=k&c=e2da114abf5d40a5adc0c411f7f86c8d 7) Notary Documents For Users Components with filters for each users according to the document status https://app.ora.pm/p/fb56ed95daa7456b888d266a050b9afa?v=86662&s=28564&t=k&c=c682d55c2d42438f9a880493a5ac6b12 8) Fix Local Docker Compose Front (pas de tickets correspondants) 9) DropDown Component https://app.ora.pm/p/fb56ed95daa7456b888d266a050b9afa?v=86662&s=28564&t=k&c=933bcc4418ea46f88c696e52b97d7bfc 10) Minor Fixes https://app.ora.pm/p/fb56ed95daa7456b888d266a050b9afa?v=86662&s=28564&t=k&c=0c799226315c4d7ca7ee13648105cfcf https://app.ora.pm/p/fb56ed95daa7456b888d266a050b9afa?v=86662&s=28564&t=k&c=eb9838e8ad894ac5b43e4c8562bc6450 --------- Co-authored-by: leabruchon <89223887+leabruchon@users.noreply.github.com>
This commit is contained in:
parent
8001cd4aa9
commit
e98b8b601b
4167
package-lock.json
generated
4167
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -20,13 +20,13 @@
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "8.36.0",
|
||||
"eslint-config-next": "13.2.4",
|
||||
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.18",
|
||||
"next": "13.2.4",
|
||||
"react": "18.2.0",
|
||||
"react-apexcharts": "^1.4.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-tsparticles": "^2.9.3",
|
||||
"react-select": "^5.7.2",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"sass": "^1.59.2",
|
||||
"tsparticles": "^2.9.3",
|
||||
"typedi": "^0.10.0",
|
||||
"typescript": "4.9.5"
|
||||
}
|
||||
|
5
src/front/Api/LeCoffreApi/Customer/BaseCustomer.ts
Normal file
5
src/front/Api/LeCoffreApi/Customer/BaseCustomer.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import BaseApiService from "@Front/Api/BaseApiService";
|
||||
|
||||
export default abstract class BaseNotary extends BaseApiService {
|
||||
protected readonly namespaceUrl = this.backUrl.concat("/customers");
|
||||
}
|
51
src/front/Api/LeCoffreApi/Customer/Users/Users.ts
Normal file
51
src/front/Api/LeCoffreApi/Customer/Users/Users.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { Service } from "typedi";
|
||||
import BaseNotary from "../BaseCustomer";
|
||||
import User from "le-coffre-resources/dist/Notary";
|
||||
|
||||
@Service()
|
||||
export default class Users extends BaseNotary {
|
||||
private static instance: Users;
|
||||
private readonly baseURl = this.namespaceUrl.concat("/Users");
|
||||
|
||||
private constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static getInstance() {
|
||||
if (!this.instance) {
|
||||
return new Users();
|
||||
} else {
|
||||
return this.instance;
|
||||
}
|
||||
}
|
||||
|
||||
public async get(): Promise<User[]> {
|
||||
const url = new URL(this.baseURl);
|
||||
try {
|
||||
return await this.getRequest<User[]>(url);
|
||||
} catch (err) {
|
||||
this.onError(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
public async getOne(uid: string): Promise<User> {
|
||||
const url = new URL(this.baseURl.concat("/").concat(uid));
|
||||
try {
|
||||
return await this.getRequest<User>(url);
|
||||
} catch (err) {
|
||||
this.onError(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
// public async post(params: User): Promise<User> {
|
||||
// const url = new URL(this.baseURl);
|
||||
// try {
|
||||
// return await this.postRequest<User>(url, params);
|
||||
// } catch (err) {
|
||||
// this.onError(err);
|
||||
// return Promise.reject(err);
|
||||
// }
|
||||
// }
|
||||
}
|
5
src/front/Api/LeCoffreApi/Notary/BaseNotary.ts
Normal file
5
src/front/Api/LeCoffreApi/Notary/BaseNotary.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import BaseApiService from "@Front/Api/BaseApiService";
|
||||
|
||||
export default abstract class BaseNotary extends BaseApiService {
|
||||
protected readonly namespaceUrl = this.backUrl.concat("/notary");
|
||||
}
|
51
src/front/Api/LeCoffreApi/Notary/Users/Users.ts
Normal file
51
src/front/Api/LeCoffreApi/Notary/Users/Users.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { Service } from "typedi";
|
||||
import BaseNotary from "../BaseNotary";
|
||||
import User from "le-coffre-resources/dist/Notary";
|
||||
|
||||
@Service()
|
||||
export default class Users extends BaseNotary {
|
||||
private static instance: Users;
|
||||
private readonly baseURl = this.namespaceUrl.concat("/Users");
|
||||
|
||||
private constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static getInstance() {
|
||||
if (!this.instance) {
|
||||
return new Users();
|
||||
} else {
|
||||
return this.instance;
|
||||
}
|
||||
}
|
||||
|
||||
public async get(): Promise<User[]> {
|
||||
const url = new URL(this.baseURl);
|
||||
try {
|
||||
return await this.getRequest<User[]>(url);
|
||||
} catch (err) {
|
||||
this.onError(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
public async getOne(uid: string): Promise<User> {
|
||||
const url = new URL(this.baseURl.concat("/").concat(uid));
|
||||
try {
|
||||
return await this.getRequest<User>(url);
|
||||
} catch (err) {
|
||||
this.onError(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
// public async post(params: User): Promise<User> {
|
||||
// const url = new URL(this.baseURl);
|
||||
// try {
|
||||
// return await this.postRequest<User>(url, params);
|
||||
// } catch (err) {
|
||||
// this.onError(err);
|
||||
// return Promise.reject(err);
|
||||
// }
|
||||
// }
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
import BaseApiService from "src/front/Api/BaseApiService";
|
||||
import { IProject } from "src/front/interfaces";
|
||||
import { Service } from "typedi";
|
||||
|
||||
type IPostProject = {
|
||||
title: string;
|
||||
network: string;
|
||||
};
|
||||
@Service()
|
||||
export default class Project extends BaseApiService {
|
||||
private static instance: Project;
|
||||
private readonly baseURl = this.backUrl.concat("/projects");
|
||||
|
||||
private constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static getInstance() {
|
||||
if (!this.instance) {
|
||||
return new Project();
|
||||
} else {
|
||||
return this.instance;
|
||||
}
|
||||
}
|
||||
|
||||
public async getAllProject(): Promise<IProject[]> {
|
||||
const url = new URL(this.baseURl);
|
||||
try {
|
||||
return await this.getRequest<IProject[]>(url);
|
||||
} catch (err) {
|
||||
this.onError(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
public async getOneProject(uuid: string): Promise<IProject> {
|
||||
const url = new URL(this.baseURl.concat("/").concat(uuid));
|
||||
try {
|
||||
return await this.getRequest<IProject>(url);
|
||||
} catch (err) {
|
||||
this.onError(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
public async postProject(params: IPostProject): Promise<IProject> {
|
||||
const url = new URL(this.baseURl);
|
||||
try {
|
||||
return await this.postRequest<IProject>(url, params);
|
||||
} catch (err) {
|
||||
this.onError(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
}
|
4
src/front/Assets/icons/check-valid.svg
Normal file
4
src/front/Assets/icons/check-valid.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 7.33366L8 9.33366L14.6667 2.66699" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M14 8V12.6667C14 13.0203 13.8595 13.3594 13.6095 13.6095C13.3594 13.8595 13.0203 14 12.6667 14H3.33333C2.97971 14 2.64057 13.8595 2.39052 13.6095C2.14048 13.3594 2 13.0203 2 12.6667V3.33333C2 2.97971 2.14048 2.64057 2.39052 2.39052C2.64057 2.14048 2.97971 2 3.33333 2H10.6667" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 598 B |
3
src/front/Assets/icons/chevron.svg
Normal file
3
src/front/Assets/icons/chevron.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.5 18L15.5 12L9.5 6" stroke="#101010" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 218 B |
3
src/front/Assets/icons/pen.svg
Normal file
3
src/front/Assets/icons/pen.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17 3.5003C17.2626 3.23766 17.5744 3.02932 17.9176 2.88718C18.2608 2.74503 18.6286 2.67188 19 2.67188C19.3714 2.67187 19.7392 2.74503 20.0824 2.88718C20.4256 3.02932 20.7374 3.23766 21 3.5003C21.2626 3.76295 21.471 4.07475 21.6131 4.41791C21.7553 4.76107 21.8284 5.12887 21.8284 5.5003C21.8284 5.87174 21.7553 6.23953 21.6131 6.58269C21.471 6.92585 21.2626 7.23766 21 7.5003L7.5 21.0003L2 22.5003L3.5 17.0003L17 3.5003Z" stroke="#939393" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 616 B |
3
src/front/Assets/icons/plus.svg
Normal file
3
src/front/Assets/icons/plus.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11 5V19M4 12H18" stroke="#BD4B91" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 213 B |
6
src/front/Assets/icons/trash.svg
Normal file
6
src/front/Assets/icons/trash.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 6H5H21" stroke="#939393" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8 6V4C8 3.46957 8.21071 2.96086 8.58579 2.58579C8.96086 2.21071 9.46957 2 10 2H14C14.5304 2 15.0391 2.21071 15.4142 2.58579C15.7893 2.96086 16 3.46957 16 4V6M19 6V20C19 20.5304 18.7893 21.0391 18.4142 21.4142C18.0391 21.7893 17.5304 22 17 22H7C6.46957 22 5.96086 21.7893 5.58579 21.4142C5.21071 21.0391 5 20.5304 5 20V6H19Z" stroke="#939393" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M14 11V17" stroke="#939393" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10 11V17" stroke="#939393" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 830 B |
12
src/front/Assets/icons/warning.svg
Normal file
12
src/front/Assets/icons/warning.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_3175_67304)">
|
||||
<path d="M5.74016 1.33203H11.2602L15.1668 5.2387V10.7587L11.2602 14.6654H5.74016L1.8335 10.7587V5.2387L5.74016 1.33203Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8.5 10.668H8.50667" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8.5 5.33203V7.9987" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_3175_67304">
|
||||
<rect width="16" height="16" fill="white" transform="translate(0.5)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 702 B |
@ -98,4 +98,15 @@
|
||||
&[touppercase="false"] {
|
||||
text-transform: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
&[variant="line"] {
|
||||
color: $pink-flash;
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
padding: 0;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
line-height: 22px;
|
||||
text-decoration-line: underline;
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
}
|
||||
|
||||
input[type="checkbox"]::before {
|
||||
content: url("../../../Assets/icons/check.svg");
|
||||
content: url("../../../Assets/Icons/check.svg");
|
||||
place-content: center;
|
||||
display: grid;
|
||||
width: 16px;
|
||||
|
@ -0,0 +1,25 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
border: 1px solid $grey-medium;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
&.DEPOSITED{
|
||||
border-color: $orange-soft;
|
||||
}
|
||||
&.VALIDATED{
|
||||
border-color: $green-soft;
|
||||
}
|
||||
.valid-radius{
|
||||
background-color: $green-flash;
|
||||
padding: 6px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.trash{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import { Document } from "le-coffre-resources/dist/Customer";
|
||||
import Typography, { ITypo } from "../../Typography";
|
||||
import Image from "next/image";
|
||||
import TrashIcon from "@Assets/Icons/trash.svg";
|
||||
import ValidIcon from "@Assets/Icons/check-valid.svg";
|
||||
import classNames from "classnames";
|
||||
import WarningBadge from "../../WarningBadge";
|
||||
|
||||
type IProps = {
|
||||
document: {
|
||||
uid: Document["uid"];
|
||||
document_type: Document["document_type"];
|
||||
document_status: Document["document_status"];
|
||||
|
||||
}
|
||||
openDeletionModal?: (uid: Document["uid"]) => void;
|
||||
};
|
||||
type IState = {};
|
||||
|
||||
export default class DocumentNotary extends React.Component<IProps, IState> {
|
||||
public constructor(props: IProps) {
|
||||
super(props);
|
||||
this.onOpenDeletionModal = this.onOpenDeletionModal.bind(this);
|
||||
}
|
||||
public override render(): JSX.Element {
|
||||
return <div className={classNames(classes["root"], classes[this.props.document.document_status])}>
|
||||
<div>
|
||||
<Typography typo={ITypo.P_SB_16}>{this.props.document?.document_type?.name}</Typography>
|
||||
<Typography typo={ITypo.CAPTION_14}>Aucun document déposé</Typography>
|
||||
</div>
|
||||
{this.renderIcon()}
|
||||
</div>;
|
||||
}
|
||||
|
||||
private renderIcon(): JSX.Element {
|
||||
switch (this.props.document.document_status) {
|
||||
case "VALIDATED":
|
||||
return <div className={classes["valid-radius"]}>
|
||||
<Image src={ValidIcon} alt="valid icon" />
|
||||
</div>
|
||||
case "PENDING":
|
||||
return <WarningBadge />
|
||||
default:
|
||||
return <Image src={TrashIcon} alt="trash icon" className={classes["trash"]} onClick={this.onOpenDeletionModal}/>;
|
||||
}
|
||||
}
|
||||
|
||||
private onOpenDeletionModal(): void {
|
||||
if(!this.props.openDeletionModal) return;
|
||||
this.props.openDeletionModal(this.props.document.uid);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
display: inline-flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 24px;
|
||||
border: 1px solid $grey-medium;
|
||||
|
||||
.left-side {
|
||||
display: inline-flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.warning-circle {
|
||||
margin-left: 32px;
|
||||
padding: 6px;
|
||||
border-radius: 100px;
|
||||
background-color: $orange-flash;
|
||||
}
|
||||
}
|
||||
}
|
33
src/front/Components/DesignSystem/FolderContainer/index.tsx
Normal file
33
src/front/Components/DesignSystem/FolderContainer/index.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import Typography, { ITypo } from "../Typography";
|
||||
import Image from "next/image";
|
||||
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||
import { OfficeFolder } from "le-coffre-resources/dist/Notary";
|
||||
import WarningBadge from "../WarningBadge";
|
||||
|
||||
type IProps = {
|
||||
folder: {
|
||||
folder_number: OfficeFolder["folder_number"];
|
||||
documents?: OfficeFolder["documents"];
|
||||
};
|
||||
}
|
||||
type IState = {};
|
||||
|
||||
export default class FolderContainer extends React.Component<IProps, IState> {
|
||||
public override render(): JSX.Element {
|
||||
return <div className={classes["root"]}>
|
||||
<div className={classes["left-side"]}>
|
||||
<Typography typo={ITypo.P_16}>{"Dossier ".concat(this.props.folder.folder_number)}</Typography>
|
||||
{this.countPendingDocuments() > 0 && <WarningBadge />}
|
||||
|
||||
</div>
|
||||
<Image alt="chevron" src={ChevronIcon} />
|
||||
</div>;
|
||||
}
|
||||
|
||||
private countPendingDocuments(): number {
|
||||
if(!this.props.folder.documents) return 0;
|
||||
return this.props.folder.documents?.filter((document) => document.document_status === "PENDING").length ?? 0;
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import Image from "next/image";
|
||||
import BurgerIcon from "@Assets/icons/burger.svg";
|
||||
import CrossIcon from "@Assets/icons/cross.svg";
|
||||
import BurgerIcon from "@Assets/Icons/burger.svg";
|
||||
import CrossIcon from "@Assets/Icons/cross.svg";
|
||||
import BurgerModal from "./BurgerModal";
|
||||
|
||||
type IProps = {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||
import CloseIcon from "@Assets/icons/cross.svg";
|
||||
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";
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import Image from "next/image";
|
||||
import NotificationIcon from "@Assets/icons/notification.svg";
|
||||
import NotificationIcon from "@Assets/Icons/notification.svg";
|
||||
import Toasts, { IToast } from "@Front/Stores/Toasts";
|
||||
import NotificationModal from "./NotificationModal";
|
||||
import InfoIcon from "@Assets/icons/info.svg";
|
||||
import InfoIcon from "@Assets/Icons/info.svg";
|
||||
|
||||
type IProps = {
|
||||
isModalOpen: boolean;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import Image from "next/image";
|
||||
import ProfileIcon from "@Assets/icons/user.svg";
|
||||
import ProfileIcon from "@Assets/Icons/user.svg";
|
||||
import ProfileModal from "./ProfileModal";
|
||||
|
||||
type IProps = {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import LoaderIcon from "assets/images/icons/loader.svg";
|
||||
import LoaderIcon from "assets/images/Icons/loader.svg";
|
||||
import classes from "./classes.module.scss";
|
||||
import Image from "next/image";
|
||||
|
||||
interface IProps {
|
||||
className?: string;
|
||||
@ -8,7 +9,7 @@ interface IProps {
|
||||
|
||||
export default class Loader extends React.Component<IProps> {
|
||||
public override render(): JSX.Element {
|
||||
return <img src={LoaderIcon} className={[classes["loader"], this.props.className].filter(Boolean).join(" ")} />;
|
||||
return <Image src={LoaderIcon} className={[classes["loader"], this.props.className].filter(Boolean).join(" ")} alt={"Loader"} />;
|
||||
// <LoaderIcon className={[classes["loader"], this.props.className].filter(Boolean).join(" ")} />;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import DisconnectIcon from "@Assets/icons/disconnect.svg";
|
||||
import DisconnectIcon from "@Assets/Icons/disconnect.svg";
|
||||
import classes from "./classes.module.scss";
|
||||
import Typography, { ITypo } from "../Typography";
|
||||
|
||||
|
@ -0,0 +1,49 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
.label-container {
|
||||
cursor: pointer;
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
border: 1px solid $grey-medium;
|
||||
background-color: transparent;
|
||||
|
||||
&.active{
|
||||
padding: 16px 24px;
|
||||
|
||||
}
|
||||
.label {
|
||||
font-family: var(--font-primary);
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
text-transform: uppercase;
|
||||
color: var(--color-primary-8);
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: flex;
|
||||
outline: none;
|
||||
gap: 16px;
|
||||
border: none;
|
||||
width: 100%;
|
||||
|
||||
>div {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.is-active-placeholder {
|
||||
position: absolute;
|
||||
top: -11px;
|
||||
left: 8px;
|
||||
background-color: #ffffff;
|
||||
z-index: 1;
|
||||
padding: 0 16px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
import React from "react";
|
||||
import ReactSelect, { ActionMeta, MultiValue, Options, PropsValue } from "react-select";
|
||||
|
||||
import { styles } from "./styles";
|
||||
import classes from "./classes.module.scss";
|
||||
import { IOption } from "../../Select";
|
||||
import Typography, { ITypo } from "../../Typography";
|
||||
import classNames from "classnames";
|
||||
|
||||
|
||||
type IProps = {
|
||||
options: IOption[];
|
||||
label?: string | JSX.Element;
|
||||
placeholder?: string;
|
||||
onChange?: (newValue: MultiValue<IOption>, actionMeta: ActionMeta<IOption>) => void;
|
||||
defaultValue?: PropsValue<IOption>;
|
||||
value?: PropsValue<IOption>;
|
||||
isMulti?: boolean;
|
||||
shouldCloseMenuOnSelect?: boolean;
|
||||
isOptionDisabled?: (option: IOption, selectValue: Options<IOption>) => boolean;
|
||||
};
|
||||
type IState = {
|
||||
isSelectedOption: boolean;
|
||||
};
|
||||
|
||||
export default class MultiSelect extends React.Component<IProps, IState> {
|
||||
public static defaultProps: Partial<IProps> = {
|
||||
placeholder: "Sélectionner une option...",
|
||||
}
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isSelectedOption: this.props.defaultValue ? true : false
|
||||
}
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.onEmptyResearch = this.onEmptyResearch.bind(this);
|
||||
}
|
||||
public override render(): JSX.Element {
|
||||
return (
|
||||
<div className={classes["root"]}>
|
||||
<div className={classNames(classes["label-container"], this.state.isSelectedOption && classes["active"])}>
|
||||
{this.props.label && <div className={classes["label"]}>{this.props.label}</div>}
|
||||
{this.state.isSelectedOption &&
|
||||
<>
|
||||
< Typography typo={ITypo.NAV_INPUT_16}>
|
||||
<div className={classes["is-active-placeholder"]}>{this.props.placeholder}</div>
|
||||
</Typography>
|
||||
</>
|
||||
}
|
||||
<div className={classes["input-container"]}>
|
||||
<ReactSelect
|
||||
placeholder={this.props.placeholder}
|
||||
options={this.props.options}
|
||||
styles={styles}
|
||||
onChange={this.onChange}
|
||||
value={this.props.value}
|
||||
defaultValue={this.props.defaultValue}
|
||||
closeMenuOnSelect={this.props.shouldCloseMenuOnSelect}
|
||||
isMulti
|
||||
isOptionDisabled={this.props.isOptionDisabled}
|
||||
noOptionsMessage={this.onEmptyResearch}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
|
||||
private onChange(newValue: MultiValue<IOption>, actionMeta: ActionMeta<IOption>) {
|
||||
this.props.onChange && this.props.onChange(newValue, actionMeta);
|
||||
this.setState({ isSelectedOption: newValue.length > 0 });
|
||||
|
||||
}
|
||||
|
||||
private onEmptyResearch(){
|
||||
return "Aucune option correspondante"
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
export const styles = {
|
||||
option: (provided: any, props: { isSelected: boolean; isFocused: boolean }) => ({
|
||||
...provided,
|
||||
cursor: "pointer",
|
||||
padding: "8px 24px",
|
||||
fontFamily: "var(--font-primary)",
|
||||
fontStyle: "normal",
|
||||
fontWeight: "400",
|
||||
fontSize: "18px",
|
||||
lineHeight: "21.78px",
|
||||
color: "#939393",
|
||||
backgroundColor: props.isSelected ? "var(--color-primary-3)" : props.isFocused ? "var(--color-primary-3)" : undefined,
|
||||
|
||||
":active": {
|
||||
...provided[":active"],
|
||||
backgroundColor: props.isSelected ? "var(--color-primary-3)" : undefined,
|
||||
},
|
||||
}),
|
||||
control: () => ({
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
background: "transparent",
|
||||
}),
|
||||
valueContainer: (provided: any) => ({
|
||||
...provided,
|
||||
padding: 0,
|
||||
minWidth: "100px",
|
||||
fontFamily: "var(--font-primary)",
|
||||
fontStyle: "normal",
|
||||
fontWeight: "600",
|
||||
fontSize: "16px",
|
||||
lineHeight: "22px",
|
||||
color: "#939393",
|
||||
letter: "0.5 px"
|
||||
}),
|
||||
multiValue: (provided: any) => ({
|
||||
...provided,
|
||||
margin: "4px",
|
||||
padding: "8px 16px",
|
||||
fontStyle: "normal",
|
||||
fontWeight: "400",
|
||||
fontSize: "16px",
|
||||
lineHeight: "22px",
|
||||
background: "transparent",
|
||||
border: "1px solid black",
|
||||
borderRadius: "100px",
|
||||
}),
|
||||
MultiValueGeneric: (provided: any) => ({
|
||||
...provided,
|
||||
color: "red",
|
||||
}),
|
||||
input: (provided: any) => ({
|
||||
...provided,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
}),
|
||||
placeholder: (provided: any) => ({
|
||||
...provided,
|
||||
fontSize: "16px",
|
||||
lineHeight: "22px",
|
||||
fontWeight: "400",
|
||||
color: "#939393",
|
||||
}),
|
||||
indicatorSeparator: () => ({
|
||||
display: "none",
|
||||
|
||||
}),
|
||||
menu: (provided: any) => ({
|
||||
...provided,
|
||||
position: "static",
|
||||
border: "0",
|
||||
boxShadow: "none"
|
||||
}),
|
||||
menuList: (provided: any) => ({
|
||||
...provided,
|
||||
}),
|
||||
multiValueRemove: (provided: any) => ({
|
||||
...provided,
|
||||
backgroundColor: "transparent",
|
||||
color: "black",
|
||||
"&:hover": {
|
||||
color: "grey",
|
||||
backgroundColor: "transparent",
|
||||
}
|
||||
}),
|
||||
indicatorsContainer: (provided: any) => ({
|
||||
...provided,
|
||||
display: "none",
|
||||
}),
|
||||
listBox: (provided: any) => ({
|
||||
...provided,
|
||||
color: "red",
|
||||
fontSize: "16px",
|
||||
}),
|
||||
};
|
||||
|
@ -21,7 +21,6 @@
|
||||
}
|
||||
|
||||
.root {
|
||||
--animation-delay: 1ms;
|
||||
position: fixed;
|
||||
z-index: 6;
|
||||
top: 0;
|
||||
@ -31,6 +30,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
--animation-delay: 1ms;
|
||||
animation: smooth-appear var(--animation-delay) $custom-easing;
|
||||
|
||||
&[data-will-close="true"] {
|
||||
@ -48,7 +48,7 @@
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
width: 594px;
|
||||
width: 610px;
|
||||
max-height: 90%;
|
||||
background: $white;
|
||||
box-shadow: 0px 6px 12px rgba(255, 255, 255, 0.11);
|
||||
|
@ -5,7 +5,7 @@ import Header from "./Elements/Header";
|
||||
|
||||
import Loader from "./Elements/Loader";
|
||||
import Typography, { ITypo } from "../Typography";
|
||||
import CrossIcon from "@Assets/icons/cross.svg";
|
||||
import CrossIcon from "@Assets/Icons/cross.svg";
|
||||
import Image from "next/image";
|
||||
|
||||
export type IProps = {
|
||||
|
@ -0,0 +1,26 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
position: relative;
|
||||
background-color: $grey-medium;
|
||||
box-shadow: inset 0px 4px 8px rgba(0, 0, 0, 0.08);
|
||||
height: 12px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.progress {
|
||||
position: relative;
|
||||
border-radius: 5px;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
transition: width 300ms;
|
||||
background-color: $turquoise-flash;
|
||||
.percentage{
|
||||
width: 37px;
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 50%;
|
||||
transform: translate(-50%);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import Typography, { ITypo } from "../../Typography";
|
||||
|
||||
type IProps = {
|
||||
percentage: number;
|
||||
};
|
||||
export default class ProgressBar extends React.Component<IProps> {
|
||||
|
||||
public override render(): JSX.Element {
|
||||
const quantity = (this.props.percentage.toFixed(2)).toString().concat("%")
|
||||
return (
|
||||
<div className={classes["root"]}>
|
||||
<div className={classes["progress"]} style={{ width: quantity }} >
|
||||
<Typography typo={ITypo.P_16}>
|
||||
<div className={classes["percentage"]}>{quantity}</div>
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
font-feature-settings: "salt" on;
|
||||
height: 70px;
|
||||
|
||||
.title {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import React from "react";
|
||||
import ProgressBar from "./ProgressBar";
|
||||
import classes from "./classes.module.scss";
|
||||
import Typography, { ITypo } from "../Typography";
|
||||
|
||||
type IProps = {
|
||||
currentNumber: number;
|
||||
total: number;
|
||||
title: string;
|
||||
};
|
||||
export default class QuantityProgressBar extends React.Component<IProps> {
|
||||
public override render(): JSX.Element {
|
||||
let numerator: number = this.props.currentNumber;
|
||||
if (this.props.currentNumber > this.props.total) { numerator = this.props.total }
|
||||
|
||||
const percentage = (numerator / this.props.total) * 100;
|
||||
return (
|
||||
<div className={classes["root"]}>
|
||||
<div className={classes["title"]}>
|
||||
<Typography typo={ITypo.P_16}>{this.props.title}</Typography>
|
||||
</div>
|
||||
<ProgressBar percentage={percentage} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
131
src/front/Components/DesignSystem/Select/classes.module.scss
Normal file
131
src/front/Components/DesignSystem/Select/classes.module.scss
Normal file
@ -0,0 +1,131 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
border: 1px solid $grey-medium;
|
||||
|
||||
.container-label {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
background-color: $white;
|
||||
cursor: pointer;
|
||||
padding: 24px;
|
||||
z-index: 2;
|
||||
|
||||
&[data-border-right-collapsed="true"] {
|
||||
border-radius: 8px 0 0 8px;
|
||||
}
|
||||
|
||||
.container-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
|
||||
.icon {
|
||||
display: flex;
|
||||
margin-right: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
position: absolute;
|
||||
top: 24px;
|
||||
left: 8px;
|
||||
background-color: $white;
|
||||
padding: 0 16px;
|
||||
|
||||
&[data-open="true"] {
|
||||
transform: translateY(-36px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chevron-icon {
|
||||
height: 24px;
|
||||
|
||||
fill: $grey;
|
||||
transition: all 350ms $custom-easing;
|
||||
|
||||
&[data-open="true"] {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container-ul {
|
||||
padding-left: 24px;
|
||||
z-index: 3;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
transition: height 350ms $custom-easing, opacity 350ms $custom-easing;
|
||||
opacity: 1;
|
||||
overflow: hidden;
|
||||
top: 50px;
|
||||
background-color: $white;
|
||||
|
||||
&[data-open="false"] {
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.container-li {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding-bottom: 24px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
background: var(--color-neutral-50);
|
||||
|
||||
&:hover {
|
||||
background: var(--color-neutral-100);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--color-neutral-200);
|
||||
}
|
||||
|
||||
span {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.token-icon {
|
||||
max-width: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 11px;
|
||||
|
||||
>svg {
|
||||
height: 20px;
|
||||
margin-right: 11px;
|
||||
}
|
||||
|
||||
>img {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.backdrop {
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
inset: 0;
|
||||
}
|
||||
}
|
144
src/front/Components/DesignSystem/Select/index.tsx
Normal file
144
src/front/Components/DesignSystem/Select/index.tsx
Normal file
@ -0,0 +1,144 @@
|
||||
import classNames from "classnames";
|
||||
import React, { FormEvent, ReactNode } from "react";
|
||||
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||
|
||||
import Typography, { ITypo } from "../Typography";
|
||||
import classes from "./classes.module.scss";
|
||||
import WindowStore from "@Front/Stores/Window";
|
||||
import Image from "next/image";
|
||||
|
||||
type IProps = {
|
||||
selectedOption?: IOption;
|
||||
onChange: (selectedOption: IOption) => void;
|
||||
options: IOption[];
|
||||
hasBorderRightCollapsed?: boolean;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export type IOption = {
|
||||
value: unknown;
|
||||
label: string;
|
||||
icon?: ReactNode;
|
||||
};
|
||||
|
||||
type IState = {
|
||||
isOpen: boolean;
|
||||
listWidth: number;
|
||||
listHeight: number;
|
||||
};
|
||||
|
||||
export default class Select extends React.Component<IProps, IState> {
|
||||
private contentRef = React.createRef<HTMLUListElement>();
|
||||
private rootRef = React.createRef<HTMLDivElement>();
|
||||
private removeOnresize = () => { };
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isOpen: false,
|
||||
listHeight: 0,
|
||||
listWidth: 0,
|
||||
};
|
||||
this.toggle = this.toggle.bind(this);
|
||||
this.onSelect = this.onSelect.bind(this);
|
||||
}
|
||||
|
||||
public override render(): JSX.Element {
|
||||
const selectedOption = this.props.selectedOption;
|
||||
return (
|
||||
<div className={classNames(classes["root"], this.props.className)} ref={this.rootRef}>
|
||||
<label
|
||||
className={classNames(classes["container-label"])}
|
||||
data-open={this.state.isOpen}
|
||||
onClick={this.toggle}
|
||||
data-border-right-collapsed={this.props.hasBorderRightCollapsed}>
|
||||
<div className={classNames(classes["container-input"])}>
|
||||
<>
|
||||
{selectedOption?.icon && (
|
||||
<span className={classNames(classes["icon"], classes["token-icon"])}>{selectedOption?.icon}</span>
|
||||
)}
|
||||
<Typography typo={ITypo.P_18}>
|
||||
<span className={classes["text"]}>{selectedOption?.label}</span>
|
||||
</Typography>
|
||||
<div className={classes["placeholder"]} data-open={selectedOption && true}>
|
||||
<Typography typo={ITypo.NAV_INPUT_16}>
|
||||
<span className={classes["text"]}>{this.props.placeholder ?? ""}</span>
|
||||
</Typography>
|
||||
</div>
|
||||
</>
|
||||
|
||||
</div>
|
||||
<Image className={classes["chevron-icon"]} data-open={this.state.isOpen} src={ChevronIcon} alt="chevron icon" />
|
||||
</label>
|
||||
|
||||
<ul
|
||||
className={classes["container-ul"]}
|
||||
data-open={this.state.isOpen}
|
||||
ref={this.contentRef}
|
||||
style={{
|
||||
height: this.state.listHeight + "px",
|
||||
}}>
|
||||
{this.props.options.map((option, index) => (
|
||||
<li key={`${index}-${option.value}`} className={classes["container-li"]} onClick={(e) => this.onSelect(option, e)}>
|
||||
<div className={classes["token-icon"]}>{option.icon}</div>
|
||||
<Typography typo={ITypo.P_18}>
|
||||
{option.label}
|
||||
</Typography>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
|
||||
{this.state.isOpen && <div className={classes["backdrop"]} onClick={this.toggle} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props: IProps, state: IState) {
|
||||
if (props.selectedOption?.value) {
|
||||
return {
|
||||
value: props.selectedOption?.value,
|
||||
};
|
||||
}
|
||||
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;
|
||||
listWidth = this.rootRef.current?.scrollWidth ?? 0;
|
||||
if (this.state.listHeight) {
|
||||
listHeight = this.contentRef.current?.scrollHeight ?? 0;
|
||||
}
|
||||
this.setState({ listHeight, listWidth });
|
||||
}
|
||||
|
||||
private toggle(e: FormEvent) {
|
||||
e.preventDefault();
|
||||
let listHeight = 0;
|
||||
let listWidth = this.rootRef.current?.scrollWidth ?? 0;
|
||||
|
||||
if (!this.state.listHeight) {
|
||||
listHeight = this.contentRef.current?.scrollHeight ?? 0;
|
||||
}
|
||||
|
||||
this.setState((state) => {
|
||||
return { isOpen: !state.isOpen, listHeight, listWidth };
|
||||
});
|
||||
}
|
||||
|
||||
private onSelect(option: IOption, e: React.MouseEvent<HTMLLIElement, MouseEvent>) {
|
||||
this.props.onChange && this.props.onChange(option);
|
||||
this.toggle(e);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import ToolTipIcon from "@Assets/icons/tool-tip.svg";
|
||||
import ToolTipIcon from "@Assets/Icons/tool-tip.svg";
|
||||
import TooltipMUI, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip";
|
||||
import styled from "@emotion/styled";
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
width: 100%;
|
||||
.title{
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.content{
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
margin-top: 32px;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import { Document } from "le-coffre-resources/dist/Customer";
|
||||
import Typography, { ITypo } from "../../Typography";
|
||||
import DocumentNotary from "../../Document/DocumentNotary";
|
||||
|
||||
type IProps = {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
documents: {
|
||||
uid: Document["uid"];
|
||||
document_type: Document["document_type"];
|
||||
document_status: Document["document_status"];
|
||||
|
||||
}[] | null;
|
||||
openDeletionModal: (uid: Document["uid"]) => void;
|
||||
};
|
||||
type IState = {};
|
||||
|
||||
export default class DocumentList extends React.Component<IProps, IState> {
|
||||
public override render(): JSX.Element {
|
||||
return <div className={classes["root"]}>
|
||||
<div className={classes["title"]}>
|
||||
<Typography typo={ITypo.P_SB_18}>{this.props.title}</Typography>
|
||||
</div>
|
||||
<Typography typo={ITypo.P_16}>{this.props.subtitle}</Typography>
|
||||
<div className={classes["content"]}>
|
||||
{this.props.documents && this.props.documents.map((document) => {
|
||||
return <DocumentNotary document={document} key={document.uid} openDeletionModal={this.props.openDeletionModal}/>
|
||||
})}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24px;
|
||||
background-color: $grey-soft;
|
||||
width: 100%;
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
|
||||
@media (max-width: $screen-ls) {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.icons {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 24px;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import { Contact } from "le-coffre-resources/dist/Notary";
|
||||
import Typography, { ITypo } from "../../Typography";
|
||||
import Image from "next/image";
|
||||
import PenIcon from "@Assets/Icons/pen.svg";
|
||||
import WarningBadge from "../../WarningBadge";
|
||||
|
||||
type IProps = {
|
||||
contact: {
|
||||
first_name: Contact["first_name"],
|
||||
last_name: Contact["last_name"],
|
||||
phone_number: Contact["phone_number"],
|
||||
cell_phone_number: Contact["cell_phone_number"],
|
||||
email: Contact["email"],
|
||||
}
|
||||
};
|
||||
type IState = {};
|
||||
|
||||
export default class UserFolderHeader extends React.Component<IProps, IState> {
|
||||
public override render(): JSX.Element {
|
||||
return <div className={classes["root"]}>
|
||||
<div className={classes["content"]}>
|
||||
<div className={classes["container"]}>
|
||||
<Typography typo={ITypo.NAV_INPUT_16}>Nom</Typography>
|
||||
<Typography typo={ITypo.P_18}>{this.props.contact.last_name}</Typography>
|
||||
</div>
|
||||
|
||||
<div className={classes["container"]}>
|
||||
<Typography typo={ITypo.NAV_INPUT_16}>Prénom</Typography>
|
||||
<Typography typo={ITypo.P_18}>{this.props.contact.first_name}</Typography>
|
||||
</div>
|
||||
|
||||
<div className={classes["container"]}>
|
||||
<Typography typo={ITypo.NAV_INPUT_16}>Numéro de téléphone</Typography>
|
||||
<Typography typo={ITypo.P_18}>{this.formatPhoneNumber(this.props.contact.phone_number) ?? this.formatPhoneNumber(this.props.contact.cell_phone_number)}</Typography>
|
||||
</div>
|
||||
|
||||
<div className={classes["container"]}>
|
||||
<Typography typo={ITypo.NAV_INPUT_16}>E-mail</Typography>
|
||||
<Typography typo={ITypo.P_18}>{this.props.contact.email}</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes["icons"]}>
|
||||
<WarningBadge />
|
||||
<Image src={PenIcon} alt="edit" className={classes["edit-icon"]} />
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
private formatPhoneNumber(phoneNumber: string): string {
|
||||
if (!phoneNumber) return "";
|
||||
const output = phoneNumber.split('').map((char, index) => {
|
||||
if(index%2) return char + " ";
|
||||
return char;
|
||||
});
|
||||
return output.join("");
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
@keyframes smooth-appear {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes smooth-disappear {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.root {
|
||||
border: 1px solid $grey;
|
||||
padding: 16px;
|
||||
transition: all 350ms $custom-easing;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.chevron-icon {
|
||||
margin-left: 16px;
|
||||
transform: rotate(90deg);
|
||||
transition: all 350ms $custom-easing;
|
||||
cursor: pointer;
|
||||
&.open {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-top: 32px;
|
||||
--animation-delay: 1ms;
|
||||
animation: smooth-appear var(--animation-delay) $custom-easing;
|
||||
|
||||
&[data-will-close="true"] {
|
||||
animation: smooth-disappear var(--animation-delay) $custom-easing;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 64px;
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
display: inline-grid;
|
||||
justify-items: start;
|
||||
gap: 32px;
|
||||
}
|
||||
}
|
||||
}
|
146
src/front/Components/DesignSystem/UserFolder/index.tsx
Normal file
146
src/front/Components/DesignSystem/UserFolder/index.tsx
Normal file
@ -0,0 +1,146 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import UserFolderHeader from "./UserFolderHeader";
|
||||
import Customer, { Document } from "le-coffre-resources/dist/Customer";
|
||||
import Image from "next/image";
|
||||
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||
import QuantityProgressBar from "../QuantityProgressBar";
|
||||
import classNames from "classnames";
|
||||
import DocumentList from "./DocumentList";
|
||||
import Button, { EButtonVariant } from "../Button";
|
||||
import PlusIcon from "@Assets/Icons/plus.svg"
|
||||
import Confirm from "../Modal/Confirm";
|
||||
|
||||
type IProps = {
|
||||
customer: Customer
|
||||
animationDelay?: number;
|
||||
};
|
||||
type IState = {
|
||||
isOpen: boolean;
|
||||
isOpenDeletionModal: boolean;
|
||||
willClose: boolean;
|
||||
};
|
||||
|
||||
export default class UserFolder extends React.Component<IProps, IState> {
|
||||
static defaultProps = {
|
||||
animationDelay: 300
|
||||
};
|
||||
public rootRefElement = React.createRef<HTMLDivElement>();
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isOpen: false,
|
||||
isOpenDeletionModal: false,
|
||||
willClose: false
|
||||
};
|
||||
this.toggleOpen = this.toggleOpen.bind(this);
|
||||
this.closeDeletionModal = this.closeDeletionModal.bind(this);
|
||||
this.openDeletionModal = this.openDeletionModal.bind(this);
|
||||
this.openComponent = this.openComponent.bind(this);
|
||||
this.closeComponent = this.closeComponent.bind(this);
|
||||
|
||||
}
|
||||
public override render(): JSX.Element {
|
||||
|
||||
const documentsAsked: Document[] | null = this.getDocumentsByStatus("ASKED");
|
||||
const otherDocuments: Document[] | null = this.getOtherDocuments(documentsAsked);
|
||||
|
||||
return <div className={classes["root"]}>
|
||||
<Confirm
|
||||
isOpen={this.state.isOpenDeletionModal}
|
||||
onClose={this.closeDeletionModal}
|
||||
closeBtn
|
||||
header={"Supprimer la demande de document ?"}
|
||||
cancelText={"Cancel"}
|
||||
confirmText={"Confirmer"}>
|
||||
Êtes-vous vous de vouloir supprimer la demande de document ?
|
||||
</Confirm>
|
||||
|
||||
<div className={classes["header"]}>
|
||||
<UserFolderHeader contact={this.props.
|
||||
customer.contact} />
|
||||
<Image src={ChevronIcon} alt="chevron open close" className={classNames(classes["chevron-icon"], this.state.isOpen && classes["open"])} onClick={this.toggleOpen} />
|
||||
</div>
|
||||
|
||||
{this.state.isOpen &&
|
||||
<div className={classes["container"]} data-will-close={this.state.willClose.toString()} ref={this.rootRefElement}>
|
||||
<QuantityProgressBar title="Complétion du dossier" total={100} currentNumber={this.calculateDocumentsPercentageProgress()} />
|
||||
<div className={classes["content"]}>
|
||||
<DocumentList documents={documentsAsked} title="Documents demandés" openDeletionModal={this.openDeletionModal} />
|
||||
<DocumentList documents={otherDocuments} title="Documents à valider / validés" subtitle="Vous avez des documents à valider." openDeletionModal={this.openDeletionModal} />
|
||||
</div>
|
||||
<div className={classes["button-container"]}>
|
||||
<Button variant={EButtonVariant.LINE} icon={<Image src={PlusIcon} alt="plus icon" />}>Demander un autre document </Button>
|
||||
<Button>Envoyer un mail de demande de documents</Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>;
|
||||
}
|
||||
|
||||
public override componentDidUpdate(): void {
|
||||
this.rootRefElement.current?.style.setProperty("--animation-delay", this.props.animationDelay!.toString().concat("ms"));
|
||||
}
|
||||
|
||||
private calculateDocumentsPercentageProgress(): number {
|
||||
if (!this.props.customer.documents) return 0;
|
||||
const totalDocuments: number = this.props.customer.documents.length;
|
||||
const numberDocumentsAsked: number = this.getDocumentsByStatus("ASKED")?.length || 0;
|
||||
return Math.round((numberDocumentsAsked / totalDocuments) * 100);
|
||||
}
|
||||
|
||||
private getDocumentsByStatus(status: string): Document[] | null {
|
||||
if (!this.props.customer.documents) return null;
|
||||
return this.props.customer.documents.filter((document) => document.document_status === status);
|
||||
}
|
||||
|
||||
private getOtherDocuments(documentToExclude: Document[] | null): Document[] | null {
|
||||
if (!this.props.customer.documents) return null;
|
||||
if (!documentToExclude) return this.props.customer.documents;
|
||||
return this.props.customer.documents.filter((document) => !documentToExclude.includes(document));
|
||||
}
|
||||
|
||||
private toggleOpen(): void {
|
||||
|
||||
|
||||
if (this.state.isOpen) {
|
||||
this.closeComponent();
|
||||
}
|
||||
else {
|
||||
this.openComponent();
|
||||
}
|
||||
}
|
||||
|
||||
private openComponent(): void {
|
||||
this.setState({
|
||||
isOpen: true
|
||||
});
|
||||
}
|
||||
|
||||
private closeComponent(): void {
|
||||
if (this.state.willClose) return;
|
||||
this.setState({ willClose: true })
|
||||
window.setTimeout(() => {
|
||||
this.setState({
|
||||
isOpen: false,
|
||||
willClose: false
|
||||
});
|
||||
}, this.props.animationDelay)
|
||||
}
|
||||
|
||||
private openDeletionModal(uid: string): void {
|
||||
console.log("Delete item > ", uid);
|
||||
// TODO: call API to delete document
|
||||
this.setState({
|
||||
isOpenDeletionModal: true
|
||||
});
|
||||
}
|
||||
private closeDeletionModal(): void {
|
||||
this.setState({
|
||||
isOpenDeletionModal: false
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
background-color: $orange-flash;
|
||||
padding: 6px;
|
||||
border-radius: 20px;
|
||||
}
|
15
src/front/Components/DesignSystem/WarningBadge/index.tsx
Normal file
15
src/front/Components/DesignSystem/WarningBadge/index.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import Image from "next/image";
|
||||
import WarningIcon from "@Assets/Icons/warning.svg";
|
||||
|
||||
type IProps = {};
|
||||
type IState = {};
|
||||
|
||||
export default class WarningBadge extends React.Component<IProps, IState> {
|
||||
public override render(): JSX.Element {
|
||||
return <div className={classes["root"]}>
|
||||
<Image src={WarningIcon} alt="warning icon" />
|
||||
</div>;
|
||||
}
|
||||
}
|
@ -2,8 +2,8 @@ import React, { RefObject } from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import classNames from "classnames";
|
||||
import Image from "next/image";
|
||||
import ErrorIcon from "@Assets/icons/input-error.svg";
|
||||
import SuccessIcon from "@Assets/icons/input-success.svg";
|
||||
import ErrorIcon from "@Assets/Icons/input-error.svg";
|
||||
import SuccessIcon from "@Assets/Icons/input-success.svg";
|
||||
|
||||
type IProps = {
|
||||
inputRef?: RefObject<HTMLInputElement>;
|
||||
|
@ -11,4 +11,8 @@
|
||||
.inline-flex {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.folder-conatainer{
|
||||
width: 389px ;
|
||||
}
|
||||
}
|
||||
|
155
src/front/Components/Layouts/DesignSystem/dummyData.ts
Normal file
155
src/front/Components/Layouts/DesignSystem/dummyData.ts
Normal file
@ -0,0 +1,155 @@
|
||||
import {
|
||||
Address,
|
||||
Office,
|
||||
DeedType,
|
||||
Deed,
|
||||
OfficeFolder,
|
||||
Contact,
|
||||
Customer,
|
||||
DocumentType,
|
||||
Document,
|
||||
} from "le-coffre-resources/dist/Notary";
|
||||
import { ECustomerStatus } from "le-coffre-resources/dist/Customer/Customer";
|
||||
import { EFolderStatus } from "le-coffre-resources/dist/Customer/OfficeFolder";
|
||||
|
||||
export const address: Address = {
|
||||
uid: "a&23",
|
||||
address: "123",
|
||||
city: "France",
|
||||
zip_code: 78140,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
};
|
||||
|
||||
export const office: Office = {
|
||||
uid: "111213",
|
||||
idNot: "12EE12",
|
||||
name: "Office 1",
|
||||
crpcen: "AZezdz",
|
||||
address: address,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
office_status: "ACTIVATED",
|
||||
};
|
||||
export const deedType: DeedType = {
|
||||
uid: "123312",
|
||||
name: "Acte mariage",
|
||||
description: "dzsdaf",
|
||||
archived_at: new Date(),
|
||||
office: office,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
};
|
||||
|
||||
export const deed: Deed = {
|
||||
uid: "123124",
|
||||
deed_type: deedType,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
};
|
||||
|
||||
export const folder: OfficeFolder = {
|
||||
uid: "11123312",
|
||||
folder_number: "12331",
|
||||
name: "Mon dossier",
|
||||
status: EFolderStatus.ARCHIVED,
|
||||
deed: deed,
|
||||
office: office,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
description: "Description",
|
||||
archived_description: "Archived description",
|
||||
};
|
||||
|
||||
export const contact: Contact = {
|
||||
uid: "123123",
|
||||
first_name: "John",
|
||||
last_name: "Doe",
|
||||
email: "johnDoe@gmail.com",
|
||||
address: address,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
cell_phone_number: "0132249865",
|
||||
phone_number: "0132249865",
|
||||
civility: "MALE",
|
||||
};
|
||||
|
||||
export const docType: DocumentType = {
|
||||
name: "Acte de naissance",
|
||||
uid: "123123",
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
public_description: "Acte de naissance public description",
|
||||
private_description: "Acte de naissance private description",
|
||||
archived_at: new Date(),
|
||||
};
|
||||
export const customer: Customer = {
|
||||
uid: "123123",
|
||||
contact: contact,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
status: ECustomerStatus.VALIDATED,
|
||||
};
|
||||
|
||||
export const document: Document = {
|
||||
uid: "0",
|
||||
depositor: customer,
|
||||
document_status: "ASKED",
|
||||
folder: folder,
|
||||
document_type: docType,
|
||||
updated_at: new Date(),
|
||||
created_at: new Date(),
|
||||
};
|
||||
|
||||
export const document2: Document = {
|
||||
uid: "1",
|
||||
depositor: customer,
|
||||
document_status: "ASKED",
|
||||
folder: folder,
|
||||
document_type: docType,
|
||||
updated_at: new Date(),
|
||||
created_at: new Date(),
|
||||
};
|
||||
|
||||
export const documentPending: Document = {
|
||||
uid: "2",
|
||||
depositor: customer,
|
||||
document_status: "PENDING",
|
||||
folder: folder,
|
||||
document_type: docType,
|
||||
updated_at: new Date(),
|
||||
created_at: new Date(),
|
||||
};
|
||||
|
||||
export const documentDeposited: Document = {
|
||||
uid: "3",
|
||||
depositor: customer,
|
||||
document_status: "VALIDATED",
|
||||
folder: folder,
|
||||
document_type: docType,
|
||||
updated_at: new Date(),
|
||||
created_at: new Date(),
|
||||
};
|
||||
|
||||
export const customer2: Customer = {
|
||||
uid: "123123",
|
||||
contact: contact,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
status: ECustomerStatus.VALIDATED,
|
||||
documents: [document, document2, documentPending, documentDeposited],
|
||||
};
|
||||
|
||||
export const folderWithPendingDocument: OfficeFolder = {
|
||||
uid: "11123312",
|
||||
folder_number: "12332",
|
||||
name: "Mon dossier",
|
||||
status: EFolderStatus.ARCHIVED,
|
||||
deed: deed,
|
||||
office: office,
|
||||
created_at: new Date(),
|
||||
updated_at: new Date(),
|
||||
description: "Description",
|
||||
archived_description: "Archived description",
|
||||
documents: [documentPending],
|
||||
};
|
@ -10,13 +10,23 @@ import CheckBox from "@Front/Components/DesignSystem/CheckBox";
|
||||
import ToolTip from "@Front/Components/DesignSystem/ToolTip";
|
||||
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
|
||||
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
|
||||
import QuantityProgressBar from "@Front/Components/DesignSystem/QuantityProgressBar";
|
||||
import "reflect-metadata";
|
||||
import FolderContainer from "@Front/Components/DesignSystem/FolderContainer";
|
||||
import { customer2, document, documentDeposited, documentPending, folder, folderWithPendingDocument } from "./dummyData"
|
||||
import DocumentNotary from "@Front/Components/DesignSystem/Document/DocumentNotary";
|
||||
import Select, { IOption } from "@Front/Components/DesignSystem/Select";
|
||||
import UserFolder from "@Front/Components/DesignSystem/UserFolder";
|
||||
import MultiSelect from "@Front/Components/DesignSystem/Materials/MultiSelect";
|
||||
|
||||
type IState = {
|
||||
isModalDisplayed: boolean;
|
||||
selectedOption?: IOption;
|
||||
};
|
||||
type IProps = {};
|
||||
|
||||
export default class DesignSystem extends BasePage<IProps, IState> {
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@ -24,12 +34,23 @@ export default class DesignSystem extends BasePage<IProps, IState> {
|
||||
};
|
||||
this.openModal = this.openModal.bind(this);
|
||||
this.closeModal = this.closeModal.bind(this);
|
||||
this.onSelectedOption = this.onSelectedOption.bind(this);
|
||||
}
|
||||
|
||||
|
||||
public override render(): JSX.Element {
|
||||
|
||||
const selectOptions: IOption[] = [
|
||||
{ value: "1", label: "Divorce" },
|
||||
{ value: "2", label: "Succession" },
|
||||
{ value: "3", label: "Vente immobilière" },
|
||||
]
|
||||
|
||||
|
||||
return (
|
||||
<DefaultTemplate title={"HomePage"}>
|
||||
<div className={classes["root"]}>
|
||||
|
||||
<div className={classes["section"]}>
|
||||
<div className={classes["sub-section"]}>
|
||||
<Typography typo={ITypo.H1}>Website design System</Typography>
|
||||
@ -44,6 +65,7 @@ export default class DesignSystem extends BasePage<IProps, IState> {
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<MultiSelect options={selectOptions} placeholder="Numéro CRPCEN"/>
|
||||
|
||||
<div className={classes["section"]}>
|
||||
<div className={classes["sub-section"]}>
|
||||
@ -127,6 +149,86 @@ export default class DesignSystem extends BasePage<IProps, IState> {
|
||||
<InputField name="input field" fakeplaceholder="number place hodler" type="number" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={classes["section"]}>
|
||||
<div className={classes["sub-section"]}>
|
||||
<Typography typo={ITypo.H3}>Progress bar component</Typography>
|
||||
</div>
|
||||
<div className={classes["sub-section"]}>
|
||||
<QuantityProgressBar currentNumber={10} total={100} title={"Complétion du dossier client"} />
|
||||
</div>
|
||||
<div className={classes["sub-section"]}>
|
||||
<QuantityProgressBar currentNumber={30} total={100} title={"Complétion du dossier client"} />
|
||||
</div>
|
||||
<div className={classes["sub-section"]}>
|
||||
<QuantityProgressBar currentNumber={70} total={100} title={"Complétion du dossier client"} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={classes["section"]}>
|
||||
<div className={classes["sub-section"]}>
|
||||
<Typography typo={ITypo.H3}>Folder container component</Typography>
|
||||
</div>
|
||||
<div className={classes["sub-section"]}>
|
||||
<Typography typo={ITypo.P_16}>Folder with no document to validate</Typography>
|
||||
<div className={classes["folder-conatainer"]}>
|
||||
<FolderContainer folder={folder} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes["sub-section"]}>
|
||||
|
||||
<Typography typo={ITypo.P_16}>Folder with document waiting for being validate</Typography>
|
||||
<div className={classes["folder-conatainer"]}>
|
||||
<FolderContainer folder={folderWithPendingDocument} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={classes["section"]}>
|
||||
<div className={classes["sub-section"]}>
|
||||
<Typography typo={ITypo.H3}>Select component</Typography>
|
||||
</div>
|
||||
<div className={classes["sub-section"]}>
|
||||
<div className={classes["folder-conatainer"]}>
|
||||
<Select options={selectOptions} onChange={this.onSelectedOption} placeholder={"Type d’acte"} selectedOption={this.state.selectedOption} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={classes["section"]}>
|
||||
<div className={classes["sub-section"]}>
|
||||
<Typography typo={ITypo.H3}>Notary Documents</Typography>
|
||||
</div>
|
||||
<div className={classes["sub-section"]}>
|
||||
<Typography typo={ITypo.P_16}>Documents ASKED</Typography>
|
||||
<div className={classes["folder-conatainer"]}>
|
||||
<DocumentNotary document={document} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes["sub-section"]}>
|
||||
<Typography typo={ITypo.P_16}>Documents PENDING</Typography>
|
||||
<div className={classes["folder-conatainer"]}>
|
||||
<DocumentNotary document={documentPending} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes["sub-section"]}>
|
||||
<Typography typo={ITypo.P_16}>Documents VALIDATED</Typography>
|
||||
|
||||
<div className={classes["folder-conatainer"]}>
|
||||
<DocumentNotary document={documentDeposited} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={classes["section"]}>
|
||||
<div className={classes["sub-section"]}>
|
||||
<Typography typo={ITypo.H3}>Notary Documents</Typography>
|
||||
</div>
|
||||
<div className={classes["sub-section"]}>
|
||||
<UserFolder customer={customer2} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</DefaultTemplate>
|
||||
);
|
||||
@ -148,4 +250,10 @@ export default class DesignSystem extends BasePage<IProps, IState> {
|
||||
};
|
||||
Toasts.getInstance().open(toast);
|
||||
}
|
||||
|
||||
private onSelectedOption(option: IOption) {
|
||||
this.setState({
|
||||
selectedOption: option,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
67
src/front/Stores/Window.ts
Normal file
67
src/front/Stores/Window.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import EventEmitter from "events";
|
||||
|
||||
export default class WindowStore {
|
||||
private static ctx: WindowStore;
|
||||
private readonly event = new EventEmitter();
|
||||
|
||||
private constructor() {
|
||||
WindowStore.ctx = this;
|
||||
this.iniEvents();
|
||||
}
|
||||
|
||||
public static getInstance() {
|
||||
if (!WindowStore.ctx) return new this();
|
||||
return WindowStore.ctx;
|
||||
}
|
||||
|
||||
public onScrollYDirectionChange(callback: (scrollYDifference: number) => void) {
|
||||
this.event.on("scrollYDirectionChange", callback);
|
||||
return () => {
|
||||
this.event.off("scrollYDirectionChange", callback);
|
||||
};
|
||||
}
|
||||
|
||||
public onResize(callback: (window: Window) => void) {
|
||||
this.event.on("resize", callback);
|
||||
return () => {
|
||||
this.event.off("resize", callback);
|
||||
};
|
||||
}
|
||||
|
||||
public onClick(callback: (e: MouseEvent) => void) {
|
||||
this.event.on("click", callback);
|
||||
return () => {
|
||||
this.event.off("click", callback);
|
||||
};
|
||||
}
|
||||
|
||||
private iniEvents(): void {
|
||||
window.addEventListener("scroll", (e: Event) => this.scrollYHandler());
|
||||
window.addEventListener("resize", (e: Event) => this.resizeHandler());
|
||||
document.addEventListener("click", (e: MouseEvent) => this.clickHandler(e), true);
|
||||
}
|
||||
|
||||
private clickHandler(e: MouseEvent) {
|
||||
this.event.emit("click", e);
|
||||
}
|
||||
|
||||
private scrollYHandler = (() => {
|
||||
let previousY: number = window.scrollY;
|
||||
let snapShotY: number = previousY;
|
||||
let previousYDirection: number = 1;
|
||||
return (): void => {
|
||||
const scrollYDirection = window.scrollY - previousY > 0 ? 1 : -1;
|
||||
if (previousYDirection !== scrollYDirection) {
|
||||
snapShotY = window.scrollY;
|
||||
}
|
||||
|
||||
this.event.emit("scrollYDirectionChange", snapShotY - window.scrollY);
|
||||
previousY = window.scrollY;
|
||||
previousYDirection = scrollYDirection;
|
||||
};
|
||||
})();
|
||||
|
||||
private resizeHandler() {
|
||||
this.event.emit("resize", window);
|
||||
}
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "v0.0.1"
|
||||
"version": "v0.1.0"
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user