🎨 format all documents

This commit is contained in:
Hugo Lextrait 2023-02-27 15:04:51 +01:00
parent c4659e99e8
commit ff0e493b67
110 changed files with 2017 additions and 2050 deletions

View File

@ -4,6 +4,9 @@
"[typescript]": { "[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": { "[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
@ -13,6 +16,9 @@
"[javascript]": { "[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"terminal.integrated.env.linux": { "terminal.integrated.env.linux": {
"PATH": "${env:HOME}/elrondsdk/vendor-rust/bin:${env:HOME}/elrondsdk/erdpy-venv/bin:${env:HOME}/elrondsdk/vmtools:${env:HOME}/elrondsdk/nodejs/latest/bin:${env:PATH}", "PATH": "${env:HOME}/elrondsdk/vendor-rust/bin:${env:HOME}/elrondsdk/erdpy-venv/bin:${env:HOME}/elrondsdk/vmtools:${env:HOME}/elrondsdk/nodejs/latest/bin:${env:PATH}",
"VIRTUAL_ENV": "${env:HOME}/elrondsdk/erdpy-venv", "VIRTUAL_ENV": "${env:HOME}/elrondsdk/erdpy-venv",

24
package-lock.json generated
View File

@ -42,7 +42,8 @@
"@types/react": "^18.0.27", "@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10", "@types/react-dom": "^18.0.10",
"@types/uuid": "^9.0.0", "@types/uuid": "^9.0.0",
"nodemon": "^2.0.20" "nodemon": "^2.0.20",
"prettier": "2.8.4"
} }
}, },
"node_modules/@cspotcode/source-map-support": { "node_modules/@cspotcode/source-map-support": {
@ -1439,6 +1440,21 @@
"node": "^10 || ^12 || >=14" "node": "^10 || ^12 || >=14"
} }
}, },
"node_modules/prettier": {
"version": "2.8.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz",
"integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prisma": { "node_modules/prisma": {
"version": "4.9.0", "version": "4.9.0",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.9.0.tgz", "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.9.0.tgz",
@ -3437,6 +3453,12 @@
"source-map-js": "^1.0.2" "source-map-js": "^1.0.2"
} }
}, },
"prettier": {
"version": "2.8.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz",
"integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==",
"dev": true
},
"prisma": { "prisma": {
"version": "4.9.0", "version": "4.9.0",
"resolved": "https://registry.npmjs.org/prisma/-/prisma-4.9.0.tgz", "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.9.0.tgz",

View File

@ -7,9 +7,9 @@
"@Front": "./dist/front/*", "@Front": "./dist/front/*",
"@Assets": "./dist/front/Assets/*", "@Assets": "./dist/front/Assets/*",
"@Components": "./dist/front/Components/*", "@Components": "./dist/front/Components/*",
"@Themes": "./dist/front/Themes/*", "@Themes": "./dist/front/Themes/*",
"@Stores": "./dist/front/Stores/*", "@Stores": "./dist/front/Stores/*",
"@FrontServices": "./dist/front/Services/*", "@FrontServices": "./dist/front/Services/*",
"@Pages": "./dist/pages", "@Pages": "./dist/pages",
"@Common": "./dist/common", "@Common": "./dist/common",
"@Services": "./dist/common/services", "@Services": "./dist/common/services",
@ -74,7 +74,8 @@
"@types/react": "^18.0.27", "@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10", "@types/react-dom": "^18.0.10",
"@types/uuid": "^9.0.0", "@types/uuid": "^9.0.0",
"nodemon": "^2.0.20" "nodemon": "^2.0.20",
"prettier": "2.8.4"
}, },
"prisma": { "prisma": {
"schema": "src/common/databases/schema.prisma" "schema": "src/common/databases/schema.prisma"

View File

@ -7,7 +7,7 @@ module.exports = {
useTabs: true, useTabs: true,
singleQuote: false, singleQuote: false,
trailingComma: "all", trailingComma: "all",
printWidth: 240, printWidth: 140,
semi: true, semi: true,
bracketSameLine: true, bracketSameLine: true,
}, },

View File

@ -61,4 +61,3 @@ export default class ProjectController extends ApiController {
this.httpCreated(res, await this.projectService.create(projectEntity)); this.httpCreated(res, await this.projectService.create(projectEntity));
} }
} }

View File

@ -2,7 +2,7 @@ import { Container } from "typedi";
import ProjectController from "./ProjectController"; import ProjectController from "./ProjectController";
export default { export default {
start: () => { start: () => {
Container.get(ProjectController); Container.get(ProjectController);
} },
} };

View File

@ -10,7 +10,7 @@ export default function errorHandler(error: any, req: Request, response: Respons
if (error instanceof SyntaxError && errorStatus === 400 && "body" in error) { if (error instanceof SyntaxError && errorStatus === 400 && "body" in error) {
response.status(HttpCodes.BAD_REQUEST).send({ response.status(HttpCodes.BAD_REQUEST).send({
body: error["body"], body: error["body"],
type: error as any ["type"], type: error as any["type"],
}); });
return; return;
} }
@ -22,4 +22,3 @@ export default function errorHandler(error: any, req: Request, response: Respons
next(error); next(error);
} }

View File

@ -1,4 +1,4 @@
export default interface IDatabaseConfig { export default interface IDatabaseConfig {
name: string; name: string;
url?: string; url?: string;
} }

View File

@ -26,4 +26,3 @@ export default class TezosLink {
return name; return name;
} }
} }

View File

@ -1,7 +1,7 @@
import { plainToClassFromExist } from "class-transformer"; import { plainToClassFromExist } from "class-transformer";
export default abstract class ObjectHydrate { export default abstract class ObjectHydrate {
public static hydrate<T = { [key: string]: any }>(object: { [key: string]: any }, from: { [key: string]: any }): T { public static hydrate<T = { [key: string]: any }>(object: { [key: string]: any }, from: { [key: string]: any }): T {
return plainToClassFromExist(object, from) as T; return plainToClassFromExist(object, from) as T;
} }
} }

View File

@ -64,7 +64,7 @@ export default class MetricRepository {
const data = { ...metricEntity }; const data = { ...metricEntity };
const result: MetricEntity[] = []; const result: MetricEntity[] = [];
this.instanceDb.$transaction(async(transaction: Prisma.TransactionClient) => { this.instanceDb.$transaction(async (transaction: Prisma.TransactionClient) => {
for (const item of data) { for (const item of data) {
if (!item) continue; if (!item) continue;
result.push( result.push(
@ -135,7 +135,7 @@ export default class MetricRepository {
const response = this.model.groupBy({ const response = this.model.groupBy({
by: ["date_requested"], by: ["date_requested"],
_count: { _count: {
date_requested: true, date_requested: true,
}, },
where: { where: {
projectId: projectId, projectId: projectId,
@ -187,4 +187,3 @@ export default class MetricRepository {
} }
} }
} }

View File

@ -24,14 +24,13 @@ export default class ProjectRepository {
const data = { ...projectEntity }; const data = { ...projectEntity };
return this.model.findUnique({ return this.model.findUnique({
where: data, where: data,
include: { include: {
// Include metrics & count // Include metrics & count
Metrics: true, Metrics: true,
_count: { _count: {
select: { Metrics: true }, select: { Metrics: true },
}, },
}, },
}); });
} catch (error) { } catch (error) {
@ -59,4 +58,3 @@ export default class ProjectRepository {
} }
} }
} }

View File

@ -4,28 +4,28 @@ import ProjectEntity from "./ProjectEntity";
export default class MetricEntity { export default class MetricEntity {
@IsNotEmpty() @IsNotEmpty()
public id!: number; public id!: number;
@IsNotEmpty(({groups: ["create"]})) @IsNotEmpty({ groups: ["create"] })
public path!: string; public path!: string;
@IsNotEmpty(({groups: ["create"]})) @IsNotEmpty({ groups: ["create"] })
public uuid!: string; public uuid!: string;
@IsNotEmpty(({groups: ["create"]})) @IsNotEmpty({ groups: ["create"] })
public remote_address!: string; public remote_address!: string;
@IsNotEmpty(({groups: ["create"]})) @IsNotEmpty({ groups: ["create"] })
public date_requested!: Date; public date_requested!: Date;
@IsNotEmpty(({groups: ["create"]})) @IsNotEmpty({ groups: ["create"] })
public projectId!: number; public projectId!: number;
@IsNotEmpty(({groups: ["create"]})) @IsNotEmpty({ groups: ["create"] })
public project!: ProjectEntity; public project!: ProjectEntity;
@IsDate() @IsDate()
public createdAt?: Date; public createdAt?: Date;
@IsDate() @IsDate()
public updatedAt?: Date; public updatedAt?: Date;
} }

View File

@ -5,21 +5,21 @@ export default class ProjectEntity {
@IsNotEmpty() @IsNotEmpty()
public id!: number; public id!: number;
@IsNotEmpty({groups: ["create"]}) @IsNotEmpty({ groups: ["create"] })
public title!: string; public title!: string;
@IsNotEmpty() @IsNotEmpty()
public uuid!: string; public uuid!: string;
@IsDate() @IsDate()
public createdAt!: Date; public createdAt!: Date;
@IsDate() @IsDate()
public updatedAt!: Date; public updatedAt!: Date;
@IsNotEmpty({groups: ["create"]}) @IsNotEmpty({ groups: ["create"] })
public network!: string; public network!: string;
@IsOptional() @IsOptional()
public metrics?: MetricEntity[]; public metrics?: MetricEntity[];
} }

View File

@ -1,4 +1,4 @@
import ProjectEntity from "./ProjectEntity"; import ProjectEntity from "./ProjectEntity";
import MetricEntity from "./MetricEntity"; import MetricEntity from "./MetricEntity";
export { ProjectEntity, MetricEntity}; export { ProjectEntity, MetricEntity };

View File

@ -1,2 +1 @@
export default class BaseService {} export default class BaseService {}

View File

@ -35,18 +35,18 @@ export default class MetricService {
} }
/** /**
* *
* @throws {Error} If metric is undefined * @throws {Error} If metric is undefined
* @returns * @returns
*/ */
public async getCountRpcPath(metricEntity: Partial<MetricEntity>, from: Date, to: Date) { public async getCountRpcPath(metricEntity: Partial<MetricEntity>, from: Date, to: Date) {
const pathsCount = await this.metricRepository.countRpcPathUsage(metricEntity.projectId!,from,to); const pathsCount = await this.metricRepository.countRpcPathUsage(metricEntity.projectId!, from, to);
if (!pathsCount) return null; if (!pathsCount) return null;
return pathsCount; return pathsCount;
} }
/** /**
* *
* @throws {Error} If metric is undefined * @throws {Error} If metric is undefined
* @returns * @returns
*/ */
public async getCountAllMetrics(metricEntity: Partial<MetricEntity>) { public async getCountAllMetrics(metricEntity: Partial<MetricEntity>) {
@ -56,27 +56,27 @@ export default class MetricService {
} }
/** /**
* *
* @throws {Error} If metric is undefined * @throws {Error} If metric is undefined
* @returns * @returns
*/ */
public async getLastMetrics(metricEntity: Partial<MetricEntity>, limit: number){ public async getLastMetrics(metricEntity: Partial<MetricEntity>, limit: number) {
const lastMetric = await this.metricRepository.findLastRequests(metricEntity.projectId!,limit); const lastMetric = await this.metricRepository.findLastRequests(metricEntity.projectId!, limit);
return ObjectHydrate.hydrate<Partial<MetricEntity>>(new MetricEntity(), lastMetric); return ObjectHydrate.hydrate<Partial<MetricEntity>>(new MetricEntity(), lastMetric);
} }
/** /**
* *
* @throws {Error} If metric is undefined * @throws {Error} If metric is undefined
* @returns * @returns
*/ */
public async getRequestsByDay(metricEntity: Partial<MetricEntity>, from: Date, to: Date){ public async getRequestsByDay(metricEntity: Partial<MetricEntity>, from: Date, to: Date) {
const requestByDay = await this.metricRepository.findRequestsByDay(metricEntity.projectId!,from,to); const requestByDay = await this.metricRepository.findRequestsByDay(metricEntity.projectId!, from, to);
return ObjectHydrate.hydrate<Partial<MetricEntity>>(new MetricEntity(), requestByDay); return ObjectHydrate.hydrate<Partial<MetricEntity>>(new MetricEntity(), requestByDay);
} }
/** /**
* *
* @throws {Error} If metric is undefined * @throws {Error} If metric is undefined
* @returns * @returns
*/ */
@ -85,4 +85,3 @@ export default class MetricService {
await this.metricRepository.removeOldMetricsBymonths(months); await this.metricRepository.removeOldMetricsBymonths(months);
} }
} }

View File

@ -4,8 +4,6 @@ import { ProjectEntity } from "@Common/ressources";
import { type processFindManyQuery } from "prisma-query"; import { type processFindManyQuery } from "prisma-query";
import { Service } from "typedi"; import { Service } from "typedi";
@Service() @Service()
export default class ProjectService { export default class ProjectService {
constructor(private projectRepository: ProjectRepository) {} constructor(private projectRepository: ProjectRepository) {}
@ -17,7 +15,7 @@ export default class ProjectService {
const projects = await this.projectRepository.findMany(query); const projects = await this.projectRepository.findMany(query);
return ObjectHydrate.hydrate<Partial<ProjectEntity>>(new ProjectEntity(), projects); return ObjectHydrate.hydrate<Partial<ProjectEntity>>(new ProjectEntity(), projects);
} }
/** /**
* @throws {Error} If project is undefined * @throws {Error} If project is undefined
*/ */
public async getByUUID(projectEntity: Partial<ProjectEntity>) { public async getByUUID(projectEntity: Partial<ProjectEntity>) {
@ -25,15 +23,14 @@ export default class ProjectService {
if (!project) return null; if (!project) return null;
return ObjectHydrate.hydrate<Partial<ProjectEntity>>(new ProjectEntity(), project); return ObjectHydrate.hydrate<Partial<ProjectEntity>>(new ProjectEntity(), project);
} }
/** /**
* *
* @throws {Error} If project cannot be created * @throws {Error} If project cannot be created
* @returns * @returns
*/ */
public async create(projectEntity: Partial<ProjectEntity>) { public async create(projectEntity: Partial<ProjectEntity>) {
const project = await this.projectRepository.create(projectEntity); const project = await this.projectRepository.create(projectEntity);
if (!project) return null; if (!project) return null;
return ObjectHydrate.hydrate<Partial<ProjectEntity>>(new ProjectEntity(), project); return ObjectHydrate.hydrate<Partial<ProjectEntity>>(new ProjectEntity(), project);
} }
} }

View File

@ -31,4 +31,3 @@ export default class ExpressServer implements ServerInterface {
return this; return this;
} }
} }

View File

@ -14,4 +14,3 @@ export default interface ServerInterface {
init(config: IConfig): this; init(config: IConfig): this;
} }

View File

@ -6,4 +6,3 @@ import HttpCodes from "@Common/system/controller-pattern/HttpCodes";
export default abstract class ApiController extends BaseController {} export default abstract class ApiController extends BaseController {}
export { HttpCodes as ResponseStatusCodes }; export { HttpCodes as ResponseStatusCodes };

View File

@ -2,10 +2,8 @@ import { StRoute } from "./StRoute";
import { Response } from "express"; import { Response } from "express";
import HttpCodes from "@Common/system/controller-pattern/HttpCodes"; import HttpCodes from "@Common/system/controller-pattern/HttpCodes";
type IResponseData = {} | string | number | boolean | null | unknown; type IResponseData = {} | string | number | boolean | null | unknown;
export default abstract class BaseController { export default abstract class BaseController {
public expressRoutes!: StRoute[]; public expressRoutes!: StRoute[];
public httpCode: typeof HttpCodes = HttpCodes; public httpCode: typeof HttpCodes = HttpCodes;

View File

@ -34,4 +34,3 @@ function createRoute(controller: any, route: StRoute) {
} }
export default Controller; export default Controller;

View File

@ -12,4 +12,3 @@ export default class ErrorCatch {
next(args[args.length - 1] ?? "Unknown Error"); next(args[args.length - 1] ?? "Unknown Error");
} }
} }

View File

@ -1,10 +1,10 @@
enum HttpCodes { enum HttpCodes {
SUCCESS = 200, SUCCESS = 200,
CREATED = 201, CREATED = 201,
BAD_REQUEST = 400, BAD_REQUEST = 400,
INTERNAL_ERROR = 500, INTERNAL_ERROR = 500,
UNKNOWN_ERROR = 520, UNKNOWN_ERROR = 520,
NOT_IMPLEMENTED = 501, NOT_IMPLEMENTED = 501,
NOT_FOUND = 404, NOT_FOUND = 404,
} }
export default HttpCodes; export default HttpCodes;

View File

@ -1,7 +1,12 @@
import BaseController from "./BaseController"; import BaseController from "./BaseController";
import { StRoute } from "./StRoute"; import { StRoute } from "./StRoute";
function MethodsAny(type: StRoute["type"], path: string, frontMiddlewares: StRoute["frontMiddlewares"] = [], backMiddlewares: StRoute["backMiddlewares"] = []) { function MethodsAny(
type: StRoute["type"],
path: string,
frontMiddlewares: StRoute["frontMiddlewares"] = [],
backMiddlewares: StRoute["backMiddlewares"] = [],
) {
return (target: any, memberName: string, propertyDescriptor: PropertyDescriptor) => { return (target: any, memberName: string, propertyDescriptor: PropertyDescriptor) => {
const func = propertyDescriptor.value; const func = propertyDescriptor.value;
const constructor: typeof BaseController = target.constructor; const constructor: typeof BaseController = target.constructor;
@ -29,4 +34,3 @@ export const Delete = MethodsAny.bind(null, "delete");
* @description Decorator Method PUT * @description Decorator Method PUT
*/ */
export const Put = MethodsAny.bind(null, "put"); export const Put = MethodsAny.bind(null, "put");

View File

@ -7,4 +7,3 @@ export interface StRoute {
frontMiddlewares: ((requests: Request, response: Response, next: NextFunction) => void)[]; frontMiddlewares: ((requests: Request, response: Response, next: NextFunction) => void)[];
backMiddlewares: ((requests: Request, response: Response, next: NextFunction) => void)[]; backMiddlewares: ((requests: Request, response: Response, next: NextFunction) => void)[];
} }

View File

@ -1,7 +1,7 @@
import HttpCodes from "../HttpCodes"; import HttpCodes from "../HttpCodes";
export default class HttpException extends Error { export default class HttpException extends Error {
constructor(message: string, public httpCode: HttpCodes = HttpCodes.UNKNOWN_ERROR) { constructor(message: string, public httpCode: HttpCodes = HttpCodes.UNKNOWN_ERROR) {
super(message); super(message);
} }
} }

View File

@ -1,32 +1,31 @@
import dotenv from "dotenv"; import dotenv from "dotenv";
import { PrismaClient } from "@prisma/client"; import { PrismaClient } from "@prisma/client";
import IDatabaseConfig from "../../config/IDatabaseConfig"; import IDatabaseConfig from "../../config/IDatabaseConfig";
dotenv.config(); dotenv.config();
export default class DbProvider { export default class DbProvider {
protected client = new PrismaClient({ protected client = new PrismaClient({
datasources: { datasources: {
db: { db: {
url: `postgres://${process.env["DATABASE_USER"]}:${process.env["DATABASE_PASSWORD"]}@${process.env["DATABASE_HOSTNAME"]}:${process.env["DATABASE_PORT"]}/${process.env["DATABASE_NAME"]}`, url: `postgres://${process.env["DATABASE_USER"]}:${process.env["DATABASE_PASSWORD"]}@${process.env["DATABASE_HOSTNAME"]}:${process.env["DATABASE_PORT"]}/${process.env["DATABASE_NAME"]}`,
}, },
}, },
}); });
constructor(protected config: IDatabaseConfig) { constructor(protected config: IDatabaseConfig) {}
}
public async connect(): Promise<void> {
public async connect(): Promise<void> { await this.client.$connect();
await this.client.$connect(); console.info(`⚡️[Prisma]: Connected to ${this.config.name}`); // A Logger middleware is to be added here
console.info(`⚡️[Prisma]: Connected to ${this.config.name}`);// A Logger middleware is to be added here }
}
public getClient() {
public getClient() { return this.client;
return this.client; }
}
public async disconnect(): Promise<void> {
public async disconnect(): Promise<void> { await this.client.$disconnect();
await this.client.$disconnect(); console.info(`⚡️[Prisma]: Disconnected from ${this.config.name}`); // A Logger middleware is to be added here
console.info(`⚡️[Prisma]: Disconnected from ${this.config.name}`); // A Logger middleware is to be added here }
} }
}

View File

@ -2,4 +2,4 @@ export class ORMBadQueryError extends Error {
constructor(message: string, public error: Error) { constructor(message: string, public error: Error) {
super(message); super(message);
} }
} }

View File

@ -2,4 +2,4 @@ import IDatabaseConfig from "@Common/config/IDatabaseConfig";
import DbProvider from "./DbProvider"; import DbProvider from "./DbProvider";
export type { IDatabaseConfig }; export type { IDatabaseConfig };
export default DbProvider; export default DbProvider;

View File

@ -22,15 +22,8 @@ Container.get(ExpressServer).init({
label, label,
port: parseInt(port), port: parseInt(port),
rootUrl, rootUrl,
middlwares: [ middlwares: [cors({ origin: "*" }), bodyParser.urlencoded({ extended: true }), bodyParser.json()],
cors({ origin: "*" }),
bodyParser.urlencoded({ extended: true }),
bodyParser.json(),
],
errorHandler, errorHandler,
}); });
routes.start(); routes.start();

View File

@ -15,7 +15,7 @@ if (!rootUrl) throw new Error(`process.env RootUrl is undefined`);
Container.get(NextServer).init({ Container.get(NextServer).init({
label, label,
isDev: process.env.NODE_ENV !== 'production', isDev: process.env.NODE_ENV !== "production",
port: parseInt(port), port: parseInt(port),
rootUrl, rootUrl,
}); });

View File

@ -1,14 +1,17 @@
export enum ContentType { export enum ContentType {
JSON = "application/json", JSON = "application/json",
FORM_DATA = "multipart/form-data;", FORM_DATA = "multipart/form-data;",
} }
export default abstract class BaseApiService { export default abstract class BaseApiService {
protected readonly backUrl = process.env["NEXT_PUBLIC_API_HOSTNAME"] + ':' + process.env['NEXT_PUBLIC_API_PORT'] + process.env['NEXT_PUBLIC_API_ROOT_URL']; protected readonly backUrl =
protected readonly proxyUrl = process.env["NEXT_PUBLIC_RPC_GATEWAY_HOSTNAME"] + ':' + process.env['NEXT_PUBLIC_RPC_GATEWAY_PORT'] + process.env['NEXT_PUBLIC_RPC_GATEWAY_ROOT_URL']; process.env["NEXT_PUBLIC_API_HOSTNAME"] + ":" + process.env["NEXT_PUBLIC_API_PORT"] + process.env["NEXT_PUBLIC_API_ROOT_URL"];
protected readonly proxyUrl =
process.env["NEXT_PUBLIC_RPC_GATEWAY_HOSTNAME"] +
":" +
process.env["NEXT_PUBLIC_RPC_GATEWAY_PORT"] +
process.env["NEXT_PUBLIC_RPC_GATEWAY_ROOT_URL"];
// eslint-disable-next-line @typescript-eslint/no-empty-function // eslint-disable-next-line @typescript-eslint/no-empty-function
protected constructor() {} protected constructor() {}
@ -114,7 +117,6 @@ export default abstract class BaseApiService {
protected onError(error: unknown) { protected onError(error: unknown) {
console.error(error); console.error(error);
} }
} }
export interface IResponse { export interface IResponse {

View File

@ -1,55 +1,55 @@
import BaseApiService from "src/front/Api/BaseApiService" import BaseApiService from "src/front/Api/BaseApiService";
import { IProject } from "src/front/interfaces" import { IProject } from "src/front/interfaces";
import { Service } from "typedi"; import { Service } from "typedi";
type IPostProject = { type IPostProject = {
title: string, title: string;
network: string network: string;
} };
@Service() @Service()
export default class Project extends BaseApiService { export default class Project extends BaseApiService {
private static instance: Project; private static instance: Project;
private readonly baseURl = this.backUrl.concat('/projects'); private readonly baseURl = this.backUrl.concat("/projects");
private constructor() { private constructor() {
super(); super();
} }
public static getInstance() { public static getInstance() {
if (!this.instance) { if (!this.instance) {
return new Project(); return new Project();
} else { } else {
return this.instance; return this.instance;
} }
} }
public async getAllProject(): Promise<IProject[]> { public async getAllProject(): Promise<IProject[]> {
const url = new URL(this.baseURl); const url = new URL(this.baseURl);
try { try {
return await this.getRequest<IProject[]>(url); return await this.getRequest<IProject[]>(url);
} catch (err) { } catch (err) {
this.onError(err); this.onError(err);
return Promise.reject(err); return Promise.reject(err);
} }
} }
public async getOneProject(uuid: string): Promise<IProject> { public async getOneProject(uuid: string): Promise<IProject> {
const url = new URL(this.baseURl.concat('/').concat(uuid)); const url = new URL(this.baseURl.concat("/").concat(uuid));
try { try {
return await this.getRequest<IProject>(url); return await this.getRequest<IProject>(url);
} catch (err) { } catch (err) {
this.onError(err); this.onError(err);
return Promise.reject(err); return Promise.reject(err);
} }
} }
public async postProject(params: IPostProject): Promise<IProject> { public async postProject(params: IPostProject): Promise<IProject> {
const url = new URL(this.baseURl); const url = new URL(this.baseURl);
try { try {
return await this.postRequest<IProject>(url, params); return await this.postRequest<IProject>(url, params);
} catch (err) { } catch (err) {
this.onError(err); this.onError(err);
return Promise.reject(err); return Promise.reject(err);
} }
} }
} }

View File

@ -1,101 +1,101 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
display: inline-flex; display: inline-flex;
justify-content: center; justify-content: center;
border: 1px solid; border: 1px solid;
gap: 12px; gap: 12px;
box-sizing: border-box; box-sizing: border-box;
height: fit-content; height: fit-content;
align-items: center; align-items: center;
gap: 6px; gap: 6px;
background: transparent; background: transparent;
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
white-space: nowrap; white-space: nowrap;
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
svg { svg {
width: 18px; width: 18px;
height: 18px; height: 18px;
} }
&[variant="primary"] { &[variant="primary"] {
color: $white; color: $white;
background-color: $purple-flash; background-color: $purple-flash;
border-color: $purple-flash; border-color: $purple-flash;
padding: 24px 48px; padding: 24px 48px;
font-weight: 400; font-weight: 400;
font-size: 18px; font-size: 18px;
line-height: 22px; line-height: 22px;
&:hover { &:hover {
border-color: $purple-hover; border-color: $purple-hover;
background-color: $purple-hover; background-color: $purple-hover;
} }
&:disabled { &:disabled {
border-color: $purple-soft; border-color: $purple-soft;
background-color: $purple-soft; background-color: $purple-soft;
pointer-events: none; pointer-events: none;
} }
} }
&[variant="secondary"] { &[variant="secondary"] {
color: $white; color: $white;
background-color: $red-flash; background-color: $red-flash;
border-color: $red-flash; border-color: $red-flash;
padding: 24px 48px; padding: 24px 48px;
font-weight: 400; font-weight: 400;
font-size: 18px; font-size: 18px;
line-height: 22px; line-height: 22px;
&:hover { &:hover {
border-color: $re-hover; border-color: $re-hover;
background-color: $re-hover; background-color: $re-hover;
} }
&:disabled { &:disabled {
border-color: $red-soft; border-color: $red-soft;
background-color: $red-soft; background-color: $red-soft;
pointer-events: none; pointer-events: none;
} }
} }
&[variant="ghost"] { &[variant="ghost"] {
color: $pink-flash; color: $pink-flash;
background-color: transparent; background-color: transparent;
border-color: $pink-flash; border-color: $pink-flash;
padding: 24px 48px; padding: 24px 48px;
font-weight: 400; font-weight: 400;
font-size: 18px; font-size: 18px;
line-height: 22px; line-height: 22px;
svg { svg {
path { path {
stroke: $white; stroke: $white;
} }
} }
&:hover { &:hover {
border-color: $pink-hover; border-color: $pink-hover;
color: $pink-hover; color: $pink-hover;
} }
&:disabled { &:disabled {
border-color: $pink-soft; border-color: $pink-soft;
background-color: $pink-soft; background-color: $pink-soft;
pointer-events: none; pointer-events: none;
} }
} }
&[fullwidth="true"] { &[fullwidth="true"] {
width: 100%; width: 100%;
flex: 1; flex: 1;
} }
&[touppercase="false"] { &[touppercase="false"] {
text-transform: inherit; text-transform: inherit;
} }
} }

View File

@ -2,49 +2,44 @@ import React from "react";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
export enum EButtonVariant { export enum EButtonVariant {
PRIMARY = "primary", PRIMARY = "primary",
SECONDARY = "secondary", SECONDARY = "secondary",
GHOST = "ghost", GHOST = "ghost",
LINE = "line", LINE = "line",
} }
type IProps = { type IProps = {
onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined; onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined;
children?: React.ReactNode; children?: React.ReactNode;
variant?: EButtonVariant; variant?: EButtonVariant;
fullwidth?: "true" | "false"; fullwidth?: "true" | "false";
icon?: React.ReactNode; icon?: React.ReactNode;
disabled?: boolean; disabled?: boolean;
type: "button" | "submit"; type: "button" | "submit";
isloading: string; isloading: string;
}; };
type IState = {}; type IState = {};
export default class Button extends React.Component<IProps, IState> { export default class Button extends React.Component<IProps, IState> {
static defaultProps: IProps = { static defaultProps: IProps = {
variant: EButtonVariant.PRIMARY, variant: EButtonVariant.PRIMARY,
disabled: false, disabled: false,
type: "button", type: "button",
isloading: "false", isloading: "false",
fullwidth: "false", fullwidth: "false",
}; };
public override render(): JSX.Element { public override render(): JSX.Element {
const attributes = { ...this.props }; const attributes = { ...this.props };
delete attributes.icon; delete attributes.icon;
// let icon = this.props.isloading === "true" ? <Loader /> : this.props.icon; // Notion de loader // let icon = this.props.isloading === "true" ? <Loader /> : this.props.icon; // Notion de loader
let icon = this.props.icon; let icon = this.props.icon;
return ( return (
<button <button {...attributes} onClick={this.props.onClick} className={classes["root"]} type={this.props.type}>
{...attributes} {this.props.children}
onClick={this.props.onClick} {this.props.icon && icon}
className={classes["root"]} </button>
type={this.props.type} );
> }
{this.props.children}
{this.props.icon && icon}
</button>
);
}
} }

View File

@ -1,39 +1,38 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
cursor: pointer; cursor: pointer;
display: flex; display: flex;
align-items: center; align-items: center;
input[type="checkbox"] { input[type="checkbox"] {
appearance: none; appearance: none;
background-color: transparent; background-color: transparent;
width: 16px; width: 16px;
height: 16px; height: 16px;
border: 1px solid $green-flash; border: 1px solid $green-flash;
border-radius: 2px; border-radius: 2px;
margin-right: 16px; margin-right: 16px;
display: grid; display: grid;
place-content: center; place-content: center;
} }
input[type="checkbox"]::before { input[type="checkbox"]::before {
content: url("../../../assets/icons/check.svg"); content: url("../../../assets/icons/check.svg");
place-content: center; place-content: center;
display: grid; display: grid;
width: 16px; width: 16px;
height: 16px; height: 16px;
background-color: $green-flash; background-color: $green-flash;
border-radius: 2px; border-radius: 2px;
transform: scale(0); transform: scale(0);
} }
input[type="checkbox"]:checked::before { input[type="checkbox"]:checked::before {
transform: scale(1); transform: scale(1);
} }
.tooltip {
margin-left: 16px;
}
.tooltip {
margin-left: 16px;
}
} }

View File

@ -4,27 +4,24 @@ import Typography, { ITypo, ITypoColor } from "../Typography";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
type IProps = { type IProps = {
name: string; name: string;
toolTip?: string; toolTip?: string;
}; };
export default class CheckBox extends React.Component<IProps> { export default class CheckBox extends React.Component<IProps> {
static defaultProps = { static defaultProps = {
toolTip: "", toolTip: "",
}; };
public override render(): JSX.Element { public override render(): JSX.Element {
return ( return (
<Typography typo={ITypo.P_ERR_16} color={ITypoColor.BLACK}> <Typography typo={ITypo.P_ERR_16} color={ITypoColor.BLACK}>
<label className={classes["root"]}> <label className={classes["root"]}>
<input <input type="checkbox" name={this.props.name} />
type="checkbox" {this.props.name}
name={this.props.name} {this.props.toolTip && <Tooltip className={classes["tooltip"]} text={this.props.toolTip} />}
/> </label>
{this.props.name} </Typography>
{this.props.toolTip && <Tooltip className={classes["tooltip"]} text={this.props.toolTip}/>} );
</label> }
</Typography>
);
}
} }

View File

@ -1,154 +1,154 @@
import { ChangeEvent, Component, createRef } from "react"; import { ChangeEvent, Component, createRef } from "react";
import { FormContext, IFormContext } from ".."; import { FormContext, IFormContext } from "..";
// elements // elements
import Validators, { IValidationTypes } from "../Validators/Validators"; import Validators, { IValidationTypes } from "../Validators/Validators";
export type IError = { export type IError = {
message: string; message: string;
validator: string; validator: string;
value: string | number | readonly string[]; value: string | number | readonly string[];
args: any[]; args: any[];
isErrored?: (hasError: boolean) => void; isErrored?: (hasError: boolean) => void;
}; };
export type INewBasefieldProps = { export type INewBasefieldProps = {
onChange?: (event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) => void; onChange?: (event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) => void;
name: string; name: string;
regex?: RegExp; regex?: RegExp;
onCancel?: () => void; onCancel?: () => void;
disableValidation?: boolean; disableValidation?: boolean;
onErrors?: (errors: IError[]) => void; onErrors?: (errors: IError[]) => void;
fieldRef?: React.RefObject<any>; fieldRef?: React.RefObject<any>;
}; };
export type IProps = IValidationTypes & React.InputHTMLAttributes<HTMLInputElement> & INewBasefieldProps; export type IProps = IValidationTypes & React.InputHTMLAttributes<HTMLInputElement> & INewBasefieldProps;
type IState = { type IState = {
value?: string | number | readonly string[] ; value?: string | number | readonly string[];
errors: IError[]; errors: IError[];
}; };
export default abstract class BaseField<P extends IProps> extends Component<P, IState> { export default abstract class BaseField<P extends IProps> extends Component<P, IState> {
public static override contextType = FormContext; public static override contextType = FormContext;
public override context: IFormContext | null = null; public override context: IFormContext | null = null;
public fieldRef: React.RefObject<any> = createRef(); public fieldRef: React.RefObject<any> = createRef();
static defaultProps: Partial<IProps> = { static defaultProps: Partial<IProps> = {
disableValidation: false, disableValidation: false,
}; };
constructor(props: P) { constructor(props: P) {
super(props); super(props);
this.onChange = this.onChange.bind(this); this.onChange = this.onChange.bind(this);
this.validate = this.validate.bind(this); this.validate = this.validate.bind(this);
this.state = { this.state = {
value: this.props.value ?? this.props.defaultValue ?? "", value: this.props.value ?? this.props.defaultValue ?? "",
errors: [], errors: [],
}; };
} }
public override componentDidMount() { public override componentDidMount() {
this.context?.setField(this.props.name, this); this.context?.setField(this.props.name, this);
} }
public override componentDidUpdate(prevProps: P) { public override componentDidUpdate(prevProps: P) {
if (prevProps.value !== this.props.value || prevProps.defaultValue !== this.props.defaultValue) { if (prevProps.value !== this.props.value || prevProps.defaultValue !== this.props.defaultValue) {
this.setState({ value: this.props.value ?? this.props.defaultValue ?? "" }); this.setState({ value: this.props.value ?? this.props.defaultValue ?? "" });
} }
} }
public override componentWillUnmount() { public override componentWillUnmount() {
this.context?.unSetField(this.props.name); this.context?.unSetField(this.props.name);
} }
public async onBlur(event: React.FocusEvent<HTMLInputElement, Element>) { public async onBlur(event: React.FocusEvent<HTMLInputElement, Element>) {
// this.validate(); // this.validate();
// if (this.props.onBlur) { // if (this.props.onBlur) {
// this.props.onBlur(event); // this.props.onBlur(event);
// } // }
} }
public async validate(isOnSubmit?: boolean) { public async validate(isOnSubmit?: boolean) {
if (this.props.disableValidation) return; if (this.props.disableValidation) return;
if (this.props.readOnly) return; if (this.props.readOnly) return;
const errorArray: IError[] = []; const errorArray: IError[] = [];
const props: { [key: string]: any } = this.props; const props: { [key: string]: any } = this.props;
const validators = Object.entries(Validators).filter(([key]) => props[key]); const validators = Object.entries(Validators).filter(([key]) => props[key]);
const isValidable = isOnSubmit const isValidable = isOnSubmit
? this.props.required || (this.state.value && this.state.value !== "") ? this.props.required || (this.state.value && this.state.value !== "")
: this.state.value && this.state.value !== ""; : this.state.value && this.state.value !== "";
if (isValidable) { if (isValidable) {
const validations = await Promise.all( const validations = await Promise.all(
validators.map(async ([key, validator]) => { validators.map(async ([key, validator]) => {
const validation = await (validator.validate as any)(this.state.value, ...(props[key].args ?? [])); const validation = await (validator.validate as any)(this.state.value, ...(props[key].args ?? []));
if (props[key].isErrored) { if (props[key].isErrored) {
props[key].isErrored(!validation); props[key].isErrored(!validation);
} }
return [key, validator, validation]; return [key, validator, validation];
}), }),
); );
const unValidateds = validations.filter(([key, validator, validation]) => !validation); const unValidateds = validations.filter(([key, validator, validation]) => !validation);
const errors: IError[] = unValidateds.map(([key, unValidated]) => { const errors: IError[] = unValidateds.map(([key, unValidated]) => {
let message = unValidated.message; let message = unValidated.message;
if (typeof props[key] === "object" && props[key].message) message = props[key].message; if (typeof props[key] === "object" && props[key].message) message = props[key].message;
return { message, validator: key, value: this.state.value!, args: props[key].args ?? [] }; return { message, validator: key, value: this.state.value!, args: props[key].args ?? [] };
}); });
errorArray.push(...errors); errorArray.push(...errors);
} else { } else {
validators.forEach(async ([key]) => { validators.forEach(async ([key]) => {
if (props[key].isErrored) { if (props[key].isErrored) {
props[key].isErrored(false); props[key].isErrored(false);
} }
}); });
} }
this.setState({ errors: errorArray }); this.setState({ errors: errorArray });
this.onErrors(errorArray); this.onErrors(errorArray);
return errorArray; return errorArray;
} }
public setErrors(errors: IError[]) { public setErrors(errors: IError[]) {
this.setState({ ...this.state, errors }); this.setState({ ...this.state, errors });
} }
/** /**
* It is automatically called by the parent form when the user cancelled the * It is automatically called by the parent form when the user cancelled the
* form and all of its changes. * form and all of its changes.
* *
* Override the method for custom cancelling logic, or pass a custom onCancel * Override the method for custom cancelling logic, or pass a custom onCancel
* callback. * callback.
*/ */
public cancel() { public cancel() {
if (this.props.onCancel) { if (this.props.onCancel) {
this.props.onCancel(); this.props.onCancel();
} }
} }
public onErrors(errors: IError[]) { public onErrors(errors: IError[]) {
if (this.props.onErrors) { if (this.props.onErrors) {
this.props.onErrors(errors); this.props.onErrors(errors);
} }
} }
protected onChange(event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) { protected onChange(event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) {
if (this.props.regex) { if (this.props.regex) {
if (!this.props.regex.test(event.currentTarget.value)) { if (!this.props.regex.test(event.currentTarget.value)) {
event.currentTarget.value = event.currentTarget.value.substring(0, event.currentTarget.value.length - 1); event.currentTarget.value = event.currentTarget.value.substring(0, event.currentTarget.value.length - 1);
} }
} }
this.setState({ value: event.currentTarget.value }, () => { this.setState({ value: event.currentTarget.value }, () => {
this.validate(); this.validate();
this.context?.onFieldChange(this.props.name, this); this.context?.onFieldChange(this.props.name, this);
}); });
if (this.props.onChange) { if (this.props.onChange) {
this.props.onChange(event); this.props.onChange(event);
} }
} }
} }

View File

@ -1,87 +1,87 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
position: relative; position: relative;
.input { .input {
z-index: 1; z-index: 1;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 24px; padding: 24px;
gap: 10px; gap: 10px;
width: 530px; width: 530px;
height: 70px; height: 70px;
border: 1px solid $grey-medium; border: 1px solid $grey-medium;
&:focus { &:focus {
~ .fake-placeholder { ~ .fake-placeholder {
transform: translateY(-35px); transform: translateY(-35px);
transition: transform 0.5s ease; transition: transform 0.5s ease;
} }
} }
&:not([value=""]) { &:not([value=""]) {
~ .fake-placeholder { ~ .fake-placeholder {
transform: translateY(-35px); transform: translateY(-35px);
transition: transform; transition: transform;
} }
} }
&[type="number"] { &[type="number"] {
&:focus { &:focus {
~ .fake-placeholder { ~ .fake-placeholder {
transform: translateY(-35px); transform: translateY(-35px);
transition: transform 0.5s ease; transition: transform 0.5s ease;
} }
} }
&:not([value=""]) { &:not([value=""]) {
~ .fake-placeholder { ~ .fake-placeholder {
transform: translateY(-35px); transform: translateY(-35px);
transition: transform; transition: transform;
} }
} }
} }
&:not([value=""]) { &:not([value=""]) {
~ .fake-placeholder { ~ .fake-placeholder {
transform: translateY(-35px); transform: translateY(-35px);
transition: transform 0.5s ease; transition: transform 0.5s ease;
} }
} }
~ .fake-placeholder { ~ .fake-placeholder {
z-index: 2; z-index: 2;
top: 35%; top: 35%;
margin-left: 8px; margin-left: 8px;
padding: 0 16px; padding: 0 16px;
pointer-events: none; pointer-events: none;
position: absolute; position: absolute;
background: $white; background: $white;
} }
} }
} }
.textarea { .textarea {
z-index: 1; z-index: 1;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 24px; padding: 24px;
gap: 10px; gap: 10px;
width: 530px; width: 530px;
height: 70px; height: 70px;
border: 1px solid $grey-medium; border: 1px solid $grey-medium;
~ .fake-placeholder { ~ .fake-placeholder {
z-index: 2; z-index: 2;
top: -12px; top: -12px;
margin-left: 8px; margin-left: 8px;
padding: 0 16px; padding: 0 16px;
pointer-events: none; pointer-events: none;
position: absolute; position: absolute;
background: $white; background: $white;
// transform: translateY(-35px); // transform: translateY(-35px);
} }
} }

View File

@ -43,7 +43,9 @@ export default class InputField extends BaseField<IProps> {
value={value} value={value}
onChange={this.onChange} onChange={this.onChange}
data-has-validation-errors={this.state.errors.length > 0} data-has-validation-errors={this.state.errors.length > 0}
className={this.props.className ? [classes["textarea"], classes[this.props.className]].join(" ") : classes["textarea"]} className={
this.props.className ? [classes["textarea"], classes[this.props.className]].join(" ") : classes["textarea"]
}
/> />
<div className={classes["fake-placeholder"]}>{this.props.fakeplaceholder}</div> <div className={classes["fake-placeholder"]}>{this.props.fakeplaceholder}</div>
</div> </div>
@ -61,7 +63,9 @@ export default class InputField extends BaseField<IProps> {
onBlur={this.onBlur} onBlur={this.onBlur}
value={value} value={value}
data-has-validation-errors={this.state.errors.length > 0} data-has-validation-errors={this.state.errors.length > 0}
className={this.props.className ? [classes["input"], classes[this.props.className]].join(" ") : classes["input"]} className={
this.props.className ? [classes["input"], classes[this.props.className]].join(" ") : classes["input"]
}
/> />
<div className={classes["fake-placeholder"]}>{this.props.fakeplaceholder}</div> <div className={classes["fake-placeholder"]}>{this.props.fakeplaceholder}</div>
</div> </div>

View File

@ -1,180 +1,180 @@
import { isEmail, isNotEmpty, isNumberString, isString, max, maxLength, min, minLength } from "class-validator"; import { isEmail, isNotEmpty, isNumberString, isString, max, maxLength, min, minLength } from "class-validator";
const Validators = { const Validators = {
/** /**
* **Parameters** : boolean * **Parameters** : boolean
* *
* This validator verifies the value is not empty * This validator verifies the value is not empty
*/ */
required: { validate: isNotEmpty, message: "validation_messages.field_required" }, required: { validate: isNotEmpty, message: "validation_messages.field_required" },
/** /**
* **Parameters** : boolean * **Parameters** : boolean
* *
* This validator verifies the value is a number * This validator verifies the value is a number
*/ */
numbersOnly: { validate: isNumberString, message: "validation_messages.only_numbers" }, numbersOnly: { validate: isNumberString, message: "validation_messages.only_numbers" },
/** /**
* **Parameters** : boolean * **Parameters** : boolean
* *
* This validator verifies the value is a number * This validator verifies the value is a number
*/ */
intOnly: { intOnly: {
validate: function (value: string) { validate: function (value: string) {
const regex = /^[0-9]*$/; const regex = /^[0-9]*$/;
return regex.test(value); return regex.test(value);
}, },
message: "validation_messages.only_integers", message: "validation_messages.only_integers",
}, },
/** /**
* **Parameters** : number * **Parameters** : number
* *
* This validator verifies the number is not below the parameter * This validator verifies the number is not below the parameter
*/ */
minNumber: { validate: (value: string, minVal: number) => min(Number(value), minVal), message: "validation_messages.below_min" }, minNumber: { validate: (value: string, minVal: number) => min(Number(value), minVal), message: "validation_messages.below_min" },
/** /**
* **Parameters** : number * **Parameters** : number
* *
* This validator verifies the number is not above the parameter * This validator verifies the number is not above the parameter
*/ */
maxNumber: { validate: (value: string, maxVal: number) => max(Number(value), maxVal), message: "validation_messages.above_max" }, maxNumber: { validate: (value: string, maxVal: number) => max(Number(value), maxVal), message: "validation_messages.above_max" },
/** /**
* **Parameters** : number * **Parameters** : number
* *
* This validator verifies the string minimum length is conform to the parameter * This validator verifies the string minimum length is conform to the parameter
*/ */
minLength: { minLength: {
validate: minLength, validate: minLength,
message: "validation_messages.min_string_length", message: "validation_messages.min_string_length",
}, },
/** /**
* **Parameters** : number * **Parameters** : number
* *
* This validator verifies the string maximum length is conform to the parameter * This validator verifies the string maximum length is conform to the parameter
*/ */
maxLength: { maxLength: {
validate: maxLength, validate: maxLength,
message: "validation_messages.max_string_length", message: "validation_messages.max_string_length",
}, },
/** /**
* **Parameters** : boolean * **Parameters** : boolean
* *
* This validator verifies the input's value is a string. * This validator verifies the input's value is a string.
*/ */
isString: { validate: (value: string) => isString(value), message: "validation_messages.only_letters" }, isString: { validate: (value: string) => isString(value), message: "validation_messages.only_letters" },
/** /**
* **Parameters** : boolean * **Parameters** : boolean
* *
* This validator verifies the input's value is conform to the tag regex. * This validator verifies the input's value is conform to the tag regex.
*/ */
isTag: { isTag: {
validate: function (value: string) { validate: function (value: string) {
const regex = /^[a-zA-Z0-9][a-zA-Z0-9 ]*(,[a-zA-Z0-9][a-zA-Z0-9 ]*)*$/; const regex = /^[a-zA-Z0-9][a-zA-Z0-9 ]*(,[a-zA-Z0-9][a-zA-Z0-9 ]*)*$/;
const isValid = regex.test(value); const isValid = regex.test(value);
if (!isValid) return false; if (!isValid) return false;
const splittedTag = value.split(","); const splittedTag = value.split(",");
if (splittedTag.length !== new Set(splittedTag).size) { if (splittedTag.length !== new Set(splittedTag).size) {
return false; return false;
} }
return true; return true;
}, },
message: "validation_messages.not_valid_tag", message: "validation_messages.not_valid_tag",
}, },
/** /**
* **Parameters** : boolean * **Parameters** : boolean
* *
* This validator verifies the input's value is a valid email. * This validator verifies the input's value is a valid email.
* *
* If the **input is empty, it is considered valid**. If you do not wish this * If the **input is empty, it is considered valid**. If you do not wish this
* to happen please refer to the `required` validator. * to happen please refer to the `required` validator.
*/ */
isEmail: { isEmail: {
validate: (value: string) => (Boolean(value) ? isEmail(value) : true), validate: (value: string) => (Boolean(value) ? isEmail(value) : true),
message: "validation_messages.invalid_email", message: "validation_messages.invalid_email",
}, },
isPseudo: { isPseudo: {
validate: (value: string) => { validate: (value: string) => {
const pseudoRegex = /^[a-zA-Z][a-zA-Z0-9_-]{2,19}$/; const pseudoRegex = /^[a-zA-Z][a-zA-Z0-9_-]{2,19}$/;
return pseudoRegex.test(value); return pseudoRegex.test(value);
}, },
message: "validation_messages.is_pseudo", message: "validation_messages.is_pseudo",
}, },
noSpaceInString: { noSpaceInString: {
validate: (value: string) => { validate: (value: string) => {
const regex = /^\S*$/; const regex = /^\S*$/;
return regex.test(value); return regex.test(value);
}, },
message: "validation_messages.no_space_in_string", message: "validation_messages.no_space_in_string",
}, },
isPositiveNumber: { isPositiveNumber: {
validate: (value: string) => { validate: (value: string) => {
let nbr = parseFloat(value); let nbr = parseFloat(value);
return !(isNaN(nbr) || nbr <= 0); return !(isNaN(nbr) || nbr <= 0);
}, },
message: "validation_messages.positive_number", message: "validation_messages.positive_number",
}, },
floatPrecision: { floatPrecision: {
validate: (value: string, precision: number) => { validate: (value: string, precision: number) => {
// If value is not a float // If value is not a float
if (isNaN(parseFloat(value))) return false; if (isNaN(parseFloat(value))) return false;
let splittedValue = value.split("."); let splittedValue = value.split(".");
// If there is no decimals // If there is no decimals
if (!splittedValue[1]) return true; if (!splittedValue[1]) return true;
// If there is more decimals than the required precision // If there is more decimals than the required precision
if (splittedValue[1].length > precision) return false; if (splittedValue[1].length > precision) return false;
return true; return true;
}, },
message: "validation_messages.float_precision", message: "validation_messages.float_precision",
}, },
isUrl: { isUrl: {
validate: (value: string, root: string | string[]) => { validate: (value: string, root: string | string[]) => {
try { try {
const url = new URL(value); const url = new URL(value);
if (root) { if (root) {
if (typeof root === "string") { if (typeof root === "string") {
return url.hostname === root || url.hostname === `www.${root}`; return url.hostname === root || url.hostname === `www.${root}`;
} else { } else {
return root.some((r) => url.hostname === r || url.hostname === `www.${r}`); return root.some((r) => url.hostname === r || url.hostname === `www.${r}`);
} }
} }
return true; return true;
} catch (e) { } catch (e) {
return false; return false;
} }
}, },
message: "validation_messages.invalid_url", message: "validation_messages.invalid_url",
}, },
// isUniqueEmail: { TODO : uncomment and implement DB request // isUniqueEmail: { TODO : uncomment and implement DB request
// validate: async (value: string, actual: string) => { // validate: async (value: string, actual: string) => {
// try { // try {
// const users = await AppUser.getInstance().getUsers({email: value}); // const users = await AppUser.getInstance().getUsers({email: value});
// if (!users.metadata.count) return true; // if (!users.metadata.count) return true;
// if (users.data.length > 1) return false; // if (users.data.length > 1) return false;
// if (users.data[0]?.email === actual) return true; // if (users.data[0]?.email === actual) return true;
// return false; // return false;
// } catch { // } catch {
// return true; // return true;
// } // }
// }, // },
// message: "validation_messages.unique_email", // message: "validation_messages.unique_email",
// }, // },
}; };
export default Validators; export default Validators;
export type IValidationTypes = Partial< export type IValidationTypes = Partial<
Record<keyof typeof Validators, boolean | Partial<{ message: string; args: any[]; isErrored: (errored: boolean) => void }>> Record<keyof typeof Validators, boolean | Partial<{ message: string; args: any[]; isErrored: (errored: boolean) => void }>>
>; >;

View File

@ -1,22 +1,22 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
display: flex; display: flex;
position: relative; position: relative;
width: fit-content; width: fit-content;
margin: auto; margin: auto;
height: 83px; height: 83px;
padding: 10px 16px; padding: 10px 16px;
.content{ .content {
margin: auto; margin: auto;
} }
.underline{ .underline {
width: 100%; width: 100%;
height: 3px; height: 3px;
background-color: $black; background-color: $black;
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
} }
} }

View File

@ -4,33 +4,32 @@ import Link from "next/link";
import Typography, { ITypo } from "../../Typography"; import Typography, { ITypo } from "../../Typography";
import classNames from "classnames"; import classNames from "classnames";
import router from "next/router"; import router from "next/router";
import { useEffect, useState } from 'react' import { useEffect, useState } from "react";
type IPropsClass = { type IPropsClass = {
text: string | JSX.Element; text: string | JSX.Element;
path?: string; path?: string;
isActive?: boolean; isActive?: boolean;
}; };
type IStateClass = {}; type IStateClass = {};
class HeaderLinkClass extends React.Component<IPropsClass, IStateClass> { class HeaderLinkClass extends React.Component<IPropsClass, IStateClass> {
public override render(): JSX.Element { public override render(): JSX.Element {
return <Link href={this.props.path ?? ""} className={classNames(classes["root"], this.props.isActive && [classes["active"]])} return (
> <Link href={this.props.path ?? ""} className={classNames(classes["root"], this.props.isActive && [classes["active"]])}>
<div className={classes["content"]}> <div className={classes["content"]}>
<Typography typo={ITypo.NAV_HEADER_18}> <Typography typo={ITypo.NAV_HEADER_18}>{this.props.text}</Typography>
{this.props.text} </div>
</Typography> {this.props.isActive && <div className={classes["underline"]} />}
</div> </Link>
{this.props.isActive && <div className={classes["underline"]} />} );
</Link>; }
}
} }
export default function HeaderLink(props: IPropsClass) { export default function HeaderLink(props: IPropsClass) {
const [url, setUrl] = useState("") const [url, setUrl] = useState("");
useEffect(() => setUrl(router?.asPath), []) useEffect(() => setUrl(router?.asPath), []);
const isActive = url === props.path; const isActive = url === props.path;
return <HeaderLinkClass {...props} isActive={isActive} />; return <HeaderLinkClass {...props} isActive={isActive} />;
} }

View File

@ -1,8 +1,8 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
display: inline-flex; display: inline-flex;
@media screen and (max-width: $screen-ls) { @media screen and (max-width: $screen-ls) {
display: none; display: none;
} }
} }

View File

@ -6,13 +6,15 @@ type IProps = {};
type IState = {}; type IState = {};
export default class Navigation extends React.Component<IProps, IState> { export default class Navigation extends React.Component<IProps, IState> {
public override render(): JSX.Element { public override render(): JSX.Element {
return <div className={classes["root"]}> return (
<HeaderLink text={"Home"} path={"/"} /> <div className={classes["root"]}>
<HeaderLink text={"Design system"} path={"/design-system"} /> <HeaderLink text={"Home"} path={"/"} />
<HeaderLink text={"Ancrage"} path={""} /> <HeaderLink text={"Design system"} path={"/design-system"} />
<HeaderLink text={"Collaborateurs"} path={""} /> <HeaderLink text={"Ancrage"} path={""} />
<HeaderLink text={"Paramétrage des listes de pièces"} path={""} /> <HeaderLink text={"Collaborateurs"} path={""} />
</div>; <HeaderLink text={"Paramétrage des listes de pièces"} path={""} />
} </div>
);
}
} }

View File

@ -1,37 +1,37 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 300px; width: 300px;
max-height: 80%; max-height: 80%;
background-color: $white; background-color: $white;
box-shadow: $shadow-nav; box-shadow: $shadow-nav;
padding: 24px; padding: 24px;
position: absolute; position: absolute;
top: 107px; top: 107px;
right:56px; right: 56px;
.notification-header{ .notification-header {
width: 100%; width: 100%;
display: inline-flex; display: inline-flex;
justify-content: space-between; justify-content: space-between;
.close-icon{ .close-icon {
cursor: pointer; cursor: pointer;
} }
} }
.notification-body{ .notification-body {
margin-top: 24px; margin-top: 24px;
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;
} }
} }
.background{ .background {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: transparent; background-color: transparent;
} }

View File

@ -7,63 +7,64 @@ import ToastHandler from "@Front/Components/DesignSystem/Toasts/ToastsHandler";
import Toasts, { IToast } from "@Front/Stores/Toasts"; import Toasts, { IToast } from "@Front/Stores/Toasts";
type IProps = { type IProps = {
isOpen: boolean; isOpen: boolean;
closeModal: () => void; closeModal: () => void;
}; };
type IState = { type IState = {
toastList: IToast[] | null; toastList: IToast[] | null;
}; };
export default class NotificationModal extends React.Component<IProps, IState> { export default class NotificationModal extends React.Component<IProps, IState> {
private removeOnToastChange: () => void = () => { }; private removeOnToastChange: () => void = () => {};
constructor(props: IProps) { constructor(props: IProps) {
super(props); super(props);
this.state = { this.state = {
toastList: Toasts.getInstance().toasts, toastList: Toasts.getInstance().toasts,
}; };
this.handleToastChange = this.handleToastChange.bind(this); this.handleToastChange = this.handleToastChange.bind(this);
} }
public override render(): JSX.Element | null { public override render(): JSX.Element | null {
if (!this.props.isOpen) return null; if (!this.props.isOpen) return null;
return <> return (
<div className={classes["background"]} onClick={this.props.closeModal}/> <>
<div className={classes["root"]}> <div className={classes["background"]} onClick={this.props.closeModal} />
<div className={classes["notification-header"]}> <div className={classes["root"]}>
<Typography typo={ITypo.P_16}> <div className={classes["notification-header"]}>
Notifications <Typography typo={ITypo.P_16}>Notifications</Typography>
</Typography> <div className={classes["close-icon"]} onClick={this.props.closeModal}>
<div className={classes["close-icon"]} onClick={this.props.closeModal}> <Image src={CloseIcon} alt="Close notification modal" className={classes["close-icon"]}></Image>
<Image src={CloseIcon} alt="Close notification modal" className={classes["close-icon"]}></Image> </div>
</div> </div>
</div>; ;
<div className={classes["notification-body"]}>
<>
{Toasts.getInstance().toasts.length === 0 ? (
<div>
<Typography typo={ITypo.P_16}>No notification yet</Typography>
</div>
) : (
<ToastHandler />
)}
</>
</div>
</div>
</>
);
}
<div className={classes["notification-body"]}> public override componentDidMount() {
<> this.removeOnToastChange = Toasts.getInstance().onChange(this.handleToastChange);
{Toasts.getInstance().toasts.length === 0 }
?
<div>
<Typography typo={ITypo.P_16}>No notification yet</Typography>
</div>
: <ToastHandler />}
</>
</div>
</div>
</>
}
public override componentDidMount() { public override componentWillUnmount() {
this.removeOnToastChange = Toasts.getInstance().onChange(this.handleToastChange); this.removeOnToastChange();
} }
public override componentWillUnmount() { private handleToastChange(toastList: IToast[] | null) {
this.removeOnToastChange(); this.setState({
} toastList,
});
private handleToastChange(toastList: IToast[] | null) { }
this.setState({
toastList,
});
}
} }

View File

@ -1,18 +1,18 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
.icon-container{ .icon-container {
position: relative; position: relative;
cursor: pointer; cursor: pointer;
.notification-icon{ .notification-icon {
height: 24px; height: 24px;
width: 24px; width: 24px;
} }
.notification-dot{ .notification-dot {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
} }
} }
} }

View File

@ -8,60 +8,61 @@ import InfoIcon from "@Assets/icons/info.svg";
type IProps = {}; type IProps = {};
type IState = { type IState = {
hasNotifications: boolean; hasNotifications: boolean;
isModalOpen: boolean; isModalOpen: boolean;
toastList: IToast[] | null; toastList: IToast[] | null;
}; };
export default class Notifications extends React.Component<IProps, IState> { export default class Notifications extends React.Component<IProps, IState> {
private removeOnToastChange: () => void = () => { }; private removeOnToastChange: () => void = () => {};
constructor(props: IProps) { constructor(props: IProps) {
super(props); super(props);
this.state = { this.state = {
isModalOpen: false, isModalOpen: false,
toastList: Toasts.getInstance().toasts, //TODO : Get from bbd toastList: Toasts.getInstance().toasts, //TODO : Get from bbd
hasNotifications: Toasts.getInstance().toasts.length > 0, // TODO: Change this when we have notification stored in bbd, unread notifications hasNotifications: Toasts.getInstance().toasts.length > 0, // TODO: Change this when we have notification stored in bbd, unread notifications
}; };
this.openModal = this.openModal.bind(this); this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this); this.closeModal = this.closeModal.bind(this);
this.handleToastChange = this.handleToastChange.bind(this); this.handleToastChange = this.handleToastChange.bind(this);
}
} public override render(): JSX.Element {
return (
<div className={classes["root"]}>
<div className={classes["icon-container"]} onClick={this.openModal}>
<Image alt="notifications" src={NotificationIcon} className={classes["notification-icon"]} />
{this.state.hasNotifications && (
<Image className={classes["notification-dot"]} src={InfoIcon} alt="Unread notification" />
)}
</div>
public override render(): JSX.Element { {this.state.isModalOpen && <NotificationModal isOpen={this.state.isModalOpen} closeModal={this.closeModal} />}
return <div className={classes["root"]}> </div>
<div className={classes["icon-container"]} onClick={this.openModal}> );
<Image alt="notifications" src={NotificationIcon} className={classes["notification-icon"]} /> }
{this.state.hasNotifications &&
<Image className={classes["notification-dot"]} src={InfoIcon} alt="Unread notification" />
}
</div>
{this.state.isModalOpen && <NotificationModal isOpen={this.state.isModalOpen} closeModal={this.closeModal} />} public override componentDidMount() {
</div>; this.removeOnToastChange = Toasts.getInstance().onChange(this.handleToastChange);
} }
public override componentDidMount() { public override componentWillUnmount() {
this.removeOnToastChange = Toasts.getInstance().onChange(this.handleToastChange); this.removeOnToastChange();
} }
public override componentWillUnmount() { private handleToastChange(toastList: IToast[] | null) {
this.removeOnToastChange(); this.setState({
} toastList,
hasNotifications: toastList ? toastList.length > 0 : false,
});
}
private handleToastChange(toastList: IToast[] | null) { private openModal() {
this.setState({ this.setState({ isModalOpen: true });
toastList, }
hasNotifications: toastList ? toastList.length > 0 : false
});
}
private openModal() { private closeModal() {
this.setState({ isModalOpen: true }); this.setState({ isModalOpen: false });
}; }
}
private closeModal() {
this.setState({ isModalOpen: false });
};
}

View File

@ -1,12 +1,12 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
display: flex; display: flex;
position: relative; position: relative;
width: fit-content; width: fit-content;
margin: auto; margin: auto;
.content{ .content {
align-content: center; align-content: center;
} }
} }

View File

@ -1,9 +1,9 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
.profile-icon{ .profile-icon {
cursor: pointer; cursor: pointer;
height: 24px; height: 24px;
width: 24px; width: 24px;
} }
} }

View File

@ -6,33 +6,33 @@ import ProfileModal from "./ProfileModal";
type IProps = {}; type IProps = {};
type IState = { type IState = {
isModalOpen: boolean; isModalOpen: boolean;
}; };
export default class Profile extends React.Component<IProps, IState> { export default class Profile extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
isModalOpen: false,
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
constructor(props: IProps) { public override render(): JSX.Element {
super(props); return (
this.state = { <div className={classes["root"]}>
isModalOpen: false, <Image alt="profile" src={ProfileIcon} className={classes["profile-icon"]} onClick={this.openModal} />
}; {this.state.isModalOpen && <ProfileModal isOpen={this.state.isModalOpen} closeModal={this.closeModal} />}
this.openModal = this.openModal.bind(this); </div>
this.closeModal = this.closeModal.bind(this); );
}
} private openModal() {
this.setState({ isModalOpen: true });
}
public override render(): JSX.Element { private closeModal() {
return <div className={classes["root"]}> this.setState({ isModalOpen: false });
<Image alt="profile" src={ProfileIcon} className={classes["profile-icon"]} onClick={this.openModal} /> }
{this.state.isModalOpen && <ProfileModal isOpen={this.state.isModalOpen} closeModal={this.closeModal} />}
</div>;
}
private openModal() {
this.setState({ isModalOpen: true });
};
private closeModal() {
this.setState({ isModalOpen: false });
};
} }

View File

@ -1,26 +1,26 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
height: 83px; height: 83px;
background-color: $white; background-color: $white;
box-shadow: $shadow-nav; box-shadow: $shadow-nav;
padding: 0 48px; padding: 0 48px;
position: relative; position: relative;
.logo-container { .logo-container {
.logo { .logo {
width: 174px; width: 174px;
height: 39px; height: 39px;
} }
} }
.right-section { .right-section {
display: inline-flex; display: inline-flex;
>:first-child{ > :first-child {
margin-right: 32px; margin-right: 32px;
} }
} }
} }

View File

@ -1,7 +1,7 @@
import React from "react"; import React from "react";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import Image from "next/image"; import Image from "next/image";
import LogoIcon from "@Assets/logo.svg" import LogoIcon from "@Assets/logo.svg";
import Link from "next/link"; import Link from "next/link";
import Navigation from "./Navigation"; import Navigation from "./Navigation";
import Notifications from "./Notifications"; import Notifications from "./Notifications";
@ -11,18 +11,20 @@ type IProps = {};
type IState = {}; type IState = {};
export default class Header extends React.Component<IProps, IState> { export default class Header extends React.Component<IProps, IState> {
public override render(): JSX.Element { public override render(): JSX.Element {
return <div className={classes["root"]}> return (
<div className={classes["logo-container"]}> <div className={classes["root"]}>
<Link href="/"> <div className={classes["logo-container"]}>
<Image src={LogoIcon} alt="logo" className={classes["logo"]} /> <Link href="/">
</Link> <Image src={LogoIcon} alt="logo" className={classes["logo"]} />
</div> </Link>
<Navigation /> </div>
<div className={classes["right-section"]}> <Navigation />
<Notifications/> <div className={classes["right-section"]}>
<Profile /> <Notifications />
</div> <Profile />
</div>; </div>
} </div>
);
}
} }

View File

@ -8,7 +8,7 @@ interface IProps {
export default class Loader extends React.Component<IProps> { export default class Loader extends React.Component<IProps> {
public override render(): JSX.Element { public override render(): JSX.Element {
return <img src={LoaderIcon} className={[classes["loader"], this.props.className].filter(Boolean).join(" ")} /> return <img src={LoaderIcon} className={[classes["loader"], this.props.className].filter(Boolean).join(" ")} />;
// <LoaderIcon className={[classes["loader"], this.props.className].filter(Boolean).join(" ")} />; // <LoaderIcon className={[classes["loader"], this.props.className].filter(Boolean).join(" ")} />;
} }
} }

View File

@ -3,11 +3,11 @@ import classes from "./classes.module.scss";
type IProps = {}; type IProps = {};
type IState = { type IState = {
logged: boolean; logged: boolean;
}; };
export default class Login extends React.Component<IProps, IState> { export default class Login extends React.Component<IProps, IState> {
public override render(): JSX.Element { public override render(): JSX.Element {
return <div className={classes["root"]}></div>; return <div className={classes["root"]}></div>;
} }
} }

View File

@ -11,4 +11,4 @@
width: 24px; width: 24px;
height: 24px; height: 24px;
} }
} }

View File

@ -1,10 +1,10 @@
@import "Themes/constants.scss"; @import "Themes/constants.scss";
.sub-container{ .sub-container {
padding: 40px; padding: 40px;
} }
.button-container{ .button-container {
display: flex; display: flex;
justify-content:flex-start; justify-content: flex-start;
} }

View File

@ -49,10 +49,7 @@ export default class Confirm extends Modal<IProps, IState> {
</Button> </Button>
)} )}
<Button <Button variant={EButtonVariant.PRIMARY} onClick={this.props.onAccept} disabled={this.props.isConfirmButtonDisabled}>
variant={EButtonVariant.PRIMARY}
onClick={this.props.onAccept}
disabled={this.props.isConfirmButtonDisabled}>
{this.props.confirmText} {this.props.confirmText}
</Button> </Button>
</div> </div>

View File

@ -10,4 +10,3 @@
color: var(--color-neutral-900); color: var(--color-neutral-900);
} }
} }

View File

@ -10,9 +10,7 @@ export default class Header extends React.Component<IProps> {
public override render(): JSX.Element { public override render(): JSX.Element {
return ( return (
<header className={classes["root"]}> <header className={classes["root"]}>
<Typography typo={ITypo.H2}> <Typography typo={ITypo.H2}>{this.props.content}</Typography>
{this.props.content}
</Typography>
</header> </header>
); );
} }

View File

@ -13,9 +13,7 @@ export default class PopUpLoader extends React.Component<IProps> {
<div className={classes["root"]}> <div className={classes["root"]}>
{/* <Loader /> */} {/* <Loader /> */}
TODO: INTEGRER LOARDER ISLOADING TODO: INTEGRER LOARDER ISLOADING
<Typography typo={ITypo.P_16}> <Typography typo={ITypo.P_16}>{this.props.text && this.props.text}</Typography>
{this.props.text && this.props.text}
</Typography>
</div> </div>
); );
} }

View File

@ -95,4 +95,4 @@
} }
} }
} }
} }

View File

@ -5,7 +5,7 @@ import Header from "./Elements/Header";
import Loader from "./Elements/Loader"; import Loader from "./Elements/Loader";
import Typography, { ITypo } from "../Typography"; import Typography, { ITypo } from "../Typography";
import CrossIcon from "@Assets/icons/cross.svg" import CrossIcon from "@Assets/icons/cross.svg";
import Image from "next/image"; import Image from "next/image";
export type IModalProps = { export type IModalProps = {
@ -29,7 +29,7 @@ export default class Modal<P extends IModalProps, S extends IState = IState> ext
constructor(props: P) { constructor(props: P) {
super(props); super(props);
this.close = this.close.bind(this); this.close = this.close.bind(this);
(this.state as any) = { (this.state as any) = {
isOpen: props.isOpen ?? true, isOpen: props.isOpen ?? true,
}; };
@ -45,17 +45,15 @@ export default class Modal<P extends IModalProps, S extends IState = IState> ext
className={[classes["container"], this.props.hasTransparentBackground && classes["transparant-background"]].join(" ")} className={[classes["container"], this.props.hasTransparentBackground && classes["transparant-background"]].join(" ")}
onClick={this.props.hasContainerClosable && this.close}> onClick={this.props.hasContainerClosable && this.close}>
{this.props.closeBtn && ( {this.props.closeBtn && (
<div className={classes["cross"]} > <div className={classes["cross"]}>
<Image alt="Unplugged" src={CrossIcon} className={classes["close-icon"]} onClick={this.close}/> <Image alt="Unplugged" src={CrossIcon} className={classes["close-icon"]} onClick={this.close} />
</div> </div>
)} )}
<div className={classes["sub-container"]}> <div className={classes["sub-container"]}>
{this.props.header && <Header content={this.props.header} />} {this.props.header && <Header content={this.props.header} />}
<Typography typo={ITypo.P_16}> <Typography typo={ITypo.P_16}>
<> <>{this.props.children ? this.props.children : <Loader text={this.props.textLoader} />}</>
{this.props.children ? this.props.children : <Loader text={this.props.textLoader} />}
</>
</Typography> </Typography>
{this.props.children && this.props.footer && <Footer content={this.props.footer} />} {this.props.children && this.props.footer && <Footer content={this.props.footer} />}
</div> </div>

View File

@ -1,39 +1,39 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
cursor: pointer; cursor: pointer;
user-select: none; user-select: none;
display: flex; display: flex;
align-items: center; align-items: center;
input[type="radio"] { input[type="radio"] {
appearance: none; appearance: none;
background-color: transparent; background-color: transparent;
width: 16px; width: 16px;
height: 16px; height: 16px;
border: 1px solid $green-flash; border: 1px solid $green-flash;
border-radius: 100px; border-radius: 100px;
margin-right: 16px; margin-right: 16px;
display: grid; display: grid;
place-content: center; place-content: center;
margin-top: auto; margin-top: auto;
margin-bottom: auto; margin-bottom: auto;
} }
input[type="radio"]::before { input[type="radio"]::before {
content: ""; content: "";
width: 10px; width: 10px;
height: 10px; height: 10px;
background-color: $green-flash; background-color: $green-flash;
border-radius: 100px; border-radius: 100px;
transform: scale(0); transform: scale(0);
} }
input[type="radio"]:checked::before { input[type="radio"]:checked::before {
transform: scale(1); transform: scale(1);
} }
.tooltip { .tooltip {
margin-left: 16px; margin-left: 16px;
} }
} }

View File

@ -4,25 +4,21 @@ import Typography, { ITypo, ITypoColor } from "../Typography";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
type IProps = { type IProps = {
children: React.ReactNode; children: React.ReactNode;
name: string; name: string;
toolTip?: string; toolTip?: string;
}; };
export default class RadioBox extends React.Component<IProps> { export default class RadioBox extends React.Component<IProps> {
public override render(): JSX.Element {
public override render(): JSX.Element { return (
return ( <Typography typo={ITypo.P_ERR_16} color={ITypoColor.BLACK}>
<Typography typo={ITypo.P_ERR_16} color={ITypoColor.BLACK}> <label className={classes["root"]}>
<label className={classes["root"]}> <input type="radio" name={this.props.name} />
<input {this.props.children}
type="radio" {this.props.toolTip && <Tooltip className={classes["tooltip"]} text={this.props.toolTip} />}
name={this.props.name} </label>
/> </Typography>
{this.props.children} );
{this.props.toolTip && <Tooltip className={classes["tooltip"]} text={this.props.toolTip}/>} }
</label>
</Typography>
);
}
} }

View File

@ -1,96 +1,96 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
@keyframes slide-left { @keyframes slide-left {
from { from {
opacity: 0; opacity: 0;
transform: translateX(120%); transform: translateX(120%);
} }
to { to {
opacity: 1; opacity: 1;
transform: translate(0%); transform: translate(0%);
} }
} }
@keyframes slide-right { @keyframes slide-right {
from { from {
opacity: 1; opacity: 1;
transform: translateX(0); transform: translateX(0);
} }
to { to {
opacity: 0; opacity: 0;
transform: translate(120%); transform: translate(120%);
} }
} }
.root { .root {
pointer-events: all; pointer-events: all;
position: relative; position: relative;
padding: 24px; padding: 24px;
background: $orange-soft; background: $orange-soft;
box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.11); box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.11);
border-radius: 5px; border-radius: 5px;
animation-name: slide-left; animation-name: slide-left;
animation-duration: 400ms; animation-duration: 400ms;
animation-timing-function: $custom-easing; animation-timing-function: $custom-easing;
animation-fill-mode: forwards; animation-fill-mode: forwards;
&[data-will-close="true"] { &[data-will-close="true"] {
animation-duration: 200ms; animation-duration: 200ms;
animation-name: slide-right; animation-name: slide-right;
animation-timing-function: $custom-easing; animation-timing-function: $custom-easing;
animation-fill-mode: forwards; animation-fill-mode: forwards;
} }
.loadbar { .loadbar {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
left: 0; left: 0;
height: 2px; height: 2px;
background: var(--color-neutral-500); background: var(--color-neutral-500);
border-radius: 5px; border-radius: 5px;
transform-origin: right; transform-origin: right;
transform: scaleX(0); transform: scaleX(0);
animation: loadbar-animation var(--data-duration) linear; animation: loadbar-animation var(--data-duration) linear;
} }
.header { .header {
font-family: var(--font-primary); font-family: var(--font-primary);
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
font-size: 16px; font-size: 16px;
line-height: 24px; line-height: 24px;
color: var(--color-neutral-900); color: var(--color-neutral-900);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
.cross { .cross {
cursor: pointer; cursor: pointer;
} }
} }
.text-icon_row { .text-icon_row {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
p { p {
padding-left: 14px; padding-left: 14px;
width: 150%; width: 150%;
} }
} }
.text-container { .text-container {
font-family: var(--font-primary); font-family: var(--font-primary);
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;
line-height: 20px; line-height: 20px;
color: var(--color-neutral-500); color: var(--color-neutral-500);
} }
a { a {
text-decoration: none; text-decoration: none;
} }
} }

View File

@ -1,102 +1,98 @@
import React from "react"; import React from "react";
// Components // Components
// Stores // Stores
// Styles // Styles
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import Toasts, { IToast } from "@Front/Stores/Toasts"; import Toasts, { IToast } from "@Front/Stores/Toasts";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
type IProps = { type IProps = {
toast: IToast; toast: IToast;
}; };
type IState = { type IState = {
willClose: boolean; willClose: boolean;
}; };
export default class ToastElement extends React.Component<IProps, IState> { export default class ToastElement extends React.Component<IProps, IState> {
private closeTimeout = 0; private closeTimeout = 0;
constructor(props: IProps) { constructor(props: IProps) {
super(props); super(props);
this.state = { this.state = {
willClose: false, willClose: false,
}; };
this.onClose = this.onClose.bind(this); this.onClose = this.onClose.bind(this);
} }
public override render(): JSX.Element { public override render(): JSX.Element {
const toast = this.props.toast; const toast = this.props.toast;
const style = { const style = {
"--data-duration": `${toast.time}ms`, "--data-duration": `${toast.time}ms`,
} as React.CSSProperties; } as React.CSSProperties;
return ( return (
<div className={classes["root"]} data-will-close={this.state.willClose}> <div className={classes["root"]} data-will-close={this.state.willClose}>
{toast.time !== 0 && <div className={classes["loadbar"]} style={style} />} {toast.time !== 0 && <div className={classes["loadbar"]} style={style} />}
<div className={classes["header"]}> <div className={classes["header"]}>
<div className={classes["text-icon_row"]}> <div className={classes["text-icon_row"]}>
{toast.icon && toast.icon} {toast.icon && toast.icon}
<div className={classes["text-container"]}> <div className={classes["text-container"]}>
{this.getToastTitle(toast.title)} {this.getToastTitle(toast.title)}
{this.getToastText(toast.text)} {this.getToastText(toast.text)}
</div> </div>
</div> </div>
{/* {toast.closable && <Cross className={classes["cross"]} onClick={this.onClose} />} */} {/* {toast.closable && <Cross className={classes["cross"]} onClick={this.onClose} />} */}
</div> </div>
{toast.button} {toast.button}
</div> </div>
); );
} }
public override componentDidMount() { public override componentDidMount() {
if (this.props.toast.time === 0) return; if (this.props.toast.time === 0) return;
this.closeTimeout = window.setTimeout(() => { this.closeTimeout = window.setTimeout(() => {
this.close(); this.close();
}, this.props.toast.time); }, this.props.toast.time);
} }
private getToastTitle(title: string | React.ReactNode) { private getToastTitle(title: string | React.ReactNode) {
if (typeof title === "string") { if (typeof title === "string") {
return ( return <Typography typo={ITypo.P_16}>{title}</Typography>;
<Typography typo={ITypo.P_16}> }
{title} return title;
</Typography> }
);
} private getToastText(text: React.ReactNode) {
return title; if (typeof text === "string") {
} return (
<div className={classes["text-container"]}>
private getToastText(text: React.ReactNode) { <Typography typo={ITypo.CAPTION_14} color={ITypoColor.GREY}>
if (typeof text === "string") { {text}
return ( </Typography>
<div className={classes["text-container"]}> </div>
<Typography typo={ITypo.CAPTION_14} color={ITypoColor.GREY}> );
{text} }
</Typography> return text;
</div> }
);
} private onClose(e: React.MouseEvent) {
return text; e.preventDefault();
} e.stopPropagation();
this.close();
private onClose(e: React.MouseEvent) { }
e.preventDefault();
e.stopPropagation(); private close() {
this.close(); window.clearTimeout(this.closeTimeout);
} this.setState({
willClose: true,
private close() { });
window.clearTimeout(this.closeTimeout); setTimeout(() => {
this.setState({ Toasts.getInstance().close(this.props.toast);
willClose: true, }, 200);
}); }
setTimeout(() => { }
Toasts.getInstance().close(this.props.toast);
}, 200);
}
}

View File

@ -1,18 +1,18 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
& > *:not(:first-child) { & > *:not(:first-child) {
margin-top: 16px; margin-top: 16px;
} }
@media (max-width: 444px) { @media (max-width: 444px) {
width: unset; width: unset;
left: 0; left: 0;
padding: 8px; padding: 8px;
} }
} }

View File

@ -1,46 +1,46 @@
import React from "react"; import React from "react";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import ToastElement from "./ToastElement"; import ToastElement from "./ToastElement";
import classNames from "classnames"; import classNames from "classnames";
import Toasts, { IToast } from "@Front/Stores/Toasts"; import Toasts, { IToast } from "@Front/Stores/Toasts";
type IProps = {}; type IProps = {};
type IState = { type IState = {
toastList: IToast[]; toastList: IToast[];
}; };
export default class ToastsContainer extends React.Component<IProps, IState> { export default class ToastsContainer extends React.Component<IProps, IState> {
private removeOnChange = () => { }; private removeOnChange = () => {};
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);
this.state = { this.state = {
toastList: Toasts.getInstance().toasts, toastList: Toasts.getInstance().toasts,
}; };
this.updateToasts = this.updateToasts.bind(this); this.updateToasts = this.updateToasts.bind(this);
} }
public override render(): JSX.Element { public override render(): JSX.Element {
return ( return (
<div className={classNames(classes["root"], this.state.toastList.length > 0 && classes["open"])}> <div className={classNames(classes["root"], this.state.toastList.length > 0 && classes["open"])}>
<> <>
{this.state.toastList.map((toast) => { {this.state.toastList.map((toast) => {
return <ToastElement toast={toast} key={toast.id} />; return <ToastElement toast={toast} key={toast.id} />;
})} })}
</> </>
</div> </div>
); );
} }
public override componentDidMount() { public override componentDidMount() {
this.removeOnChange = Toasts.getInstance().onChange(this.updateToasts); this.removeOnChange = Toasts.getInstance().onChange(this.updateToasts);
} }
public override componentWillUnmount() { public override componentWillUnmount() {
this.removeOnChange(); this.removeOnChange();
} }
private updateToasts(toastList: IToast[]) { private updateToasts(toastList: IToast[]) {
this.setState({ toastList }); this.setState({ toastList });
} }
} }

View File

@ -6,8 +6,6 @@ type IState = {};
export default class ToastHandler extends React.Component<IProps, IState> { export default class ToastHandler extends React.Component<IProps, IState> {
public override render(): JSX.Element { public override render(): JSX.Element {
return ( return <ToastsContainer />;
<ToastsContainer />
);
} }
} }

View File

@ -30,4 +30,4 @@
right: 20px; right: 20px;
margin-top: -4px; margin-top: -4px;
fill: $white; fill: $white;
} }

View File

@ -13,12 +13,12 @@ export default class TooltipContent extends React.Component<IProps> {
public override render(): JSX.Element { public override render(): JSX.Element {
const mousePositionX = this.props.event?.clientX; const mousePositionX = this.props.event?.clientX;
const mousePositionY = this.props.event?.clientY; const mousePositionY = this.props.event?.clientY;
let right = 0; let right = 0;
let bottom = 0; let bottom = 0;
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
right = window.innerWidth - (mousePositionX ?? 0) - 35; right = window.innerWidth - (mousePositionX ?? 0) - 35;
bottom = window.innerHeight - (mousePositionY ?? 0) + 15; bottom = window.innerHeight - (mousePositionY ?? 0) + 15;
} }
return ( return (
<div <div
style={{ bottom: bottom + "px", right: right + "px" }} style={{ bottom: bottom + "px", right: right + "px" }}
@ -39,4 +39,4 @@ export default class TooltipContent extends React.Component<IProps> {
</div> </div>
); );
} }
} }

View File

@ -40,13 +40,13 @@ export default class Tooltip extends React.Component<IProps, IState> {
onMouseEnter={this.togglePopup} onMouseEnter={this.togglePopup}
onMouseLeave={this.togglePopup} onMouseLeave={this.togglePopup}
onMouseMove={this.moovePopup}> onMouseMove={this.moovePopup}>
<Image src={ToolTipIcon} alt="toolTip icon"/> <Image src={ToolTipIcon} alt="toolTip icon" />
</span> </span>
<Typography typo={ITypo.CAPTION_14}> <Typography typo={ITypo.CAPTION_14}>
<TooltipContent title={this.props.title} event={this.state.event} display={this.state.showContent}> <TooltipContent title={this.props.title} event={this.state.event} display={this.state.showContent}>
{this.props.text} {this.props.text}
</TooltipContent> </TooltipContent>
</Typography> </Typography>
</> </>
); );
} }

View File

@ -2,126 +2,126 @@
@import "@Themes/modes.scss"; @import "@Themes/modes.scss";
.root { .root {
color: $black; color: $black;
font-family: 'Inter', sans-serif; font-family: "Inter", sans-serif;
&.H1-60 { &.H1-60 {
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
font-size: 50px; font-size: 50px;
line-height: 61px; line-height: 61px;
} }
&.H1-bis-40 { &.H1-bis-40 {
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
font-size: 40px; font-size: 40px;
line-height: 48px; line-height: 48px;
} }
&.H2-30 { &.H2-30 {
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;
font-size: 30px; font-size: 30px;
line-height: 36px; line-height: 36px;
} }
&.H3-24 { &.H3-24 {
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
font-size: 24px; font-size: 24px;
line-height: 29px; line-height: 29px;
} }
&.Paragraphe-semibold-18 { &.Paragraphe-semibold-18 {
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
font-size: 18px; font-size: 18px;
line-height: 22px; line-height: 22px;
letter-spacing: 0.5px; letter-spacing: 0.5px;
} }
&.Paragraphe-simple-18 { &.Paragraphe-simple-18 {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-size: 18px; font-size: 18px;
line-height: 22px; line-height: 22px;
} }
&.Paragraphe-MAJ-18 { &.Paragraphe-MAJ-18 {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-size: 18px; font-size: 18px;
line-height: 22px; line-height: 22px;
text-transform: uppercase; text-transform: uppercase;
} }
&.Nav-header-off-18 { &.Nav-header-off-18 {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-size: 18px; font-size: 18px;
line-height: 22px; line-height: 22px;
letter-spacing: 0.5px; letter-spacing: 0.5px;
} }
&.Paragraphe-18-error { &.Paragraphe-18-error {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-size: 18px; font-size: 18px;
line-height: 22px; line-height: 22px;
letter-spacing: 0.5px; letter-spacing: 0.5px;
} }
&.Paragraphe-semibold-16 { &.Paragraphe-semibold-16 {
font-style: normal; font-style: normal;
font-weight: 600; font-weight: 600;
font-size: 16px; font-size: 16px;
line-height: 22px; line-height: 22px;
letter-spacing: 0.5px; letter-spacing: 0.5px;
} }
&.Nav-input-off-16 { &.Nav-input-off-16 {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-size: 16px; font-size: 16px;
line-height: 22px; line-height: 22px;
letter-spacing: 0.5px; letter-spacing: 0.5px;
color: $grey; color: $grey;
} }
&.Paragraphe-simple-16 { &.Paragraphe-simple-16 {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-size: 16px; font-size: 16px;
line-height: 22px; line-height: 22px;
letter-spacing: 0.005em letter-spacing: 0.005em;
} }
&.Paragraphe-16-error { &.Paragraphe-16-error {
color: $re-hover; color: $re-hover;
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-size: 16px; font-size: 16px;
line-height: 22px; line-height: 22px;
letter-spacing: 0.5px; letter-spacing: 0.5px;
} }
&.Caption_14 { &.Caption_14 {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
font-size: 14px; font-size: 14px;
line-height: 22px; line-height: 22px;
letter-spacing: 0.5px; letter-spacing: 0.5px;
} }
&.re-hover { &.re-hover {
color: $re-hover; color: $re-hover;
} }
&.grey { &.grey {
color: $grey; color: $grey;
} }
&.black { &.black {
color: $black; color: $black;
} }
} }

View File

@ -3,50 +3,44 @@ import classes from "./classes.module.scss";
import classNames from "classnames"; import classNames from "classnames";
type IProps = { type IProps = {
typo: ITypo; typo: ITypo;
children: React.ReactNode; children: React.ReactNode;
color?: ITypoColor; color?: ITypoColor;
}; };
type IState = {}; type IState = {};
export enum ITypo { export enum ITypo {
H1 = "H1-60", H1 = "H1-60",
H1Bis = "H1-bis-40", H1Bis = "H1-bis-40",
H2 = "H2-30", H2 = "H2-30",
H3 = "H3-24", H3 = "H3-24",
P_SB_18 = "Paragraphe-semibold-18", P_SB_18 = "Paragraphe-semibold-18",
P_18 = "Paragraphe-simple-18", P_18 = "Paragraphe-simple-18",
P_MAJ_18 = "Paragraphe-MAJ-18", P_MAJ_18 = "Paragraphe-MAJ-18",
NAV_HEADER_18 = "Nav-header-off-18", NAV_HEADER_18 = "Nav-header-off-18",
P_ERR_18 = "Paragraphe-18-error", P_ERR_18 = "Paragraphe-18-error",
P_SB_16 = "Paragraphe-semibold-16", P_SB_16 = "Paragraphe-semibold-16",
P_16 = "Paragraphe-simple-16", P_16 = "Paragraphe-simple-16",
NAV_INPUT_16 = "Nav-input-off-16", NAV_INPUT_16 = "Nav-input-off-16",
P_ERR_16 = "Paragraphe-16-error", P_ERR_16 = "Paragraphe-16-error",
CAPTION_14 = "Caption_14", CAPTION_14 = "Caption_14",
} }
export enum ITypoColor { export enum ITypoColor {
RE_HOVER = "re-hover", RE_HOVER = "re-hover",
GREY = "grey", GREY = "grey",
BLACK = 'black' BLACK = "black",
} }
export default class Typography extends React.Component<IProps, IState> { export default class Typography extends React.Component<IProps, IState> {
public override render(): JSX.Element { public override render(): JSX.Element {
return ( return (
<div <div className={classNames(classes["root"], classes[this.props.typo], classes[this.props.color ?? ""])}>
className={classNames( {this.props.children}
classes["root"], </div>
classes[this.props.typo], );
classes[this.props.color ?? ""] }
)}
>
{this.props.children}
</div>
);
}
} }

View File

@ -1,7 +1,7 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
position: fixed; position: fixed;
bottom: 16px; bottom: 16px;
right: 24px; right: 24px;
} }

View File

@ -7,13 +7,13 @@ type IProps = {};
type IState = {}; type IState = {};
export default class Version extends React.Component<IProps, IState> { export default class Version extends React.Component<IProps, IState> {
public override render(): JSX.Element { public override render(): JSX.Element {
return <div className={classes["root"]}> return (
<Typography typo={ITypo.P_16} color={ITypoColor.GREY}> <div className={classes["root"]}>
<div> <Typography typo={ITypo.P_16} color={ITypoColor.GREY}>
{VersionFile.version} <div>{VersionFile.version}</div>
</div> </Typography>
</Typography> </div>
</div>; );
} }
} }

View File

@ -5,7 +5,7 @@ type IProps = {};
type IState = {}; type IState = {};
export default class _Template extends React.Component<IProps, IState> { export default class _Template extends React.Component<IProps, IState> {
public override render(): JSX.Element { public override render(): JSX.Element {
return <div className={classes["root"]}></div>; return <div className={classes["root"]}></div>;
} }
} }

View File

@ -1,39 +1,39 @@
@keyframes BurgerTopForward { @keyframes BurgerTopForward {
0% { 0% {
transform: translate3d(0px, 0px, 0) rotate(0deg) scaleX(1); transform: translate3d(0px, 0px, 0) rotate(0deg) scaleX(1);
} }
100% { 100% {
transform: translate3d(-8.000023662749896px, 2.000005915687474px, 0) rotate(-45.000133102968164deg) scaleX(0.4999985210781315) transform: translate3d(-8.000023662749896px, 2.000005915687474px, 0) rotate(-45.000133102968164deg) scaleX(0.4999985210781315);
} }
} }
@keyframes BurgerTopBackward { @keyframes BurgerTopBackward {
0% { 0% {
transform: translate3d(-8.000023662749896px, 2.000005915687474px, 0) rotate(-45.000133102968164deg) scaleX(0.4999985210781315) transform: translate3d(-8.000023662749896px, 2.000005915687474px, 0) rotate(-45.000133102968164deg) scaleX(0.4999985210781315);
} }
100% { 100% {
transform: translate3d(0px, 0px, 0) rotate(0deg) scaleX(1); transform: translate3d(0px, 0px, 0) rotate(0deg) scaleX(1);
} }
} }
@keyframes BurgerBottomForward { @keyframes BurgerBottomForward {
0% { 0% {
transform: translate3d(0px, 0px, 0) rotate(0deg) scaleX(1); transform: translate3d(0px, 0px, 0) rotate(0deg) scaleX(1);
} }
100% { 100% {
transform: translate3d(-8.000023662749896px, -2.000005915687474px, 0) rotate(45.000133102968164deg) scaleX(0.4999985210781315); transform: translate3d(-8.000023662749896px, -2.000005915687474px, 0) rotate(45.000133102968164deg) scaleX(0.4999985210781315);
} }
} }
@keyframes BurgerBottomBackward { @keyframes BurgerBottomBackward {
0% { 0% {
transform: translate3d(-8.000023662749896px, -2.000005915687474px, 0) rotate(45.000133102968164deg) scaleX(0.4999985210781315); transform: translate3d(-8.000023662749896px, -2.000005915687474px, 0) rotate(45.000133102968164deg) scaleX(0.4999985210781315);
} }
100% { 100% {
transform: translate3d(0px, 0px, 0) rotate(0deg) scaleX(1); transform: translate3d(0px, 0px, 0) rotate(0deg) scaleX(1);
} }
} }

View File

@ -1,9 +1,7 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
@import "./animation.scss"; @import "./animation.scss";
.root { .root {
position: fixed; position: fixed;
left: 18px; left: 18px;
top: 23px; top: 23px;
@ -30,18 +28,16 @@
background-color: $textColor; background-color: $textColor;
} }
.inner-top { .inner-top {
top: 0; top: 0;
&.true { &.true {
animation: BurgerTopForward 0.2s cubic-bezier(.43,1.89,.68,.28); animation: BurgerTopForward 0.2s cubic-bezier(0.43, 1.89, 0.68, 0.28);
animation-fill-mode: forwards; animation-fill-mode: forwards;
} }
&.false { &.false {
animation: BurgerTopBackward 0.2s cubic-bezier(.43,1.89,.68,.28); animation: BurgerTopBackward 0.2s cubic-bezier(0.43, 1.89, 0.68, 0.28);
animation-fill-mode: forwards; animation-fill-mode: forwards;
} }
} }
@ -59,14 +55,13 @@
bottom: 1px; bottom: 1px;
&.true { &.true {
animation: BurgerBottomForward 0.2s cubic-bezier(.43,1.89,.68,.28); animation: BurgerBottomForward 0.2s cubic-bezier(0.43, 1.89, 0.68, 0.28);
animation-fill-mode: forwards; animation-fill-mode: forwards;
} }
&.false { &.false {
animation: BurgerBottomBackward 0.2s cubic-bezier(.43,1.89,.68,.28); animation: BurgerBottomBackward 0.2s cubic-bezier(0.43, 1.89, 0.68, 0.28);
animation-fill-mode: forwards; animation-fill-mode: forwards;
} }
} }
}
}

View File

@ -2,14 +2,14 @@ import classes from "./classes.module.scss";
import classNames from "classnames"; import classNames from "classnames";
type IProps = { type IProps = {
state: boolean, state: boolean;
callback: () => void callback: () => void;
}; };
export default function Burger({ state, callback }: IProps) { export default function Burger({ state, callback }: IProps) {
return ( return (
<div className={classes["root"]} onClick={() => callback()}> <div className={classes["root"]} onClick={() => callback()}>
<div className={classes["box"]} > <div className={classes["box"]}>
<div className={classNames(classes["inner-top"], classes["inner"], classes[String(state)])} /> <div className={classNames(classes["inner-top"], classes["inner"], classes[String(state)])} />
<div className={classNames(classes["inner-middle"], classes["inner"], classes[String(state)])} /> <div className={classNames(classes["inner-middle"], classes["inner"], classes[String(state)])} />
<div className={classNames(classes["inner-bottom"], classes["inner"], classes[String(state)])} /> <div className={classNames(classes["inner-bottom"], classes["inner"], classes[String(state)])} />

View File

@ -2,122 +2,121 @@
@import "@Themes/animation.scss"; @import "@Themes/animation.scss";
.root { .root {
padding: 15px 0; padding: 15px 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
will-change: transform, opacity; will-change: transform, opacity;
animation: fadeInFromLeft 500ms; animation: fadeInFromLeft 500ms;
>h1 { > h1 {
margin-top: 0; margin-top: 0;
} }
button { button {
margin-top: 10px; margin-top: 10px;
} }
.component { .component {
width: 100%; width: 100%;
display: block; display: block;
position: relative; position: relative;
height: 40px; height: 40px;
padding: 12px 16px 12px 40px; padding: 12px 16px 12px 40px;
border-width: 1px; border-width: 1px;
border-style: solid; border-style: solid;
border-color: $borderColor; border-color: $borderColor;
border-radius: 4px; border-radius: 4px;
transition: border-color 0.3s ease-in-out, box-shadow 0.3s ease-in-out; transition: border-color 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
will-change: border-color, box-shadow; will-change: border-color, box-shadow;
background-color: $backgroundColor; background-color: $backgroundColor;
&:hover { &:hover {
border-color: $primaryColor; border-color: $primaryColor;
} }
&:focus { &:focus {
box-shadow: 0 0 0 2px $primaryColor; box-shadow: 0 0 0 2px $primaryColor;
border-color: $primaryColor; border-color: $primaryColor;
} }
&.error { &.error {
border-color: $downColor; border-color: $downColor;
&:focus { &:focus {
box-shadow: 0 0 0 2px rgba(237, 29, 37, 0.1); box-shadow: 0 0 0 2px rgba(237, 29, 37, 0.1);
} }
} }
&.success { &.success {
border-color: $upColor; border-color: $upColor;
&:focus { &:focus {
box-shadow: 0 0 0 2px rgba(0, 201, 167, 0.1); box-shadow: 0 0 0 2px rgba(0, 201, 167, 0.1);
} }
} }
} }
@keyframes zoomIn { @keyframes zoomIn {
from { from {
transform: scale(.2); transform: scale(0.2);
opacity: 0 opacity: 0;
} }
to { to {
transform: scale(1); transform: scale(1);
opacity: 1 opacity: 1;
} }
} }
.status { .status {
display: block; display: block;
position: absolute; position: absolute;
top: 50%; top: 50%;
right: 10px; right: 10px;
z-index: 1; z-index: 1;
width: 20px; width: 20px;
height: 20px; height: 20px;
margin-top: -10px; margin-top: -10px;
font-size: 14px; font-size: 14px;
line-height: 20px; line-height: 20px;
text-align: center; text-align: center;
visibility: visible; visibility: visible;
pointer-events: none; pointer-events: none;
will-change: transform, opacity; will-change: transform, opacity;
&.error { &.error {
animation: zoomIn 0.3s cubic-bezier(0.12, 0.4, 0.29, 1.46); animation: zoomIn 0.3s cubic-bezier(0.12, 0.4, 0.29, 1.46);
} }
&.success { &.success {
animation: zoomIn 0.3s cubic-bezier(0.12, 0.4, 0.29, 1.46); animation: zoomIn 0.3s cubic-bezier(0.12, 0.4, 0.29, 1.46);
} }
} }
.icon {
display: block;
position: absolute;
top: 50%;
left: 10px;
z-index: 1;
width: 20px;
height: 20px;
margin-top: -10px;
font-size: 14px;
line-height: 20px;
text-align: center;
visibility: visible;
pointer-events: none;
}
.icon {
display: block;
position: absolute;
top: 50%;
left: 10px;
z-index: 1;
width: 20px;
height: 20px;
margin-top: -10px;
font-size: 14px;
line-height: 20px;
text-align: center;
visibility: visible;
pointer-events: none;
}
} }
.errorMsg { .errorMsg {
color: $downColor; color: $downColor;
margin: -15px 0 15px 0; margin: -15px 0 15px 0;
line-height: 24px; line-height: 24px;
will-change: transform, opacity; will-change: transform, opacity;
animation: slideDown 0.3s cubic-bezier(0.12, 0.4, 0.29, 1.46); animation: slideDown 0.3s cubic-bezier(0.12, 0.4, 0.29, 1.46);
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }

View File

@ -1,50 +1,50 @@
import React, { RefObject } from "react"; import React, { RefObject } from "react";
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" import Image from "next/image";
import ErrorIcon from "@Assets/icons/input-error.svg" import ErrorIcon from "@Assets/icons/input-error.svg";
import SuccessIcon from "@Assets/icons/input-success.svg" import SuccessIcon from "@Assets/icons/input-success.svg";
type IProps = { type IProps = {
inputRef?: RefObject<HTMLInputElement>, inputRef?: RefObject<HTMLInputElement>;
icon?: string, icon?: string;
placeholder?: string, placeholder?: string;
name?: string, name?: string;
value?: string, value?: string;
onChange: any, onChange: any;
onBlur?: any, onBlur?: any;
inputStatus: 'success' | 'error' | 'neutral', inputStatus: "success" | "error" | "neutral";
errorMsg?: string errorMsg?: string;
type: string type: string;
}; };
export default class InputField extends React.Component<IProps> { export default class InputField extends React.Component<IProps> {
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);
} }
public override render(): JSX.Element { public override render(): JSX.Element {
return <> return (
<div className={classNames(classes["root"])}> <>
{this.props.icon && <Image className={classes["icon"]} alt={this.props.icon} src={this.props.icon} />} <div className={classNames(classes["root"])}>
<input className={classNames(classes["component"], classes[this.props.inputStatus])} {this.props.icon && <Image className={classes["icon"]} alt={this.props.icon} src={this.props.icon} />}
ref={this.props.inputRef} <input
type={this.props.type} className={classNames(classes["component"], classes[this.props.inputStatus])}
name={this.props.name} ref={this.props.inputRef}
placeholder={this.props.placeholder} type={this.props.type}
value={this.props.value} name={this.props.name}
onChange={this.props.onChange} placeholder={this.props.placeholder}
onBlur={this.props.onBlur} value={this.props.value}
autoComplete={this.props.name} onChange={this.props.onChange}
/> onBlur={this.props.onBlur}
<div className={classNames(classes["status"], classes[this.props.inputStatus])}> autoComplete={this.props.name}
{this.props.inputStatus === "success" && />
<Image alt="success icon" src={SuccessIcon} />} <div className={classNames(classes["status"], classes[this.props.inputStatus])}>
{this.props.inputStatus === "error" && {this.props.inputStatus === "success" && <Image alt="success icon" src={SuccessIcon} />}
<Image alt="error icon" src={ErrorIcon} /> {this.props.inputStatus === "error" && <Image alt="error icon" src={ErrorIcon} />}
} </div>
</div> </div>
</div> {this.props.errorMsg && <div className={classes["errorMsg"]}>{this.props.errorMsg}</div>}
{this.props.errorMsg && <div className={classes["errorMsg"]}>{this.props.errorMsg}</div>} </>
</> );
} }
} }

View File

@ -1,17 +1,16 @@
import Head from 'next/head'; import Head from "next/head";
import { ReactNode } from 'react'; import { ReactNode } from "react";
type DefaultLayoutProps = { children: ReactNode }; type DefaultLayoutProps = { children: ReactNode };
export const DefaultLayout = ({ children }: DefaultLayoutProps) => { export const DefaultLayout = ({ children }: DefaultLayoutProps) => {
return ( return (
<> <>
<Head> <Head>
<title>LECoffre</title> <title>LECoffre</title>
<link rel="shortcut icon" href="/favicon-16x16.png" /> <link rel="shortcut icon" href="/favicon-16x16.png" />
</Head> </Head>
<main>{children}</main> <main>{children}</main>
</> </>
); );
}; };

View File

@ -27,7 +27,6 @@ export default class DefaultTemplate extends React.Component<IProps, IState> {
</div> </div>
<Version /> <Version />
</> </>
); );
} }
@ -37,4 +36,4 @@ export default class DefaultTemplate extends React.Component<IProps, IState> {
window.scrollTo(0, this.props.scrollTop); window.scrollTo(0, this.props.scrollTop);
} }
} }
} }

View File

@ -3,4 +3,4 @@ import React from "react";
type _IProps = {}; type _IProps = {};
type _IState = {}; type _IState = {};
export default class BasePage<IProps = _IProps, IState = _IState> extends React.Component<IProps, IState> {} export default class BasePage<IProps = _IProps, IState = _IState> extends React.Component<IProps, IState> {}

View File

@ -1,14 +1,14 @@
.root { .root {
margin-left: 35px; margin-left: 35px;
margin-right: 35px; margin-right: 35px;
.section { .section {
margin-bottom: 32px; margin-bottom: 32px;
} }
.sub-section { .sub-section {
margin-bottom: 24px; margin-bottom: 24px;
} }
.inline-flex{ .inline-flex {
display: inline-flex; display: inline-flex;
} }
} }

View File

@ -1,2 +1,2 @@
.root { .root {
} }

View File

@ -4,13 +4,13 @@ import BasePage from "../Base";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
export default class Home extends BasePage { export default class Home extends BasePage {
public override render(): JSX.Element { public override render(): JSX.Element {
return ( return (
<DefaultTemplate title={"HomePage"}> <DefaultTemplate title={"HomePage"}>
<div className={classes["root"]}> <div className={classes["root"]}>
<Typography typo={ITypo.H1}>HomePage</Typography> <Typography typo={ITypo.H1}>HomePage</Typography>
</div> </div>
</DefaultTemplate> </DefaultTemplate>
); );
} }
} }

View File

@ -2,20 +2,20 @@
@import "@Themes/animation.scss"; @import "@Themes/animation.scss";
.root { .root {
margin: 100px auto 20px auto; margin: 100px auto 20px auto;
font-size: 4em; font-size: 4em;
text-align: center; text-align: center;
will-change: opacity, transform; will-change: opacity, transform;
animation: fadeInFromTop 500ms; animation: fadeInFromTop 500ms;
.text { .text {
margin: 20px auto 20px auto; margin: 20px auto 20px auto;
font-size: 0.5em; font-size: 0.5em;
text-align: center; text-align: center;
} }
.home-button { .home-button {
margin: 50px auto; margin: 50px auto;
max-width: 150px; max-width: 150px;
} }
} }

View File

@ -4,30 +4,21 @@ import BasePage from "../Base";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
export default class PageNotFound extends BasePage { export default class PageNotFound extends BasePage {
public override render(): JSX.Element { public override render(): JSX.Element {
return ( return (
<DefaultTemplate title={"Project Not Found"}> <DefaultTemplate title={"Project Not Found"}>
<div className={classes["root"]}> <div className={classes["root"]}>
{/* <Image alt="Unplugged" height="50" src={UnpluggedIcon} /> Oops */} {/* <Image alt="Unplugged" height="50" src={UnpluggedIcon} /> Oops */}
<div className={classes["text"]}>There isn't anything here...</div> <div className={classes["text"]}>There isn't anything here...</div>
<div className={classes["home-button"]}> <div className={classes["home-button"]}>
<Link href="/"> <Link href="/">{/* <Button text="Go to Home" icon={CardsIcon} /> */}</Link>
{/* <Button text="Go to Home" icon={CardsIcon} /> */} </div>
</Link>
</div>
<label> <label>
<input /> <input />
</label> </label>
</div>
</DefaultTemplate>
);
}
</div>
</DefaultTemplate>
);
}
} }

View File

@ -8,51 +8,45 @@ import Burger from "@Front/Components/Elements/Burger";
type IProps = {}; type IProps = {};
type IState = { type IState = {
status: boolean; status: boolean;
}; };
export default class Header extends React.Component<IProps, IState> { export default class Header extends React.Component<IProps, IState> {
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);
this.state = { this.state = {
status: false, status: false,
}; };
this.switchStatus = this.switchStatus.bind(this); this.switchStatus = this.switchStatus.bind(this);
} }
public override render(): JSX.Element { public override render(): JSX.Element {
return ( return (
<> <>
<div className={classes["root"]}> <div className={classes["root"]}>
<Burger state={this.state.status} callback={this.switchStatus} /> <Burger state={this.state.status} callback={this.switchStatus} />
<div className={classes["menu"]}> <div className={classes["menu"]}>
<Link href="/"> <Link href="/">
<Image alt="TEZOS LINK" src={TezosLinkLogo} /> <Image alt="TEZOS LINK" src={TezosLinkLogo} />
</Link> </Link>
</div> </div>
<div className={classes["triangle-under-logo"]}></div> <div className={classes["triangle-under-logo"]}></div>
<div className={classes["logo"]}> <div className={classes["logo"]}>
<Link href="/"> <Link href="/">
<Image alt="entire stack" src={Logo} /> <Image alt="entire stack" src={Logo} />
</Link> </Link>
</div> </div>
<div className={classes["button"]}> <div className={classes["button"]}>
<Link href="/show-project"> <Link href="/show-project">{/* <Button color="transparent" text="MY PROJECT" icon={LoginIcon} /> */}</Link>
{/* <Button color="transparent" text="MY PROJECT" icon={LoginIcon} /> */} <Link href="/new-project">{/* <Button text="CREATE" icon={PlusCardIcon} /> */}</Link>
</Link> </div>
<Link href="/new-project"> </div>
{/* <Button text="CREATE" icon={PlusCardIcon} /> */} </>
</Link> );
</div> }
</div>
</>
);
}
private switchStatus() { private switchStatus() {
this.state.status this.state.status ? this.setState({ status: false }) : this.setState({ status: true });
? this.setState({ status: false }) }
: this.setState({ status: true });
}
} }

View File

@ -1,6 +1,5 @@
import EventEmitter from "@Front/Services/EventEmitter"; import EventEmitter from "@Front/Services/EventEmitter";
export default abstract class BaseStore { export default abstract class BaseStore {
protected readonly event = new EventEmitter(); protected readonly event = new EventEmitter();

View File

@ -1,106 +1,106 @@
import EventEmitter from "@Front/Services/EventEmitter"; import EventEmitter from "@Front/Services/EventEmitter";
// import I18n from "Components/Elements/I18n"; // import I18n from "Components/Elements/I18n";
export enum EToastPriority { export enum EToastPriority {
HIGH = "high", HIGH = "high",
LOW = "low", LOW = "low",
} }
export interface IToast { export interface IToast {
id?: number; id?: number;
title: string | React.ReactNode; title: string | React.ReactNode;
icon?: React.ReactNode; icon?: React.ReactNode;
text?: string | React.ReactNode; text?: string | React.ReactNode;
button?: React.ReactNode; button?: React.ReactNode;
time?: number; time?: number;
closable?: boolean; closable?: boolean;
priority?: EToastPriority; priority?: EToastPriority;
} }
export default class Toasts { export default class Toasts {
private static ctx: Toasts; private static ctx: Toasts;
private readonly event = new EventEmitter(); private readonly event = new EventEmitter();
private toastList: IToast[] = []; private toastList: IToast[] = [];
private uid: number = 0; private uid: number = 0;
private defaultTime: IToast["time"] = 10000; private defaultTime: IToast["time"] = 10000;
private defaultClosable: IToast["closable"] = true; private defaultClosable: IToast["closable"] = true;
private defaultPriority: IToast["priority"] = EToastPriority.LOW; private defaultPriority: IToast["priority"] = EToastPriority.LOW;
private constructor() { private constructor() {
Toasts.ctx = this; Toasts.ctx = this;
} }
public static getInstance() { public static getInstance() {
if (!Toasts.ctx) new this(); if (!Toasts.ctx) new this();
return Toasts.ctx; return Toasts.ctx;
} }
public get toasts() { public get toasts() {
return this.toastList; return this.toastList;
} }
/** /**
* @returns removelistener callback * @returns removelistener callback
*/ */
public onChange(callback: (toastList: IToast[]) => void) { public onChange(callback: (toastList: IToast[]) => void) {
this.event.on("change", callback); this.event.on("change", callback);
return () => this.event.off("change", callback); return () => this.event.off("change", callback);
} }
public open(toast: IToast): () => void { public open(toast: IToast): () => void {
const index = this.toastList.indexOf(toast); const index = this.toastList.indexOf(toast);
if (index !== -1) return () => this.close(toast); if (index !== -1) return () => this.close(toast);
toast.id = toast.id ?? this.uid++; toast.id = toast.id ?? this.uid++;
toast.time = toast.time ?? this.defaultTime; toast.time = toast.time ?? this.defaultTime;
toast.closable = toast.closable ?? this.defaultClosable; toast.closable = toast.closable ?? this.defaultClosable;
toast.priority = toast.priority ?? this.defaultPriority; toast.priority = toast.priority ?? this.defaultPriority;
const highToasts = this.toastList.filter((toast) => { const highToasts = this.toastList.filter((toast) => {
return toast.priority === EToastPriority.HIGH; return toast.priority === EToastPriority.HIGH;
}); });
const lowToasts = this.toastList.filter((toast) => { const lowToasts = this.toastList.filter((toast) => {
return toast.priority === EToastPriority.LOW; return toast.priority === EToastPriority.LOW;
}); });
if (toast.priority === EToastPriority.HIGH) { if (toast.priority === EToastPriority.HIGH) {
highToasts.unshift(toast); highToasts.unshift(toast);
} else { } else {
lowToasts.unshift(toast); lowToasts.unshift(toast);
} }
this.toastList.splice(0); this.toastList.splice(0);
this.toastList.unshift(...lowToasts); this.toastList.unshift(...lowToasts);
this.toastList.unshift(...highToasts); this.toastList.unshift(...highToasts);
this.event.emit("change", this.toastList); this.event.emit("change", this.toastList);
return () => this.close(toast); return () => this.close(toast);
} }
public close(toast: IToast) { public close(toast: IToast) {
const index = this.toastList.indexOf(toast); const index = this.toastList.indexOf(toast);
if (index === -1) return; if (index === -1) return;
this.toastList.splice(index, 1); this.toastList.splice(index, 1);
this.event.emit("change", this.toastList); this.event.emit("change", this.toastList);
} }
/** /**
* An utility static method you can use to quickly display an error toast * An utility static method you can use to quickly display an error toast
* with a custom error message. * with a custom error message.
* *
* @param message_key a key to a l18n message. * @param message_key a key to a l18n message.
*/ */
public static errorToast(message_key: string) { public static errorToast(message_key: string) {
Toasts.getInstance().open({ Toasts.getInstance().open({
text: "Toast text", text: "Toast text",
title: "Toast title", title: "Toast title",
// text: <I18n map={message_key} />, // text: <I18n map={message_key} />,
// title: <I18n map="toast.an_error_occured" />, // title: <I18n map="toast.an_error_occured" />,
closable: true, closable: true,
priority: EToastPriority.HIGH, priority: EToastPriority.HIGH,
}); });
} }
} }

View File

@ -1,3 +1,3 @@
# Documentation # Documentation
This is the documentation served at `https://<BASE_PATH>/documentation` This is the documentation served at `https://<BASE_PATH>/documentation`

View File

@ -5,18 +5,21 @@ Once sign up, a `Project ID` is generated for your project, to use within your a
Then, add the tezoslink.net RPC endpoint to your prefered Tezos JS library. Then, add the tezoslink.net RPC endpoint to your prefered Tezos JS library.
> i.e with [Sotez](https://github.com/AndrewKishino/sotez) : > i.e with [Sotez](https://github.com/AndrewKishino/sotez) :
>```js >
> const sotez = new Sotez('https://<NETWORK>.tezoslink.net/v1/<YOUR_PROJECT_ID>'); > ```js
> const sotez = new Sotez(
> "https://<NETWORK>.tezoslink.net/v1/<YOUR_PROJECT_ID>"
> );
> ``` > ```
## Networks ## Networks
Use one of these endpoints as your Tezos client provider. Use one of these endpoints as your Tezos client provider.
|NETWORK|DESCRIPTION|URL | | NETWORK | DESCRIPTION | URL |
|-------|-----------|-------------------------------------------------| | ------- | ----------- | -------------------------------------------------- |
|Mainnet| JSON/RPC |https://mainnet.tezoslink.net/v1/<YOUR_PROJECT_ID>| | Mainnet | JSON/RPC | https://mainnet.tezoslink.net/v1/<YOUR_PROJECT_ID> |
|Testnet| JSON/RPC |https://testnet.tezoslink.net/v1/<YOUR_PROJECT_ID>| | Testnet | JSON/RPC | https://testnet.tezoslink.net/v1/<YOUR_PROJECT_ID> |
## Make requests ## Make requests
@ -37,26 +40,29 @@ The `Project ID` authorize requests.
All requests of type `/chains/main/blocks(.*?)` are accepted. All requests of type `/chains/main/blocks(.*?)` are accepted.
>Example of valid paths: > Example of valid paths:
>- `/chains/main/blocks/head/context/contracts/<ADDRESS>/balance` >
>- `/chains/main/blocks/head/context/contracts/<ADDRESS>/delegate` > - `/chains/main/blocks/head/context/contracts/<ADDRESS>/balance`
>- `/chains/main/blocks/head/context/contracts/<ADDRESS>/manager_key` > - `/chains/main/blocks/head/context/contracts/<ADDRESS>/delegate`
>- `/chains/main/blocks/head/context/contracts/<ADDRESS>/counter` > - `/chains/main/blocks/head/context/contracts/<ADDRESS>/manager_key`
>- `/chains/main/blocks/head/context/delegates/<ADDRESS>` > - `/chains/main/blocks/head/context/contracts/<ADDRESS>/counter`
>- `/chains/main/blocks/head/header` > - `/chains/main/blocks/head/context/delegates/<ADDRESS>`
>- `/chains/main/blocks/head/votes/proposals` > - `/chains/main/blocks/head/header`
>- `/chains/main/blocks/head/votes/current_quorum` > - `/chains/main/blocks/head/votes/proposals`
> - `/chains/main/blocks/head/votes/current_quorum`
[More about the Tezos `JSON/RPC` endpoints](https://tezos.gitlab.io/api/rpc.html) [More about the Tezos `JSON/RPC` endpoints](https://tezos.gitlab.io/api/rpc.html)
## Nodes ## Nodes
Tezos has three types of nodes: Tezos has three types of nodes:
- Full mode (default mode) - Full mode (default mode)
- **Rolling mode** - **Rolling mode**
- **Archive mode** - **Archive mode**
We use two types of mode: We use two types of mode:
- **Archive** to store the whole blockchain. Archive is the heaviest mode as it keeps the whole chain data to be able to query any information stored on the chain since the genesis. It is particularly suitable for indexers or block explorer, that is why we use archive nodes. - **Archive** to store the whole blockchain. Archive is the heaviest mode as it keeps the whole chain data to be able to query any information stored on the chain since the genesis. It is particularly suitable for indexers or block explorer, that is why we use archive nodes.
- **Rolling** to store last blocks (and scale them faster) - **Rolling** to store last blocks (and scale them faster)

View File

@ -4,4 +4,3 @@
- [Security](##security) - [Security](##security)
- [RPC Endpoints](#rpc-endpoints) - [RPC Endpoints](#rpc-endpoints)
- [Nodes](#nodes) - [Nodes](#nodes)

Some files were not shown because too many files have changed in this diff Show More