diff --git a/src/app/(sidebar)/smart-contracts/contract-explorer/components/VersionHistory.tsx b/src/app/(sidebar)/smart-contracts/contract-explorer/components/VersionHistory.tsx index 996c7d29..c9dea9eb 100644 --- a/src/app/(sidebar)/smart-contracts/contract-explorer/components/VersionHistory.tsx +++ b/src/app/(sidebar)/smart-contracts/contract-explorer/components/VersionHistory.tsx @@ -1,8 +1,11 @@ -import { Card, Loader, Text } from "@stellar/design-system"; +import { useState } from "react"; +import { Card, Icon, Loader, Text } from "@stellar/design-system"; + import { Box } from "@/components/layout/Box"; import { ErrorText } from "@/components/ErrorText"; import { useSEContracVersionHistory } from "@/query/external/useSEContracVersionHistory"; import { formatEpochToDate } from "@/helpers/formatEpochToDate"; + import { NetworkType } from "@/types/types"; export const VersionHistory = ({ @@ -12,6 +15,11 @@ export const VersionHistory = ({ contractId: string; networkId: NetworkType; }) => { + type SortDirection = "default" | "asc" | "desc"; + + const [sortById, setSortById] = useState(""); + const [sortByDir, setSortByDir] = useState("default"); + const { data: versionHistoryData, error: versionHistoryError, @@ -47,29 +55,81 @@ export const VersionHistory = ({ type TableHeader = { id: string; value: string; + isSortable?: boolean; }; const tableId = "contract-version-history"; const cssGridTemplateColumns = "minmax(210px, 2fr) minmax(210px, 1fr)"; const tableHeaders: TableHeader[] = [ - { id: "contract-wasm-hash", value: "Contract WASM Hash" }, - { id: "contract-updated", value: "Updated" }, + { id: "wasm", value: "Contract WASM Hash", isSortable: true }, + { id: "ts", value: "Updated", isSortable: true }, ]; - type TableRow = { + type TableCell = { value: string; isBold?: boolean; }; - const tableRows: TableRow[][] = versionHistoryData.map((vh) => [ - { value: vh.wasm, isBold: true }, - { value: formatEpochToDate(vh.ts, "short") || "-" }, - ]); + const tableRowsData = (): TableCell[][] => { + let sortedData = [...versionHistoryData]; + + if (sortById) { + if (["asc", "desc"].includes(sortByDir)) { + // Asc + sortedData = sortedData.sort((a: any, b: any) => + a[sortById] > b[sortById] ? 1 : -1, + ); + + // Desc + if (sortByDir === "desc") { + sortedData = sortedData.reverse(); + } + } + } + + return sortedData.map((vh) => [ + { value: vh.wasm, isBold: true }, + { value: formatEpochToDate(vh.ts, "short") || "-" }, + ]); + }; const customStyle = { "--LabTable-grid-template-columns": cssGridTemplateColumns, } as React.CSSProperties; + const getSortByProps = (th: TableHeader) => { + if (th.isSortable) { + return { + "data-sortby-dir": sortById === th.id ? sortByDir : "default", + onClick: () => handleSort(th.id), + }; + } + + return {}; + }; + + const handleSort = (headerId: string) => { + let sortDir: SortDirection; + + // Sorting by new id + if (sortById && headerId !== sortById) { + sortDir = "asc"; + } else { + // Sorting the same id + if (sortByDir === "default") { + sortDir = "asc"; + } else if (sortByDir === "asc") { + sortDir = "desc"; + } else { + // from descending + sortDir = "default"; + } + } + + setSortById(headerId); + setSortByDir(sortDir); + }; + return ( @@ -79,14 +139,20 @@ export const VersionHistory = ({ {tableHeaders.map((th) => ( - + {th.value} + {th.isSortable ? ( + + + + + ) : null} ))} - {tableRows.map((row, rowIdx) => { + {tableRowsData().map((row, rowIdx) => { const rowKey = `${tableId}-row-${rowIdx}`; return ( diff --git a/src/styles/globals.scss b/src/styles/globals.scss index ddc716f9..80364ca9 100644 --- a/src/styles/globals.scss +++ b/src/styles/globals.scss @@ -118,6 +118,25 @@ font-size: pxToRem(12px); line-height: pxToRem(18px); min-width: 100px; + + &[data-sortby-dir] { + cursor: pointer; + display: flex; + align-items: center; + gap: pxToRem(4px); + } + + &[data-sortby-dir="asc"] { + .LabTable__sortBy svg:first-of-type { + stroke: var(--sds-clr-gray-12); + } + } + + &[data-sortby-dir="desc"] { + .LabTable__sortBy svg:last-of-type { + stroke: var(--sds-clr-gray-12); + } + } } td { @@ -134,6 +153,30 @@ border-bottom: 1px solid var(--sds-clr-gray-06); } } + + &__sortBy { + display: block; + position: relative; + width: pxToRem(12px); + height: pxToRem(12px); + overflow: hidden; + + svg { + display: block; + position: absolute; + width: 100%; + left: 0; + stroke: var(--sds-clr-gray-09); + + &:first-of-type { + top: pxToRem(-3px); + } + + &:last-of-type { + bottom: pxToRem(-3px); + } + } + } } // ===========================================================================