Skip to content

Commit

Permalink
feat(ledger-browser): refactor eth tokens page into accounts page
Browse files Browse the repository at this point in the history
- This concludes refactoring of ethereum app, it should be fully usable
  with mostly same features as before.
- Refactor completely ETH app token page into accounts page
  using MUI components.
- Update materialized view in peristence plugin ethereum schema.
- Use hyperledger favicon from local files and not from the URL.
- Remove files and components that are not used anymore.
- Remove unnecessary package dependencies.

Depends on hyperledger-cacti#3237

Signed-off-by: Michal Bajer <michal.bajer@fujitsu.com>
  • Loading branch information
outSH committed Jun 25, 2024
1 parent 740c061 commit 0b0c22c
Show file tree
Hide file tree
Showing 50 changed files with 1,210 additions and 1,241 deletions.
2 changes: 1 addition & 1 deletion packages/cacti-ledger-browser/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<head>
<meta charset="UTF-8" />
<link rel="icon" href="https://www.hyperledger.org/hubfs/hyperledgerfavicon.png" />
<link rel="icon" href="/hyperledgerfavicon.webp" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Cacti Ledger Browser</title>
</head>
Expand Down
12 changes: 7 additions & 5 deletions packages/cacti-ledger-browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
"email": "your.name@example.com",
"url": "https://example.com"
},
{
"name": "Michal Bajer",
"email": "michal.bajer@fujitsu.com",
"url": "https://www.fujitsu.com/global/"
},
{
"name": "Tomasz Awramski",
"email": "tomasz.awramski@fujitsu.com",
Expand Down Expand Up @@ -56,26 +61,23 @@
"@emotion/react": "11.11.4",
"@emotion/styled": "11.11.5",
"@mui/icons-material": "5.15.10",
"@mui/lab": "5.0.0-alpha.170",
"@mui/material": "5.15.15",
"@supabase/supabase-js": "1.35.6",
"@tanstack/react-query": "5.29.2",
"apexcharts": "3.45.2",
"localforage": "1.10.0",
"match-sorter": "6.3.3",
"moment": "2.30.1",
"ethers": "6.12.1",
"react": "18.2.0",
"react-apexcharts": "1.4.1",
"react-dom": "18.2.0",
"react-router-dom": "6.21.3",
"sort-by": "1.2.0",
"web3": "4.1.1"
},
"devDependencies": {
"@tanstack/eslint-plugin-query": "5.28.11",
"@tanstack/react-query-devtools": "5.29.2",
"@types/react": "18.2.43",
"@types/react-dom": "18.2.17",
"@types/sort-by": "1",
"@vitejs/plugin-react": "4.2.1",
"typescript": "5.2.2",
"vite": "5.1.7"
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from "react";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Divider from "@mui/material/Divider";

import { TokenERC20 } from "../../../../common/supabase-types";
import ERC20TokenList from "./ERC20TokenList";
import ERC20TokenDetails from "./ERC20TokenDetails";

export type AccountERC20ViewProps = {
accountAddress: string;
};

export default function AccountERC20View({
accountAddress,
}: AccountERC20ViewProps) {
const [selectedToken, setSelectedToken] = React.useState<
TokenERC20 | undefined
>(undefined);

const tokenDetailsId = selectedToken
? `${selectedToken.token_address}-${selectedToken.account_address}`
: "token-not-selected";

return (
<Box>
<Typography variant="h5" color="secondary">
ERC20
</Typography>
<Box
display="flex"
flexDirection="row"
justifyContent="space-around"
alignContent="center"
gap={5}
>
<Box flex={5}>
<ERC20TokenList
accountAddress={accountAddress}
onTokenSelected={(token) => setSelectedToken(token)}
/>
</Box>

<Divider orientation="vertical" flexItem />

<Box flex={7}>
<ERC20TokenDetails key={tokenDetailsId} token={selectedToken} />
</Box>
</Box>
</Box>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import Chart from "react-apexcharts";
import { useTheme } from "@mui/material";

import { BalanceHistoryListData } from "./balanceHistory";

export type ERC20BalanceHistoryChartProps = {
data: BalanceHistoryListData[];
height?: string | number;
};

export default function ERC20BalanceHistoryChart({
data,
height,
}: ERC20BalanceHistoryChartProps) {
if (!data) {
return;
}

const theme = useTheme();

return (
<>
{/* Style overwrite for Apex Charts to use colors from the theme for toolbar buttons (right-top of the chart) */}
<style>
{`
.apexcharts-zoom-icon.apexcharts-selected svg {
fill: ${theme.palette.secondary.main} !important;
}
.apexcharts-pan-icon.apexcharts-selected svg {
stroke: ${theme.palette.secondary.main} !important;
}
`}
</style>

{/* Chart component */}
<Chart
options={{
chart: {
type: "line",
zoom: {
enabled: true,
type: "x",
autoScaleYaxis: true,
},
toolbar: {
autoSelected: "zoom",
tools: {
zoom: true,
zoomin: true,
zoomout: true,
pan: true,
reset: true,
},
},
},
colors: [theme.palette.primary.main],
xaxis: {
type: "datetime",
categories: data?.map((txn) => new Date(txn.created_at).getTime()),
labels: {
format: "dd-MM-yyyy h:mm",
},
},
yaxis: {
title: {
text: "Balance",
},
},
stroke: {
curve: "stepline",
},
markers: {
size: 6,
},
tooltip: {
x: {
format: "dd-MM-yyyy h:mm:ss",
},
},
}}
series={[
{
name: "Balance",
data: data.map((txn) => txn.balance),
},
]}
type="line"
height={height}
/>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import * as React from "react";
import { styled } from "@mui/material/styles";
import Box from "@mui/material/Box";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableFooter from "@mui/material/TableFooter";
import TablePagination from "@mui/material/TablePagination";
import TableRow from "@mui/material/TableRow";
import Paper from "@mui/material/Paper";
import TableHead from "@mui/material/TableHead";
import Typography from "@mui/material/Typography";
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
import ArrowDropUpIcon from "@mui/icons-material/ArrowDropUp";

import { TokenHistoryItem20 } from "../../../../common/supabase-types";
import ShortenedTypography from "../../../../components/ui/ShortenedTypography";

const StyledHeaderCell = styled(TableCell)(({ theme }) => ({
color: theme.palette.primary.main,
fontWeight: "bold",
}));

export type BalanceAmountTextProps = {
children: React.ReactNode;
};

function PositiveBalanceAmountText({ children }: BalanceAmountTextProps) {
return (
<Box
display="flex"
flexDirection="row"
justifyContent="right"
alignItems="center"
>
<Typography color="green" fontWeight="bold">
{children}
</Typography>
<ArrowDropUpIcon color="success" />
</Box>
);
}

function NegativeBalanceAmountText({ children }: BalanceAmountTextProps) {
return (
<Box
display="flex"
flexDirection="row"
justifyContent="right"
alignItems="center"
>
<Typography color="red" fontWeight="bold">
{children}
</Typography>
<ArrowDropDownIcon color="error" />
</Box>
);
}

export type ERC20BalanceHistoryTableProps = {
data: TokenHistoryItem20[];
ownerAddress: string;
};

function formatCreatedAtDate(createdAt: string) {
const date = new Date(createdAt);
return date.toUTCString();
}

export default function ERC20BalanceHistoryTable({
data,
ownerAddress,
}: ERC20BalanceHistoryTableProps) {
const [page, setPage] = React.useState(0);
const [rowsPerPage, setRowsPerPage] = React.useState(5);
const sortedData = [...data].sort((a, b) =>
b.created_at.localeCompare(a.created_at),
);

// Avoid a layout jump when reaching the last page with empty rows.
const emptyRows =
page > 0 ? Math.max(0, (1 + page) * rowsPerPage - sortedData.length) : 0;

return (
<TableContainer
component={Paper}
sx={{
minWidth: 500,
}}
>
<Table aria-label="erc20 token history for account">
<TableHead>
<TableRow>
<StyledHeaderCell>Time</StyledHeaderCell>
<StyledHeaderCell>Hash</StyledHeaderCell>
<StyledHeaderCell>From/To</StyledHeaderCell>
<StyledHeaderCell align="right">Amount</StyledHeaderCell>
</TableRow>
</TableHead>
<TableBody>
{(rowsPerPage > 0
? sortedData.slice(
page * rowsPerPage,
page * rowsPerPage + rowsPerPage,
)
: sortedData
).map((row) => {
const isReceiving = row.recipient === ownerAddress;

return (
<TableRow key={row.transaction_hash}>
<TableCell>{formatCreatedAtDate(row.created_at)}</TableCell>
<TableCell>
<ShortenedTypography
text={row.transaction_hash}
minWidth={300}
/>
</TableCell>
<TableCell>
{isReceiving ? (
<ShortenedTypography text={row.sender} minWidth={200} />
) : (
<ShortenedTypography text={row.recipient} minWidth={200} />
)}
</TableCell>
<TableCell align="right">
{isReceiving ? (
<PositiveBalanceAmountText>
{row.value}
</PositiveBalanceAmountText>
) : (
<NegativeBalanceAmountText>
-{row.value}
</NegativeBalanceAmountText>
)}
</TableCell>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 53 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[5, 10, 25, { label: "All", value: -1 }]}
colSpan={3}
count={sortedData.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={(_event, newPage) => {
setPage(newPage);
}}
onRowsPerPageChange={(event) => {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
}}
/>
</TableRow>
</TableFooter>
</Table>
</TableContainer>
);
}
Loading

0 comments on commit 0b0c22c

Please sign in to comment.