Skip to content
Snippets Groups Projects
Commit f1a0a30e authored by Dima Rifai's avatar Dima Rifai
Browse files

Issue #398- Support Operation Details for balance history

parent de22f493
No related branches found
No related tags found
1 merge request!498Delrifai/#398 add operation details balance history
Pipeline #112021 failed
import { useState } from "react";
import Hive from "@/types/Hive";
import {
Table,
......@@ -25,16 +26,21 @@ import {
} from "../ui/tooltip";
import { useRouter } from "next/router";
import useOperationsTypes from "@/hooks/api/common/useOperationsTypes";
import useOperation from "@/hooks/api/common/useOperation";
import { formatNumber } from "@/lib/utils";
import CustomPagination from "../CustomPagination";
import { config } from "@/Config";
import { faChevronUp, faChevronDown } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import useOperationsFormatter from "@/hooks/common/useOperationsFormatter";
import { convertOperationResultsToTableOperations } from "@/lib/utils";
interface OperationsTableProps {
operations: Explorer.BalanceHistoryForTable[];
total_operations: number;
total_pages: number;
current_page: number;
}
const BalanceHistoryTable: React.FC<OperationsTableProps> = ({
operations,
total_operations,
......@@ -42,8 +48,13 @@ const BalanceHistoryTable: React.FC<OperationsTableProps> = ({
current_page,
}) => {
const router = useRouter();
const {
settings: { rawJsonView, prettyJsonView },
} = useUserSettingsContext();
const [expandedRow, setExpandedRow] = useState<number | null>(null);
const operationsTypes = useOperationsTypes().operationsTypes || [];
const formatRawCoin = (coinValue: number) =>
formatNumber(coinValue, false, false);
......@@ -56,25 +67,79 @@ const BalanceHistoryTable: React.FC<OperationsTableProps> = ({
cat.types.includes(operation.operation_name)
);
return category ? colorByOperationCategory[category.name] : "";
};
};
const getOperationTypeForDisplayById = (op_type_id: number) =>
getOperationTypeForDisplay(
operationsTypes.find((op) => op.op_type_id === op_type_id)
?.operation_name || ""
);
const updateUrl = (page: number) => {
router.push({
pathname: router.pathname,
query: { ...router.query, page: page.toString() },
});
};
const updateUrl = (page: number) => {
router.push({
pathname: router.pathname,
query: { ...router.query, page: page.toString() },
});
};
const OperationDetails: React.FC<{ operationId: number }> = ({
operationId,
}) => {
const { operationData, operationDataIsFetched, operationDataError } =
useOperation(operationId.toString());
const formattedAccountOperations = useOperationsFormatter(operationData);
if (operationDataIsFetched) {
if (!operationData || Object.keys(operationData).length === 0) {
return <p>No records for operation {operationId}</p>;
}
if (!rawJsonView && !prettyJsonView) {
return <div>{getOneLineDescription(formattedAccountOperations)}</div>;
}
if (prettyJsonView) {
return <pre>{JSON.stringify(operationData.op, null, 2)}</pre>;
} else {
return <pre>{JSON.stringify(operationData.op)}</pre>;
}
}
if (operationDataError) {
return <p>Error fetching operation details.</p>;
}
return <p>Loading operation details...</p>;
};
const getOneLineDescription = (operation: any) => {
const value = operation.op.value;
// Check if 'value' is a string or a valid React element
if (typeof value === "string" || React.isValidElement(value)) {
// If trxId is present, prepend a div with a link to the transaction page
if (operation.trx_id) {
return (
<>
{value}
<div>
<span>Transaction : </span>
<Link
className="text-link"
href={`/transaction/${operation.trx_id}`}
>
{operation.trx_id?.slice(0, 10)}{" "}
</Link>
</div>
</>
);
}
return value;
}
return null;
};
return (
<>
<CustomPagination
currentPage={current_page? current_page: 1}
currentPage={current_page ? current_page : 1}
onPageChange={updateUrl}
pageSize={config.standardPaginationSize}
totalCount={total_operations}
......@@ -86,7 +151,11 @@ const BalanceHistoryTable: React.FC<OperationsTableProps> = ({
No results matching given criteria
</div>
) : (
<Table className={cn("rounded-[6px] overflow-hidden max-w-[100%] text-xs mt-3")}>
<Table
className={cn(
"rounded-[6px] overflow-hidden max-w-full text-xs mt-3"
)}
>
<TableHeader>
<TableRow>
<TableHead>Operation Type</TableHead>
......@@ -95,54 +164,99 @@ const BalanceHistoryTable: React.FC<OperationsTableProps> = ({
<TableHead>Balance</TableHead>
<TableHead>Balance Change</TableHead>
<TableHead>New Balance</TableHead>
<TableHead>Details</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{operations.map((operation) => {
{operations.map((operation, index) => {
const operationBgColor = getOperationColor(operation.opTypeId);
const coinName = router.query.coinType?router.query.coinType: 'HIVE'; //defaults to HIVE
const coinName = router.query.coinType
? router.query.coinType
: "HIVE";
const isExpanded = expandedRow === operation.operationId;
return (
<TableRow key={operation.operationId}>
<TableCell data-testid="operation-type">
<div className="flex justify-stretch p-1 rounded">
<span className={`rounded w-4 mr-2 ${operationBgColor}`}></span>
<span>{getOperationTypeForDisplayById(operation.opTypeId)}</span>
</div>
</TableCell>
<TableCell>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div>
<TimeAgo
datetime={new Date(
formatAndDelocalizeTime(operation.timestamp)
)}
/>
</div>
</TooltipTrigger>
<TooltipContent className="bg-theme text-text">
{formatAndDelocalizeTime(operation.timestamp)}
</TooltipContent>
</Tooltip>
</TooltipProvider>
</TableCell>
<TableCell data-testid="block-number">
<Link className="text-link" href={`/block/${operation.blockNumber}`}>
{operation.blockNumber?.toLocaleString()}
</Link>
</TableCell>
<TableCell data-testid="operation-prev-balance">
{formatRawCoin(operation.prev_balance)} {coinName}
</TableCell>
<TableCell data-testid="operation-balance-change">
{formatRawCoin(operation.balanceChange)} {coinName}
</TableCell>
<TableCell>
{formatRawCoin(operation.balance)} {coinName}
</TableCell>
</TableRow>
<React.Fragment key={index}>
<TableRow key={operation.operationId}>
<TableCell data-testid="operation-type">
<div className="flex justify-stretch p-1 rounded">
<span
className={`rounded w-4 mr-2 ${operationBgColor}`}
></span>
<span>
{getOperationTypeForDisplayById(operation.opTypeId)}
</span>
</div>
</TableCell>
<TableCell>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<div>
<TimeAgo
datetime={
new Date(
formatAndDelocalizeTime(operation.timestamp)
)
}
/>
</div>
</TooltipTrigger>
<TooltipContent className="bg-theme text-text">
{formatAndDelocalizeTime(operation.timestamp)}
</TooltipContent>
</Tooltip>
</TooltipProvider>
</TableCell>
<TableCell data-testid="block-number">
<Link
className="text-link"
href={`/block/${operation.blockNumber}`}
>
{operation.blockNumber?.toLocaleString()}
</Link>
</TableCell>
<TableCell data-testid="operation-prev-balance">
{formatRawCoin(operation.prev_balance)} {coinName}
</TableCell>
<TableCell data-testid="operation-balance-change">
{formatRawCoin(operation.balanceChange)} {coinName}
</TableCell>
<TableCell>
{formatRawCoin(operation.balance)} {coinName}
</TableCell>
<TableCell>
<button
onClick={() =>
setExpandedRow(
isExpanded ? null : operation.operationId
)
}
className="text-link"
>
<FontAwesomeIcon
icon={isExpanded ? faChevronUp : faChevronDown}
size="lg"
data-testid="last-updated-icon"
/>
</button>
</TableCell>
</TableRow>
{isExpanded && (
<TableRow>
<TableCell colSpan={7} className="p-4">
<div className="border rounded-2xl p-4">
<h3 className="text-lg font-bold">
Operation Details
</h3>
<OperationDetails
operationId={operation.operationId}
/>
</div>
</TableCell>
</TableRow>
)}
</React.Fragment>
);
})}
</TableBody>
......@@ -152,4 +266,4 @@ const BalanceHistoryTable: React.FC<OperationsTableProps> = ({
);
};
export default BalanceHistoryTable;
\ No newline at end of file
export default BalanceHistoryTable;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment