Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Polish Delegation section #1459

Merged
merged 2 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

.delegation-outputs {
font-family: $metropolis;
margin-top: 24px;

.table-container table thead th {
padding-bottom: 16px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,97 +4,39 @@
@import "../../../../../../scss/variables";
@import "../../../../../../scss/themes";

.table--delegation {
width: 100%;
border-spacing: 12px 28px;
border-collapse: separate;

@include tablet-down {
display: none;
.section--delegations {
.card-info-wrapper {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;

@include phone-down {
grid-template-columns: repeat(1, 1fr);
}
}

tr {
@include font-size(14px);

color: $gray-7;
font-family: $inter;
letter-spacing: 0.5px;
.delegation-outputs {
font-family: $metropolis;

th {
@include font-size(12px);

color: $gray-6;
font-weight: 600;
text-align: left;
text-transform: uppercase;
.table-container table thead th {
padding-bottom: 16px;
}

td {
color: var(--body-color);

&.highlight {
color: var(--link-color);
@include font-size(14px);

font-family: $ibm-plex-mono;
font-weight: normal;
letter-spacing: 0.02em;
line-height: 20px;

a {
max-width: 200px;
}
}
&.truncate {
max-width: 150px;
table {
@include tablet-down {
display: block;
overflow-x: auto;
white-space: nowrap;
width: 100%;
}
}
}
}

.cards--delegation {
display: none;
.truncated-id-cell {
max-width: 400px;

@include tablet-down {
display: block;
}
.card--delegation {
margin-bottom: 16px;
padding: 8px;

.field {
margin-bottom: 8px;

.label {
color: $gray-6;
font-family: $inter;
letter-spacing: 0.5px;

@include font-size(14px, 21px);
}

.value {
@include font-size(14px, 21px);

color: var(--body-color);
font-family: $metropolis;
font-weight: 700;

.highlight {
color: var(--link-color);
@include font-size(14px);

font-family: $ibm-plex-mono;
font-weight: normal;
letter-spacing: 0.02em;
line-height: 20px;
max-width: 200px;
}
@include desktop-down {
max-width: 165px;
}
}

.field:last-child {
margin-bottom: 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { DelegationOutput, Utils } from "@iota/sdk-wasm-nova/web";
import React, { useEffect, useState } from "react";
import Pagination from "~/app/components/Pagination";
import TruncatedId from "~/app/components/stardust/TruncatedId";
import { useNetworkInfoNova } from "~/helpers/nova/networkInfo";
import "./DelegationSection.scss";
import { IDelegationWithDetails } from "~/models/api/nova/IDelegationWithDetails";
import { CardInfo, CardInfoProps } from "~/app/components/CardInfo";
import { formatAmount } from "~/helpers/stardust/valueFormatHelper";
import { DelegationsTableHeadings } from "~/app/lib/ui/enums/DelegationsTableHeadings.enum";
import { useGenerateDelegationsTable } from "~/helpers/nova/hooks/useGenerateDelegationsTable";
import TableCellWrapper, { TTableData } from "../../../TableCell";
import Table, { ITableRow } from "~/app/components/Table";

interface DelegationSectionProps {
readonly delegationDetails: IDelegationWithDetails[] | null;
Expand All @@ -13,9 +17,12 @@ interface DelegationSectionProps {
const PAGE_SIZE: number = 10;

const DelegationSection: React.FC<DelegationSectionProps> = ({ delegationDetails }) => {
const { name: network, bech32Hrp } = useNetworkInfoNova((s) => s.networkInfo);
const { tokenInfo, manaInfo } = useNetworkInfoNova((s) => s.networkInfo);
const [isFormatBalance, setIsFormatBalance] = useState<boolean>(false);
const [pageNumber, setPageNumber] = useState(1);
const [currentPage, setCurrentPage] = useState<IDelegationWithDetails[]>([]);
const tableData: ITableRow<TTableData>[] = useGenerateDelegationsTable(currentPage ?? []);
const tableHeadings = Object.values(DelegationsTableHeadings);

const totalAmount = delegationDetails?.reduce((acc, delegation) => acc + BigInt(delegation.output?.output?.amount ?? 0), BigInt(0));
const totalRewards = delegationDetails?.reduce(
Expand All @@ -35,87 +42,40 @@ const DelegationSection: React.FC<DelegationSectionProps> = ({ delegationDetails
return null;
}

const delegationData: CardInfoProps[] = [
{
title: "Total amount:",
value: formatAmount(totalAmount ?? 0, tokenInfo, isFormatBalance),
onClickValue: () => setIsFormatBalance(!isFormatBalance),
copyValue: String(totalAmount),
},
{
title: "Total rewards",
value: formatAmount(totalRewards ?? 0, manaInfo, isFormatBalance),
onClickValue: () => setIsFormatBalance(!isFormatBalance),
copyValue: String(totalRewards),
},
];
return (
<div className="section transaction--section">
<div className="card card--no-border">
<div className="field">
<div className="card--label margin-b-t">Total amount</div>
<div className="card--value">{totalAmount?.toString()}</div>
</div>
<div className="field">
<div className="card--label margin-b-t">Total rewards</div>
<div className="card--value">{totalRewards?.toString()}</div>
</div>
</div>

<table className="table--delegation">
<thead>
<tr>
<th>Output Id</th>
<th>Validator address</th>
<th>Amount</th>
<th>Rewards</th>
</tr>
</thead>
<tbody>
{currentPage.map((delegation, k) => {
const outputId = delegation.output.metadata.outputId;
const validatorAddress = Utils.addressToBech32(
(delegation.output?.output as DelegationOutput).validatorAddress,
bech32Hrp,
);

return (
<tr key={`delegation-row-${k}`}>
<td className="highlight">
<TruncatedId id={outputId} link={`/${network}/output/${outputId}`} />
</td>
<td className="highlight">
<TruncatedId id={validatorAddress} link={`/${network}/addr/${validatorAddress}`} />
</td>
<td>{delegation.output?.output.amount.toString() ?? "-"}</td>
<td>{delegation.rewards?.manaRewards?.rewards.toString() ?? "-"}</td>
</tr>
);
})}
</tbody>
</table>

{/* Only visible in mobile*/}
<div className="cards--delegation">
{currentPage.map((delegation, k) => {
const outputId = delegation.output.metadata.outputId;
const validatorAddress = Utils.addressToBech32(
(delegation.output?.output as DelegationOutput).validatorAddress,
bech32Hrp,
);

<div className="section section--delegations">
<div className="card-info-wrapper">
{delegationData.map((data, index) => {
return (
<div className="card card--delegation" key={`delegation-row-${k}`}>
<div className="field">
<div className="card--label">Output Id</div>
<div className="card--value">
<TruncatedId id={outputId} link={`/${network}/output/${outputId}`} />
</div>
</div>
<div className="field">
<div className="card--label">Validator Address</div>
<div className="card--value">
<TruncatedId id={validatorAddress} link={`/${network}/addr/${validatorAddress}`} />
</div>
</div>
<div className="field">
<div className="card--label">Amount</div>
<div className="card--value">{delegation.output?.output.amount.toString() ?? "-"}</div>
</div>
<div className="field">
<div className="card--label">Rewards</div>
<div className="card--value">{delegation.rewards?.manaRewards?.rewards.toString() ?? "-"}</div>
</div>
</div>
<CardInfo
key={index}
title={data.title}
value={data.value}
onClickValue={data.onClickValue}
copyValue={data.copyValue}
/>
);
})}
</div>

<div className="section--data delegation-outputs">
<Table headings={tableHeadings} data={tableData} TableDataComponent={TableCellWrapper} />
</div>

<Pagination
currentPage={pageNumber}
totalCount={delegationDetails?.length ?? 0}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum DelegationOutputsTableHeadings {
OutputId = "Output Id",
OutputId = "Delegations",
Amount = "Amount",
}
6 changes: 6 additions & 0 deletions client/src/app/lib/ui/enums/DelegationsTableHeadings.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum DelegationsTableHeadings {
OutputId = "Output Id",
ValidatorAddress = "Validator address",
Amount = "Amount",
Rewards = "Rewards",
}
79 changes: 79 additions & 0 deletions client/src/helpers/nova/hooks/useGenerateDelegationsTable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import type { ITableRow } from "~/app/components/Table";
import { TableCellType, type TTableData } from "~/app/components/nova/TableCell";
import { BaseTokenResponse, DelegationOutput, Utils } from "@iota/sdk-wasm-nova/web";
import { useNetworkInfoNova } from "../networkInfo";
import { DelegationsTableHeadings } from "~/app/lib/ui/enums/DelegationsTableHeadings.enum";
import { IDelegationWithDetails } from "~/models/api/nova/IDelegationWithDetails";

function getDelegationTableRow(
network: string,
bech32Hrp: string,
delegation: IDelegationWithDetails,
tokenInfo: BaseTokenResponse,
manaInfo: BaseTokenResponse,
): ITableRow<TTableData> {
const data: TTableData[] = [];
const outputId = delegation.output.metadata.outputId;
const validatorAddress = Utils.addressToBech32((delegation.output?.output as DelegationOutput).validatorAddress, bech32Hrp);
const amount = delegation.output.output.amount;
const rewards = delegation.rewards?.manaRewards?.rewards ?? 0;

Object.values(DelegationsTableHeadings).forEach((heading) => {
let tableData: TTableData | null = null;

switch (heading) {
case DelegationsTableHeadings.OutputId:
tableData = {
type: TableCellType.TruncatedId,
data: outputId,
href: `/${network}/output/${outputId}`,
shouldCopy: true,
};
break;
case DelegationsTableHeadings.ValidatorAddress:
tableData = {
type: TableCellType.TruncatedId,
data: validatorAddress,
href: `/${network}/addr/${validatorAddress}`,
shouldCopy: true,
};
break;
case DelegationsTableHeadings.Amount:
tableData = {
type: TableCellType.Formatted,
data: amount,
tokenInfo,
};
break;
case DelegationsTableHeadings.Rewards:
tableData = {
type: TableCellType.Formatted,
data: rewards,
tokenInfo: manaInfo,
};
break;
default:
break;
}
if (tableData) {
data.push(tableData);
}
});

return {
id: outputId,
data,
};
}

export function useGenerateDelegationsTable(delegations: IDelegationWithDetails[]): ITableRow<TTableData>[] {
const { name: network, bech32Hrp, tokenInfo, manaInfo } = useNetworkInfoNova((s) => s.networkInfo);
const rows: ITableRow<TTableData>[] = [];

delegations?.map((delegation) => {
const row = getDelegationTableRow(network, bech32Hrp, delegation, tokenInfo, manaInfo);
rows.push(row);
});

return rows;
}
Loading