antoncoding/monarch

View on GitHub
app/history/components/HistoryTable.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import React from 'react';
import { useMemo, useState } from 'react';
import { Pagination } from '@nextui-org/react';
import { Table, TableHeader, TableBody, TableColumn, TableRow, TableCell } from '@nextui-org/table';
import { ExternalLinkIcon } from '@radix-ui/react-icons';
import moment from 'moment';
import Image from 'next/image';

import { formatReadable, formatBalance } from '@/utils/balance';
import { getExplorerTxURL, getMarketURL } from '@/utils/external';
import { actionTypeToText } from '@/utils/morpho';
import { getNetworkImg } from '@/utils/networks';
import { findToken } from '@/utils/tokens';
import { UserTransaction, UserTxTypes } from '@/utils/types';

type HistoryTableProps = {
  history: UserTransaction[];
};

export function HistoryTable({ history }: HistoryTableProps) {
  const [page, setPage] = useState(1);
  const rowsPerPage = 5;

  const pages = Math.ceil(history.length / rowsPerPage);

  const items = useMemo(() => {
    const start = (page - 1) * rowsPerPage;
    const end = start + rowsPerPage;

    return history.sort((a, b) => b.timestamp - a.timestamp).slice(start, end);
  }, [page, history]);

  return (
    <Table
      classNames={{
        th: 'bg-secondary',
        wrapper: 'rounded-none shadow-none bg-secondary',
      }}
      bottomContent={
        <div className="flex w-full justify-center">
          <Pagination
            className="text-black"
            isCompact
            showControls
            // showShadow
            variant="light"
            color="default"
            page={page}
            total={pages}
            onChange={(_page: number) => setPage(_page)}
          />
        </div>
      }
    >
      <TableHeader className="table-header">
        <TableColumn className="text-center"> Network </TableColumn>
        <TableColumn className="text-center">Market ID </TableColumn>
        <TableColumn className="text-center">Action</TableColumn>
        <TableColumn className="text-center">Asset</TableColumn>
        <TableColumn className="text-center">
          <div> Timestamp </div>
        </TableColumn>
        <TableColumn className="text-center">
          <div> Tx Hash </div>
        </TableColumn>
      </TableHeader>
      <TableBody>
        {items.map((tx, index) => {
          const loanImg = findToken(
            tx.data.market.loanAsset.address,
            tx.data.market.morphoBlue.chain.id,
          )?.img;

          const networkImg = getNetworkImg(tx.data.market.morphoBlue.chain.id);

          const sign = tx.type === UserTxTypes.MarketSupply ? '+' : '-';

          return (
            <TableRow key={index.toFixed()}>
              <TableCell>
                <div className="flex justify-center">
                  {networkImg && <Image src={networkImg} alt="network" width="20" height="20" />}
                </div>
              </TableCell>

              {/* id */}
              <TableCell>
                <div className="flex justify-center font-monospace text-xs">
                  <a
                    className="group flex items-center gap-1 no-underline hover:underline"
                    href={getMarketURL(
                      tx.data.market.uniqueKey,
                      tx.data.market.morphoBlue.chain.id,
                    )}
                    target="_blank"
                  >
                    <p>{tx.data.market.uniqueKey.slice(2, 8)} </p>
                    <p className="opacity-0 group-hover:opacity-100">
                      <ExternalLinkIcon />
                    </p>
                  </a>
                </div>
              </TableCell>

              {/* Action */}
              <TableCell>
                <div>
                  <div className="flex items-center justify-center gap-1">
                    <div> {actionTypeToText(tx.type)} </div>
                  </div>
                </div>
              </TableCell>

              {/* Asset */}
              <TableCell>
                <div className="flex items-center justify-center gap-1">
                  <div>
                    {' '}
                    {sign}{' '}
                    {formatReadable(
                      formatBalance(tx.data.assets, tx.data.market.loanAsset.decimals),
                    )}{' '}
                  </div>
                  {loanImg ? (
                    <Image src={loanImg} alt="icon" width="18" height="18" />
                  ) : (
                    tx.data.market.loanAsset.symbol
                  )}
                  <p> {} </p>
                </div>
              </TableCell>

              {/* Timestamp */}
              <TableCell className="z-50 text-center">
                {moment(tx.timestamp * 1000).fromNow()}
              </TableCell>

              {/* Tx Hash */}
              <TableCell>
                <div className="flex items-center justify-center gap-1">
                  <a
                    className="group flex items-center gap-1 font-monospace text-xs no-underline hover:underline"
                    href={getExplorerTxURL(tx.hash, tx.data.market.morphoBlue.chain.id)}
                    target="_blank"
                  >
                    <p> {tx.hash.slice(0, 6)} </p>
                    <p className="opacity-0 group-hover:opacity-100">
                      <ExternalLinkIcon />
                    </p>
                  </a>
                </div>
              </TableCell>
            </TableRow>
          );
        })}
      </TableBody>
    </Table>
  );
}