Merge branch 'dev' into staging
This commit is contained in:
commit
1990c9d4c6
6
.vscode/custom.code-snippets
vendored
6
.vscode/custom.code-snippets
vendored
@ -6,4 +6,10 @@
|
|||||||
],
|
],
|
||||||
"description": "media queries"
|
"description": "media queries"
|
||||||
},
|
},
|
||||||
|
"Default div": {
|
||||||
|
"prefix": "<div",
|
||||||
|
"body": [
|
||||||
|
"<div className={classes[\"$1\"]}>$2</div>"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
@ -13,16 +13,16 @@ const nextConfig = {
|
|||||||
NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT: process.env.NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT,
|
NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT: process.env.NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT,
|
||||||
NEXT_PUBLIC_IDNOT_CLIENT_ID: process.env.NEXT_PUBLIC_IDNOT_CLIENT_ID,
|
NEXT_PUBLIC_IDNOT_CLIENT_ID: process.env.NEXT_PUBLIC_IDNOT_CLIENT_ID,
|
||||||
},
|
},
|
||||||
webpack: config => {
|
// webpack: config => {
|
||||||
config.node = {
|
// config.node = {
|
||||||
fs: 'empty',
|
// fs: 'empty',
|
||||||
child_process: 'empty',
|
// child_process: 'empty',
|
||||||
net: 'empty',
|
// net: 'empty',
|
||||||
dns: 'empty',
|
// dns: 'empty',
|
||||||
tls: 'empty',
|
// tls: 'empty',
|
||||||
};
|
// };
|
||||||
return config;
|
// return config;
|
||||||
},
|
// },
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = nextConfig;
|
module.exports = nextConfig;
|
||||||
|
1189
package-lock.json
generated
1189
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -23,13 +23,15 @@
|
|||||||
"eslint": "8.36.0",
|
"eslint": "8.36.0",
|
||||||
"eslint-config-next": "13.2.4",
|
"eslint-config-next": "13.2.4",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.52",
|
"jwt-decode": "^3.1.2",
|
||||||
|
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.58",
|
||||||
"next": "13.2.4",
|
"next": "13.2.4",
|
||||||
"prettier": "^2.8.7",
|
"prettier": "^2.8.7",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-select": "^5.7.2",
|
"react-select": "^5.7.2",
|
||||||
"sass": "^1.59.2",
|
"sass": "^1.59.2",
|
||||||
|
"sharp": "^0.32.1",
|
||||||
"typescript": "4.9.5"
|
"typescript": "4.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
src/front/Api/Auth/IdNot/User.ts
Normal file
38
src/front/Api/Auth/IdNot/User.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import BaseApiService from "@Front/Api/BaseApiService";
|
||||||
|
|
||||||
|
export default class User extends BaseApiService {
|
||||||
|
private static instance: User;
|
||||||
|
private readonly baseURl = this.getBaseUrl().concat("/idnot/user");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new User();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async login(uid: string) {
|
||||||
|
const url = new URL(this.baseURl.concat("/login/").concat(uid));
|
||||||
|
try {
|
||||||
|
return await this.postRequest(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async refreshToken(refreshToken: string): Promise<{ accessToken: string }> {
|
||||||
|
const url = new URL(this.baseURl.concat("/refresh-token"));
|
||||||
|
try {
|
||||||
|
return await this.postRequest(url, {}, refreshToken);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import { FrontendVariables } from "@Front/Config/VariablesFront";
|
import { FrontendVariables } from "@Front/Config/VariablesFront";
|
||||||
|
import CookieService from "@Front/Services/CookieService/CookieService";
|
||||||
|
|
||||||
export enum ContentType {
|
export enum ContentType {
|
||||||
JSON = "application/json",
|
JSON = "application/json",
|
||||||
@ -21,11 +22,14 @@ export default abstract class BaseApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected buildHeaders(contentType: ContentType) {
|
protected buildHeaders(contentType: ContentType) {
|
||||||
|
const token = CookieService.getInstance().getCookie("leCoffreAccessToken");
|
||||||
|
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
|
|
||||||
if (contentType === ContentType.JSON) {
|
if (contentType === ContentType.JSON) {
|
||||||
headers.set("Content-Type", contentType);
|
headers.set("Content-Type", contentType);
|
||||||
}
|
}
|
||||||
|
headers.set("Authorization", `Bearer ${token}`);
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +37,7 @@ export default abstract class BaseApiService {
|
|||||||
return JSON.stringify(body);
|
return JSON.stringify(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async getRequest<T>(url: URL) {
|
protected async getRequest<T>(url: URL, token?: string) {
|
||||||
const request = async () =>
|
const request = async () =>
|
||||||
await fetch(url, {
|
await fetch(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
@ -42,7 +46,7 @@ export default abstract class BaseApiService {
|
|||||||
return this.sendRequest<T>(request);
|
return this.sendRequest<T>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async postRequest<T>(url: URL, body: { [key: string]: unknown } = {}) {
|
protected async postRequest<T>(url: URL, body: { [key: string]: unknown } = {}, token?: string) {
|
||||||
return this.sendRequest<T>(
|
return this.sendRequest<T>(
|
||||||
async () =>
|
async () =>
|
||||||
await fetch(url, {
|
await fetch(url, {
|
||||||
@ -64,7 +68,7 @@ export default abstract class BaseApiService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async putRequest<T>(url: URL, body: { [key: string]: unknown } = {}) {
|
protected async putRequest<T>(url: URL, body: { [key: string]: unknown } = {}, token?: string) {
|
||||||
const request = async () =>
|
const request = async () =>
|
||||||
await fetch(url, {
|
await fetch(url, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
@ -86,7 +90,7 @@ export default abstract class BaseApiService {
|
|||||||
return this.sendRequest<T>(request);
|
return this.sendRequest<T>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async deleteRequest<T>(url: URL, body: { [key: string]: unknown } = {}) {
|
protected async deleteRequest<T>(url: URL, body: { [key: string]: unknown } = {}, token?: string) {
|
||||||
const request = async () =>
|
const request = async () =>
|
||||||
await fetch(url, {
|
await fetch(url, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
@ -97,7 +101,7 @@ export default abstract class BaseApiService {
|
|||||||
return this.sendRequest<T>(request);
|
return this.sendRequest<T>(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async putFormDataRequest<T>(url: URL, body: FormData) {
|
protected async putFormDataRequest<T>(url: URL, body: FormData, token?: string) {
|
||||||
const request = async () =>
|
const request = async () =>
|
||||||
await fetch(url, {
|
await fetch(url, {
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
|
5
src/front/Api/LeCoffreApi/Admin/BaseAdmin.ts
Normal file
5
src/front/Api/LeCoffreApi/Admin/BaseAdmin.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import BaseApiService from "@Front/Api/BaseApiService";
|
||||||
|
|
||||||
|
export default abstract class BaseAdmin extends BaseApiService {
|
||||||
|
protected readonly namespaceUrl = this.getBaseUrl().concat("/admin");
|
||||||
|
}
|
49
src/front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes.ts
Normal file
49
src/front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { DeedType } from "le-coffre-resources/dist/Admin";
|
||||||
|
|
||||||
|
import BaseAdmin from "../BaseAdmin";
|
||||||
|
|
||||||
|
export type IGetDeedTypesParams = {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
select?: {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DeedTypes extends BaseAdmin {
|
||||||
|
private static instance: DeedTypes;
|
||||||
|
private readonly baseURl = this.namespaceUrl.concat("/deed-types");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new DeedTypes();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get(q: IGetDeedTypesParams): Promise<DeedType[]> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
const query = { q };
|
||||||
|
Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<DeedType[]>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getByUid(uid: string, q?: any): Promise<DeedType> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
if (q) Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<DeedType>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
src/front/Api/LeCoffreApi/Admin/Deeds/Deeds.ts
Normal file
49
src/front/Api/LeCoffreApi/Admin/Deeds/Deeds.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Deed } from "le-coffre-resources/dist/Admin";
|
||||||
|
|
||||||
|
import BaseAdmin from "../BaseAdmin";
|
||||||
|
|
||||||
|
export type IGetDeedsParams = {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
select?: {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Deeds extends BaseAdmin {
|
||||||
|
private static instance: Deeds;
|
||||||
|
private readonly baseURl = this.namespaceUrl.concat("/deeds");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new Deeds();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get(q: IGetDeedsParams): Promise<Deed[]> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
const query = { q };
|
||||||
|
Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<Deed[]>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getByUid(uid: string, q?: any): Promise<Deed> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
if (q) Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<Deed>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
import { DocumentType } from "le-coffre-resources/dist/SuperAdmin";
|
||||||
|
|
||||||
|
import BaseAdmin from "../BaseAdmin";
|
||||||
|
|
||||||
|
// TODO Type get query params -> Where + inclue + orderby
|
||||||
|
export interface IGetDocumentTypesparams {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Type getbyuid query params
|
||||||
|
|
||||||
|
export type IPutDocumentTypesParams = {};
|
||||||
|
|
||||||
|
export interface IPostDocumentTypesParams {
|
||||||
|
name: string;
|
||||||
|
public_description: string;
|
||||||
|
private_description: string;
|
||||||
|
office: {
|
||||||
|
uid: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DocumentTypes extends BaseAdmin {
|
||||||
|
private static instance: DocumentTypes;
|
||||||
|
private readonly baseURl = this.namespaceUrl.concat("/document-types");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new this();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get(q: IGetDocumentTypesparams): Promise<DocumentType[]> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
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) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Create a Document
|
||||||
|
*/
|
||||||
|
public async post(body: DocumentType): Promise<DocumentType> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
try {
|
||||||
|
return await this.postRequest<DocumentType>(url, body as any);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getByUid(uid: string, q?: any): Promise<DocumentType> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
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) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async put(uid: string, body: IPutDocumentTypesParams): Promise<DocumentType> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
try {
|
||||||
|
return await this.putRequest<DocumentType>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
93
src/front/Api/LeCoffreApi/Admin/Documents/Documents.ts
Normal file
93
src/front/Api/LeCoffreApi/Admin/Documents/Documents.ts
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
|
||||||
|
import { Document } from "le-coffre-resources/dist/SuperAdmin";
|
||||||
|
|
||||||
|
import BaseAdmin from "../BaseAdmin";
|
||||||
|
|
||||||
|
// TODO Type get query params -> Where + inclue + orderby
|
||||||
|
export interface IGetDocumentsparams {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Type getbyuid query params
|
||||||
|
|
||||||
|
export type IPutDocumentsParams = {
|
||||||
|
document_status?: EDocumentStatus;
|
||||||
|
refused_reason?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface IPostDocumentsParams {}
|
||||||
|
|
||||||
|
export default class Documents extends BaseAdmin {
|
||||||
|
private static instance: Documents;
|
||||||
|
private readonly baseURl = this.namespaceUrl.concat("/documents");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new this();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get(q: IGetDocumentsparams): Promise<Document[]> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
const query = { q };
|
||||||
|
if (q) Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<Document[]>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Create a Document
|
||||||
|
*/
|
||||||
|
public async post(body: any): Promise<Document> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
try {
|
||||||
|
return await this.postRequest<Document>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getByUid(uid: string, q?: any): Promise<Document> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
const query = { q };
|
||||||
|
if (q) Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<Document>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async put(uid: string, body: IPutDocumentsParams): Promise<Document> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
try {
|
||||||
|
return await this.putRequest<Document>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async delete(uid: string): Promise<Document> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
try {
|
||||||
|
return await this.deleteRequest<Document>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
src/front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles.ts
Normal file
65
src/front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { OfficeRole } from "le-coffre-resources/dist/Admin";
|
||||||
|
|
||||||
|
import BaseAdmin from "../BaseAdmin";
|
||||||
|
|
||||||
|
export type IGetRolesParams = {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
select?: {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type IPutRoleParams = {
|
||||||
|
rules: OfficeRole["rules"];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class OfficeRoles extends BaseAdmin {
|
||||||
|
private static instance: OfficeRoles;
|
||||||
|
private readonly baseURl = this.namespaceUrl.concat("/office-roles");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new OfficeRoles();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get(q?: IGetRolesParams): Promise<OfficeRole[]> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
if (q) {
|
||||||
|
const query = { q };
|
||||||
|
Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return await this.getRequest<OfficeRole[]>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getByUid(uid: string, q?: any): Promise<OfficeRole> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
if (q) Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<OfficeRole>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async put(uid: string, body: IPutRoleParams): Promise<OfficeRole> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
try {
|
||||||
|
return await this.putRequest<OfficeRole>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
src/front/Api/LeCoffreApi/Admin/Rules/Rules.ts
Normal file
49
src/front/Api/LeCoffreApi/Admin/Rules/Rules.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { Rule } from "le-coffre-resources/dist/Admin";
|
||||||
|
|
||||||
|
import BaseAdmin from "../BaseAdmin";
|
||||||
|
|
||||||
|
export type IGetRulesParams = {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
select?: {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Rules extends BaseAdmin {
|
||||||
|
private static instance: Rules;
|
||||||
|
private readonly baseURl = this.namespaceUrl.concat("/rules");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new Rules();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get(q: IGetRulesParams): Promise<Rule[]> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
const query = { q };
|
||||||
|
Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<Rule[]>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getByUid(uid: string, q?: any): Promise<Rule> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
if (q) Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<Rule>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
src/front/Api/LeCoffreApi/Admin/Users/Users.ts
Normal file
91
src/front/Api/LeCoffreApi/Admin/Users/Users.ts
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import User from "le-coffre-resources/dist/SuperAdmin";
|
||||||
|
import BaseAdmin from "../BaseAdmin";
|
||||||
|
|
||||||
|
// TODO Type get query params -> Where + inclue + orderby
|
||||||
|
export interface IGetUsersparams {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
select?: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Type getbyuid query params
|
||||||
|
|
||||||
|
export type IPutUsersParams = {
|
||||||
|
uid?: User["uid"];
|
||||||
|
idNot?: User["idNot"];
|
||||||
|
contact?: User["contact"];
|
||||||
|
office_membership?: User["office_membership"];
|
||||||
|
documents?: User["documents"];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Users extends BaseAdmin {
|
||||||
|
private static instance: Users;
|
||||||
|
private readonly baseURl = this.namespaceUrl.concat("/users");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new this();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get all Users
|
||||||
|
*/
|
||||||
|
public async get(q: IGetUsersparams): Promise<User[]> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
const query = { q };
|
||||||
|
Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<User[]>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get a folder by uid
|
||||||
|
*/
|
||||||
|
public async getByUid(uid: string, q?: any): Promise<User> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
if (q) Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<User>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Create a User
|
||||||
|
*/
|
||||||
|
// public async post(body: IPostDeedsParams): Promise<OfficeFolder> {
|
||||||
|
// const url = new URL(this.baseURl);
|
||||||
|
// try {
|
||||||
|
// return await this.postRequest<OfficeFolder>(url, body);
|
||||||
|
// } catch (err) {
|
||||||
|
// this.onError(err);
|
||||||
|
// return Promise.reject(err);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Update the folder description
|
||||||
|
*/
|
||||||
|
public async put(uid: string, body: IPutUsersParams): Promise<User> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
try {
|
||||||
|
return await this.putRequest<User>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,7 @@ export type IPutDeedTypesParams = {
|
|||||||
deed?: DeedType["deed"];
|
deed?: DeedType["deed"];
|
||||||
office?: DeedType["office"];
|
office?: DeedType["office"];
|
||||||
archived_at?: DeedType["archived_at"];
|
archived_at?: DeedType["archived_at"];
|
||||||
deed_type_has_document_types?: DeedType["deed_type_has_document_types"];
|
document_types?: DeedType["document_types"];
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class DeedTypes extends BaseSuperAdmin {
|
export default class DeedTypes extends BaseSuperAdmin {
|
||||||
@ -37,9 +37,11 @@ export default class DeedTypes extends BaseSuperAdmin {
|
|||||||
/**
|
/**
|
||||||
* @description : Get all DeedTypes
|
* @description : Get all DeedTypes
|
||||||
*/
|
*/
|
||||||
public async get(q: IGetDeedTypesParams): Promise<DeedType[]> {
|
public async get(q?: IGetDeedTypesParams): Promise<DeedType[]> {
|
||||||
const url = new URL(this.baseURl);
|
const url = new URL(this.baseURl);
|
||||||
Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
if(q){
|
||||||
|
Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return await this.getRequest<DeedType[]>(url);
|
return await this.getRequest<DeedType[]>(url);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -15,7 +15,7 @@ export type IPutDeedsParams = {
|
|||||||
description?: OfficeFolder["description"];
|
description?: OfficeFolder["description"];
|
||||||
archived_description?: OfficeFolder["archived_description"];
|
archived_description?: OfficeFolder["archived_description"];
|
||||||
status?: OfficeFolder["status"];
|
status?: OfficeFolder["status"];
|
||||||
deed_has_document_types?: Deed["deed_has_document_types"];
|
document_types?: Deed["document_types"];
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class Deeds extends BaseSuperAdmin {
|
export default class Deeds extends BaseSuperAdmin {
|
||||||
|
@ -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);
|
const url = new URL(this.baseURl);
|
||||||
const query = { q };
|
if (q) {
|
||||||
if (q) Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
const query = { q };
|
||||||
|
if (q) Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return await this.getRequest<DocumentType[]>(url);
|
return await this.getRequest<DocumentType[]>(url);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { File } from "le-coffre-resources/dist/SuperAdmin";
|
import { File } from "le-coffre-resources/dist/SuperAdmin";
|
||||||
|
|
||||||
import BaseSuperAdmin from "../BaseSuperAdmin";
|
import BaseSuperAdmin from "../BaseSuperAdmin";
|
||||||
|
|
||||||
// TODO Type get query params -> Where + inclue + orderby
|
// TODO Type get query params -> Where + inclue + orderby
|
||||||
|
@ -88,7 +88,7 @@ export default class Folders extends BaseSuperAdmin {
|
|||||||
public async delete(uid: string): Promise<OfficeFolder> {
|
public async delete(uid: string): Promise<OfficeFolder> {
|
||||||
const url = new URL(this.baseURl.concat(`/${uid}`));
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
const targetedFolder = await this.getByUid(uid);
|
const targetedFolder = await this.getByUid(uid);
|
||||||
if (targetedFolder.office_folder_has_customers) return Promise.reject(`The folder ${uid} contains customers`);
|
if (targetedFolder.customers) return Promise.reject(`The folder ${uid} contains customers`);
|
||||||
try {
|
try {
|
||||||
return await this.deleteRequest(url);
|
return await this.deleteRequest(url);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
53
src/front/Api/LeCoffreApi/SuperAdmin/Offices/Offices.ts
Normal file
53
src/front/Api/LeCoffreApi/SuperAdmin/Offices/Offices.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { Office } from "le-coffre-resources/dist/SuperAdmin";
|
||||||
|
import BaseSuperAdmin from "../BaseSuperAdmin";
|
||||||
|
|
||||||
|
export interface IGetOfficesparams {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
select?: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Offices extends BaseSuperAdmin {
|
||||||
|
private static instance: Offices;
|
||||||
|
private readonly baseURl = this.namespaceUrl.concat("/offices");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new this();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get(q?: IGetOfficesparams): Promise<Office[]> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
if (q) {
|
||||||
|
const query = { q };
|
||||||
|
Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return await this.getRequest<Office[]>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get a folder by uid
|
||||||
|
*/
|
||||||
|
public async getByUid(uid: string, q?: any): Promise<Office> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
if (q) Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<Office>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,6 @@ export type IPutUsersParams = {
|
|||||||
idNot?: User["idNot"];
|
idNot?: User["idNot"];
|
||||||
contact?: User["contact"];
|
contact?: User["contact"];
|
||||||
office_membership?: User["office_membership"];
|
office_membership?: User["office_membership"];
|
||||||
office_folder_has_stakeholders?: User["office_folder_has_stakeholders"];
|
|
||||||
documents?: User["documents"];
|
documents?: User["documents"];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BIN
src/front/Assets/images/warning.png
Normal file
BIN
src/front/Assets/images/warning.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,29 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
padding: 24px;
|
||||||
|
border: 1px solid $grey-medium;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $grey-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-selected="true"] {
|
||||||
|
background-color: $grey-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-side {
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
margin-left: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
src/front/Components/DesignSystem/BlockList/index.tsx
Normal file
40
src/front/Components/DesignSystem/BlockList/index.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import React, { useCallback } from "react";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import Typography, { ITypo } from "../Typography";
|
||||||
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
export type IBlock = {
|
||||||
|
name: string;
|
||||||
|
id: string;
|
||||||
|
selected: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
blocks: IBlock[];
|
||||||
|
onSelectedBlock: (block: IBlock) => void;
|
||||||
|
};
|
||||||
|
export default function BlockList({ blocks, onSelectedBlock }: IProps) {
|
||||||
|
const selectBlock = useCallback(
|
||||||
|
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
|
onSelectedBlock && onSelectedBlock(blocks.find((block) => block.id === e.currentTarget.id)!);
|
||||||
|
},
|
||||||
|
[blocks, onSelectedBlock],
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{blocks.map((block) => {
|
||||||
|
return (
|
||||||
|
<div onClick={selectBlock} key={block.id} id={block.id}>
|
||||||
|
<div className={classes["root"]} data-selected={block.selected.toString()}>
|
||||||
|
<div className={classes["left-side"]}>
|
||||||
|
<Typography typo={ITypo.P_16}>{block.name}</Typography>
|
||||||
|
</div>
|
||||||
|
<Image alt="chevron" src={ChevronIcon} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -9,13 +9,29 @@ type IProps = {
|
|||||||
name?: string;
|
name?: string;
|
||||||
option: IOption;
|
option: IOption;
|
||||||
toolTip?: string;
|
toolTip?: string;
|
||||||
|
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
checked: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class CheckBox extends React.Component<IProps> {
|
type IState = {
|
||||||
|
checked: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class CheckBox extends React.Component<IProps, IState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
toolTip: "",
|
toolTip: "",
|
||||||
|
checked: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
checked: this.props.checked ?? false,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onChange = this.onChange.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public override render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Typography typo={ITypo.P_ERR_16} color={ITypoColor.BLACK}>
|
<Typography typo={ITypo.P_ERR_16} color={ITypoColor.BLACK}>
|
||||||
@ -24,6 +40,8 @@ export default class CheckBox extends React.Component<IProps> {
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
name={this.props.name ?? (this.props.option.value as string)}
|
name={this.props.name ?? (this.props.option.value as string)}
|
||||||
value={this.props.option.value as string}
|
value={this.props.option.value as string}
|
||||||
|
onChange={this.onChange}
|
||||||
|
checked={this.state.checked}
|
||||||
/>
|
/>
|
||||||
{this.props.option.label}
|
{this.props.option.label}
|
||||||
{this.props.toolTip && <Tooltip className={classes["tooltip"]} text={this.props.toolTip} />}
|
{this.props.toolTip && <Tooltip className={classes["tooltip"]} text={this.props.toolTip} />}
|
||||||
@ -31,4 +49,20 @@ export default class CheckBox extends React.Component<IProps> {
|
|||||||
</Typography>
|
</Typography>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override componentDidUpdate(prevProps: Readonly<IProps>): void {
|
||||||
|
if (prevProps.checked !== this.props.checked) {
|
||||||
|
this.setState({
|
||||||
|
checked: this.props.checked,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||||
|
this.setState({
|
||||||
|
checked: !this.state.checked,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.onChange && this.props.onChange(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,11 @@ import Link from "next/link";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Button from "../Button";
|
import Button from "../Button";
|
||||||
import FolderList from "../FolderList";
|
|
||||||
import SearchBar from "../SearchBar";
|
import SearchBar from "../SearchBar";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import BlockList, { IBlock } from "../BlockList";
|
||||||
|
import { NextRouter, useRouter } from "next/router";
|
||||||
|
import { EDocumentStatus } from "le-coffre-resources/dist/SuperAdmin/Document";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
folders: IDashBoardFolder[];
|
folders: IDashBoardFolder[];
|
||||||
@ -14,17 +16,26 @@ type IProps = {
|
|||||||
onSelectedFolder?: (folder: IDashBoardFolder) => void;
|
onSelectedFolder?: (folder: IDashBoardFolder) => void;
|
||||||
onCloseLeftSide?: () => void;
|
onCloseLeftSide?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type IPropsClass = IProps & {
|
||||||
|
router: NextRouter;
|
||||||
|
};
|
||||||
|
|
||||||
type IState = {
|
type IState = {
|
||||||
filteredFolders: IDashBoardFolder[];
|
filteredFolders: IDashBoardFolder[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class FolderListContainer extends React.Component<IProps, IState> {
|
class FolderListContainerClass extends React.Component<IPropsClass, IState> {
|
||||||
public constructor(props: IProps) {
|
private redirectPath: string = this.props.isArchived
|
||||||
|
? Module.getInstance().get().modules.pages.Folder.pages.FolderArchived.pages.FolderInformation.props.path
|
||||||
|
: Module.getInstance().get().modules.pages.Folder.pages.FolderInformation.props.path;
|
||||||
|
public constructor(props: IPropsClass) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
filteredFolders: this.props.folders,
|
filteredFolders: this.props.folders,
|
||||||
};
|
};
|
||||||
this.filterFolders = this.filterFolders.bind(this);
|
this.filterFolders = this.filterFolders.bind(this);
|
||||||
|
this.onSelectedFolder = this.onSelectedFolder.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public override render(): JSX.Element {
|
||||||
@ -33,15 +44,10 @@ export default class FolderListContainer extends React.Component<IProps, IState>
|
|||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<div className={classes["header"]}>
|
<div className={classes["header"]}>
|
||||||
<div className={classes["searchbar"]}>
|
<div className={classes["searchbar"]}>
|
||||||
<SearchBar folders={this.props.folders} onChange={this.filterFolders} placeholder="Chercher un dossier" />
|
<SearchBar onChange={this.filterFolders} placeholder="Chercher un dossier" />
|
||||||
</div>
|
</div>
|
||||||
<div className={classes["folderlist-container"]}>
|
<div className={classes["folderlist-container"]}>
|
||||||
<FolderList
|
<BlockList blocks={this.getBlocks()} onSelectedBlock={this.onSelectedFolder} />
|
||||||
folders={this.state.filteredFolders}
|
|
||||||
onSelectedFolder={this.props.onSelectedFolder && this.props.onSelectedFolder}
|
|
||||||
onCloseLeftSide={this.props.onCloseLeftSide}
|
|
||||||
isArchived={this.props.isArchived}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!this.props.isArchived && (
|
{!this.props.isArchived && (
|
||||||
@ -55,8 +61,62 @@ export default class FolderListContainer extends React.Component<IProps, IState>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private filterFolders(folders: IDashBoardFolder[]): IDashBoardFolder[] {
|
private getBlocks(): IBlock[] {
|
||||||
this.setState({ filteredFolders: folders });
|
const pendingFolders = this.props.folders
|
||||||
return folders;
|
.filter((folder) => {
|
||||||
|
const pendingDocuments = (folder.documents ?? []).filter(
|
||||||
|
(document) => document.document_status === EDocumentStatus.DEPOSITED,
|
||||||
|
);
|
||||||
|
return pendingDocuments.length >= 1;
|
||||||
|
})
|
||||||
|
.sort((folder1, folder2) => {
|
||||||
|
return folder1.created_at! > folder2.created_at! ? -1 : 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
const otherFolders = this.props.folders
|
||||||
|
.filter((folder) => {
|
||||||
|
const pendingDocuments = (folder.documents ?? []).filter(
|
||||||
|
(document) => document.document_status === EDocumentStatus.DEPOSITED,
|
||||||
|
);
|
||||||
|
return pendingDocuments.length === 0;
|
||||||
|
})
|
||||||
|
.sort((folder1, folder2) => {
|
||||||
|
return folder1.created_at! > folder2.created_at! ? -1 : 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
return [...pendingFolders, ...otherFolders].map((folder) => {
|
||||||
|
return { id: folder.uid!, name: folder.folder_number! + " - " + folder.name!, selected: false };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private onSelectedFolder(block: IBlock) {
|
||||||
|
const folder = this.props.folders.find((folder) => folder.uid === block.id);
|
||||||
|
if (!folder) return;
|
||||||
|
this.props.onSelectedFolder && this.props.onSelectedFolder(folder);
|
||||||
|
const path = this.redirectPath.replace("[folderUid]", folder.uid ?? "");
|
||||||
|
this.props.router.push(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private filterFolders(value: string): void {
|
||||||
|
const filteredFolders: IDashBoardFolder[] = this.props.folders.filter((folder) => {
|
||||||
|
const name = folder.name.toLowerCase();
|
||||||
|
const number = folder.folder_number.toLowerCase();
|
||||||
|
|
||||||
|
if (folder.customers) {
|
||||||
|
const customerNames = folder.customers
|
||||||
|
.map((customer) => {
|
||||||
|
return `${customer.contact?.first_name.toLowerCase()} ${customer.contact?.last_name.toLowerCase()}`;
|
||||||
|
})
|
||||||
|
.join(", ");
|
||||||
|
return name.includes(value) || number.includes(value) || customerNames.includes(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return name.includes(value) || number.includes(value);
|
||||||
|
});
|
||||||
|
this.setState({ filteredFolders });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function FolderListContainer(props: IProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
return <FolderListContainerClass {...props} router={router} />;
|
||||||
|
}
|
||||||
|
@ -55,6 +55,12 @@ export default abstract class BaseField<P extends IProps, S extends IState = ISt
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.props.defaultValue !== prevProps.defaultValue) {
|
||||||
|
this.setState({
|
||||||
|
value: this.props.defaultValue ?? "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (this.props.validationError !== prevProps.validationError) {
|
if (this.props.validationError !== prevProps.validationError) {
|
||||||
this.setState({
|
this.setState({
|
||||||
validationError: this.props.validationError ?? null,
|
validationError: this.props.validationError ?? null,
|
||||||
|
@ -123,6 +123,12 @@ export default class SelectField extends React.Component<IProps, IState> {
|
|||||||
errors: this.props.errors ?? null,
|
errors: this.props.errors ?? null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.props.selectedOption !== prevProps.selectedOption) {
|
||||||
|
this.setState({
|
||||||
|
selectedOption: this.props.selectedOption ?? null,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDerivedStateFromProps(props: IProps, state: IState) {
|
static getDerivedStateFromProps(props: IProps, state: IState) {
|
||||||
|
@ -32,6 +32,11 @@ export default class BurgerModal extends React.Component<IProps, IState> {
|
|||||||
text="Dossiers archivés"
|
text="Dossiers archivés"
|
||||||
routesActive={[Module.getInstance().get().modules.pages.Folder.pages.FolderArchived.props.path]}
|
routesActive={[Module.getInstance().get().modules.pages.Folder.pages.FolderArchived.props.path]}
|
||||||
/>
|
/>
|
||||||
|
<NavigationLink
|
||||||
|
path={Module.getInstance().get().modules.pages.Collaborators.props.path}
|
||||||
|
text="Collaborateurs"
|
||||||
|
routesActive={[Module.getInstance().get().modules.pages.Collaborators.props.path]}
|
||||||
|
/>
|
||||||
<div className={classes["separator"]} />
|
<div className={classes["separator"]} />
|
||||||
<LogOutButton />
|
<LogOutButton />
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,6 +24,11 @@ export default class Navigation extends React.Component<IProps, IState> {
|
|||||||
path={Module.getInstance().get().modules.pages.Folder.pages.FolderArchived.props.path}
|
path={Module.getInstance().get().modules.pages.Folder.pages.FolderArchived.props.path}
|
||||||
routesActive={[Module.getInstance().get().modules.pages.Folder.pages.FolderArchived.props.path]}
|
routesActive={[Module.getInstance().get().modules.pages.Folder.pages.FolderArchived.props.path]}
|
||||||
/>
|
/>
|
||||||
|
<HeaderLink
|
||||||
|
text={"Collaborateurs"}
|
||||||
|
path={Module.getInstance().get().modules.pages.Collaborators.props.path}
|
||||||
|
routesActive={[Module.getInstance().get().modules.pages.Collaborators.props.path]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import React from "react";
|
|
||||||
import classes from "./classes.module.scss";
|
|
||||||
import NavigationLink from "../../NavigationLink";
|
|
||||||
import LogOutButton from "@Front/Components/DesignSystem/LogOutButton";
|
import LogOutButton from "@Front/Components/DesignSystem/LogOutButton";
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import NavigationLink from "../../NavigationLink";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -19,6 +20,34 @@ export default class ProfileModal extends React.Component<IProps, IState> {
|
|||||||
<div className={classes["background"]} onClick={this.props.closeModal} />
|
<div className={classes["background"]} onClick={this.props.closeModal} />
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<NavigationLink path={Module.getInstance().get().modules.pages.MyAccount.props.path} text="Mon compte" />
|
<NavigationLink path={Module.getInstance().get().modules.pages.MyAccount.props.path} text="Mon compte" />
|
||||||
|
<NavigationLink path={Module.getInstance().get().modules.pages.Roles.props.path} text="Gestion des rôles" />
|
||||||
|
<NavigationLink
|
||||||
|
path={Module.getInstance().get().modules.pages.DeedTypes.props.path}
|
||||||
|
text="Paramétrage des listes de pièces"
|
||||||
|
routesActive={[
|
||||||
|
Module.getInstance().get().modules.pages.DeedTypes.props.path,
|
||||||
|
Module.getInstance().get().modules.pages.DeedTypes.pages.Create.props.path,
|
||||||
|
Module.getInstance().get().modules.pages.DeedTypes.pages.DeedTypesInformations.props.path,
|
||||||
|
Module.getInstance().get().modules.pages.DeedTypes.pages.Edit.props.path,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<NavigationLink
|
||||||
|
path={Module.getInstance().get().modules.pages.Users.props.path}
|
||||||
|
text="Gestion des utilisateurs"
|
||||||
|
routesActive={[
|
||||||
|
Module.getInstance().get().modules.pages.Users.props.path,
|
||||||
|
Module.getInstance().get().modules.pages.Users.pages.UsersInformations.props.path,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<NavigationLink
|
||||||
|
path={Module.getInstance().get().modules.pages.Offices.props.path}
|
||||||
|
text="Gestion des offices"
|
||||||
|
routesActive={[
|
||||||
|
Module.getInstance().get().modules.pages.Offices.props.path,
|
||||||
|
Module.getInstance().get().modules.pages.Offices.pages.OfficesInformations.props.path,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<NavigationLink text="Gestion des noms de domaine" />
|
||||||
<NavigationLink text="CGU" />
|
<NavigationLink text="CGU" />
|
||||||
<div className={classes["separator"]} />
|
<div className={classes["separator"]} />
|
||||||
<LogOutButton />
|
<LogOutButton />
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import LoopIcon from "@Assets/Icons/loop.svg";
|
import LoopIcon from "@Assets/Icons/loop.svg";
|
||||||
import { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
@ -7,10 +6,10 @@ import Typography, { ITypo } from "../Typography";
|
|||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
folders: IDashBoardFolder[];
|
onChange?: (input: string) => void;
|
||||||
onChange?: (folders: IDashBoardFolder[]) => IDashBoardFolder[];
|
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IState = {
|
type IState = {
|
||||||
hasValue: boolean;
|
hasValue: boolean;
|
||||||
};
|
};
|
||||||
@ -46,30 +45,10 @@ export default class SearchBar extends React.Component<IProps, IState> {
|
|||||||
const hasValue = event.target.value.length > 0;
|
const hasValue = event.target.value.length > 0;
|
||||||
this.doesInputHaveValue(hasValue);
|
this.doesInputHaveValue(hasValue);
|
||||||
if (!this.props.onChange) return;
|
if (!this.props.onChange) return;
|
||||||
this.props.onChange(this.filterFolders(event)!);
|
this.props.onChange(event.target.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private doesInputHaveValue(hasValue: boolean) {
|
private doesInputHaveValue(hasValue: boolean) {
|
||||||
this.setState({ hasValue });
|
this.setState({ hasValue });
|
||||||
}
|
}
|
||||||
|
|
||||||
private filterFolders(event: React.ChangeEvent<HTMLInputElement>) {
|
|
||||||
const filteredFolders: IDashBoardFolder[] = this.props.folders.filter((folder) => {
|
|
||||||
const name = folder.name.toLowerCase();
|
|
||||||
const number = folder.folder_number.toLowerCase();
|
|
||||||
const value = event.target.value.toLowerCase();
|
|
||||||
|
|
||||||
if (folder.office_folder_has_customers) {
|
|
||||||
const customerNames = folder.office_folder_has_customers
|
|
||||||
.map((customer) => {
|
|
||||||
return `${customer.customer.contact?.first_name.toLowerCase()} ${customer.customer.contact?.last_name.toLowerCase()}`;
|
|
||||||
})
|
|
||||||
.join(", ");
|
|
||||||
return name.includes(value) || number.includes(value) || customerNames.includes(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return name.includes(value) || number.includes(value);
|
|
||||||
});
|
|
||||||
return filteredFolders;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
import React, { useCallback, useState } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
||||||
|
import User from "le-coffre-resources/dist/Notary";
|
||||||
|
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import Module from "@Front/Config/Module";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
collaborators: User[];
|
||||||
|
onSelectedCollaborator?: (user: User) => void;
|
||||||
|
onCloseLeftSide?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function CollaboratorListContainer(props: IProps) {
|
||||||
|
const [filteredUsers, setFilteredUsers] = useState<User[]>(props.collaborators);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const { collaboratorUid } = router.query;
|
||||||
|
const filterUsers = useCallback(
|
||||||
|
(input: string) => {
|
||||||
|
const filteredUsers = props.collaborators.filter((user) => {
|
||||||
|
return (
|
||||||
|
user.contact?.first_name?.toLowerCase().includes(input.toLowerCase()) ||
|
||||||
|
user.contact?.last_name?.toLowerCase().includes(input.toLowerCase())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
setFilteredUsers(filteredUsers);
|
||||||
|
},
|
||||||
|
[props.collaborators],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSelectedBlock = useCallback(
|
||||||
|
(block: IBlock) => {
|
||||||
|
props.onCloseLeftSide && props.onCloseLeftSide();
|
||||||
|
const redirectPath = Module.getInstance().get().modules.pages.Collaborators.pages.CollaboratorInformations.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={filterUsers} placeholder="Chercher un collaborateur" />
|
||||||
|
</div>
|
||||||
|
<div className={classes["folderlist-container"]}>
|
||||||
|
<BlockList
|
||||||
|
blocks={filteredUsers.map((user) => {
|
||||||
|
return {
|
||||||
|
name: user.contact?.first_name + " " + user.contact?.last_name,
|
||||||
|
id: user.uid!,
|
||||||
|
selected: user.uid === collaboratorUid,
|
||||||
|
};
|
||||||
|
})}
|
||||||
|
onSelectedBlock={onSelectedBlock}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
|
import Users, { IGetUsersparams } from "@Front/Api/LeCoffreApi/Admin/Users/Users";
|
||||||
|
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 JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
|
import WindowStore from "@Front/Stores/WindowStore";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import User from "le-coffre-resources/dist/Notary";
|
||||||
|
import Image from "next/image";
|
||||||
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import CollaboratorListContainer from "./CollaboratorListContainer";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
title: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
onSelectedUser: (user: User) => void;
|
||||||
|
hasBackArrow: boolean;
|
||||||
|
backArrowUrl?: string;
|
||||||
|
mobileBackText?: string;
|
||||||
|
};
|
||||||
|
type IState = {
|
||||||
|
collaborators: User[] | null;
|
||||||
|
isLeftSideOpen: boolean;
|
||||||
|
leftSideCanBeClosed: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DefaultCollaboratorDashboard extends React.Component<IProps, IState> {
|
||||||
|
private onWindowResize = () => {};
|
||||||
|
public static defaultProps: Partial<IProps> = {
|
||||||
|
hasBackArrow: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
public constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
collaborators: 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.collaborators && (
|
||||||
|
<CollaboratorListContainer collaborators={this.state.collaborators} 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 jwt = JwtService.getInstance().decodeJwt();
|
||||||
|
if (!jwt) return;
|
||||||
|
const query: IGetUsersparams = {
|
||||||
|
where: { office_uid: jwt!.office_Id },
|
||||||
|
include: { contact: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
const collaborators = await Users.getInstance().get(query);
|
||||||
|
this.setState({ collaborators });
|
||||||
|
}
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
@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 {
|
||||||
|
max-height: calc(100vh - 290px);
|
||||||
|
overflow: auto;
|
||||||
|
border-right: 1px solid var(--grey-medium);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
import DeedTypes from "@Front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes";
|
||||||
|
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
||||||
|
import Button from "@Front/Components/DesignSystem/Button";
|
||||||
|
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
||||||
|
import Module from "@Front/Config/Module";
|
||||||
|
import { DeedType } from "le-coffre-resources/dist/Admin";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import React, { useCallback, useState } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
deedTypes: DeedType[];
|
||||||
|
onSelectedDeed?: (deed: DeedTypes) => void;
|
||||||
|
onCloseLeftSide?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function DeedListContainer(props: IProps) {
|
||||||
|
const [filteredUsers, setFilteredUsers] = useState<DeedType[]>(props.deedTypes);
|
||||||
|
const router = useRouter();
|
||||||
|
const { deedTypeUid } = router.query;
|
||||||
|
|
||||||
|
const filterDeeds = useCallback(
|
||||||
|
(input: string) => {
|
||||||
|
const filteredUsers = props.deedTypes.filter((deedType) => {
|
||||||
|
return deedType.name?.toLowerCase().includes(input.toLowerCase());
|
||||||
|
});
|
||||||
|
setFilteredUsers(filteredUsers);
|
||||||
|
},
|
||||||
|
[props.deedTypes],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSelectedBlock = useCallback(
|
||||||
|
(block: IBlock) => {
|
||||||
|
props.onCloseLeftSide && props.onCloseLeftSide();
|
||||||
|
const redirectPath = Module.getInstance().get().modules.pages.DeedTypes.pages.DeedTypesInformations.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={filterDeeds} placeholder="Chercher un type d'acte" />
|
||||||
|
</div>
|
||||||
|
<div className={classes["folderlist-container"]}>
|
||||||
|
<BlockList
|
||||||
|
blocks={filteredUsers.map((deed) => {
|
||||||
|
return {
|
||||||
|
name: deed.name,
|
||||||
|
id: deed.uid!,
|
||||||
|
selected: deedTypeUid === deed.uid,
|
||||||
|
};
|
||||||
|
})}
|
||||||
|
onSelectedBlock={onSelectedBlock}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Link href={Module.getInstance().get().modules.pages.DeedTypes.pages.Create.props.path}>
|
||||||
|
<Button fullwidth={true}>Créer un type d'acte</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
|
import DeedTypes, { IGetDeedTypesParams } from "@Front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes";
|
||||||
|
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 { Deed, DeedType } from "le-coffre-resources/dist/Admin";
|
||||||
|
import Image from "next/image";
|
||||||
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import DeedListContainer from "./DeedTypeListContainer";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
title: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
onSelectedDeed: (deed: Deed) => void;
|
||||||
|
hasBackArrow: boolean;
|
||||||
|
backArrowUrl?: string;
|
||||||
|
mobileBackText?: string;
|
||||||
|
};
|
||||||
|
type IState = {
|
||||||
|
deedTypes: DeedType[] | null;
|
||||||
|
isLeftSideOpen: boolean;
|
||||||
|
leftSideCanBeClosed: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DefaultDeedTypesDashboard extends React.Component<IProps, IState> {
|
||||||
|
private onWindowResize = () => {};
|
||||||
|
public static defaultProps: Partial<IProps> = {
|
||||||
|
hasBackArrow: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
public constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
deedTypes: 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.deedTypes && (
|
||||||
|
<DeedListContainer deedTypes={this.state.deedTypes} 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 query: IGetDeedTypesParams = {};
|
||||||
|
|
||||||
|
const deedTypes = await DeedTypes.getInstance().get(query);
|
||||||
|
this.setState({ deedTypes });
|
||||||
|
}
|
||||||
|
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
position: relative;
|
||||||
|
.header {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbar {
|
||||||
|
padding: 40px 24px 24px 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.folderlist-container {
|
||||||
|
max-height: calc(100vh - 290px);
|
||||||
|
overflow: auto;
|
||||||
|
border-right: 1px solid var(--grey-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-container {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
||||||
|
import Button from "@Front/Components/DesignSystem/Button";
|
||||||
|
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
||||||
|
import Module from "@Front/Config/Module";
|
||||||
|
import { DocumentType } from "le-coffre-resources/dist/SuperAdmin";
|
||||||
|
import Link from "next/link";
|
||||||
|
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 className={classes["create-container"]}>
|
||||||
|
<Link href={Module.getInstance().get().modules.pages.DocumentTypes.pages.Create.props.path}>
|
||||||
|
<Button fullwidth={true}>Créer un type de document</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
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 JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
|
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 jwt = JwtService.getInstance().decodeJwt();
|
||||||
|
if (!jwt) return;
|
||||||
|
const documentTypes = await DocumentTypes.getInstance().get({
|
||||||
|
where: {
|
||||||
|
office_uid: jwt.office_Id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
import Folders, { IGetFoldersParams } from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
import Folders, { IGetFoldersParams } from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
@ -9,12 +8,11 @@ import BackArrow from "@Front/Components/Elements/BackArrow";
|
|||||||
import WindowStore from "@Front/Stores/WindowStore";
|
import WindowStore from "@Front/Stores/WindowStore";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { OfficeFolder } from "le-coffre-resources/dist/Customer";
|
import { OfficeFolder } from "le-coffre-resources/dist/Customer";
|
||||||
|
import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus";
|
|
||||||
|
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
title: string;
|
title: string;
|
||||||
@ -39,7 +37,7 @@ export type IDashBoardFolder = {
|
|||||||
description: OfficeFolder["description"];
|
description: OfficeFolder["description"];
|
||||||
deed?: OfficeFolder["deed"];
|
deed?: OfficeFolder["deed"];
|
||||||
created_at: OfficeFolder["created_at"];
|
created_at: OfficeFolder["created_at"];
|
||||||
office_folder_has_customers?: OfficeFolder["office_folder_has_customers"];
|
customers?: OfficeFolder["customers"];
|
||||||
archived_description: OfficeFolder["archived_description"];
|
archived_description: OfficeFolder["archived_description"];
|
||||||
status: OfficeFolder["status"];
|
status: OfficeFolder["status"];
|
||||||
};
|
};
|
||||||
@ -118,18 +116,14 @@ export default class DefaultNotaryDashboard extends React.Component<IProps, ISta
|
|||||||
include: {
|
include: {
|
||||||
deed: { include: { deed_type: true } },
|
deed: { include: { deed_type: true } },
|
||||||
office: true,
|
office: true,
|
||||||
office_folder_has_customers: {
|
customers: {
|
||||||
include: {
|
include: {
|
||||||
customer: {
|
contact: true,
|
||||||
|
documents: {
|
||||||
include: {
|
include: {
|
||||||
contact: true,
|
folder: true,
|
||||||
documents: {
|
document_type: true,
|
||||||
include: {
|
files: true,
|
||||||
folder: true,
|
|
||||||
document_type: true,
|
|
||||||
files: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
||||||
|
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
||||||
|
import Module from "@Front/Config/Module";
|
||||||
|
import { Office } 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 = {
|
||||||
|
offices: Office[];
|
||||||
|
onSelectedOffice?: (office: Office) => void;
|
||||||
|
onCloseLeftSide?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function OfficeListContainer(props: IProps) {
|
||||||
|
const [filteredOffices, setFilteredOffices] = useState<Office[]>(props.offices);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const { officeUid } = router.query;
|
||||||
|
const filterOffices = useCallback(
|
||||||
|
(input: string) => {
|
||||||
|
const filteredOffices = props.offices.filter((office) => {
|
||||||
|
return (
|
||||||
|
office.name.toLowerCase().includes(input.toLowerCase()) || office.crpcen?.toLowerCase().includes(input.toLowerCase())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
setFilteredOffices(filteredOffices);
|
||||||
|
},
|
||||||
|
[props.offices],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSelectedBlock = useCallback(
|
||||||
|
(block: IBlock) => {
|
||||||
|
props.onCloseLeftSide && props.onCloseLeftSide();
|
||||||
|
const redirectPath = Module.getInstance().get().modules.pages.Offices.pages.OfficesInformations.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={filterOffices} placeholder="Chercher un utilisateur" />
|
||||||
|
</div>
|
||||||
|
<div className={classes["folderlist-container"]}>
|
||||||
|
<BlockList
|
||||||
|
blocks={filteredOffices.map((office) => {
|
||||||
|
return {
|
||||||
|
name: office.crpcen + " - " + office.name,
|
||||||
|
id: office.uid!,
|
||||||
|
selected: office.uid === officeUid,
|
||||||
|
};
|
||||||
|
})}
|
||||||
|
onSelectedBlock={onSelectedBlock}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
|
import Offices from "@Front/Api/LeCoffreApi/SuperAdmin/Offices/Offices";
|
||||||
|
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 { Office } from "le-coffre-resources/dist/Notary";
|
||||||
|
import Image from "next/image";
|
||||||
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import OfficeListContainer from "./OfficeListContainer";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
title: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
onSelectedOffice: (office: Office) => void;
|
||||||
|
hasBackArrow: boolean;
|
||||||
|
backArrowUrl?: string;
|
||||||
|
mobileBackText?: string;
|
||||||
|
};
|
||||||
|
type IState = {
|
||||||
|
offices: Office[] | null;
|
||||||
|
isLeftSideOpen: boolean;
|
||||||
|
leftSideCanBeClosed: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DefaultOfficeDashboard extends React.Component<IProps, IState> {
|
||||||
|
private onWindowResize = () => {};
|
||||||
|
public static defaultProps: Partial<IProps> = {
|
||||||
|
hasBackArrow: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
public constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
offices: 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.offices && <OfficeListContainer offices={this.state.offices} 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 offices = await Offices.getInstance().get();
|
||||||
|
this.setState({ offices });
|
||||||
|
}
|
||||||
|
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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 { OfficeRole } from "le-coffre-resources/dist/Admin";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import React, { useCallback, useState } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
roles: OfficeRole[];
|
||||||
|
onSelectedRole?: (role: OfficeRole) => void;
|
||||||
|
onCloseLeftSide?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RoleListContainer(props: IProps) {
|
||||||
|
const [filteredRoles, setFilteredRoles] = useState<OfficeRole[]>(props.roles);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const { roleUid } = router.query;
|
||||||
|
|
||||||
|
const filterRoles = useCallback(
|
||||||
|
(input: string) => {
|
||||||
|
const filteredRoles = props.roles.filter((role) => {
|
||||||
|
return role.name?.toLowerCase().includes(input.toLowerCase());
|
||||||
|
});
|
||||||
|
setFilteredRoles(filteredRoles);
|
||||||
|
},
|
||||||
|
[props.roles],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSelectedBlock = useCallback(
|
||||||
|
(block: IBlock) => {
|
||||||
|
props.onCloseLeftSide && props.onCloseLeftSide();
|
||||||
|
const redirectPath = Module.getInstance().get().modules.pages.Roles.pages.RolesInformations.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={filterRoles} placeholder="Chercher un rôle" />
|
||||||
|
</div>
|
||||||
|
<div className={classes["folderlist-container"]}>
|
||||||
|
<BlockList
|
||||||
|
blocks={filteredRoles.map((role) => {
|
||||||
|
return {
|
||||||
|
name: role.name,
|
||||||
|
id: role.uid!,
|
||||||
|
selected: role.uid === roleUid,
|
||||||
|
};
|
||||||
|
})}
|
||||||
|
onSelectedBlock={onSelectedBlock}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,118 @@
|
|||||||
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
|
import OfficeRoles, { IGetRolesParams } from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles";
|
||||||
|
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 { OfficeRole } from "le-coffre-resources/dist/Admin";
|
||||||
|
import Image from "next/image";
|
||||||
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import RoleListContainer from "./RoleListContainer";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
title: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
onSelectedRole: (role: OfficeRole) => void;
|
||||||
|
hasBackArrow: boolean;
|
||||||
|
backArrowUrl?: string;
|
||||||
|
mobileBackText?: string;
|
||||||
|
};
|
||||||
|
type IState = {
|
||||||
|
roles: OfficeRole[] | null;
|
||||||
|
isLeftSideOpen: boolean;
|
||||||
|
leftSideCanBeClosed: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DefaultRoleDashboard extends React.Component<IProps, IState> {
|
||||||
|
private onWindowResize = () => {};
|
||||||
|
public static defaultProps: Partial<IProps> = {
|
||||||
|
hasBackArrow: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
public constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
roles: 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.roles && <RoleListContainer roles={this.state.roles} 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 query: IGetRolesParams = {
|
||||||
|
include: { rules: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
const roles = await OfficeRoles.getInstance().get(query);
|
||||||
|
console.log(roles);
|
||||||
|
|
||||||
|
this.setState({ roles });
|
||||||
|
}
|
||||||
|
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
||||||
|
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
||||||
|
import Module from "@Front/Config/Module";
|
||||||
|
import User from "le-coffre-resources/dist/Notary";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import React, { useCallback, useState } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
users: User[];
|
||||||
|
onSelectedUser?: (user: User) => void;
|
||||||
|
onCloseLeftSide?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function UserListContainer(props: IProps) {
|
||||||
|
const [filteredUsers, setFilteredUsers] = useState<User[]>(props.users);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const { userUid } = router.query;
|
||||||
|
const filterUsers = useCallback(
|
||||||
|
(input: string) => {
|
||||||
|
const filteredUsers = props.users.filter((user) => {
|
||||||
|
return (
|
||||||
|
user.contact?.first_name?.toLowerCase().includes(input.toLowerCase()) ||
|
||||||
|
user.contact?.last_name?.toLowerCase().includes(input.toLowerCase())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
setFilteredUsers(filteredUsers);
|
||||||
|
},
|
||||||
|
[props.users],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSelectedBlock = useCallback(
|
||||||
|
(block: IBlock) => {
|
||||||
|
props.onCloseLeftSide && props.onCloseLeftSide();
|
||||||
|
const redirectPath = Module.getInstance().get().modules.pages.Users.pages.UsersInformations.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={filterUsers} placeholder="Chercher un utilisateur" />
|
||||||
|
</div>
|
||||||
|
<div className={classes["folderlist-container"]}>
|
||||||
|
<BlockList
|
||||||
|
blocks={filteredUsers.map((user) => {
|
||||||
|
return {
|
||||||
|
name: user.contact?.first_name + " " + user.contact?.last_name,
|
||||||
|
id: user.uid!,
|
||||||
|
selected: user.uid === userUid,
|
||||||
|
};
|
||||||
|
})}
|
||||||
|
onSelectedBlock={onSelectedBlock}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
|
import Users, { IGetUsersparams } from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
|
||||||
|
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 User from "le-coffre-resources/dist/Notary";
|
||||||
|
import Image from "next/image";
|
||||||
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import UserListContainer from "./UserListContainer";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
title: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
onSelectedUser: (user: User) => void;
|
||||||
|
hasBackArrow: boolean;
|
||||||
|
backArrowUrl?: string;
|
||||||
|
mobileBackText?: string;
|
||||||
|
};
|
||||||
|
type IState = {
|
||||||
|
users: User[] | null;
|
||||||
|
isLeftSideOpen: boolean;
|
||||||
|
leftSideCanBeClosed: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DefaultUserDashboard extends React.Component<IProps, IState> {
|
||||||
|
private onWindowResize = () => {};
|
||||||
|
public static defaultProps: Partial<IProps> = {
|
||||||
|
hasBackArrow: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
public constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
users: 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.users && <UserListContainer users={this.state.users} 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 query: IGetUsersparams = {
|
||||||
|
include: { contact: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
const users = await Users.getInstance().get(query);
|
||||||
|
this.setState({ users });
|
||||||
|
}
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,6 @@ import React from "react";
|
|||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import Customers from "@Front/Api/LeCoffreApi/SuperAdmin/Customers/Customers";
|
import Customers from "@Front/Api/LeCoffreApi/SuperAdmin/Customers/Customers";
|
||||||
import Customer, { Document } from "le-coffre-resources/dist/Customer";
|
import Customer, { Document } from "le-coffre-resources/dist/Customer";
|
||||||
import { document } from "./../../../Components/Layouts/DesignSystem/dummyData";
|
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
targetedCustormer: string; // MOCK
|
targetedCustormer: string; // MOCK
|
||||||
@ -69,7 +68,7 @@ export default class ClientDashboard extends Base<IProps, IState> {
|
|||||||
Glissez / Déposez votre document dans la zone prévue à cet effet ou cliquez sur la zone puis sélectionnez le
|
Glissez / Déposez votre document dans la zone prévue à cet effet ou cliquez sur la zone puis sélectionnez le
|
||||||
document correspondant.
|
document correspondant.
|
||||||
</Typography>
|
</Typography>
|
||||||
<DepositDocument document={document} />
|
{/* <DepositDocument document={document} /> */}
|
||||||
</div>
|
</div>
|
||||||
</Confirm>
|
</Confirm>
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
.user-infos {
|
||||||
|
background-color: var(--grey-soft);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 24px;
|
||||||
|
|
||||||
|
margin-top: 32px;
|
||||||
|
|
||||||
|
@media (max-width: $screen-l) {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: $screen-s) {
|
||||||
|
grid-template-columns: repeat(1, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-infos-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-container {
|
||||||
|
padding: 32px 16px;
|
||||||
|
border: 1px solid var(--grey);
|
||||||
|
|
||||||
|
margin-top: 32px;
|
||||||
|
|
||||||
|
.first-line {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.second-line {
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
.third-line {
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,118 @@
|
|||||||
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
|
import OfficeRoles from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles";
|
||||||
|
import Users from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
|
||||||
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
|
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
|
||||||
|
import SelectField, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import DefaultCollaboratorDashboard from "@Front/Components/LayoutTemplates/DefaultCollaboratorDashboard";
|
||||||
|
import Module from "@Front/Config/Module";
|
||||||
|
import User from "le-coffre-resources/dist/Notary";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {};
|
||||||
|
export default function CollaboratorInformations(props: IProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
let { collaboratorUid } = router.query;
|
||||||
|
|
||||||
|
const [userSelected, setUserSelected] = useState<User | null>(null);
|
||||||
|
const [availableRoles, setAvailableRoles] = useState<IOption[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function getUser() {
|
||||||
|
if (!collaboratorUid) return;
|
||||||
|
const user = await Users.getInstance().getByUid(collaboratorUid as string, {
|
||||||
|
q: {
|
||||||
|
contact: true,
|
||||||
|
office_role: true,
|
||||||
|
role: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!user) return;
|
||||||
|
|
||||||
|
const roles = await OfficeRoles.getInstance().get();
|
||||||
|
if (!roles) return;
|
||||||
|
setAvailableRoles(roles.map((role) => ({ value: role.uid, label: role.name })));
|
||||||
|
setUserSelected(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUser();
|
||||||
|
}, [collaboratorUid]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultCollaboratorDashboard mobileBackText={"Liste des collaborateurs"}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["folder-header"]}>
|
||||||
|
<Typography typo={ITypo.H1Bis}>{userSelected?.contact?.first_name + " " + userSelected?.contact?.last_name}</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["user-infos"]}>
|
||||||
|
<div className={classes["user-infos-row"]}>
|
||||||
|
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
|
||||||
|
Nom
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18}>{userSelected?.contact?.first_name}</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["user-infos-row"]}>
|
||||||
|
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
|
||||||
|
Prénom
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18}>{userSelected?.contact?.last_name}</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["user-infos-row"]}>
|
||||||
|
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
|
||||||
|
Numéro de téléphone
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18}>{userSelected?.contact?.phone_number}</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["user-infos-row"]}>
|
||||||
|
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
|
||||||
|
Email
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18}>{userSelected?.contact?.email}</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes["role-container"]}>
|
||||||
|
<div className={classes["first-line"]}>
|
||||||
|
<Typography typo={ITypo.P_SB_18}>Modifier le rôle</Typography>
|
||||||
|
<div className={classes["gestion-role"]}>
|
||||||
|
<Link href={Module.getInstance().get().modules.pages.Roles.props.path}>
|
||||||
|
<Button
|
||||||
|
icon={ChevronIcon}
|
||||||
|
iconposition={"right"}
|
||||||
|
iconstyle={{ width: "22px", height: "22px" }}
|
||||||
|
variant={EButtonVariant.LINE}>
|
||||||
|
Gestion des rôles
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["second-line"]}>
|
||||||
|
<SelectField
|
||||||
|
placeholder="Rôle"
|
||||||
|
name="role"
|
||||||
|
options={availableRoles}
|
||||||
|
selectedOption={{
|
||||||
|
value: userSelected?.office_role ? userSelected?.office_role?.uid : userSelected?.role?.uid,
|
||||||
|
label: userSelected?.office_role ? userSelected?.office_role?.name : userSelected?.role?.name!,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={classes["third-line"]}>
|
||||||
|
<CheckBox
|
||||||
|
option={{
|
||||||
|
value: "1",
|
||||||
|
label: "Nommer administrateur de l'office",
|
||||||
|
}}
|
||||||
|
toolTip="blabla"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultCollaboratorDashboard>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100%;
|
||||||
|
|
||||||
|
.no-folder-selected {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.choose-a-folder {
|
||||||
|
margin-top: 96px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.folder-informations {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
.folder-header {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.second-box {
|
||||||
|
margin-top: 24px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-container {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
:first-child {
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
> * {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
@media (max-width: $screen-m) {
|
||||||
|
:first-child {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
> * {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-title {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/front/Components/Layouts/Collaborators/index.tsx
Normal file
26
src/front/Components/Layouts/Collaborators/index.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
|
||||||
|
import BasePage from "../Base";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import DefaultCollaboratorDashboard from "@Front/Components/LayoutTemplates/DefaultCollaboratorDashboard";
|
||||||
|
|
||||||
|
type IProps = {};
|
||||||
|
type IState = {};
|
||||||
|
export default class Collaborators extends BasePage<IProps, IState> {
|
||||||
|
public override render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<DefaultCollaboratorDashboard title={"Dossier"} mobileBackText={"Liste des collaborateurs"}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["no-folder-selected"]}>
|
||||||
|
<Typography typo={ITypo.H1Bis}>Informations du collaboraeur</Typography>
|
||||||
|
<div className={classes["choose-a-folder"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.GREY}>
|
||||||
|
Sélectionnez un collaborateur
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultCollaboratorDashboard>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
import DeedTypes from "@Front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes";
|
||||||
|
import Form from "@Front/Components/DesignSystem/Form";
|
||||||
|
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import DefaultDeedTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDeedTypeDashboard";
|
||||||
|
import { DeedType } from "le-coffre-resources/dist/Admin";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import TextField from "@Front/Components/DesignSystem/Form/TextField";
|
||||||
|
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
|
||||||
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
|
|
||||||
|
export default function DeedTypesEdit() {
|
||||||
|
const router = useRouter();
|
||||||
|
let { deedTypeUid } = router.query;
|
||||||
|
|
||||||
|
const [deedTypeSelected, setDeedTypeSelected] = useState<DeedType | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function getDeedType() {
|
||||||
|
if (!deedTypeUid) return;
|
||||||
|
const deedType = await DeedTypes.getInstance().getByUid(deedTypeUid as string, {
|
||||||
|
q: {
|
||||||
|
document_types: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
setDeedTypeSelected(deedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDeedType();
|
||||||
|
}, [deedTypeUid]);
|
||||||
|
|
||||||
|
const onSubmitHandler = useCallback(async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultDeedTypesDashboard mobileBackText={"Liste des types d'actes"} hasBackArrow title="Modifier les informations d'un acte">
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["header"]}>
|
||||||
|
<Typography typo={ITypo.H1Bis}>Modifier les informations de l'acte</Typography>
|
||||||
|
</div>
|
||||||
|
<Form onSubmit={onSubmitHandler} className={classes["form-container"]}>
|
||||||
|
<TextField name="name" placeholder="Nom de l'acte" defaultValue={deedTypeSelected?.name} />
|
||||||
|
<TextAreaField name="description" placeholder="Description" defaultValue={deedTypeSelected?.description} />
|
||||||
|
<div className={classes["buttons-container"]}>
|
||||||
|
<Button variant={EButtonVariant.GHOST}>Annuler</Button>
|
||||||
|
<Button type="submit">Enregistrer</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</DefaultDeedTypesDashboard>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,129 @@
|
|||||||
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
|
import PenICon from "@Assets/Icons/pen.svg";
|
||||||
|
import DeedTypes from "@Front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes";
|
||||||
|
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 { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
||||||
|
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
|
||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import DefaultDeedTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDeedTypeDashboard";
|
||||||
|
import Module from "@Front/Config/Module";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import { DeedType, 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 { MultiValue } from "react-select";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {};
|
||||||
|
export default function DeedTypesInformations(props: IProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
let { deedTypeUid } = router.query;
|
||||||
|
|
||||||
|
const [deedTypeSelected, setDeedTypeSelected] = useState<DeedType | null>(null);
|
||||||
|
const [availableDocuments, setAvailableDocuments] = useState<DocumentType[]>([]);
|
||||||
|
const [selectedDocuments, setSelectedDocuments] = useState<IOption[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function getDeedType() {
|
||||||
|
if (!deedTypeUid) return;
|
||||||
|
const deedType = await DeedTypes.getInstance().getByUid(deedTypeUid as string, {
|
||||||
|
q: {
|
||||||
|
document_types: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
setDeedTypeSelected(deedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getDocuments() {
|
||||||
|
const documents = await DocumentTypes.getInstance().get({});
|
||||||
|
setAvailableDocuments(documents);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelectedDocuments([]);
|
||||||
|
getDocuments();
|
||||||
|
getDeedType();
|
||||||
|
}, [deedTypeUid]);
|
||||||
|
|
||||||
|
const onSubmitHandler = useCallback(async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {}, []);
|
||||||
|
|
||||||
|
const onDocumentChangeHandler = useCallback((values: MultiValue<IOption>) => {
|
||||||
|
setSelectedDocuments(values as IOption[]);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const formattedOptions: IOption[] = availableDocuments.map((document) => {
|
||||||
|
return {
|
||||||
|
label: document.name,
|
||||||
|
value: document.uid,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultDeedTypesDashboard 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>
|
||||||
|
<Link href={Module.getInstance().get().modules.pages.DocumentTypes.props.path}>
|
||||||
|
<Button variant={EButtonVariant.LINE}>
|
||||||
|
Modifier la liste des documents
|
||||||
|
<Image src={ChevronIcon} alt="Chevron" />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
<div className={classes["subtitle"]}>
|
||||||
|
<Typography typo={ITypo.H3}>{deedTypeSelected?.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}>{deedTypeSelected?.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>
|
||||||
|
<Typography typo={ITypo.P_18}>{deedTypeSelected?.description}</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["pencil"]}>
|
||||||
|
<Link
|
||||||
|
href={Module.getInstance()
|
||||||
|
.get()
|
||||||
|
.modules.pages.DeedTypes.pages.Edit.props.path.replace("[uid]", deedTypeUid 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["documents"]}>
|
||||||
|
<MultiSelect
|
||||||
|
options={formattedOptions}
|
||||||
|
placeholder="Type de document"
|
||||||
|
onChange={onDocumentChangeHandler}
|
||||||
|
defaultValue={selectedDocuments}
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
|
</DefaultDeedTypesDashboard>
|
||||||
|
);
|
||||||
|
}
|
17
src/front/Components/Layouts/DeedTypes/classes.module.scss
Normal file
17
src/front/Components/Layouts/DeedTypes/classes.module.scss
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/front/Components/Layouts/DeedTypes/index.tsx
Normal file
26
src/front/Components/Layouts/DeedTypes/index.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import DefaultDeedTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDeedTypeDashboard";
|
||||||
|
|
||||||
|
import BasePage from "../Base";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {};
|
||||||
|
type IState = {};
|
||||||
|
export default class DeedTypes extends BasePage<IProps, IState> {
|
||||||
|
public override render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<DefaultDeedTypesDashboard mobileBackText={"Liste des listes de pièces"}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["no-role-selected"]}>
|
||||||
|
<Typography typo={ITypo.H1Bis}>Paramétrage des listes de pièces</Typography>
|
||||||
|
<div className={classes["choose-a-role"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.GREY}>
|
||||||
|
Sélectionnez une liste de pièces
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultDeedTypesDashboard>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
.root {
|
|
||||||
margin-left: 35px;
|
|
||||||
margin-right: 35px;
|
|
||||||
.section {
|
|
||||||
margin-bottom: 32px;
|
|
||||||
}
|
|
||||||
.sub-section {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-flex {
|
|
||||||
display: inline-flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.folder-conatainer {
|
|
||||||
width: 389px;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,347 +0,0 @@
|
|||||||
import { ECustomerStatus } from "le-coffre-resources/dist/Customer/Customer";
|
|
||||||
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
|
|
||||||
import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus";
|
|
||||||
import {
|
|
||||||
Address,
|
|
||||||
Contact,
|
|
||||||
Customer,
|
|
||||||
Deed,
|
|
||||||
DeedType,
|
|
||||||
Document,
|
|
||||||
DocumentType,
|
|
||||||
File,
|
|
||||||
Office,
|
|
||||||
OfficeFolder,
|
|
||||||
OfficeFolderHasCustomer,
|
|
||||||
} from "le-coffre-resources/dist/Notary";
|
|
||||||
|
|
||||||
export const address: Address = {
|
|
||||||
uid: "a&2azedzaa3",
|
|
||||||
address: "123",
|
|
||||||
city: "France",
|
|
||||||
zip_code: 78140,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const office: Office = {
|
|
||||||
uid: "111zdazaefez213",
|
|
||||||
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: "123azefezgzeg312",
|
|
||||||
name: "Acte mariage",
|
|
||||||
description: "dzsdaf",
|
|
||||||
archived_at: new Date(),
|
|
||||||
office: office,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const deed: Deed = {
|
|
||||||
uid: "zegefzeferg",
|
|
||||||
deed_type: deedType,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const contact: Contact = {
|
|
||||||
uid: "contact_1_uid",
|
|
||||||
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 contact2: Contact = {
|
|
||||||
uid: "contact_2_uid",
|
|
||||||
first_name: "Customer2",
|
|
||||||
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: "Votre document",
|
|
||||||
uid: "fezezfazegezrgrezg",
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
public_description: "",
|
|
||||||
private_description: "",
|
|
||||||
archived_at: new Date(),
|
|
||||||
office: office,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const identityDocType: DocumentType = {
|
|
||||||
name: "Carte d'identité",
|
|
||||||
uid: "fezezfazegezrgrezg",
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
public_description: "Carte d'identité public description",
|
|
||||||
private_description: "Carte d'identité private description",
|
|
||||||
archived_at: new Date(),
|
|
||||||
office: office,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const customer: Customer = {
|
|
||||||
uid: "erhtgerfzeare",
|
|
||||||
contact: contact,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
status: ECustomerStatus.VALIDATED,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const customer2_mock: Customer = {
|
|
||||||
uid: "yregrgetergrt",
|
|
||||||
contact: contact2,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
status: ECustomerStatus.VALIDATED,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const folder: OfficeFolder = {
|
|
||||||
uid: "mkovrijvrezviev",
|
|
||||||
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 document: Document = {
|
|
||||||
uid: "fzeafergreztyzgrf",
|
|
||||||
depositor: customer2_mock,
|
|
||||||
document_status: "ASKED",
|
|
||||||
folder: folder,
|
|
||||||
document_type: docType,
|
|
||||||
updated_at: new Date(),
|
|
||||||
created_at: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fileMock: File = {
|
|
||||||
uid: "super_file_uid_1",
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
document: document,
|
|
||||||
file_name: "file_1",
|
|
||||||
file_path:
|
|
||||||
"https://minteed-stg-euwest3-s3.s3.eu-west-3.amazonaws.com/Qmf_Yb_Eh_X9st_F_Srq_Ve_Bj_Yb_Aj56xv_AV_Nj6_Wjypo_B4r5ubce_U_ae3303e7ab.pdf",
|
|
||||||
archived_at: null,
|
|
||||||
mimetype: "image/png",
|
|
||||||
size: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const fileMock2: File = {
|
|
||||||
uid: "super_file_uid_2",
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
document: document,
|
|
||||||
file_name: "file_2",
|
|
||||||
file_path:
|
|
||||||
"https://minteed-prod-euwest3-s3.s3.eu-west-3.amazonaws.com/Qm_Wq_En1_DCA_8yt_RX_Qx_QFA_9_Fm_ZKZH_Qqb_VH_1_Q_Mnv_G_Jtt1_FS_Xp_2a35a36e19",
|
|
||||||
archived_at: null,
|
|
||||||
mimetype: "image/png",
|
|
||||||
size: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const identityFile: File = {
|
|
||||||
uid: "identity_file_uid",
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
document: document,
|
|
||||||
file_name: "file_3",
|
|
||||||
file_path: "https://minteed-stg-euwest3-s3.s3.eu-west-3.amazonaws.com/cni_fake_c7259d4923.png",
|
|
||||||
archived_at: null,
|
|
||||||
mimetype: "image/png",
|
|
||||||
size: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const documentIdentity: Document = {
|
|
||||||
uid: "ethrthbkjtrbporjbh",
|
|
||||||
depositor: customer2_mock,
|
|
||||||
document_status: EDocumentStatus.DEPOSITED,
|
|
||||||
folder: folder,
|
|
||||||
document_type: identityDocType,
|
|
||||||
updated_at: new Date(),
|
|
||||||
created_at: new Date(),
|
|
||||||
files: [identityFile],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const documentPending: Document = {
|
|
||||||
uid: "fzefeazdagrtetrury",
|
|
||||||
depositor: customer2_mock,
|
|
||||||
document_status: EDocumentStatus.DEPOSITED,
|
|
||||||
folder: folder,
|
|
||||||
document_type: docType,
|
|
||||||
updated_at: new Date(),
|
|
||||||
created_at: new Date(),
|
|
||||||
files: [fileMock, fileMock2],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const documentDeposited: Document = {
|
|
||||||
uid: "uè§u§htfgrthytrgr",
|
|
||||||
depositor: customer2_mock,
|
|
||||||
document_status: "VALIDATED",
|
|
||||||
folder: folder,
|
|
||||||
document_type: docType,
|
|
||||||
updated_at: new Date(),
|
|
||||||
created_at: new Date(),
|
|
||||||
files: [fileMock],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const customer2: Customer = {
|
|
||||||
uid: "yregrgetergrt",
|
|
||||||
contact: contact2,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
status: ECustomerStatus.VALIDATED,
|
|
||||||
documents: [document, documentPending, documentDeposited, documentIdentity],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const folderWithPendingDocument: OfficeFolder = {
|
|
||||||
uid: "ferzferzfezeefzdd",
|
|
||||||
folder_number: "00001",
|
|
||||||
name: "Mon dossier",
|
|
||||||
status: EFolderStatus.LIVE,
|
|
||||||
deed: deed,
|
|
||||||
office: office,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
description: "Description",
|
|
||||||
archived_description: "Archived description",
|
|
||||||
documents: [],
|
|
||||||
};
|
|
||||||
export const folderWithPendingDocument1: OfficeFolder = {
|
|
||||||
uid: "gtrtyutyhretgytu",
|
|
||||||
folder_number: "00002",
|
|
||||||
name: "Mon dossier",
|
|
||||||
status: EFolderStatus.LIVE,
|
|
||||||
deed: deed,
|
|
||||||
office: office,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
description: "Description",
|
|
||||||
archived_description: "Archived description",
|
|
||||||
documents: [documentDeposited],
|
|
||||||
};
|
|
||||||
export const folderWithPendingDocument2: OfficeFolder = {
|
|
||||||
uid: "adzefzefsfrefzrtgtr",
|
|
||||||
folder_number: "00003",
|
|
||||||
name: "Mon dossier",
|
|
||||||
status: EFolderStatus.LIVE,
|
|
||||||
deed: deed,
|
|
||||||
office: office,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
description: "Description",
|
|
||||||
archived_description: "Archived description",
|
|
||||||
documents: [document],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const officeFolderHasCustomer1: OfficeFolderHasCustomer = {
|
|
||||||
uid: "ferzfergrzeyerezrz",
|
|
||||||
customer: customer,
|
|
||||||
office_folder: folderWithPendingDocument,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const officeFolderHasCustomer2: OfficeFolderHasCustomer = {
|
|
||||||
uid: "tezrfzdfgrggeerry",
|
|
||||||
customer: customer2,
|
|
||||||
office_folder: folderWithPendingDocument,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const folderWithPendingDocument3: OfficeFolder = {
|
|
||||||
uid: "mkovrijvrezviev",
|
|
||||||
folder_number: "00014",
|
|
||||||
name: "Mon dossier",
|
|
||||||
status: EFolderStatus.LIVE,
|
|
||||||
deed: deed,
|
|
||||||
office: office,
|
|
||||||
created_at: new Date(),
|
|
||||||
updated_at: new Date(),
|
|
||||||
description: "Description",
|
|
||||||
archived_description: "Archived description",
|
|
||||||
documents: [document, documentDeposited, documentPending, documentIdentity],
|
|
||||||
office_folder_has_customers: [officeFolderHasCustomer1, officeFolderHasCustomer2],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const document8: Document = {
|
|
||||||
uid: "eztreggrgbyunjukhg",
|
|
||||||
depositor: customer,
|
|
||||||
document_status: "ASKED",
|
|
||||||
folder: folderWithPendingDocument,
|
|
||||||
document_type: docType,
|
|
||||||
updated_at: new Date(),
|
|
||||||
created_at: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const folderWithPendingDocumentArchived1: OfficeFolder = {
|
|
||||||
uid: "gtrtyutyhrdazafad&éfytu",
|
|
||||||
folder_number: "00007",
|
|
||||||
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: [documentDeposited],
|
|
||||||
office_folder_has_customers: [officeFolderHasCustomer1, officeFolderHasCustomer2],
|
|
||||||
};
|
|
||||||
export const folderWithPendingDocumentArchived2: OfficeFolder = {
|
|
||||||
uid: "adzefdazdaazzrtgtr",
|
|
||||||
folder_number: "00008",
|
|
||||||
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: [document],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const document2: Document = {
|
|
||||||
uid: "mejfihruehfoire",
|
|
||||||
depositor: customer,
|
|
||||||
document_status: "ASKED",
|
|
||||||
folder: folderWithPendingDocument3,
|
|
||||||
document_type: docType,
|
|
||||||
updated_at: new Date(),
|
|
||||||
created_at: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const folders: OfficeFolder[] = [
|
|
||||||
folderWithPendingDocument,
|
|
||||||
folderWithPendingDocument1,
|
|
||||||
folderWithPendingDocument2,
|
|
||||||
folderWithPendingDocument3,
|
|
||||||
];
|
|
||||||
|
|
||||||
export const foldersArchived: OfficeFolder[] = [folderWithPendingDocumentArchived1, folderWithPendingDocumentArchived2];
|
|
@ -1,319 +0,0 @@
|
|||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
|
||||||
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
|
|
||||||
import DocumentNotary from "@Front/Components/DesignSystem/Document/DocumentNotary";
|
|
||||||
import FilePreview from "@Front/Components/DesignSystem/FilePreview";
|
|
||||||
import FolderContainer from "@Front/Components/DesignSystem/FolderContainer";
|
|
||||||
import FolderList from "@Front/Components/DesignSystem/FolderListContainer";
|
|
||||||
import HeaderLink from "@Front/Components/DesignSystem/Header/HeaderLink";
|
|
||||||
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
|
||||||
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
|
|
||||||
import QuantityProgressBar from "@Front/Components/DesignSystem/QuantityProgressBar";
|
|
||||||
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
|
|
||||||
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
|
||||||
import ToolTip from "@Front/Components/DesignSystem/ToolTip";
|
|
||||||
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
|
||||||
import UserFolder from "@Front/Components/DesignSystem/UserFolder";
|
|
||||||
import BasePage from "@Front/Components/Layouts/Base";
|
|
||||||
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
|
||||||
import Toasts, { IToast } from "@Front/Stores/Toasts";
|
|
||||||
|
|
||||||
import classes from "./classes.module.scss";
|
|
||||||
import { customer2, document, documentDeposited, documentPending, folder, folders, folderWithPendingDocument } from "./dummyData";
|
|
||||||
import { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
|
|
||||||
import SelectField, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
|
||||||
import TextField from "@Front/Components/DesignSystem/Form/TextField";
|
|
||||||
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
|
|
||||||
|
|
||||||
type IState = {
|
|
||||||
isModalDisplayed: boolean;
|
|
||||||
selectedOption?: IOption;
|
|
||||||
};
|
|
||||||
type IProps = {};
|
|
||||||
|
|
||||||
export default class DesignSystem extends BasePage<IProps, IState> {
|
|
||||||
constructor(props: IProps) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
isModalDisplayed: false,
|
|
||||||
};
|
|
||||||
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>
|
|
||||||
</div>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.P_18}>
|
|
||||||
This page allows to gather all the design system of the site. A Design System is a library of components,
|
|
||||||
visuals and principles with reusable code. This evolving kit offers a UX and UI repository for designers and
|
|
||||||
developers of digital products and services. The construction of a design system offers many advantages.
|
|
||||||
This solution facilitates the work of the teams and reduces the "design debt" and the "technical debt". The
|
|
||||||
result is a coherent ecosystem and therefore a better experience for users and customers.
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>Button components</Typography>
|
|
||||||
</div>
|
|
||||||
<Button variant={EButtonVariant.PRIMARY}>Primary</Button>
|
|
||||||
<Button variant={EButtonVariant.SECONDARY}>Secondary</Button>
|
|
||||||
<Button variant={EButtonVariant.GHOST}>Ghost</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>Toaster component</Typography>
|
|
||||||
</div>
|
|
||||||
<Button variant={EButtonVariant.PRIMARY} onClick={this.spawnToast}>
|
|
||||||
Spawn a toast
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>Modal components</Typography>
|
|
||||||
</div>
|
|
||||||
<Button variant={EButtonVariant.PRIMARY} onClick={this.openModal}>
|
|
||||||
Show Modal
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Confirm
|
|
||||||
isOpen={this.state.isModalDisplayed}
|
|
||||||
onClose={this.closeModal}
|
|
||||||
closeBtn
|
|
||||||
header={"Title"}
|
|
||||||
cancelText={"Cancel"}
|
|
||||||
confirmText={"Confirmer"}>
|
|
||||||
Lorem ipsum dolor sit amet consectetur. Aliquam nunc lobortis lacus vulputate sagittis sed tempor eget feugiat.
|
|
||||||
Elementum malesuada at sit elit.
|
|
||||||
</Confirm>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>HeaderLink components</Typography>
|
|
||||||
</div>
|
|
||||||
<div className={classes["inline-flex"]}>
|
|
||||||
<HeaderLink text={"Home"} path={"/"} />
|
|
||||||
<HeaderLink text={"Design-system"} path={"/design-system"} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>CheckBox component</Typography>
|
|
||||||
</div>
|
|
||||||
<CheckBox
|
|
||||||
toolTip="Mon super tooltip"
|
|
||||||
option={{
|
|
||||||
label: "Check Box 1",
|
|
||||||
value: "box_1",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<CheckBox
|
|
||||||
option={{
|
|
||||||
label: "Check Box 2",
|
|
||||||
value: "box_2",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>RadioBox component</Typography>
|
|
||||||
</div>
|
|
||||||
<RadioBox name="RadioBox" toolTip="Radiobox with tooltip" value="box_1">
|
|
||||||
Radio Box 1
|
|
||||||
</RadioBox>
|
|
||||||
<RadioBox name="RadioBox" value="box_2">
|
|
||||||
Radio Box 2
|
|
||||||
</RadioBox>
|
|
||||||
</div>
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>Tool tip component</Typography>
|
|
||||||
</div>
|
|
||||||
<ToolTip title="toolTip" text="tooltip content" isNotFlex={true} />
|
|
||||||
</div>
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>Input component</Typography>
|
|
||||||
</div>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<TextField name="input field" placeholder="input place hodler" />
|
|
||||||
</div>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<TextAreaField name="input field" placeholder="text area place hodler" />
|
|
||||||
</div>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<TextField name="input field" placeholder="number place hodler" />
|
|
||||||
</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 as IDashBoardFolder} />
|
|
||||||
</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 as IDashBoardFolder} />
|
|
||||||
</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"]}>
|
|
||||||
<SelectField
|
|
||||||
name="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} folderUid="" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.P_16}>Documents Depoited</Typography>
|
|
||||||
<div className={classes["folder-conatainer"]}>
|
|
||||||
<DocumentNotary document={documentPending} folderUid="" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.P_16}>Documents VALIDATED</Typography>
|
|
||||||
|
|
||||||
<div className={classes["folder-conatainer"]}>
|
|
||||||
<DocumentNotary document={documentDeposited} folderUid="" />
|
|
||||||
</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}
|
|
||||||
folder={folder as IDashBoardFolder}
|
|
||||||
isOpened={true}
|
|
||||||
onChange={() => {
|
|
||||||
return;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>MultiSelect</Typography>
|
|
||||||
</div>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<MultiSelect options={selectOptions} placeholder="Numéro CRPCEN" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>Document SearchBar</Typography>
|
|
||||||
</div>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<SearchBar folders={folders as IDashBoardFolder[]} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>Folder List</Typography>
|
|
||||||
</div>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<FolderList folders={folders as IDashBoardFolder[]} isArchived={false} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={classes["section"]}>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<Typography typo={ITypo.H3}>Preview Image/Pdf</Typography>
|
|
||||||
</div>
|
|
||||||
<div className={classes["sub-section"]}>
|
|
||||||
<div style={{ height: "500px" }}>
|
|
||||||
<FilePreview href="https://minteed-stg-euwest3-s3.s3.eu-west-3.amazonaws.com/Qmf_Yb_Eh_X9st_F_Srq_Ve_Bj_Yb_Aj56xv_AV_Nj6_Wjypo_B4r5ubce_U_ae3303e7ab.pdf" />
|
|
||||||
</div>
|
|
||||||
<FilePreview href="https://minteed-stg-euwest3-s3.s3.eu-west-3.amazonaws.com/Qmf_Vgs_Vr_Mt_TDY_Xme8qhw8quiin_Co_Bo_FBA_Vc9k6_H2d1_Bh_UU_162d84281d.jpeg" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</DefaultTemplate>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
private openModal() {
|
|
||||||
this.setState({
|
|
||||||
isModalDisplayed: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
private closeModal() {
|
|
||||||
this.setState({
|
|
||||||
isModalDisplayed: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
private spawnToast() {
|
|
||||||
const toast: IToast = {
|
|
||||||
title: "Un collaborateur veut rejoindre votre office",
|
|
||||||
text: "12:00 - 1 fev 2023",
|
|
||||||
};
|
|
||||||
Toasts.getInstance().open(toast);
|
|
||||||
}
|
|
||||||
|
|
||||||
private onSelectedOption(option: IOption) {
|
|
||||||
this.setState({
|
|
||||||
selectedOption: option,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
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 Module from "@Front/Config/Module";
|
||||||
|
import JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
|
import { validateOrReject, ValidationError } from "class-validator";
|
||||||
|
import { DocumentType, Office } from "le-coffre-resources/dist/Admin";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useCallback, useState } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {};
|
||||||
|
export default function DocumentTypesCreate(props: IProps) {
|
||||||
|
const [validationError, setValidationError] = useState<ValidationError[]>([]);
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const onSubmitHandler = useCallback(
|
||||||
|
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
||||||
|
try {
|
||||||
|
const jwt = JwtService.getInstance().decodeJwt();
|
||||||
|
if (!jwt) return;
|
||||||
|
const documentToCreate = DocumentType.hydrate<DocumentType>({
|
||||||
|
...values,
|
||||||
|
office: Office.hydrate<Office>({
|
||||||
|
uid: jwt.office_Id,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
await validateOrReject(documentToCreate, { groups: ["createDocumentType"] });
|
||||||
|
const documentTypeCreated = await DocumentTypes.getInstance().post(documentToCreate);
|
||||||
|
|
||||||
|
router.push(
|
||||||
|
Module.getInstance().get().modules.pages.DocumentTypes.pages.Edit.props.path.replace("[uid]", documentTypeCreated.uid!),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof Array) {
|
||||||
|
setValidationError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[router],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultDocumentTypesDashboard 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 nouveau document</Typography>
|
||||||
|
</div>
|
||||||
|
<Form onSubmit={onSubmitHandler} className={classes["form-container"]}>
|
||||||
|
<TextField
|
||||||
|
name="name"
|
||||||
|
placeholder="Nom du document"
|
||||||
|
validationError={validationError.find((error) => error.property === "name")}
|
||||||
|
/>
|
||||||
|
<TextAreaField
|
||||||
|
name="private_description"
|
||||||
|
placeholder="Description visible par les collaborateurs de l'office"
|
||||||
|
validationError={validationError.find((error) => error.property === "private_description")}
|
||||||
|
/>
|
||||||
|
<TextAreaField
|
||||||
|
name="public_description"
|
||||||
|
placeholder="Description visible par les clients de l'office"
|
||||||
|
validationError={validationError.find((error) => error.property === "public_description")}
|
||||||
|
/>
|
||||||
|
<div className={classes["buttons-container"]}>
|
||||||
|
<Button variant={EButtonVariant.GHOST}>Annuler</Button>
|
||||||
|
<Button type="submit">Créer le document</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</DefaultDocumentTypesDashboard>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
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 { validateOrReject } from "class-validator";
|
||||||
|
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, {
|
||||||
|
_count: true,
|
||||||
|
});
|
||||||
|
setDocumentTypeSelected(documentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDocumentType();
|
||||||
|
}, [documentTypeUid]);
|
||||||
|
|
||||||
|
const onSubmitHandler = useCallback(
|
||||||
|
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
||||||
|
try {
|
||||||
|
const documentToUpdate = DocumentType.hydrate<DocumentType>({
|
||||||
|
...values,
|
||||||
|
uid: documentTypeUid as string,
|
||||||
|
});
|
||||||
|
await validateOrReject(documentToUpdate, { groups: ["updateDocumentType"] });
|
||||||
|
const documentTypeUpdated = await DocumentTypes.getInstance().put(documentTypeUid as string, documentToUpdate);
|
||||||
|
console.log(documentTypeUpdated);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[documentTypeUid],
|
||||||
|
);
|
||||||
|
|
||||||
|
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 l’office"
|
||||||
|
defaultValue={documentTypeSelected?.public_description}
|
||||||
|
/>
|
||||||
|
<div className={classes["buttons-container"]}>
|
||||||
|
<Button variant={EButtonVariant.GHOST}>Annuler</Button>
|
||||||
|
<Button type="submit">Enregistrer</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</DefaultDocumentTypesDashboard>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/front/Components/Layouts/DocumentTypes/index.tsx
Normal file
26
src/front/Components/Layouts/DocumentTypes/index.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -2,21 +2,21 @@ import Customers from "@Front/Api/LeCoffreApi/SuperAdmin/Customers/Customers";
|
|||||||
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import Form from "@Front/Components/DesignSystem/Form";
|
import Form from "@Front/Components/DesignSystem/Form";
|
||||||
|
import { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
||||||
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
|
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
|
||||||
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
|
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
|
||||||
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
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, OfficeFolderHasCustomer } 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";
|
||||||
import { NextRouter, useRouter } from "next/router";
|
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 { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
|
||||||
import { TextField } from "@mui/material";
|
|
||||||
|
|
||||||
enum ESelectedOption {
|
enum ESelectedOption {
|
||||||
EXISTING_CUSTOMER = "existing_customer",
|
EXISTING_CUSTOMER = "existing_customer",
|
||||||
@ -108,10 +108,7 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
<TextField name="last_name" placeholder="Nom" />
|
<TextField name="last_name" placeholder="Nom" />
|
||||||
<TextField name="first_name" placeholder="Prénom" />
|
<TextField name="first_name" placeholder="Prénom" />
|
||||||
<TextField name="email" placeholder="E-mail" />
|
<TextField name="email" placeholder="E-mail" />
|
||||||
<TextField
|
<TextField name="cell_phone_number" placeholder="Numéro de téléphone" />
|
||||||
name="cell_phone_number"
|
|
||||||
placeholder="Numéro de téléphone"
|
|
||||||
/>
|
|
||||||
<div className={classes["button-container"]}>
|
<div className={classes["button-container"]}>
|
||||||
<Link href={backwardPath} className={classes["cancel-button"]}>
|
<Link href={backwardPath} className={classes["cancel-button"]}>
|
||||||
<Button variant={EButtonVariant.GHOST}>Annuler</Button>
|
<Button variant={EButtonVariant.GHOST}>Annuler</Button>
|
||||||
@ -150,13 +147,9 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
private async getFolderPreSelectedCustomers(folderUid: string): Promise<IOption[] | undefined> {
|
private async getFolderPreSelectedCustomers(folderUid: string): Promise<IOption[] | undefined> {
|
||||||
const query = {
|
const query = {
|
||||||
q: {
|
q: {
|
||||||
office_folder_has_customers: {
|
customers: {
|
||||||
include: {
|
include: {
|
||||||
customer: {
|
contact: true,
|
||||||
include: {
|
|
||||||
contact: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -164,10 +157,10 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
let preExistingCustomers: IOption[] = [];
|
let preExistingCustomers: IOption[] = [];
|
||||||
try {
|
try {
|
||||||
const folder = await Folders.getInstance().getByUid(folderUid, query);
|
const folder = await Folders.getInstance().getByUid(folderUid, query);
|
||||||
preExistingCustomers = folder.office_folder_has_customers!.map((folderHasCustomer) => {
|
preExistingCustomers = folder.customers!.map((customer) => {
|
||||||
return {
|
return {
|
||||||
label: folderHasCustomer.customer.contact?.first_name + " " + folderHasCustomer.customer.contact?.last_name,
|
label: customer.contact?.first_name + " " + customer.contact?.last_name,
|
||||||
value: folderHasCustomer.customer.uid,
|
value: customer.uid,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -209,24 +202,26 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
values["civility"] = ECivility.MALE; // TODO: should maybe be deleted later or added to the form
|
values["civility"] = ECivility.MALE; // TODO: should maybe be deleted later or added to the form
|
||||||
|
|
||||||
const allCustomersToLink = this.state.selectedCustomers.concat(this.state.existingCustomers);
|
const allCustomersToLink = this.state.selectedCustomers.concat(this.state.existingCustomers);
|
||||||
let customersToLink: Partial<OfficeFolderHasCustomer>[] = allCustomersToLink.map((customer) => {
|
let customersToLink: Partial<Customer>[] = allCustomersToLink.map((customer) => {
|
||||||
return {
|
return {
|
||||||
customer: { uid: customer.value },
|
customer: { uid: customer.value },
|
||||||
};
|
};
|
||||||
}) as Partial<OfficeFolderHasCustomer>[];
|
}) as Partial<Customer>[];
|
||||||
|
|
||||||
if (this.state.selectedOption === "new_customer") {
|
if (this.state.selectedOption === "new_customer") {
|
||||||
const customer: Customer = await Customers.getInstance().post({
|
const customer: Customer = await Customers.getInstance().post({
|
||||||
contact: values,
|
contact: values,
|
||||||
});
|
});
|
||||||
if (!customer.uid) return;
|
if (!customer.uid) return;
|
||||||
customersToLink?.push({ customer: { uid: customer.uid } } as Partial<OfficeFolderHasCustomer>);
|
customersToLink?.push({ customer: { uid: customer.uid } } as Partial<Customer>);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (customersToLink) {
|
if (customersToLink) {
|
||||||
const body = OfficeFolder.hydrate<OfficeFolder>({ office_folder_has_customers: customersToLink.map((customer) => {
|
const body = OfficeFolder.hydrate<OfficeFolder>({
|
||||||
return OfficeFolderHasCustomer.hydrate<OfficeFolderHasCustomer>(customer);
|
customers: customersToLink.map((customer) => {
|
||||||
}) });
|
return Customer.hydrate<Customer>(customer);
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
await Folders.getInstance().put(this.props.selectedFolderUid, body);
|
await Folders.getInstance().put(this.props.selectedFolderUid, body);
|
||||||
this.props.router.push(`/folders/${this.props.selectedFolderUid}`);
|
this.props.router.push(`/folders/${this.props.selectedFolderUid}`);
|
||||||
|
@ -169,8 +169,8 @@ class AskDocumentsClass extends BasePage<IPropsClass, IState> {
|
|||||||
.map((document) => {
|
.map((document) => {
|
||||||
return document.document_type!.uid!;
|
return document.document_type!.uid!;
|
||||||
});
|
});
|
||||||
const documentTypes = folder.deed!.deed_has_document_types!.filter((documentType) => {
|
const documentTypes = folder.deed!.document_types!.filter((documentType) => {
|
||||||
if (userDocumentTypesUids.includes(documentType.document_type!.uid!)) return false;
|
if (userDocumentTypesUids.includes(documentType!.uid!)) return false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -182,9 +182,9 @@ class AskDocumentsClass extends BasePage<IPropsClass, IState> {
|
|||||||
})
|
})
|
||||||
.map((documentType) => {
|
.map((documentType) => {
|
||||||
return {
|
return {
|
||||||
label: documentType.document_type!.name!,
|
label: documentType!.name!,
|
||||||
value: documentType.document_type!.uid!,
|
value: documentType!.uid!,
|
||||||
description: documentType.document_type!.private_description!,
|
description: documentType!.private_description!,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -209,13 +209,11 @@ class AskDocumentsClass extends BasePage<IPropsClass, IState> {
|
|||||||
public_description: this.state.visibleDescription,
|
public_description: this.state.visibleDescription,
|
||||||
});
|
});
|
||||||
|
|
||||||
const oldDocumentsType = this.state.folder?.deed?.deed_has_document_types!;
|
const oldDocumentsType = this.state.folder?.deed?.document_types!;
|
||||||
await Deeds.getInstance().put(this.state.folder?.deed?.uid!, {
|
await Deeds.getInstance().put(this.state.folder?.deed?.uid!, {
|
||||||
deed_has_document_types: [
|
document_types: [
|
||||||
...oldDocumentsType,
|
...oldDocumentsType,
|
||||||
{
|
documentType,
|
||||||
document_type: documentType,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Ty
|
|||||||
import BackArrow from "@Front/Components/Elements/BackArrow";
|
import BackArrow from "@Front/Components/Elements/BackArrow";
|
||||||
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
|
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
|
||||||
import { ValidationError } from "class-validator";
|
import { ValidationError } from "class-validator";
|
||||||
import { Deed, DeedType, Office, OfficeFolder, OfficeFolderHasStakeholder } from "le-coffre-resources/dist/Notary";
|
import { Deed, DeedType, Office, OfficeFolder } from "le-coffre-resources/dist/Notary";
|
||||||
import User from "le-coffre-resources/dist/Notary";
|
import User from "le-coffre-resources/dist/Notary";
|
||||||
import { NextRouter, useRouter } from "next/router";
|
import { NextRouter, useRouter } from "next/router";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
@ -21,6 +21,7 @@ import { ActionMeta, MultiValue } from "react-select";
|
|||||||
|
|
||||||
import BasePage from "../../Base";
|
import BasePage from "../../Base";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
|
|
||||||
type IFormValues = {
|
type IFormValues = {
|
||||||
folder_number: string;
|
folder_number: string;
|
||||||
@ -150,7 +151,7 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override async componentDidMount() {
|
public override async componentDidMount() {
|
||||||
const deedTypes = await DeedTypes.getInstance().get({ q: {} });
|
const deedTypes = await DeedTypes.getInstance().get();
|
||||||
|
|
||||||
// TODO SETUP userStore and get the user's office membership -> Replace IwJ70M471c by the user's office membership uid
|
// TODO SETUP userStore and get the user's office membership -> Replace IwJ70M471c by the user's office membership uid
|
||||||
const usersMock = await Users.getInstance().get({ include: { office_membership: true } });
|
const usersMock = await Users.getInstance().get({ include: { office_membership: true } });
|
||||||
@ -233,23 +234,19 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
const officeId = JwtService.getInstance().decodeJwt()?.office_Id;
|
||||||
const selectedDeedTypeUid: DeedType | undefined = this.state.deedTypes.find(
|
const selectedDeedTypeUid: DeedType | undefined = this.state.deedTypes.find(
|
||||||
(deedType) => deedType.uid === this.state.formValues.act_typ?.value,
|
(deedType) => deedType.uid === this.state.formValues.act_typ?.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
let stakeholders = this.state.collaborators;
|
||||||
* MOCK DATA
|
if (this.state.folder_access === "select_collaborators") {
|
||||||
*/
|
stakeholders = this.state.collaborators.filter((collaborator) => {
|
||||||
const usersMock = await Users.getInstance().get({ include: { office_membership: true } });
|
return this.state.formValues.collaborators?.some((selectedCollaborator) => {
|
||||||
const userMock = usersMock[0];
|
return selectedCollaborator.value === collaborator.uid;
|
||||||
|
});
|
||||||
let stakeholders = this.getStakeholders();
|
});
|
||||||
let testUsers = stakeholders.map((stakeholder) => ({
|
}
|
||||||
user_stakeholder: {
|
|
||||||
uid: stakeholder.user_stakeholder.uid,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const officeFolderForm = OfficeFolder.hydrate<OfficeFolder>({
|
const officeFolderForm = OfficeFolder.hydrate<OfficeFolder>({
|
||||||
folder_number: values["folder_number"],
|
folder_number: values["folder_number"],
|
||||||
name: values["name"],
|
name: values["name"],
|
||||||
@ -260,15 +257,10 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
office: Office.hydrate<Office>({
|
office: Office.hydrate<Office>({
|
||||||
uid: userMock?.office_membership?.uid,
|
uid: officeId,
|
||||||
}),
|
|
||||||
office_folder_has_stakeholder: testUsers.map((user) => {
|
|
||||||
return OfficeFolderHasStakeholder.hydrate<OfficeFolderHasStakeholder>({
|
|
||||||
user_stakeholder: User.hydrate<User>({
|
|
||||||
uid: user.user_stakeholder.uid,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}),
|
}),
|
||||||
|
customers: [],
|
||||||
|
stakeholders,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -285,6 +277,7 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
if (!newOfficeFolder) return;
|
if (!newOfficeFolder) return;
|
||||||
this.props.router.push(`/folders/${newOfficeFolder.uid}`);
|
this.props.router.push(`/folders/${newOfficeFolder.uid}`);
|
||||||
} catch (backError: any) {
|
} catch (backError: any) {
|
||||||
|
if (!Array.isArray(backError)) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
validationError: backError as ValidationError[],
|
validationError: backError as ValidationError[],
|
||||||
});
|
});
|
||||||
@ -313,25 +306,6 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
folder_access: e.target.value,
|
folder_access: e.target.value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getStakeholders() {
|
|
||||||
let collaborators: User[] = this.state.collaborators;
|
|
||||||
|
|
||||||
let office_folder_has_stakeholders = collaborators.map((collaborator) => {
|
|
||||||
return OfficeFolderHasStakeholder.hydrate<OfficeFolderHasStakeholder>({
|
|
||||||
user_stakeholder: collaborator,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.state.folder_access === "select_collaborators") {
|
|
||||||
office_folder_has_stakeholders = office_folder_has_stakeholders.filter((collaborator) => {
|
|
||||||
return this.state.formValues.collaborators?.some((selectedCollaborator) => {
|
|
||||||
return selectedCollaborator.value === collaborator.user_stakeholder.uid;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return office_folder_has_stakeholders;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CreateFolder(props: IProps): JSX.Element {
|
export default function CreateFolder(props: IProps): JSX.Element {
|
||||||
|
@ -60,14 +60,14 @@ export default class ClientSection extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private renderCustomerFolders() {
|
private renderCustomerFolders() {
|
||||||
const output = this.props.folder.office_folder_has_customers?.map((folderHasCustomer) => {
|
const output = this.props.folder.customers?.map((customer) => {
|
||||||
if (!folderHasCustomer.customer) return null;
|
if (!customer) return null;
|
||||||
return (
|
return (
|
||||||
<UserFolder
|
<UserFolder
|
||||||
folder={this.props.folder}
|
folder={this.props.folder}
|
||||||
customer={folderHasCustomer.customer}
|
customer={customer}
|
||||||
key={folderHasCustomer.customer.uid}
|
key={customer.uid}
|
||||||
isOpened={this.state.openedCustomer === folderHasCustomer.customer.uid}
|
isOpened={this.state.openedCustomer === customer.uid}
|
||||||
onChange={this.changeUserFolder}
|
onChange={this.changeUserFolder}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -83,7 +83,7 @@ export default class ClientSection extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private doesFolderHaveCustomer(): boolean {
|
private doesFolderHaveCustomer(): boolean {
|
||||||
if (!this.props.folder?.office_folder_has_customers) return false;
|
if (!this.props.folder?.customers) return false;
|
||||||
return this.props.folder?.office_folder_has_customers!.length > 0;
|
return this.props.folder?.customers!.length > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import ChevronIcon from "@Assets/Icons/chevron.svg";
|
|||||||
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import FolderBoxInformation, { EFolderBoxInformationType } from "@Front/Components/DesignSystem/FolderBoxInformation";
|
import FolderBoxInformation, { EFolderBoxInformationType } from "@Front/Components/DesignSystem/FolderBoxInformation";
|
||||||
|
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
|
||||||
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
||||||
import QuantityProgressBar from "@Front/Components/DesignSystem/QuantityProgressBar";
|
import QuantityProgressBar from "@Front/Components/DesignSystem/QuantityProgressBar";
|
||||||
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
@ -16,7 +17,6 @@ import { ChangeEvent } from "react";
|
|||||||
import BasePage from "../../Base";
|
import BasePage from "../../Base";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import ClientSection from "./ClientSection";
|
import ClientSection from "./ClientSection";
|
||||||
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
|
|
||||||
|
|
||||||
type IProps = {};
|
type IProps = {};
|
||||||
|
|
||||||
@ -155,8 +155,8 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private doesFolderHaveCustomer(): boolean {
|
private doesFolderHaveCustomer(): boolean {
|
||||||
if (!this.state.selectedFolder?.office_folder_has_customers) return false;
|
if (!this.state.selectedFolder?.customers) return false;
|
||||||
return this.state.selectedFolder?.office_folder_has_customers!.length > 0;
|
return this.state.selectedFolder?.customers!.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onSelectedFolder(folder: IDashBoardFolder): void {
|
private onSelectedFolder(folder: IDashBoardFolder): void {
|
||||||
@ -189,18 +189,14 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
|
|||||||
q: {
|
q: {
|
||||||
deed: { include: { deed_type: true } },
|
deed: { include: { deed_type: true } },
|
||||||
office: true,
|
office: true,
|
||||||
office_folder_has_customers: {
|
customers: {
|
||||||
include: {
|
include: {
|
||||||
customer: {
|
contact: true,
|
||||||
|
documents: {
|
||||||
include: {
|
include: {
|
||||||
contact: true,
|
folder: true,
|
||||||
documents: {
|
document_type: true,
|
||||||
include: {
|
files: true,
|
||||||
folder: true,
|
|
||||||
document_type: true,
|
|
||||||
files: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
|
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
||||||
|
import Users, { IGetUsersparams } from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import Form from "@Front/Components/DesignSystem/Form";
|
import Form from "@Front/Components/DesignSystem/Form";
|
||||||
|
import { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
||||||
|
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
|
||||||
|
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
|
||||||
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
||||||
import BackArrow from "@Front/Components/Elements/BackArrow";
|
import BackArrow from "@Front/Components/Elements/BackArrow";
|
||||||
import DefaultNotaryDashboard, { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
|
import DefaultNotaryDashboard, { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
|
||||||
import BasePage from "../../Base";
|
import Module from "@Front/Config/Module";
|
||||||
import classes from "./classes.module.scss";
|
import User from "le-coffre-resources/dist/Notary";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { NextRouter, useRouter } from "next/router";
|
import { NextRouter, useRouter } from "next/router";
|
||||||
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
|
|
||||||
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
|
import BasePage from "../../Base";
|
||||||
import Module from "@Front/Config/Module";
|
import classes from "./classes.module.scss";
|
||||||
import Users, { IGetUsersparams } from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
|
|
||||||
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
|
||||||
import { OfficeFolderHasStakeholder } from "le-coffre-resources/dist/Customer";
|
|
||||||
import { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
|
||||||
import User from "le-coffre-resources/dist/Notary";
|
|
||||||
|
|
||||||
type IPropsClass = {
|
type IPropsClass = {
|
||||||
selectedFolderUid: string;
|
selectedFolderUid: string;
|
||||||
@ -104,13 +104,9 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
|
|||||||
const query = {
|
const query = {
|
||||||
q: {
|
q: {
|
||||||
office: true,
|
office: true,
|
||||||
office_folder_has_stakeholder: {
|
stakeholders: {
|
||||||
include: {
|
include: {
|
||||||
user_stakeholder: {
|
contact: true,
|
||||||
include: {
|
|
||||||
contact: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -119,10 +115,10 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
|
|||||||
let folder = null;
|
let folder = null;
|
||||||
try {
|
try {
|
||||||
folder = await Folders.getInstance().getByUid(folderUid, query);
|
folder = await Folders.getInstance().getByUid(folderUid, query);
|
||||||
const preSelectedCollaborators: IOption[] = folder.office_folder_has_stakeholder!.map((collaborator) => {
|
const preSelectedCollaborators: IOption[] = folder.stakeholders!.map((collaborator) => {
|
||||||
return {
|
return {
|
||||||
label: collaborator.user_stakeholder.contact?.first_name + " " + collaborator.user_stakeholder.contact?.last_name,
|
label: collaborator.contact?.first_name + " " + collaborator.contact?.last_name,
|
||||||
value: collaborator.user_stakeholder.uid,
|
value: collaborator.uid,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
this.setState({ selectedCollaborators: preSelectedCollaborators });
|
this.setState({ selectedCollaborators: preSelectedCollaborators });
|
||||||
@ -173,17 +169,13 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
|
|||||||
|
|
||||||
private async onFormSubmit(e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) {
|
private async onFormSubmit(e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) {
|
||||||
try {
|
try {
|
||||||
let collaboratorsUid: OfficeFolderHasStakeholder[];
|
let collaboratorsUid: User[] = this.state.availableCollaborators;
|
||||||
if (this.state.selectedOption === ERadioBoxValue.SELECTION) {
|
if (this.state.selectedOption === ERadioBoxValue.SELECTION) {
|
||||||
collaboratorsUid = this.state.selectedCollaborators.map(
|
collaboratorsUid = this.state.selectedCollaborators.map((collaborator) =>
|
||||||
(collaborator) => ({ user_stakeholder: { uid: collaborator.value } } as OfficeFolderHasStakeholder),
|
User.hydrate<User>({ uid: collaborator.value as string }),
|
||||||
);
|
|
||||||
} else {
|
|
||||||
collaboratorsUid = this.state.availableCollaborators.map(
|
|
||||||
(collaborator) => ({ user_stakeholder: { uid: collaborator.uid } } as OfficeFolderHasStakeholder),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
await Folders.getInstance().put(this.props.selectedFolderUid, { office_folder_has_stakeholder: collaboratorsUid });
|
await Folders.getInstance().put(this.props.selectedFolderUid, { stakeholders: collaboratorsUid });
|
||||||
this.props.router.push(
|
this.props.router.push(
|
||||||
Module.getInstance()
|
Module.getInstance()
|
||||||
.get()
|
.get()
|
||||||
|
@ -12,6 +12,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 { Deed, OfficeFolder } from "le-coffre-resources/dist/Notary";
|
||||||
|
|
||||||
type IProps = {};
|
type IProps = {};
|
||||||
|
|
||||||
@ -88,7 +89,14 @@ class UpdateFolderMetadataClass extends BasePage<IPropsClass, IState> {
|
|||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
await Folders.getInstance().put(this.props.folderUid, values);
|
const newValues = OfficeFolder.hydrate<OfficeFolder>({
|
||||||
|
...values,
|
||||||
|
deed: Deed.hydrate<Deed>({
|
||||||
|
uid: values["deed"],
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
await Folders.getInstance().put(this.props.folderUid, newValues);
|
||||||
const url = Module.getInstance()
|
const url = Module.getInstance()
|
||||||
.get()
|
.get()
|
||||||
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.folderUid);
|
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.folderUid);
|
||||||
@ -103,7 +111,7 @@ class UpdateFolderMetadataClass extends BasePage<IPropsClass, IState> {
|
|||||||
q: {
|
q: {
|
||||||
deed: { include: { deed_type: true } },
|
deed: { include: { deed_type: true } },
|
||||||
office: true,
|
office: true,
|
||||||
office_folder_has_customers: { include: { customer: { include: { contact: true } } } },
|
customers: { include: { contact: true } },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const folder = await Folders.getInstance().getByUid(this.props.folderUid, query);
|
const folder = await Folders.getInstance().getByUid(this.props.folderUid, query);
|
||||||
|
@ -40,14 +40,14 @@ export default class ClientSection extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private renderCustomerFolders() {
|
private renderCustomerFolders() {
|
||||||
const output = this.props.folder.office_folder_has_customers?.map((folderHasCustomer) => {
|
const output = this.props.folder.customers?.map((customer) => {
|
||||||
if (!folderHasCustomer.customer) return null;
|
if (!customer) return null;
|
||||||
return (
|
return (
|
||||||
<UserFolder
|
<UserFolder
|
||||||
folder={this.props.folder}
|
folder={this.props.folder}
|
||||||
customer={folderHasCustomer.customer}
|
customer={customer}
|
||||||
key={folderHasCustomer.customer.uid}
|
key={customer.uid}
|
||||||
isOpened={this.state.openedCustomer === folderHasCustomer.customer.uid}
|
isOpened={this.state.openedCustomer === customer.uid}
|
||||||
onChange={this.changeUserFolder}
|
onChange={this.changeUserFolder}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -62,7 +62,7 @@ export default class ClientSection extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private doesFolderHaveCustomer(): boolean {
|
private doesFolderHaveCustomer(): boolean {
|
||||||
if (!this.props.folder?.office_folder_has_customers) return false;
|
if (!this.props.folder?.customers) return false;
|
||||||
return this.props.folder?.office_folder_has_customers!.length > 0;
|
return this.props.folder?.customers!.length > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private doesFolderHaveCustomer(): boolean {
|
private doesFolderHaveCustomer(): boolean {
|
||||||
return this.state.selectedFolder?.office_folder_has_customers !== undefined;
|
return this.state.selectedFolder?.customers !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onSelectedFolder(folder: IDashBoardFolder): void {
|
private onSelectedFolder(folder: IDashBoardFolder): void {
|
||||||
@ -140,7 +140,7 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
|
|||||||
q: {
|
q: {
|
||||||
deed: { include: { deed_type: "true" } },
|
deed: { include: { deed_type: "true" } },
|
||||||
office: "true",
|
office: "true",
|
||||||
office_folder_has_customers: { include: { customer: { include: { contact: true } } } },
|
customers: { include: { contact: true } },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const folder = await Folders.getInstance().getByUid(this.props.selectedFolderUid, query);
|
const folder = await Folders.getInstance().getByUid(this.props.selectedFolderUid, query);
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
|
import CoffreIcon from "@Assets/Icons/coffre.svg";
|
||||||
|
// import { FrontendVariables } from "@Front/Config/VariablesFront";
|
||||||
|
import idNoteLogo from "@Assets/Icons/id-note-logo.svg";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
|
||||||
|
import UserStore from "@Front/Stores/UserStore";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
import BasePage from "../Base";
|
import BasePage from "../Base";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import CoffreIcon from "@Assets/Icons/coffre.svg";
|
|
||||||
import LandingImage from "./landing-connect.jpeg";
|
import LandingImage from "./landing-connect.jpeg";
|
||||||
import Image from "next/image";
|
|
||||||
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
|
|
||||||
import { FrontendVariables } from "@Front/Config/VariablesFront";
|
|
||||||
import idNoteLogo from "@Assets/Icons/id-note-logo.svg";
|
|
||||||
|
|
||||||
export default class LoginClass extends BasePage {
|
export default class LoginClass extends BasePage {
|
||||||
public override render(): JSX.Element {
|
public override render(): JSX.Element {
|
||||||
@ -30,12 +32,17 @@ export default class LoginClass extends BasePage {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private redirectUserOnConnection() {
|
private async redirectUserOnConnection() {
|
||||||
const variables = FrontendVariables.getInstance();
|
// const variables = FrontendVariables.getInstance();
|
||||||
const baseFronturl = variables.BACK_API_PROTOCOL + variables.FRONT_APP_HOST;
|
// const baseFronturl = variables.BACK_API_PROTOCOL + variables.FRONT_APP_HOST;
|
||||||
const authorizeEndPoint = variables.IDNOT_AUTHORIZE_ENDPOINT;
|
|
||||||
const clientId = variables.IDNOT_CLIENT_ID;
|
await UserStore.instance.connect(process.env["NEXT_PUBLIC_ADMIN_ID"] as string);
|
||||||
const url = `${authorizeEndPoint}?client_id=${clientId}&redirect_uri=${baseFronturl}/authorized-client&scope=openid,profile,offline_access&response_type=code`;
|
// await JwtService.getInstance().checkJwt();
|
||||||
window.location.assign(url);
|
// window.location.assign("http://localhost:3000" + "/folders");
|
||||||
|
|
||||||
|
// const authorizeEndPoint = variables.IDNOT_AUTHORIZE_ENDPOINT;
|
||||||
|
// const clientId = variables.IDNOT_CLIENT_ID;
|
||||||
|
// const url = `${authorizeEndPoint}?client_id=${clientId}&redirect_uri=${baseFronturl}/authorized-client&scope=openid,profile,offline_access&response_type=code`;
|
||||||
|
// window.location.assign(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,114 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
@media (max-width: $screen-s) {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.round {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background-color: var(--green-flash);
|
||||||
|
border-radius: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.office-infos {
|
||||||
|
background-color: var(--grey-soft);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 24px;
|
||||||
|
|
||||||
|
margin-top: 32px;
|
||||||
|
|
||||||
|
@media (max-width: $screen-l) {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: $screen-s) {
|
||||||
|
grid-template-columns: repeat(1, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.office-infos-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.office-users {
|
||||||
|
.users {
|
||||||
|
.title {
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.users-container {
|
||||||
|
margin-top: 32px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
|
||||||
|
@media (max-width: $screen-l) {
|
||||||
|
text-align: left;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: $screen-s) {
|
||||||
|
grid-template-columns: repeat(1, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.first-line,
|
||||||
|
.user-line-desktop {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(5, 1fr);
|
||||||
|
padding: 24px;
|
||||||
|
background-color: var(--purple-soft);
|
||||||
|
|
||||||
|
@media (max-width: $screen-l) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-line-desktop {
|
||||||
|
background-color: var(--grey-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-line-desktop {
|
||||||
|
&:nth-child(odd) {
|
||||||
|
background-color: var(--grey-medium);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-line-mobile {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
@media (max-width: $screen-l) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 24px;
|
||||||
|
background-color: var(--grey-soft);
|
||||||
|
padding: 24px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,193 @@
|
|||||||
|
import Offices from "@Front/Api/LeCoffreApi/SuperAdmin/Offices/Offices";
|
||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import DefaultOfficeDashboard from "@Front/Components/LayoutTemplates/DefaultOfficeDashboard";
|
||||||
|
import User, { Office } from "le-coffre-resources/dist/SuperAdmin";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {};
|
||||||
|
export default function OfficeInformations(props: IProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
let { officeUid } = router.query;
|
||||||
|
|
||||||
|
const [officeSelected, setOfficeSelected] = useState<Office | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function getOffice() {
|
||||||
|
if (!officeUid) return;
|
||||||
|
const office = await Offices.getInstance().getByUid(officeUid as string, {
|
||||||
|
q: {
|
||||||
|
address: true,
|
||||||
|
users: {
|
||||||
|
include: {
|
||||||
|
role: true,
|
||||||
|
office_role: true,
|
||||||
|
contact: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!office) return;
|
||||||
|
setOfficeSelected(office);
|
||||||
|
}
|
||||||
|
|
||||||
|
getOffice();
|
||||||
|
}, [officeUid]);
|
||||||
|
|
||||||
|
const renderUser = (user: User) => (
|
||||||
|
<>
|
||||||
|
<div key={user.uid} className={classes["user-line-desktop"]}>
|
||||||
|
<Typography typo={ITypo.P_16}>{user.contact?.last_name}</Typography>
|
||||||
|
<Typography typo={ITypo.P_16}>{user.contact?.first_name}</Typography>
|
||||||
|
<Typography typo={ITypo.P_16}>{user.contact?.email}</Typography>
|
||||||
|
<Typography typo={ITypo.P_16}>{user.contact?.phone_number}</Typography>
|
||||||
|
<Typography typo={ITypo.P_16}>{user.office_role ? user.office_role?.name : user.role?.name}</Typography>
|
||||||
|
</div>
|
||||||
|
<div key={user.uid} className={classes["user-line-mobile"]}>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK}>
|
||||||
|
Nom
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_16}>{user.contact?.last_name}</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK}>
|
||||||
|
Prénom
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_16}>{user.contact?.first_name}</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK}>
|
||||||
|
E-mail pro
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_16}>{user.contact?.email}</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK}>
|
||||||
|
Numéro de téléphone
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_16}>{user.contact?.phone_number}</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["line"]}>
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK}>
|
||||||
|
Rôle
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_16}>{user.office_role ? user.office_role?.name : user.role?.name}</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<DefaultOfficeDashboard mobileBackText={"Liste des utilisateurs"}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["header"]}>
|
||||||
|
<Typography typo={ITypo.H1Bis}>Office {officeSelected?.crpcen + " - " + officeSelected?.name}</Typography>
|
||||||
|
<div className={classes["header-right"]}>
|
||||||
|
<div className={classes["round"]} />
|
||||||
|
<Typography typo={ITypo.P_16}>Office active</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["office-infos"]}>
|
||||||
|
<div className={classes["office-infos-row"]}>
|
||||||
|
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
|
||||||
|
CRPCEN
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18}>{officeSelected?.crpcen}</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["office-infos-row"]}>
|
||||||
|
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
|
||||||
|
Dénomination
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18}>{officeSelected?.name}</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["office-infos-row"]}>
|
||||||
|
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
|
||||||
|
Addresse
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_18}>
|
||||||
|
{officeSelected?.address?.address} - {officeSelected?.address?.city} {officeSelected?.address?.zip_code}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["office-users"]}>
|
||||||
|
<div className={classes["users"]}>
|
||||||
|
<div className={classes["title"]}>
|
||||||
|
<Typography typo={ITypo.H3}>Administrateurs</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["users-container"]}>
|
||||||
|
<div className={classes["first-line"]}>
|
||||||
|
<Typography typo={ITypo.NAV_HEADER_18} color={ITypoColor.BLACK}>
|
||||||
|
Nom
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.NAV_HEADER_18} color={ITypoColor.BLACK}>
|
||||||
|
Prénom
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.NAV_HEADER_18} color={ITypoColor.BLACK}>
|
||||||
|
E-mail pro
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.NAV_HEADER_18} color={ITypoColor.BLACK}>
|
||||||
|
Numéro de téléphone
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.NAV_HEADER_18} color={ITypoColor.BLACK}>
|
||||||
|
Rôle
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
{officeSelected?.users
|
||||||
|
?.filter((user) => {
|
||||||
|
if (user.office_role && user.office_role.name === "admin") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!user.office_role && user.role?.name === "admin") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.map((user) => {
|
||||||
|
return renderUser(user);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={classes["users"]}>
|
||||||
|
<div className={classes["title"]}>
|
||||||
|
<Typography typo={ITypo.H3}>Collaborateurs</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["users-container"]}>
|
||||||
|
<div className={classes["first-line"]}>
|
||||||
|
<Typography typo={ITypo.NAV_HEADER_18} color={ITypoColor.BLACK}>
|
||||||
|
Nom
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.NAV_HEADER_18} color={ITypoColor.BLACK}>
|
||||||
|
Prénom
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.NAV_HEADER_18} color={ITypoColor.BLACK}>
|
||||||
|
E-mail pro
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.NAV_HEADER_18} color={ITypoColor.BLACK}>
|
||||||
|
Numéro de téléphone
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.NAV_HEADER_18} color={ITypoColor.BLACK}>
|
||||||
|
Rôle
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
{officeSelected?.users
|
||||||
|
?.filter((user) => {
|
||||||
|
if (user.office_role && user.office_role.name !== "admin") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!user.office_role && user.role?.name !== "admin") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.map((user) => {
|
||||||
|
return renderUser(user);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultOfficeDashboard>
|
||||||
|
);
|
||||||
|
}
|
72
src/front/Components/Layouts/Offices/classes.module.scss
Normal file
72
src/front/Components/Layouts/Offices/classes.module.scss
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100%;
|
||||||
|
|
||||||
|
.no-folder-selected {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.choose-a-folder {
|
||||||
|
margin-top: 96px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.folder-informations {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
|
||||||
|
.folder-header {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.second-box {
|
||||||
|
margin-top: 24px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-container {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
:first-child {
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
> * {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
@media (max-width: $screen-m) {
|
||||||
|
:first-child {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
> * {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.modal-title {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/front/Components/Layouts/Offices/index.tsx
Normal file
26
src/front/Components/Layouts/Offices/index.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
|
||||||
|
import BasePage from "../Base";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import DefaultOfficeDashboard from "@Front/Components/LayoutTemplates/DefaultOfficeDashboard";
|
||||||
|
|
||||||
|
type IProps = {};
|
||||||
|
type IState = {};
|
||||||
|
export default class Offices extends BasePage<IProps, IState> {
|
||||||
|
public override render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<DefaultOfficeDashboard title={"Dossier"} mobileBackText={"Liste des offices"}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["no-folder-selected"]}>
|
||||||
|
<Typography typo={ITypo.H1Bis}>Informations des offices</Typography>
|
||||||
|
<div className={classes["choose-a-folder"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.GREY}>
|
||||||
|
Sélectionnez une office
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultOfficeDashboard>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
.subtitle {
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rights-container {
|
||||||
|
margin-top: 32px;
|
||||||
|
padding: 32px 16px;
|
||||||
|
border: 1px solid gray;
|
||||||
|
.select-all-container {
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rights {
|
||||||
|
margin-top: 32px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 32px;
|
||||||
|
|
||||||
|
@media (max-width: $screen-m) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-container {
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
122
src/front/Components/Layouts/Roles/RolesInformations/index.tsx
Normal file
122
src/front/Components/Layouts/Roles/RolesInformations/index.tsx
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import Roles from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles";
|
||||||
|
import Rules from "@Front/Api/LeCoffreApi/Admin/Rules/Rules";
|
||||||
|
import Button from "@Front/Components/DesignSystem/Button";
|
||||||
|
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
|
||||||
|
import Form from "@Front/Components/DesignSystem/Form";
|
||||||
|
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import DefaultRoleDashboard from "@Front/Components/LayoutTemplates/DefaultRoleDashboard";
|
||||||
|
import { Role, Rule } from "le-coffre-resources/dist/Admin";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {};
|
||||||
|
type RuleCheckbox = Rule & {
|
||||||
|
checked: boolean;
|
||||||
|
};
|
||||||
|
export default function RolesInformations(props: IProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
let { roleUid } = router.query;
|
||||||
|
|
||||||
|
const [roleSelected, setRoleSelected] = useState<Role | null>(null);
|
||||||
|
const [rulesCheckboxes, setRulesCheckboxes] = useState<RuleCheckbox[]>([]);
|
||||||
|
const [selectAll, setSelectAll] = useState<boolean>(false);
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectAll(false);
|
||||||
|
async function getUser() {
|
||||||
|
if (!roleUid) return;
|
||||||
|
const role = await Roles.getInstance().getByUid(roleUid as string, {
|
||||||
|
q: {
|
||||||
|
rules: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules = await Rules.getInstance().get({});
|
||||||
|
if (!role) return;
|
||||||
|
setRoleSelected(role);
|
||||||
|
if (!role.rules) return;
|
||||||
|
const rulesCheckboxes = rules
|
||||||
|
.map((rule) => {
|
||||||
|
if (role.rules?.find((r) => r.uid === rule.uid)) {
|
||||||
|
return { ...rule, checked: true };
|
||||||
|
}
|
||||||
|
return { ...rule, checked: false };
|
||||||
|
})
|
||||||
|
.sort((ruleA, ruleB) => (ruleA.name < ruleB.name ? 1 : -1))
|
||||||
|
.sort((rule) => (rule.checked ? -1 : 1));
|
||||||
|
|
||||||
|
const selectAll = rulesCheckboxes.every((rule) => rule.checked);
|
||||||
|
setSelectAll(selectAll);
|
||||||
|
setRulesCheckboxes(rulesCheckboxes);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUser();
|
||||||
|
}, [roleUid]);
|
||||||
|
|
||||||
|
const handleSelectAllChange = useCallback(
|
||||||
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setSelectAll(e.target.checked);
|
||||||
|
const checked = e.target.checked;
|
||||||
|
rulesCheckboxes.forEach((rule) => (rule.checked = checked));
|
||||||
|
setRulesCheckboxes([...rulesCheckboxes]);
|
||||||
|
},
|
||||||
|
[rulesCheckboxes],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSubmitHandler = useCallback(
|
||||||
|
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
||||||
|
if (!roleSelected || !roleSelected.uid) return;
|
||||||
|
const rules = rulesCheckboxes.filter((rule) => rule.checked)?.map((rule) => Rule.hydrate<Rule>(rule));
|
||||||
|
const role = await Roles.getInstance().put(roleSelected.uid, {
|
||||||
|
rules,
|
||||||
|
});
|
||||||
|
if (!role) return;
|
||||||
|
setRoleSelected(role);
|
||||||
|
if (!role.rules) return;
|
||||||
|
setRulesCheckboxes(role.rules.map((rule) => ({ ...rule, checked: false })));
|
||||||
|
},
|
||||||
|
[roleSelected, rulesCheckboxes],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultRoleDashboard mobileBackText={"Liste des rôles"}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["header"]}>
|
||||||
|
<Typography typo={ITypo.H1Bis}>Gestion des rôles</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["subtitle"]}>
|
||||||
|
<Typography typo={ITypo.H3}>{roleSelected?.name}</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["rights-container"]}>
|
||||||
|
<div className={classes["rights-header"]}>
|
||||||
|
<Typography typo={ITypo.P_SB_18}>Modifier les droits</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes["select-all-container"]}>
|
||||||
|
<CheckBox
|
||||||
|
option={{
|
||||||
|
label: "Tout sélectionner",
|
||||||
|
value: "all",
|
||||||
|
}}
|
||||||
|
toolTip="Tout sélectionner"
|
||||||
|
onChange={handleSelectAllChange}
|
||||||
|
checked={selectAll}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Form onSubmit={onSubmitHandler}>
|
||||||
|
<div className={classes["rights"]}>
|
||||||
|
{rulesCheckboxes.map((rule) => (
|
||||||
|
<div className={classes["right"]} key={rule.uid}>
|
||||||
|
<CheckBox option={{ label: rule.name, value: rule.uid }} checked={rule.checked} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className={classes["save-container"]}>
|
||||||
|
<Button type="submit">Enregistrer</Button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultRoleDashboard>
|
||||||
|
);
|
||||||
|
}
|
17
src/front/Components/Layouts/Roles/classes.module.scss
Normal file
17
src/front/Components/Layouts/Roles/classes.module.scss
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
src/front/Components/Layouts/Roles/index.tsx
Normal file
26
src/front/Components/Layouts/Roles/index.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import DefaultRoleDashboard from "@Front/Components/LayoutTemplates/DefaultRoleDashboard";
|
||||||
|
|
||||||
|
import BasePage from "../Base";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {};
|
||||||
|
type IState = {};
|
||||||
|
export default class Collaborators extends BasePage<IProps, IState> {
|
||||||
|
public override render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<DefaultRoleDashboard mobileBackText={"Liste des rôles"}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["no-role-selected"]}>
|
||||||
|
<Typography typo={ITypo.H1Bis}>Gestion des rôles</Typography>
|
||||||
|
<div className={classes["choose-a-role"]}>
|
||||||
|
<Typography typo={ITypo.P_18} color={ITypoColor.GREY}>
|
||||||
|
Sélectionnez un rôle
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DefaultRoleDashboard>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 24px;
|
||||||
|
|
||||||
|
@media (max-width: $screen-s) {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-infos {
|
||||||
|
background-color: var(--grey-soft);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 24px;
|
||||||
|
|
||||||
|
margin-top: 32px;
|
||||||
|
|
||||||
|
@media (max-width: $screen-l) {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: $screen-s) {
|
||||||
|
grid-template-columns: repeat(1, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-infos-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-container {
|
||||||
|
padding: 32px 16px;
|
||||||
|
border: 1px solid var(--grey);
|
||||||
|
|
||||||
|
margin-top: 32px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
gap: 32px;
|
||||||
|
|
||||||
|
@media (max-width: $screen-m) {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.part {
|
||||||
|
flex: 1;
|
||||||
|
.first-line {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.second-line {
|
||||||
|
margin-top: 32px;
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.votes-block {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
background-color: var(--orange-soft);
|
||||||
|
border: 1px solid #e7e7e7;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.third-line {
|
||||||
|
margin-top: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user