From 7c1e855cceada4ef877e8bbc6d85c38092393ac1 Mon Sep 17 00:00:00 2001 From: "joh@deep-ink.ventures" Date: Wed, 25 Oct 2023 19:57:16 +0800 Subject: [PATCH 1/7] created initial service for assets with mock asset interface --- src/services/assets.ts | 68 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/services/assets.ts diff --git a/src/services/assets.ts b/src/services/assets.ts new file mode 100644 index 0000000..4bff459 --- /dev/null +++ b/src/services/assets.ts @@ -0,0 +1,68 @@ +import type { JwtToken } from '@/types/auth'; +import type { Paginated } from '@/types/response'; + +export interface MockPolicyAssets { + address: string; + limit: number; + spending: number; +} + +export interface ListPolicyAssetsParams { + search?: string; + limit: number; + offset: number; + multicliqueAccountAddress?: string; +} + +export const listPolicyAssets = async ( + params: ListPolicyAssetsParams, + jwt: JwtToken +): Promise> => { + // const queryString = convertToQueryString(keysToSnakeCase(params)); + + // const response = await fetch( + // `${SERVICE_URL}/api/path/for/assets/?${queryString}`, + // { + // headers: { + // 'Content-Type': 'application/json', + // Authorization: `Bearer ${jwt.access}`, + // }, + // } + // ); + + const mockResponse: MockPolicyAssets[] = await new Promise((resolve) => { + setTimeout( + () => + resolve( + Array(5) + .fill(null) + .map((v, i) => ({ + address: `Address ${i}`, + limit: i, + spending: i, + })) + ), + 1000 + ); + }); + + // const objResponse: Paginated = await response.json(); + + // const formattedResponse = { + // ...objResponse, + // results: objResponse.results?.map((data) => keysToCamelCase(data)), + // }; + + // return formattedResponse; + + return { + count: mockResponse.length, + next: null, + previous: null, + results: mockResponse, + }; +}; + +export const AssetsService = { + listPolicyAssets, +}; From 617c64ca50e7552260b62dda9d323ec0e06dfa7a Mon Sep 17 00:00:00 2001 From: "joh@deep-ink.ventures" Date: Wed, 25 Oct 2023 19:57:36 +0800 Subject: [PATCH 2/7] added assets to account page store --- src/stores/account.ts | 61 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/stores/account.ts b/src/stores/account.ts index 7f7acf1..a8b3002 100644 --- a/src/stores/account.ts +++ b/src/stores/account.ts @@ -5,6 +5,11 @@ import type { StateCreator } from 'zustand'; import type { ListMultiCliqueTransactionsParams } from '@/services'; import { AccountService, TransactionService } from '@/services'; +import type { + ListPolicyAssetsParams, + MockPolicyAssets, +} from '@/services/assets'; +import { AssetsService } from '@/services/assets'; import type { JwtToken } from '@/types/auth'; import type { MultiCliqueAccount } from '@/types/multiCliqueAccount'; import type { MultisigTransaction } from '@/types/multisigTransaction'; @@ -35,6 +40,14 @@ export type AccountSlice = { ) => void; clear: () => void; }; + assets: { + loading: boolean; + failed: boolean; + fulfilled?: boolean; + data: Paginated | null; + getPolicyAssets: (params: ListPolicyAssetsParams, jwt: JwtToken) => void; + clear: () => void; + }; }; export const createAccountSlice: StateCreator< @@ -161,5 +174,53 @@ export const createAccountSlice: StateCreator< ); }, }, + assets: { + loading: false, + data: null, + failed: false, + fulfilled: false, + getPolicyAssets: (params, jwt) => { + set( + produce((state: MCState) => { + state.pages.account.assets.loading = true; + state.pages.account.assets.fulfilled = false; + state.pages.account.assets.failed = false; + }) + ); + AssetsService.listPolicyAssets(params, jwt) + .then(async (response) => { + set( + produce((state: MCState) => { + state.pages.account.assets.data = response; + state.pages.account.assets.fulfilled = true; + }) + ); + }) + .catch(() => { + set( + produce((state: MCState) => { + state.pages.account.assets.failed = true; + }) + ); + }) + .finally(() => { + set( + produce((state: MCState) => { + state.pages.account.assets.loading = false; + }) + ); + }); + }, + clear: () => { + set( + produce((state: MCState) => { + state.pages.account.transactions.loading = false; + state.pages.account.transactions.data = null; + state.pages.account.transactions.fulfilled = false; + state.pages.account.transactions.failed = false; + }) + ); + }, + }, }, }); From 0e99a8a3c88f27cf2ba03b2b627b80928c407cf2 Mon Sep 17 00:00:00 2001 From: "joh@deep-ink.ventures" Date: Wed, 25 Oct 2023 19:58:11 +0800 Subject: [PATCH 3/7] initial integration for assets tab with jwt fetch and loading state --- src/components/ManageElioPolicy.tsx | 141 ++++++++++++++++++------ src/pages/account/[accountId]/index.tsx | 5 +- 2 files changed, 112 insertions(+), 34 deletions(-) diff --git a/src/components/ManageElioPolicy.tsx b/src/components/ManageElioPolicy.tsx index 8e79110..10ab807 100644 --- a/src/components/ManageElioPolicy.tsx +++ b/src/components/ManageElioPolicy.tsx @@ -1,8 +1,11 @@ +import useMC from '@/hooks/useMC'; import useMCStore from '@/stores/MCStore'; import Pencil from '@/svg/components/Pencil'; import Switch from '@/svg/components/Switch'; +import type { JwtToken } from '@/types/auth'; import type { MultiCliquePolicy } from '@/types/multiCliqueAccount'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; +import { EmptyPlaceholder, LoadingPlaceholder, Pagination } from '.'; import SpendLimitFormModal from './SpendLimitFormModal'; interface IManageElioPolicyProps { @@ -10,15 +13,42 @@ interface IManageElioPolicyProps { policy: MultiCliquePolicy; } -const ManageElioPolicy = ({ policy }: IManageElioPolicyProps) => { +const ManageElioPolicy = ({ address }: IManageElioPolicyProps) => { const [isSpendLimitModalVisible, setIsSpendLimitModalVisible] = useState(false); - const [account, currentWalletAccount] = useMCStore((s) => [ + const [account, currentWalletAccount, jwt] = useMCStore((s) => [ s.pages.account, s.currentWalletAccount, + s.jwt, ]); + const { getJwtToken } = useMC(); + + const [pagination, setPagination] = useState({ + currentPage: 1, + offset: 0, + }); + + const fetchPolicyAssets = (jwtToken?: JwtToken | null) => { + if (jwtToken) { + account.assets.getPolicyAssets( + { + offset: Math.max(pagination.offset - 1, 0), + limit: 10, + }, + jwtToken + ); + } + }; + + useEffect(() => { + if (address && jwt) { + fetchPolicyAssets(jwt); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [address, JSON.stringify(pagination)]); + if ( !account.multisig.data?.signatories.some( (signer) => @@ -32,45 +62,90 @@ const ManageElioPolicy = ({ policy }: IManageElioPolicyProps) => { ); } + + const handleLoadTransactions = async () => { + if (address) { + const newJwt = await getJwtToken(address); + fetchPolicyAssets(newJwt); + } + }; + return ( <>
Manage ELIO DAO Policy
- <> -
-
-
Asset
-
Limit
-
Spending
-
Action
-
- {Array(5) - .fill(null) - ?.map((arg, index) => ( -
-
Asset {index}
-
Limit {index}
-
Spending {index}
-
- - + {!jwt && ( + +
+ At the moment, we require users to authenticate to view assets +
+ +
+ } + /> + )} + {jwt && ( + <> + {account.assets.loading && } + {!account.assets.loading && ( + <> +
+
+
Asset
+
Limit
+
Spending
+
Action
+ {account.assets.data?.results?.map((asset, index) => { + return ( +
+
{asset.address}
+
{asset.limit}
+
{asset.spending}
+
+ + +
+
+ ); + })}
- ))} -
- + + )} + + )}
+ {!account.assets.loading && + Boolean(account.assets.data?.results?.length) && ( +
+ + setPagination({ currentPage: newPage, offset: newOffset }) + } + /> +
+ )} { )} {accountPage.multisig.data?.policy.name === 'ELIO_DAO' && currentTab === 'Manage ELIO DAO Policy' && ( - + )}
From eeff64f228f43d298cba8ffb97d375f9ae96ff27 Mon Sep 17 00:00:00 2001 From: "joh@deep-ink.ventures" Date: Fri, 27 Oct 2023 12:53:01 +0800 Subject: [PATCH 4/7] fix reverted change --- src/components/ManageElioPolicy.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/ManageElioPolicy.tsx b/src/components/ManageElioPolicy.tsx index 3a9dd60..f744a99 100644 --- a/src/components/ManageElioPolicy.tsx +++ b/src/components/ManageElioPolicy.tsx @@ -6,6 +6,7 @@ import Switch from '@/svg/components/Switch'; import CopyIcon from '@/svg/copy.svg'; import type { JwtToken } from '@/types/auth'; import type { MultiCliquePolicy } from '@/types/multiCliqueAccount'; +import { truncateMiddle } from '@/utils'; import Image from 'next/image'; import { useEffect, useState } from 'react'; import { EmptyPlaceholder, LoadingPlaceholder, Pagination } from '.'; @@ -131,14 +132,13 @@ const ManageElioPolicy = ({ address }: IManageElioPolicyProps) => {
-
{asset.address}
+
+ {truncateMiddle(asset.address)} + +
{asset.limit}
{asset.spending}
-
- {!jwt && ( - -
- At the moment, we require users to authenticate to view assets +
+
+
Asset
+
Limit
+
Spending
+
Action
+
+ {!policy.contracts?.length && } + {policy.contracts?.map((contract, index) => { + return ( +
+
+ {truncateMiddle(contract.address)} +
- -
- } - /> - )} - {jwt && ( - <> - {account.assets.loading && } - {!account.assets.loading && ( - <> -
-
-
Asset
-
Limit
-
Spending
-
Action
-
- {account.assets.data?.results?.map((asset, index) => { - return ( -
-
- {truncateMiddle(asset.address)} - -
-
{asset.limit}
-
{asset.spending}
-
- -
-
- ); - })} +
{contract.limit.toString()}
+
+ {contract.alreadySpent.toString()}
- - )} - - )} +
+ +
+
+ ); + })} +
- {!account.assets.loading && - Boolean(account.assets.data?.results?.length) && ( -
- - setPagination({ currentPage: newPage, offset: newOffset }) - } - /> -
- )} { )} {accountPage.multisig.data?.policy.name === 'ELIO_DAO' && currentTab === 'Manage ELIO DAO Policy' && ( - + )}
diff --git a/src/services/assets.ts b/src/services/assets.ts deleted file mode 100644 index 4bff459..0000000 --- a/src/services/assets.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { JwtToken } from '@/types/auth'; -import type { Paginated } from '@/types/response'; - -export interface MockPolicyAssets { - address: string; - limit: number; - spending: number; -} - -export interface ListPolicyAssetsParams { - search?: string; - limit: number; - offset: number; - multicliqueAccountAddress?: string; -} - -export const listPolicyAssets = async ( - params: ListPolicyAssetsParams, - jwt: JwtToken -): Promise> => { - // const queryString = convertToQueryString(keysToSnakeCase(params)); - - // const response = await fetch( - // `${SERVICE_URL}/api/path/for/assets/?${queryString}`, - // { - // headers: { - // 'Content-Type': 'application/json', - // Authorization: `Bearer ${jwt.access}`, - // }, - // } - // ); - - const mockResponse: MockPolicyAssets[] = await new Promise((resolve) => { - setTimeout( - () => - resolve( - Array(5) - .fill(null) - .map((v, i) => ({ - address: `Address ${i}`, - limit: i, - spending: i, - })) - ), - 1000 - ); - }); - - // const objResponse: Paginated = await response.json(); - - // const formattedResponse = { - // ...objResponse, - // results: objResponse.results?.map((data) => keysToCamelCase(data)), - // }; - - // return formattedResponse; - - return { - count: mockResponse.length, - next: null, - previous: null, - results: mockResponse, - }; -}; - -export const AssetsService = { - listPolicyAssets, -}; diff --git a/src/stores/account.ts b/src/stores/account.ts index a8b3002..f7d2184 100644 --- a/src/stores/account.ts +++ b/src/stores/account.ts @@ -5,11 +5,7 @@ import type { StateCreator } from 'zustand'; import type { ListMultiCliqueTransactionsParams } from '@/services'; import { AccountService, TransactionService } from '@/services'; -import type { - ListPolicyAssetsParams, - MockPolicyAssets, -} from '@/services/assets'; -import { AssetsService } from '@/services/assets'; + import type { JwtToken } from '@/types/auth'; import type { MultiCliqueAccount } from '@/types/multiCliqueAccount'; import type { MultisigTransaction } from '@/types/multisigTransaction'; @@ -40,14 +36,6 @@ export type AccountSlice = { ) => void; clear: () => void; }; - assets: { - loading: boolean; - failed: boolean; - fulfilled?: boolean; - data: Paginated | null; - getPolicyAssets: (params: ListPolicyAssetsParams, jwt: JwtToken) => void; - clear: () => void; - }; }; export const createAccountSlice: StateCreator< @@ -174,53 +162,5 @@ export const createAccountSlice: StateCreator< ); }, }, - assets: { - loading: false, - data: null, - failed: false, - fulfilled: false, - getPolicyAssets: (params, jwt) => { - set( - produce((state: MCState) => { - state.pages.account.assets.loading = true; - state.pages.account.assets.fulfilled = false; - state.pages.account.assets.failed = false; - }) - ); - AssetsService.listPolicyAssets(params, jwt) - .then(async (response) => { - set( - produce((state: MCState) => { - state.pages.account.assets.data = response; - state.pages.account.assets.fulfilled = true; - }) - ); - }) - .catch(() => { - set( - produce((state: MCState) => { - state.pages.account.assets.failed = true; - }) - ); - }) - .finally(() => { - set( - produce((state: MCState) => { - state.pages.account.assets.loading = false; - }) - ); - }); - }, - clear: () => { - set( - produce((state: MCState) => { - state.pages.account.transactions.loading = false; - state.pages.account.transactions.data = null; - state.pages.account.transactions.fulfilled = false; - state.pages.account.transactions.failed = false; - }) - ); - }, - }, }, }); From 3992bca3aa14fb3075d437914e8f05a8ba33aa43 Mon Sep 17 00:00:00 2001 From: "joh@deep-ink.ventures" Date: Fri, 27 Oct 2023 17:27:11 +0800 Subject: [PATCH 7/7] remove unused selector --- src/components/ManageElioPolicy.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ManageElioPolicy.tsx b/src/components/ManageElioPolicy.tsx index ca3757b..08a8bb1 100644 --- a/src/components/ManageElioPolicy.tsx +++ b/src/components/ManageElioPolicy.tsx @@ -20,7 +20,6 @@ const ManageElioPolicy = ({ policy }: IManageElioPolicyProps) => { const [account, currentWalletAccount] = useMCStore((s) => [ s.pages.account, s.currentWalletAccount, - s.jwt, ]); if (