mirror of
https://github.com/emo2007/block-accounting.git
synced 2025-01-18 15:36:27 +00:00
back integ
Co-authored-by: Nick <emochka2007@users.noreply.github.com>
This commit is contained in:
parent
8791e4f103
commit
f01dbe094b
107
front/package-lock.json
generated
107
front/package-lock.json
generated
@ -10,11 +10,14 @@
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.3.7",
|
||||
"antd": "^5.17.0",
|
||||
"axios": "^1.7.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
"next": "14.2.3",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
@ -649,6 +652,12 @@
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/js-cookie": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz",
|
||||
"integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/json5": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||
@ -1165,6 +1174,11 @@
|
||||
"integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/available-typed-arrays": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
|
||||
@ -1189,6 +1203,16 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
|
||||
"integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axobject-query": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
|
||||
@ -1385,6 +1409,17 @@
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
|
||||
@ -1563,6 +1598,14 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
@ -2330,6 +2373,25 @@
|
||||
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
|
||||
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/for-each": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
|
||||
@ -2355,6 +2417,19 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
@ -3155,6 +3230,14 @@
|
||||
"jiti": "bin/jiti.js"
|
||||
}
|
||||
},
|
||||
"node_modules/js-cookie": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz",
|
||||
"integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@ -3343,6 +3426,25 @@
|
||||
"node": ">=8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@ -3971,6 +4073,11 @@
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
|
@ -11,11 +11,14 @@
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.3.7",
|
||||
"antd": "^5.17.0",
|
||||
"axios": "^1.7.2",
|
||||
"js-cookie": "^3.0.5",
|
||||
"next": "14.2.3",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
|
37
front/src/app/axios/api-types.ts
Normal file
37
front/src/app/axios/api-types.ts
Normal file
@ -0,0 +1,37 @@
|
||||
export type LoginResponse = {
|
||||
token: string;
|
||||
token_expired_at: number;
|
||||
refresh_token: string;
|
||||
refresh_token_expired_at: number;
|
||||
};
|
||||
export type Organization = {
|
||||
id: string;
|
||||
name: string;
|
||||
address: string;
|
||||
};
|
||||
export type OrganizationsResponse = {
|
||||
items: Organization[];
|
||||
};
|
||||
export type NewOrgResponse = {
|
||||
id: string;
|
||||
};
|
||||
export type Ids = {
|
||||
id: string;
|
||||
};
|
||||
export type ParticipantsResponse = {
|
||||
ids: Ids[];
|
||||
};
|
||||
export type AddPartResponse = {
|
||||
name: string;
|
||||
position: string;
|
||||
wallet_address: string;
|
||||
};
|
||||
export type PublicKey = {
|
||||
public_key: string;
|
||||
};
|
||||
export type DeployResponse = {
|
||||
title: string;
|
||||
owners: PublicKey[];
|
||||
confirmations: number;
|
||||
};
|
||||
export type MultiSigResponse = {};
|
27
front/src/app/axios/global-api.ts
Normal file
27
front/src/app/axios/global-api.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import axios from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
// const tokenStorage = Cookies.get("accessToken");
|
||||
|
||||
export const globalService = axios.create({
|
||||
baseURL: "http://209.141.36.222:8085/",
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
globalService.interceptors.request.use(
|
||||
(config) => {
|
||||
// Get the access token from the cookie
|
||||
const token = Cookies.get("accessToken");
|
||||
console.log(token);
|
||||
|
||||
// If the token exists, set it in the Authorization header
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// If there's an error in the request configuration, you can handle it here
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
91
front/src/app/axios/global.service.ts
Normal file
91
front/src/app/axios/global.service.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { globalService } from "../axios/global-api";
|
||||
import { AxiosResponse } from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
import {
|
||||
LoginResponse,
|
||||
OrganizationsResponse,
|
||||
NewOrgResponse,
|
||||
ParticipantsResponse,
|
||||
AddPartResponse,
|
||||
DeployResponse,
|
||||
MultiSigResponse,
|
||||
} from "./api-types";
|
||||
export class AccountingService {
|
||||
async login(seedKey: string): Promise<AxiosResponse<LoginResponse>> {
|
||||
console.log(seedKey);
|
||||
|
||||
return await globalService.post("login", {
|
||||
mnemonic: seedKey,
|
||||
});
|
||||
}
|
||||
|
||||
async register(seedKey: string) {
|
||||
return await globalService.post("join", {
|
||||
mnemonic: seedKey,
|
||||
});
|
||||
}
|
||||
|
||||
async newOrganization(
|
||||
name: string,
|
||||
address: string
|
||||
): Promise<AxiosResponse<NewOrgResponse>> {
|
||||
return await globalService.post("organizations", {
|
||||
name,
|
||||
address,
|
||||
});
|
||||
}
|
||||
|
||||
async getOrganizations(): Promise<AxiosResponse<OrganizationsResponse>> {
|
||||
return await globalService.post("organizations/fetch", {
|
||||
data: {
|
||||
limit: 5,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async getEmployees(
|
||||
organizationId: string
|
||||
): Promise<AxiosResponse<ParticipantsResponse>> {
|
||||
return await globalService.get(
|
||||
`organizations/${organizationId}/participants`
|
||||
);
|
||||
}
|
||||
|
||||
async addEmployee(
|
||||
name: string,
|
||||
position: string,
|
||||
wallet_address: string,
|
||||
organizationId: string
|
||||
): Promise<AxiosResponse<AddPartResponse>> {
|
||||
return await globalService.post(
|
||||
`organizations/${organizationId}/participants`,
|
||||
{
|
||||
name,
|
||||
position,
|
||||
wallet_address,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// POST /organizations/{organization_id}/multisig
|
||||
async deployMultisig(
|
||||
organization_id: string,
|
||||
title: string,
|
||||
owners: string[],
|
||||
confirmations: number
|
||||
): Promise<AxiosResponse<DeployResponse>> {
|
||||
return await globalService.post(`${organization_id}/multi-sig`, {
|
||||
title,
|
||||
owners,
|
||||
confirmations,
|
||||
});
|
||||
}
|
||||
|
||||
async getAllMultisigsByOrganizationId(
|
||||
organizationId: string
|
||||
): Promise<AxiosResponse<MultiSigResponse>> {
|
||||
return await globalService.get(`organizations/${organizationId}/multisig`);
|
||||
}
|
||||
}
|
||||
|
||||
export const apiService = new AccountingService();
|
@ -1,37 +1,41 @@
|
||||
// 1. Страница входа (Login Page)
|
||||
// Дизайн: Страница должна быть минималистичной с использованием профессиональной цветовой схемы (синие и серые тона). Должно быть поле для ввода мнемонической фразы (SEED_KEY) и кнопка для входа.
|
||||
// Безопасность: Добавить элементы, подчеркивающие безопасность, например, иконку замка и текст, имитирующий шифрование.
|
||||
// Валидация: Проверять формат введенного SEED_KEY на клиентской стороне перед отправкой на сервер.
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { SeedItem } from "../seedItem/SeedItem";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState, useEffect, FC } from "react";
|
||||
import { EyeInvisibleOutlined, EyeTwoTone } from "@ant-design/icons";
|
||||
|
||||
import { apiService } from "../axios/global.service";
|
||||
import { Input, Space, Button, List, Card, Typography } from "antd";
|
||||
import { LockOutlined } from "@ant-design/icons";
|
||||
import useLoginHooks from "@/hooks/login";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
export function LoginPage() {
|
||||
const { passwordVisible, setPasswordVisible, seed, getSeed } =
|
||||
useLoginHooks();
|
||||
const { passwordVisible, setPasswordVisible } = useLoginHooks();
|
||||
const [inp, setInp] = useState("");
|
||||
const [seed, setSeed] = useState<string>();
|
||||
const [disabled, setDisabled] = useState(true);
|
||||
const router = useRouter();
|
||||
const onNextPageHandler = () => {
|
||||
router.push("/organization");
|
||||
};
|
||||
|
||||
const onNextPageHandler = async () => {};
|
||||
// const getSeed = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// setSeed(inp);
|
||||
// };
|
||||
console.log(inp);
|
||||
const { Text } = Typography;
|
||||
useEffect(() => {
|
||||
setDisabled(!(inp.length >= 4));
|
||||
}, [inp]);
|
||||
|
||||
const onSubmitHandler = () => {
|
||||
const onSubmitHandler = async () => {
|
||||
const result = await apiService.login(inp);
|
||||
if (result) {
|
||||
Cookies.set("accessToken", result.data.token);
|
||||
router.push("/organization");
|
||||
}
|
||||
setInp("");
|
||||
getSeed(inp);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex relative overflow-hidden flex-col w-2/3 h-3/4 items-center justify-center gap-10 bg-white border-solid border rounded-md border-neutral-300 text-neutral-500">
|
||||
<div className="w-full h-20 bg-[#1677FF] absolute top-0 flex items-center justify-center">
|
||||
@ -39,7 +43,9 @@ export function LoginPage() {
|
||||
</div>
|
||||
<div className="flex flex-col w-6/12 gap-3 items-start mt-20">
|
||||
<div>
|
||||
<Text type="secondary">Please enter 12 words always lowercase.</Text>
|
||||
<Text type="secondary">
|
||||
Please enter by spaces 12 words always lowercase.
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<Space.Compact style={{ width: "100%" }}>
|
||||
@ -59,8 +65,9 @@ export function LoginPage() {
|
||||
}
|
||||
placeholder="Enter your seed words in order"
|
||||
onInput={(event: any) => setInp(event.target.value)}
|
||||
maxLength={8}
|
||||
//maxLength={8}
|
||||
minLength={4}
|
||||
//onChange={getSeed}
|
||||
/>
|
||||
<Button
|
||||
size="large"
|
||||
@ -72,14 +79,14 @@ export function LoginPage() {
|
||||
</Button>
|
||||
</Space.Compact>
|
||||
</div>
|
||||
<div
|
||||
{/* <div
|
||||
className="flex flex-row w-[700px] gap-3 content-box flex-wrap
|
||||
"
|
||||
>
|
||||
{seed.map((element: string, index: number) => (
|
||||
<SeedItem key={index} seed={element} />
|
||||
))}
|
||||
</div>
|
||||
{/* {seed.map((element: string, index: number) => (
|
||||
// <SeedItem key={index} seed={element} />
|
||||
))}
|
||||
</div> */}
|
||||
<Button
|
||||
onClick={onNextPageHandler}
|
||||
style={{ width: "150px" }}
|
||||
|
@ -1,5 +0,0 @@
|
||||
export class LoginService {
|
||||
login(seedKey: string) {
|
||||
return fetch(`backend`);
|
||||
}
|
||||
}
|
@ -4,33 +4,32 @@ import React from "react";
|
||||
import { Card } from "antd";
|
||||
import { useState, useEffect, FC } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
type OrgData = {
|
||||
name: string;
|
||||
address: string;
|
||||
phone: number;
|
||||
};
|
||||
import Link from "next/link";
|
||||
import { Organization } from "../axios/api-types";
|
||||
|
||||
type OrgItemProps = {
|
||||
element: OrgData;
|
||||
element: Organization;
|
||||
};
|
||||
|
||||
export const OrganizationCard: FC<OrgItemProps> = ({ element }) => {
|
||||
const router = useRouter();
|
||||
const onNextPageHandler = () => {
|
||||
router.push("/organization/dashboard");
|
||||
};
|
||||
const id: any = element.id;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card
|
||||
title={element.name}
|
||||
type="inner"
|
||||
extra={
|
||||
<a onClick={onNextPageHandler} href="#">
|
||||
<Link
|
||||
href={{ pathname: "/organization/overview/dashboard/", query: id }}
|
||||
>
|
||||
More
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<p>{element.address}</p>
|
||||
<p>{element.phone}</p>
|
||||
<p>{element.name}</p>
|
||||
</Card>
|
||||
</>
|
||||
);
|
@ -6,35 +6,39 @@
|
||||
//* <h1>{seed.join("\n")}</h1> */shtuchka kak map
|
||||
|
||||
"use client";
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { Button, Modal } from "antd";
|
||||
import { useState } from "react";
|
||||
|
||||
import { apiService } from "../axios/global.service";
|
||||
import { OrgForm } from "./OrgForm";
|
||||
import { OrganizationCard } from "./OrgCard";
|
||||
import { FolderOpenTwoTone } from "@ant-design/icons";
|
||||
|
||||
type OrgData = {
|
||||
name: string;
|
||||
address: string;
|
||||
phone: number;
|
||||
};
|
||||
import {
|
||||
Organization,
|
||||
NewOrgResponse,
|
||||
OrganizationsResponse,
|
||||
} from "../axios/api-types";
|
||||
import Cookies from "js-cookie";
|
||||
export function OrgCreatePage() {
|
||||
const [organizations, setOrganizations] = useState([
|
||||
{
|
||||
name: "My Company",
|
||||
address: "2930 Pearl St Boulder, CO 80301 United States",
|
||||
phone: "+1303-245-0086",
|
||||
},
|
||||
]);
|
||||
const [organizations, setOrganizations] = useState<Organization[]>([]);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
const onFinish = (values: any) => {
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
address: "",
|
||||
});
|
||||
const onFinish = async (values: any) => {
|
||||
handleOk();
|
||||
setOrganizations((prev: any[]) => [...prev, formData]);
|
||||
setFormData({});
|
||||
setOrganizations((prev: any) => [...prev, formData]);
|
||||
|
||||
// setFormData({});
|
||||
const result = await apiService.newOrganization(
|
||||
formData.name,
|
||||
formData.address
|
||||
);
|
||||
if (result) {
|
||||
loadOrganizations();
|
||||
}
|
||||
};
|
||||
const [formData, setFormData] = useState({});
|
||||
const showModal = () => {
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
@ -46,7 +50,15 @@ export function OrgCreatePage() {
|
||||
const handleCancel = () => {
|
||||
setIsModalOpen(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadOrganizations();
|
||||
}, []);
|
||||
const loadOrganizations = async () => {
|
||||
const result: Organization[] = await apiService.getOrganizations();
|
||||
if (result) {
|
||||
setOrganizations(result.data.items);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className="flex relative overflow-hidden flex-col w-2/3 h-3/4 items-center justify-center z-30 gap-5 bg-white border-solid border rounded-md border-neutral-300 text-neutral-500">
|
@ -39,10 +39,10 @@ export function OrgForm({ setFormData }) {
|
||||
<Input
|
||||
name="name"
|
||||
style={{ width: 350 }}
|
||||
onInput={(e: any) =>
|
||||
onInput={(element: any) =>
|
||||
setFormData((prev: object) => ({
|
||||
...prev,
|
||||
[e.target.name]: e.target.value,
|
||||
[element.target.name]: element.target.value,
|
||||
}))
|
||||
}
|
||||
/>
|
||||
@ -58,10 +58,10 @@ export function OrgForm({ setFormData }) {
|
||||
>
|
||||
<Input
|
||||
name="address"
|
||||
onInput={(e: any) =>
|
||||
onInput={(element: any) =>
|
||||
setFormData((prev: object) => ({
|
||||
...prev,
|
||||
[e.target.name]: e.target.value,
|
||||
[element.target.name]: element.target.value,
|
||||
}))
|
||||
}
|
||||
style={{ width: 350 }}
|
@ -1,7 +0,0 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { OrgProfile } from "./OrgProfile";
|
||||
|
||||
export default function Home() {
|
||||
return <OrgProfile />;
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
"use client";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Select, Typography, Card, Divider, Button } from "antd";
|
||||
import { WalletOutlined } from "@ant-design/icons";
|
||||
const handleChange = (value: string) => {
|
||||
console.log(`selected ${value}`);
|
||||
};
|
||||
|
||||
const { Title } = Typography;
|
||||
|
||||
export function AgreementPage() {
|
||||
return (
|
||||
<div className="flex flex-col w-full p-8 ">
|
||||
<Title style={{ color: "#302d43" }}>Agreement</Title>
|
||||
|
||||
<Card className="w-full ">
|
||||
<Divider
|
||||
style={{ color: "#1677FF" }}
|
||||
orientation="left"
|
||||
orientationMargin="0"
|
||||
>
|
||||
<a href="#">Owners</a>
|
||||
</Divider>
|
||||
<div className="flex flex-col gap-2">
|
||||
<Select
|
||||
suffixIcon={<WalletOutlined />}
|
||||
defaultValue={""}
|
||||
style={{ width: "full" }}
|
||||
allowClear
|
||||
options={[{ value: "", label: "" }]}
|
||||
/>
|
||||
<Select
|
||||
suffixIcon={<WalletOutlined />}
|
||||
defaultValue={""}
|
||||
style={{ width: "full" }}
|
||||
allowClear
|
||||
options={[{ value: "", label: "" }]}
|
||||
/>
|
||||
<Select
|
||||
suffixIcon={<WalletOutlined />}
|
||||
defaultValue={""}
|
||||
style={{ width: "full" }}
|
||||
allowClear
|
||||
options={[{ value: "", label: "" }]}
|
||||
/>
|
||||
<Select
|
||||
suffixIcon={<WalletOutlined />}
|
||||
defaultValue={""}
|
||||
style={{ width: "full" }}
|
||||
allowClear
|
||||
options={[{ value: "", label: "" }]}
|
||||
/>
|
||||
<Select
|
||||
suffixIcon={<WalletOutlined />}
|
||||
defaultValue={""}
|
||||
style={{ width: "full" }}
|
||||
allowClear
|
||||
options={[{ value: "", label: "" }]}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
<div className="flex w-full justify-end mt-8">
|
||||
<Button size={"large"} style={{ width: 150 }} type="primary">
|
||||
Confirm
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
11
front/src/app/organization/overview/agreement/page.tsx
Normal file
11
front/src/app/organization/overview/agreement/page.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { AgreementPage } from "./AgreementPage";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="flex w-full h-screen bg-slate-50">
|
||||
<AgreementPage />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,27 +1,10 @@
|
||||
"use client";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { Card } from "antd";
|
||||
import {
|
||||
AppstoreOutlined,
|
||||
ContainerOutlined,
|
||||
DesktopOutlined,
|
||||
MailOutlined,
|
||||
MenuFoldOutlined,
|
||||
MenuUnfoldOutlined,
|
||||
PieChartOutlined,
|
||||
UserOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import type { MenuProps } from "antd";
|
||||
import {
|
||||
Button,
|
||||
Menu,
|
||||
List,
|
||||
Divider,
|
||||
Typography,
|
||||
Avatar,
|
||||
Skeleton,
|
||||
} from "antd";
|
||||
import { UserOutlined } from "@ant-design/icons";
|
||||
import { Button, List, Divider, Typography, Avatar, Skeleton } from "antd";
|
||||
|
||||
interface DataType {
|
||||
gender?: string;
|
||||
name: {
|
||||
@ -41,7 +24,6 @@ interface DataType {
|
||||
const count = 3;
|
||||
const fakeDataUrl = `https://randomuser.me/api/?results=${count}&inc=name,gender,email,nat,picture&noinfo`;
|
||||
|
||||
type MenuItem = Required<MenuProps>["items"][number];
|
||||
const data = [
|
||||
"Ackee Blockchain is a team of auditors and white hat hackers who perform security audits and assessments for Ethereum and Solana.",
|
||||
"Global blockchain services company and Initial Coin Offering solutions provider",
|
||||
@ -50,51 +32,23 @@ const data = [
|
||||
"Securing the DeFi ecosystem",
|
||||
];
|
||||
|
||||
const items: MenuItem[] = [
|
||||
{ key: "1", icon: <PieChartOutlined />, label: "Wallet Info" },
|
||||
{ key: "2", icon: <DesktopOutlined />, label: "Option 2" },
|
||||
{ key: "3", icon: <ContainerOutlined />, label: "Contracts" },
|
||||
{
|
||||
key: "sub1",
|
||||
label: "Navigation One",
|
||||
icon: <MailOutlined />,
|
||||
// children: [
|
||||
// { key: "5", label: "Option 5" },
|
||||
// { key: "6", label: "Option 6" },
|
||||
// ],
|
||||
},
|
||||
{
|
||||
key: "sub2",
|
||||
label: "Navigation Two",
|
||||
icon: <AppstoreOutlined />,
|
||||
children: [
|
||||
{ key: "9", label: "Option 9" },
|
||||
{ key: "10", label: "Option 10" },
|
||||
{
|
||||
key: "sub3",
|
||||
label: "Submenu",
|
||||
children: [
|
||||
{ key: "11", label: "Option 11" },
|
||||
{ key: "12", label: "Option 12" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
const { Title } = Typography;
|
||||
|
||||
export function OrgProfile() {
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const [initLoading, setInitLoading] = useState(true);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dataEmployees, setData] = useState<DataType[]>([]);
|
||||
const [list, setList] = useState<DataType[]>([]);
|
||||
|
||||
const router = useRouter();
|
||||
const pathname = useSearchParams();
|
||||
console.log(pathname.getAll("query"));
|
||||
|
||||
const onNextPageHandler = () => {
|
||||
router.push("/organization/employees");
|
||||
router.push("/organization/overview/employees");
|
||||
};
|
||||
const onMultisigPageHandler = () => {
|
||||
router.push("/organization/multiSig");
|
||||
router.push("/organization/overview/multiSig");
|
||||
};
|
||||
useEffect(() => {
|
||||
fetch(fakeDataUrl)
|
||||
@ -144,25 +98,8 @@ export function OrgProfile() {
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div className="flex flex-row w-full h-full bg-slate-50 gap-5 pb-20 px-30 p-10">
|
||||
<div className="w-24 py-2">
|
||||
<div>
|
||||
<Menu
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
height: "228px",
|
||||
border: "solid 1px #1677FF",
|
||||
}}
|
||||
defaultSelectedKeys={["1"]}
|
||||
defaultOpenKeys={["sub1"]}
|
||||
mode="inline"
|
||||
theme="light"
|
||||
inlineCollapsed={collapsed}
|
||||
items={items}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col w-11/12 pr-10">
|
||||
<div className="flex flex-row w-full h-full bg-slate-50 p-8">
|
||||
<div className="flex flex-col w-11/12 ">
|
||||
<Title style={{ color: "#302d43", textIndent: 15 }}>Dashboard</Title>
|
||||
<Card
|
||||
title="Organization Name"
|
||||
@ -188,7 +125,7 @@ export function OrgProfile() {
|
||||
orientation="left"
|
||||
orientationMargin="0"
|
||||
>
|
||||
Recent Activities
|
||||
<a href="#">Contracts</a>
|
||||
</Divider>
|
||||
<List
|
||||
bordered
|
||||
@ -214,7 +151,9 @@ export function OrgProfile() {
|
||||
orientation="left"
|
||||
orientationMargin="0"
|
||||
>
|
||||
Employee List
|
||||
<a href="http://localhost:3000/organization/employees/employeeList">
|
||||
Employee List
|
||||
</a>
|
||||
</Divider>
|
||||
<List
|
||||
className="demo-loadmore-list"
|
11
front/src/app/organization/overview/dashboard/page.tsx
Normal file
11
front/src/app/organization/overview/dashboard/page.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { OrgProfile } from "./id";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="flex flex-row w-full h-screen bg-slate-50 gap-5">
|
||||
<OrgProfile />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -6,10 +6,10 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Input, Button, Typography, Space } from "antd";
|
||||
import { MailOutlined, CopyOutlined } from "@ant-design/icons";
|
||||
export function EmployeePage() {
|
||||
export function EmployeeInvitatonPage() {
|
||||
const { Text } = Typography;
|
||||
return (
|
||||
<div className="flex relative overflow-hidden flex-col w-2/3 h-3/4 items-center justify-center gap-10 bg-white border-solid border rounded-md border-neutral-300 text-neutral-500">
|
||||
<div className="flex relative overflow-hidden flex-col w-2/3 h-3/4 items-center justify-center gap-10 bg-white border-solid border rounded-md border-neutral-300 p-10 text-neutral-500">
|
||||
<div className="w-full h-20 bg-[#1677FF] absolute top-0 flex items-center justify-center">
|
||||
<h1 className="text-white text-xl font-semibold">Invite</h1>
|
||||
</div>
|
@ -0,0 +1,103 @@
|
||||
"use client";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Button, Menu, List, Typography, Avatar, Skeleton } from "antd";
|
||||
import { UserOutlined } from "@ant-design/icons";
|
||||
import type { MenuProps } from "antd";
|
||||
import { PayOutBtn } from "@/app/ui/PayOutBtn";
|
||||
const count = 8;
|
||||
const fakeDataUrl = `https://randomuser.me/api/?results=${count}&inc=name,gender,email,nat,picture&noinfo`;
|
||||
interface DataType {
|
||||
gender?: string;
|
||||
name: {
|
||||
title?: string;
|
||||
first?: string;
|
||||
last?: string;
|
||||
};
|
||||
email?: string;
|
||||
picture: {
|
||||
large?: string;
|
||||
medium?: string;
|
||||
thumbnail?: string;
|
||||
};
|
||||
nat?: string;
|
||||
loading: boolean;
|
||||
}
|
||||
const { Title } = Typography;
|
||||
type MenuItem = Required<MenuProps>["items"][number];
|
||||
export function EmployeeList() {
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const [initLoading, setInitLoading] = useState(true);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dataEmployees, setData] = useState<DataType[]>([]);
|
||||
const [list, setList] = useState<DataType[]>([]);
|
||||
useEffect(() => {
|
||||
fetch(fakeDataUrl)
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
setInitLoading(false);
|
||||
setData(res.results);
|
||||
setList(res.results);
|
||||
});
|
||||
}, []);
|
||||
const onLoadMore = () => {
|
||||
setLoading(true);
|
||||
setList(
|
||||
dataEmployees.concat(
|
||||
[...new Array(count)].map(() => ({
|
||||
loading: true,
|
||||
name: {},
|
||||
picture: {},
|
||||
}))
|
||||
)
|
||||
);
|
||||
fetch(fakeDataUrl)
|
||||
.then((res) => res.json())
|
||||
.then((res) => {
|
||||
const newData = dataEmployees.concat(res.results);
|
||||
setData(newData);
|
||||
setList(newData);
|
||||
setLoading(false);
|
||||
// Resetting window's offsetTop so as to display react-virtualized demo underfloor.
|
||||
// In real scene, you can using public method of react-virtualized:
|
||||
// https://stackoverflow.com/questions/46700726/how-to-use-public-method-updateposition-of-react-virtualized
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
});
|
||||
};
|
||||
const loadMore =
|
||||
!initLoading && !loading ? (
|
||||
<div
|
||||
style={{
|
||||
textAlign: "center",
|
||||
marginTop: 12,
|
||||
height: 32,
|
||||
lineHeight: "32px",
|
||||
}}
|
||||
>
|
||||
<Button onClick={onLoadMore}>loading more</Button>
|
||||
</div>
|
||||
) : null;
|
||||
return (
|
||||
<div className="flex flex-col w-full h-full gap-5 pb-20 px-30 p-8">
|
||||
<Title style={{ color: "#302d43", textIndent: 15 }}>Employee List</Title>
|
||||
<List
|
||||
className="demo-loadmore-list"
|
||||
loading={initLoading}
|
||||
itemLayout="horizontal"
|
||||
loadMore={loadMore}
|
||||
dataSource={list}
|
||||
renderItem={(item) => (
|
||||
<List.Item actions={[<PayOutBtn />]}>
|
||||
<Skeleton avatar title={false} loading={item.loading} active>
|
||||
<List.Item.Meta
|
||||
avatar={<Avatar icon={<UserOutlined />} />}
|
||||
title={<a href="https://ant.design">{item.name?.last}</a>}
|
||||
description="1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71"
|
||||
/>
|
||||
<div>wallet address</div>
|
||||
</Skeleton>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { EmployeeList } from "./EmployeeList";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="flex w-full h-screen items-center justify-center bg-slate-50">
|
||||
<EmployeeList />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { EmployeePage } from "./Employee";
|
||||
import { EmployeeInvitatonPage } from "./Employee";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="flex w-full h-screen items-center justify-center bg-white">
|
||||
<EmployeePage />
|
||||
<EmployeeInvitatonPage />
|
||||
</div>
|
||||
);
|
||||
}
|
117
front/src/app/organization/overview/layout.tsx
Normal file
117
front/src/app/organization/overview/layout.tsx
Normal file
@ -0,0 +1,117 @@
|
||||
"use client";
|
||||
import React, { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { BackBtn } from "@/app/ui/BackBtn";
|
||||
import {
|
||||
PieChartOutlined,
|
||||
KeyOutlined,
|
||||
UsergroupAddOutlined,
|
||||
FileProtectOutlined,
|
||||
WalletOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import type { MenuProps } from "antd";
|
||||
import { Menu } from "antd";
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
type MenuItem = Required<MenuProps>["items"][number];
|
||||
const [collapsed, setCollapsed] = useState(true);
|
||||
const items: MenuItem[] = [
|
||||
{
|
||||
key: "1",
|
||||
icon: <PieChartOutlined />,
|
||||
label: (
|
||||
<Link href="http://localhost:3000/organization/overview/dashboard">
|
||||
Overview
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "2",
|
||||
icon: <FileProtectOutlined />,
|
||||
|
||||
children: [
|
||||
{
|
||||
key: "5",
|
||||
label: (
|
||||
<Link href="http://localhost:3000/organization/overview/license">
|
||||
Licenses
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "6",
|
||||
label: (
|
||||
<Link href="http://localhost:3000/organization/overview/agreement">
|
||||
Agreement
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "3",
|
||||
icon: <WalletOutlined />,
|
||||
label: "Transactions",
|
||||
children: [
|
||||
{
|
||||
key: "5",
|
||||
label: (
|
||||
<Link href="http://localhost:3000/organization/overview/pending">
|
||||
Pending Contracts
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{ key: "6", label: "Option 6" },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "4",
|
||||
icon: <UsergroupAddOutlined />,
|
||||
label: (
|
||||
<Link href="http://localhost:3000/organization//overview/employees/employeeList">
|
||||
Employees
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "sub1",
|
||||
|
||||
label: (
|
||||
<Link href="http://localhost:3000/organization/overview/multiSig">
|
||||
Multisig
|
||||
</Link>
|
||||
),
|
||||
icon: <KeyOutlined />,
|
||||
// children: [
|
||||
// { key: "5", label: "Option 5" },
|
||||
// { key: "6", label: "Option 6" },
|
||||
// ],
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div className="flex h-screen flex-col md:flex-row md:overflow-hidden justify-center pl-10 bg-slate-50">
|
||||
<div className="w-full flex-none md:w-24 pt-24">
|
||||
<Menu
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
height: "228px",
|
||||
border: "solid 1px #1677FF",
|
||||
}}
|
||||
defaultSelectedKeys={["1"]}
|
||||
defaultOpenKeys={["sub1"]}
|
||||
mode="inline"
|
||||
theme="light"
|
||||
inlineCollapsed={collapsed}
|
||||
items={items}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-grow md:overflow-y-auto pt-2">
|
||||
<div className="flex justify-end pt-2 mr-2">
|
||||
<BackBtn />
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
49
front/src/app/organization/overview/license/LicensesPage.tsx
Normal file
49
front/src/app/organization/overview/license/LicensesPage.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Typography, Button, Card, Input } from "antd";
|
||||
import { WalletOutlined } from "@ant-design/icons";
|
||||
|
||||
const { Title } = Typography;
|
||||
const data = [
|
||||
"1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71",
|
||||
"1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71",
|
||||
"1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71",
|
||||
"1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71",
|
||||
"1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71",
|
||||
];
|
||||
|
||||
export function LicensesPage() {
|
||||
return (
|
||||
<div className="flex flex-col w-full p-8 ">
|
||||
<Title style={{ color: "#302d43" }}>Licenses</Title>
|
||||
|
||||
<Card style={{ width: "100%" }}>
|
||||
<div className=" flex flex-row w-full gap-10">
|
||||
<div className="flex flex-col gap-2 w-1/4">
|
||||
<Title level={4}>Owners</Title>
|
||||
<Input placeholder="Name" />
|
||||
<Input placeholder="Name" />
|
||||
<Input placeholder="Name" />
|
||||
<Input placeholder="Name" />
|
||||
<Input placeholder="Name" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<Title level={4}>Shares</Title>
|
||||
|
||||
<Input placeholder="Input information" />
|
||||
<Input placeholder="Input information" />
|
||||
<Input placeholder="Input information" />
|
||||
<Input placeholder="Input information" />
|
||||
<Input placeholder="Input information" />
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<div className="flex w-full justify-end mt-5">
|
||||
<Button size={"large"} style={{ width: "150px" }} type="primary">
|
||||
Confirm
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
//suffixIcon={<WalletOutlined />}
|
11
front/src/app/organization/overview/license/page.tsx
Normal file
11
front/src/app/organization/overview/license/page.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { LicensesPage } from "./LicensesPage";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="flex w-full h-screen bg-slate-50">
|
||||
<LicensesPage />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -3,8 +3,9 @@ import React, { useState } from "react";
|
||||
import { Input } from "antd";
|
||||
import { Typography } from "antd";
|
||||
import { Card } from "antd";
|
||||
import { WalletOutlined } from "@ant-design/icons";
|
||||
import type { InputNumberProps } from "antd";
|
||||
import { Col, InputNumber, Row, Slider, Space, Button } from "antd";
|
||||
import { Col, InputNumber, Row, Slider, Select, Button } from "antd";
|
||||
|
||||
const { Title } = Typography;
|
||||
|
||||
@ -14,14 +15,14 @@ export function MultisigPage() {
|
||||
setInputValue(newValue as number);
|
||||
};
|
||||
return (
|
||||
<div className="flex flex-col w-full h-full px-28 py-20 gap-10 ">
|
||||
<div className="flex flex-col w-full h-full p-8 gap-10 ">
|
||||
<div className="flex flex-col w-1/3">
|
||||
<Title level={3}>Create a new Multisig</Title>
|
||||
<Title>Create a new Multisig</Title>
|
||||
<Input size="large" placeholder="Multisig Name/Label" />
|
||||
</div>
|
||||
<div className="flex w-full ">
|
||||
<Card style={{ width: "100%" }}>
|
||||
<Title level={4}>Signers</Title>
|
||||
<Title level={4}>Owners</Title>
|
||||
<div className="flex flex-row gap-5">
|
||||
<div className="flex flex-col gap-2 w-1/4">
|
||||
<Input placeholder="Name" />
|
||||
@ -29,14 +30,32 @@ export function MultisigPage() {
|
||||
<Input placeholder="Name" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<Input placeholder="Pubic Key" />
|
||||
<Input placeholder="Pubic Key" />
|
||||
<Input placeholder="Pubic Key" />
|
||||
<Select
|
||||
suffixIcon={<WalletOutlined />}
|
||||
defaultValue={""}
|
||||
style={{ width: "full" }}
|
||||
allowClear
|
||||
options={[{ value: "", label: "" }]}
|
||||
/>
|
||||
<Select
|
||||
suffixIcon={<WalletOutlined />}
|
||||
defaultValue={""}
|
||||
style={{ width: "full" }}
|
||||
allowClear
|
||||
options={[{ value: "", label: "" }]}
|
||||
/>
|
||||
<Select
|
||||
suffixIcon={<WalletOutlined />}
|
||||
defaultValue={""}
|
||||
style={{ width: "full" }}
|
||||
allowClear
|
||||
options={[{ value: "", label: "" }]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full justify-end mt-5">
|
||||
<Button size={"large"} type="primary">
|
||||
Add Signer
|
||||
Add Owner
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
@ -53,7 +72,7 @@ export function MultisigPage() {
|
||||
<Col span={12}>
|
||||
<Slider
|
||||
min={1}
|
||||
max={20}
|
||||
max={5}
|
||||
onChange={onChange}
|
||||
value={typeof inputValue === "number" ? inputValue : 0}
|
||||
/>
|
||||
@ -61,7 +80,7 @@ export function MultisigPage() {
|
||||
<Col span={4}>
|
||||
<InputNumber
|
||||
min={1}
|
||||
max={20}
|
||||
max={5}
|
||||
style={{ margin: "0 16px" }}
|
||||
value={inputValue}
|
||||
onChange={onChange}
|
91
front/src/app/organization/overview/pending/PendingPage.tsx
Normal file
91
front/src/app/organization/overview/pending/PendingPage.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
"use client";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Steps, Typography, Card, Input, Space, Button, Select } from "antd";
|
||||
import type { MenuProps } from "antd";
|
||||
import { WalletOutlined } from "@ant-design/icons";
|
||||
const { Title } = Typography;
|
||||
type MenuItem = Required<MenuProps>["items"][number];
|
||||
const data = [
|
||||
"1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71",
|
||||
"1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71",
|
||||
"1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71",
|
||||
"1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71",
|
||||
"1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71",
|
||||
];
|
||||
|
||||
export function PendingPage() {
|
||||
return (
|
||||
<div className="flex flex-col w-full h-full gap-5 p-8 ">
|
||||
<Title style={{ color: "#302d43" }}>Pending Confirmations</Title>
|
||||
<Steps
|
||||
current={1}
|
||||
items={[
|
||||
{
|
||||
title: "Request",
|
||||
},
|
||||
{
|
||||
title: "Verify",
|
||||
},
|
||||
{
|
||||
title: "Success",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Card className="flex flex-col w-full ">
|
||||
<Space.Compact style={{ width: "100%" }}>
|
||||
<Input
|
||||
size="middle"
|
||||
defaultValue=""
|
||||
placeholder="Pay Out Transaction"
|
||||
/>
|
||||
<Button style={{ color: "#4096ff", borderColor: "#4096ff" }}>
|
||||
Submit
|
||||
</Button>
|
||||
</Space.Compact>
|
||||
|
||||
<div className="flex justify-end mt-5">
|
||||
<Button type="primary" style={{ width: "150px" }}>
|
||||
Execute
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="flex flex-col w-full ">
|
||||
<Space.Compact style={{ width: "100%" }}>
|
||||
<Input
|
||||
size="middle"
|
||||
defaultValue=""
|
||||
placeholder="Pay Out Transaction"
|
||||
/>
|
||||
<Button style={{ color: "#4096ff", borderColor: "#4096ff" }}>
|
||||
Submit
|
||||
</Button>
|
||||
</Space.Compact>
|
||||
|
||||
<div className="flex justify-end mt-5">
|
||||
<Button type="primary" style={{ width: "150px" }}>
|
||||
Execute
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="flex flex-col w-full ">
|
||||
<Space.Compact style={{ width: "100%" }}>
|
||||
<Input
|
||||
size="middle"
|
||||
defaultValue=""
|
||||
placeholder="Pay Out Transaction"
|
||||
/>
|
||||
<Button style={{ color: "#4096ff", borderColor: "#4096ff" }}>
|
||||
Submit
|
||||
</Button>
|
||||
</Space.Compact>
|
||||
|
||||
<div className="flex justify-end mt-5">
|
||||
<Button type="primary" style={{ width: "150px" }}>
|
||||
Execute
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
11
front/src/app/organization/overview/pending/page.tsx
Normal file
11
front/src/app/organization/overview/pending/page.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { PendingPage } from "./PendingPage";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="flex w-full h-screen items-center justify-center bg-slate-50">
|
||||
<PendingPage />
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { OrgCreatePage } from "./OrgCreatePage";
|
||||
// вместо этого надо класть большие компоненты
|
||||
import { OrgCreatePage } from "../orgCreate/OrgCreatePage";
|
||||
|
||||
export default function organization() {
|
||||
return (
|
||||
|
20
front/src/app/ui/BackBtn.tsx
Normal file
20
front/src/app/ui/BackBtn.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
"use client";
|
||||
import { Button } from "antd";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { ArrowLeftOutlined } from "@ant-design/icons";
|
||||
export function BackBtn() {
|
||||
const router = useRouter();
|
||||
const goBack = () => {
|
||||
router.back();
|
||||
};
|
||||
return (
|
||||
<Button
|
||||
className="flex items-center"
|
||||
type="text"
|
||||
size="large"
|
||||
onClick={goBack}
|
||||
>
|
||||
<ArrowLeftOutlined />
|
||||
</Button>
|
||||
);
|
||||
}
|
14
front/src/app/ui/PayOutBtn.tsx
Normal file
14
front/src/app/ui/PayOutBtn.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
import { Button } from "antd";
|
||||
import { useRouter } from "next/navigation";
|
||||
export function PayOutBtn() {
|
||||
const router = useRouter();
|
||||
const onPayHandler = () => {
|
||||
router.push("/organization/overview/pending");
|
||||
};
|
||||
return (
|
||||
<Button onClick={onPayHandler} type="primary">
|
||||
Pay Out
|
||||
</Button>
|
||||
);
|
||||
}
|
@ -2,14 +2,11 @@ import { useState } from "react";
|
||||
|
||||
export default function useLoginHooks() {
|
||||
const [passwordVisible, setPasswordVisible] = useState([]);
|
||||
const [seed, setSeed] = useState<string[]>([]);
|
||||
|
||||
const getSeed = (string: string) => {
|
||||
if (seed.length < 12) {
|
||||
setSeed((prev) => [...prev, string]);
|
||||
}
|
||||
};
|
||||
console.log(seed);
|
||||
// const getSeed = (string: string) => {
|
||||
// // if (seed.length < 12) {
|
||||
// setSeed((prev) => [...prev, string]);
|
||||
// };
|
||||
|
||||
return { passwordVisible, setPasswordVisible, seed, getSeed };
|
||||
return { passwordVisible, setPasswordVisible };
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user