mirror of
https://github.com/emo2007/block-accounting.git
synced 2025-01-18 07:26:27 +00:00
org emp multi back intg
This commit is contained in:
parent
1082e2fa6c
commit
e6611d88fa
@ -32,6 +32,13 @@ export type PublicKey = {
|
|||||||
export type DeployResponse = {
|
export type DeployResponse = {
|
||||||
title: string;
|
title: string;
|
||||||
owners: PublicKey[];
|
owners: PublicKey[];
|
||||||
confirmations: number;
|
confirmations: string;
|
||||||
};
|
};
|
||||||
export type MultiSigResponse = {};
|
export type MultiSigResponse = {};
|
||||||
|
|
||||||
|
export type InvitationResponse = {
|
||||||
|
token: string;
|
||||||
|
token_expired_at: number;
|
||||||
|
refresh_token: string;
|
||||||
|
refresh_token_expired_at: number;
|
||||||
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { globalService } from "../axios/global-api";
|
import { globalService } from "../axios/global-api";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
LoginResponse,
|
LoginResponse,
|
||||||
OrganizationsResponse,
|
OrganizationsResponse,
|
||||||
@ -9,6 +10,7 @@ import {
|
|||||||
AddPartResponse,
|
AddPartResponse,
|
||||||
DeployResponse,
|
DeployResponse,
|
||||||
MultiSigResponse,
|
MultiSigResponse,
|
||||||
|
InvitationResponse,
|
||||||
} from "./api-types";
|
} from "./api-types";
|
||||||
export class AccountingService {
|
export class AccountingService {
|
||||||
async login(seedKey: string): Promise<AxiosResponse<LoginResponse>> {
|
async login(seedKey: string): Promise<AxiosResponse<LoginResponse>> {
|
||||||
@ -44,10 +46,16 @@ export class AccountingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getEmployees(
|
async getEmployees(
|
||||||
organizationId: string
|
organizationId: string,
|
||||||
|
ids: string[]
|
||||||
): Promise<AxiosResponse<ParticipantsResponse>> {
|
): Promise<AxiosResponse<ParticipantsResponse>> {
|
||||||
return await globalService.get(
|
return await globalService.post(
|
||||||
`organizations/${organizationId}/participants`
|
`organizations/${organizationId}/participants/fetch`,
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
ids: [...ids, organizationId],
|
||||||
|
},
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,16 +77,19 @@ export class AccountingService {
|
|||||||
|
|
||||||
// POST /organizations/{organization_id}/multisig
|
// POST /organizations/{organization_id}/multisig
|
||||||
async deployMultisig(
|
async deployMultisig(
|
||||||
organization_id: string,
|
organizationId: string,
|
||||||
title: string,
|
title: string,
|
||||||
owners: string[],
|
owners: string[],
|
||||||
confirmations: number
|
confirmations: number
|
||||||
): Promise<AxiosResponse<DeployResponse>> {
|
): Promise<AxiosResponse<DeployResponse>> {
|
||||||
return await globalService.post(`${organization_id}/multi-sig`, {
|
return await globalService.post(
|
||||||
title,
|
`organizations/${organizationId}/multisig`,
|
||||||
owners,
|
{
|
||||||
confirmations,
|
title,
|
||||||
});
|
owners,
|
||||||
|
confirmations,
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getAllMultisigsByOrganizationId(
|
async getAllMultisigsByOrganizationId(
|
||||||
@ -86,6 +97,25 @@ export class AccountingService {
|
|||||||
): Promise<AxiosResponse<MultiSigResponse>> {
|
): Promise<AxiosResponse<MultiSigResponse>> {
|
||||||
return await globalService.get(`organizations/${organizationId}/multisig`);
|
return await globalService.get(`organizations/${organizationId}/multisig`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async sentInvitation(
|
||||||
|
hash: string,
|
||||||
|
name: string,
|
||||||
|
credentals: {
|
||||||
|
email: string;
|
||||||
|
phone: string;
|
||||||
|
telegram: string;
|
||||||
|
},
|
||||||
|
mnemonic: string
|
||||||
|
): Promise<AxiosResponse<InvitationResponse>> {
|
||||||
|
return await globalService.post(`/invite/${hash}/join`, {
|
||||||
|
data: {
|
||||||
|
name,
|
||||||
|
credentals,
|
||||||
|
mnemonic,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const apiService = new AccountingService();
|
export const apiService = new AccountingService();
|
||||||
|
@ -14,17 +14,32 @@ export function LoginPage() {
|
|||||||
const { passwordVisible, setPasswordVisible } = useLoginHooks();
|
const { passwordVisible, setPasswordVisible } = useLoginHooks();
|
||||||
const [inp, setInp] = useState("");
|
const [inp, setInp] = useState("");
|
||||||
//
|
//
|
||||||
const [seed, setSeed] = useState<string[]>(["airport","donate","language","disagree","dumb","access","insect","tribe","ozone","humor","foot","jealous","much","digital",]);
|
const [seed, setSeed] = useState<string[]>([
|
||||||
|
"airport",
|
||||||
|
"donate",
|
||||||
|
"language",
|
||||||
|
"disagree",
|
||||||
|
"dumb",
|
||||||
|
"access",
|
||||||
|
"insect",
|
||||||
|
"tribe",
|
||||||
|
"ozone",
|
||||||
|
"humor",
|
||||||
|
"foot",
|
||||||
|
"jealous",
|
||||||
|
"much",
|
||||||
|
"digital",
|
||||||
|
]);
|
||||||
|
|
||||||
// const [seed, setSeed] = useState<string[]>(["melody","correct","brain","slide","flip","polar","asset","know","pencil","major","smile","vital","nominee","merge","addict"]);
|
// const [seed, setSeed] = useState<string[]>(["melody","correct","brain","slide","flip","polar","asset","know","pencil","major","smile","vital","nominee","merge","addict"]);
|
||||||
const [disabled, setDisabled] = useState(true);
|
const [disabled, setDisabled] = useState(true);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const onLogin = async () => {
|
const onLogin = async () => {
|
||||||
const result = await apiService.login(seed.join(' '));
|
const result = await apiService.login(seed.join(" "));
|
||||||
// if (result) {
|
// if (result) {
|
||||||
Cookies.set("accessToken", result.data.token);
|
Cookies.set("accessToken", result.data.token);
|
||||||
router.push("/organization");
|
router.push("/organization");
|
||||||
// }
|
// }
|
||||||
};
|
};
|
||||||
const onRegister = async () => {
|
const onRegister = async () => {
|
||||||
@ -33,7 +48,7 @@ export function LoginPage() {
|
|||||||
Cookies.set("accessToken", result.data.token);
|
Cookies.set("accessToken", result.data.token);
|
||||||
router.push("/organization");
|
router.push("/organization");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
// const getSeed = (event: React.ChangeEvent<HTMLInputElement>) => {
|
// const getSeed = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
// setSeed(inp);
|
// setSeed(inp);
|
||||||
// };
|
// };
|
||||||
@ -44,7 +59,7 @@ export function LoginPage() {
|
|||||||
}, [inp]);
|
}, [inp]);
|
||||||
|
|
||||||
const onSubmitHandler = async () => {
|
const onSubmitHandler = async () => {
|
||||||
setSeed((prevState) => prevState ? [...prevState, inp] : [inp]);
|
setSeed((prevState) => (prevState ? [...prevState, inp] : [inp]));
|
||||||
setInp("");
|
setInp("");
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -91,14 +106,17 @@ export function LoginPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Space.Compact>
|
</Space.Compact>
|
||||||
</div>
|
</div>
|
||||||
{ <div
|
{
|
||||||
className="flex flex-row w-[700px] gap-3 content-box flex-wrap
|
<div
|
||||||
|
className="flex flex-row w-[700px] gap-3 content-box flex-wrap
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{seed && seed.map((element: string, index: number) => (
|
{seed &&
|
||||||
<SeedItem key={index} seed={element} />
|
seed.map((element: string, index: number) => (
|
||||||
))}
|
<SeedItem key={index} seed={element} />
|
||||||
</div> }
|
))}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<Button
|
<Button
|
||||||
onClick={onLogin}
|
onClick={onLogin}
|
||||||
style={{ width: "150px" }}
|
style={{ width: "150px" }}
|
||||||
@ -108,10 +126,10 @@ export function LoginPage() {
|
|||||||
Login
|
Login
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={onRegister}
|
onClick={onRegister}
|
||||||
style={{ width: "150px" }}
|
style={{ width: "150px" }}
|
||||||
type="primary"
|
type="primary"
|
||||||
size="large"
|
size="large"
|
||||||
>
|
>
|
||||||
Join
|
Join
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -14,7 +14,6 @@ type OrgItemProps = {
|
|||||||
export const OrganizationCard: FC<OrgItemProps> = ({ element }) => {
|
export const OrganizationCard: FC<OrgItemProps> = ({ element }) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const id: any = element.id;
|
const id: any = element.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card
|
<Card
|
||||||
@ -22,7 +21,10 @@ export const OrganizationCard: FC<OrgItemProps> = ({ element }) => {
|
|||||||
type="inner"
|
type="inner"
|
||||||
extra={
|
extra={
|
||||||
<Link
|
<Link
|
||||||
href={{ pathname: "/organization/overview/dashboard/", query: id }}
|
href={{
|
||||||
|
pathname: "/organization/overview/dashboard/",
|
||||||
|
query: { id: id },
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Go To Overview
|
Go To Overview
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -13,6 +13,7 @@ import { apiService } from "../axios/global.service";
|
|||||||
import { OrgForm } from "./OrgForm";
|
import { OrgForm } from "./OrgForm";
|
||||||
import { OrganizationCard } from "./OrgCard";
|
import { OrganizationCard } from "./OrgCard";
|
||||||
import { FolderOpenTwoTone } from "@ant-design/icons";
|
import { FolderOpenTwoTone } from "@ant-design/icons";
|
||||||
|
import useOrganizationsHooks from "@/hooks/organizations";
|
||||||
import {
|
import {
|
||||||
Organization,
|
Organization,
|
||||||
NewOrgResponse,
|
NewOrgResponse,
|
||||||
@ -20,7 +21,8 @@ import {
|
|||||||
} from "../axios/api-types";
|
} from "../axios/api-types";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
export function OrgCreatePage() {
|
export function OrgCreatePage() {
|
||||||
const [organizations, setOrganizations] = useState<Organization[]>([]);
|
//const [organizations, setOrganizations] = useState<Organization[]>([]);
|
||||||
|
const { organizations, setOrganizations } = useOrganizationsHooks();
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
name: "",
|
name: "",
|
||||||
@ -47,16 +49,19 @@ export function OrgCreatePage() {
|
|||||||
setIsModalOpen(false);
|
setIsModalOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(organizations);
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
setIsModalOpen(false);
|
setIsModalOpen(false);
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadOrganizations();
|
loadOrganizations();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const loadOrganizations = async () => {
|
const loadOrganizations = async () => {
|
||||||
const result = await apiService.getOrganizations();
|
const result = await apiService.getOrganizations();
|
||||||
if (result) {
|
if (result) {
|
||||||
setOrganizations(result.data.items);
|
setOrganizations(result.data.items || []);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
@ -69,7 +74,7 @@ export function OrgCreatePage() {
|
|||||||
</div>
|
</div>
|
||||||
<div></div>
|
<div></div>
|
||||||
<div className="flex flex-col relative w-full h-3/4 items-center overflow-scroll gap-10 p-10 z-0">
|
<div className="flex flex-col relative w-full h-3/4 items-center overflow-scroll gap-10 p-10 z-0">
|
||||||
{organizations.length === 0 && (
|
{organizations.length && (
|
||||||
<FolderOpenTwoTone style={{ fontSize: "400%" }} />
|
<FolderOpenTwoTone style={{ fontSize: "400%" }} />
|
||||||
)}
|
)}
|
||||||
{organizations.length ? (
|
{organizations.length ? (
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { Card } from "antd";
|
import { useSearchParams } from "next/navigation";
|
||||||
import { UserOutlined } from "@ant-design/icons";
|
import { UserOutlined } from "@ant-design/icons";
|
||||||
import { Button, List, Divider, Typography, Avatar, Skeleton } from "antd";
|
import { Button, List, Divider, Typography, Avatar, Skeleton } from "antd";
|
||||||
|
import { OrganizationCard } from "@/app/orgCreate/OrgCard";
|
||||||
|
import { Organization } from "@/app/axios/api-types";
|
||||||
|
import useOrganizationsHooks from "@/hooks/organizations";
|
||||||
|
import { apiService } from "@/app/axios/global.service";
|
||||||
|
|
||||||
|
type OrgItemProps = {
|
||||||
|
element: Organization;
|
||||||
|
};
|
||||||
interface DataType {
|
interface DataType {
|
||||||
gender?: string;
|
gender?: string;
|
||||||
name: {
|
name: {
|
||||||
@ -35,53 +42,51 @@ const data = [
|
|||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
|
|
||||||
export function OrgProfile() {
|
export function OrgProfile() {
|
||||||
|
const { organizations, setOrganizations, loadOrganizations } =
|
||||||
|
useOrganizationsHooks();
|
||||||
|
const [organization, setOrganization] = useState<Organization>({
|
||||||
|
id: "",
|
||||||
|
name: "",
|
||||||
|
address: "",
|
||||||
|
});
|
||||||
const [initLoading, setInitLoading] = useState(true);
|
const [initLoading, setInitLoading] = useState(true);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [dataEmployees, setData] = useState<DataType[]>([]);
|
const [dataEmployees, setData] = useState<DataType[]>([]);
|
||||||
const [list, setList] = useState<DataType[]>([]);
|
const [list, setList] = useState<any[]>([]);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pathname = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
console.log(pathname.getAll("query"));
|
useEffect(() => {
|
||||||
|
const id = searchParams.get("id") || "";
|
||||||
|
const filteredOrganization = organizations.find(
|
||||||
|
(element) => element.id === id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (filteredOrganization) {
|
||||||
|
loadEmployees(id);
|
||||||
|
setOrganization(filteredOrganization);
|
||||||
|
setInitLoading(false);
|
||||||
|
}
|
||||||
|
}, [organizations]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadOrganizations();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const loadEmployees = async (id: string) => {
|
||||||
|
const data: any = await apiService.getEmployees(id, []);
|
||||||
|
setList(data.data.participants);
|
||||||
|
};
|
||||||
|
|
||||||
const onNextPageHandler = () => {
|
const onNextPageHandler = () => {
|
||||||
router.push("/organization/overview/employees");
|
router.push("/organization/overview/employees");
|
||||||
};
|
};
|
||||||
const onMultisigPageHandler = () => {
|
const onMultisigPageHandler = () => {
|
||||||
router.push("/organization/overview/multiSig");
|
router.push("/organization/overview/multiSig/?id=" + organization.id);
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
|
||||||
fetch(fakeDataUrl)
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((res) => {
|
|
||||||
setInitLoading(false);
|
|
||||||
setData(res.results);
|
|
||||||
setList(res.results);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
const onLoadMore = () => {
|
const onLoadMore = () => {
|
||||||
setLoading(true);
|
loadEmployees(organization.id);
|
||||||
setList(
|
setInitLoading(false);
|
||||||
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 =
|
const loadMore =
|
||||||
!initLoading && !loading ? (
|
!initLoading && !loading ? (
|
||||||
@ -101,7 +106,12 @@ export function OrgProfile() {
|
|||||||
<div className="flex flex-row w-full h-full bg-slate-50 p-8">
|
<div className="flex flex-row w-full h-full bg-slate-50 p-8">
|
||||||
<div className="flex flex-col w-11/12 ">
|
<div className="flex flex-col w-11/12 ">
|
||||||
<Title style={{ color: "#302d43", textIndent: 15 }}>Dashboard</Title>
|
<Title style={{ color: "#302d43", textIndent: 15 }}>Dashboard</Title>
|
||||||
<Card
|
|
||||||
|
<div style={{ width: "60%" }} className="flex flex-col ">
|
||||||
|
{organization && <OrganizationCard element={organization} />}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* <Card
|
||||||
title="Organization Name"
|
title="Organization Name"
|
||||||
bordered={false}
|
bordered={false}
|
||||||
style={{ width: "60%" }}
|
style={{ width: "60%" }}
|
||||||
@ -109,7 +119,7 @@ export function OrgProfile() {
|
|||||||
<p>Address</p>
|
<p>Address</p>
|
||||||
<p>Phone</p>
|
<p>Phone</p>
|
||||||
<p>Description</p>
|
<p>Description</p>
|
||||||
</Card>
|
</Card> */}
|
||||||
<div className="flex w-full justify-end ">
|
<div className="flex w-full justify-end ">
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
@ -161,23 +171,27 @@ export function OrgProfile() {
|
|||||||
itemLayout="horizontal"
|
itemLayout="horizontal"
|
||||||
loadMore={loadMore}
|
loadMore={loadMore}
|
||||||
dataSource={list}
|
dataSource={list}
|
||||||
renderItem={(item) => (
|
renderItem={(item) => {
|
||||||
<List.Item
|
console.log(item);
|
||||||
actions={[
|
|
||||||
<a key="list-loadmore-edit">edit</a>,
|
return (
|
||||||
<a key="list-loadmore-more">more</a>,
|
<List.Item
|
||||||
]}
|
actions={[
|
||||||
>
|
<a key="list-loadmore-edit">edit</a>,
|
||||||
<Skeleton avatar title={false} loading={item.loading} active>
|
<a key="list-loadmore-more">more</a>,
|
||||||
<List.Item.Meta
|
]}
|
||||||
avatar={<Avatar icon={<UserOutlined />} />}
|
>
|
||||||
title={<a href="https://ant.design">{item.name?.last}</a>}
|
<Skeleton avatar title={false} loading={item.loading} active>
|
||||||
description="1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71"
|
<List.Item.Meta
|
||||||
/>
|
avatar={<Avatar icon={<UserOutlined />} />}
|
||||||
<div>wallet address</div>
|
title={<a href="https://ant.design">{item.name}</a>}
|
||||||
</Skeleton>
|
description="1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71"
|
||||||
</List.Item>
|
/>
|
||||||
)}
|
<div>wallet address</div>
|
||||||
|
</Skeleton>
|
||||||
|
</List.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { OrgProfile } from "./id";
|
import { OrgProfile } from "./[id]";
|
||||||
|
import { useSearchParams } from "next/navigation";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
|
@ -6,8 +6,26 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Input, Button, Typography, Space } from "antd";
|
import { Input, Button, Typography, Space } from "antd";
|
||||||
import { MailOutlined, CopyOutlined } from "@ant-design/icons";
|
import { MailOutlined, CopyOutlined } from "@ant-design/icons";
|
||||||
|
import { apiService } from "@/app/axios/global.service";
|
||||||
|
|
||||||
export function EmployeeInvitatonPage() {
|
export function EmployeeInvitatonPage() {
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
const [values, setValues] = useState({
|
||||||
|
email: "ower@gmail.com",
|
||||||
|
phone: "79999999999",
|
||||||
|
telegram: "@ower",
|
||||||
|
});
|
||||||
|
|
||||||
|
async function sendInvite() {
|
||||||
|
const data = await apiService.sentInvitation(
|
||||||
|
"",
|
||||||
|
"Alex",
|
||||||
|
values,
|
||||||
|
"short orient camp maple lend pole balance token pledge fat analyst badge art happy sadsad"
|
||||||
|
);
|
||||||
|
console.log(data);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
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 p-10 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">
|
<div className="w-full h-20 bg-[#1677FF] absolute top-0 flex items-center justify-center">
|
||||||
@ -16,12 +34,21 @@ export function EmployeeInvitatonPage() {
|
|||||||
<div className="flex flex-col w-9/12 pb-36 gap-5 items-start ">
|
<div className="flex flex-col w-9/12 pb-36 gap-5 items-start ">
|
||||||
<Text type="secondary">Invite new Employee</Text>
|
<Text type="secondary">Invite new Employee</Text>
|
||||||
<Space.Compact style={{ width: "100%" }}>
|
<Space.Compact style={{ width: "100%" }}>
|
||||||
<Input size="large" addonBefore="E-mail" />
|
<Input
|
||||||
|
size="large"
|
||||||
|
name="email"
|
||||||
|
addonBefore="E-mail"
|
||||||
|
value={values.email}
|
||||||
|
onChange={(e) =>
|
||||||
|
setValues((prev) => ({ ...prev, email: e.target.value }))
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
size="large"
|
size="large"
|
||||||
icon={<MailOutlined />}
|
icon={<MailOutlined />}
|
||||||
style={{ width: 210 }}
|
style={{ width: 210 }}
|
||||||
type="primary"
|
type="primary"
|
||||||
|
onClick={sendInvite}
|
||||||
>
|
>
|
||||||
Send Invite
|
Send Invite
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -4,6 +4,10 @@ import { Button, Menu, List, Typography, Avatar, Skeleton } from "antd";
|
|||||||
import { UserOutlined } from "@ant-design/icons";
|
import { UserOutlined } from "@ant-design/icons";
|
||||||
import type { MenuProps } from "antd";
|
import type { MenuProps } from "antd";
|
||||||
import { PayOutBtn } from "@/app/ui/PayOutBtn";
|
import { PayOutBtn } from "@/app/ui/PayOutBtn";
|
||||||
|
import { apiService } from "@/app/axios/global.service";
|
||||||
|
import useOrganizationsHooks from "@/hooks/organizations";
|
||||||
|
import { useSearchParams } from "next/navigation";
|
||||||
|
import { Organization } from "@/app/axios/api-types";
|
||||||
const count = 8;
|
const count = 8;
|
||||||
const fakeDataUrl = `https://randomuser.me/api/?results=${count}&inc=name,gender,email,nat,picture&noinfo`;
|
const fakeDataUrl = `https://randomuser.me/api/?results=${count}&inc=name,gender,email,nat,picture&noinfo`;
|
||||||
interface DataType {
|
interface DataType {
|
||||||
@ -25,11 +29,35 @@ interface DataType {
|
|||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
type MenuItem = Required<MenuProps>["items"][number];
|
type MenuItem = Required<MenuProps>["items"][number];
|
||||||
export function EmployeeList() {
|
export function EmployeeList() {
|
||||||
|
const {
|
||||||
|
organizations,
|
||||||
|
filteredOrganization,
|
||||||
|
setOrganizations,
|
||||||
|
loadOrganizations,
|
||||||
|
} = useOrganizationsHooks();
|
||||||
const [collapsed, setCollapsed] = useState(true);
|
const [collapsed, setCollapsed] = useState(true);
|
||||||
const [initLoading, setInitLoading] = useState(true);
|
const [initLoading, setInitLoading] = useState(true);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [dataEmployees, setData] = useState<DataType[]>([]);
|
const [dataEmployees, setData] = useState<DataType[]>([]);
|
||||||
const [list, setList] = useState<DataType[]>([]);
|
const [list, setList] = useState<DataType[]>([]);
|
||||||
|
const [organization, setOrganization] = useState<Organization>({
|
||||||
|
id: "",
|
||||||
|
name: "",
|
||||||
|
address: "",
|
||||||
|
});
|
||||||
|
const loadEmployees = async (id: string) => {
|
||||||
|
const data: any = await apiService.getEmployees(id, []);
|
||||||
|
setList(data.data.participants);
|
||||||
|
};
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
useEffect(() => {
|
||||||
|
const id = searchParams.get("id") || "";
|
||||||
|
if (filteredOrganization) {
|
||||||
|
loadEmployees(id);
|
||||||
|
setOrganization(filteredOrganization);
|
||||||
|
setInitLoading(false);
|
||||||
|
}
|
||||||
|
}, [organizations]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch(fakeDataUrl)
|
fetch(fakeDataUrl)
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
@ -41,27 +69,7 @@ export function EmployeeList() {
|
|||||||
}, []);
|
}, []);
|
||||||
const onLoadMore = () => {
|
const onLoadMore = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setList(
|
loadEmployees(organization.id);
|
||||||
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 =
|
const loadMore =
|
||||||
!initLoading && !loading ? (
|
!initLoading && !loading ? (
|
||||||
@ -77,7 +85,7 @@ export function EmployeeList() {
|
|||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col w-full h-full gap-5 pb-20 px-30 p-8">
|
<div className="flex flex-col w-full h-full gap-5 pb-20 px-30 p-10">
|
||||||
<Title style={{ color: "#302d43", textIndent: 15 }}>Employee List</Title>
|
<Title style={{ color: "#302d43", textIndent: 15 }}>Employee List</Title>
|
||||||
<List
|
<List
|
||||||
className="demo-loadmore-list"
|
className="demo-loadmore-list"
|
||||||
@ -85,18 +93,22 @@ export function EmployeeList() {
|
|||||||
itemLayout="horizontal"
|
itemLayout="horizontal"
|
||||||
loadMore={loadMore}
|
loadMore={loadMore}
|
||||||
dataSource={list}
|
dataSource={list}
|
||||||
renderItem={(item) => (
|
renderItem={(item) => {
|
||||||
<List.Item actions={[<PayOutBtn />]}>
|
console.log(item);
|
||||||
<Skeleton avatar title={false} loading={item.loading} active>
|
|
||||||
<List.Item.Meta
|
return (
|
||||||
avatar={<Avatar icon={<UserOutlined />} />}
|
<List.Item actions={[<PayOutBtn />]}>
|
||||||
title={<a href="https://ant.design">{item.name?.last}</a>}
|
<Skeleton avatar title={false} loading={item.loading} active>
|
||||||
description="1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71"
|
<List.Item.Meta
|
||||||
/>
|
avatar={<Avatar icon={<UserOutlined />} />}
|
||||||
<div>wallet address</div>
|
title={<a href="https://ant.design">{item.name}</a>}
|
||||||
</Skeleton>
|
description="1Lbcfr7sAHTD9CgdQo3HTMTkV8LK4ZnX71"
|
||||||
</List.Item>
|
/>
|
||||||
)}
|
<div>wallet address</div>
|
||||||
|
</Skeleton>
|
||||||
|
</List.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -6,14 +6,37 @@ import { Card } from "antd";
|
|||||||
import { WalletOutlined } from "@ant-design/icons";
|
import { WalletOutlined } from "@ant-design/icons";
|
||||||
import type { InputNumberProps } from "antd";
|
import type { InputNumberProps } from "antd";
|
||||||
import { Col, InputNumber, Row, Slider, Select, Button } from "antd";
|
import { Col, InputNumber, Row, Slider, Select, Button } from "antd";
|
||||||
|
import { apiService } from "@/app/axios/global.service";
|
||||||
|
import Cookies from "js-cookie";
|
||||||
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
|
|
||||||
export function MultisigPage() {
|
export function MultisigPage() {
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
const [multiSigData, setmultiSigData] = useState({
|
||||||
|
title: "",
|
||||||
|
owners: [],
|
||||||
|
confirmations: 0,
|
||||||
|
organizationId: searchParams.get("id") || "",
|
||||||
|
});
|
||||||
|
const router = useRouter();
|
||||||
const [inputValue, setInputValue] = useState(1);
|
const [inputValue, setInputValue] = useState(1);
|
||||||
const onChange: InputNumberProps["onChange"] = (newValue) => {
|
const onChange: InputNumberProps["onChange"] = (newValue) => {
|
||||||
setInputValue(newValue as number);
|
setInputValue(newValue as number);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onDeployMultisig = async () => {
|
||||||
|
const result = await apiService.deployMultisig(
|
||||||
|
multiSigData.organizationId,
|
||||||
|
multiSigData.title,
|
||||||
|
multiSigData.owners,
|
||||||
|
multiSigData.confirmations
|
||||||
|
);
|
||||||
|
if (result) {
|
||||||
|
//Cookies.set("multisig", {result.data.confirmations, result.data.owners, result.data.organizationId, result.data.title});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col w-full h-full p-8 gap-10 ">
|
<div className="flex flex-col w-full h-full p-8 gap-10 ">
|
||||||
<div className="flex flex-col w-1/3">
|
<div className="flex flex-col w-1/3">
|
||||||
@ -93,7 +116,7 @@ export function MultisigPage() {
|
|||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex w-full justify-end pr-5">
|
<div className="flex w-full justify-end pr-5">
|
||||||
<Button size={"large"} type="primary">
|
<Button onClick={onDeployMultisig} size={"large"} type="primary">
|
||||||
Create Multisig
|
Create Multisig
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
31
front/src/hooks/organizations.tsx
Normal file
31
front/src/hooks/organizations.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { Organization } from "@/app/axios/api-types";
|
||||||
|
import { apiService } from "@/app/axios/global.service";
|
||||||
|
import { useSearchParams } from "next/navigation";
|
||||||
|
|
||||||
|
export default function useOrganizationsHooks() {
|
||||||
|
const [organizations, setOrganizations] = useState<Organization[]>([]);
|
||||||
|
const [filteredOrganization, setFilteredOrganization] = useState<
|
||||||
|
Organization[]
|
||||||
|
>([]);
|
||||||
|
const loadOrganizations = async () => {
|
||||||
|
const result = await apiService.getOrganizations();
|
||||||
|
if (result) {
|
||||||
|
setOrganizations(result.data.items || []);
|
||||||
|
}
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
const id = searchParams.get("id") || "";
|
||||||
|
const filteredOrg = organizations.find((element) => element.id === id);
|
||||||
|
|
||||||
|
if (filteredOrg) {
|
||||||
|
setFilteredOrganization(filteredOrg || []);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
organizations,
|
||||||
|
filteredOrganization,
|
||||||
|
setOrganizations,
|
||||||
|
loadOrganizations,
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user