Merge branch 'dev' into staging
This commit is contained in:
commit
0205a42fe3
4678
package-lock.json
generated
4678
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@
|
|||||||
"eslint-config-next": "13.2.4",
|
"eslint-config-next": "13.2.4",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.68",
|
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.73",
|
||||||
"next": "13.2.4",
|
"next": "13.2.4",
|
||||||
"prettier": "^2.8.7",
|
"prettier": "^2.8.7",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
@ -33,5 +33,6 @@
|
|||||||
"sass": "^1.59.2",
|
"sass": "^1.59.2",
|
||||||
"sharp": "^0.32.1",
|
"sharp": "^0.32.1",
|
||||||
"typescript": "4.9.5"
|
"typescript": "4.9.5"
|
||||||
}
|
},
|
||||||
|
"devDependencies": {}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -2,7 +2,7 @@ import BaseApiService from "@Front/Api/BaseApiService";
|
|||||||
|
|
||||||
export default class User extends BaseApiService {
|
export default class User extends BaseApiService {
|
||||||
private static instance: User;
|
private static instance: User;
|
||||||
private readonly baseURl = this.getBaseUrl().concat("/idnot/user");
|
private readonly baseURl = `${this.getBaseUrl()}/idnot/user`;
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
super();
|
super();
|
||||||
@ -17,7 +17,18 @@ export default class User extends BaseApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async login(uid: string) {
|
public async login(uid: string) {
|
||||||
const url = new URL(this.baseURl.concat("/login/").concat(uid));
|
const url = new URL(`${this.baseURl}/login/${uid}`);
|
||||||
|
try {
|
||||||
|
return await this.postRequest(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async verifyJwt(jwt: string) {
|
||||||
|
console.log(this.baseURl);
|
||||||
|
const url = new URL(`${this.baseURl}/verify-token/${jwt}`);
|
||||||
try {
|
try {
|
||||||
return await this.postRequest(url);
|
return await this.postRequest(url);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -27,7 +38,7 @@ export default class User extends BaseApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async refreshToken(refreshToken: string): Promise<{ accessToken: string }> {
|
public async refreshToken(refreshToken: string): Promise<{ accessToken: string }> {
|
||||||
const url = new URL(this.baseURl.concat("/refresh-token"));
|
const url = new URL(`${this.baseURl}/refresh-token`);
|
||||||
try {
|
try {
|
||||||
return await this.postRequest(url, {}, refreshToken);
|
return await this.postRequest(url, {}, refreshToken);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -11,13 +11,13 @@ export default abstract class BaseApiService {
|
|||||||
|
|
||||||
protected constructor() {
|
protected constructor() {
|
||||||
BaseApiService.baseUrl ??=
|
BaseApiService.baseUrl ??=
|
||||||
FrontendVariables.getInstance().BACK_API_PROTOCOL +
|
this.variables.BACK_API_PROTOCOL +
|
||||||
FrontendVariables.getInstance().BACK_API_HOST +
|
this.variables.BACK_API_HOST +
|
||||||
FrontendVariables.getInstance().BACK_API_ROOT_URL +
|
this.variables.BACK_API_ROOT_URL +
|
||||||
FrontendVariables.getInstance().BACK_API_VERSION;
|
this.variables.BACK_API_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getBaseUrl() {
|
protected getBaseUrl(): string {
|
||||||
return BaseApiService.baseUrl;
|
return BaseApiService.baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
src/front/Api/Entities/rule.ts
Normal file
16
src/front/Api/Entities/rule.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export interface IAppRule {
|
||||||
|
name: AppRuleNames;
|
||||||
|
action: AppRuleActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum AppRuleActions {
|
||||||
|
read = "GET",
|
||||||
|
create = "POST",
|
||||||
|
update = "PUT",
|
||||||
|
delete = "DELETE",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum AppRuleNames {
|
||||||
|
users = "users",
|
||||||
|
officeFolders = "folders",
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { DocumentType } from "le-coffre-resources/dist/SuperAdmin";
|
import { DocumentType } from "le-coffre-resources/dist/Admin";
|
||||||
|
|
||||||
import BaseAdmin from "../BaseAdmin";
|
import BaseAdmin from "../BaseAdmin";
|
||||||
|
|
||||||
|
90
src/front/Api/LeCoffreApi/Notary/Customers/Customers.ts
Normal file
90
src/front/Api/LeCoffreApi/Notary/Customers/Customers.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { Contact, Customer } from "le-coffre-resources/dist/Notary";
|
||||||
|
|
||||||
|
import BaseNotary from "../BaseNotary";
|
||||||
|
import { ECivility } from "le-coffre-resources/dist/Customer/Contact";
|
||||||
|
|
||||||
|
// TODO Type get query params -> Where + inclue + orderby
|
||||||
|
export interface IGetCustomersparams {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Type getbyuid query params
|
||||||
|
|
||||||
|
export type IPutCustomersParams = {
|
||||||
|
uid?: Customer["uid"];
|
||||||
|
contact?: Customer["contact"];
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface IPostCustomersParams {
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
email: string;
|
||||||
|
cell_phone_number: string;
|
||||||
|
civility: ECivility;
|
||||||
|
address?: Contact["address"];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Customers extends BaseNotary {
|
||||||
|
private static instance: Customers;
|
||||||
|
private readonly baseURl = this.namespaceUrl.concat("/customers");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new this();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get(q: IGetCustomersparams): Promise<Customer[]> {
|
||||||
|
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<Customer[]>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Create a Customer
|
||||||
|
*/
|
||||||
|
public async post(body: any): Promise<Customer> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
try {
|
||||||
|
return await this.postRequest<Customer>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getByUid(uid: string, q?: any): Promise<Customer> {
|
||||||
|
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<Customer>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async put(uid: string, body: IPutCustomersParams): Promise<Customer> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
try {
|
||||||
|
return await this.putRequest<Customer>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
84
src/front/Api/LeCoffreApi/Notary/DeedTypes/DeedTypes.ts
Normal file
84
src/front/Api/LeCoffreApi/Notary/DeedTypes/DeedTypes.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import { DeedType } from "le-coffre-resources/dist/Notary";
|
||||||
|
|
||||||
|
import BaseNotary from "../BaseNotary";
|
||||||
|
|
||||||
|
export type IPutDeedTypesParams = {
|
||||||
|
uid?: DeedType["uid"];
|
||||||
|
name?: DeedType["name"];
|
||||||
|
description?: DeedType["description"];
|
||||||
|
deed?: DeedType["deed"];
|
||||||
|
office?: DeedType["office"];
|
||||||
|
archived_at?: DeedType["archived_at"];
|
||||||
|
document_types?: DeedType["document_types"];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type IPostDeedTypesParams = {
|
||||||
|
name?: DeedType["name"];
|
||||||
|
description?: DeedType["description"];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type IGetDeedTypesParams = {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
select?: {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DeedTypes extends BaseNotary {
|
||||||
|
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 };
|
||||||
|
if (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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async put(uid: string, body: IPutDeedTypesParams) {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
try {
|
||||||
|
return await this.putRequest<DeedType>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async post(body: IPostDeedTypesParams) {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
try {
|
||||||
|
return await this.postRequest<DeedType>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
72
src/front/Api/LeCoffreApi/Notary/Deeds/Deeds.ts
Normal file
72
src/front/Api/LeCoffreApi/Notary/Deeds/Deeds.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { Deed, OfficeFolder } from "le-coffre-resources/dist/Notary";
|
||||||
|
|
||||||
|
import BaseAdmin from "../BaseNotary";
|
||||||
|
|
||||||
|
export type IGetDeedsParams = {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
select?: {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type IPutDeedsParams = {
|
||||||
|
uid?: OfficeFolder["uid"];
|
||||||
|
folder_number?: OfficeFolder["folder_number"];
|
||||||
|
name?: OfficeFolder["name"];
|
||||||
|
description?: OfficeFolder["description"];
|
||||||
|
archived_description?: OfficeFolder["archived_description"];
|
||||||
|
status?: OfficeFolder["status"];
|
||||||
|
document_types?: Deed["document_types"];
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Update the folder description
|
||||||
|
*/
|
||||||
|
public async put(uid: string, body: IPutDeedsParams): Promise<Deed> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
try {
|
||||||
|
return await this.putRequest<Deed>(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
import { DocumentType } from "le-coffre-resources/dist/Notary";
|
||||||
|
|
||||||
|
import BaseNotary from "../BaseNotary";
|
||||||
|
|
||||||
|
// 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 | null;
|
||||||
|
office?: {
|
||||||
|
uid?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class DocumentTypes extends BaseNotary {
|
||||||
|
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: IPostDocumentTypesParams): 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/Notary/Documents/Documents.ts
Normal file
93
src/front/Api/LeCoffreApi/Notary/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/Notary";
|
||||||
|
|
||||||
|
import BaseNotary from "../BaseNotary";
|
||||||
|
|
||||||
|
// 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 BaseNotary {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
119
src/front/Api/LeCoffreApi/Notary/Folders/Folders.ts
Normal file
119
src/front/Api/LeCoffreApi/Notary/Folders/Folders.ts
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
import { type OfficeFolder } from "le-coffre-resources/dist/Notary";
|
||||||
|
|
||||||
|
import BaseNotary from "../BaseNotary";
|
||||||
|
import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus";
|
||||||
|
|
||||||
|
// TODO Type get query params -> Where + inclue + orderby
|
||||||
|
export interface IGetFoldersParams {
|
||||||
|
q?: {
|
||||||
|
select?: {};
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Folders extends BaseNotary {
|
||||||
|
private static instance: Folders;
|
||||||
|
private readonly baseURl = this.namespaceUrl.concat("/folders");
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getInstance() {
|
||||||
|
if (!this.instance) {
|
||||||
|
return new this();
|
||||||
|
} else {
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get all folders
|
||||||
|
*/
|
||||||
|
public async get(q: IGetFoldersParams): Promise<OfficeFolder[]> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
|
try {
|
||||||
|
return await this.getRequest<OfficeFolder[]>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Get a folder by uid
|
||||||
|
*/
|
||||||
|
public async getByUid(uid: string, q?: any): Promise<OfficeFolder> {
|
||||||
|
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<OfficeFolder>(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Create a folder
|
||||||
|
*/
|
||||||
|
public async post(officeFolder: Partial<OfficeFolder>): Promise<OfficeFolder> {
|
||||||
|
const url = new URL(this.baseURl);
|
||||||
|
try {
|
||||||
|
return await this.postRequest(url, officeFolder);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Update the folder description
|
||||||
|
*/
|
||||||
|
public async put(uid: string, body: Partial<OfficeFolder>): Promise<OfficeFolder> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
try {
|
||||||
|
return await this.putRequest(url, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Delete a folder only if the folder don't contains customers
|
||||||
|
*/
|
||||||
|
public async delete(uid: string): Promise<OfficeFolder> {
|
||||||
|
const url = new URL(this.baseURl.concat(`/${uid}`));
|
||||||
|
const targetedFolder = await this.getByUid(uid);
|
||||||
|
if (targetedFolder.customers) return Promise.reject(`The folder ${uid} contains customers`);
|
||||||
|
try {
|
||||||
|
return await this.deleteRequest(url);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async archive(uid: string, body: Partial<OfficeFolder>): Promise<OfficeFolder> {
|
||||||
|
body.status = EFolderStatus.ARCHIVED;
|
||||||
|
try {
|
||||||
|
return await this.put(uid, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async restore(uid: string, body: Partial<OfficeFolder>): Promise<OfficeFolder> {
|
||||||
|
body.status = EFolderStatus.LIVE;
|
||||||
|
try {
|
||||||
|
return await this.put(uid, body);
|
||||||
|
} catch (err) {
|
||||||
|
this.onError(err);
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,15 @@
|
|||||||
import BaseNotary from "../BaseNotary";
|
import BaseNotary from "../BaseNotary";
|
||||||
import User from "le-coffre-resources/dist/Notary";
|
import User from "le-coffre-resources/dist/Notary";
|
||||||
|
|
||||||
|
export type IGetUsersParams = {
|
||||||
|
where?: {};
|
||||||
|
include?: {};
|
||||||
|
select?: {};
|
||||||
|
};
|
||||||
|
|
||||||
export default class Users extends BaseNotary {
|
export default class Users extends BaseNotary {
|
||||||
private static instance: Users;
|
private static instance: Users;
|
||||||
private readonly baseURl = this.namespaceUrl.concat("/Users");
|
private readonly baseURl = this.namespaceUrl.concat("/users");
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
super();
|
super();
|
||||||
@ -17,8 +23,10 @@ export default class Users extends BaseNotary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async get(): Promise<User[]> {
|
public async get(q?: IGetUsersParams): Promise<User[]> {
|
||||||
const url = new URL(this.baseURl);
|
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 {
|
try {
|
||||||
return await this.getRequest<User[]>(url);
|
return await this.getRequest<User[]>(url);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -27,23 +35,9 @@ export default class Users extends BaseNotary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAuthorizationCode(): Promise<any> {
|
public async getByUid(uid: string, q?: any): Promise<User> {
|
||||||
try {
|
|
||||||
const url = new URL(`https://qual-connexion.idnot.fr/IdPOAuth2/authorize/idnot_idp_v1?
|
|
||||||
client_id=4501646203F3EF67
|
|
||||||
&redirect_uri=https://app.stg.lecoffre.smart-chain.fr/
|
|
||||||
&scope=openid,profile,offline_access
|
|
||||||
&response_type=code`);
|
|
||||||
// const url = new URL("https://jsonplaceholder.typicode.com/todos/1");
|
|
||||||
await this.getRequest(url);
|
|
||||||
} catch (err) {
|
|
||||||
this.onError(err);
|
|
||||||
return Promise.reject(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getByUid(uid: string): Promise<User> {
|
|
||||||
const url = new URL(this.baseURl.concat("/").concat(uid));
|
const url = new URL(this.baseURl.concat("/").concat(uid));
|
||||||
|
if (q) Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
|
||||||
try {
|
try {
|
||||||
return await this.getRequest<User>(url);
|
return await this.getRequest<User>(url);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -51,14 +45,4 @@ export default class Users extends BaseNotary {
|
|||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public async post(params: User): Promise<User> {
|
|
||||||
// const url = new URL(this.baseURl);
|
|
||||||
// try {
|
|
||||||
// return await this.postRequest<User>(url, params);
|
|
||||||
// } catch (err) {
|
|
||||||
// this.onError(err);
|
|
||||||
// return Promise.reject(err);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
4
src/front/Assets/Icons/copy.svg
Normal file
4
src/front/Assets/Icons/copy.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20 9H11C9.89543 9 9 9.89543 9 11V20C9 21.1046 9.89543 22 11 22H20C21.1046 22 22 21.1046 22 20V11C22 9.89543 21.1046 9 20 9Z" stroke="#939393" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M5 15H4C3.46957 15 2.96086 14.7893 2.58579 14.4142C2.21071 14.0391 2 13.5304 2 13V4C2 3.46957 2.21071 2.96086 2.58579 2.58579C2.96086 2.21071 3.46957 2 4 2H13C13.5304 2 14.0391 2.21071 14.4142 2.58579C14.7893 2.96086 15 3.46957 15 4V5" stroke="#939393" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 649 B |
@ -17,18 +17,18 @@ type IProps = {
|
|||||||
export default function BlockList({ blocks, onSelectedBlock }: IProps) {
|
export default function BlockList({ blocks, onSelectedBlock }: IProps) {
|
||||||
const selectBlock = useCallback(
|
const selectBlock = useCallback(
|
||||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
(e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
onSelectedBlock && onSelectedBlock(blocks.find((block) => block.id === e.currentTarget.id)!);
|
onSelectedBlock && onSelectedBlock(blocks.find((folder) => folder.id === e.currentTarget.id)!);
|
||||||
},
|
},
|
||||||
[blocks, onSelectedBlock],
|
[blocks, onSelectedBlock],
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{blocks.map((block) => {
|
{blocks.map((folder) => {
|
||||||
return (
|
return (
|
||||||
<div onClick={selectBlock} key={block.id} id={block.id}>
|
<div onClick={selectBlock} key={folder.id} id={folder.id}>
|
||||||
<div className={classes["root"]} data-selected={block.selected.toString()}>
|
<div className={classes["root"]} data-selected={folder.selected.toString()}>
|
||||||
<div className={classes["left-side"]}>
|
<div className={classes["left-side"]}>
|
||||||
<Typography typo={ITypo.P_16}>{block.name}</Typography>
|
<Typography typo={ITypo.P_16}>{folder.name}</Typography>
|
||||||
</div>
|
</div>
|
||||||
<Image alt="chevron" src={ChevronIcon} />
|
<Image alt="chevron" src={ChevronIcon} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,6 +41,30 @@ type IState = {
|
|||||||
loading: boolean;
|
loading: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type fileAccepted = {
|
||||||
|
extension: string;
|
||||||
|
size: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const filesAccepted: { [key: string]: fileAccepted } = {
|
||||||
|
"application/pdf": {
|
||||||
|
extension: "pdf",
|
||||||
|
size: 41943040,
|
||||||
|
},
|
||||||
|
"image/jpeg": {
|
||||||
|
extension: "jpeg",
|
||||||
|
size: 41943040,
|
||||||
|
},
|
||||||
|
"image/png": {
|
||||||
|
extension: "png",
|
||||||
|
size: 41943040,
|
||||||
|
},
|
||||||
|
"image/jpg": {
|
||||||
|
extension: "jpg",
|
||||||
|
size: 41943040,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export default class DepositDocument extends React.Component<IProps, IState> {
|
export default class DepositDocument extends React.Component<IProps, IState> {
|
||||||
private inputRef = React.createRef<HTMLInputElement>();
|
private inputRef = React.createRef<HTMLInputElement>();
|
||||||
private index = 0;
|
private index = 0;
|
||||||
@ -80,7 +104,13 @@ export default class DepositDocument extends React.Component<IProps, IState> {
|
|||||||
onDrop={this.onDragDrop}
|
onDrop={this.onDragDrop}
|
||||||
onDragLeave={this.onDragLeave}
|
onDragLeave={this.onDragLeave}
|
||||||
data-drag-over={this.state.isDragOver.toString()}>
|
data-drag-over={this.state.isDragOver.toString()}>
|
||||||
<input type="file" ref={this.inputRef} hidden onChange={this.onFileChange} />
|
<input
|
||||||
|
type="file"
|
||||||
|
ref={this.inputRef}
|
||||||
|
hidden
|
||||||
|
onChange={this.onFileChange}
|
||||||
|
accept={Object.keys(filesAccepted).join(",")}
|
||||||
|
/>
|
||||||
<div className={classes["top-container"]}>
|
<div className={classes["top-container"]}>
|
||||||
<div className={classes["left"]}>
|
<div className={classes["left"]}>
|
||||||
<Image src={DepositDocumentIcon} alt="Deposit document" />
|
<Image src={DepositDocumentIcon} alt="Deposit document" />
|
||||||
@ -121,7 +151,7 @@ export default class DepositDocument extends React.Component<IProps, IState> {
|
|||||||
<div className={classes["file-container"]} key={fileObj.name + file.index}>
|
<div className={classes["file-container"]} key={fileObj.name + file.index}>
|
||||||
<div className={classes["left-part"]}>
|
<div className={classes["left-part"]}>
|
||||||
<Image src={DocumentCheckIcon} alt="Document check" />
|
<Image src={DocumentCheckIcon} alt="Document check" />
|
||||||
<Typography typo={ITypo.P_16} color={ITypoColor.GREY}>
|
<Typography typo={ITypo.P_16} color={ITypoColor.GREY} title={file.fileName ?? fileObj.name}>
|
||||||
{this.shortName(file.fileName || fileObj.name)}
|
{this.shortName(file.fileName || fileObj.name)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
@ -281,19 +311,29 @@ export default class DepositDocument extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async onDragDrop(event: React.DragEvent<HTMLDivElement>) {
|
private async onDragDrop(event: React.DragEvent<HTMLDivElement>) {
|
||||||
this.setState({
|
|
||||||
loading: true,
|
|
||||||
});
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.setState({
|
this.setState({
|
||||||
isDragOver: false,
|
isDragOver: false,
|
||||||
});
|
});
|
||||||
const file = event.dataTransfer.files[0];
|
const file = event.dataTransfer.files[0];
|
||||||
if (file) this.addFile(file);
|
if (file) this.addFile(file);
|
||||||
else this.setState({ loading: false });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async addFile(file: File) {
|
private async addFile(file: File) {
|
||||||
|
const fileAccepted = filesAccepted[file.type];
|
||||||
|
if (!fileAccepted) {
|
||||||
|
alert("Ce type de fichier n'est pas accepté");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (file.size > fileAccepted.size) {
|
||||||
|
alert("Ce fichier est trop volumineux");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", file, file.name);
|
formData.append("file", file, file.name);
|
||||||
const query = JSON.stringify({ document: { uid: this.props.document.uid } });
|
const query = JSON.stringify({ document: { uid: this.props.document.uid } });
|
||||||
@ -302,22 +342,28 @@ export default class DepositDocument extends React.Component<IProps, IState> {
|
|||||||
const newFile = await Files.getInstance().post(formData);
|
const newFile = await Files.getInstance().post(formData);
|
||||||
const files = this.state.currentFiles ? [...this.state.currentFiles, newFile] : [newFile];
|
const files = this.state.currentFiles ? [...this.state.currentFiles, newFile] : [newFile];
|
||||||
|
|
||||||
this.setState({
|
const newFileList = [
|
||||||
currentFiles: files,
|
...this.state.files,
|
||||||
loading: false,
|
{
|
||||||
files: [
|
index: this.index++,
|
||||||
...this.state.files,
|
file: file,
|
||||||
{
|
uid: newFile.uid!,
|
||||||
index: this.index++,
|
archived: null,
|
||||||
file: file,
|
fileName: newFile?.file_name ?? "",
|
||||||
uid: newFile.uid!,
|
},
|
||||||
archived: null,
|
];
|
||||||
fileName: newFile?.file_name ?? "",
|
this.setState(
|
||||||
},
|
{
|
||||||
],
|
currentFiles: files,
|
||||||
});
|
loading: false,
|
||||||
|
files: newFileList,
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
if (this.props.onChange) this.props.onChange(newFileList.map((file) => file.file));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (this.props.onChange) this.props.onChange(this.state.files.map((file) => file.file));
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async removeFile(e: any) {
|
private async removeFile(e: any) {
|
||||||
@ -336,9 +382,6 @@ export default class DepositDocument extends React.Component<IProps, IState> {
|
|||||||
|
|
||||||
private async onFileChange() {
|
private async onFileChange() {
|
||||||
if (!this.inputRef.current) return;
|
if (!this.inputRef.current) return;
|
||||||
this.setState({
|
|
||||||
loading: true,
|
|
||||||
});
|
|
||||||
const files = this.inputRef.current.files;
|
const files = this.inputRef.current.files;
|
||||||
if (!files) {
|
if (!files) {
|
||||||
this.setState({ loading: false });
|
this.setState({ loading: false });
|
||||||
@ -346,12 +389,16 @@ export default class DepositDocument extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
const file = files[0];
|
const file = files[0];
|
||||||
|
|
||||||
if (file) this.addFile(file);
|
try {
|
||||||
else this.setState({ loading: false });
|
if (file) this.addFile(file);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private addDocument() {
|
private addDocument() {
|
||||||
if (!this.inputRef.current) return;
|
if (!this.inputRef.current) return;
|
||||||
|
this.inputRef.current.value = "";
|
||||||
this.inputRef.current.click();
|
this.inputRef.current.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,106 @@
|
|||||||
|
.container {
|
||||||
|
.root {
|
||||||
|
padding: 24px;
|
||||||
|
background-color: var(--white);
|
||||||
|
border: 1px dashed #e7e7e7;
|
||||||
|
|
||||||
|
height: fit-content;
|
||||||
|
|
||||||
|
&[data-drag-over="true"] {
|
||||||
|
border: 1px dashed var(--grey);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.validated {
|
||||||
|
border: 1px dashed var(--green-flash);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
margin-right: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
background-color: #939393;
|
||||||
|
width: 1px;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
margin-left: 18px;
|
||||||
|
|
||||||
|
.validated {
|
||||||
|
color: var(--green-flash);
|
||||||
|
}
|
||||||
|
|
||||||
|
.refused-button {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--re-hover);
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.documents-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
.file-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.left-part {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
.loader {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cross {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-container {
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
.add-button {
|
||||||
|
.add-document {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: var(--red-flash);
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
303
src/front/Components/DesignSystem/DepositOtherDocument/index.tsx
Normal file
303
src/front/Components/DesignSystem/DepositOtherDocument/index.tsx
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
import DepositDocumentIcon from "@Assets/Icons/deposit-document.svg";
|
||||||
|
import CrossIcon from "@Assets/Icons/cross.svg";
|
||||||
|
import DocumentCheckIcon from "@Assets/Icons/document-check.svg";
|
||||||
|
import PlusIcon from "@Assets/Icons/plus.svg";
|
||||||
|
|
||||||
|
import Image from "next/image";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import Typography, { ITypo, ITypoColor } from "../Typography";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import { Document } from "le-coffre-resources/dist/Customer";
|
||||||
|
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
import Button, { EButtonVariant } from "../Button";
|
||||||
|
import Confirm from "../Modal/Confirm";
|
||||||
|
import Documents from "@Front/Api/LeCoffreApi/Customer/Documents/Documents";
|
||||||
|
import Files from "@Front/Api/LeCoffreApi/Customer/Files/Files";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
onChange?: (files: File[]) => void;
|
||||||
|
open: boolean;
|
||||||
|
onClose?: () => void;
|
||||||
|
document: Document;
|
||||||
|
customer_uid: string;
|
||||||
|
folder_uid: string | string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type IFile = {
|
||||||
|
index: number;
|
||||||
|
file: File;
|
||||||
|
fileName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type IState = {
|
||||||
|
files: IFile[];
|
||||||
|
isDragOver: boolean;
|
||||||
|
currentFiles?: IFile[];
|
||||||
|
refusedReason?: string;
|
||||||
|
isShowRefusedReasonModalVisible: boolean;
|
||||||
|
isAddDocumentModalVisible: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class DepositOtherDocument extends React.Component<IProps, IState> {
|
||||||
|
private inputRef = React.createRef<HTMLInputElement>();
|
||||||
|
private index = 0;
|
||||||
|
|
||||||
|
public constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isAddDocumentModalVisible: this.props.open,
|
||||||
|
files: [],
|
||||||
|
isDragOver: false,
|
||||||
|
refusedReason: "",
|
||||||
|
isShowRefusedReasonModalVisible: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.addDocument = this.addDocument.bind(this);
|
||||||
|
this.onFileChange = this.onFileChange.bind(this);
|
||||||
|
this.removeFile = this.removeFile.bind(this);
|
||||||
|
this.onDragOver = this.onDragOver.bind(this);
|
||||||
|
this.onDragDrop = this.onDragDrop.bind(this);
|
||||||
|
this.onDragLeave = this.onDragLeave.bind(this);
|
||||||
|
this.onAccept = this.onAccept.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async onAccept() {
|
||||||
|
const filesArray = this.state.currentFiles;
|
||||||
|
|
||||||
|
if (!filesArray) return;
|
||||||
|
|
||||||
|
const documentCreated = await Documents.getInstance().post({
|
||||||
|
folder: {
|
||||||
|
uid: this.props.folder_uid,
|
||||||
|
},
|
||||||
|
depositor: {
|
||||||
|
uid: this.props.customer_uid,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(documentCreated);
|
||||||
|
|
||||||
|
filesArray.forEach(async (file) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", file.file, file.fileName);
|
||||||
|
const query = JSON.stringify({ document: { uid: documentCreated.uid } });
|
||||||
|
formData.append("q", query);
|
||||||
|
|
||||||
|
const newFile = await Files.getInstance().post(formData);
|
||||||
|
console.log(newFile);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.onClose!();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Confirm
|
||||||
|
isOpen={this.state.isAddDocumentModalVisible}
|
||||||
|
onClose={this.props.onClose!}
|
||||||
|
onAccept={this.onAccept}
|
||||||
|
closeBtn
|
||||||
|
header={"Ajouter un document"}
|
||||||
|
cancelText={"Annuler"}
|
||||||
|
confirmText={"Déposer le document"}>
|
||||||
|
<div className={classes["modal-content"]}>
|
||||||
|
<div className={classes["container"]}>
|
||||||
|
<Typography typo={ITypo.P_16} className={classes["text"]}>
|
||||||
|
Vous souhaitez envoyer un autre document à votre notaire ?
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_16} className={classes["text"]}>
|
||||||
|
Glissez / Déposez votre document dans la zone prévue à cet effet ou cliquez sur la zone puis sélectionnez le
|
||||||
|
document correspondant.
|
||||||
|
</Typography>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
classes["root"],
|
||||||
|
this.props.document.document_status === EDocumentStatus.VALIDATED && classes["validated"],
|
||||||
|
)}
|
||||||
|
onDragOver={this.onDragOver}
|
||||||
|
onDrop={this.onDragDrop}
|
||||||
|
onDragLeave={this.onDragLeave}
|
||||||
|
data-drag-over={this.state.isDragOver.toString()}>
|
||||||
|
<input type="file" ref={this.inputRef} hidden onChange={this.onFileChange} />
|
||||||
|
<div className={classes["top-container"]}>
|
||||||
|
<div className={classes["left"]}>
|
||||||
|
<Image src={DepositDocumentIcon} alt="Deposit document" />
|
||||||
|
</div>
|
||||||
|
<div className={classes["separator"]} />
|
||||||
|
<div className={classes["right"]}>
|
||||||
|
<Typography typo={ITypo.P_SB_16} color={ITypoColor.BLACK} className={classes["title"]}>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
this.props.document.document_status === EDocumentStatus.VALIDATED
|
||||||
|
? classes["validated"]
|
||||||
|
: ""
|
||||||
|
}>
|
||||||
|
{this.props.document.document_type?.name}
|
||||||
|
</div>
|
||||||
|
</Typography>
|
||||||
|
<Typography color={ITypoColor.GREY} typo={ITypo.CAPTION_14}>
|
||||||
|
Sélectionnez des TEST documents .jpg, .pdf ou .png
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{this.state.currentFiles && this.state.currentFiles.length > 0 && (
|
||||||
|
<div className={classes["documents-container"]}>
|
||||||
|
{this.state.currentFiles.map((file) => {
|
||||||
|
console.log(file);
|
||||||
|
|
||||||
|
const fileObj = file.file;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes["file-container"]} key={fileObj.name}>
|
||||||
|
<div className={classes["left-part"]}>
|
||||||
|
<Image src={DocumentCheckIcon} alt="Document check" />
|
||||||
|
<Typography typo={ITypo.P_16} color={ITypoColor.GREY}>
|
||||||
|
{this.shortName(fileObj.name)}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<Image
|
||||||
|
src={CrossIcon}
|
||||||
|
alt="Cross icon"
|
||||||
|
className={classes["cross"]}
|
||||||
|
onClick={this.removeFile}
|
||||||
|
data-file={file.index}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className={classes["bottom-container"]}>
|
||||||
|
<Button variant={EButtonVariant.LINE} className={classes["add-button"]} onClick={this.addDocument}>
|
||||||
|
<Typography typo={ITypo.P_SB_16} color={ITypoColor.PINK_FLASH} className={classes["add-document"]}>
|
||||||
|
Ajouter un document <Image src={PlusIcon} alt="Plus icon" />
|
||||||
|
</Typography>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Confirm>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override componentDidMount(): void {}
|
||||||
|
|
||||||
|
private shortName(name: string): string {
|
||||||
|
const maxLength = 20;
|
||||||
|
if (name.length > maxLength) {
|
||||||
|
return name.substring(0, maxLength / 2) + "..." + name.substring(name.length - maxLength / 2, name.length);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private onDragOver(event: React.DragEvent<HTMLDivElement>) {
|
||||||
|
if (!this.state.isDragOver) {
|
||||||
|
this.setState({
|
||||||
|
isDragOver: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
private onDragLeave(event: React.DragEvent<HTMLDivElement>) {
|
||||||
|
this.setState({
|
||||||
|
isDragOver: false,
|
||||||
|
});
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async onDragDrop(event: React.DragEvent<HTMLDivElement>) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.setState({
|
||||||
|
isDragOver: false,
|
||||||
|
});
|
||||||
|
const file = event.dataTransfer.files[0];
|
||||||
|
if (file) this.addFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async addFile(file: File) {
|
||||||
|
const iFile: IFile = {
|
||||||
|
file: file,
|
||||||
|
fileName: file.name,
|
||||||
|
index: this.index++,
|
||||||
|
};
|
||||||
|
const tmpArray: IFile[] = this.state.currentFiles || [];
|
||||||
|
tmpArray.push(iFile);
|
||||||
|
this.setState({
|
||||||
|
currentFiles: tmpArray,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(this.state.currentFiles);
|
||||||
|
|
||||||
|
// const formData = new FormData();
|
||||||
|
// formData.append("file", file, file.name);
|
||||||
|
// const query = JSON.stringify({ document: { uid: this.props.document.uid } });
|
||||||
|
// formData.append("q", query);
|
||||||
|
|
||||||
|
// const newFile = await Files.getInstance().post(formData);
|
||||||
|
// const newFile: FileCustomer = {
|
||||||
|
// file_name: file.name,
|
||||||
|
// }
|
||||||
|
// const files = this.state.currentFiles ? [...this.state.currentFiles, newFile] : [newFile];
|
||||||
|
|
||||||
|
// this.setState({
|
||||||
|
// currentFiles: files,
|
||||||
|
// loading: false,
|
||||||
|
// files: [
|
||||||
|
// ...this.state.files,
|
||||||
|
// {
|
||||||
|
// index: this.index++,
|
||||||
|
// file: file,
|
||||||
|
// uid: newFile.uid!,
|
||||||
|
// archived: null,
|
||||||
|
// fileName: newFile?.file_name ?? "",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// });
|
||||||
|
|
||||||
|
// if (this.props.onChange) this.props.onChange(this.state.files.map((file) => file.file));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async removeFile(e: any) {
|
||||||
|
const image = e.target as HTMLElement;
|
||||||
|
const indexToRemove = image.getAttribute("data-file");
|
||||||
|
console.log(indexToRemove);
|
||||||
|
|
||||||
|
if (!indexToRemove) return;
|
||||||
|
const file = this.state.currentFiles!.find((file) => file.index === parseInt(indexToRemove));
|
||||||
|
if (!file) return;
|
||||||
|
this.setState({
|
||||||
|
currentFiles: this.state.currentFiles!.filter((file) => file.index !== parseInt(indexToRemove)),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.props.onChange) this.props.onChange(this.state.currentFiles!.map((file) => file.file));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async onFileChange() {
|
||||||
|
if (!this.inputRef.current) return;
|
||||||
|
|
||||||
|
const files = this.inputRef.current.files;
|
||||||
|
|
||||||
|
if (!files) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const file = files[0];
|
||||||
|
|
||||||
|
if (file) this.addFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private addDocument() {
|
||||||
|
if (!this.inputRef.current) return;
|
||||||
|
this.inputRef.current.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
// private formatDate(date: Date) {
|
||||||
|
// const dateToConvert = new Date(date);
|
||||||
|
// return dateToConvert.toLocaleDateString("fr-FR");
|
||||||
|
// }
|
||||||
|
}
|
@ -9,6 +9,8 @@ import BlockList, { IBlock } from "../BlockList";
|
|||||||
import Button from "../Button";
|
import Button from "../Button";
|
||||||
import SearchBar from "../SearchBar";
|
import SearchBar from "../SearchBar";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import Rules, { RulesMode } from "@Front/Components/Elements/Rules";
|
||||||
|
import { AppRuleActions, AppRuleNames } from "@Front/Api/Entities/rule";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
folders: OfficeFolder[];
|
folders: OfficeFolder[];
|
||||||
@ -19,6 +21,7 @@ type IProps = {
|
|||||||
|
|
||||||
type IPropsClass = IProps & {
|
type IPropsClass = IProps & {
|
||||||
router: NextRouter;
|
router: NextRouter;
|
||||||
|
selectedFolder: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IState = {
|
type IState = {
|
||||||
@ -52,9 +55,18 @@ class FolderListContainerClass extends React.Component<IPropsClass, IState> {
|
|||||||
</div>
|
</div>
|
||||||
{!this.props.isArchived && (
|
{!this.props.isArchived && (
|
||||||
<div>
|
<div>
|
||||||
<Link href={navigatePath}>
|
<Rules
|
||||||
<Button fullwidth={true}>Créer un dossier</Button>
|
mode={RulesMode.NECESSARY}
|
||||||
</Link>
|
rules={[
|
||||||
|
{
|
||||||
|
action: AppRuleActions.create,
|
||||||
|
name: AppRuleNames.officeFolders,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Link href={navigatePath}>
|
||||||
|
<Button fullwidth={true}>Créer un dossier</Button>
|
||||||
|
</Link>
|
||||||
|
</Rules>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -85,7 +97,11 @@ class FolderListContainerClass extends React.Component<IPropsClass, IState> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return [...pendingFolders, ...otherFolders].map((folder) => {
|
return [...pendingFolders, ...otherFolders].map((folder) => {
|
||||||
return { id: folder.uid!, name: folder.folder_number! + " - " + folder.name!, selected: false };
|
return {
|
||||||
|
id: folder.uid!,
|
||||||
|
name: folder.folder_number! + " - " + folder.name!,
|
||||||
|
selected: this.props.selectedFolder === folder.uid,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private onSelectedFolder(block: IBlock) {
|
private onSelectedFolder(block: IBlock) {
|
||||||
@ -118,5 +134,6 @@ class FolderListContainerClass extends React.Component<IPropsClass, IState> {
|
|||||||
|
|
||||||
export default function FolderListContainer(props: IProps) {
|
export default function FolderListContainer(props: IProps) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
return <FolderListContainerClass {...props} router={router} />;
|
const { folderUid } = router.query;
|
||||||
|
return <FolderListContainerClass {...props} router={router} selectedFolder={folderUid as string} />;
|
||||||
}
|
}
|
||||||
|
@ -16,17 +16,8 @@
|
|||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
background: white;
|
|
||||||
opacity: 0.6;
|
|
||||||
~ .fake-placeholder {
|
|
||||||
color: rgba($grey, 0.6);
|
|
||||||
/**
|
|
||||||
TODO
|
|
||||||
* 1. Add styles so the placeholder has the same color as the background when disabled
|
|
||||||
*/
|
|
||||||
// background: transparent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
~ .fake-placeholder {
|
~ .fake-placeholder {
|
||||||
transform: translateY(-35px);
|
transform: translateY(-35px);
|
||||||
@ -91,12 +82,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&[data-is-errored="true"] {
|
&[data-is-errored="true"] {
|
||||||
.input{
|
.input {
|
||||||
border: 1px solid var(--red-flash);
|
border: 1px solid var(--red-flash);
|
||||||
~ .fake-placeholder{
|
~ .fake-placeholder {
|
||||||
color: var(--red-flash);
|
color: var(--red-flash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 24px;
|
||||||
|
transform: translate(0, -50%);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,18 +1,22 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
|
import CopyIcon from "@Assets/Icons/copy.svg";
|
||||||
import BaseField, { IProps as IBaseFieldProps } from "../BaseField";
|
import BaseField, { IProps as IBaseFieldProps } from "../BaseField";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import classnames from "classnames";
|
import classnames from "classnames";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
export type IProps = IBaseFieldProps & {};
|
export type IProps = IBaseFieldProps & {
|
||||||
|
canCopy?: boolean;
|
||||||
|
password?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export default class TextField extends BaseField<IProps> {
|
export default class TextField extends BaseField<IProps> {
|
||||||
constructor(props: IProps){
|
constructor(props: IProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = this.getDefaultState();
|
this.state = this.getDefaultState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): ReactNode {
|
public override render(): ReactNode {
|
||||||
const value = this.state.value ?? "";
|
const value = this.state.value ?? "";
|
||||||
@ -28,13 +32,26 @@ export default class TextField extends BaseField<IProps> {
|
|||||||
onFocus={this.onFocus}
|
onFocus={this.onFocus}
|
||||||
onBlur={this.onBlur}
|
onBlur={this.onBlur}
|
||||||
name={this.props.name}
|
name={this.props.name}
|
||||||
|
disabled={this.props.disabled}
|
||||||
|
type={this.props.password ? "password" : "text"}
|
||||||
/>
|
/>
|
||||||
<div className={classes["fake-placeholder"]}>
|
<div className={classes["fake-placeholder"]}>
|
||||||
{this.props.placeholder} {!this.props.required && " (Facultatif)"}
|
{this.props.placeholder} {!this.props.required && " (Facultatif)"}
|
||||||
</div>
|
</div>
|
||||||
|
{this.props.canCopy && (
|
||||||
|
<div className={classes["copy-icon"]} onClick={this.onCopyClick}>
|
||||||
|
<Image src={CopyIcon} alt="Copy icon" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{this.hasError() && <div className={classes["errors-container"]}>{this.renderErrors()}</div>}
|
{this.hasError() && <div className={classes["errors-container"]}>{this.renderErrors()}</div>}
|
||||||
</Typography>
|
</Typography>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onCopyClick = (): void => {
|
||||||
|
if (this.props.canCopy) {
|
||||||
|
navigator.clipboard.writeText(this.state.value ?? "");
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,12 @@
|
|||||||
gap: 16px;
|
gap: 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
|
|
||||||
|
.disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
.switch-container {
|
.switch-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 46px;
|
width: 46px;
|
||||||
|
@ -7,8 +7,9 @@ type IProps = {
|
|||||||
onChange?: (checked: boolean) => void;
|
onChange?: (checked: boolean) => void;
|
||||||
checked?: boolean;
|
checked?: boolean;
|
||||||
label: string;
|
label: string;
|
||||||
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
export default function Switch({ onChange, checked, label }: IProps) {
|
export default function Switch({ onChange, checked, label, disabled }: IProps) {
|
||||||
const [isChecked, setIsChecked] = useState<boolean>(checked ? checked : false);
|
const [isChecked, setIsChecked] = useState<boolean>(checked ? checked : false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -21,9 +22,11 @@ export default function Switch({ onChange, checked, label }: IProps) {
|
|||||||
}, [isChecked, onChange]);
|
}, [isChecked, onChange]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes["root"]} onClick={handleChange}>
|
<div className={classes["root"]}>
|
||||||
<div className={classes["switch-container"]} data-checked={isChecked.toString()}>
|
<div className={disabled ? classes["disabled"] : classes["root"]} onClick={disabled ? () => {} : handleChange}>
|
||||||
<div className={classes["round"]} />
|
<div className={classes["switch-container"]} data-checked={isChecked.toString()}>
|
||||||
|
<div className={classes["round"]} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Typography typo={ITypo.P_ERR_16} color={ITypoColor.BLACK}>
|
<Typography typo={ITypo.P_ERR_16} color={ITypoColor.BLACK}>
|
||||||
{label}
|
{label}
|
||||||
|
@ -7,6 +7,7 @@ type IProps = {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
color?: ITypoColor;
|
color?: ITypoColor;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
title?: string;
|
||||||
};
|
};
|
||||||
type IState = {};
|
type IState = {};
|
||||||
|
|
||||||
@ -50,7 +51,8 @@ export default class Typography extends React.Component<IProps, IState> {
|
|||||||
classes[this.props.typo],
|
classes[this.props.typo],
|
||||||
classes[this.props.color ?? ""],
|
classes[this.props.color ?? ""],
|
||||||
this.props.className ?? "",
|
this.props.className ?? "",
|
||||||
)}>
|
)}
|
||||||
|
title={this.props.title}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
45
src/front/Components/Elements/Rules/index.tsx
Normal file
45
src/front/Components/Elements/Rules/index.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import React, { useCallback, useEffect } from "react";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import Module from "@Front/Config/Module";
|
||||||
|
import JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
|
import { IAppRule } from "@Front/Api/Entities/rule";
|
||||||
|
|
||||||
|
export enum RulesMode {
|
||||||
|
OPTIONAL = "optional",
|
||||||
|
NECESSARY = "necessary",
|
||||||
|
}
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
isPage?: boolean;
|
||||||
|
mode: RulesMode;
|
||||||
|
rules: IAppRule[];
|
||||||
|
no?: boolean;
|
||||||
|
children: JSX.Element;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Rules(props: IProps) {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const getShowValue = useCallback(() => {
|
||||||
|
if (props.mode === RulesMode.NECESSARY) {
|
||||||
|
return props.rules.every((rule) => JwtService.getInstance().hasRule(rule.name, rule.action));
|
||||||
|
}
|
||||||
|
return !!props.rules.find((rule) => JwtService.getInstance().hasRule(rule.name, rule.action));
|
||||||
|
}, [props.mode, props.rules]);
|
||||||
|
|
||||||
|
const show = getShowValue();
|
||||||
|
const [isShowing, setIsShowing] = React.useState(props.no ? !show : show);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsShowing(props.no ? !show : show);
|
||||||
|
}, [props.no, show]);
|
||||||
|
|
||||||
|
if (!isShowing && props.isPage) {
|
||||||
|
router.push(Module.getInstance().get().modules.pages.Home.props.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!JwtService.getInstance().decodeJwt() || !isShowing) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return props.children;
|
||||||
|
}
|
@ -7,7 +7,7 @@ import BackArrow from "@Front/Components/Elements/BackArrow";
|
|||||||
import JwtService from "@Front/Services/JwtService/JwtService";
|
import JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
import WindowStore from "@Front/Stores/WindowStore";
|
import WindowStore from "@Front/Stores/WindowStore";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import User from "le-coffre-resources/dist/Notary";
|
import User from "le-coffre-resources/dist/Admin";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ export default class DefaultCollaboratorDashboard extends React.Component<IProps
|
|||||||
const jwt = JwtService.getInstance().decodeJwt();
|
const jwt = JwtService.getInstance().decodeJwt();
|
||||||
if (!jwt) return;
|
if (!jwt) return;
|
||||||
const query: IGetUsersparams = {
|
const query: IGetUsersparams = {
|
||||||
where: { office_uid: jwt!.office_Id },
|
where: { office_uid: jwt.office_Id },
|
||||||
include: { contact: true },
|
include: { contact: true },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
import DeedTypes, { IGetDeedTypesParams } from "@Front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes";
|
import DeedTypes, { IGetDeedTypesParams } from "@Front/Api/LeCoffreApi/Notary/DeedTypes/DeedTypes";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import Header from "@Front/Components/DesignSystem/Header";
|
import Header from "@Front/Components/DesignSystem/Header";
|
||||||
import Version from "@Front/Components/DesignSystem/Version";
|
import Version from "@Front/Components/DesignSystem/Version";
|
||||||
import BackArrow from "@Front/Components/Elements/BackArrow";
|
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 { Deed, DeedType } from "le-coffre-resources/dist/Admin";
|
import { Deed, DeedType } from "le-coffre-resources/dist/Notary";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
import DocumentTypes from "@Front/Api/LeCoffreApi/SuperAdmin/DocumentTypes/DocumentTypes";
|
import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import Header from "@Front/Components/DesignSystem/Header";
|
import Header from "@Front/Components/DesignSystem/Header";
|
||||||
import Version from "@Front/Components/DesignSystem/Version";
|
import Version from "@Front/Components/DesignSystem/Version";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
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/Notary/Folders/Folders";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import FolderListContainer from "@Front/Components/DesignSystem/FolderListContainer";
|
import FolderListContainer from "@Front/Components/DesignSystem/FolderListContainer";
|
||||||
import Header from "@Front/Components/DesignSystem/Header";
|
import Header from "@Front/Components/DesignSystem/Header";
|
||||||
|
@ -6,7 +6,7 @@ import Version from "@Front/Components/DesignSystem/Version";
|
|||||||
import BackArrow from "@Front/Components/Elements/BackArrow";
|
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 User from "le-coffre-resources/dist/Notary";
|
import User from "le-coffre-resources/dist/SuperAdmin";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
|
|
||||||
|
@ -25,8 +25,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.folder-number {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.office-name {
|
||||||
|
margin-top: 8px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
.subtitle {
|
.subtitle {
|
||||||
margin: 32px 0;
|
margin: 64px 0 32px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,9 +52,6 @@
|
|||||||
@media (max-width: $screen-s) {
|
@media (max-width: $screen-s) {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.component-to-replace {
|
.component-to-replace {
|
||||||
@ -78,9 +84,6 @@
|
|||||||
background-color: var(--grey-soft);
|
background-color: var(--grey-soft);
|
||||||
height: 98px;
|
height: 98px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -3,16 +3,16 @@ import Customers from "@Front/Api/LeCoffreApi/Customer/Customers/Customers";
|
|||||||
import Documents, { IGetDocumentsparams } from "@Front/Api/LeCoffreApi/Customer/Documents/Documents";
|
import Documents, { IGetDocumentsparams } from "@Front/Api/LeCoffreApi/Customer/Documents/Documents";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import DepositDocument from "@Front/Components/DesignSystem/DepositDocument";
|
import DepositDocument from "@Front/Components/DesignSystem/DepositDocument";
|
||||||
import TextField from "@Front/Components/DesignSystem/Form/TextField";
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
|
||||||
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
|
||||||
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
||||||
import Customer, { Document, DocumentType } from "le-coffre-resources/dist/Customer";
|
import Customer, { Document, DocumentType, OfficeFolder } from "le-coffre-resources/dist/Customer";
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import JwtService from "@Front/Services/JwtService/JwtService";
|
import JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
|
import DepositOtherDocument from "@Front/Components/DesignSystem/DepositOtherDocument";
|
||||||
|
import Folders from "@Front/Api/LeCoffreApi/Customer/Folders/Folders";
|
||||||
|
|
||||||
type IProps = {};
|
type IProps = {};
|
||||||
|
|
||||||
@ -21,9 +21,12 @@ export default function ClientDashboard(props: IProps) {
|
|||||||
let { folderUid } = router.query;
|
let { folderUid } = router.query;
|
||||||
const [documents, setDocuments] = useState<Document[] | null>(null);
|
const [documents, setDocuments] = useState<Document[] | null>(null);
|
||||||
const [customer, setCustomer] = useState<Customer | null>(null);
|
const [customer, setCustomer] = useState<Customer | null>(null);
|
||||||
|
const [folder, setFolder] = useState<OfficeFolder | null>(null);
|
||||||
const [isAddDocumentModalVisible, setIsAddDocumentModalVisible] = useState<boolean>(false);
|
const [isAddDocumentModalVisible, setIsAddDocumentModalVisible] = useState<boolean>(false);
|
||||||
|
|
||||||
const onCloseModalAddDocument = useCallback(() => {
|
const onCloseModalAddDocument = useCallback(() => {
|
||||||
|
console.log("Closing");
|
||||||
|
|
||||||
setIsAddDocumentModalVisible(false);
|
setIsAddDocumentModalVisible(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -55,6 +58,8 @@ export default function ClientDashboard(props: IProps) {
|
|||||||
|
|
||||||
const documentList = await Documents.getInstance().get(query);
|
const documentList = await Documents.getInstance().get(query);
|
||||||
|
|
||||||
|
const folder = await Folders.getInstance().getByUid(folderUid as string, { q: { office: true } });
|
||||||
|
setFolder(folder);
|
||||||
setDocuments(documentList);
|
setDocuments(documentList);
|
||||||
setCustomer(actualCustomer);
|
setCustomer(actualCustomer);
|
||||||
}
|
}
|
||||||
@ -63,6 +68,7 @@ export default function ClientDashboard(props: IProps) {
|
|||||||
}, [folderUid]);
|
}, [folderUid]);
|
||||||
|
|
||||||
const renderHeader = useCallback(() => {
|
const renderHeader = useCallback(() => {
|
||||||
|
console.log("Dossier : ", customer);
|
||||||
return (
|
return (
|
||||||
<div className={classes["header"]}>
|
<div className={classes["header"]}>
|
||||||
<div className={classes["text-container"]}>
|
<div className={classes["text-container"]}>
|
||||||
@ -71,6 +77,14 @@ export default function ClientDashboard(props: IProps) {
|
|||||||
Bonjour {customer?.contact?.first_name.concat(" ", customer?.contact?.last_name)}
|
Bonjour {customer?.contact?.first_name.concat(" ", customer?.contact?.last_name)}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
|
<Typography typo={ITypo.P_SB_18} className={classes["folder-number"]} color={ITypoColor.GREY}>
|
||||||
|
Dossier {folder?.folder_number} - {folder?.name}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<Typography typo={ITypo.P_SB_18} className={classes["office-name"]} color={ITypoColor.GREY}>
|
||||||
|
{folder?.office?.name}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
<Typography typo={ITypo.H2} className={classes["subtitle"]}>
|
<Typography typo={ITypo.H2} className={classes["subtitle"]}>
|
||||||
Documents à envoyer
|
Documents à envoyer
|
||||||
</Typography>
|
</Typography>
|
||||||
@ -89,6 +103,24 @@ export default function ClientDashboard(props: IProps) {
|
|||||||
);
|
);
|
||||||
}, [customer]);
|
}, [customer]);
|
||||||
|
|
||||||
|
const renderBox = useCallback(() => {
|
||||||
|
console.log(isAddDocumentModalVisible);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DepositOtherDocument
|
||||||
|
folder_uid={folderUid!}
|
||||||
|
customer_uid={customer!.uid!}
|
||||||
|
open={isAddDocumentModalVisible}
|
||||||
|
onClose={onCloseModalAddDocument}
|
||||||
|
document={Document.hydrate<Document>({
|
||||||
|
document_type: DocumentType.hydrate<DocumentType>({
|
||||||
|
name: "Document annexe",
|
||||||
|
}),
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}, [customer, folderUid, isAddDocumentModalVisible, onCloseModalAddDocument]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultTemplate title={"Mon compte"} isPadding={false} hasHeaderLinks={false}>
|
<DefaultTemplate title={"Mon compte"} isPadding={false} hasHeaderLinks={false}>
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
@ -107,33 +139,8 @@ export default function ClientDashboard(props: IProps) {
|
|||||||
Ajouter d'autres documents
|
Ajouter d'autres documents
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Confirm
|
|
||||||
isOpen={isAddDocumentModalVisible}
|
|
||||||
onClose={onCloseModalAddDocument}
|
|
||||||
onAccept={onOpenModalAddDocument}
|
|
||||||
closeBtn
|
|
||||||
header={"Ajouter un document"}
|
|
||||||
cancelText={"Annuler"}
|
|
||||||
confirmText={"Déposer le document"}>
|
|
||||||
<div className={classes["modal-content"]}>
|
|
||||||
<Typography typo={ITypo.P_16} className={classes["text"]}>
|
|
||||||
Vous souhaitez envoyer un autre document à votre notaire ?
|
|
||||||
</Typography>
|
|
||||||
<TextField placeholder="Nom du document" />
|
|
||||||
<Typography typo={ITypo.P_16} className={classes["text"]}>
|
|
||||||
Glissez / Déposez votre document dans la zone prévue à cet effet ou cliquez sur la zone puis sélectionnez le
|
|
||||||
document correspondant.
|
|
||||||
</Typography>
|
|
||||||
<DepositDocument
|
|
||||||
document={Document.hydrate<Document>({
|
|
||||||
document_type: DocumentType.hydrate<DocumentType>({
|
|
||||||
name: "Document annexe",
|
|
||||||
}),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Confirm>
|
|
||||||
</div>
|
</div>
|
||||||
|
{isAddDocumentModalVisible && renderBox()}
|
||||||
</DefaultTemplate>
|
</DefaultTemplate>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -117,12 +117,6 @@ export default function DeedTypesInformations(props: IProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className={classes["deed-type-container"]}>
|
<div className={classes["deed-type-container"]}>
|
||||||
<div className={classes["infos"]}>
|
<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"])}>
|
<div className={classNames(classes["middle-box"], classes["box"])}>
|
||||||
<Typography typo={ITypo.NAV_INPUT_16} className={classes["box-title"]} color={ITypoColor.BLACK}>
|
<Typography typo={ITypo.NAV_INPUT_16} className={classes["box-title"]} color={ITypoColor.BLACK}>
|
||||||
Description
|
Description
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import DocumentTypes from "@Front/Api/LeCoffreApi/Admin/DocumentTypes/DocumentTypes";
|
import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes";
|
||||||
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 TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
|
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
|
||||||
@ -8,7 +8,7 @@ import DefaultDocumentTypesDashboard from "@Front/Components/LayoutTemplates/Def
|
|||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import JwtService from "@Front/Services/JwtService/JwtService";
|
import JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
import { validateOrReject, ValidationError } from "class-validator";
|
import { validateOrReject, ValidationError } from "class-validator";
|
||||||
import { DocumentType, Office } from "le-coffre-resources/dist/Admin";
|
import { DocumentType, Office } from "le-coffre-resources/dist/Notary";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
|
|
||||||
@ -24,11 +24,12 @@ export default function DocumentTypesCreate(props: IProps) {
|
|||||||
try {
|
try {
|
||||||
const jwt = JwtService.getInstance().decodeJwt();
|
const jwt = JwtService.getInstance().decodeJwt();
|
||||||
if (!jwt) return;
|
if (!jwt) return;
|
||||||
|
const office = Office.hydrate<Office>({
|
||||||
|
uid: jwt.office_Id,
|
||||||
|
});
|
||||||
const documentToCreate = DocumentType.hydrate<DocumentType>({
|
const documentToCreate = DocumentType.hydrate<DocumentType>({
|
||||||
...values,
|
...values,
|
||||||
office: Office.hydrate<Office>({
|
office: office
|
||||||
uid: jwt.office_Id,
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
await validateOrReject(documentToCreate, { groups: ["createDocumentType"] });
|
await validateOrReject(documentToCreate, { groups: ["createDocumentType"] });
|
||||||
const documentTypeCreated = await DocumentTypes.getInstance().post(documentToCreate);
|
const documentTypeCreated = await DocumentTypes.getInstance().post(documentToCreate);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import DocumentTypes from "@Front/Api/LeCoffreApi/Admin/DocumentTypes/DocumentTypes";
|
import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes";
|
||||||
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 TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
|
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
|
||||||
@ -7,7 +7,7 @@ import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
|||||||
import DefaultDocumentTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDocumentTypesDashboard";
|
import DefaultDocumentTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDocumentTypesDashboard";
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import { validateOrReject } from "class-validator";
|
import { validateOrReject } from "class-validator";
|
||||||
import { DocumentType } from "le-coffre-resources/dist/Admin";
|
import { DocumentType } from "le-coffre-resources/dist/Notary";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import PenICon from "@Assets/Icons/pen.svg";
|
import PenICon from "@Assets/Icons/pen.svg";
|
||||||
import DocumentTypes from "@Front/Api/LeCoffreApi/Admin/DocumentTypes/DocumentTypes";
|
import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes";
|
||||||
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
import DefaultDocumentTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDocumentTypesDashboard";
|
import DefaultDocumentTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDocumentTypesDashboard";
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import { DocumentType } from "le-coffre-resources/dist/Admin";
|
import { DocumentType } from "le-coffre-resources/dist/Notary";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Customers from "@Front/Api/LeCoffreApi/SuperAdmin/Customers/Customers";
|
import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers";
|
||||||
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/Notary/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 { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import PlusIcon from "@Assets/Icons/plus.svg";
|
import PlusIcon from "@Assets/Icons/plus.svg";
|
||||||
import Deeds from "@Front/Api/LeCoffreApi/SuperAdmin/Deeds/Deeds";
|
import Deeds from "@Front/Api/LeCoffreApi/Notary/Deeds/Deeds";
|
||||||
import Documents from "@Front/Api/LeCoffreApi/SuperAdmin/Documents/Documents";
|
import Documents from "@Front/Api/LeCoffreApi/Notary/Documents/Documents";
|
||||||
import DocumentTypes from "@Front/Api/LeCoffreApi/SuperAdmin/DocumentTypes/DocumentTypes";
|
import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes";
|
||||||
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
|
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
|
||||||
import Form from "@Front/Components/DesignSystem/Form";
|
import Form from "@Front/Components/DesignSystem/Form";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import backgroundImage from "@Assets/images/404-background-image.jpeg";
|
import backgroundImage from "@Assets/images/404-background-image.jpeg";
|
||||||
import DeedTypes from "@Front/Api/LeCoffreApi/SuperAdmin/DeedTypes/DeedTypes";
|
import DeedTypes from "@Front/Api/LeCoffreApi/Notary/DeedTypes/DeedTypes";
|
||||||
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders";
|
||||||
import Users from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
|
import Users from "@Front/Api/LeCoffreApi/Notary/Users/Users";
|
||||||
import Button from "@Front/Components/DesignSystem/Button";
|
import Button from "@Front/Components/DesignSystem/Button";
|
||||||
import Form from "@Front/Components/DesignSystem/Form";
|
import Form from "@Front/Components/DesignSystem/Form";
|
||||||
import SelectField, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
import SelectField, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
||||||
@ -152,13 +152,8 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
|
|
||||||
public override async componentDidMount() {
|
public override async componentDidMount() {
|
||||||
const deedTypes = await DeedTypes.getInstance().get();
|
const deedTypes = await DeedTypes.getInstance().get();
|
||||||
|
// no need to pass query 'where' param here, default query for notaries include only users which are in the same office as the caller
|
||||||
// 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 userMock = usersMock[0];
|
|
||||||
// -------------------
|
|
||||||
const collaborators = await Users.getInstance().get({
|
const collaborators = await Users.getInstance().get({
|
||||||
where: { office_membership: { uid: userMock?.office_membership?.uid } },
|
|
||||||
include: { contact: true },
|
include: { contact: true },
|
||||||
});
|
});
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/Notary/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 TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import Customers from "@Front/Api/LeCoffreApi/SuperAdmin/Customers/Customers";
|
import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers";
|
||||||
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 TextField from "@Front/Components/DesignSystem/Form/TextField";
|
import TextField from "@Front/Components/DesignSystem/Form/TextField";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders";
|
||||||
import Users, { IGetUsersparams } from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
|
import Users, { IGetUsersParams } from "@Front/Api/LeCoffreApi/Notary/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 { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
||||||
@ -127,10 +127,8 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userQuery: IGetUsersparams = {
|
// no need to pass query 'where' param here, default query for notaries include only users which are in the same office as the caller
|
||||||
where: {
|
const userQuery: IGetUsersParams = {
|
||||||
office_uid: folder.office?.uid,
|
|
||||||
},
|
|
||||||
include: {
|
include: {
|
||||||
contact: {
|
contact: {
|
||||||
select: {
|
select: {
|
||||||
@ -142,6 +140,7 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const availableCollaborators = await Users.getInstance().get(userQuery);
|
const availableCollaborators = await Users.getInstance().get(userQuery);
|
||||||
|
console.log(availableCollaborators)
|
||||||
this.setState({ availableCollaborators });
|
this.setState({ availableCollaborators });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/Notary/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 TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
|
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/Notary/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 Select, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
import Select, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import LeftArrowIcon from "@Assets/Icons/left-arrow.svg";
|
import LeftArrowIcon from "@Assets/Icons/left-arrow.svg";
|
||||||
import RightArrowIcon from "@Assets/Icons/right-arrow.svg";
|
import RightArrowIcon from "@Assets/Icons/right-arrow.svg";
|
||||||
import Documents from "@Front/Api/LeCoffreApi/SuperAdmin/Documents/Documents";
|
import Documents from "@Front/Api/LeCoffreApi/Notary/Documents/Documents";
|
||||||
import ValidateAnchoringGif from "@Front/Assets/images/validate_anchoring.gif";
|
import ValidateAnchoringGif from "@Front/Assets/images/validate_anchoring.gif";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
|
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
|
||||||
@ -9,8 +9,8 @@ import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
|||||||
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
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 { Document, File } from "le-coffre-resources/dist/Customer";
|
import { Document, File } from "le-coffre-resources/dist/Notary";
|
||||||
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
|
import { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { NextRouter, useRouter } from "next/router";
|
import { NextRouter, useRouter } from "next/router";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
||||||
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/Notary/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 QuantityProgressBar from "@Front/Components/DesignSystem/QuantityProgressBar";
|
import QuantityProgressBar from "@Front/Components/DesignSystem/QuantityProgressBar";
|
||||||
|
@ -19,7 +19,10 @@ export default function Login() {
|
|||||||
const redirectUserOnConnection = useCallback(() => {
|
const redirectUserOnConnection = useCallback(() => {
|
||||||
async function getUser() {
|
async function getUser() {
|
||||||
try {
|
try {
|
||||||
|
// Super admin
|
||||||
await UserStore.instance.connect("jelkvelknvlkn");
|
await UserStore.instance.connect("jelkvelknvlkn");
|
||||||
|
// Notaire
|
||||||
|
// await UserStore.instance.connect("ljfeflecnmd");
|
||||||
await JwtService.getInstance().checkJwt();
|
await JwtService.getInstance().checkJwt();
|
||||||
router.push(Module.getInstance().get().modules.pages.Folder.props.path);
|
router.push(Module.getInstance().get().modules.pages.Folder.props.path);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -6,11 +6,23 @@ import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import User from "le-coffre-resources/dist/Notary";
|
||||||
|
import Users from "@Front/Api/LeCoffreApi/Notary/Users/Users";
|
||||||
|
import JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
|
|
||||||
type IProps = {};
|
type IProps = {};
|
||||||
type IState = {};
|
type IState = {
|
||||||
|
user: User | null;
|
||||||
|
};
|
||||||
|
|
||||||
export default class MyAccount extends Base<IProps, IState> {
|
export default class MyAccount extends Base<IProps, IState> {
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
user: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public override render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<DefaultTemplate title={"Mon compte"}>
|
<DefaultTemplate title={"Mon compte"}>
|
||||||
@ -25,19 +37,33 @@ export default class MyAccount extends Base<IProps, IState> {
|
|||||||
</Typography>
|
</Typography>
|
||||||
<Form onSubmit={this.onFormSubmit}>
|
<Form onSubmit={this.onFormSubmit}>
|
||||||
<div className={classes["form-container"]}>
|
<div className={classes["form-container"]}>
|
||||||
<TextField name="name" placeholder="Nom" defaultValue={"BIHR"} disabled />
|
<TextField
|
||||||
<TextField name="surname" placeholder="Prénom" defaultValue={"Nicolas"} disabled />
|
name="name"
|
||||||
|
placeholder="Nom"
|
||||||
|
defaultValue={this.state.user?.contact?.last_name}
|
||||||
|
disabled
|
||||||
|
canCopy
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
name="surname"
|
||||||
|
placeholder="Prénom"
|
||||||
|
defaultValue={this.state.user?.contact?.first_name}
|
||||||
|
disabled
|
||||||
|
canCopy
|
||||||
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
name="email"
|
name="email"
|
||||||
placeholder="E-mail"
|
placeholder="E-mail"
|
||||||
defaultValue={"nicolas.bihr@notaires.fr"}
|
defaultValue={this.state.user?.contact?.email}
|
||||||
disabled
|
disabled
|
||||||
|
canCopy
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
name="phone"
|
name="phone"
|
||||||
placeholder="Numéro de téléphone"
|
placeholder="Numéro de téléphone"
|
||||||
defaultValue={"06 74 83 90 23"}
|
defaultValue={this.state.user?.contact?.phone_number as string}
|
||||||
disabled
|
disabled
|
||||||
|
canCopy
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
@ -51,21 +77,34 @@ export default class MyAccount extends Base<IProps, IState> {
|
|||||||
<TextField
|
<TextField
|
||||||
name="office_denomination"
|
name="office_denomination"
|
||||||
placeholder="Dénomination de l'office"
|
placeholder="Dénomination de l'office"
|
||||||
defaultValue="Etude Office notarial du Cormier"
|
defaultValue={this.state.user?.office_membership?.name}
|
||||||
disabled
|
disabled
|
||||||
|
canCopy
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
name="crpcen"
|
||||||
|
placeholder="CRPCEN"
|
||||||
|
defaultValue={this.state.user?.office_membership?.crpcen}
|
||||||
|
disabled
|
||||||
|
canCopy
|
||||||
/>
|
/>
|
||||||
<TextField name="crpcen" placeholder="CRPCEN" defaultValue="35137" disabled />
|
|
||||||
<TextField
|
<TextField
|
||||||
name="cp_address"
|
name="cp_address"
|
||||||
placeholder="Adresse CP"
|
placeholder="Adresse CP"
|
||||||
defaultValue="2 RUE DE RENNES"
|
defaultValue={this.state.user?.office_membership?.address?.address}
|
||||||
disabled
|
disabled
|
||||||
|
canCopy
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
name="city"
|
name="city"
|
||||||
placeholder="Ville"
|
placeholder="Ville"
|
||||||
defaultValue="35140 ST AUBIN DU CORMIER"
|
defaultValue={
|
||||||
|
this.state.user?.office_membership?.address?.zip_code +
|
||||||
|
" - " +
|
||||||
|
this.state.user?.office_membership?.address?.city
|
||||||
|
}
|
||||||
disabled
|
disabled
|
||||||
|
canCopy
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
@ -76,10 +115,29 @@ export default class MyAccount extends Base<IProps, IState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async componentDidMount() {
|
||||||
|
const jwtUncoded = JwtService.getInstance().decodeCustomerJwt();
|
||||||
|
console.log(jwtUncoded);
|
||||||
|
if (!jwtUncoded) return;
|
||||||
|
const user = await Users.getInstance().getByUid(jwtUncoded.userId, {
|
||||||
|
q: {
|
||||||
|
office_membership: {
|
||||||
|
include: {
|
||||||
|
address: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
contact: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!user) return;
|
||||||
|
this.setState({
|
||||||
|
user,
|
||||||
|
});
|
||||||
|
}
|
||||||
private onFormSubmit(
|
private onFormSubmit(
|
||||||
e: React.FormEvent<HTMLFormElement> | null,
|
e: React.FormEvent<HTMLFormElement> | null,
|
||||||
values: {
|
values: {
|
||||||
[key: string]: string;
|
[key: string]: string;
|
||||||
}
|
},
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
29
src/front/Components/Layouts/Protect/classes.module.scss
Normal file
29
src/front/Components/Layouts/Protect/classes.module.scss
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
max-width: 530px;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin: 32px 0;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
@media (max-width: $screen-s) {
|
||||||
|
font-family: 48px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.forget-password {
|
||||||
|
margin-top: 32px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
57
src/front/Components/Layouts/Protect/index.tsx
Normal file
57
src/front/Components/Layouts/Protect/index.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import Module from "@Front/Config/Module";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { useState } from "react";
|
||||||
|
import Image from "next/image";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import LandingImage from "./landing-connect.jpeg";
|
||||||
|
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
|
||||||
|
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
import CoffreIcon from "@Assets/Icons/coffre.svg";
|
||||||
|
import TextField from "@Front/Components/DesignSystem/Form/TextField";
|
||||||
|
import Button from "@Front/Components/DesignSystem/Button";
|
||||||
|
|
||||||
|
export default function Protect() {
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const router = useRouter();
|
||||||
|
const setPasswordFromInput = (event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
|
||||||
|
setPassword(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitAuth = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (password === "team-fullstack") {
|
||||||
|
console.log("ok");
|
||||||
|
setCookie("protect_staging", Date.now().toString());
|
||||||
|
router.push(Module.getInstance().get().modules.pages.Login.props.path);
|
||||||
|
} else {
|
||||||
|
console.log("pas ok");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const setCookie = (name: string, value: string) => {
|
||||||
|
if (!name || !value) throw new Error("Cookie name or value is empty");
|
||||||
|
const date = new Date();
|
||||||
|
|
||||||
|
// Set it expire in 7 days
|
||||||
|
date.setTime(date.getTime() + 7 * 24 * 60 * 60 * 1000);
|
||||||
|
|
||||||
|
// Set it
|
||||||
|
document.cookie = name + "=" + value + "; expires=" + date.toUTCString() + "; path=/";
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultDoubleSidePage title={"Login"} image={LandingImage}>
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<Image alt="coffre" src={CoffreIcon} />
|
||||||
|
<Typography typo={ITypo.H1}>
|
||||||
|
<div className={classes["title"]}>Le site est verrouillé</div>
|
||||||
|
</Typography>
|
||||||
|
<form onSubmit={submitAuth} className={classes["form"]}>
|
||||||
|
<TextField placeholder="Password" onChange={setPasswordFromInput} password />
|
||||||
|
<Button type="submit">Submit</Button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</DefaultDoubleSidePage>
|
||||||
|
);
|
||||||
|
}
|
BIN
src/front/Components/Layouts/Protect/landing-connect.jpeg
Normal file
BIN
src/front/Components/Layouts/Protect/landing-connect.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 MiB |
@ -16,15 +16,16 @@ export default function SelectFolder() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getFolders() {
|
async function getFolders() {
|
||||||
const jwt = JwtService.getInstance().decodeJwt();
|
const jwt = JwtService.getInstance().decodeCustomerJwt();
|
||||||
if (!jwt) return;
|
if (!jwt) return;
|
||||||
|
console.log(jwt)
|
||||||
|
|
||||||
const folders = await Folders.getInstance().get({
|
const folders = await Folders.getInstance().get({
|
||||||
q: {
|
q: {
|
||||||
where: {
|
where: {
|
||||||
customers: {
|
customers: {
|
||||||
some: {
|
some: {
|
||||||
uid: jwt.userId,
|
uid: jwt.customerId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -37,8 +38,8 @@ export default function SelectFolder() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSelectBlock = useCallback(
|
const handleSelectBlock = useCallback(
|
||||||
(block: IBlock) => {
|
(folder: IBlock) => {
|
||||||
router.push("/client-dashboard/" + block.id);
|
router.push("/client-dashboard/" + folder.id);
|
||||||
},
|
},
|
||||||
[router],
|
[router],
|
||||||
);
|
);
|
||||||
|
@ -81,7 +81,7 @@ export default function UserInformations(props: IProps) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!userSelected) return;
|
if (!userSelected) return;
|
||||||
setCurrentAppointment(userSelected?.appointment?.find((appointment) => appointment.status === EAppointmentStatus.OPEN) ?? null);
|
setCurrentAppointment(userSelected?.appointment?.find((appointment) => appointment.status === EAppointmentStatus.OPEN && appointment.votes?.length != 0) ?? null);
|
||||||
}, [userSelected]);
|
}, [userSelected]);
|
||||||
|
|
||||||
/** Functions for the admin modal */
|
/** Functions for the admin modal */
|
||||||
@ -282,7 +282,7 @@ export default function UserInformations(props: IProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className={classes["second-line"]}>
|
<div className={classes["second-line"]}>
|
||||||
<Switch label="Admin de son office" checked={isAdminChecked} onChange={handleAdminChanged} />
|
<Switch label="Admin de son office" checked={isAdminChecked} onChange={handleAdminChanged} />
|
||||||
<Switch label="Super-admin LeCoffre.io" checked={isSuperAdminChecked} onChange={handleSuperAdminChanged} />
|
<Switch label="Super-admin LeCoffre.io" checked={isSuperAdminChecked} disabled={userHasVoted()} onChange={handleSuperAdminChanged} />
|
||||||
{currentAppointment && (
|
{currentAppointment && (
|
||||||
<div className={classes["votes-block"]}>
|
<div className={classes["votes-block"]}>
|
||||||
<div className={classes["left"]}>
|
<div className={classes["left"]}>
|
||||||
|
@ -6,7 +6,7 @@ enum PROVIDER_OPENID {
|
|||||||
idNot = "idNot",
|
idNot = "idNot",
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IUserJwtPayload {
|
export interface IUserJwtPayload {
|
||||||
userId: string;
|
userId: string;
|
||||||
email: string | null;
|
email: string | null;
|
||||||
openId: {
|
openId: {
|
||||||
@ -19,6 +19,11 @@ interface IUserJwtPayload {
|
|||||||
exp: number;
|
exp: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ICustomerJwtPayload {
|
||||||
|
userId: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
export default class JwtService {
|
export default class JwtService {
|
||||||
private static instance: JwtService;
|
private static instance: JwtService;
|
||||||
private constructor() {}
|
private constructor() {}
|
||||||
@ -33,6 +38,12 @@ export default class JwtService {
|
|||||||
return jwt_decode(accessToken);
|
return jwt_decode(accessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public decodeCustomerJwt(): ICustomerJwtPayload | undefined {
|
||||||
|
const accessToken = CookieService.getInstance().getCookie("leCoffreAccessToken");
|
||||||
|
if (!accessToken) return;
|
||||||
|
return jwt_decode(accessToken);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description : set a cookie with a name and a value that expire in 7 days
|
* @description : set a cookie with a name and a value that expire in 7 days
|
||||||
* @throws {Error} If the name or the value is empty
|
* @throws {Error} If the name or the value is empty
|
||||||
@ -55,4 +66,12 @@ export default class JwtService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public hasRule(name: string, action: string) {
|
||||||
|
const accessToken = CookieService.getInstance().getCookie("leCoffreAccessToken");
|
||||||
|
if (!accessToken) return false;
|
||||||
|
const decodedToken = this.decodeJwt();
|
||||||
|
if (!decodedToken) return false;
|
||||||
|
return decodedToken?.rules?.some((rule: string) => rule === `${action} ${name}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import User from "@Front/Api/Auth/IdNot/User";
|
|||||||
import Customer from "@Front/Api/Auth/franceConnect/Customer";
|
import Customer from "@Front/Api/Auth/franceConnect/Customer";
|
||||||
import CookieService from "@Front/Services/CookieService/CookieService";
|
import CookieService from "@Front/Services/CookieService/CookieService";
|
||||||
import EventEmitter from "@Front/Services/EventEmitter";
|
import EventEmitter from "@Front/Services/EventEmitter";
|
||||||
|
import JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
|
|
||||||
export default class UserStore {
|
export default class UserStore {
|
||||||
public static readonly instance = new this();
|
public static readonly instance = new this();
|
||||||
@ -17,6 +18,11 @@ export default class UserStore {
|
|||||||
return !!this.accessToken;
|
return !!this.accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getRole(): string | undefined {
|
||||||
|
const decodedPayload = JwtService.getInstance().decodeJwt();
|
||||||
|
return decodedPayload?.role;
|
||||||
|
}
|
||||||
|
|
||||||
public async connect(idnotUid: string) {
|
public async connect(idnotUid: string) {
|
||||||
try {
|
try {
|
||||||
//call connection function
|
//call connection function
|
||||||
|
61
src/middleware.ts
Normal file
61
src/middleware.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { ICustomerJwtPayload, IUserJwtPayload } from "@Front/Services/JwtService/JwtService";
|
||||||
|
import jwt_decode from "jwt-decode";
|
||||||
|
import { NextResponse } from "next/server";
|
||||||
|
import type { NextRequest } from "next/server";
|
||||||
|
|
||||||
|
export async function middleware(request: NextRequest) {
|
||||||
|
const cookieStaging = request.cookies.get("protect_staging");
|
||||||
|
if (!cookieStaging) return NextResponse.redirect(new URL("/protect", request.url));
|
||||||
|
|
||||||
|
// Get the JWT from the cookies
|
||||||
|
const cookies = request.cookies.get("leCoffreAccessToken");
|
||||||
|
if (!cookies) return NextResponse.redirect(new URL("/login", request.url));
|
||||||
|
|
||||||
|
// Decode it
|
||||||
|
const userDecodedToken = jwt_decode(cookies.value) as IUserJwtPayload;
|
||||||
|
const customerDecodedToken = jwt_decode(cookies.value) as ICustomerJwtPayload;
|
||||||
|
|
||||||
|
// If no JWT provided, redirect to login page
|
||||||
|
if (!userDecodedToken && !customerDecodedToken) return NextResponse.redirect(new URL("/login", request.url));
|
||||||
|
|
||||||
|
// If JWT expired, redirect to login page
|
||||||
|
const token = userDecodedToken ?? customerDecodedToken;
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
if (token.exp < now) {
|
||||||
|
return NextResponse.redirect(new URL("/login", request.url));
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestUrlPath = request.nextUrl.pathname;
|
||||||
|
if (
|
||||||
|
requestUrlPath.startsWith("/collaborators") ||
|
||||||
|
requestUrlPath.startsWith("/deed-types") ||
|
||||||
|
requestUrlPath.startsWith("/customer") ||
|
||||||
|
requestUrlPath.startsWith("/offices") ||
|
||||||
|
requestUrlPath.startsWith("/roles") ||
|
||||||
|
requestUrlPath.startsWith("/users")
|
||||||
|
) {
|
||||||
|
if (userDecodedToken.role !== "admin" && userDecodedToken.role !== "super-admin")
|
||||||
|
return NextResponse.redirect(new URL("/404", request.url));
|
||||||
|
}
|
||||||
|
if ((requestUrlPath.startsWith("/my-account") || requestUrlPath.startsWith("/document-types")) && !userDecodedToken)
|
||||||
|
return NextResponse.redirect(new URL("/404", request.url));
|
||||||
|
if (requestUrlPath.startsWith("/client-dashboard") && !customerDecodedToken) return NextResponse.redirect(new URL("/404", request.url));
|
||||||
|
|
||||||
|
return NextResponse.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
matcher: [
|
||||||
|
"/client-dashboard/:path*",
|
||||||
|
"/collaborators/:path*",
|
||||||
|
"/customer/:path*",
|
||||||
|
"/document-types/:path*",
|
||||||
|
"/deed-types/:path*",
|
||||||
|
"/folders/:path*",
|
||||||
|
"/my-account/:path*",
|
||||||
|
"/offices/:path*",
|
||||||
|
"/roles/:path*",
|
||||||
|
"/users/:path*",
|
||||||
|
"/",
|
||||||
|
],
|
||||||
|
};
|
5
src/pages/protect.tsx
Normal file
5
src/pages/protect.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import Protect from "@Front/Components/Layouts/Protect";
|
||||||
|
|
||||||
|
export default function Route() {
|
||||||
|
return <Protect />;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user