diff --git a/components/FA2Transfer.tsx b/components/FA2Transfer.tsx index 75468121..2610f8c7 100644 --- a/components/FA2Transfer.tsx +++ b/components/FA2Transfer.tsx @@ -109,25 +109,25 @@ const FA2Transfer = ({ onTokenChange?.(newToken); setCurrentToken(newToken); - if (autoSetField) { - const previousValue = getFieldProps( - `transfers.${proposalIndex}.values.${localIndex}` - ).value; - - if ( - Array.isArray(previousValue) || - (!!previousValue && "balance" in previousValue) - ) { - throw new Error("Expect previous value to be formValue"); - } - - setFieldValue(`transfers.${proposalIndex}.values.${localIndex}`, { - ...(previousValue ?? {}), - token: newToken ?? "", - tokenId: newToken?.token.tokenId ?? "", - fa2Address: newToken?.token.contract.address ?? "", - }); + if (!autoSetField) return; + + const previousValue = getFieldProps( + `transfers.${proposalIndex}.values.${localIndex}` + ).value; + + if ( + Array.isArray(previousValue) || + (!!previousValue && "balance" in previousValue) + ) { + throw new Error("Expect previous value to be formValue"); } + + setFieldValue(`transfers.${proposalIndex}.values.${localIndex}`, { + ...(previousValue ?? {}), + token: newToken ?? "", + tokenId: newToken?.token.tokenId ?? "", + fa2Address: newToken?.token.contract.address ?? "", + }); }; const fetchTokens = useCallback( @@ -345,7 +345,19 @@ const FA2TransferGroup = ({ proposalIndex, remove }: props) => { remove={remove} autoSetField={false} onTokenChange={token => { + const previousValue = getFieldProps( + `transfers.${proposalIndex}.values.0` + ).value; + + if ( + Array.isArray(previousValue) || + (!!previousValue && "balance" in previousValue) + ) { + throw new Error("Expect previous value to be formValue"); + } + const data = { + ...previousValue, token, fa2Address: token.token.contract.address, tokenId: token.token.tokenId, diff --git a/components/HistoryFaToken.tsx b/components/HistoryFaToken.tsx new file mode 100644 index 00000000..f1f37029 --- /dev/null +++ b/components/HistoryFaToken.tsx @@ -0,0 +1,97 @@ +import { TriangleDownIcon } from "@radix-ui/react-icons"; +import BigNumber from "bignumber.js"; +import { useMemo, useState } from "react"; +import { TransferType } from "../types/display"; +import Alias from "./Alias"; +import { fa1_2Token } from "./FA1_2"; +import { fa2Token } from "./FA2Transfer"; + +type props = { + transferType: TransferType; + token: { + timestamp: string; + from: { + address: string; + }; + amount: string; + token: fa1_2Token["token"] | fa2Token["token"]; + }; +}; + +const HistoryFaToken = ({ transferType, token }: props) => { + const [isOpen, setIsOpen] = useState(false); + + const { tzDate, tzHours, tzMinutes } = useMemo( + () => ({ + tzDate: new Date(token.timestamp).toLocaleDateString(), + tzHours: new Date(token.timestamp).getHours().toString().padStart(2, "0"), + tzMinutes: new Date(token.timestamp) + .getMinutes() + .toString() + .padStart(2, "0"), + }), + [token.timestamp] + ); + + return ( +
+ +
+ +
+
+ ); +}; + +export default HistoryFaToken; diff --git a/context/proposals.ts b/context/proposals.ts index 46a6ebb5..ee2b5721 100644 --- a/context/proposals.ts +++ b/context/proposals.ts @@ -1,4 +1,4 @@ -import { mutezTransfer } from "../types/display"; +import { mutezTransfer, tokenTransfer } from "../types/display"; import { API_URL } from "./config"; async function getProposals(bigmap: string) { @@ -7,14 +7,27 @@ async function getProposals(bigmap: string) { return json; } async function getTransfers(address: string): Promise { - try { - let res = await fetch( - `${API_URL}/v1/operations/transactions?target=${address}&status=applied&amount.gt=0` - ); - return await res.json(); - } catch (e) { - console.log(e); - return []; - } + return fetch( + `${API_URL}/v1/operations/transactions?target=${address}&status=applied&amount.gt=0` + ) + .then(res => res.json()) + .catch(e => { + console.log(e); + + return Promise.resolve([]); + }); } -export { getProposals, getTransfers }; + +function getTokenTransfers(address: string): Promise { + return fetch( + `${API_URL}/v1/tokens/transfers?anyof.to_.to=${address}&sort.desc=id` + ) + .then(res => res.json()) + .catch(e => { + console.log(e); + + return Promise.resolve([]); + }); +} + +export { getProposals, getTransfers, getTokenTransfers }; diff --git a/pages/history.tsx b/pages/history.tsx index c1d6b252..c367e6f9 100644 --- a/pages/history.tsx +++ b/pages/history.tsx @@ -1,20 +1,32 @@ import { tzip16 } from "@taquito/tzip16"; import { validateContractAddress } from "@taquito/utils"; +import BigNumber from "bignumber.js"; import { useContext, useEffect, useMemo, useState } from "react"; import Alias from "../components/Alias"; +import HistoryFaToken from "../components/HistoryFaToken"; import ProposalCard from "../components/ProposalCard"; import Spinner from "../components/Spinner"; import Meta from "../components/meta"; import Modal from "../components/modal"; import ProposalSignForm from "../components/proposalSignForm"; import fetchVersion from "../context/metadata"; -import { getProposals, getTransfers } from "../context/proposals"; +import { + getProposals, + getTokenTransfers, + getTransfers, +} from "../context/proposals"; import { AppDispatchContext, AppStateContext, contractStorage, } from "../context/state"; -import { mutezTransfer, proposal, version } from "../types/display"; +import { + TransferType, + mutezTransfer, + proposal, + tokenTransfer, + version, +} from "../types/display"; import { mutezToTez } from "../utils/tez"; import useWalletTokens from "../utils/useWalletTokens"; import { getProposalsId, toProposal, toStorage } from "../versioned/apis"; @@ -38,7 +50,9 @@ const History = () => { state.contracts[state.currentContract ?? ""] ); const [proposals, setProposals] = useState(emptyProps); - const [transfers, setTransfers] = useState([] as mutezTransfer[]); + const [transfers, setTransfers] = useState< + [mutezTransfer[], tokenTransfer[]] + >([[], []]); const [openModal, setCloseModal] = useState<{ state: number; proposal: [boolean | undefined, number]; @@ -59,11 +73,16 @@ const History = () => { setIsLoading(true); if (!state.currentContract) return; - let c = await state.connection.contract.at(state.currentContract, tzip16); - let balance = await state.connection.tz.getBalance(state.currentContract); + const c = await state.connection.contract.at( + state.currentContract, + tzip16 + ); + const balance = await state.connection.tz.getBalance( + state.currentContract + ); - let cc = await c.storage(); - let version = await (state.contracts[state.currentContract] + const cc = await c.storage(); + const version = await (state.contracts[state.currentContract] ? Promise.resolve( state.contracts[state.currentContract].version ) @@ -78,16 +97,19 @@ const History = () => { }, }) : null; - let bigmap: { key: string; value: any }[] = await getProposals( + const bigmap: { key: string; value: any }[] = await getProposals( getProposalsId(version, cc) ); - let transfers = await getTransfers(state.currentContract); - let proposals: [number, any][] = bigmap.map(({ key, value }) => [ + const response = await Promise.all([ + getTransfers(state.currentContract), + getTokenTransfers(state.currentContract), + ]); + const proposals: [number, any][] = bigmap.map(({ key, value }) => [ Number.parseInt(key), { ui: toProposal(version, value), og: value }, ]); setContract(updatedContract); - setTransfers(transfers); + setTransfers(response); setProposals(proposals); setIsLoading(false); })(); @@ -103,8 +125,25 @@ const History = () => { ), ] .concat( - transfers.map( - x => [-1, { ui: { timestamp: x.timestamp }, ...x }] as any + transfers[0].map( + x => + [ + TransferType.MUTEZ, + { ui: { timestamp: x.timestamp }, ...x }, + ] as any + ) + ) + .concat( + transfers[1].map( + x => + [ + x.token.standard === "fa2" + ? TransferType.FA2 + : x.token.standard === "fa1.2" + ? TransferType.FA1_2 + : TransferType.UNKNOWN, + { ui: { timestamp: x.timestamp }, ...x }, + ] as any ) ) .sort((a, b) => { @@ -167,58 +206,81 @@ const History = () => { filteredProposals.length > 0 && (
{filteredProposals.map((x, i) => { - return x[0] == -1 ? ( -
- - Received Tez - Received - - - From:{" "} - - - - Amount:{" "} - {mutezToTez((x[1] as any).amount)} Tez - - - {new Date((x[1] as any).timestamp).toLocaleDateString()}{" "} - -{" "} - {`${new Date((x[1] as any).timestamp) - .getHours() - .toString() - .padStart(2, "0")}:${new Date((x[1] as any).timestamp) - .getMinutes() - .toString() - .padStart(2, "0")}`} - -
- ) : ( - ({ - hasApproved: result, - signer, - }) - )} - content={x[1].ui.content} - proposer={x[1].og.proposer} - resolver={x[1].og.resolver} - walletTokens={walletTokens} - /> - ); + switch (x[0]) { + case TransferType.MUTEZ: + return ( +
+ + + Received Tez + + Received + + + From:{" "} + + + + Amount:{" "} + {mutezToTez((x[1] as any).amount)} Tez + + + {new Date( + (x[1] as any).timestamp + ).toLocaleDateString()}{" "} + -{" "} + {`${new Date((x[1] as any).timestamp) + .getHours() + .toString() + .padStart(2, "0")}:${new Date( + (x[1] as any).timestamp + ) + .getMinutes() + .toString() + .padStart(2, "0")}`} + +
+ ); + case TransferType.FA2: + case TransferType.FA1_2: + return ( + + ); + + case TransferType.UNKNOWN: + return null; + default: + return ( + ({ + hasApproved: result, + signer, + }) + )} + content={x[1].ui.content} + proposer={x[1].og.proposer} + resolver={x[1].og.resolver} + walletTokens={walletTokens} + /> + ); + break; + } })}
) diff --git a/types/display.ts b/types/display.ts index d299c5a2..8348bc8d 100644 --- a/types/display.ts +++ b/types/display.ts @@ -29,6 +29,34 @@ type mutezTransfer = { address: string; }; }; +export type tokenTransfer = { + id: number; + level: number; + timestamp: string; + token: { + id: number; + contract: { + address: string; + }; + tokenId: string; + standard: string; + totalSupply: string; + metadata: { + name: string; + symbol: string; + decimals: string; + }; + }; + from: { + address: string; + }; + to: { + address: string; + }; + amount: number; + transactionId: number; +}; + type status = "Proposing" | "Executed" | "Rejected" | "Expired"; type proposal = { author: string; @@ -46,6 +74,14 @@ type version = | "0.0.11" | "0.1.1" | "unknown version"; + +export enum TransferType { + MUTEZ = -1, + FA2 = -2, + FA1_2 = -3, + UNKNOWN = -9999, +} + export { type proposal, type changeThreshold,